Re: [PATCH v2 2/3] dm-inlinecrypt: add target for inline block device encryption

2026-04-30 Thread Linlin Zhang



On 4/29/2026 11:58 PM, Benjamin Marzinski wrote:
> On Wed, Apr 29, 2026 at 11:25:04AM -0400, Benjamin Marzinski wrote:
>> On Wed, Apr 29, 2026 at 08:34:00PM +0800, Linlin Zhang wrote:
> [...]
>>>
>>> Thanks for the suggestions.
>>>
>>> Adding a bool need_acct parameter to __blk_crypto_submit_bio() would require
>>> updating all existing callers, which feels rather intrusive given that the
>>> accounting issue only affects the blk‑crypto fallback write slow‑path. I’m a
>>> bit concerned that this would broaden the scope of the change more than
>>> necessary for the problem at hand.
>>
>> I get your concern, and I'd like a second opinion on how much we should
>> care about this, but it doesn't look like there are many other callers
>> that would be effected here. The only existing caller of
>> __blk_crypto_submit_bio() is blk_crypto_submit_bio(), which would just
>> call it with "need_acct=true". Looking at the code path below
>> __blk_crypto_submit_bio() that would need to change for submitting the
>> bios:
>>
>> __blk_crypto_submit_bio() is the only caller of
>> blk_crypto_fallback_bio_prep()
>>
>> blk_crypto_fallback_bio_prep() is the only caller of
>> blk_crypto_fallback_encrypt_bio().
>>
>> blk_crypto_fallback_encrypt_bio() is the only caller of
>> __blk_crypto_fallback_encrypt_bio(), which is the function that would
>> need to choose between submit_bio() and submit_bio_noacct().
>>
>> Doing this would change the crypto API (by necessity, since we're adding
>> a new argument to __blk_crypto_submit_bio() for stacking devices to
>> use), and it is adds a extra argument to a number of functions, just to
>> handle this corner case. But it is still a relatively contained change.
> 
> Having discussed this a bit, I'm fine with leaving this as a TODO for
> now. If anyone wants to chime in with an opinion on how acceptable it
> would be to add a new bio flag for skipping accounting, that would be
> great.

Thanks, Ben.

I’d appreciate it if someone else could chime in on these two approaches.

> 
> -Ben 
> 




Re: [PATCH v2 2/3] dm-inlinecrypt: add target for inline block device encryption

2026-04-29 Thread Benjamin Marzinski
On Wed, Apr 29, 2026 at 11:25:04AM -0400, Benjamin Marzinski wrote:
> On Wed, Apr 29, 2026 at 08:34:00PM +0800, Linlin Zhang wrote:
[...]
> > 
> > Thanks for the suggestions.
> > 
> > Adding a bool need_acct parameter to __blk_crypto_submit_bio() would require
> > updating all existing callers, which feels rather intrusive given that the
> > accounting issue only affects the blk‑crypto fallback write slow‑path. I’m a
> > bit concerned that this would broaden the scope of the change more than
> > necessary for the problem at hand.
> 
> I get your concern, and I'd like a second opinion on how much we should
> care about this, but it doesn't look like there are many other callers
> that would be effected here. The only existing caller of
> __blk_crypto_submit_bio() is blk_crypto_submit_bio(), which would just
> call it with "need_acct=true". Looking at the code path below
> __blk_crypto_submit_bio() that would need to change for submitting the
> bios:
> 
> __blk_crypto_submit_bio() is the only caller of
> blk_crypto_fallback_bio_prep()
> 
> blk_crypto_fallback_bio_prep() is the only caller of
> blk_crypto_fallback_encrypt_bio().
> 
> blk_crypto_fallback_encrypt_bio() is the only caller of
> __blk_crypto_fallback_encrypt_bio(), which is the function that would
> need to choose between submit_bio() and submit_bio_noacct().
> 
> Doing this would change the crypto API (by necessity, since we're adding
> a new argument to __blk_crypto_submit_bio() for stacking devices to
> use), and it is adds a extra argument to a number of functions, just to
> handle this corner case. But it is still a relatively contained change.

Having discussed this a bit, I'm fine with leaving this as a TODO for
now. If anyone wants to chime in with an opinion on how acceptable it
would be to add a new bio flag for skipping accounting, that would be
great.

-Ben 




Re: [PATCH v2 2/3] dm-inlinecrypt: add target for inline block device encryption

2026-04-29 Thread Benjamin Marzinski
On Wed, Apr 29, 2026 at 08:34:00PM +0800, Linlin Zhang wrote:
> 
> 
> On 4/29/2026 12:36 AM, Benjamin Marzinski wrote:
> > On Tue, Apr 28, 2026 at 05:20:07PM +0800, Linlin Zhang wrote:
> >>
> >>
> >> On 4/28/2026 7:21 AM, Benjamin Marzinski wrote:
> >>> On Mon, Apr 27, 2026 at 01:23:27AM -0400, Benjamin Marzinski wrote:
>  On Fri, Apr 10, 2026 at 06:40:30AM -0700, Linlin Zhang wrote:
> > From: Eric Biggers 
> > +   /*
> > +* Since we've added an encryption context to the bio and
> > +* blk-crypto-fallback may be needed to process it, it's 
> > necessary to
> > +* use the fallback-aware bio submission code rather than
> > +* unconditionally returning DM_MAPIO_REMAPPED.
> > +*
> > +* To get the correct accounting for a dm target in the case 
> > where
> > +* __blk_crypto_submit_bio() doesn't take ownership of the bio 
> > (returns
> > +* true), call __blk_crypto_submit_bio() directly and return
> > +* DM_MAPIO_REMAPPED in that case, rather than relying on
> > +* blk_crypto_submit_bio() which calls submit_bio() in that 
> > case.
> > +*/
> > +   if (__blk_crypto_submit_bio(bio))
> 
>  This will still double account for fallback writes (which call
>  submit_bio() on the encrypted bios, and return DM_MAPIO_SUBMITTED here). 
> >>>
> >>> Just to clarify, I'm talking about the vmstats accounting. The IO
> >>> originally gets accounted by submit_bio() when the bio is submitted to
> >>> the dm device. For actual inline encryption and fallback reads, dm will
> >>> submit the bio to the underlying device using submit_bio_noacct() to
> >>> avoid double-counting the IO.
> >>>
> >>> For fallback writes, __blk_crypto_submit_bio() will submit the encrypted
> >>> bios to the underlying device with submit_bio(). This adds the IO
> >>> sectors again, even though it's the same IO, only encrypted now.
> >>
> >>
> >> Right, thanks for calling this out.
> >>
> >> For fallback writes, the IO is still double-counted. Given that this only
> >> affects IO accounting in the blk-crypto fallback write slow-path and not
> >> correctness, I think this is an acceptable tradeoff, and we can leave a
> >> TODO to revisit the accounting once a better solution exists.
> >>
> >> Add the bellow to the annotate.
> >>
> >>   /*
> >>* TODO: blk-crypto fallback write slow-path currently double-accounts
> >>* IO in vmstat, as encrypted bios are submitted via submit_bio().
> >>* This does not affect data correctness. Consider fixing this if
> >>* a cleaner accounting model for derived bios is introduced.
> >>*/
> >>
> >> Do you agree?
> > 
> > You could add an extra argument, for instance "bool need_acct", to
> > __blk_crypto_submit_bio(), and plumb it through to
> > __blk_crypto_fallback_encrypt_bio(), where it could be used to choose
> > between calling submit_bio() and and submit_bio_noacct().
> > 
> > We could even add a flag to cloned bios for stacked devices, that could
> > be checked in submit_bio(), so we didn't need to have
> > submit_bio_noacct(). But this is a pretty niche case with other
> > solutions, so I'm not sure if it warrants adding more checks to
> > submit_bio().
> > 
> > I do agree that people probably aren't using dm-inlinecrypt for devices
> > where they don't actually have inline encryption capabilities, so it's
> > not a major issue. What to you think, Mikulas?
> 
> Thanks for the suggestions.
> 
> Adding a bool need_acct parameter to __blk_crypto_submit_bio() would require
> updating all existing callers, which feels rather intrusive given that the
> accounting issue only affects the blk‑crypto fallback write slow‑path. I’m a
> bit concerned that this would broaden the scope of the change more than
> necessary for the problem at hand.

