[PATCH v3 2/5] block: factor mapped-range topology out of blk_stack_limits
Yao Sang <[email protected]>
| Newsgroups | org.kernel.vger.linux-block,org.infradead.lists.linux-nvme |
|---|---|
| Message-ID | <[email protected]> |
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 <[email protected]> Signed-off-by: Yao Sang <[email protected]> --- 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