[PATCH 5/6] nvme: track subsystems

Sagi Grimberg sagi at grimberg.me
Thu Jun 15 10:04:53 PDT 2017



On 15/06/17 19:35, Christoph Hellwig wrote:
> This adds a new nvme_subsystem structure so that we can track multiple
> controllers that belong to a single subsystem.  For now we only use it
> to store the NQN, and to check that we don't have duplicate NQNs unless
> the involved subsystems support multiple controllers.
> 
> Signed-off-by: Christoph Hellwig <hch at lst.de>
> ---
>   drivers/nvme/host/core.c    | 111 ++++++++++++++++++++++++++++++++++++++++----
>   drivers/nvme/host/fabrics.c |   4 +-
>   drivers/nvme/host/nvme.h    |  12 ++++-
>   3 files changed, 116 insertions(+), 11 deletions(-)
> 
> diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c
> index 328da5d8c469..57e48d893173 100644
> --- a/drivers/nvme/host/core.c
> +++ b/drivers/nvme/host/core.c
> @@ -68,6 +68,9 @@ MODULE_PARM_DESC(force_apst, "allow APST for newly enumerated devices even if qu
>   struct workqueue_struct *nvme_wq;
>   EXPORT_SYMBOL_GPL(nvme_wq);
>   
> +static LIST_HEAD(nvme_subsystems);
> +static DEFINE_MUTEX(nvme_subsystems_lock);
> +
>   static LIST_HEAD(nvme_ctrl_list);
>   static DEFINE_SPINLOCK(dev_list_lock);
>   
> @@ -1633,13 +1636,14 @@ static bool quirk_matches(const struct nvme_id_ctrl *id,
>   		string_matches(id->fr, q->fr, sizeof(id->fr));
>   }
>   
> -static void nvme_init_subnqn(struct nvme_ctrl *ctrl, struct nvme_id_ctrl *id)
> +static void nvme_init_subnqn(struct nvme_subsystem *subsys, struct nvme_ctrl *ctrl,
> +		struct nvme_id_ctrl *id)
>   {
>   	size_t nqnlen;
>   
>   	nqnlen = strnlen(id->subnqn, NVMF_NQN_SIZE);
>   	if (nqnlen > 0 && nqnlen < NVMF_NQN_SIZE) {
> -		strcpy(ctrl->subnqn, id->subnqn);
> +		strcpy(subsys->subnqn, id->subnqn);
>   		return;
>   	}
>   
> @@ -1647,12 +1651,89 @@ static void nvme_init_subnqn(struct nvme_ctrl *ctrl, struct nvme_id_ctrl *id)
>   		dev_warn(ctrl->device, "missing or invalid SUBNQN field.\n");
>   
>   	/* Generate a "fake" NQN per Figure 254 in NVMe 1.3 + ECN 001 */
> -	snprintf(ctrl->subnqn, NVMF_NQN_SIZE,
> +	snprintf(subsys->subnqn, NVMF_NQN_SIZE,
>   		"nqn.2014.08.org.nvmexpress:%4x%4x",
>   		le16_to_cpu(id->vid), le16_to_cpu(id->ssvid));
> -	memcpy(ctrl->subnqn + 35, id->sn, sizeof(id->sn));
> -	memcpy(ctrl->subnqn + 55, id->mn, sizeof(id->mn));
> -	memset(ctrl->subnqn + 95, 0, sizeof(ctrl->subnqn) - 95);
> +	memcpy(subsys->subnqn + 35, id->sn, sizeof(id->sn));
> +	memcpy(subsys->subnqn + 55, id->mn, sizeof(id->mn));
> +	memset(subsys->subnqn + 95, 0, sizeof(subsys->subnqn) - 95);
> +}
> +
> +static void nvme_destroy_subsystem(struct kref *ref)
> +{
> +	struct nvme_subsystem *subsys =
> +			container_of(ref, struct nvme_subsystem, ref);
> +
> +	mutex_lock(&nvme_subsystems_lock);
> +	list_del(&subsys->entry);
> +	mutex_unlock(&nvme_subsystems_lock);
> +
> +	kfree(ref);
> +}
> +
> +static void nvme_put_subsystem(struct nvme_subsystem *subsys)
> +{
> +	kref_put(&subsys->ref, nvme_destroy_subsystem);
> +}
> +
> +static struct nvme_subsystem *__nvme_find_subsystem(const char *subsysnqn)

__nvme_find_get_subsystem?

> +{
> +	struct nvme_subsystem *subsys;
> +
> +	lockdep_assert_held(&nvme_subsystems_lock);
> +
> +	list_for_each_entry(subsys, &nvme_subsystems, entry) {
> +		if (strcmp(subsys->subnqn, subsysnqn))
> +			continue;
> +		if (!kref_get_unless_zero(&subsys->ref))
> +			continue;
> +		return subsys;
> +	}
> +
> +	return NULL;
> +}
> +
> +static int nvme_init_subsystem(struct nvme_ctrl *ctrl, struct nvme_id_ctrl *id)
> +{
> +	struct nvme_subsystem *subsys, *found;
> +
> +	subsys = kzalloc(sizeof(*subsys), GFP_KERNEL);
> +	if (!subsys)
> +		return -ENOMEM;
> +	INIT_LIST_HEAD(&subsys->ctrls);
> +	kref_init(&subsys->ref);
> +	nvme_init_subnqn(subsys, ctrl, id);
> +	mutex_init(&subsys->lock);

Nit: might be nicer to allocate the subsys only if its new (in the
else case) instead of freeing if you found a match. Maybe
nvme_init_subsysnqn should receive the subsysnqn buffer (on stack
here) which would be copied to the subsys->subnqn if new.

Just a suggestion.



More information about the Linux-nvme mailing list