I get your concern, and I'd like a second opinion on how much we should
care about this, but it doesn't look like there are many other callers
that would be effected here. The only existing caller of
__blk_crypto_submit_bio() is blk_crypto_submit_bio(), which would just
call it with "need_acct=true". Looking at the code path below
__blk_crypto_submit_bio() that would need to change for submitting the
bios:

__blk_crypto_submit_bio() is the only caller of
blk_crypto_fallback_bio_prep()

blk_crypto_fallback_bio_prep() is the only caller of
blk_crypto_fallback_encrypt_bio().

blk_crypto_fallback_encrypt_bio() is the only caller of
__blk_crypto_fallback_encrypt_bio(), which is the function that would
need to choose between submit_bio() and submit_bio_noacct().

Doing this would change the crypto API (by necessity, since we're adding
a new argument to __blk_crypto_submit_bio() for stacking devices to
use), and it is adds a extra argument to a number of functions, just to
handle this corner case. But it is still a relatively contained change.

-Ben 




Re: [PATCH v2 2/3] dm-inlinecrypt: add target for inline block device encryption

2026-04-29 Thread Linlin Zhang



On 4/29/2026 12:36 AM, Benjamin Marzinski wrote:
> On Tue, Apr 28, 2026 at 05:20:07PM +0800, Linlin Zhang wrote:
>>
>>
>> On 4/28/2026 7:21 AM, Benjamin Marzinski wrote:
>>> On Mon, Apr 27, 2026 at 01:23:27AM -0400, Benjamin Marzinski wrote:
 On Fri, Apr 10, 2026 at 06:40:30AM -0700, Linlin Zhang wrote:
> From: Eric Biggers 
> + /*
> +  * Since we've added an encryption context to the bio and
> +  * blk-crypto-fallback may be needed to process it, it's necessary to
> +  * use the fallback-aware bio submission code rather than
> +  * unconditionally returning DM_MAPIO_REMAPPED.
> +  *
> +  * To get the correct accounting for a dm target in the case where
> +  * __blk_crypto_submit_bio() doesn't take ownership of the bio (returns
> +  * true), call __blk_crypto_submit_bio() directly and return
> +  * DM_MAPIO_REMAPPED in that case, rather than relying on
> +  * blk_crypto_submit_bio() which calls submit_bio() in that case.
> +  */
> + if (__blk_crypto_submit_bio(bio))

 This will still double account for fallback writes (which call
 submit_bio() on the encrypted bios, and return DM_MAPIO_SUBMITTED here). 
>>>
>>> Just to clarify, I'm talking about the vmstats accounting. The IO
>>> originally gets accounted by submit_bio() when the bio is submitted to
>>> the dm device. For actual inline encryption and fallback reads, dm will
>>> submit the bio to the underlying device using submit_bio_noacct() to
>>> avoid double-counting the IO.
>>>
>>> For fallback writes, __blk_crypto_submit_bio() will submit the encrypted
>>> bios to the underlying device with submit_bio(). This adds the IO
>>> sectors again, even though it's the same IO, only encrypted now.
>>
>>
>> Right, thanks for calling this out.
>>
>> For fallback writes, the IO is still double-counted. Given that this only
>> affects IO accounting in the blk-crypto fallback write slow-path and not
>> correctness, I think this is an acceptable tradeoff, and we can leave a
>> TODO to revisit the accounting once a better solution exists.
>>
>> Add the bellow to the annotate.
>>
>>   /*
>>* TODO: blk-crypto fallback write slow-path currently double-accounts
>>* IO in vmstat, as encrypted bios are submitted via submit_bio().
>>* This does not affect data correctness. Consider fixing this if
>>* a cleaner accounting model for derived bios is introduced.
>>*/
>>
>> Do you agree?
> 
> You could add an extra argument, for instance "bool need_acct", to
> __blk_crypto_submit_bio(), and plumb it through to
> __blk_crypto_fallback_encrypt_bio(), where it could be used to choose
> between calling submit_bio() and and submit_bio_noacct().
> 
> We could even add a flag to cloned bios for stacked devices, that could
> be checked in submit_bio(), so we didn't need to have
> submit_bio_noacct(). But this is a pretty niche case with other
> solutions, so I'm not sure if it warrants adding more checks to
> submit_bio().
> 
> I do agree that people probably aren't using dm-inlinecrypt for devices
> where they don't actually have inline encryption capabilities, so it's
> not a major issue. What to you think, Mikulas?

Thanks for the suggestions.

Adding a bool need_acct parameter to __blk_crypto_submit_bio() would require
updating all existing callers, which feels rather intrusive given that the
accounting issue only affects the blk‑crypto fallback write slow‑path. I’m a
bit concerned that this would broaden the scope of the change more than
necessary for the problem at hand.

An alternative might be to track this at the bio level instead — for example,
by introducing a bio flag or metadata that indicates whether accounting should
be charged for a derived/cloned bio. That would avoid having to thread 
additional
parameters through multiple blk‑crypto entry points. However, this likely needs
a broader discussion to make sure it fits well with existing stacking and
accounting semantics.

Also, as discussed, the current behavior does not affect data correctness; it
only results in double vmstat accounting for fallback writes. Given that
dm‑inlinecrypt is expected to be used primarily on devices with actual inline
encryption support, the fallback write path should be relatively uncommon in
practice.

