[PATCH v2 2/4] block: factor block size and alignment handling out of blk_stack_limits
Yao Sang
sangyao at kylinos.cn
Wed Aug 5 19:46:56 PDT 2026
Topology limits are the block size and alignment limits that the top
device exposes after its data is placed at an offset on a bottom device.
blk_stack_limits() uses start, the first data sector in the bottom device
used by the top device, to calculate alignment_offset.
It then stacks logical_block_size, physical_block_size, io_min, io_opt and
chunk_sectors, checks that they are compatible, and rounds max_sectors,
max_hw_sectors and max_dev_sectors down to the final logical_block_size.
Keep these operations together because the checks and rounding must run
after the final logical and physical block sizes are known. Factor them
into a static blk_stack_topology_limits() helper.
There is no behavior change.
Signed-off-by: Yao Sang <sangyao at kylinos.cn>
---
block/blk-settings.c | 169 ++++++++++++++++++++++++-------------------
1 file changed, 93 insertions(+), 76 deletions(-)
diff --git a/block/blk-settings.c b/block/blk-settings.c
index 8274631290db..1aff818aaaac 100644
--- a/block/blk-settings.c
+++ b/block/blk-settings.c
@@ -756,6 +756,96 @@ static void blk_stack_atomic_writes_limits(struct queue_limits *t,
t->atomic_write_hw_boundary = 0;
}
+/*
+ * Stack and check logical_block_size, physical_block_size, io_min, io_opt,
+ * chunk_sectors and alignment_offset for a bottom-device range, then round
+ * max_sectors, max_hw_sectors and max_dev_sectors to logical_block_size.
+ */
+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 +870,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 +888,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 +918,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