FROMLIST: block: Add encryption context to struct bio

We must have some way of letting a storage device driver know what
encryption context it should use for en/decrypting a request. However,
it's the filesystem/fscrypt that knows about and manages encryption
contexts. As such, when the filesystem layer submits a bio to the block
layer, and this bio eventually reaches a device driver with support for
inline encryption, the device driver will need to have been told the
encryption context for that bio.

We want to communicate the encryption context from the filesystem layer
to the storage device along with the bio, when the bio is submitted to the
block layer. To do this, we add a struct bio_crypt_ctx to struct bio, which
can represent an encryption context (note that we can't use the bi_private
field in struct bio to do this because that field does not function to pass
information across layers in the storage stack). We also introduce various
functions to manipulate the bio_crypt_ctx and make the bio/request merging
logic aware of the bio_crypt_ctx.

Bug: 137270441
Test: tested as series; see Ie1b77f7615d6a7a60fdc9105c7ab2200d17636a8
Change-Id: I479de9ec13758f1978b34d897e6956e680caeb92
Signed-off-by: Satya Tangirala <[email protected]>
Link: https://patchwork.kernel.org/patch/11214719/
This commit is contained in:
Satya Tangirala 2019-10-24 14:44:24 -07:00
commit 10f1b43cbc
10 changed files with 426 additions and 30 deletions

View file

@ -557,6 +557,9 @@ static inline int ll_new_hw_segment(struct request *req, struct bio *bio,
if (blk_integrity_merge_bio(req->q, req, bio) == false)
goto no_merge;
if (WARN_ON_ONCE(!bio_crypt_ctx_compatible(bio, req->bio)))
goto no_merge;
/*
* This will form the start of a new hw segment. Bump both
* counters.
@ -711,8 +714,14 @@ static enum elv_merge blk_try_req_merge(struct request *req,
{
if (blk_discard_mergable(req))
return ELEVATOR_DISCARD_MERGE;
else if (blk_rq_pos(req) + blk_rq_sectors(req) == blk_rq_pos(next))
else if (blk_rq_pos(req) + blk_rq_sectors(req) == blk_rq_pos(next)) {
if (!bio_crypt_ctx_back_mergeable(req->bio,
blk_rq_sectors(req),
next->bio)) {
return ELEVATOR_NO_MERGE;
}
return ELEVATOR_BACK_MERGE;
}
return ELEVATOR_NO_MERGE;
}
@ -748,6 +757,9 @@ static struct request *attempt_merge(struct request_queue *q,
if (req->ioprio != next->ioprio)
return NULL;
if (!bio_crypt_ctx_compatible(req->bio, next->bio))
return NULL;
/*
* If we are allowed to merge, then append bio list
* from next to rq and release next. merge_requests_fn
@ -880,16 +892,31 @@ bool blk_rq_merge_ok(struct request *rq, struct bio *bio)
if (rq->ioprio != bio_prio(bio))
return false;
/* Only merge if the crypt contexts are compatible */
if (!bio_crypt_ctx_compatible(bio, rq->bio))
return false;
return true;
}
enum elv_merge blk_try_merge(struct request *rq, struct bio *bio)
{
if (blk_discard_mergable(rq))
if (blk_discard_mergable(rq)) {
return ELEVATOR_DISCARD_MERGE;
else if (blk_rq_pos(rq) + blk_rq_sectors(rq) == bio->bi_iter.bi_sector)
} else if (blk_rq_pos(rq) + blk_rq_sectors(rq) ==
bio->bi_iter.bi_sector) {
if (!bio_crypt_ctx_back_mergeable(rq->bio,
blk_rq_sectors(rq), bio)) {
return ELEVATOR_NO_MERGE;
}
return ELEVATOR_BACK_MERGE;
else if (blk_rq_pos(rq) - bio_sectors(bio) == bio->bi_iter.bi_sector)
} else if (blk_rq_pos(rq) - bio_sectors(bio) ==
bio->bi_iter.bi_sector) {
if (!bio_crypt_ctx_back_mergeable(bio,
bio_sectors(bio), rq->bio)) {
return ELEVATOR_NO_MERGE;
}
return ELEVATOR_FRONT_MERGE;
}
return ELEVATOR_NO_MERGE;
}