With that in mind, would it be acceptable to merge the current change as‑is,
with an explicit TODO documenting the double‑accounting in the fallback write 
path,
and revisit the accounting model in a follow‑up patch once we have agreement on 
a
cleaner solution? What do you think, Ben and Mikulas?

Happy to iterate further if there’s a preferred direction here. 

> 
> -Ben
>  
>>>
>>> -Ben
>>>

 -Ben

> + return DM_MAPIO_REMAPPED;
> + return DM_MAPIO_SUBMITTED;
> +}

>>>
> 




Re: [PATCH v2 2/3] dm-inlinecrypt: add target for inline block device encryption

2026-04-29 Thread Linlin Zhang



On 4/29/2026 12:20 AM, Benjamin Marzinski wrote:
> On Tue, Apr 28, 2026 at 06:43:08PM +0800, Linlin Zhang wrote:
>> Correct the response to Benjamin's comments.
>>
>> On 4/27/2026 8:20 PM, Linlin Zhang wrote:
>>>
>>>
>>> On 4/27/2026 9:19 AM, Benjamin Marzinski wrote:
 On Fri, Apr 10, 2026 at 06:40:30AM -0700, Linlin Zhang wrote:
> From: Eric Biggers 
> +
> +static int inlinecrypt_map(struct dm_target *ti, struct bio *bio)
> +{
> + const struct inlinecrypt_ctx *ctx = ti->private;
> + sector_t sector_in_target;
> + u64 dun[BLK_CRYPTO_DUN_ARRAY_SIZE] = {};
> +
> + bio_set_dev(bio, ctx->dev->bdev);
> +
> + /*
> +  * If the bio is a device-level request which doesn't target a specific
> +  * sector, there's nothing more to do.
> +  */
> + if (bio_sectors(bio) == 0)
> + return DM_MAPIO_REMAPPED;
> +
> + /*
> +  * The bio should never have an encryption context already, since
> +  * dm-inlinecrypt doesn't pass through any inline encryption
> +  * capabilities to the layer above it.
> +  */
> + if (WARN_ON_ONCE(bio_has_crypt_ctx(bio)))
> + return DM_MAPIO_KILL;
> +
> + /* Map the bio's sector to the underlying device. (512-byte sectors) */
> + sector_in_target = dm_target_offset(ti, bio->bi_iter.bi_sector);
> + bio->bi_iter.bi_sector = ctx->start + sector_in_target;
> + /*
> +  * If the bio doesn't have any data (e.g. if it's a DISCARD request),
> +  * there's nothing more to do.
> +  */
> + if (!bio_has_data(bio))
> + return DM_MAPIO_REMAPPED;
> +
> + /* Calculate the DUN and enforce data-unit (crypto sector) alignment. */
> + dun[0] = ctx->iv_offset + sector_in_target; /* 512-byte sectors */
> + if (dun[0] & ((ctx->sector_size >> SECTOR_SHIFT) - 1))
> + return DM_MAPIO_KILL;

 If ctx->iv_offset is not a multiple of ctx->sector_size, this will
 always fail. ctx->iv_offset should probably get validated in
 inlinecrypt_ctr()
>>>
>>> ACK
>>>
>>> Yes, this assumes iv_offset is aligned to sector_size when large crypto
>>> sectors are used. That’s a requirement of dm-inlinecrypt semantics, and
>>> adding an explicit check in inlinecrypt_ctr() would make this fail earlier
>>> and more clearly.
>>
>> Sorry, the last response is wrong. No need to add check in inlinecrypt_ctr().
>>
>> iv_offset is the starting offset for IVs that are generated as if the target 
>> were
>> preceded by iv_offset 512-byte sectors.
>>
>> I think this concern is based on an implicit assumption that
>> sector_in_target is always data-unit (crypto sector) aligned. In this
>> target, however, sector_in_target is derived from dm_target_offset() and
>> is in 512-byte sectors, so it is not guaranteed to be a multiple of
>> (sector_size >> SECTOR_SHIFT).
> 
> sector_in_target should be guaranteed to be sector_size aligned.
> inlinecrypt_io_hints() sets the device logical block size to at least
> ctx->sector_size, and validate_hardware_logical_block_alignment() makes
> sure that the target starts on a logical block boundary. The block
> layer enforces IO to be aligned with the logical block size, so
> an IO that starts 7 sectors into a device with a 4096 ctx->sector_size
> should be impossible. 

Thanks for the detailed clarification!

In the next patch, I will add an explicit alignment check in ctr() to ensure 
that
iv_offset is aligned to the configured sector size. For example:

if (ctx->iv_offset & ((ctx->sector_size >> SECTOR_SHIFT) - 1)) {
ti->error = "Wrong alignment of iv_offset sector";
err = -EINVAL;
}

Please let me know if you would like this validation to be handled differently,
or if additional checks are needed.

> 
> -Ben
> 




Re: [PATCH v2 2/3] dm-inlinecrypt: add target for inline block device encryption

2026-04-28 Thread Benjamin Marzinski
On Tue, Apr 28, 2026 at 05:20:07PM +0800, Linlin Zhang wrote:
> 
> 
> On 4/28/2026 7:21 AM, Benjamin Marzinski wrote:
> > On Mon, Apr 27, 2026 at 01:23:27AM -0400, Benjamin Marzinski wrote:
> >> On Fri, Apr 10, 2026 at 06:40:30AM -0700, Linlin Zhang wrote:
> >>> From: Eric Biggers 
> >>> + /*
> >>> +  * Since we've added an encryption context to the bio and
> >>> +  * blk-crypto-fallback may be needed to process it, it's necessary to
> >>> +  * use the fallback-aware bio submission code rather than
> >>> +  * unconditionally returning DM_MAPIO_REMAPPED.
> >>> +  *
> >>> +  * To get the correct accounting for a dm target in the case where
> >>> +  * __blk_crypto_submit_bio() doesn't take ownership of the bio (returns
> >>> +  * true), call __blk_crypto_submit_bio() directly and return
> >>> +  * DM_MAPIO_REMAPPED in that case, rather than relying on
> >>> +  * blk_crypto_submit_bio() which calls submit_bio() in that case.
> >>> +  */
> >>> + if (__blk_crypto_submit_bio(bio))
> >>
> >> This will still double account for fallback writes (which call
> >> submit_bio() on the encrypted bios, and return DM_MAPIO_SUBMITTED here). 
> > 
> > Just to clarify, I'm talking about the vmstats accounting. The IO
> > originally gets accounted by submit_bio() when the bio is submitted to
> > the dm device. For actual inline encryption and fallback reads, dm will
> > submit the bio to the underlying device using submit_bio_noacct() to
> > avoid double-counting the IO.
> > 
> > For fallback writes, __blk_crypto_submit_bio() will submit the encrypted
> > bios to the underlying device with submit_bio(). This adds the IO
> > sectors again, even though it's the same IO, only encrypted now.
> 
> 
> Right, thanks for calling this out.
> 
> For fallback writes, the IO is still double-counted. Given that this only
> affects IO accounting in the blk-crypto fallback write slow-path and not
> correctness, I think this is an acceptable tradeoff, and we can leave a
> TODO to revisit the accounting once a better solution exists.
> 
> Add the bellow to the annotate.
> 
>   /*
>* TODO: blk-crypto fallback write slow-path currently double-accounts
>* IO in vmstat, as encrypted bios are submitted via submit_bio().
>* This does not affect data correctness. Consider fixing this if
>* a cleaner accounting model for derived bios is introduced.
>*/
> 
> Do you agree?

You could add an extra argument, for instance "bool need_acct", to
__blk_crypto_submit_bio(), and plumb it through to
__blk_crypto_fallback_encrypt_bio(), where it could be used to choose
between calling submit_bio() and and submit_bio_noacct().

We could even add a flag to cloned bios for stacked devices, that could
be checked in submit_bio(), so we didn't need to have
submit_bio_noacct(). But this is a pretty niche case with other
solutions, so I'm not sure if it warrants adding more checks to
submit_bio().

I do agree that people probably aren't using dm-inlinecrypt for devices
where they don't actually have inline encryption capabilities, so it's
not a major issue. What to you think, Mikulas?

-Ben
 
> > 
> > -Ben
> > 
> >>
> >> -Ben
> >>
> >>> + return DM_MAPIO_REMAPPED;
> >>> + return DM_MAPIO_SUBMITTED;
> >>> +}
> >>
> > 




