block: accumulate memory segment gaps per bio

The blk-mq dma iterator has an optimization for requests that align to
the device's iommu merge boundary. This boundary may be larger than the
device's virtual boundary, but the code had been depending on that queue
limit to know ahead of time if the request is guaranteed to align to
that optimization.

Rather than rely on that queue limit, which many devices may not report,
save the lowest set bit of any boundary gap between each segment in the
bio while checking the segments. The request stores the value for
merging and quickly checking per io if the request can use iova
optimizations.

Signed-off-by: Keith Busch <kbusch@kernel.org>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Martin K. Petersen <martin.petersen@oracle.com>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
This commit is contained in:
Keith Busch
2025-10-14 08:04:55 -07:00
committed by Jens Axboe
parent 0739c2c6a0
commit 2f6b2565d4
8 changed files with 77 additions and 5 deletions

View File

@@ -152,6 +152,14 @@ struct request {
unsigned short nr_phys_segments;
unsigned short nr_integrity_segments;
/*
* The lowest set bit for address gaps between physical segments. This
* provides information necessary for dma optimization opprotunities,
* like for testing if the segments can be coalesced against the
* device's iommu granule.
*/
unsigned char phys_gap_bit;
#ifdef CONFIG_BLK_INLINE_ENCRYPTION
struct bio_crypt_ctx *crypt_ctx;
struct blk_crypto_keyslot *crypt_keyslot;
@@ -208,6 +216,14 @@ struct request {
void *end_io_data;
};
/*
* Returns a mask with all bits starting at req->phys_gap_bit set to 1.
*/
static inline unsigned long req_phys_gap_mask(const struct request *req)
{
return ~(((1 << req->phys_gap_bit) >> 1) - 1);
}
static inline enum req_op req_op(const struct request *req)
{
return req->cmd_flags & REQ_OP_MASK;