Re: [PATCH v1 05/11] blk-crypto: add slot-based inline encryption path
From: Stefan Hajnoczi
Date: Tue Sep 01 2026 - 15:10:50 EST
On Thu, Aug 27, 2026 at 09:07:14AM -0700, Linlin Zhang wrote:
> From: linlzhan <linlin.zhang@xxxxxxxxxxxxxxxx>
>
> For the virtio-blk inline encryption use case, the guest kernel goes
> through the normal blk_crypto_key programming flow via SMC call in a
> virtual slot format before I/O starts. It then requests the host to
> handle that I/O with the key programmed into the corresponding physical
> keyslot.
Just a note for other reviewers: This patch is specific to the
out-of-band key slot programming approach taken in this series. We are
discussing in-band key slot programming where this patch probably won't
be necessary.
I am skipping this patch for now.
>
> Introduce a "slot path" that lets a bio carry a pre-programmed physical
> ICE keyslot index rather than a blk_crypto_key pointer. Add struct
> blk_crypto_slot, containing the physical slot index (phy_slot) and
> data_unit_size_bits, and embed it in struct bio_crypt_ctx alongside the
> existing bc_key pointer. A NULL bc_key indicates the slot path.
>
> Provide bio_crypt_set_ctx_by_slot() as the caller-facing API for this
> path. Update the internal consumers of bio_crypt_ctx to handle both
> paths:
>
> - __bio_crypt_advance() and bio_crypt_dun_is_contiguous() use
> bc_slot.data_unit_size_bits to update the DUN when bc_key is NULL.
> - bio_crypt_ctx_compatible() compares phy_slot and data_unit_size_bits
> when bc_key is NULL, preserving request-merging for slot-based bios.
> - __blk_crypto_submit_bio() short-circuits for the slot path: if the
> device exposes a crypto_profile the bio is passed through as-is;
> otherwise it fails with BLK_STS_NOTSUPP. The software fallback is
> not attempted since the guest has no key material.
> - blk_crypto_rq_get_keyslot() skips kernel-side keyslot allocation
> when bc_key is NULL.
>
> There is no functional change to the existing key-based path.
>
> Signed-off-by: linlzhan <linlin.zhang@xxxxxxxxxxxxxxxx>
> ---
> block/blk-crypto-internal.h | 2 +-
> block/blk-crypto.c | 57 ++++++++++++++++++++++++++++++++++---
> include/linux/blk-crypto.h | 25 ++++++++++++++++
> 3 files changed, 79 insertions(+), 5 deletions(-)
>
> diff --git a/block/blk-crypto-internal.h b/block/blk-crypto-internal.h
> index 2c7a0446572a..04035d237f03 100644
> --- a/block/blk-crypto-internal.h
> +++ b/block/blk-crypto-internal.h
> @@ -176,7 +176,7 @@ static inline void bio_crypt_do_front_merge(struct request *rq,
> blk_status_t __blk_crypto_rq_get_keyslot(struct request *rq);
> static inline blk_status_t blk_crypto_rq_get_keyslot(struct request *rq)
> {
> - if (blk_crypto_rq_is_encrypted(rq))
> + if (blk_crypto_rq_is_encrypted(rq) && rq->crypt_ctx->bc_key)
> return __blk_crypto_rq_get_keyslot(rq);
> return BLK_STS_OK;
> }
> diff --git a/block/blk-crypto.c b/block/blk-crypto.c
> index bc3a9f59574b..2212d06d3c11 100644
> --- a/block/blk-crypto.c
> +++ b/block/blk-crypto.c
> @@ -113,11 +113,31 @@ void bio_crypt_set_ctx(struct bio *bio, const struct blk_crypto_key *key,
>
> bc->bc_key = key;
> memcpy(bc->bc_dun, dun, sizeof(bc->bc_dun));
> + memset(&bc->bc_slot, 0, sizeof(bc->bc_slot));
>
> bio->bi_crypt_context = bc;
> }
> EXPORT_SYMBOL_GPL(bio_crypt_set_ctx);
>
> +void bio_crypt_set_ctx_by_slot(struct bio *bio,
> + const struct blk_crypto_slot *slot,
> + const u64 dun[BLK_CRYPTO_DUN_ARRAY_SIZE],
> + gfp_t gfp_mask)
> +{
> + struct bio_crypt_ctx *bc;
> +
> + WARN_ON_ONCE(!(gfp_mask & __GFP_DIRECT_RECLAIM));
> +
> + bc = mempool_alloc(bio_crypt_ctx_pool, gfp_mask);
> +
> + bc->bc_key = NULL;
> + bc->bc_slot = *slot;
> + memcpy(bc->bc_dun, dun, sizeof(bc->bc_dun));
> +
> + bio->bi_crypt_context = bc;
> +}
> +EXPORT_SYMBOL_GPL(bio_crypt_set_ctx_by_slot);
> +
> void __bio_crypt_free_ctx(struct bio *bio)
> {
> mempool_free(bio->bi_crypt_context, bio_crypt_ctx_pool);
> @@ -156,8 +176,12 @@ void __bio_crypt_advance(struct bio *bio, unsigned int bytes)
> {
> struct bio_crypt_ctx *bc = bio->bi_crypt_context;
>
> - bio_crypt_dun_increment(bc->bc_dun,
> - bytes >> bc->bc_key->data_unit_size_bits);
> + if (bc->bc_key)
> + bio_crypt_dun_increment(bc->bc_dun,
> + bytes >> bc->bc_key->data_unit_size_bits);
> + else if (bc->bc_slot.data_unit_size_bits)
> + bio_crypt_dun_increment(bc->bc_dun,
> + bytes >> bc->bc_slot.data_unit_size_bits);
> }
>
> /*
> @@ -169,7 +193,14 @@ bool bio_crypt_dun_is_contiguous(const struct bio_crypt_ctx *bc,
> const u64 next_dun[BLK_CRYPTO_DUN_ARRAY_SIZE])
> {
> int i;
> - unsigned int carry = bytes >> bc->bc_key->data_unit_size_bits;
> + unsigned int carry;
> +
> + if (bc->bc_key)
> + carry = bytes >> bc->bc_key->data_unit_size_bits;
> + else if (bc->bc_slot.data_unit_size_bits) {
> + carry = bytes >> bc->bc_slot.data_unit_size_bits;
> + } else
> + return false;
>
> for (i = 0; i < BLK_CRYPTO_DUN_ARRAY_SIZE; i++) {
> if (bc->bc_dun[i] + carry != next_dun[i])
> @@ -198,7 +229,12 @@ static bool bio_crypt_ctx_compatible(struct bio_crypt_ctx *bc1,
> if (!bc1)
> return !bc2;
>
> - return bc2 && bc1->bc_key == bc2->bc_key;
> + if (bc1->bc_key)
> + return bc2 && bc1->bc_key == bc2->bc_key;
> + else
> + return bc2 && !bc2->bc_key &&
> + bc1->bc_slot.phy_slot == bc2->bc_slot.phy_slot &&
> + bc1->bc_slot.data_unit_size_bits == bc2->bc_slot.data_unit_size_bits;
> }
>
> bool bio_crypt_rq_ctx_compatible(struct request *rq, struct bio *bio)
> @@ -260,6 +296,19 @@ bool __blk_crypto_submit_bio(struct bio *bio)
> return false;
> }
>
> + if (!bc_key) {
> + /*
> + * Slot path: the ICE keyslot was pre-programmed by the
> + * hypervisor. The target device must natively support inline
> + * encryption; there is no fallback for slot-based crypto.
> + */
> + if (!bdev_get_queue(bdev)->crypto_profile) {
> + bio_endio_status(bio, BLK_STS_NOTSUPP);
> + return false;
> + }
> + return true;
> + }
> +
> /*
> * If the device does not natively support the encryption context, try to use
> * the fallback if available.
> diff --git a/include/linux/blk-crypto.h b/include/linux/blk-crypto.h
> index 938ff536838c..33ae52b77522 100644
> --- a/include/linux/blk-crypto.h
> +++ b/include/linux/blk-crypto.h
> @@ -119,9 +119,28 @@ struct blk_crypto_key {
> #define BLK_CRYPTO_MAX_IV_SIZE 32
> #define BLK_CRYPTO_DUN_ARRAY_SIZE (BLK_CRYPTO_MAX_IV_SIZE / sizeof(u64))
>
> +/**
> + * struct blk_crypto_slot - physical slot context for slot-based inline crypto
> + * @phy_slot: Physical ICE keyslot index (already resolved from virt).
> + * @data_unit_size_bits: log2 of the encryption data unit size; used by
> + * __bio_crypt_advance() to increment the DUN correctly
> + * when a bio is split. 0 means unknown/unset.
> + *
> + * Used when a bio carries inline crypto context by physical slot index rather
> + * than by a blk_crypto_key pointer (i.e. bc_key == NULL in bio_crypt_ctx).
> + * Set by crypto_vblk when building the bio for a GVM VIRTIO_BLK_T_CRYPTO_IN/OUT
> + * request; left zeroed for all other bio types.
> + */
> +struct blk_crypto_slot {
> + unsigned int phy_slot;
> + unsigned int data_unit_size_bits;
> +};
> +
> /**
> * struct bio_crypt_ctx - an inline encryption context
> * @bc_key: the key, algorithm, and data unit size to use
> + * @bc_slot: physical slot + data_unit_size_bits for slot-based crypto
> + * (used when bc_key == NULL)
> * @bc_dun: the data unit number (starting IV) to use
> *
> * A bio_crypt_ctx specifies that the contents of the bio will be encrypted (for
> @@ -130,6 +149,7 @@ struct blk_crypto_key {
> */
> struct bio_crypt_ctx {
> const struct blk_crypto_key *bc_key;
> + struct blk_crypto_slot bc_slot;
> u64 bc_dun[BLK_CRYPTO_DUN_ARRAY_SIZE];
> };
>
> @@ -152,6 +172,11 @@ void bio_crypt_set_ctx(struct bio *bio, const struct blk_crypto_key *key,
> const u64 dun[BLK_CRYPTO_DUN_ARRAY_SIZE],
> gfp_t gfp_mask);
>
> +void bio_crypt_set_ctx_by_slot(struct bio *bio,
> + const struct blk_crypto_slot *slot,
> + const u64 dun[BLK_CRYPTO_DUN_ARRAY_SIZE],
> + gfp_t gfp_mask);
> +
> bool bio_crypt_dun_is_contiguous(const struct bio_crypt_ctx *bc,
> unsigned int bytes,
> const u64 next_dun[BLK_CRYPTO_DUN_ARRAY_SIZE]);
> --
> 2.34.1
>
Attachment:
signature.asc
Description: PGP signature