Re: [PATCH v2 2/3] dm-inlinecrypt: add target for inline block device encryption

2026-04-28 Thread Benjamin Marzinski
On Tue, Apr 28, 2026 at 06:43:08PM +0800, Linlin Zhang wrote:
> Correct the response to Benjamin's comments.
> 
> On 4/27/2026 8:20 PM, Linlin Zhang wrote:
> > 
> > 
> > On 4/27/2026 9:19 AM, Benjamin Marzinski wrote:
> >> On Fri, Apr 10, 2026 at 06:40:30AM -0700, Linlin Zhang wrote:
> >>> From: Eric Biggers 
> >>> +
> >>> +static int inlinecrypt_map(struct dm_target *ti, struct bio *bio)
> >>> +{
> >>> + const struct inlinecrypt_ctx *ctx = ti->private;
> >>> + sector_t sector_in_target;
> >>> + u64 dun[BLK_CRYPTO_DUN_ARRAY_SIZE] = {};
> >>> +
> >>> + bio_set_dev(bio, ctx->dev->bdev);
> >>> +
> >>> + /*
> >>> +  * If the bio is a device-level request which doesn't target a specific
> >>> +  * sector, there's nothing more to do.
> >>> +  */
> >>> + if (bio_sectors(bio) == 0)
> >>> + return DM_MAPIO_REMAPPED;
> >>> +
> >>> + /*
> >>> +  * The bio should never have an encryption context already, since
> >>> +  * dm-inlinecrypt doesn't pass through any inline encryption
> >>> +  * capabilities to the layer above it.
> >>> +  */
> >>> + if (WARN_ON_ONCE(bio_has_crypt_ctx(bio)))
> >>> + return DM_MAPIO_KILL;
> >>> +
> >>> + /* Map the bio's sector to the underlying device. (512-byte sectors) */
> >>> + sector_in_target = dm_target_offset(ti, bio->bi_iter.bi_sector);
> >>> + bio->bi_iter.bi_sector = ctx->start + sector_in_target;
> >>> + /*
> >>> +  * If the bio doesn't have any data (e.g. if it's a DISCARD request),
> >>> +  * there's nothing more to do.
> >>> +  */
> >>> + if (!bio_has_data(bio))
> >>> + return DM_MAPIO_REMAPPED;
> >>> +
> >>> + /* Calculate the DUN and enforce data-unit (crypto sector) alignment. */
> >>> + dun[0] = ctx->iv_offset + sector_in_target; /* 512-byte sectors */
> >>> + if (dun[0] & ((ctx->sector_size >> SECTOR_SHIFT) - 1))
> >>> + return DM_MAPIO_KILL;
> >>
> >> If ctx->iv_offset is not a multiple of ctx->sector_size, this will
> >> always fail. ctx->iv_offset should probably get validated in
> >> inlinecrypt_ctr()
> > 
> > ACK
> > 
> > Yes, this assumes iv_offset is aligned to sector_size when large crypto
> > sectors are used. That’s a requirement of dm-inlinecrypt semantics, and
> > adding an explicit check in inlinecrypt_ctr() would make this fail earlier
> > and more clearly.
> 
> Sorry, the last response is wrong. No need to add check in inlinecrypt_ctr().
> 
> iv_offset is the starting offset for IVs that are generated as if the target 
> were
> preceded by iv_offset 512-byte sectors.
> 
> I think this concern is based on an implicit assumption that
> sector_in_target is always data-unit (crypto sector) aligned. In this
> target, however, sector_in_target is derived from dm_target_offset() and
> is in 512-byte sectors, so it is not guaranteed to be a multiple of
> (sector_size >> SECTOR_SHIFT).

sector_in_target should be guaranteed to be sector_size aligned.
inlinecrypt_io_hints() sets the device logical block size to at least
ctx->sector_size, and validate_hardware_logical_block_alignment() makes
sure that the target starts on a logical block boundary. The block
layer enforces IO to be aligned with the logical block size, so
an IO that starts 7 sectors into a device with a 4096 ctx->sector_size
should be impossible. 

-Ben




Re: [PATCH v2 2/3] dm-inlinecrypt: add target for inline block device encryption

2026-04-28 Thread Linlin Zhang
Correct the response to Benjamin's comments.

On 4/27/2026 8:20 PM, Linlin Zhang wrote:
> 
> 
> On 4/27/2026 9:19 AM, Benjamin Marzinski wrote:
>> On Fri, Apr 10, 2026 at 06:40:30AM -0700, Linlin Zhang wrote:
>>> From: Eric Biggers 
>>> +
>>> +static int inlinecrypt_map(struct dm_target *ti, struct bio *bio)
>>> +{
>>> +   const struct inlinecrypt_ctx *ctx = ti->private;
>>> +   sector_t sector_in_target;
>>> +   u64 dun[BLK_CRYPTO_DUN_ARRAY_SIZE] = {};
>>> +
>>> +   bio_set_dev(bio, ctx->dev->bdev);
>>> +
>>> +   /*
>>> +* If the bio is a device-level request which doesn't target a specific
>>> +* sector, there's nothing more to do.
>>> +*/
>>> +   if (bio_sectors(bio) == 0)
>>> +   return DM_MAPIO_REMAPPED;
>>> +
>>> +   /*
>>> +* The bio should never have an encryption context already, since
>>> +* dm-inlinecrypt doesn't pass through any inline encryption
>>> +* capabilities to the layer above it.
>>> +*/
>>> +   if (WARN_ON_ONCE(bio_has_crypt_ctx(bio)))
>>> +   return DM_MAPIO_KILL;
>>> +
>>> +   /* Map the bio's sector to the underlying device. (512-byte sectors) */
>>> +   sector_in_target = dm_target_offset(ti, bio->bi_iter.bi_sector);
>>> +   bio->bi_iter.bi_sector = ctx->start + sector_in_target;
>>> +   /*
>>> +* If the bio doesn't have any data (e.g. if it's a DISCARD request),
>>> +* there's nothing more to do.
>>> +*/
>>> +   if (!bio_has_data(bio))
>>> +   return DM_MAPIO_REMAPPED;
>>> +
>>> +   /* Calculate the DUN and enforce data-unit (crypto sector) alignment. */
>>> +   dun[0] = ctx->iv_offset + sector_in_target; /* 512-byte sectors */
>>> +   if (dun[0] & ((ctx->sector_size >> SECTOR_SHIFT) - 1))
>>> +   return DM_MAPIO_KILL;
>>
>> If ctx->iv_offset is not a multiple of ctx->sector_size, this will
>> always fail. ctx->iv_offset should probably get validated in
>> inlinecrypt_ctr()
> 
> ACK
> 
> Yes, this assumes iv_offset is aligned to sector_size when large crypto
> sectors are used. That’s a requirement of dm-inlinecrypt semantics, and
> adding an explicit check in inlinecrypt_ctr() would make this fail earlier
> and more clearly.

Sorry, the last response is wrong. No need to add check in inlinecrypt_ctr().

iv_offset is the starting offset for IVs that are generated as if the target 
were
preceded by iv_offset 512-byte sectors.

I think this concern is based on an implicit assumption that
sector_in_target is always data-unit (crypto sector) aligned. In this
target, however, sector_in_target is derived from dm_target_offset() and
is in 512-byte sectors, so it is not guaranteed to be a multiple of
(sector_size >> SECTOR_SHIFT).

The intended alignment requirement is on the *final* DUN, i.e. on
(iv_offset + sector_in_target) in 512-byte sector units, before it gets
shifted down to crypto-sector units. That's why the code checks alignment
on the sum (iv_offset + sector_in_target).

With this definition, iv_offset itself does not need to be aligned to the
data-unit size; any non-negative value is valid as long as the resulting
DUN for a given bio is data-unit aligned. For example, iv_offset = 1 can
still be valid when sector_in_target is 7 (4096-byte sector case), since
their sum is aligned. Validating iv_offset alone in inlinecrypt_ctr()
would therefore reject configurations that are otherwise correct per the
(sum-based) DUN definition.

So I believe the runtime check in ->map() is the right place to enforce
the data-unit alignment constraint, as it has the actual bio offset
(sector_in_target) needed to evaluate the constraint.

Let me know if you'd prefer we document this more explicitly in the map()
argument description; I'm fine adding a short note about the
iv_offset units and the sum-based alignment rule.

> 
>>
>> -Ben
>>
>>> +   dun[0] >>= ctx->sector_bits - SECTOR_SHIFT; /* crypto sectors */
>>> +
>>> +   /*
>>> +* This check isn't necessary as we should have calculated max_dun
>>> +* correctly, but be safe.
>>> +*/
>>> +   if (WARN_ON_ONCE(dun[0] > ctx->max_dun))
>>> +   return DM_MAPIO_KILL;
>>> +
>>> +   bio_crypt_set_ctx(bio, &ctx->key, dun, GFP_NOIO);
>>> +
>>> +   /*
>>> +* Since we've added an encryption context to the bio and
>>> +* blk-crypto-fallback may be needed to process it, it's necessary to
>>> +* use the fallback-aware bio submission code rather than
>>> +* unconditionally returning DM_MAPIO_REMAPPED.
>>> +*
>>> +* To get the correct accounting for a dm target in the case where
>>> +* __blk_crypto_submit_bio() doesn't take ownership of the bio (returns
>>> +* true), call __blk_crypto_submit_bio() directly and return
>>> +* DM_MAPIO_REMAPPED in that case, rather than relying on
>>> +* blk_crypto_submit_bio() which calls submit_bio() in that case.
>>> +*/
>>> +   if (__blk_crypto_submit_bio(bio))
>>> +   return DM_MAPIO_REMAPPED;
>>> +   return DM_MAPIO_SUBMITTED;
>>> +}
>>> +
 
>>> +MODULE_AUTHOR("Eric Biggers ");
>>> +MO

Re: [PATCH v2 2/3] dm-inlinecrypt: add target for inline block device encryption

2026-04-28 Thread Linlin Zhang



On 4/28/2026 7:21 AM, Benjamin Marzinski wrote:
> On Mon, Apr 27, 2026 at 01:23:27AM -0400, Benjamin Marzinski wrote:
>> On Fri, Apr 10, 2026 at 06:40:30AM -0700, Linlin Zhang wrote:
>>> From: Eric Biggers 
>>> +   /*
>>> +* Since we've added an encryption context to the bio and
>>> +* blk-crypto-fallback may be needed to process it, it's necessary to
>>> +* use the fallback-aware bio submission code rather than
>>> +* unconditionally returning DM_MAPIO_REMAPPED.
>>> +*
>>> +* To get the correct accounting for a dm target in the case where
>>> +* __blk_crypto_submit_bio() doesn't take ownership of the bio (returns
>>> +* true), call __blk_crypto_submit_bio() directly and return
>>> +* DM_MAPIO_REMAPPED in that case, rather than relying on
>>> +* blk_crypto_submit_bio() which calls submit_bio() in that case.
>>> +*/
>>> +   if (__blk_crypto_submit_bio(bio))
>>
>> This will still double account for fallback writes (which call
>> submit_bio() on the encrypted bios, and return DM_MAPIO_SUBMITTED here). 
> 
> Just to clarify, I'm talking about the vmstats accounting. The IO
> originally gets accounted by submit_bio() when the bio is submitted to
> the dm device. For actual inline encryption and fallback reads, dm will
> submit the bio to the underlying device using submit_bio_noacct() to
> avoid double-counting the IO.
> 
> For fallback writes, __blk_crypto_submit_bio() will submit the encrypted
> bios to the underlying device with submit_bio(). This adds the IO
> sectors again, even though it's the same IO, only encrypted now.


Right, thanks for calling this out.

For fallback writes, the IO is still double-counted. Given that this only
affects IO accounting in the blk-crypto fallback write slow-path and not
correctness, I think this is an acceptable tradeoff, and we can leave a
TODO to revisit the accounting once a better solution exists.

Add the bellow to the annotate.

  /*
   * TODO: blk-crypto fallback write slow-path currently double-accounts
   * IO in vmstat, as encrypted bios are submitted via submit_bio().
   * This does not affect data correctness. Consider fixing this if
   * a cleaner accounting model for derived bios is introduced.
   */

Do you agree?

> 
> -Ben
> 
>>
>> -Ben
>>
>>> +   return DM_MAPIO_REMAPPED;
>>> +   return DM_MAPIO_SUBMITTED;
>>> +}
>>
> 




