[PATCH 2/3] nvme: move hidden device and multipath handling out of nvme_update_ns_info

Martin Wilck mwilck at suse.com
Thu Aug 29 12:41:15 PDT 2024


On Thu, 2024-08-29 at 09:31 +0300, Christoph Hellwig wrote:
> Turn nvme_update_ns_info into a pure multiplexer and move the real
> work
> into nvme_update_ns_info_generic and nvme_update_ns_block, which
> allows
> to set the flags more coherently while the queue is still frozen.
> 
> Signed-off-by: Christoph Hellwig <hch at lst.de>
> ---
>  drivers/nvme/host/core.c | 55 ++++++++++++++++++--------------------
> --
>  1 file changed, 25 insertions(+), 30 deletions(-)
> 
> diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c
> index 51cb3b001b3757..81d2a09dd00f30 100644
> --- a/drivers/nvme/host/core.c
> +++ b/drivers/nvme/host/core.c
> @@ -2147,12 +2147,18 @@ static int nvme_update_ns_info_generic(struct
> nvme_ns *ns,
>  	lim = queue_limits_start_update(ns->disk->queue);
>  	nvme_set_ctrl_limits(ns->ctrl, &lim);
>  	ret = queue_limits_commit_update(ns->disk->queue, &lim);
> -	set_disk_ro(ns->disk, nvme_ns_is_readonly(ns, info));
> -	blk_mq_unfreeze_queue(ns->disk->queue);
> +	if (ret)
> +		goto out_unfreeze;
>  
>  	/* Hide the block-interface for these devices */
> -	if (!ret)
> -		ret = -ENODEV;
> +	ns->disk->flags |= GENHD_FL_HIDDEN;
> +	set_bit(NVME_NS_READY, &ns->flags);
> +	set_disk_ro(ns->disk, nvme_ns_is_readonly(ns, info));
> +
> +out_unfreeze:
> +	blk_mq_unfreeze_queue(ns->disk->queue);
> +	if (nvme_ns_head_multipath(ns->head) && !ret)
> +		ret = nvme_update_ns_info_mpath(ns, info, true);
>  	return ret;
>  }
>  
> @@ -2163,6 +2169,7 @@ static int nvme_update_ns_info_block(struct
> nvme_ns *ns,
>  	struct nvme_id_ns_nvm *nvm = NULL;
>  	struct nvme_zone_info zi = {};
>  	struct nvme_id_ns *id;
> +	bool unsupported = false;
>  	sector_t capacity;
>  	unsigned lbaf;
>  	int ret;
> @@ -2188,6 +2195,11 @@ static int nvme_update_ns_info_block(struct
> nvme_ns *ns,
>  	if (IS_ENABLED(CONFIG_BLK_DEV_ZONED) &&
>  	    ns->head->ids.csi == NVME_CSI_ZNS) {
>  		ret = nvme_query_zone_info(ns, lbaf, &zi);
> +		if (ret == -ENODEV) {
> +			unsupported = true;
> +			ns->disk->flags |= GENHD_FL_HIDDEN;
> +			goto done;


This looks wrong to me. We call blk_mq_unfreeze_queue() after the
"done" label, although the queue has not been frozen yet.


> +		}
>  		if (ret < 0)
>  			goto out;
>  	}
> @@ -2238,6 +2250,8 @@ static int nvme_update_ns_info_block(struct
> nvme_ns *ns,
>  	 */
>  	if ((id->dlfeat & 0x7) == 0x1 && (id->dlfeat & (1 << 3)))
>  		ns->head->features |= NVME_NS_DEAC;
> +
> +done:
>  	set_disk_ro(ns->disk, nvme_ns_is_readonly(ns, info));
>  	set_bit(NVME_NS_READY, &ns->flags);
>  	blk_mq_unfreeze_queue(ns->disk->queue);
> @@ -2252,50 +2266,31 @@ static int nvme_update_ns_info_block(struct
> nvme_ns *ns,
>  out:
>  	kfree(nvm);
>  	kfree(id);
> +
> +	if (nvme_ns_head_multipath(ns->head) && !ret)
> +		ret = nvme_update_ns_info_mpath(ns, info,
> unsupported);
>  	return ret;
>  }
>  
>  static int nvme_update_ns_info(struct nvme_ns *ns, struct
> nvme_ns_info *info)
>  {
> -	bool unsupported = false;
> -	int ret;
> -
>  	switch (info->ids.csi) {
>  	case NVME_CSI_ZNS:
>  		if (!IS_ENABLED(CONFIG_BLK_DEV_ZONED)) {
>  			dev_info(ns->ctrl->device,
>  	"block device for nsid %u not supported without
> CONFIG_BLK_DEV_ZONED\n",
>  				info->nsid);
> -			ret = nvme_update_ns_info_generic(ns, info);
> -			break;
> +			return nvme_update_ns_info_generic(ns,
> info);
>  		}
> -		ret = nvme_update_ns_info_block(ns, info);
> -		break;
> +		return nvme_update_ns_info_block(ns, info);
>  	case NVME_CSI_NVM:
> -		ret = nvme_update_ns_info_block(ns, info);
> -		break;
> +		return nvme_update_ns_info_block(ns, info);
>  	default:
>  		dev_info(ns->ctrl->device,
>  			"block device for nsid %u not supported (csi
> %u)\n",
>  			info->nsid, info->ids.csi);
> -		ret = nvme_update_ns_info_generic(ns, info);
> -		break;
> +		return nvme_update_ns_info_generic(ns, info);
>  	}
> -
> -	/*
> -	 * If probing fails due an unsupported feature, hide the
> block device,
> -	 * but still allow other access.
> -	 */
> -	if (ret == -ENODEV) {
> -		ns->disk->flags |= GENHD_FL_HIDDEN;
> -		set_bit(NVME_NS_READY, &ns->flags);
> -		unsupported = true;
> -		ret = 0;
> -	}


Are we certain that the two cases above (nvme_update_ns_info_generic()
and failure of nvme_query_zone_info()) are the only cases in which ret
== -ENODEV would have been true here?

Regards
Martin


> -
> -	if (nvme_ns_head_multipath(ns->head) && !ret)
> -		ret = nvme_update_ns_info_mpath(ns, info,
> unsupported);
> -	return ret;
>  }
>  
>  int nvme_ns_get_unique_id(struct nvme_ns *ns, u8 id[16],




More information about the Linux-nvme mailing list