[PATCH v3 2/5] block: factor mapped-range topology out of blk_stack_limits
Yao Sang
sangyao at kylinos.cn
Fri Aug 21 03:10:47 PDT 2026
Block sizes, I/O granularities, chunk boundaries and alignment offsets
must be stacked and checked when a top-device range is mapped onto a
bottom device.
Factor this code into blk_stack_topology_limits(). Keep rounding of the
maximum sector limits there because it depends on the resulting logical
block size.
There is no behavior change.
Reviewed-by: Christoph Hellwig <hch at lst.de>
Signed-off-by: Yao Sang <sangyao at kylinos.cn>
---
block/blk-settings.c | 168 +++++++++++++++++++++++--------------------
1 file changed, 92 insertions(+), 76 deletions(-)
diff --git a/block/blk-settings.c b/block/blk-settings.c
index 8274631290db..9e7cdaaefbca 100644
--- a/block/blk-settings.c
+++ b/block/blk-settings.c
@@ -756,6 +756,95 @@ static void blk_stack_atomic_writes_limits(struct queue_limits *t,
t->atomic_write_hw_boundary = 0;
}
+/*
+ * Stack block sizes, I/O granularities, chunk boundaries and alignment for a
+ * bottom-device range mapped at @start. Round maximum sector limits after the
+ * resulting logical block size is known.
+ */
+static int blk_stack_topology_limits(struct queue_limits *t,
+ const struct queue_limits *b, sector_t start)
+{
+ unsigned int top, bottom, alignment;
+ int ret = 0;
+
+ t->flags |= b->flags & BLK_FLAG_MISALIGNED;
+
+ alignment = queue_limit_alignment_offset(b, start);
+
+ /*
+ * The bottom device has a different alignment. Check that it is
+ * compatible with the current top alignment.
+ */
+ if (t->alignment_offset != alignment) {
+ top = max(t->physical_block_size, t->io_min) + t->alignment_offset;
+ bottom = max(b->physical_block_size, b->io_min) + alignment;
+
+ /* Verify that top and bottom intervals line up. */
+ if (max(top, bottom) % min(top, bottom)) {
+ t->flags |= BLK_FLAG_MISALIGNED;
+ ret = -1;
+ }
+ }
+
+ t->logical_block_size = max(t->logical_block_size,
+ b->logical_block_size);
+ t->physical_block_size = max(t->physical_block_size,
+ b->physical_block_size);
+ t->io_min = max(t->io_min, b->io_min);
+ t->io_opt = lcm_not_zero(t->io_opt, b->io_opt);
+
+ /* Set non-power-of-2 compatible chunk_sectors boundary. */
+ if (b->chunk_sectors)
+ t->chunk_sectors = gcd(t->chunk_sectors, b->chunk_sectors);
+
+ /* Physical block size a multiple of the logical block size? */
+ if (t->physical_block_size & (t->logical_block_size - 1)) {
+ t->physical_block_size = t->logical_block_size;
+ t->flags |= BLK_FLAG_MISALIGNED;
+ ret = -1;
+ }
+
+ /* Minimum I/O a multiple of the physical block size? */
+ if (t->io_min & (t->physical_block_size - 1)) {
+ t->io_min = t->physical_block_size;
+ t->flags |= BLK_FLAG_MISALIGNED;
+ ret = -1;
+ }
+
+ /* Optimal I/O a multiple of the physical block size? */
+ if (t->io_opt & (t->physical_block_size - 1)) {
+ t->io_opt = 0;
+ t->flags |= BLK_FLAG_MISALIGNED;
+ ret = -1;
+ }
+
+ /* chunk_sectors a multiple of the physical block size? */
+ if (t->chunk_sectors % (t->physical_block_size >> SECTOR_SHIFT)) {
+ t->chunk_sectors = 0;
+ t->flags |= BLK_FLAG_MISALIGNED;
+ ret = -1;
+ }
+
+ /* Find lowest common alignment_offset. */
+ t->alignment_offset = lcm_not_zero(t->alignment_offset, alignment) %
+ max(t->physical_block_size, t->io_min);
+
+ /* Verify that new alignment_offset is on a logical block boundary. */
+ if (t->alignment_offset & (t->logical_block_size - 1)) {
+ t->flags |= BLK_FLAG_MISALIGNED;
+ ret = -1;
+ }
+
+ t->max_sectors = blk_round_down_sectors(t->max_sectors,
+ t->logical_block_size);
+ t->max_hw_sectors = blk_round_down_sectors(t->max_hw_sectors,
+ t->logical_block_size);
+ t->max_dev_sectors = blk_round_down_sectors(t->max_dev_sectors,
+ t->logical_block_size);
+
+ return ret;
+}
+
/**
* blk_stack_limits - adjust queue_limits for stacked devices
* @t: the stacking driver limits (top device)
@@ -780,8 +869,8 @@ static void blk_stack_atomic_writes_limits(struct queue_limits *t,
int blk_stack_limits(struct queue_limits *t, struct queue_limits *b,
sector_t start)
{
- unsigned int top, bottom, alignment;
- int ret = 0;
+ unsigned int alignment;
+ int ret;
t->features |= (b->features & BLK_FEAT_INHERIT_MASK);
@@ -798,8 +887,6 @@ int blk_stack_limits(struct queue_limits *t, struct queue_limits *b,
if (!(b->features & BLK_FEAT_PCI_P2PDMA))
t->features &= ~BLK_FEAT_PCI_P2PDMA;
- t->flags |= (b->flags & BLK_FLAG_MISALIGNED);
-
t->max_sectors = min_not_zero(t->max_sectors, b->max_sectors);
t->max_user_sectors = min_not_zero(t->max_user_sectors,
b->max_user_sectors);
@@ -830,80 +917,9 @@ int blk_stack_limits(struct queue_limits *t, struct queue_limits *b,
t->max_segment_size = min_not_zero(t->max_segment_size,
b->max_segment_size);
-
- alignment = queue_limit_alignment_offset(b, start);
-
- /* Bottom device has different alignment. Check that it is
- * compatible with the current top alignment.
- */
- if (t->alignment_offset != alignment) {
-
- top = max(t->physical_block_size, t->io_min)
- + t->alignment_offset;
- bottom = max(b->physical_block_size, b->io_min) + alignment;
-
- /* Verify that top and bottom intervals line up */
- if (max(top, bottom) % min(top, bottom)) {
- t->flags |= BLK_FLAG_MISALIGNED;
- ret = -1;
- }
- }
-
- t->logical_block_size = max(t->logical_block_size,
- b->logical_block_size);
-
- t->physical_block_size = max(t->physical_block_size,
- b->physical_block_size);
-
- t->io_min = max(t->io_min, b->io_min);
- t->io_opt = lcm_not_zero(t->io_opt, b->io_opt);
t->dma_alignment = max(t->dma_alignment, b->dma_alignment);
- /* Set non-power-of-2 compatible chunk_sectors boundary */
- if (b->chunk_sectors)
- t->chunk_sectors = gcd(t->chunk_sectors, b->chunk_sectors);
-
- /* Physical block size a multiple of the logical block size? */
- if (t->physical_block_size & (t->logical_block_size - 1)) {
- t->physical_block_size = t->logical_block_size;
- t->flags |= BLK_FLAG_MISALIGNED;
- ret = -1;
- }
-
- /* Minimum I/O a multiple of the physical block size? */
- if (t->io_min & (t->physical_block_size - 1)) {
- t->io_min = t->physical_block_size;
- t->flags |= BLK_FLAG_MISALIGNED;
- ret = -1;
- }
-
- /* Optimal I/O a multiple of the physical block size? */
- if (t->io_opt & (t->physical_block_size - 1)) {
- t->io_opt = 0;
- t->flags |= BLK_FLAG_MISALIGNED;
- ret = -1;
- }
-
- /* chunk_sectors a multiple of the physical block size? */
- if (t->chunk_sectors % (t->physical_block_size >> SECTOR_SHIFT)) {
- t->chunk_sectors = 0;
- t->flags |= BLK_FLAG_MISALIGNED;
- ret = -1;
- }
-
- /* Find lowest common alignment_offset */
- t->alignment_offset = lcm_not_zero(t->alignment_offset, alignment)
- % max(t->physical_block_size, t->io_min);
-
- /* Verify that new alignment_offset is on a logical block boundary */
- if (t->alignment_offset & (t->logical_block_size - 1)) {
- t->flags |= BLK_FLAG_MISALIGNED;
- ret = -1;
- }
-
- t->max_sectors = blk_round_down_sectors(t->max_sectors, t->logical_block_size);
- t->max_hw_sectors = blk_round_down_sectors(t->max_hw_sectors, t->logical_block_size);
- t->max_dev_sectors = blk_round_down_sectors(t->max_dev_sectors, t->logical_block_size);
+ ret = blk_stack_topology_limits(t, b, start);
/* Discard alignment and granularity */
if (b->discard_granularity) {
--
2.25.1
More information about the Linux-nvme
mailing list