All of lore.kernel.org
 help / color / mirror / Atom feed
* [RFC PATCH] dm-crypt: allow unaligned bio_vecs for direct io
@ 2025-09-18 16:16 Keith Busch
  2025-09-18 20:13 ` Keith Busch
                   ` (3 more replies)
  0 siblings, 4 replies; 8+ messages in thread
From: Keith Busch @ 2025-09-18 16:16 UTC (permalink / raw)
  To: dm-devel; +Cc: snitzer, linux-block, mpatocka, ebiggers, Keith Busch

From: Keith Busch <kbusch@kernel.org>

Most storage devices can handle DMA for data that is not aligned to the
sector block size. The block and filesystem layers have introduced
updates to allow that kind of memory alignment flexibility when
possible.

dm-crypt, however, currently constrains itself to aligned memory because
it sends a single scatterlist element for the input ot the encrypt and
decrypt algorithms. This forces applications that have unaligned data to
copy through a bounce buffer, increasing CPU and memory utilization.

It appears to be a pretty straight forward thing to modify for skcipher
since there are 3 unused scatterlist elements immediately available. In
practice, that should be enough as the sector granularity of data
generally doesn't straddle more than one page, if at all.

Signed-off-by: Keith Busch <kbusch@kernel.org>
---
 drivers/md/dm-crypt.c | 29 +++++++++++++++++++----------
 1 file changed, 19 insertions(+), 10 deletions(-)

diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c
index 5ef43231fe77f..f860716b7a5c1 100644
--- a/drivers/md/dm-crypt.c
+++ b/drivers/md/dm-crypt.c
@@ -1429,18 +1429,14 @@ static int crypt_convert_block_skcipher(struct crypt_config *cc,
 					struct skcipher_request *req,
 					unsigned int tag_offset)
 {
-	struct bio_vec bv_in = bio_iter_iovec(ctx->bio_in, ctx->iter_in);
 	struct bio_vec bv_out = bio_iter_iovec(ctx->bio_out, ctx->iter_out);
+	unsigned int bytes = cc->sector_size;
 	struct scatterlist *sg_in, *sg_out;
 	struct dm_crypt_request *dmreq;
 	u8 *iv, *org_iv, *tag_iv;
 	__le64 *sector;
 	int r = 0;
 
-	/* Reject unexpected unaligned bio. */
-	if (unlikely(bv_in.bv_len & (cc->sector_size - 1)))
-		return -EIO;
-
 	dmreq = dmreq_of_req(cc, req);
 	dmreq->iv_sector = ctx->cc_sector;
 	if (test_bit(CRYPT_IV_LARGE_SECTORS, &cc->cipher_flags))
@@ -1457,11 +1453,24 @@ static int crypt_convert_block_skcipher(struct crypt_config *cc,
 	*sector = cpu_to_le64(ctx->cc_sector - cc->iv_offset);
 
 	/* For skcipher we use only the first sg item */
-	sg_in  = &dmreq->sg_in[0];
 	sg_out = &dmreq->sg_out[0];
 
-	sg_init_table(sg_in, 1);
-	sg_set_page(sg_in, bv_in.bv_page, cc->sector_size, bv_in.bv_offset);
+	do {
+		struct bio_vec bv_in = bio_iter_iovec(ctx->bio_in, ctx->iter_in);
+		int len = min(bytes, bv_in.bv_len);
+
+		if (r >= ARRAY_SIZE(dmreq->sg_in))
+			return -EINVAL;
+
+		sg_in = &dmreq->sg_in[r++];
+		memset(sg_in, 0, sizeof(*sg_in));
+		sg_set_page(sg_in, bv_in.bv_page, len, bv_in.bv_offset);
+		bio_advance_iter_single(ctx->bio_in, &ctx->iter_in, len);
+		bytes -= len;
+	} while (bytes);
+
+	sg_mark_end(sg_in);
+	sg_in = dmreq->sg_in[0];
 
 	sg_init_table(sg_out, 1);
 	sg_set_page(sg_out, bv_out.bv_page, cc->sector_size, bv_out.bv_offset);
@@ -1495,7 +1504,6 @@ static int crypt_convert_block_skcipher(struct crypt_config *cc,
 	if (!r && cc->iv_gen_ops && cc->iv_gen_ops->post)
 		r = cc->iv_gen_ops->post(cc, org_iv, dmreq);
 
-	bio_advance_iter(ctx->bio_in, &ctx->iter_in, cc->sector_size);
 	bio_advance_iter(ctx->bio_out, &ctx->iter_out, cc->sector_size);
 
 	return r;
@@ -3750,7 +3758,8 @@ static void crypt_io_hints(struct dm_target *ti, struct queue_limits *limits)
 	limits->physical_block_size =
 		max_t(unsigned int, limits->physical_block_size, cc->sector_size);
 	limits->io_min = max_t(unsigned int, limits->io_min, cc->sector_size);
-	limits->dma_alignment = limits->logical_block_size - 1;
+	if (crypt_integrity_aead(cc))
+		limits->dma_alignment = limits->logical_block_size - 1;
 
 	/*
 	 * For zoned dm-crypt targets, there will be no internal splitting of
-- 
2.47.3


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* Re: [RFC PATCH] dm-crypt: allow unaligned bio_vecs for direct io
  2025-09-18 16:16 [RFC PATCH] dm-crypt: allow unaligned bio_vecs for direct io Keith Busch
@ 2025-09-18 20:13 ` Keith Busch
  2025-09-26 14:19   ` Mikulas Patocka
  2025-09-18 20:27 ` Mike Snitzer
                   ` (2 subsequent siblings)
  3 siblings, 1 reply; 8+ messages in thread
From: Keith Busch @ 2025-09-18 20:13 UTC (permalink / raw)
  To: Keith Busch; +Cc: dm-devel, snitzer, linux-block, mpatocka, ebiggers

On Thu, Sep 18, 2025 at 09:16:42AM -0700, Keith Busch wrote:
> +		bio_advance_iter_single(ctx->bio_in, &ctx->iter_in, len);
> +		bytes -= len;
> +	} while (bytes);
> +
> +	sg_mark_end(sg_in);
> +	sg_in = dmreq->sg_in[0];

Err, there should be an '&' in there, "&dmreq->sg_in[0];"

By the way, I only tested plain64 for the ivmode. That appears to work
fine, but I am aware this will not be successful with elephant, lmk, or
tcw. So just an RFC for now to see if it's worth pursuing.

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [RFC PATCH] dm-crypt: allow unaligned bio_vecs for direct io
  2025-09-18 16:16 [RFC PATCH] dm-crypt: allow unaligned bio_vecs for direct io Keith Busch
  2025-09-18 20:13 ` Keith Busch
@ 2025-09-18 20:27 ` Mike Snitzer
  2025-09-18 20:52   ` Keith Busch
  2025-09-19  9:13 ` kernel test robot
  2025-09-20  5:33 ` kernel test robot
  3 siblings, 1 reply; 8+ messages in thread
From: Mike Snitzer @ 2025-09-18 20:27 UTC (permalink / raw)
  To: Keith Busch; +Cc: dm-devel, linux-block, mpatocka, ebiggers, Keith Busch

On Thu, Sep 18, 2025 at 09:16:42AM -0700, Keith Busch wrote:
> From: Keith Busch <kbusch@kernel.org>
> 
> Most storage devices can handle DMA for data that is not aligned to the
> sector block size. The block and filesystem layers have introduced
> updates to allow that kind of memory alignment flexibility when
> possible.

I'd love to understand what changes in filesystems you're referring
to.  Because I know for certain that DIO with memory that isn't
'dma_alignment' aligned fails with certainty ontop of XFS.

Pretty certain it balks at DIO that isn't logical_block_size aligned
ondisk too.

> dm-crypt, however, currently constrains itself to aligned memory because
> it sends a single scatterlist element for the input ot the encrypt and
> decrypt algorithms. This forces applications that have unaligned data to
> copy through a bounce buffer, increasing CPU and memory utilization.

Even this notion that an application is somehow able to (unwittingly)
lean on "unaligned data to copy through a bounce buffer" -- has me
asking: where does Keith get these wonderful toys?

Anyway, just asking these things because if they were true I wouldn't
be needing to add specialized code to NFSD and NFS to handle
misaligned DIO.

> It appears to be a pretty straight forward thing to modify for skcipher
> since there are 3 unused scatterlist elements immediately available. In
> practice, that should be enough as the sector granularity of data
> generally doesn't straddle more than one page, if at all.
> 
> Signed-off-by: Keith Busch <kbusch@kernel.org>
> ---
>  drivers/md/dm-crypt.c | 29 +++++++++++++++++++----------
>  1 file changed, 19 insertions(+), 10 deletions(-)
> 
> diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c
> index 5ef43231fe77f..f860716b7a5c1 100644
> --- a/drivers/md/dm-crypt.c
> +++ b/drivers/md/dm-crypt.c
> @@ -1429,18 +1429,14 @@ static int crypt_convert_block_skcipher(struct crypt_config *cc,
>  					struct skcipher_request *req,
>  					unsigned int tag_offset)
>  {
> -	struct bio_vec bv_in = bio_iter_iovec(ctx->bio_in, ctx->iter_in);
>  	struct bio_vec bv_out = bio_iter_iovec(ctx->bio_out, ctx->iter_out);
> +	unsigned int bytes = cc->sector_size;
>  	struct scatterlist *sg_in, *sg_out;
>  	struct dm_crypt_request *dmreq;
>  	u8 *iv, *org_iv, *tag_iv;
>  	__le64 *sector;
>  	int r = 0;
>  
> -	/* Reject unexpected unaligned bio. */
> -	if (unlikely(bv_in.bv_len & (cc->sector_size - 1)))
> -		return -EIO;
> -
>  	dmreq = dmreq_of_req(cc, req);
>  	dmreq->iv_sector = ctx->cc_sector;
>  	if (test_bit(CRYPT_IV_LARGE_SECTORS, &cc->cipher_flags))
> @@ -1457,11 +1453,24 @@ static int crypt_convert_block_skcipher(struct crypt_config *cc,
>  	*sector = cpu_to_le64(ctx->cc_sector - cc->iv_offset);
>  
>  	/* For skcipher we use only the first sg item */
> -	sg_in  = &dmreq->sg_in[0];
>  	sg_out = &dmreq->sg_out[0];
>  
> -	sg_init_table(sg_in, 1);
> -	sg_set_page(sg_in, bv_in.bv_page, cc->sector_size, bv_in.bv_offset);
> +	do {
> +		struct bio_vec bv_in = bio_iter_iovec(ctx->bio_in, ctx->iter_in);
> +		int len = min(bytes, bv_in.bv_len);
> +
> +		if (r >= ARRAY_SIZE(dmreq->sg_in))
> +			return -EINVAL;
> +
> +		sg_in = &dmreq->sg_in[r++];
> +		memset(sg_in, 0, sizeof(*sg_in));
> +		sg_set_page(sg_in, bv_in.bv_page, len, bv_in.bv_offset);
> +		bio_advance_iter_single(ctx->bio_in, &ctx->iter_in, len);
> +		bytes -= len;
> +	} while (bytes);
> +
> +	sg_mark_end(sg_in);
> +	sg_in = dmreq->sg_in[0];
>  
>  	sg_init_table(sg_out, 1);
>  	sg_set_page(sg_out, bv_out.bv_page, cc->sector_size, bv_out.bv_offset);
> @@ -1495,7 +1504,6 @@ static int crypt_convert_block_skcipher(struct crypt_config *cc,
>  	if (!r && cc->iv_gen_ops && cc->iv_gen_ops->post)
>  		r = cc->iv_gen_ops->post(cc, org_iv, dmreq);
>  
> -	bio_advance_iter(ctx->bio_in, &ctx->iter_in, cc->sector_size);
>  	bio_advance_iter(ctx->bio_out, &ctx->iter_out, cc->sector_size);
>  
>  	return r;
> @@ -3750,7 +3758,8 @@ static void crypt_io_hints(struct dm_target *ti, struct queue_limits *limits)
>  	limits->physical_block_size =
>  		max_t(unsigned int, limits->physical_block_size, cc->sector_size);
>  	limits->io_min = max_t(unsigned int, limits->io_min, cc->sector_size);
> -	limits->dma_alignment = limits->logical_block_size - 1;
> +	if (crypt_integrity_aead(cc))
> +		limits->dma_alignment = limits->logical_block_size - 1;
>  
>  	/*
>  	 * For zoned dm-crypt targets, there will be no internal splitting of
> -- 
> 2.47.3
> 
> 

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [RFC PATCH] dm-crypt: allow unaligned bio_vecs for direct io
  2025-09-18 20:27 ` Mike Snitzer
@ 2025-09-18 20:52   ` Keith Busch
  0 siblings, 0 replies; 8+ messages in thread
From: Keith Busch @ 2025-09-18 20:52 UTC (permalink / raw)
  To: Mike Snitzer; +Cc: Keith Busch, dm-devel, linux-block, mpatocka, ebiggers

On Thu, Sep 18, 2025 at 04:27:14PM -0400, Mike Snitzer wrote:
> On Thu, Sep 18, 2025 at 09:16:42AM -0700, Keith Busch wrote:
> > From: Keith Busch <kbusch@kernel.org>
> > 
> > Most storage devices can handle DMA for data that is not aligned to the
> > sector block size. The block and filesystem layers have introduced
> > updates to allow that kind of memory alignment flexibility when
> > possible.
> 
> I'd love to understand what changes in filesystems you're referring
> to.  Because I know for certain that DIO with memory that isn't
> 'dma_alignment' aligned fails with certainty ontop of XFS.

I only mentioned the "sector block size" alignment, not the hardware dma
alignment. The dma alignment remains the minimum address alignment you
have to use. But xfs has been able to handle dword aligned addresses for
a while now, assuming your block_device can handle dword aligned DMA.
But the old requirement for a buffer to be aligned to a 4k address
offset for a 4k block device isn't necessary anymore.
 
> Pretty certain it balks at DIO that isn't logical_block_size aligned
> ondisk too.

We might be talking about different things. The total length of a
vector must be a multiple of the logical block size, yes. But I'm
talking about the address offset. Right now dm-crypt can't handle a
request if the address offset is not aligned to the logical block size.
But that's a purely software created limitation, there's no hard reason
that needs to be the case.

> > it sends a single scatterlist element for the input ot the encrypt and
> > decrypt algorithms. This forces applications that have unaligned data to
> > copy through a bounce buffer, increasing CPU and memory utilization.
> 
> Even this notion that an application is somehow able to (unwittingly)
> lean on "unaligned data to copy through a bounce buffer" -- has me
> asking: where does Keith get these wonderful toys?

I'm just trying to write data to disk from buffers filled by NICs
subscribed to io_uring zero-copy receive capabilities. I guess they need
fancy features to do that, but it's not that uncommon, is it? Anyway,
the data that needs to be persisted often have offsets that are still
DMA friendly, but unlikely to be perfectly page aligned.

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [RFC PATCH] dm-crypt: allow unaligned bio_vecs for direct io
  2025-09-18 16:16 [RFC PATCH] dm-crypt: allow unaligned bio_vecs for direct io Keith Busch
  2025-09-18 20:13 ` Keith Busch
  2025-09-18 20:27 ` Mike Snitzer
@ 2025-09-19  9:13 ` kernel test robot
  2025-09-20  5:33 ` kernel test robot
  3 siblings, 0 replies; 8+ messages in thread
From: kernel test robot @ 2025-09-19  9:13 UTC (permalink / raw)
  To: Keith Busch; +Cc: llvm, oe-kbuild-all

Hi Keith,

[This is a private test report for your RFC patch.]
kernel test robot noticed the following build errors:

[auto build test ERROR on device-mapper-dm/for-next]
[also build test ERROR on linus/master v6.17-rc6 next-20250918]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Keith-Busch/dm-crypt-allow-unaligned-bio_vecs-for-direct-io/20250919-001836
base:   https://git.kernel.org/pub/scm/linux/kernel/git/device-mapper/linux-dm.git for-next
patch link:    https://lore.kernel.org/r/20250918161642.2867886-1-kbusch%40meta.com
patch subject: [RFC PATCH] dm-crypt: allow unaligned bio_vecs for direct io
config: x86_64-kexec (https://download.01.org/0day-ci/archive/20250919/202509191157.CgcOJXTe-lkp@intel.com/config)
compiler: clang version 20.1.8 (https://github.com/llvm/llvm-project 87f0227cb60147a26a1eeb4fb06e3b505e9c7261)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20250919/202509191157.CgcOJXTe-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202509191157.CgcOJXTe-lkp@intel.com/

All errors (new ones prefixed by >>):

>> drivers/md/dm-crypt.c:1473:8: error: assigning to 'struct scatterlist *' from incompatible type 'struct scatterlist'; take the address with &
    1473 |         sg_in = dmreq->sg_in[0];
         |               ^ ~~~~~~~~~~~~~~~
         |                 &
   1 error generated.


vim +1473 drivers/md/dm-crypt.c

  1426	
  1427	static int crypt_convert_block_skcipher(struct crypt_config *cc,
  1428						struct convert_context *ctx,
  1429						struct skcipher_request *req,
  1430						unsigned int tag_offset)
  1431	{
  1432		struct bio_vec bv_out = bio_iter_iovec(ctx->bio_out, ctx->iter_out);
  1433		unsigned int bytes = cc->sector_size;
  1434		struct scatterlist *sg_in, *sg_out;
  1435		struct dm_crypt_request *dmreq;
  1436		u8 *iv, *org_iv, *tag_iv;
  1437		__le64 *sector;
  1438		int r = 0;
  1439	
  1440		dmreq = dmreq_of_req(cc, req);
  1441		dmreq->iv_sector = ctx->cc_sector;
  1442		if (test_bit(CRYPT_IV_LARGE_SECTORS, &cc->cipher_flags))
  1443			dmreq->iv_sector >>= cc->sector_shift;
  1444		dmreq->ctx = ctx;
  1445	
  1446		*org_tag_of_dmreq(cc, dmreq) = tag_offset;
  1447	
  1448		iv = iv_of_dmreq(cc, dmreq);
  1449		org_iv = org_iv_of_dmreq(cc, dmreq);
  1450		tag_iv = iv_tag_from_dmreq(cc, dmreq);
  1451	
  1452		sector = org_sector_of_dmreq(cc, dmreq);
  1453		*sector = cpu_to_le64(ctx->cc_sector - cc->iv_offset);
  1454	
  1455		/* For skcipher we use only the first sg item */
  1456		sg_out = &dmreq->sg_out[0];
  1457	
  1458		do {
  1459			struct bio_vec bv_in = bio_iter_iovec(ctx->bio_in, ctx->iter_in);
  1460			int len = min(bytes, bv_in.bv_len);
  1461	
  1462			if (r >= ARRAY_SIZE(dmreq->sg_in))
  1463				return -EINVAL;
  1464	
  1465			sg_in = &dmreq->sg_in[r++];
  1466			memset(sg_in, 0, sizeof(*sg_in));
  1467			sg_set_page(sg_in, bv_in.bv_page, len, bv_in.bv_offset);
  1468			bio_advance_iter_single(ctx->bio_in, &ctx->iter_in, len);
  1469			bytes -= len;
  1470		} while (bytes);
  1471	
  1472		sg_mark_end(sg_in);
> 1473		sg_in = dmreq->sg_in[0];
  1474	
  1475		sg_init_table(sg_out, 1);
  1476		sg_set_page(sg_out, bv_out.bv_page, cc->sector_size, bv_out.bv_offset);
  1477	
  1478		if (cc->iv_gen_ops) {
  1479			/* For READs use IV stored in integrity metadata */
  1480			if (cc->integrity_iv_size && bio_data_dir(ctx->bio_in) != WRITE) {
  1481				memcpy(org_iv, tag_iv, cc->integrity_iv_size);
  1482			} else {
  1483				r = cc->iv_gen_ops->generator(cc, org_iv, dmreq);
  1484				if (r < 0)
  1485					return r;
  1486				/* Data can be already preprocessed in generator */
  1487				if (test_bit(CRYPT_ENCRYPT_PREPROCESS, &cc->cipher_flags))
  1488					sg_in = sg_out;
  1489				/* Store generated IV in integrity metadata */
  1490				if (cc->integrity_iv_size)
  1491					memcpy(tag_iv, org_iv, cc->integrity_iv_size);
  1492			}
  1493			/* Working copy of IV, to be modified in crypto API */
  1494			memcpy(iv, org_iv, cc->iv_size);
  1495		}
  1496	
  1497		skcipher_request_set_crypt(req, sg_in, sg_out, cc->sector_size, iv);
  1498	
  1499		if (bio_data_dir(ctx->bio_in) == WRITE)
  1500			r = crypto_skcipher_encrypt(req);
  1501		else
  1502			r = crypto_skcipher_decrypt(req);
  1503	
  1504		if (!r && cc->iv_gen_ops && cc->iv_gen_ops->post)
  1505			r = cc->iv_gen_ops->post(cc, org_iv, dmreq);
  1506	
  1507		bio_advance_iter(ctx->bio_out, &ctx->iter_out, cc->sector_size);
  1508	
  1509		return r;
  1510	}
  1511	

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [RFC PATCH] dm-crypt: allow unaligned bio_vecs for direct io
  2025-09-18 16:16 [RFC PATCH] dm-crypt: allow unaligned bio_vecs for direct io Keith Busch
                   ` (2 preceding siblings ...)
  2025-09-19  9:13 ` kernel test robot
@ 2025-09-20  5:33 ` kernel test robot
  3 siblings, 0 replies; 8+ messages in thread
From: kernel test robot @ 2025-09-20  5:33 UTC (permalink / raw)
  To: Keith Busch; +Cc: llvm, oe-kbuild-all

Hi Keith,

[This is a private test report for your RFC patch.]
kernel test robot noticed the following build errors:

[auto build test ERROR on device-mapper-dm/for-next]
[also build test ERROR on linus/master v6.17-rc6 next-20250919]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Keith-Busch/dm-crypt-allow-unaligned-bio_vecs-for-direct-io/20250919-001836
base:   https://git.kernel.org/pub/scm/linux/kernel/git/device-mapper/linux-dm.git for-next
patch link:    https://lore.kernel.org/r/20250918161642.2867886-1-kbusch%40meta.com
patch subject: [RFC PATCH] dm-crypt: allow unaligned bio_vecs for direct io
config: i386-buildonly-randconfig-001-20250920 (https://download.01.org/0day-ci/archive/20250920/202509201341.vkf3aDEL-lkp@intel.com/config)
compiler: clang version 20.1.8 (https://github.com/llvm/llvm-project 87f0227cb60147a26a1eeb4fb06e3b505e9c7261)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20250920/202509201341.vkf3aDEL-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202509201341.vkf3aDEL-lkp@intel.com/

All errors (new ones prefixed by >>):

>> drivers/md/dm-crypt.c:1473:8: error: assigning to 'struct scatterlist *' from incompatible type 'struct scatterlist'; take the address with &
    1473 |         sg_in = dmreq->sg_in[0];
         |               ^ ~~~~~~~~~~~~~~~
         |                 &
   1 error generated.


vim +1473 drivers/md/dm-crypt.c

  1426	
  1427	static int crypt_convert_block_skcipher(struct crypt_config *cc,
  1428						struct convert_context *ctx,
  1429						struct skcipher_request *req,
  1430						unsigned int tag_offset)
  1431	{
  1432		struct bio_vec bv_out = bio_iter_iovec(ctx->bio_out, ctx->iter_out);
  1433		unsigned int bytes = cc->sector_size;
  1434		struct scatterlist *sg_in, *sg_out;
  1435		struct dm_crypt_request *dmreq;
  1436		u8 *iv, *org_iv, *tag_iv;
  1437		__le64 *sector;
  1438		int r = 0;
  1439	
  1440		dmreq = dmreq_of_req(cc, req);
  1441		dmreq->iv_sector = ctx->cc_sector;
  1442		if (test_bit(CRYPT_IV_LARGE_SECTORS, &cc->cipher_flags))
  1443			dmreq->iv_sector >>= cc->sector_shift;
  1444		dmreq->ctx = ctx;
  1445	
  1446		*org_tag_of_dmreq(cc, dmreq) = tag_offset;
  1447	
  1448		iv = iv_of_dmreq(cc, dmreq);
  1449		org_iv = org_iv_of_dmreq(cc, dmreq);
  1450		tag_iv = iv_tag_from_dmreq(cc, dmreq);
  1451	
  1452		sector = org_sector_of_dmreq(cc, dmreq);
  1453		*sector = cpu_to_le64(ctx->cc_sector - cc->iv_offset);
  1454	
  1455		/* For skcipher we use only the first sg item */
  1456		sg_out = &dmreq->sg_out[0];
  1457	
  1458		do {
  1459			struct bio_vec bv_in = bio_iter_iovec(ctx->bio_in, ctx->iter_in);
  1460			int len = min(bytes, bv_in.bv_len);
  1461	
  1462			if (r >= ARRAY_SIZE(dmreq->sg_in))
  1463				return -EINVAL;
  1464	
  1465			sg_in = &dmreq->sg_in[r++];
  1466			memset(sg_in, 0, sizeof(*sg_in));
  1467			sg_set_page(sg_in, bv_in.bv_page, len, bv_in.bv_offset);
  1468			bio_advance_iter_single(ctx->bio_in, &ctx->iter_in, len);
  1469			bytes -= len;
  1470		} while (bytes);
  1471	
  1472		sg_mark_end(sg_in);
> 1473		sg_in = dmreq->sg_in[0];
  1474	
  1475		sg_init_table(sg_out, 1);
  1476		sg_set_page(sg_out, bv_out.bv_page, cc->sector_size, bv_out.bv_offset);
  1477	
  1478		if (cc->iv_gen_ops) {
  1479			/* For READs use IV stored in integrity metadata */
  1480			if (cc->integrity_iv_size && bio_data_dir(ctx->bio_in) != WRITE) {
  1481				memcpy(org_iv, tag_iv, cc->integrity_iv_size);
  1482			} else {
  1483				r = cc->iv_gen_ops->generator(cc, org_iv, dmreq);
  1484				if (r < 0)
  1485					return r;
  1486				/* Data can be already preprocessed in generator */
  1487				if (test_bit(CRYPT_ENCRYPT_PREPROCESS, &cc->cipher_flags))
  1488					sg_in = sg_out;
  1489				/* Store generated IV in integrity metadata */
  1490				if (cc->integrity_iv_size)
  1491					memcpy(tag_iv, org_iv, cc->integrity_iv_size);
  1492			}
  1493			/* Working copy of IV, to be modified in crypto API */
  1494			memcpy(iv, org_iv, cc->iv_size);
  1495		}
  1496	
  1497		skcipher_request_set_crypt(req, sg_in, sg_out, cc->sector_size, iv);
  1498	
  1499		if (bio_data_dir(ctx->bio_in) == WRITE)
  1500			r = crypto_skcipher_encrypt(req);
  1501		else
  1502			r = crypto_skcipher_decrypt(req);
  1503	
  1504		if (!r && cc->iv_gen_ops && cc->iv_gen_ops->post)
  1505			r = cc->iv_gen_ops->post(cc, org_iv, dmreq);
  1506	
  1507		bio_advance_iter(ctx->bio_out, &ctx->iter_out, cc->sector_size);
  1508	
  1509		return r;
  1510	}
  1511	

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [RFC PATCH] dm-crypt: allow unaligned bio_vecs for direct io
  2025-09-18 20:13 ` Keith Busch
@ 2025-09-26 14:19   ` Mikulas Patocka
  2025-09-26 16:17     ` Keith Busch
  0 siblings, 1 reply; 8+ messages in thread
From: Mikulas Patocka @ 2025-09-26 14:19 UTC (permalink / raw)
  To: Keith Busch; +Cc: Keith Busch, dm-devel, snitzer, linux-block, ebiggers



On Thu, 18 Sep 2025, Keith Busch wrote:

> On Thu, Sep 18, 2025 at 09:16:42AM -0700, Keith Busch wrote:
> > +		bio_advance_iter_single(ctx->bio_in, &ctx->iter_in, len);
> > +		bytes -= len;
> > +	} while (bytes);
> > +
> > +	sg_mark_end(sg_in);
> > +	sg_in = dmreq->sg_in[0];
> 
> Err, there should be an '&' in there, "&dmreq->sg_in[0];"
> 
> By the way, I only tested plain64 for the ivmode. That appears to work
> fine, but I am aware this will not be successful with elephant, lmk, or
> tcw. So just an RFC for now to see if it's worth pursuing.

Hi

I'd like to ask - how much does it help performance? How many percent 
faster does your application run?

Another question - what if the user uses preadv or pwritev with direct I/O 
and uses more than 4 sg lists? Will this be rejected in the upper layers, 
or will it reach dm-crypt and return -EINVAL? Note that returning error 
from dm-crypt may be quite problematic, because it would kick the leg out 
of RAID, if there were RAID above dm-crypt. I think that we should return 
BLK_STS_NOTSUPP, because that would be ignored by RAID.

I am considering committing this for the kernel 6.19 (it's too late to add 
it to the 6.18 merge window).

Mikulas


^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [RFC PATCH] dm-crypt: allow unaligned bio_vecs for direct io
  2025-09-26 14:19   ` Mikulas Patocka
@ 2025-09-26 16:17     ` Keith Busch
  0 siblings, 0 replies; 8+ messages in thread
From: Keith Busch @ 2025-09-26 16:17 UTC (permalink / raw)
  To: Mikulas Patocka; +Cc: Keith Busch, dm-devel, snitzer, linux-block, ebiggers

On Fri, Sep 26, 2025 at 04:19:58PM +0200, Mikulas Patocka wrote:
> 
> I'd like to ask - how much does it help performance? How many percent 
> faster does your application run?

The best info I have from the storage team I'm working with is this
reduces their application's memory bandwidth utilization by a little
over 10%.

> Another question - what if the user uses preadv or pwritev with direct I/O 
> and uses more than 4 sg lists? Will this be rejected in the upper layers, 
> or will it reach dm-crypt and return -EINVAL? 

I believe it would reach dm-crypt with this patch.

If you tried today, it should get rejected by the upper layers for
unalignement. But there are some changes pending in the 6.18 block tree
that defer the alignment detection to later such that dm-crypt may have
to deal with this and fail the IO (unless something higher splits the
bio to its queue limits first), so sounds like I should sort that out.

Regarding the 4 scatterlist limit, we're using 4k sized logical blocks.
The incoming data typically has an offset crossing a page boundary, so
needs 2 pages for each block. Just 2 scatterlists would do the trick.

If we really want to remove all software constraints here, then we could
increase the pre-allocated scatterlist size, or dynamically allocate an
approrpiate scatter gather table per-io. I guess we'd have to expand the
list somewhere if this needs to work with aead, too.

> Note that returning error 
> from dm-crypt may be quite problematic, because it would kick the leg out 
> of RAID, if there were RAID above dm-crypt. I think that we should return 
> BLK_STS_NOTSUPP, because that would be ignored by RAID.

Thanks, I'll try this out.

> I am considering committing this for the kernel 6.19 (it's too late to add 
> it to the 6.18 merge window).

No problem, I don't want to rush this. Your reply is at least
encouraging enough for me to sort out more than just "plaint64" with
this proposal.

^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2025-09-26 16:17 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-09-18 16:16 [RFC PATCH] dm-crypt: allow unaligned bio_vecs for direct io Keith Busch
2025-09-18 20:13 ` Keith Busch
2025-09-26 14:19   ` Mikulas Patocka
2025-09-26 16:17     ` Keith Busch
2025-09-18 20:27 ` Mike Snitzer
2025-09-18 20:52   ` Keith Busch
2025-09-19  9:13 ` kernel test robot
2025-09-20  5:33 ` kernel test robot

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.