Re: [PATCH] nvme: reject zoned namespaces whose zone info query failed

Chris S <[email protected]>
Newsgroups org.kernel.vger.stable,org.infradead.lists.linux-nvme,org.kernel.vger.linux-kernel
Message-ID <CACd_6n1d9kdEYARkmf6bRzbt5SXwmf-8jk_Dd-xJ0gyQ1TcMMQ@mail.gmail.com>
On Fri, Aug 14, 2026 at 3:28 PM Keith Busch <[email protected]> wrote:
>
> On Fri, Aug 14, 2026 at 12:09:54PM -0400, Chao Shi wrote:
> > Before commit c85c9ab926a5 ("nvme: split nvme_update_zone_info") the
> > caller tested "if (ret)" and bailed out on any non-zero return.  Restore
> > that behaviour.
>
> I think the namespace is generally left up on purpose for controller
> reported errors so that we have a device handle for admin debugging
> purposes.
>
> Can you just skip the zone limits update when you have a bad response?
> Something like:
>
> --- a/drivers/nvme/host/core.c
> +++ b/drivers/nvme/host/core.c
> @@ -2457,7 +2457,8 @@ static int nvme_update_ns_info_block(struct nvme_ns *ns,
>                 capacity = 0;
>
>         if (IS_ENABLED(CONFIG_BLK_DEV_ZONED) &&
> -           ns->head->ids.csi == NVME_CSI_ZNS)
> +           ns->head->ids.csi == NVME_CSI_ZNS &&
> +           zi.max_open_zones)
>                 nvme_update_zone_info(ns, &lim, &zi);
>
>         if ((ns->ctrl->vwc & NVME_CTRL_VWC_PRESENT) && !info->no_vwc)

Thanks -- keeping the namespace around is clearly the right, I
had not considered the admin handle.  v2 does that.

I did not use zi.max_open_zones as the condition though, because 0 is a
legal value there.  MOR and MAR are 0's based and FFFFFFFFh means "no
limit", so nvme_query_zone_info() does:

zi->max_open_zones = le32_to_cpu(id->mor) + 1;

which deliberately wraps FFFFFFFFh to 0, matching the block layer where
0 also means "no limit" -- blk_validate_zoned_limits() tests
"if (lim->max_active_zones && ...)" for exactly that reason.  So a
healthy device that reports no open resource limit has
zi.max_open_zones == 0, and gating on it would leave that device's
namespace unzoned.  QEMU hits this with its defaults: hw/nvme/ns.c has

id_ns_z->mor = cpu_to_le32(ns->params.max_open_zones - 1);

and zoned.max_open_zones defaults to 0.

zi.zone_size does not have that ambiguity.  Every path in
nvme_query_zone_info() that returns a positive status returns before
zone_size is assigned, and once it is assigned the only remaining
failure is -ENODEV, which the caller already handles.  A successful
query therefore always leaves it a non-zero power of two.  So v2 is:

if (IS_ENABLED(CONFIG_BLK_DEV_ZONED) &&
   ns->head->ids.csi == NVME_CSI_ZNS && zi.zone_size)
nvme_update_zone_info(ns, &lim, &zi);

One open question in v2: on a first scan the namespace now comes up as
a non-zoned block device.  Setting capacity = 0 there as well would
match what this function already does for nvme_update_disk_info() and
nvme_init_integrity() failures, and would still keep the handle.  I
left it out to keep the change minimal -- happy to add it if you would
rather have it.

Sending v2 now.

Thanks,
Chao
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.