Re: [PATCH v2 2/3] dm-inlinecrypt: add target for inline block device encryption

2026-04-27 Thread Benjamin Marzinski
On Mon, Apr 27, 2026 at 01:23:27AM -0400, Benjamin Marzinski wrote:
> On Fri, Apr 10, 2026 at 06:40:30AM -0700, Linlin Zhang wrote:
> > From: Eric Biggers 
> > +   /*
> > +* Since we've added an encryption context to the bio and
> > +* blk-crypto-fallback may be needed to process it, it's necessary to
> > +* use the fallback-aware bio submission code rather than
> > +* unconditionally returning DM_MAPIO_REMAPPED.
> > +*
> > +* To get the correct accounting for a dm target in the case where
> > +* __blk_crypto_submit_bio() doesn't take ownership of the bio (returns
> > +* true), call __blk_crypto_submit_bio() directly and return
> > +* DM_MAPIO_REMAPPED in that case, rather than relying on
> > +* blk_crypto_submit_bio() which calls submit_bio() in that case.
> > +*/
> > +   if (__blk_crypto_submit_bio(bio))
> 
> This will still double account for fallback writes (which call
> submit_bio() on the encrypted bios, and return DM_MAPIO_SUBMITTED here). 

Just to clarify, I'm talking about the vmstats accounting. The IO
originally gets accounted by submit_bio() when the bio is submitted to
the dm device. For actual inline encryption and fallback reads, dm will
submit the bio to the underlying device using submit_bio_noacct() to
avoid double-counting the IO.

