Skip to content

Commit 0c7d5c5

Browse files
Christoph Hellwigkawasaki
authored andcommitted
blk-crypto: optimize data unit alignment checking
Avoid the relatively high overhead of constructing and walking per-page segment bio_vecs for data unit alignment checking by merging the checks into existing loops. For hardware support crypto, perform the check in bio_split_io_at, which already contains a similar alignment check applied for all I/O. This means bio-based drivers that do not call bio_split_to_limits, should they ever grow blk-crypto support, need to implement the check themselves, just like all other queue limits checks. For blk-crypto-fallback do it in the encryption/decryption loops. This means alignment errors for decryption will only be detected after I/O has completed, but that seems like a worthwhile trade off. Signed-off-by: Christoph Hellwig <hch@lst.de> Reviewed-by: Eric Biggers <ebiggers@kernel.org>
1 parent c115440 commit 0c7d5c5

File tree

3 files changed

+21
-25
lines changed

3 files changed

+21
-25
lines changed

block/blk-crypto-fallback.c

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,12 @@ static void __blk_crypto_fallback_encrypt_bio(struct bio *src_bio,
278278
bio_iter_iovec(src_bio, src_bio->bi_iter);
279279
struct page *enc_page = enc_pages[enc_idx];
280280

281+
if (!IS_ALIGNED(src_bv.bv_len | src_bv.bv_offset,
282+
data_unit_size)) {
283+
enc_bio->bi_status = BLK_STS_INVAL;
284+
goto out_free_enc_bio;
285+
}
286+
281287
__bio_add_page(enc_bio, enc_page, src_bv.bv_len,
282288
src_bv.bv_offset);
283289

@@ -296,8 +302,10 @@ static void __blk_crypto_fallback_encrypt_bio(struct bio *src_bio,
296302
*/
297303
for (i = 0; i < src_bv.bv_len; i += data_unit_size) {
298304
blk_crypto_dun_to_iv(curr_dun, &iv);
299-
if (crypto_skcipher_encrypt(ciph_req))
305+
if (crypto_skcipher_encrypt(ciph_req)) {
306+
enc_bio->bi_status = BLK_STS_IOERR;
300307
goto out_free_enc_bio;
308+
}
301309
bio_crypt_dun_increment(curr_dun, 1);
302310
src.offset += data_unit_size;
303311
dst.offset += data_unit_size;
@@ -334,7 +342,7 @@ static void __blk_crypto_fallback_encrypt_bio(struct bio *src_bio,
334342
*/
335343
for (; enc_idx < nr_enc_pages; enc_idx++)
336344
__bio_add_page(enc_bio, enc_pages[enc_idx++], PAGE_SIZE, 0);
337-
bio_io_error(enc_bio);
345+
bio_endio(enc_bio);
338346
}
339347

340348
/*
@@ -387,6 +395,9 @@ static blk_status_t __blk_crypto_fallback_decrypt_bio(struct bio *bio,
387395
__bio_for_each_segment(bv, bio, iter, iter) {
388396
struct page *page = bv.bv_page;
389397

398+
if (!IS_ALIGNED(bv.bv_len | bv.bv_offset, data_unit_size))
399+
return BLK_STS_INVAL;
400+
390401
sg_set_page(&sg, page, data_unit_size, bv.bv_offset);
391402

392403
/* Decrypt each data unit in the segment */

block/blk-crypto.c

Lines changed: 0 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -219,22 +219,6 @@ bool bio_crypt_ctx_mergeable(struct bio_crypt_ctx *bc1, unsigned int bc1_bytes,
219219
return !bc1 || bio_crypt_dun_is_contiguous(bc1, bc1_bytes, bc2->bc_dun);
220220
}
221221

222-
/* Check that all I/O segments are data unit aligned. */
223-
static bool bio_crypt_check_alignment(struct bio *bio)
224-
{
225-
const unsigned int data_unit_size =
226-
bio->bi_crypt_context->bc_key->crypto_cfg.data_unit_size;
227-
struct bvec_iter iter;
228-
struct bio_vec bv;
229-
230-
bio_for_each_segment(bv, bio, iter) {
231-
if (!IS_ALIGNED(bv.bv_len | bv.bv_offset, data_unit_size))
232-
return false;
233-
}
234-
235-
return true;
236-
}
237-
238222
blk_status_t __blk_crypto_rq_get_keyslot(struct request *rq)
239223
{
240224
return blk_crypto_get_keyslot(rq->q->crypto_profile,
@@ -287,12 +271,6 @@ bool __blk_crypto_bio_prep(struct bio *bio)
287271
return false;
288272
}
289273

290-
if (!bio_crypt_check_alignment(bio)) {
291-
bio->bi_status = BLK_STS_INVAL;
292-
bio_endio(bio);
293-
return false;
294-
}
295-
296274
/*
297275
* If the device does not natively support the encryption context, try to use
298276
* the fallback if available.

block/blk-merge.c

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -324,12 +324,19 @@ static inline unsigned int bvec_seg_gap(struct bio_vec *bvprv,
324324
int bio_split_io_at(struct bio *bio, const struct queue_limits *lim,
325325
unsigned *segs, unsigned max_bytes, unsigned len_align_mask)
326326
{
327+
struct bio_crypt_ctx *bc = bio_crypt_ctx(bio);
327328
struct bio_vec bv, bvprv, *bvprvp = NULL;
328329
unsigned nsegs = 0, bytes = 0, gaps = 0;
329330
struct bvec_iter iter;
331+
unsigned start_align_mask = lim->dma_alignment;
332+
333+
if (bc) {
334+
start_align_mask |= (bc->bc_key->crypto_cfg.data_unit_size - 1);
335+
len_align_mask |= (bc->bc_key->crypto_cfg.data_unit_size - 1);
336+
}
330337

331338
bio_for_each_bvec(bv, bio, iter) {
332-
if (bv.bv_offset & lim->dma_alignment ||
339+
if (bv.bv_offset & start_align_mask ||
333340
bv.bv_len & len_align_mask)
334341
return -EINVAL;
335342

0 commit comments

Comments
 (0)