* [PATCH v2 1/4] nvme: factor namespace-head queue-limit update
2026-08-06 2:46 [PATCH v2 0/4] block/nvme: split path limits for namespace heads Yao Sang
@ 2026-08-06 2:46 ` Yao Sang
2026-08-17 8:04 ` Christoph Hellwig
2026-08-17 16:32 ` John Garry
2026-08-06 2:46 ` [PATCH v2 2/4] block: factor block size and alignment handling out of blk_stack_limits Yao Sang
` (3 subsequent siblings)
4 siblings, 2 replies; 12+ messages in thread
From: Yao Sang @ 2026-08-06 2:46 UTC (permalink / raw)
To: Jens Axboe, Keith Busch, Christoph Hellwig, Sagi Grimberg
Cc: linux-block, linux-nvme, Yao Sang
Move the namespace head queue-limit update out of nvme_update_ns_info().
The new helper keeps the current queue_limits_stack_bdev() based behavior
intact, including zoned resource handling, write-stream assignment,
integrity setup, capacity and readonly updates, path revalidation, and
namespace-head zone revalidation.
Keep queue-limit commit failures on the existing short-circuit path so
capacity and namespace-head state are only updated after a successful
limits update.
The helper gives namespace-head queue-limit updates a single NVMe-local
entry point while keeping the namespace information refresh sequencing
unchanged.
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Yao Sang <sangyao@kylinos.cn>
---
drivers/nvme/host/core.c | 104 +++++++++++++++++++++------------------
1 file changed, 56 insertions(+), 48 deletions(-)
diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c
index cb93ada4376a..e3d27c0440db 100644
--- a/drivers/nvme/host/core.c
+++ b/drivers/nvme/host/core.c
@@ -2528,6 +2528,60 @@ static void nvme_stack_zone_resources(struct queue_limits *t,
min_not_zero(t->max_active_zones, b->max_active_zones);
}
+static int nvme_update_ns_head_limits(struct nvme_ns *ns,
+ struct nvme_ns_info *info, bool unsupported)
+{
+ struct queue_limits *ns_lim = &ns->disk->queue->limits;
+ struct request_queue *head_q = ns->head->disk->queue;
+ struct queue_limits lim;
+ unsigned int memflags;
+ int ret;
+
+ lim = queue_limits_start_update(head_q);
+ memflags = blk_mq_freeze_queue(head_q);
+ /*
+ * queue_limits mixes values that are the hardware limitations
+ * for bio splitting with what is the device configuration.
+ *
+ * For NVMe the device configuration can change after e.g. a
+ * Format command, and we really want to pick up the new format
+ * value here. But we must still stack the queue limits to the
+ * least common denominator for multipathing to split the bios
+ * properly.
+ *
+ * To work around this, we explicitly set the device
+ * configuration to those that we just queried, but only stack
+ * the splitting limits in to make sure we still obey possibly
+ * lower limitations of other controllers.
+ */
+ lim.logical_block_size = ns_lim->logical_block_size;
+ lim.physical_block_size = ns_lim->physical_block_size;
+ lim.io_min = ns_lim->io_min;
+ lim.io_opt = ns_lim->io_opt;
+ queue_limits_stack_bdev(&lim, ns->disk->part0, 0,
+ ns->head->disk->disk_name);
+ if (lim.features & BLK_FEAT_ZONED)
+ nvme_stack_zone_resources(&lim, ns_lim);
+ if (unsupported)
+ ns->head->disk->flags |= GENHD_FL_HIDDEN;
+ else
+ nvme_init_integrity(ns->head, &lim, info);
+ lim.max_write_streams = ns_lim->max_write_streams;
+ lim.write_stream_granularity = ns_lim->write_stream_granularity;
+ ret = queue_limits_commit_update(head_q, &lim);
+ if (ret)
+ goto unfreeze_head_queue;
+
+ set_capacity_and_notify(ns->head->disk, get_capacity(ns->disk));
+ set_disk_ro(ns->head->disk, nvme_ns_is_readonly(ns, info));
+ nvme_mpath_revalidate_paths(ns->head);
+ ret = nvme_mpath_revalidate_zones(ns->head);
+
+unfreeze_head_queue:
+ blk_mq_unfreeze_queue(head_q, memflags);
+ return ret;
+}
+
static int nvme_update_ns_info(struct nvme_ns *ns, struct nvme_ns_info *info)
{
bool unsupported = false;
@@ -2566,54 +2620,8 @@ static int nvme_update_ns_info(struct nvme_ns *ns, struct nvme_ns_info *info)
ret = 0;
}
- if (!ret && nvme_ns_head_multipath(ns->head)) {
- struct queue_limits *ns_lim = &ns->disk->queue->limits;
- struct queue_limits lim;
- unsigned int memflags;
-
- lim = queue_limits_start_update(ns->head->disk->queue);
- memflags = blk_mq_freeze_queue(ns->head->disk->queue);
- /*
- * queue_limits mixes values that are the hardware limitations
- * for bio splitting with what is the device configuration.
- *
- * For NVMe the device configuration can change after e.g. a
- * Format command, and we really want to pick up the new format
- * value here. But we must still stack the queue limits to the
- * least common denominator for multipathing to split the bios
- * properly.
- *
- * To work around this, we explicitly set the device
- * configuration to those that we just queried, but only stack
- * the splitting limits in to make sure we still obey possibly
- * lower limitations of other controllers.
- */
- lim.logical_block_size = ns_lim->logical_block_size;
- lim.physical_block_size = ns_lim->physical_block_size;
- lim.io_min = ns_lim->io_min;
- lim.io_opt = ns_lim->io_opt;
- queue_limits_stack_bdev(&lim, ns->disk->part0, 0,
- ns->head->disk->disk_name);
- if (lim.features & BLK_FEAT_ZONED)
- nvme_stack_zone_resources(&lim, ns_lim);
- if (unsupported)
- ns->head->disk->flags |= GENHD_FL_HIDDEN;
- else
- nvme_init_integrity(ns->head, &lim, info);
- lim.max_write_streams = ns_lim->max_write_streams;
- lim.write_stream_granularity = ns_lim->write_stream_granularity;
- ret = queue_limits_commit_update(ns->head->disk->queue, &lim);
- if (ret)
- goto unfreeze_head_queue;
-
- set_capacity_and_notify(ns->head->disk, get_capacity(ns->disk));
- set_disk_ro(ns->head->disk, nvme_ns_is_readonly(ns, info));
- nvme_mpath_revalidate_paths(ns->head);
- ret = nvme_mpath_revalidate_zones(ns->head);
-
-unfreeze_head_queue:
- blk_mq_unfreeze_queue(ns->head->disk->queue, memflags);
- }
+ if (!ret && nvme_ns_head_multipath(ns->head))
+ ret = nvme_update_ns_head_limits(ns, info, unsupported);
return ret;
}
--
2.25.1
^ permalink raw reply related [flat|nested] 12+ messages in thread* Re: [PATCH v2 1/4] nvme: factor namespace-head queue-limit update
2026-08-06 2:46 ` [PATCH v2 1/4] nvme: factor namespace-head queue-limit update Yao Sang
@ 2026-08-17 8:04 ` Christoph Hellwig
2026-08-17 16:32 ` John Garry
1 sibling, 0 replies; 12+ messages in thread
From: Christoph Hellwig @ 2026-08-17 8:04 UTC (permalink / raw)
To: Yao Sang
Cc: Jens Axboe, Keith Busch, Christoph Hellwig, Sagi Grimberg,
linux-block, linux-nvme
> + /*
> + * queue_limits mixes values that are the hardware limitations
> + * for bio splitting with what is the device configuration.
> + *
A little nitpick despite already having reviewed this: we can reflow
this comments to use up all 80 characters now that the indentation
was reduced.
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH v2 1/4] nvme: factor namespace-head queue-limit update
2026-08-06 2:46 ` [PATCH v2 1/4] nvme: factor namespace-head queue-limit update Yao Sang
2026-08-17 8:04 ` Christoph Hellwig
@ 2026-08-17 16:32 ` John Garry
1 sibling, 0 replies; 12+ messages in thread
From: John Garry @ 2026-08-17 16:32 UTC (permalink / raw)
To: Yao Sang, Jens Axboe, Keith Busch, Christoph Hellwig,
Sagi Grimberg
Cc: linux-block@vger.kernel.org, linux-nvme@lists.infradead.org
On 06/08/2026 03:46, Yao Sang wrote:
> Move the namespace head queue-limit update out of nvme_update_ns_info().
> The new helper keeps the current queue_limits_stack_bdev() based behavior
> intact, including zoned resource handling, write-stream assignment,
> integrity setup, capacity and readonly updates, path revalidation, and
> namespace-head zone revalidation.
>
> Keep queue-limit commit failures on the existing short-circuit path so
> capacity and namespace-head state are only updated after a successful
> limits update.
>
> The helper gives namespace-head queue-limit updates a single NVMe-local
> entry point while keeping the namespace information refresh sequencing
> unchanged.
Like the cover letter, this message is too verbose. So much so that I
lose track of what is important to note - that being the motivation for
the change.
The motivation seems to be to just factor out the NS head update into a
separate function as it deserves its own function and the code will be
neater, but not because it will in future have multiple callsites.
>
> Reviewed-by: Christoph Hellwig <hch@lst.de>
> Signed-off-by: Yao Sang <sangyao@kylinos.cn>
> ---
> drivers/nvme/host/core.c | 104 +++++++++++++++++++++------------------
> 1 file changed, 56 insertions(+), 48 deletions(-)
>
> diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c
> index cb93ada4376a..e3d27c0440db 100644
> --- a/drivers/nvme/host/core.c
> +++ b/drivers/nvme/host/core.c
> @@ -2528,6 +2528,60 @@ static void nvme_stack_zone_resources(struct queue_limits *t,
> min_not_zero(t->max_active_zones, b->max_active_zones);
> }
>
> +static int nvme_update_ns_head_limits(struct nvme_ns *ns,
> + struct nvme_ns_info *info, bool unsupported)
> +{
> + struct queue_limits *ns_lim = &ns->disk->queue->limits;
> + struct request_queue *head_q = ns->head->disk->queue;
> + struct queue_limits lim;
> + unsigned int memflags;
> + int ret;
> +
> + lim = queue_limits_start_update(head_q);
> + memflags = blk_mq_freeze_queue(head_q);
> + /*
> + * queue_limits mixes values that are the hardware limitations
> + * for bio splitting with what is the device configuration.
> + *
> + * For NVMe the device configuration can change after e.g. a
> + * Format command, and we really want to pick up the new format
> + * value here. But we must still stack the queue limits to the
> + * least common denominator for multipathing to split the bios
> + * properly.
> + *
> + * To work around this, we explicitly set the device
> + * configuration to those that we just queried, but only stack
> + * the splitting limits in to make sure we still obey possibly
> + * lower limitations of other controllers.
> + */
> + lim.logical_block_size = ns_lim->logical_block_size;
> + lim.physical_block_size = ns_lim->physical_block_size;
> + lim.io_min = ns_lim->io_min;
> + lim.io_opt = ns_lim->io_opt;
> + queue_limits_stack_bdev(&lim, ns->disk->part0, 0,
> + ns->head->disk->disk_name);
> + if (lim.features & BLK_FEAT_ZONED)
> + nvme_stack_zone_resources(&lim, ns_lim);
> + if (unsupported)
> + ns->head->disk->flags |= GENHD_FL_HIDDEN;
> + else
> + nvme_init_integrity(ns->head, &lim, info);
> + lim.max_write_streams = ns_lim->max_write_streams;
> + lim.write_stream_granularity = ns_lim->write_stream_granularity;
> + ret = queue_limits_commit_update(head_q, &lim);
> + if (ret)
> + goto unfreeze_head_queue;
> +
> + set_capacity_and_notify(ns->head->disk, get_capacity(ns->disk));
> + set_disk_ro(ns->head->disk, nvme_ns_is_readonly(ns, info));
> + nvme_mpath_revalidate_paths(ns->head);
> + ret = nvme_mpath_revalidate_zones(ns->head);
> +
> +unfreeze_head_queue:
> + blk_mq_unfreeze_queue(head_q, memflags);
> + return ret;
> +}
> +
> static int nvme_update_ns_info(struct nvme_ns *ns, struct nvme_ns_info *info)
> {
> bool unsupported = false;
> @@ -2566,54 +2620,8 @@ static int nvme_update_ns_info(struct nvme_ns *ns, struct nvme_ns_info *info)
> ret = 0;
> }
>
> - if (!ret && nvme_ns_head_multipath(ns->head)) {
> - struct queue_limits *ns_lim = &ns->disk->queue->limits;
> - struct queue_limits lim;
> - unsigned int memflags;
> -
> - lim = queue_limits_start_update(ns->head->disk->queue);
> - memflags = blk_mq_freeze_queue(ns->head->disk->queue);
> - /*
> - * queue_limits mixes values that are the hardware limitations
> - * for bio splitting with what is the device configuration.
> - *
> - * For NVMe the device configuration can change after e.g. a
> - * Format command, and we really want to pick up the new format
> - * value here. But we must still stack the queue limits to the
> - * least common denominator for multipathing to split the bios
> - * properly.
> - *
> - * To work around this, we explicitly set the device
> - * configuration to those that we just queried, but only stack
> - * the splitting limits in to make sure we still obey possibly
> - * lower limitations of other controllers.
> - */
> - lim.logical_block_size = ns_lim->logical_block_size;
> - lim.physical_block_size = ns_lim->physical_block_size;
> - lim.io_min = ns_lim->io_min;
> - lim.io_opt = ns_lim->io_opt;
> - queue_limits_stack_bdev(&lim, ns->disk->part0, 0,
> - ns->head->disk->disk_name);
> - if (lim.features & BLK_FEAT_ZONED)
> - nvme_stack_zone_resources(&lim, ns_lim);
> - if (unsupported)
> - ns->head->disk->flags |= GENHD_FL_HIDDEN;
> - else
> - nvme_init_integrity(ns->head, &lim, info);
> - lim.max_write_streams = ns_lim->max_write_streams;
> - lim.write_stream_granularity = ns_lim->write_stream_granularity;
> - ret = queue_limits_commit_update(ns->head->disk->queue, &lim);
> - if (ret)
> - goto unfreeze_head_queue;
> -
> - set_capacity_and_notify(ns->head->disk, get_capacity(ns->disk));
> - set_disk_ro(ns->head->disk, nvme_ns_is_readonly(ns, info));
> - nvme_mpath_revalidate_paths(ns->head);
> - ret = nvme_mpath_revalidate_zones(ns->head);
> -
> -unfreeze_head_queue:
> - blk_mq_unfreeze_queue(ns->head->disk->queue, memflags);
> - }
> + if (!ret && nvme_ns_head_multipath(ns->head))
> + ret = nvme_update_ns_head_limits(ns, info, unsupported);
>
> return ret;
> }
^ permalink raw reply [flat|nested] 12+ messages in thread
* [PATCH v2 2/4] block: factor block size and alignment handling out of blk_stack_limits
2026-08-06 2:46 [PATCH v2 0/4] block/nvme: split path limits for namespace heads Yao Sang
2026-08-06 2:46 ` [PATCH v2 1/4] nvme: factor namespace-head queue-limit update Yao Sang
@ 2026-08-06 2:46 ` Yao Sang
2026-08-17 8:05 ` Christoph Hellwig
2026-08-17 17:05 ` John Garry
2026-08-06 2:46 ` [PATCH v2 3/4] block: factor out path limit stacking Yao Sang
` (2 subsequent siblings)
4 siblings, 2 replies; 12+ messages in thread
From: Yao Sang @ 2026-08-06 2:46 UTC (permalink / raw)
To: Jens Axboe, Keith Busch, Christoph Hellwig, Sagi Grimberg
Cc: linux-block, linux-nvme, Yao Sang
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@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
^ permalink raw reply related [flat|nested] 12+ messages in thread* Re: [PATCH v2 2/4] block: factor block size and alignment handling out of blk_stack_limits
2026-08-06 2:46 ` [PATCH v2 2/4] block: factor block size and alignment handling out of blk_stack_limits Yao Sang
@ 2026-08-17 8:05 ` Christoph Hellwig
2026-08-17 17:05 ` John Garry
1 sibling, 0 replies; 12+ messages in thread
From: Christoph Hellwig @ 2026-08-17 8:05 UTC (permalink / raw)
To: Yao Sang
Cc: Jens Axboe, Keith Busch, Christoph Hellwig, Sagi Grimberg,
linux-block, linux-nvme
Some of this could use the additional space on the lines due to reducing
the indentation, but otherwise this looks good:
Reviewed-by: Christoph Hellwig <hch@lst.de>
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH v2 2/4] block: factor block size and alignment handling out of blk_stack_limits
2026-08-06 2:46 ` [PATCH v2 2/4] block: factor block size and alignment handling out of blk_stack_limits Yao Sang
2026-08-17 8:05 ` Christoph Hellwig
@ 2026-08-17 17:05 ` John Garry
1 sibling, 0 replies; 12+ messages in thread
From: John Garry @ 2026-08-17 17:05 UTC (permalink / raw)
To: Yao Sang, Jens Axboe, Keith Busch, Christoph Hellwig,
Sagi Grimberg
Cc: linux-block, linux-nvme
On 06/08/2026 03:46, Yao Sang wrote:
> 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.
It still is not clear to me what is the criteria for a limit to be
evaluated in blk_stack_topology_limits() (and not in blk_stack_limits()).
You seem to be just saying that some limits need to be calculated before
other dependent limits, so put them in a separate function.
>
> There is no behavior change.
> > Signed-off-by: Yao Sang <sangyao@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.
> + */
This just describes what the code does. Anyone can see that.
> +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;
^ permalink raw reply [flat|nested] 12+ messages in thread
* [PATCH v2 3/4] block: factor out path limit stacking
2026-08-06 2:46 [PATCH v2 0/4] block/nvme: split path limits for namespace heads Yao Sang
2026-08-06 2:46 ` [PATCH v2 1/4] nvme: factor namespace-head queue-limit update Yao Sang
2026-08-06 2:46 ` [PATCH v2 2/4] block: factor block size and alignment handling out of blk_stack_limits Yao Sang
@ 2026-08-06 2:46 ` Yao Sang
2026-08-17 8:10 ` Christoph Hellwig
2026-08-06 2:46 ` [PATCH v2 4/4] block, nvme: use lower-level limit helpers for namespace heads Yao Sang
2026-08-10 8:50 ` [PATCH v2 0/4] block/nvme: split path limits " Yao Sang
4 siblings, 1 reply; 12+ messages in thread
From: Yao Sang @ 2026-08-06 2:46 UTC (permalink / raw)
To: Jens Axboe, Keith Busch, Christoph Hellwig, Sagi Grimberg
Cc: linux-block, linux-nvme, Yao Sang
Some queue limits are path limits: every queue that can execute an I/O
must support them, and they do not depend on start, the first data sector
used in a bottom device.
This includes BLK_FEAT_NOWAIT, BLK_FEAT_POLL, BLK_FEAT_PCI_P2PDMA,
max_hw_sectors, max_dev_sectors, seg_boundary_mask, virt_boundary_mask,
max_segments, max_integrity_segments, max_segment_size and dma_alignment.
Move these path limits into a static blk_stack_path_limits() helper and
call it from blk_stack_limits(). Keep topology, discard alignment, atomic
writes and other operation and resource limits in blk_stack_limits() where
the caller context is still available.
There is no behavior change.
Signed-off-by: Yao Sang <sangyao@kylinos.cn>
---
block/blk-settings.c | 59 +++++++++++++++++++++++---------------------
1 file changed, 31 insertions(+), 28 deletions(-)
diff --git a/block/blk-settings.c b/block/blk-settings.c
index 1aff818aaaac..40cd3490f168 100644
--- a/block/blk-settings.c
+++ b/block/blk-settings.c
@@ -756,6 +756,36 @@ static void blk_stack_atomic_writes_limits(struct queue_limits *t,
t->atomic_write_hw_boundary = 0;
}
+static void blk_stack_path_limits(struct queue_limits *t,
+ const struct queue_limits *b)
+{
+ /*
+ * Some features need to be supported both by the stacking driver and all
+ * underlying devices. The stacking driver sets these flags before
+ * stacking the limits, and this will clear the flags if any of the
+ * underlying devices does not support it.
+ */
+ if (!(b->features & BLK_FEAT_NOWAIT))
+ t->features &= ~BLK_FEAT_NOWAIT;
+ if (!(b->features & BLK_FEAT_POLL))
+ t->features &= ~BLK_FEAT_POLL;
+ if (!(b->features & BLK_FEAT_PCI_P2PDMA))
+ t->features &= ~BLK_FEAT_PCI_P2PDMA;
+
+ t->max_hw_sectors = min_not_zero(t->max_hw_sectors, b->max_hw_sectors);
+ t->max_dev_sectors = min_not_zero(t->max_dev_sectors, b->max_dev_sectors);
+ t->seg_boundary_mask = min_not_zero(t->seg_boundary_mask,
+ b->seg_boundary_mask);
+ t->virt_boundary_mask = min_not_zero(t->virt_boundary_mask,
+ b->virt_boundary_mask);
+ t->max_segments = min_not_zero(t->max_segments, b->max_segments);
+ t->max_integrity_segments = min_not_zero(t->max_integrity_segments,
+ b->max_integrity_segments);
+ t->max_segment_size = min_not_zero(t->max_segment_size,
+ b->max_segment_size);
+ t->dma_alignment = max(t->dma_alignment, b->dma_alignment);
+}
+
/*
* 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
@@ -874,25 +904,11 @@ int blk_stack_limits(struct queue_limits *t, struct queue_limits *b,
int ret;
t->features |= (b->features & BLK_FEAT_INHERIT_MASK);
-
- /*
- * Some feaures need to be supported both by the stacking driver and all
- * underlying devices. The stacking driver sets these flags before
- * stacking the limits, and this will clear the flags if any of the
- * underlying devices does not support it.
- */
- if (!(b->features & BLK_FEAT_NOWAIT))
- t->features &= ~BLK_FEAT_NOWAIT;
- if (!(b->features & BLK_FEAT_POLL))
- t->features &= ~BLK_FEAT_POLL;
- if (!(b->features & BLK_FEAT_PCI_P2PDMA))
- t->features &= ~BLK_FEAT_PCI_P2PDMA;
+ blk_stack_path_limits(t, b);
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);
- t->max_hw_sectors = min_not_zero(t->max_hw_sectors, b->max_hw_sectors);
- t->max_dev_sectors = min_not_zero(t->max_dev_sectors, b->max_dev_sectors);
t->max_write_zeroes_sectors = min(t->max_write_zeroes_sectors,
b->max_write_zeroes_sectors);
t->max_user_wzeroes_unmap_sectors =
@@ -904,21 +920,8 @@ int blk_stack_limits(struct queue_limits *t, struct queue_limits *b,
t->max_hw_zone_append_sectors = min(t->max_hw_zone_append_sectors,
b->max_hw_zone_append_sectors);
-
- t->seg_boundary_mask = min_not_zero(t->seg_boundary_mask,
- b->seg_boundary_mask);
- t->virt_boundary_mask = min_not_zero(t->virt_boundary_mask,
- b->virt_boundary_mask);
-
- t->max_segments = min_not_zero(t->max_segments, b->max_segments);
t->max_discard_segments = min_not_zero(t->max_discard_segments,
b->max_discard_segments);
- t->max_integrity_segments = min_not_zero(t->max_integrity_segments,
- b->max_integrity_segments);
-
- t->max_segment_size = min_not_zero(t->max_segment_size,
- b->max_segment_size);
- t->dma_alignment = max(t->dma_alignment, b->dma_alignment);
ret = blk_stack_topology_limits(t, b, start);
--
2.25.1
^ permalink raw reply related [flat|nested] 12+ messages in thread* Re: [PATCH v2 3/4] block: factor out path limit stacking
2026-08-06 2:46 ` [PATCH v2 3/4] block: factor out path limit stacking Yao Sang
@ 2026-08-17 8:10 ` Christoph Hellwig
0 siblings, 0 replies; 12+ messages in thread
From: Christoph Hellwig @ 2026-08-17 8:10 UTC (permalink / raw)
To: Yao Sang
Cc: Jens Axboe, Keith Busch, Christoph Hellwig, Sagi Grimberg,
linux-block, linux-nvme
On Thu, Aug 06, 2026 at 10:46:57AM +0800, Yao Sang wrote:
> +static void blk_stack_path_limits(struct queue_limits *t,
> + const struct queue_limits *b)
I find the path limits name a bit confusing, but I don't really
have a much better suggestion.
> + t->max_dev_sectors = min_not_zero(t->max_dev_sectors, b->max_dev_sectors);
overly long line here.
I wonder if we sould have a helper macro that encapsulates the
t = min_not_zero(t, b)
pattern to make all these lines a bit easier to read while we're
at it?
> 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);
> - t->max_hw_sectors = min_not_zero(t->max_hw_sectors, b->max_hw_sectors);
> - t->max_dev_sectors = min_not_zero(t->max_dev_sectors, b->max_dev_sectors);
> t->max_write_zeroes_sectors = min(t->max_write_zeroes_sectors,
> b->max_write_zeroes_sectors);
> t->max_user_wzeroes_unmap_sectors =
I'm also not sure why some limits are included in the path limits
and other not. E.g. wy not max_write_zeroes_sectors?
^ permalink raw reply [flat|nested] 12+ messages in thread
* [PATCH v2 4/4] block, nvme: use lower-level limit helpers for namespace heads
2026-08-06 2:46 [PATCH v2 0/4] block/nvme: split path limits for namespace heads Yao Sang
` (2 preceding siblings ...)
2026-08-06 2:46 ` [PATCH v2 3/4] block: factor out path limit stacking Yao Sang
@ 2026-08-06 2:46 ` Yao Sang
2026-08-17 8:13 ` Christoph Hellwig
2026-08-10 8:50 ` [PATCH v2 0/4] block/nvme: split path limits " Yao Sang
4 siblings, 1 reply; 12+ messages in thread
From: Yao Sang @ 2026-08-06 2:46 UTC (permalink / raw)
To: Jens Axboe, Keith Busch, Christoph Hellwig, Sagi Grimberg
Cc: linux-block, linux-nvme, Yao Sang
An NVMe namespace head and each path refer to the same namespace.
queue_limits_stack_bdev() treats the path as a bottom-device range and
applies all of blk_stack_limits(), including topology rules and start-based
atomic write checks. These mapped-device rules should not be used when
updating the namespace head.
Make blk_stack_path_limits() and the existing
blk_stack_atomic_writes_limits() public when adding their first caller
outside the block layer. Keep the existing names and parameter types.
Refresh logical_block_size, physical_block_size, io_min, io_opt,
discard_granularity, zone_write_granularity and the write stream limits
from the namespace that was just scanned. Keep chunk_sectors conservative
for non-zoned namespaces because NVME_QUIRK_STRIPE_SIZE can make it
controller-specific, while zoned namespaces refresh the zone size directly.
Use blk_stack_path_limits() for the all-path execution feature bits and
hardware limits that must work for every path, and use
blk_stack_atomic_writes_limits() with a zero start sector. Keep the
non-path feature handling in NVMe: the namespace head needs only inherited
features that can describe an NVMe path. Zoned is handled with the
namespace layout, and RAID partial stripes are not an NVMe namespace-head
property.
Keep max_user_* from queue_limits_start_update(), rebuild the integrity
profile with nvme_init_integrity(), and retain the existing write zeroes,
discard and zone resource updates in NVMe.
Signed-off-by: Yao Sang <sangyao@kylinos.cn>
---
block/blk-settings.c | 23 +++++++-
drivers/nvme/host/core.c | 115 +++++++++++++++++++++++++++++----------
include/linux/blkdev.h | 4 ++
3 files changed, 109 insertions(+), 33 deletions(-)
diff --git a/block/blk-settings.c b/block/blk-settings.c
index 40cd3490f168..877834e88745 100644
--- a/block/blk-settings.c
+++ b/block/blk-settings.c
@@ -726,8 +726,14 @@ static bool blk_stack_atomic_writes_head(struct queue_limits *t,
return true;
}
-static void blk_stack_atomic_writes_limits(struct queue_limits *t,
- struct queue_limits *b, sector_t start)
+/**
+ * blk_stack_atomic_writes_limits - stack atomic write limits
+ * @t: the stacking driver limits (top device)
+ * @b: the underlying queue limits (bottom device)
+ * @start: first data sector within bottom device
+ */
+void blk_stack_atomic_writes_limits(struct queue_limits *t,
+ struct queue_limits *b, sector_t start)
{
if (!(b->features & BLK_FEAT_ATOMIC_WRITES))
goto unsupported;
@@ -755,8 +761,18 @@ static void blk_stack_atomic_writes_limits(struct queue_limits *t,
t->atomic_write_hw_unit_min = 0;
t->atomic_write_hw_boundary = 0;
}
+EXPORT_SYMBOL_GPL(blk_stack_atomic_writes_limits);
-static void blk_stack_path_limits(struct queue_limits *t,
+/**
+ * blk_stack_path_limits - update limits that must hold for every I/O path
+ * @t: the queue limits to update
+ * @b: the queue limits for an I/O path
+ *
+ * Clear BLK_FEAT_NOWAIT, BLK_FEAT_POLL and BLK_FEAT_PCI_P2PDMA when they
+ * are not set in @b. Stack the sector, segment, integrity segment and DMA
+ * alignment limits that every path must support.
+ */
+void blk_stack_path_limits(struct queue_limits *t,
const struct queue_limits *b)
{
/*
@@ -785,6 +801,7 @@ static void blk_stack_path_limits(struct queue_limits *t,
b->max_segment_size);
t->dma_alignment = max(t->dma_alignment, b->dma_alignment);
}
+EXPORT_SYMBOL_GPL(blk_stack_path_limits);
/*
* Stack and check logical_block_size, physical_block_size, io_min, io_opt,
diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c
index e3d27c0440db..181394380510 100644
--- a/drivers/nvme/host/core.c
+++ b/drivers/nvme/host/core.c
@@ -11,6 +11,7 @@
#include <linux/compat.h>
#include <linux/delay.h>
#include <linux/errno.h>
+#include <linux/gcd.h>
#include <linux/hdreg.h>
#include <linux/kernel.h>
#include <linux/module.h>
@@ -2520,12 +2521,89 @@ static int nvme_update_ns_info_block(struct nvme_ns *ns,
return ret;
}
-static void nvme_stack_zone_resources(struct queue_limits *t,
- const struct queue_limits *b)
+static void nvme_apply_ns_head_identify_limits(struct queue_limits *lim,
+ const struct queue_limits *ns_lim)
{
- t->max_open_zones = min_not_zero(t->max_open_zones, b->max_open_zones);
- t->max_active_zones =
- min_not_zero(t->max_active_zones, b->max_active_zones);
+ /*
+ * The namespace scan sets these values from Identify data and limits
+ * calculated from it. Refresh them instead of combining them with values
+ * left from an earlier namespace scan.
+ */
+ lim->features &= ~BLK_FEAT_ZONED;
+ lim->features |= ns_lim->features & BLK_FEAT_ZONED;
+ lim->logical_block_size = ns_lim->logical_block_size;
+ lim->physical_block_size = ns_lim->physical_block_size;
+ lim->io_min = ns_lim->io_min;
+ lim->io_opt = ns_lim->io_opt;
+ /* A non-zoned path may have a controller-specific stripe size. */
+ if (ns_lim->features & BLK_FEAT_ZONED)
+ lim->chunk_sectors = ns_lim->chunk_sectors;
+ else if (ns_lim->chunk_sectors)
+ lim->chunk_sectors = gcd(lim->chunk_sectors,
+ ns_lim->chunk_sectors);
+ lim->alignment_offset = 0;
+ lim->discard_alignment = 0;
+ lim->flags &= ~BLK_FLAG_MISALIGNED;
+ lim->discard_granularity = ns_lim->discard_granularity;
+ lim->zone_write_granularity = ns_lim->zone_write_granularity;
+ lim->max_write_streams = ns_lim->max_write_streams;
+ lim->write_stream_granularity = ns_lim->write_stream_granularity;
+}
+
+static void nvme_apply_ns_head_operation_limits(struct queue_limits *lim,
+ const struct queue_limits *ns_lim)
+{
+ /* Keep the existing minimums for controller command limits. */
+ lim->max_write_zeroes_sectors =
+ min(lim->max_write_zeroes_sectors,
+ ns_lim->max_write_zeroes_sectors);
+ lim->max_hw_wzeroes_unmap_sectors =
+ min(lim->max_hw_wzeroes_unmap_sectors,
+ ns_lim->max_hw_wzeroes_unmap_sectors);
+ lim->max_discard_segments =
+ min_not_zero(lim->max_discard_segments,
+ ns_lim->max_discard_segments);
+ if (ns_lim->discard_granularity)
+ lim->max_hw_discard_sectors =
+ min_not_zero(lim->max_hw_discard_sectors,
+ ns_lim->max_hw_discard_sectors);
+ blk_stack_atomic_writes_limits(lim, ns_lim, 0);
+}
+
+static void nvme_apply_ns_head_zone_limits(struct queue_limits *lim,
+ const struct queue_limits *ns_lim)
+{
+ /*
+ * Zone geometry was set above. max_hw_zone_append_sectors must work
+ * for every path, while max_open_zones and max_active_zones are
+ * namespace resources.
+ */
+ lim->max_hw_zone_append_sectors =
+ min(lim->max_hw_zone_append_sectors,
+ ns_lim->max_hw_zone_append_sectors);
+ lim->max_open_zones = min_not_zero(lim->max_open_zones,
+ ns_lim->max_open_zones);
+ lim->max_active_zones =
+ min_not_zero(lim->max_active_zones,
+ ns_lim->max_active_zones);
+}
+
+static void nvme_apply_ns_head_limits(struct queue_limits *lim,
+ const struct queue_limits *ns_lim)
+{
+ nvme_apply_ns_head_identify_limits(lim, ns_lim);
+ /*
+ * Keep inherited non-path features that can describe an NVMe path.
+ * Zoned was handled as namespace layout above, and the RAID partial
+ * stripes flag is not an NVMe namespace-head property.
+ */
+ lim->features |= ns_lim->features &
+ (BLK_FEAT_WRITE_CACHE | BLK_FEAT_FUA |
+ BLK_FEAT_ROTATIONAL | BLK_FEAT_STABLE_WRITES);
+ blk_stack_path_limits(lim, ns_lim);
+ nvme_apply_ns_head_operation_limits(lim, ns_lim);
+ if (lim->features & BLK_FEAT_ZONED)
+ nvme_apply_ns_head_zone_limits(lim, ns_lim);
}
static int nvme_update_ns_head_limits(struct nvme_ns *ns,
@@ -2539,35 +2617,12 @@ static int nvme_update_ns_head_limits(struct nvme_ns *ns,
lim = queue_limits_start_update(head_q);
memflags = blk_mq_freeze_queue(head_q);
- /*
- * queue_limits mixes values that are the hardware limitations
- * for bio splitting with what is the device configuration.
- *
- * For NVMe the device configuration can change after e.g. a
- * Format command, and we really want to pick up the new format
- * value here. But we must still stack the queue limits to the
- * least common denominator for multipathing to split the bios
- * properly.
- *
- * To work around this, we explicitly set the device
- * configuration to those that we just queried, but only stack
- * the splitting limits in to make sure we still obey possibly
- * lower limitations of other controllers.
- */
- lim.logical_block_size = ns_lim->logical_block_size;
- lim.physical_block_size = ns_lim->physical_block_size;
- lim.io_min = ns_lim->io_min;
- lim.io_opt = ns_lim->io_opt;
- queue_limits_stack_bdev(&lim, ns->disk->part0, 0,
- ns->head->disk->disk_name);
- if (lim.features & BLK_FEAT_ZONED)
- nvme_stack_zone_resources(&lim, ns_lim);
+
+ nvme_apply_ns_head_limits(&lim, ns_lim);
if (unsupported)
ns->head->disk->flags |= GENHD_FL_HIDDEN;
else
nvme_init_integrity(ns->head, &lim, info);
- lim.max_write_streams = ns_lim->max_write_streams;
- lim.write_stream_granularity = ns_lim->write_stream_granularity;
ret = queue_limits_commit_update(head_q, &lim);
if (ret)
goto unfreeze_head_queue;
diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
index 9213a5716f95..b89930f1f7a6 100644
--- a/include/linux/blkdev.h
+++ b/include/linux/blkdev.h
@@ -1153,6 +1153,10 @@ static inline void blk_queue_disable_write_zeroes(struct request_queue *q)
*/
extern void blk_set_queue_depth(struct request_queue *q, unsigned int depth);
extern void blk_set_stacking_limits(struct queue_limits *lim);
+void blk_stack_path_limits(struct queue_limits *t,
+ const struct queue_limits *b);
+void blk_stack_atomic_writes_limits(struct queue_limits *t,
+ struct queue_limits *b, sector_t start);
extern int blk_stack_limits(struct queue_limits *t, struct queue_limits *b,
sector_t offset);
void queue_limits_stack_bdev(struct queue_limits *t, struct block_device *bdev,
--
2.25.1
^ permalink raw reply related [flat|nested] 12+ messages in thread* Re: [PATCH v2 4/4] block, nvme: use lower-level limit helpers for namespace heads
2026-08-06 2:46 ` [PATCH v2 4/4] block, nvme: use lower-level limit helpers for namespace heads Yao Sang
@ 2026-08-17 8:13 ` Christoph Hellwig
0 siblings, 0 replies; 12+ messages in thread
From: Christoph Hellwig @ 2026-08-17 8:13 UTC (permalink / raw)
To: Yao Sang
Cc: Jens Axboe, Keith Busch, Christoph Hellwig, Sagi Grimberg,
linux-block, linux-nvme
On Thu, Aug 06, 2026 at 10:46:58AM +0800, Yao Sang wrote:
> An NVMe namespace head and each path refer to the same namespace.
> queue_limits_stack_bdev() treats the path as a bottom-device range and
> applies all of blk_stack_limits(), including topology rules and start-based
> atomic write checks. These mapped-device rules should not be used when
> updating the namespace head.
>
> Make blk_stack_path_limits() and the existing
> blk_stack_atomic_writes_limits() public when adding their first caller
> outside the block layer. Keep the existing names and parameter types.
I'd move the making public including the kerneldoc and export into
the patches adding them. Much better than hiding that in nvme patches.
> +static void nvme_apply_ns_head_identify_limits(struct queue_limits *lim,
> + const struct queue_limits *ns_lim)
Nothing in here feels nvme specific. I wonder how much of this
should be in common code, and if that would be useful to John's
scsi multipath work?
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH v2 0/4] block/nvme: split path limits for namespace heads
2026-08-06 2:46 [PATCH v2 0/4] block/nvme: split path limits for namespace heads Yao Sang
` (3 preceding siblings ...)
2026-08-06 2:46 ` [PATCH v2 4/4] block, nvme: use lower-level limit helpers for namespace heads Yao Sang
@ 2026-08-10 8:50 ` Yao Sang
4 siblings, 0 replies; 12+ messages in thread
From: Yao Sang @ 2026-08-10 8:50 UTC (permalink / raw)
To: sangyao; +Cc: axboe, hch, kbusch, linux-block, linux-nvme, sagi
Just to clarify the base for this series: it is based on the public
nvme/nvme-7.3 branch at bf881dd20062 ("nvmet: reject out-of-range mdts
values in configfs store").
It depends on 224041412693 ("nvme-multipath: revalidate zones for
namespace heads"). Sashiko appears to have failed to fetch nvme/HEAD and
then tried axboe/HEAD, which does not contain that dependency, so the
reported apply failure looks like a baseline selection issue rather than a
conflict on the intended nvme tree.
Thanks,
Yao
^ permalink raw reply [flat|nested] 12+ messages in thread