For fallback writes, __blk_crypto_submit_bio() will submit the encrypted
bios to the underlying device with submit_bio(). This adds the IO
sectors again, even though it's the same IO, only encrypted now.

-Ben

> 
> -Ben
> 
> > +   return DM_MAPIO_REMAPPED;
> > +   return DM_MAPIO_SUBMITTED;
> > +}
> 




Re: [PATCH v2 2/3] dm-inlinecrypt: add target for inline block device encryption

2026-04-27 Thread Linlin Zhang



On 4/27/2026 9:19 AM, Benjamin Marzinski wrote:
> On Fri, Apr 10, 2026 at 06:40:30AM -0700, Linlin Zhang wrote:
>> From: Eric Biggers 
>>
>> Add a new device-mapper target "dm-inlinecrypt" that is similar to
>> dm-crypt but uses the blk-crypto API instead of the regular crypto API.
>> This allows it to take advantage of inline encryption hardware such as
>> that commonly built into UFS host controllers.
>>
>> The table syntax matches dm-crypt's, but for now only a stripped-down
>> set of parameters is supported.  For example, for now AES-256-XTS is the
>> only supported cipher.
>>
>> dm-inlinecrypt is based on Android's dm-default-key with the
>> controversial passthrough support removed.  Note that due to the removal
>> of passthrough support, use of dm-inlinecrypt in combination with
>> fscrypt causes double encryption of file contents (similar to dm-crypt +
>> fscrypt), with the fscrypt layer not being able to use the inline
>> encryption hardware.  This makes dm-inlinecrypt unusable on systems such
>> as Android that use fscrypt and where a more optimized approach is
>> needed.  It is however suitable as a replacement for dm-crypt.
>>
>> dm-inlinecrypt supports both keyring key and hex key, the former avoids
>> the key to be exposed in dm-table message. Similar to dm-default-key in
>> Android, it will fallabck to the software block crypto once the inline
>> crypto hardware cannot support the expected cipher.
>>
>> Test:
>> dmsetup create inlinecrypt_logon --table "0 `blockdev --getsz $1` \
>> inlinecrypt aes-xts-plain64 :64:logon:fde:dminlinecrypt_test_key 0 $1 0"
>>
>> Signed-off-by: Eric Biggers 
>> Signed-off-by: Linlin Zhang 
>> ---
>>  drivers/md/Kconfig  |  10 +
>>  drivers/md/Makefile |   1 +
>>  drivers/md/dm-inlinecrypt.c | 559 
>>  3 files changed, 570 insertions(+)
>>  create mode 100644 drivers/md/dm-inlinecrypt.c
>>
>> diff --git a/drivers/md/Kconfig b/drivers/md/Kconfig
>> index c58a9a8ea54e..aa541cc22ecc 100644
>> --- a/drivers/md/Kconfig
>> +++ b/drivers/md/Kconfig
>> @@ -313,6 +313,16 @@ config DM_CRYPT
>>  
>>If unsure, say N.
>>  
>> +config DM_INLINECRYPT
>> +tristate "Inline encryption target support"
>> +depends on BLK_DEV_DM
>> +depends on BLK_INLINE_ENCRYPTION
>> +help
>> +  This device-mapper target is similar to dm-crypt, but it uses the
>> +  blk-crypto API instead of the regular crypto API. This allows it to
>> +  take advantage of inline encryption hardware such as that commonly
>> +  built into UFS host controllers.
>> +
>>  config DM_SNAPSHOT
>> tristate "Snapshot target"
>> depends on BLK_DEV_DM
>> diff --git a/drivers/md/Makefile b/drivers/md/Makefile
>> index c338cc6fbe2e..517d1f7d8288 100644
>> --- a/drivers/md/Makefile
>> +++ b/drivers/md/Makefile
>> @@ -55,6 +55,7 @@ obj-$(CONFIG_DM_UNSTRIPED) += dm-unstripe.o
>>  obj-$(CONFIG_DM_BUFIO)  += dm-bufio.o
>>  obj-$(CONFIG_DM_BIO_PRISON) += dm-bio-prison.o
>>  obj-$(CONFIG_DM_CRYPT)  += dm-crypt.o
>> +obj-$(CONFIG_DM_INLINECRYPT)+= dm-inlinecrypt.o
>>  obj-$(CONFIG_DM_DELAY)  += dm-delay.o
>>  obj-$(CONFIG_DM_DUST)   += dm-dust.o
>>  obj-$(CONFIG_DM_FLAKEY) += dm-flakey.o
>> diff --git a/drivers/md/dm-inlinecrypt.c b/drivers/md/dm-inlinecrypt.c
>> new file mode 100644
>> index ..b6e98fdf8af1
>> --- /dev/null
>> +++ b/drivers/md/dm-inlinecrypt.c
>> @@ -0,0 +1,559 @@
>> +// SPDX-License-Identifier: GPL-2.0-only
>> +/*
>> + * Copyright 2024 Google LLC
>> + */
>> +
>> +#include 
>> +#include 
>> +#include 
>> +#include 
>> +#include 
>> +#include 
>> +
>> +#define DM_MSG_PREFIX   "inlinecrypt"
>> +
>> +static const struct dm_inlinecrypt_cipher {
>> +const char *name;
>> +enum blk_crypto_mode_num mode_num;
>> +} dm_inlinecrypt_ciphers[] = {
>> +{
>> +.name = "aes-xts-plain64",
>> +.mode_num = BLK_ENCRYPTION_MODE_AES_256_XTS,
>> +},
>> +};
>> +
>> +/**
>> + * struct inlinecrypt_ctx - private data of an inlinecrypt target
>> + * @dev: the underlying device
>> + * @start: starting sector of the range of @dev which this target actually 
>> maps.
>> + * For this purpose a "sector" is 512 bytes.
>> + * @cipher_string: the name of the encryption algorithm being used
>> + * @iv_offset: starting offset for IVs.  IVs are generated as if the target 
>> were
>> + * preceded by @iv_offset 512-byte sectors.
>> + * @sector_size: crypto sector size in bytes (usually 4096)
>> + * @sector_bits: log2(sector_size)
>> + * @key: the encryption key to use
>> + * @max_dun: the maximum DUN that may be used (computed from other params)
>> + */
>> +struct inlinecrypt_ctx {
>> +struct dm_dev *dev;
>> +sector_t start;
>> +const char *cipher_string;
>> +unsigned int key_size;
>> +u64 iv_offset;
>> +unsigned int sector_size;
>> +unsigned int sector_bits;
>> +struct blk_crypto_key ke

Re: [PATCH v2 2/3] dm-inlinecrypt: add target for inline block device encryption

2026-04-26 Thread Benjamin Marzinski
On Fri, Apr 10, 2026 at 06:40:30AM -0700, Linlin Zhang wrote:
> From: Eric Biggers 
> 
> Add a new device-mapper target "dm-inlinecrypt" that is similar to
> dm-crypt but uses the blk-crypto API instead of the regular crypto API.
> This allows it to take advantage of inline encryption hardware such as
> that commonly built into UFS host controllers.
> 
> The table syntax matches dm-crypt's, but for now only a stripped-down
> set of parameters is supported.  For example, for now AES-256-XTS is the
> only supported cipher.
> 
> dm-inlinecrypt is based on Android's dm-default-key with the
> controversial passthrough support removed.  Note that due to the removal
> of passthrough support, use of dm-inlinecrypt in combination with
> fscrypt causes double encryption of file contents (similar to dm-crypt +
> fscrypt), with the fscrypt layer not being able to use the inline
> encryption hardware.  This makes dm-inlinecrypt unusable on systems such
> as Android that use fscrypt and where a more optimized approach is
> needed.  It is however suitable as a replacement for dm-crypt.
> 
> dm-inlinecrypt supports both keyring key and hex key, the former avoids
> the key to be exposed in dm-table message. Similar to dm-default-key in
> Android, it will fallabck to the software block crypto once the inline
> crypto hardware cannot support the expected cipher.
> 
> Test:
> dmsetup create inlinecrypt_logon --table "0 `blockdev --getsz $1` \
> inlinecrypt aes-xts-plain64 :64:logon:fde:dminlinecrypt_test_key 0 $1 0"
> 
> Signed-off-by: Eric Biggers 
> Signed-off-by: Linlin Zhang 
> ---
>  drivers/md/Kconfig  |  10 +
>  drivers/md/Makefile |   1 +
>  drivers/md/dm-inlinecrypt.c | 559 
>  3 files changed, 570 insertions(+)
>  create mode 100644 drivers/md/dm-inlinecrypt.c
 
> diff --git a/drivers/md/dm-inlinecrypt.c b/drivers/md/dm-inlinecrypt.c
> new file mode 100644
> index ..b6e98fdf8af1
> --- /dev/null
> +++ b/drivers/md/dm-inlinecrypt.c

> +static int inlinecrypt_map(struct dm_target *ti, struct bio *bio)
> +{
> + const struct inlinecrypt_ctx *ctx = ti->private;
> + sector_t sector_in_target;
> + u64 dun[BLK_CRYPTO_DUN_ARRAY_SIZE] = {};
> +
> + bio_set_dev(bio, ctx->dev->bdev);
> +
> + /*
> +  * If the bio is a device-level request which doesn't target a specific
> +  * sector, there's nothing more to do.
> +  */
> + if (bio_sectors(bio) == 0)
> + return DM_MAPIO_REMAPPED;
> +
> + /*
> +  * The bio should never have an encryption context already, since
> +  * dm-inlinecrypt doesn't pass through any inline encryption
> +  * capabilities to the layer above it.
> +  */
> + if (WARN_ON_ONCE(bio_has_crypt_ctx(bio)))
> + return DM_MAPIO_KILL;
> +
> + /* Map the bio's sector to the underlying device. (512-byte sectors) */
> + sector_in_target = dm_target_offset(ti, bio->bi_iter.bi_sector);
> + bio->bi_iter.bi_sector = ctx->start + sector_in_target;
> + /*
> +  * If the bio doesn't have any data (e.g. if it's a DISCARD request),
> +  * there's nothing more to do.
> +  */
> + if (!bio_has_data(bio))
> + return DM_MAPIO_REMAPPED;
> +
> + /* Calculate the DUN and enforce data-unit (crypto sector) alignment. */
> + dun[0] = ctx->iv_offset + sector_in_target; /* 512-byte sectors */
> + if (dun[0] & ((ctx->sector_size >> SECTOR_SHIFT) - 1))
> + return DM_MAPIO_KILL;
> + dun[0] >>= ctx->sector_bits - SECTOR_SHIFT; /* crypto sectors */
> +
> + /*
> +  * This check isn't necessary as we should have calculated max_dun
> +  * correctly, but be safe.
> +  */
> + if (WARN_ON_ONCE(dun[0] > ctx->max_dun))
> + return DM_MAPIO_KILL;
> +
> + bio_crypt_set_ctx(bio, &ctx->key, dun, GFP_NOIO);
> +
> + /*
> +  * Since we've added an encryption context to the bio and
> +  * blk-crypto-fallback may be needed to process it, it's necessary to
> +  * use the fallback-aware bio submission code rather than
> +  * unconditionally returning DM_MAPIO_REMAPPED.
> +  *
> +  * To get the correct accounting for a dm target in the case where
> +  * __blk_crypto_submit_bio() doesn't take ownership of the bio (returns
> +  * true), call __blk_crypto_submit_bio() directly and return
> +  * DM_MAPIO_REMAPPED in that case, rather than relying on
> +  * blk_crypto_submit_bio() which calls submit_bio() in that case.
> +  */
> + if (__blk_crypto_submit_bio(bio))

This will still double account for fallback writes (which call
submit_bio() on the encrypted bios, and return DM_MAPIO_SUBMITTED here). 

-Ben

> + return DM_MAPIO_REMAPPED;
> + return DM_MAPIO_SUBMITTED;
> +}




Re: [PATCH v2 2/3] dm-inlinecrypt: add target for inline block device encryption

2026-04-26 Thread Benjamin Marzinski
On Fri, Apr 10, 2026 at 06:40:30AM -0700, Linlin Zhang wrote:
> From: Eric Biggers 
> 
> Add a new device-mapper target "dm-inlinecrypt" that is similar to
> dm-crypt but uses the blk-crypto API instead of the regular crypto API.
> This allows it to take advantage of inline encryption hardware such as
> that commonly built into UFS host controllers.
> 
> The table syntax matches dm-crypt's, but for now only a stripped-down
> set of parameters is supported.  For example, for now AES-256-XTS is the
> only supported cipher.
> 
> dm-inlinecrypt is based on Android's dm-default-key with the
> controversial passthrough support removed.  Note that due to the removal
> of passthrough support, use of dm-inlinecrypt in combination with
> fscrypt causes double encryption of file contents (similar to dm-crypt +
> fscrypt), with the fscrypt layer not being able to use the inline
> encryption hardware.  This makes dm-inlinecrypt unusable on systems such
> as Android that use fscrypt and where a more optimized approach is
> needed.  It is however suitable as a replacement for dm-crypt.
> 
> dm-inlinecrypt supports both keyring key and hex key, the former avoids
> the key to be exposed in dm-table message. Similar to dm-default-key in
> Android, it will fallabck to the software block crypto once the inline
> crypto hardware cannot support the expected cipher.
> 
> Test:
> dmsetup create inlinecrypt_logon --table "0 `blockdev --getsz $1` \
> inlinecrypt aes-xts-plain64 :64:logon:fde:dminlinecrypt_test_key 0 $1 0"
> 
> Signed-off-by: Eric Biggers 
> Signed-off-by: Linlin Zhang 
> ---
>  drivers/md/Kconfig  |  10 +
>  drivers/md/Makefile |   1 +
>  drivers/md/dm-inlinecrypt.c | 559 
>  3 files changed, 570 insertions(+)
>  create mode 100644 drivers/md/dm-inlinecrypt.c
> 
> diff --git a/drivers/md/Kconfig b/drivers/md/Kconfig
> index c58a9a8ea54e..aa541cc22ecc 100644
> --- a/drivers/md/Kconfig
> +++ b/drivers/md/Kconfig
> @@ -313,6 +313,16 @@ config DM_CRYPT
>  
> If unsure, say N.
>  
> +config DM_INLINECRYPT
> + tristate "Inline encryption target support"
> + depends on BLK_DEV_DM
> + depends on BLK_INLINE_ENCRYPTION
> + help
> +   This device-mapper target is similar to dm-crypt, but it uses the
> +   blk-crypto API instead of the regular crypto API. This allows it to
> +   take advantage of inline encryption hardware such as that commonly
> +   built into UFS host controllers.
> +
>  config DM_SNAPSHOT
> tristate "Snapshot target"
> depends on BLK_DEV_DM
> diff --git a/drivers/md/Makefile b/drivers/md/Makefile
> index c338cc6fbe2e..517d1f7d8288 100644
> --- a/drivers/md/Makefile
> +++ b/drivers/md/Makefile
> @@ -55,6 +55,7 @@ obj-$(CONFIG_DM_UNSTRIPED)  += dm-unstripe.o
>  obj-$(CONFIG_DM_BUFIO)   += dm-bufio.o
>  obj-$(CONFIG_DM_BIO_PRISON)  += dm-bio-prison.o
>  obj-$(CONFIG_DM_CRYPT)   += dm-crypt.o
> +obj-$(CONFIG_DM_INLINECRYPT) += dm-inlinecrypt.o
>  obj-$(CONFIG_DM_DELAY)   += dm-delay.o
>  obj-$(CONFIG_DM_DUST)+= dm-dust.o
>  obj-$(CONFIG_DM_FLAKEY)  += dm-flakey.o
> diff --git a/drivers/md/dm-inlinecrypt.c b/drivers/md/dm-inlinecrypt.c
> new file mode 100644
> index ..b6e98fdf8af1
> --- /dev/null
> +++ b/drivers/md/dm-inlinecrypt.c
> @@ -0,0 +1,559 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Copyright 2024 Google LLC
> + */
> +
> +#include 
> +#include 
> +#include 
> +#include 
> +#include 
> +#include 
> +
> +#define DM_MSG_PREFIX"inlinecrypt"
> +
> +static const struct dm_inlinecrypt_cipher {
> + const char *name;
> + enum blk_crypto_mode_num mode_num;
> +} dm_inlinecrypt_ciphers[] = {
> + {
> + .name = "aes-xts-plain64",
> + .mode_num = BLK_ENCRYPTION_MODE_AES_256_XTS,
> + },
> +};
> +
> +/**
> + * struct inlinecrypt_ctx - private data of an inlinecrypt target
> + * @dev: the underlying device
> + * @start: starting sector of the range of @dev which this target actually 
> maps.
> + *  For this purpose a "sector" is 512 bytes.
> + * @cipher_string: the name of the encryption algorithm being used
> + * @iv_offset: starting offset for IVs.  IVs are generated as if the target 
> were
> + *  preceded by @iv_offset 512-byte sectors.
> + * @sector_size: crypto sector size in bytes (usually 4096)
> + * @sector_bits: log2(sector_size)
> + * @key: the encryption key to use
> + * @max_dun: the maximum DUN that may be used (computed from other params)
> + */
> +struct inlinecrypt_ctx {
> + struct dm_dev *dev;
> + sector_t start;
> + const char *cipher_string;
> + unsigned int key_size;
> + u64 iv_offset;
> + unsigned int sector_size;
> + unsigned int sector_bits;
> + struct blk_crypto_key key;
> + u64 max_dun;
> +};
> +
> +static const struct dm_inlinecrypt_cipher *
> +lookup_cipher(const char *cipher_string)
> +{
> + int i;