blk-crypto-fallback open-codes a per-data-unit loop, issuing one skcipher request per data unit with the IV walked as a DUN counter. Allocate dun(<cipher>,le) instead of the bare cipher so a contiguous bio segment is encrypted/decrypted as one multi-data-unit request, the crypto layer walking the per-unit IV. Every blk-crypto mode feeds the DUN as a little-endian counter, and dun() handles any counter width up to 32 bytes, so all modes -- including Adiantum (32-byte IV) -- are wrapped and the open-coded inner per-unit loop is removed from both the encrypt and decrypt paths. This makes blk-crypto-fallback a second consumer of the template (after dm-crypt) and lets a higher-priority hardware dun(...) driver, if present, handle the request in one pass.
Output is unchanged: the template's little-endian per-unit counter is exactly blk_crypto_dun_to_iv()/bio_crypt_dun_increment(). Signed-off-by: Leonid Ravich <[email protected]> --- block/Kconfig | 1 + block/blk-crypto-fallback.c | 74 ++++++++++++++++++------------------- 2 files changed, 36 insertions(+), 39 deletions(-) diff --git a/block/Kconfig b/block/Kconfig index 15027963472d..0c9025f9b0f6 100644 --- a/block/Kconfig +++ b/block/Kconfig @@ -204,6 +204,7 @@ config BLK_INLINE_ENCRYPTION_FALLBACK depends on BLK_INLINE_ENCRYPTION select CRYPTO select CRYPTO_SKCIPHER + select CRYPTO_DUN # batches a segment's data units per crypto request help Enabling this lets the block layer handle inline encryption by falling back to the kernel crypto API when inline diff --git a/block/blk-crypto-fallback.c b/block/blk-crypto-fallback.c index 61f595410832..8337d56ba1dc 100644 --- a/block/blk-crypto-fallback.c +++ b/block/blk-crypto-fallback.c @@ -250,7 +250,6 @@ static void __blk_crypto_fallback_encrypt_bio(struct bio *src_bio, unsigned int nr_enc_pages, enc_idx; struct page **enc_pages; struct bio *enc_bio; - unsigned int i; skcipher_request_set_callback(ciph_req, CRYPTO_TFM_REQ_MAY_BACKLOG | CRYPTO_TFM_REQ_MAY_SLEEP, @@ -260,9 +259,6 @@ static void __blk_crypto_fallback_encrypt_bio(struct bio *src_bio, sg_init_table(&src, 1); sg_init_table(&dst, 1); - skcipher_request_set_crypt(ciph_req, &src, &dst, data_unit_size, - iv.bytes); - /* * Encrypt each page in the source bio. Because the source bio could * have bio_vecs that span more than a single page, but the encrypted @@ -287,29 +283,26 @@ static void __blk_crypto_fallback_encrypt_bio(struct bio *src_bio, __bio_add_page(enc_bio, enc_page, src_bv.bv_len, src_bv.bv_offset); - sg_set_page(&src, src_bv.bv_page, data_unit_size, - src_bv.bv_offset); - sg_set_page(&dst, enc_page, data_unit_size, src_bv.bv_offset); - /* * Increment the index now that the encrypted page is added to * the bio. This is important for the error unwind path. */ enc_idx++; - /* - * Encrypt each data unit in this page. - */ - for (i = 0; i < src_bv.bv_len; i += data_unit_size) { - blk_crypto_dun_to_iv(curr_dun, &iv); - if (crypto_skcipher_encrypt(ciph_req)) { - enc_bio->bi_status = BLK_STS_IOERR; - goto out_free_enc_bio; - } - bio_crypt_dun_increment(curr_dun, 1); - src.offset += data_unit_size; - dst.offset += data_unit_size; + /* Encrypt the whole segment as one multi-data-unit request. */ + blk_crypto_dun_to_iv(curr_dun, &iv); + sg_set_page(&src, src_bv.bv_page, src_bv.bv_len, + src_bv.bv_offset); + sg_set_page(&dst, enc_page, src_bv.bv_len, src_bv.bv_offset); + skcipher_request_set_crypt(ciph_req, &src, &dst, src_bv.bv_len, + iv.bytes); + skcipher_request_set_data_unit_size(ciph_req, data_unit_size); + if (crypto_skcipher_encrypt(ciph_req)) { + enc_bio->bi_status = BLK_STS_IOERR; + goto out_free_enc_bio; } + bio_crypt_dun_increment(curr_dun, + src_bv.bv_len / data_unit_size); bio_advance_iter_single(src_bio, &src_bio->bi_iter, src_bv.bv_len); @@ -380,7 +373,6 @@ static blk_status_t __blk_crypto_fallback_decrypt_bio(struct bio *bio, struct scatterlist sg; struct bio_vec bv; const int data_unit_size = bc->bc_key->crypto_cfg.data_unit_size; - unsigned int i; skcipher_request_set_callback(ciph_req, CRYPTO_TFM_REQ_MAY_BACKLOG | CRYPTO_TFM_REQ_MAY_SLEEP, @@ -388,26 +380,20 @@ static blk_status_t __blk_crypto_fallback_decrypt_bio(struct bio *bio, memcpy(curr_dun, bc->bc_dun, sizeof(curr_dun)); sg_init_table(&sg, 1); - skcipher_request_set_crypt(ciph_req, &sg, &sg, data_unit_size, - iv.bytes); - /* Decrypt each segment in the bio */ + /* One dun() request per segment; the crypto layer walks the per-unit DUN. */ __bio_for_each_segment(bv, bio, iter, iter) { - struct page *page = bv.bv_page; - if (!IS_ALIGNED(bv.bv_len | bv.bv_offset, data_unit_size)) return BLK_STS_INVAL; - sg_set_page(&sg, page, data_unit_size, bv.bv_offset); - - /* Decrypt each data unit in the segment */ - for (i = 0; i < bv.bv_len; i += data_unit_size) { - blk_crypto_dun_to_iv(curr_dun, &iv); - if (crypto_skcipher_decrypt(ciph_req)) - return BLK_STS_IOERR; - bio_crypt_dun_increment(curr_dun, 1); - sg.offset += data_unit_size; - } + blk_crypto_dun_to_iv(curr_dun, &iv); + sg_set_page(&sg, bv.bv_page, bv.bv_len, bv.bv_offset); + skcipher_request_set_crypt(ciph_req, &sg, &sg, bv.bv_len, + iv.bytes); + skcipher_request_set_data_unit_size(ciph_req, data_unit_size); + if (crypto_skcipher_decrypt(ciph_req)) + return BLK_STS_IOERR; + bio_crypt_dun_increment(curr_dun, bv.bv_len / data_unit_size); } return BLK_STS_OK; @@ -621,6 +607,7 @@ static int blk_crypto_fallback_init(void) int blk_crypto_fallback_start_using_mode(enum blk_crypto_mode_num mode_num) { const char *cipher_str = blk_crypto_modes[mode_num].cipher_str; + char dun_str[CRYPTO_MAX_ALG_NAME]; struct blk_crypto_fallback_keyslot *slotp; unsigned int i; int err = 0; @@ -641,15 +628,24 @@ int blk_crypto_fallback_start_using_mode(enum blk_crypto_mode_num mode_num) if (err) goto out; + /* + * Wrap in dun() to handle a whole segment per request (a higher-priority + * hardware dun() wins if present). The blk-crypto DUN is little-endian. + */ + if (snprintf(dun_str, sizeof(dun_str), "dun(%s,le)", cipher_str) >= + (int)sizeof(dun_str)) { + err = -EINVAL; + goto out; + } + for (i = 0; i < blk_crypto_num_keyslots; i++) { slotp = &blk_crypto_keyslots[i]; - slotp->tfms[mode_num] = crypto_alloc_sync_skcipher(cipher_str, - 0, 0); + slotp->tfms[mode_num] = crypto_alloc_sync_skcipher(dun_str, 0, 0); if (IS_ERR(slotp->tfms[mode_num])) { err = PTR_ERR(slotp->tfms[mode_num]); if (err == -ENOENT) { pr_warn_once("Missing crypto API support for \"%s\"\n", - cipher_str); + dun_str); err = -ENOPKG; } slotp->tfms[mode_num] = NULL; -- 2.47.3

