linux-nvme.lists.infradead.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] nvmet: make ctrl model configurable
@ 2019-10-30 19:48 Chaitanya Kulkarni
  2019-10-30 20:08 ` Mark Ruijter
  0 siblings, 1 reply; 10+ messages in thread
From: Chaitanya Kulkarni @ 2019-10-30 19:48 UTC (permalink / raw)
  To: linux-nvme; +Cc: Chaitanya Kulkarni

This patch adds a new target subsys attribute which allows user to
optionally specify model name which then used in the
nvmet_execute_identify_ctrl() to fill up the nvme_id_ctrl structure.

Default value for the model is set to "Linux".

Signed-off-by: Chaitanya Kulkarni <chaitanya.kulkarni@wdc.com>
---
 drivers/nvme/target/admin-cmd.c |  4 ++--
 drivers/nvme/target/configfs.c  | 29 +++++++++++++++++++++++++++++
 drivers/nvme/target/core.c      |  6 ++++++
 drivers/nvme/target/nvmet.h     |  2 ++
 4 files changed, 39 insertions(+), 2 deletions(-)

diff --git a/drivers/nvme/target/admin-cmd.c b/drivers/nvme/target/admin-cmd.c
index 56c21b501185..917d8f3fded7 100644
--- a/drivers/nvme/target/admin-cmd.c
+++ b/drivers/nvme/target/admin-cmd.c
@@ -315,9 +315,9 @@ static void nvmet_execute_get_log_page(struct nvmet_req *req)
 static void nvmet_execute_identify_ctrl(struct nvmet_req *req)
 {
 	struct nvmet_ctrl *ctrl = req->sq->ctrl;
+	const char *model = ctrl->subsys->model;
 	struct nvme_id_ctrl *id;
 	u16 status = 0;
-	const char model[] = "Linux";
 
 	id = kzalloc(sizeof(*id), GFP_KERNEL);
 	if (!id) {
@@ -332,7 +332,7 @@ static void nvmet_execute_identify_ctrl(struct nvmet_req *req)
 	memset(id->sn, ' ', sizeof(id->sn));
 	bin2hex(id->sn, &ctrl->subsys->serial,
 		min(sizeof(ctrl->subsys->serial), sizeof(id->sn) / 2));
-	memcpy_and_pad(id->mn, sizeof(id->mn), model, sizeof(model) - 1, ' ');
+	memcpy_and_pad(id->mn, sizeof(id->mn), model, strlen(model), ' ');
 	memcpy_and_pad(id->fr, sizeof(id->fr),
 		       UTS_RELEASE, strlen(UTS_RELEASE), ' ');
 
diff --git a/drivers/nvme/target/configfs.c b/drivers/nvme/target/configfs.c
index 98613a45bd3b..e91ebe74c938 100644
--- a/drivers/nvme/target/configfs.c
+++ b/drivers/nvme/target/configfs.c
@@ -862,10 +862,39 @@ static ssize_t nvmet_subsys_attr_serial_store(struct config_item *item,
 }
 CONFIGFS_ATTR(nvmet_subsys_, attr_serial);
 
+static ssize_t nvmet_subsys_attr_model_show(struct config_item *item,
+					     char *page)
+{
+	struct nvmet_subsys *subsys = to_subsys(item);
+
+	return snprintf(page, PAGE_SIZE, "%s\n", subsys->model);
+}
+
+static ssize_t nvmet_subsys_attr_model_store(struct config_item *item,
+					     const char *page, size_t count)
+{
+	struct nvmet_subsys *subsys = to_subsys(item);
+	int ret = 0;
+
+	down_write(&nvmet_config_sem);
+	kfree(subsys->model);
+	subsys->model = kzalloc(PAGE_SIZE, GFP_KERNEL);
+	if (!subsys->model)
+		ret = -ENOMEM;
+	else
+		sscanf(page, "%s\n", subsys->model);
+	up_write(&nvmet_config_sem);
+
+	return ret ? ret : count;
+}
+
+CONFIGFS_ATTR(nvmet_subsys_, attr_model);
+
 static struct configfs_attribute *nvmet_subsys_attrs[] = {
 	&nvmet_subsys_attr_attr_allow_any_host,
 	&nvmet_subsys_attr_attr_version,
 	&nvmet_subsys_attr_attr_serial,
+	&nvmet_subsys_attr_attr_model,
 	NULL,
 };
 
diff --git a/drivers/nvme/target/core.c b/drivers/nvme/target/core.c
index 28438b833c1b..d3e2a1f58a93 100644
--- a/drivers/nvme/target/core.c
+++ b/drivers/nvme/target/core.c
@@ -1394,6 +1394,11 @@ struct nvmet_subsys *nvmet_subsys_alloc(const char *subsysnqn,
 		return ERR_PTR(-ENOMEM);
 
 	subsys->ver = NVME_VS(1, 3, 0); /* NVMe 1.3.0 */
+
+	subsys->model = kstrdup(NVMET_DEFAULT_CTRL_MODEL, GFP_KERNEL);
+	if (!subsys->model)
+		return ERR_PTR(-ENOMEM);
+
 	/* generate a random serial number as our controllers are ephemeral: */
 	get_random_bytes(&subsys->serial, sizeof(subsys->serial));
 
@@ -1435,6 +1440,7 @@ static void nvmet_subsys_free(struct kref *ref)
 	WARN_ON_ONCE(!list_empty(&subsys->namespaces));
 
 	kfree(subsys->subsysnqn);
+	kfree(subsys->model);
 	kfree(subsys);
 }
 
diff --git a/drivers/nvme/target/nvmet.h b/drivers/nvme/target/nvmet.h
index 46df45e837c9..d5fcfd09658e 100644
--- a/drivers/nvme/target/nvmet.h
+++ b/drivers/nvme/target/nvmet.h
@@ -23,6 +23,7 @@
 #define NVMET_ASYNC_EVENTS		4
 #define NVMET_ERROR_LOG_SLOTS		128
 #define NVMET_NO_ERROR_LOC		((u16)-1)
+#define NVMET_DEFAULT_CTRL_MODEL	"Linux"
 
 /*
  * Supported optional AENs:
@@ -227,6 +228,7 @@ struct nvmet_subsys {
 
 	struct config_group	namespaces_group;
 	struct config_group	allowed_hosts_group;
+	char			*model;
 };
 
 static inline struct nvmet_subsys *to_subsys(struct config_item *item)
-- 
2.22.1


_______________________________________________
Linux-nvme mailing list
Linux-nvme@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-nvme

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* Re: [PATCH] nvmet: make ctrl model configurable
  2019-10-30 19:48 [PATCH] nvmet: make ctrl model configurable Chaitanya Kulkarni
@ 2019-10-30 20:08 ` Mark Ruijter
  2019-10-30 20:09   ` Chaitanya Kulkarni
  2019-10-30 21:43   ` Chaitanya Kulkarni
  0 siblings, 2 replies; 10+ messages in thread
From: Mark Ruijter @ 2019-10-30 20:08 UTC (permalink / raw)
  To: Chaitanya Kulkarni, linux-nvme


Hi Chaitanya,

I assume that this change is based on the patch that I send earlier today.
You seem to have changed the code that accepts the attr_model input and replaced the input validation with sscanf.
What happens when you write a string containing a TAB into the model attribute?

The NVM-Express 1.4 document states this on page 13:
"Some parameters are defined as an ASCII string. ASCII strings shall contain only code values 20h through 7Eh."

As far as I know a TAB is 9h and sscanf(page, "%s\n", subsys->model) allows the TAB. 
This seems wrong to me?

Thanks,

Mark Ruijter



Op 30-10-19 20:49 heeft Linux-nvme namens Chaitanya Kulkarni <linux-nvme-bounces@lists.infradead.org namens chaitanya.kulkarni@wdc.com> geschreven:

    This patch adds a new target subsys attribute which allows user to
    optionally specify model name which then used in the
    nvmet_execute_identify_ctrl() to fill up the nvme_id_ctrl structure.
    
    Default value for the model is set to "Linux".
    
    Signed-off-by: Chaitanya Kulkarni <chaitanya.kulkarni@wdc.com>
    ---
     drivers/nvme/target/admin-cmd.c |  4 ++--
     drivers/nvme/target/configfs.c  | 29 +++++++++++++++++++++++++++++
     drivers/nvme/target/core.c      |  6 ++++++
     drivers/nvme/target/nvmet.h     |  2 ++
     4 files changed, 39 insertions(+), 2 deletions(-)
    
    diff --git a/drivers/nvme/target/admin-cmd.c b/drivers/nvme/target/admin-cmd.c
    index 56c21b501185..917d8f3fded7 100644
    --- a/drivers/nvme/target/admin-cmd.c
    +++ b/drivers/nvme/target/admin-cmd.c
    @@ -315,9 +315,9 @@ static void nvmet_execute_get_log_page(struct nvmet_req *req)
     static void nvmet_execute_identify_ctrl(struct nvmet_req *req)
     {
     	struct nvmet_ctrl *ctrl = req->sq->ctrl;
    +	const char *model = ctrl->subsys->model;
     	struct nvme_id_ctrl *id;
     	u16 status = 0;
    -	const char model[] = "Linux";
     
     	id = kzalloc(sizeof(*id), GFP_KERNEL);
     	if (!id) {
    @@ -332,7 +332,7 @@ static void nvmet_execute_identify_ctrl(struct nvmet_req *req)
     	memset(id->sn, ' ', sizeof(id->sn));
     	bin2hex(id->sn, &ctrl->subsys->serial,
     		min(sizeof(ctrl->subsys->serial), sizeof(id->sn) / 2));
    -	memcpy_and_pad(id->mn, sizeof(id->mn), model, sizeof(model) - 1, ' ');
    +	memcpy_and_pad(id->mn, sizeof(id->mn), model, strlen(model), ' ');
     	memcpy_and_pad(id->fr, sizeof(id->fr),
     		       UTS_RELEASE, strlen(UTS_RELEASE), ' ');
     
    diff --git a/drivers/nvme/target/configfs.c b/drivers/nvme/target/configfs.c
    index 98613a45bd3b..e91ebe74c938 100644
    --- a/drivers/nvme/target/configfs.c
    +++ b/drivers/nvme/target/configfs.c
    @@ -862,10 +862,39 @@ static ssize_t nvmet_subsys_attr_serial_store(struct config_item *item,
     }
     CONFIGFS_ATTR(nvmet_subsys_, attr_serial);
     
    +static ssize_t nvmet_subsys_attr_model_show(struct config_item *item,
    +					     char *page)
    +{
    +	struct nvmet_subsys *subsys = to_subsys(item);
    +
    +	return snprintf(page, PAGE_SIZE, "%s\n", subsys->model);
    +}
    +
    +static ssize_t nvmet_subsys_attr_model_store(struct config_item *item,
    +					     const char *page, size_t count)
    +{
    +	struct nvmet_subsys *subsys = to_subsys(item);
    +	int ret = 0;
    +
    +	down_write(&nvmet_config_sem);
    +	kfree(subsys->model);
    +	subsys->model = kzalloc(PAGE_SIZE, GFP_KERNEL);
    +	if (!subsys->model)
    +		ret = -ENOMEM;
    +	else
    +		sscanf(page, "%s\n", subsys->model);
    +	up_write(&nvmet_config_sem);
    +
    +	return ret ? ret : count;
    +}
    +
    +CONFIGFS_ATTR(nvmet_subsys_, attr_model);
    +
     static struct configfs_attribute *nvmet_subsys_attrs[] = {
     	&nvmet_subsys_attr_attr_allow_any_host,
     	&nvmet_subsys_attr_attr_version,
     	&nvmet_subsys_attr_attr_serial,
    +	&nvmet_subsys_attr_attr_model,
     	NULL,
     };
     
    diff --git a/drivers/nvme/target/core.c b/drivers/nvme/target/core.c
    index 28438b833c1b..d3e2a1f58a93 100644
    --- a/drivers/nvme/target/core.c
    +++ b/drivers/nvme/target/core.c
    @@ -1394,6 +1394,11 @@ struct nvmet_subsys *nvmet_subsys_alloc(const char *subsysnqn,
     		return ERR_PTR(-ENOMEM);
     
     	subsys->ver = NVME_VS(1, 3, 0); /* NVMe 1.3.0 */
    +
    +	subsys->model = kstrdup(NVMET_DEFAULT_CTRL_MODEL, GFP_KERNEL);
    +	if (!subsys->model)
    +		return ERR_PTR(-ENOMEM);
    +
     	/* generate a random serial number as our controllers are ephemeral: */
     	get_random_bytes(&subsys->serial, sizeof(subsys->serial));
     
    @@ -1435,6 +1440,7 @@ static void nvmet_subsys_free(struct kref *ref)
     	WARN_ON_ONCE(!list_empty(&subsys->namespaces));
     
     	kfree(subsys->subsysnqn);
    +	kfree(subsys->model);
     	kfree(subsys);
     }
     
    diff --git a/drivers/nvme/target/nvmet.h b/drivers/nvme/target/nvmet.h
    index 46df45e837c9..d5fcfd09658e 100644
    --- a/drivers/nvme/target/nvmet.h
    +++ b/drivers/nvme/target/nvmet.h
    @@ -23,6 +23,7 @@
     #define NVMET_ASYNC_EVENTS		4
     #define NVMET_ERROR_LOG_SLOTS		128
     #define NVMET_NO_ERROR_LOC		((u16)-1)
    +#define NVMET_DEFAULT_CTRL_MODEL	"Linux"
     
     /*
      * Supported optional AENs:
    @@ -227,6 +228,7 @@ struct nvmet_subsys {
     
     	struct config_group	namespaces_group;
     	struct config_group	allowed_hosts_group;
    +	char			*model;
     };
     
     static inline struct nvmet_subsys *to_subsys(struct config_item *item)
    -- 
    2.22.1
    
    
    _______________________________________________
    Linux-nvme mailing list
    Linux-nvme@lists.infradead.org
    http://lists.infradead.org/mailman/listinfo/linux-nvme
    

_______________________________________________
Linux-nvme mailing list
Linux-nvme@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-nvme

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH] nvmet: make ctrl model configurable
  2019-10-30 20:08 ` Mark Ruijter
@ 2019-10-30 20:09   ` Chaitanya Kulkarni
  2019-10-30 21:43   ` Chaitanya Kulkarni
  1 sibling, 0 replies; 10+ messages in thread
From: Chaitanya Kulkarni @ 2019-10-30 20:09 UTC (permalink / raw)
  To: Mark Ruijter, linux-nvme

Didn't see your patch, until now. Since you have posted, lets go with 
yours. Meanwhile posted tests for blktests have a look.

On 10/30/2019 01:08 PM, Mark Ruijter wrote:
> Hi Chaitanya,
>
> I assume that this change is based on the patch that I send earlier today.
> You seem to have changed the code that accepts the attr_model input and replaced the input validation with sscanf.
> What happens when you write a string containing a TAB into the model attribute?
>
> The NVM-Express 1.4 document states this on page 13:
> "Some parameters are defined as an ASCII string. ASCII strings shall contain only code values 20h through 7Eh."
>
> As far as I know a TAB is 9h and sscanf(page, "%s\n", subsys->model) allows the TAB.
> This seems wrong to me?
>
> Thanks,
>
> Mark Ruijter


_______________________________________________
Linux-nvme mailing list
Linux-nvme@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-nvme

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH] nvmet: make ctrl model configurable
  2019-10-30 20:08 ` Mark Ruijter
  2019-10-30 20:09   ` Chaitanya Kulkarni
@ 2019-10-30 21:43   ` Chaitanya Kulkarni
  1 sibling, 0 replies; 10+ messages in thread
From: Chaitanya Kulkarni @ 2019-10-30 21:43 UTC (permalink / raw)
  To: Mark Ruijter, linux-nvme

I'll merge these two patches and send a new one.

_______________________________________________
Linux-nvme mailing list
Linux-nvme@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-nvme

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH] nvmet: make ctrl model configurable
  2019-11-11 13:31   ` Mark Ruijter
@ 2019-11-12  7:07     ` Chaitanya Kulkarni
  0 siblings, 0 replies; 10+ messages in thread
From: Chaitanya Kulkarni @ 2019-11-12  7:07 UTC (permalink / raw)
  To: Mark Ruijter, Christoph Hellwig; +Cc: hch, linux-nvme, sagi

On 11/11/2019 05:31 AM, Mark Ruijter wrote:
> Hi Chaitanya & Christoph,
>
> I changed the patch I posted this morning and added the changes suggested.
Thanks for the patches, let me test both and send out with proper change 
log.


_______________________________________________
Linux-nvme mailing list
Linux-nvme@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-nvme

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH] nvmet: make ctrl model configurable
  2019-11-11 10:34 ` Christoph Hellwig
  2019-11-11 13:31   ` Mark Ruijter
@ 2019-11-12  7:06   ` Chaitanya Kulkarni
  1 sibling, 0 replies; 10+ messages in thread
From: Chaitanya Kulkarni @ 2019-11-12  7:06 UTC (permalink / raw)
  To: Christoph Hellwig; +Cc: hch, linux-nvme, sagi

On 11/11/2019 02:34 AM, Christoph Hellwig wrote:
>> +	const char *model = ctrl->subsys->model;
>
> Can we have a little nvme_controller_mode() helper that uses
> subsystem->model if it is set, and otherwise the default?  That saves
> memory by not duplicating the default name for every subsystem.
>
Okay.
>> +	kfree(subsys->model);
>> +	subsys->model = kstrndup(page, len, GFP_KERNEL);
>> +	if (!subsys->model)
>> +		ret = -ENOMEM;
>
> I don't think we should free the old model until the new one
> is allocated.
>
Sounds good.
> Otherwise this looks good to me, but can someone also prepare a
> nvmetcli patch as well?
>
Mark has sent out 2 patches, I'll test and send out in the
mailing list format.


_______________________________________________
Linux-nvme mailing list
Linux-nvme@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-nvme

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH] nvmet: make ctrl model configurable
  2019-11-11 10:34 ` Christoph Hellwig
@ 2019-11-11 13:31   ` Mark Ruijter
  2019-11-12  7:07     ` Chaitanya Kulkarni
  2019-11-12  7:06   ` Chaitanya Kulkarni
  1 sibling, 1 reply; 10+ messages in thread
From: Mark Ruijter @ 2019-11-11 13:31 UTC (permalink / raw)
  To: Christoph Hellwig, Chaitanya Kulkarni; +Cc: hch, linux-nvme, sagi

[-- Attachment #1: Type: text/plain, Size: 3539 bytes --]


Hi Chaitanya & Christoph,

I changed the patch I posted this morning and added the changes suggested.

I also wrote a patch for nvmetcli and verified that nvmetcli can set and save the model description:

dev:/usr/src/nvmetcli # ./nvmetcli save /tmp/test.json
dev:/usr/src/nvmetcli # cat /sys/kernel/config/nvmet/subsystems/loop/attr_model 
mark
dev:/usr/src/nvmetcli # grep model /tmp/test.json
        "model": "mark", 

dev:/usr/src/nvmetcli # ./nvmetcli 
/subsystems/loop> ls  
o- loop ............................................................ [version=1.3, allow_any=1, serial=198f07c757eb114d, model=mark]
  o- allowed_hosts ........................................................................................................... [...]
  o- namespaces .............................................................................................................. [...]
    o- 1 ............................................ [path=/dev/loop0, uuid=d808c1db-3507-40cf-8ade-aa4b1a3b290b, grpid=1, enabled]
/subsystems/loop> set attr model=coolmodel
Parameter model is now 'coolmodel'.
/subsystems/loop> ls
o- loop ....................................................... [version=1.3, allow_any=1, serial=198f07c757eb114d, model=coolmodel]
  o- allowed_hosts ........................................................................................................... [...]
  o- namespaces .............................................................................................................. [...]
    o- 1 ............................................ [path=/dev/loop0, uuid=d808c1db-3507-40cf-8ade-aa4b1a3b290b, grpid=1, enabled]
/subsystems/loop> exit
dev:/usr/src/nvmetcli # ./nvmetcli save /tmp/testcool.jsonl 
dev:/usr/src/nvmetcli # grep model /tmp/testcool.json
        "model": "coolmodel", 
dev:/usr/src/nvmetcli #

I also verified that writing illegal characters in the model fails and that the initiator sees the model description that was set:
 echo -e "\t failit" > attr_model 
-bash: echo: write error: Invalid argument

echo this~works > attr_model

# nvme list
Node             SN                   Model                                    Namespace Usage                      Format           FW Rev  
---------------- -------------------- ---------------------------------------- --------- -------------------------- ---------------- --------
/dev/nvme0n1     4d11eb57c7078f19     this~works                               1         104,86  MB / 104,86  MB    512   B +  0 B   5.3.5   

Thanks,

Mark Ruijter
 

Op 11-11-19 11:35 heeft Linux-nvme namens Christoph Hellwig <linux-nvme-bounces@lists.infradead.org namens hch@infradead.org> geschreven:

    > +	const char *model = ctrl->subsys->model;
    
    Can we have a little nvme_controller_mode() helper that uses
    subsystem->model if it is set, and otherwise the default?  That saves
    memory by not duplicating the default name for every subsystem.
    
    > +	kfree(subsys->model);
    > +	subsys->model = kstrndup(page, len, GFP_KERNEL);
    > +	if (!subsys->model)
    > +		ret = -ENOMEM;
    
    I don't think we should free the old model until the new one
    is allocated.
    
    Otherwise this looks good to me, but can someone also prepare a
    nvmetcli patch as well?
    
    _______________________________________________
    Linux-nvme mailing list
    Linux-nvme@lists.infradead.org
    http://lists.infradead.org/mailman/listinfo/linux-nvme
    


[-- Attachment #2: model_patch_patched2.diff --]
[-- Type: application/octet-stream, Size: 4022 bytes --]

diff --git a/drivers/nvme/target/admin-cmd.c b/drivers/nvme/target/admin-cmd.c
index 51800a9..8f9366e 100644
--- a/drivers/nvme/target/admin-cmd.c
+++ b/drivers/nvme/target/admin-cmd.c
@@ -284,12 +284,19 @@ out:
 	nvmet_req_complete(req, status);
 }
 
+const char *nvme_controller_model(char *model)
+{
+	if (!model)
+		return NVMET_DEFAULT_CTRL_MODEL;
+	return model;
+}
+
 static void nvmet_execute_identify_ctrl(struct nvmet_req *req)
 {
 	struct nvmet_ctrl *ctrl = req->sq->ctrl;
+	const char *model = nvme_controller_model(ctrl->subsys->model);
 	struct nvme_id_ctrl *id;
 	u16 status = 0;
-	const char model[] = "Linux";
 
 	id = kzalloc(sizeof(*id), GFP_KERNEL);
 	if (!id) {
@@ -304,7 +311,7 @@ static void nvmet_execute_identify_ctrl(struct nvmet_req *req)
 	memset(id->sn, ' ', sizeof(id->sn));
 	bin2hex(id->sn, &ctrl->subsys->serial,
 		min(sizeof(ctrl->subsys->serial), sizeof(id->sn) / 2));
-	memcpy_and_pad(id->mn, sizeof(id->mn), model, sizeof(model) - 1, ' ');
+	memcpy_and_pad(id->mn, sizeof(id->mn), model, strlen(model), ' ');
 	memcpy_and_pad(id->fr, sizeof(id->fr),
 		       UTS_RELEASE, strlen(UTS_RELEASE), ' ');
 
diff --git a/drivers/nvme/target/configfs.c b/drivers/nvme/target/configfs.c
index 98613a4..18a3f4d 100644
--- a/drivers/nvme/target/configfs.c
+++ b/drivers/nvme/target/configfs.c
@@ -862,10 +862,57 @@ static ssize_t nvmet_subsys_attr_serial_store(struct config_item *item,
 }
 CONFIGFS_ATTR(nvmet_subsys_, attr_serial);
 
+static ssize_t nvmet_subsys_attr_model_show(struct config_item *item,
+					    char *page)
+{
+	struct nvmet_subsys *subsys = to_subsys(item);
+
+	return snprintf(page, PAGE_SIZE, "%s\n", subsys->model);
+}
+
+static ssize_t nvmet_subsys_attr_model_store(struct config_item *item,
+					     const char *page, size_t count)
+{
+	struct nvmet_subsys *subsys = to_subsys(item);
+	char *tmp;
+	int ret = -EINVAL, pos, len;
+	char c;
+
+	down_write(&nvmet_config_sem);
+	len = strcspn(page, "\n");
+	if (!len)
+		goto out_unlock;
+
+	/* Only 20h (space) until 7eh (~) is allowed */
+	for (pos = 0; pos < len; pos++) {
+		c = page[pos];
+		if (c < 0x20 || c > 0x7e)
+			goto out_unlock;
+	}
+
+	tmp = kstrndup(page, len, GFP_KERNEL);
+	if (!tmp) {
+		ret = -ENOMEM;
+		goto out_unlock;
+	}
+
+	ret = count;
+	if (subsys->model)
+		kfree(subsys->model);
+	subsys->model = tmp;
+
+out_unlock:
+	up_write(&nvmet_config_sem);
+	return ret;
+}
+
+CONFIGFS_ATTR(nvmet_subsys_, attr_model);
+
 static struct configfs_attribute *nvmet_subsys_attrs[] = {
 	&nvmet_subsys_attr_attr_allow_any_host,
 	&nvmet_subsys_attr_attr_version,
 	&nvmet_subsys_attr_attr_serial,
+	&nvmet_subsys_attr_attr_model,
 	NULL,
 };
 
@@ -901,6 +948,7 @@ static struct config_group *nvmet_subsys_make(struct config_group *group,
 	}
 
 	subsys = nvmet_subsys_alloc(name, NVME_NQN_NVME);
+	subsys->model = kstrdup(NVMET_DEFAULT_CTRL_MODEL, GFP_KERNEL);
 	if (IS_ERR(subsys))
 		return ERR_CAST(subsys);
 
diff --git a/drivers/nvme/target/core.c b/drivers/nvme/target/core.c
index 3a67e24..25ca3cd 100644
--- a/drivers/nvme/target/core.c
+++ b/drivers/nvme/target/core.c
@@ -1418,6 +1418,7 @@ struct nvmet_subsys *nvmet_subsys_alloc(const char *subsysnqn,
 		kfree(subsys);
 		return ERR_PTR(-ENOMEM);
 	}
+	subsys->model = 0;
 
 	kref_init(&subsys->ref);
 
@@ -1437,6 +1438,8 @@ static void nvmet_subsys_free(struct kref *ref)
 	WARN_ON_ONCE(!list_empty(&subsys->namespaces));
 
 	kfree(subsys->subsysnqn);
+	if (subsys->model)
+		kfree(subsys->model);
 	kfree(subsys);
 }
 
diff --git a/drivers/nvme/target/nvmet.h b/drivers/nvme/target/nvmet.h
index c51f8dd..fd0d89a 100644
--- a/drivers/nvme/target/nvmet.h
+++ b/drivers/nvme/target/nvmet.h
@@ -23,6 +23,7 @@
 #define NVMET_ASYNC_EVENTS		4
 #define NVMET_ERROR_LOG_SLOTS		128
 #define NVMET_NO_ERROR_LOC		((u16)-1)
+#define NVMET_DEFAULT_CTRL_MODEL       "Linux"
 
 /*
  * Supported optional AENs:
@@ -222,6 +223,7 @@ struct nvmet_subsys {
 	u64			ver;
 	u64			serial;
 	char			*subsysnqn;
+	char			*model;
 
 	struct config_group	group;
 

[-- Attachment #3: nvmetcli.patch --]
[-- Type: application/octet-stream, Size: 785 bytes --]

diff --git a/nvmetcli b/nvmetcli
index 3d8c16e..7347fbb 100755
--- a/nvmetcli
+++ b/nvmetcli
@@ -155,6 +155,7 @@ class UISubsystemNode(UINode):
     ui_desc_attr = {
         'allow_any_host': ('string', 'Allow access by any host if set to 1'),
         'serial': ('string', 'Export serial number to hosts'),
+        'model': ('string', 'Set a model description'),
         'version': ('string', 'Export version number to hosts'),
     }
 
@@ -172,6 +173,7 @@ class UISubsystemNode(UINode):
         info.append("allow_any=" +
                     self.cfnode.get_attr("attr", "allow_any_host"))
         info.append("serial=" + self.cfnode.get_attr("attr", "serial"))
+        info.append("model=" + self.cfnode.get_attr("attr", "model"))
         return (", ".join(info), True)
 
 

[-- Attachment #4: Type: text/plain, Size: 158 bytes --]

_______________________________________________
Linux-nvme mailing list
Linux-nvme@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-nvme

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* Re: [PATCH] nvmet: make ctrl model configurable
  2019-11-01  8:08 Chaitanya Kulkarni
  2019-11-11 10:34 ` Christoph Hellwig
@ 2019-11-11 11:09 ` Mark Ruijter
  1 sibling, 0 replies; 10+ messages in thread
From: Mark Ruijter @ 2019-11-11 11:09 UTC (permalink / raw)
  To: Chaitanya Kulkarni, linux-nvme; +Cc: hch, sagi

[-- Attachment #1: Type: text/plain, Size: 8815 bytes --]

Hi Chaitanya,

I just removed my original patch from my test system that I use and replaced it with the patch that you submitted a while ago.
When trying to use it I noticed it is flawed.

Any attempt to change the model will return 'invalid argument'.
The ret variable is initialized as '-EINVAL' by default and never set to 0 when the input was valid.

The minimum change required to solve the problem would be :
diff -u configfs.c configfs.c-orig 
--- configfs.c	2019-11-11 10:16:14.970374663 +0100
+++ configfs.c-orig	2019-11-11 10:05:27.754635151 +0100
@@ -874,7 +874,7 @@
 					     const char *page, size_t count)
 {
 	struct nvmet_subsys *subsys = to_subsys(item);
-	int ret = 0, pos, len;
+	int ret = -EINVAL, pos, len;
 	char c;
 
 	down_write(&nvmet_config_sem);

Looking at this code once more I would probably simplify it like this:

diff --git a/configfs.c-orig b/configfs.c
index 1d64059..d2e7935 100644
--- a/configfs.c-orig
+++ b/configfs.c
@@ -879,28 +879,26 @@ static ssize_t nvmet_subsys_attr_model_store(struct config_item *item,
 
        down_write(&nvmet_config_sem);
        len = strcspn(page, "\n");
-       if (!len) {
-               ret = -EINVAL;
+       if (!len)
                goto out_unlock;
-       }
 
        /* Only 20h (space) until 7eh (~) is allowed */
        for (pos = 0; pos < len; pos++) {
                c = page[pos];
-               if (c < 0x20 || c > 0x7e) {
-                       ret = -EINVAL;
+               if (c < 0x20 || c > 0x7e)
                        goto out_unlock;
-               }
        }
 
        kfree(subsys->model);
        subsys->model = kstrndup(page, len, GFP_KERNEL);
        if (!subsys->model)
                ret = -ENOMEM;
+       else
+               ret = count;
 
 out_unlock:
        up_write(&nvmet_config_sem);
-       return ret ? ret : count;
+       return ret;
 }
 
 CONFIGFS_ATTR(nvmet_subsys_, attr_model);

---

This shortens the routine with 2 lines.
I tested both changes and they work:

dev:/sys/kernel/config/nvmet/subsystems/loop # echo -e "\t model" > attr_model 
-bash: echo: write error: Invalid argument
dev:/sys/kernel/config/nvmet/subsystems/loop # echo -e "newmodel" > attr_model

I have attached the tested patch with the shortened routine to this email.

Thanks,

Mark



This email message is for the sole use of the intended recipient(s) and contains confidential information.  Any unauthorized use, disclosure or distribution is prohibited.  If you are not an intended recipient, please contact the sender by reply email and destroy all copies of the original message.

Op 01-11-19 09:09 heeft Linux-nvme namens Chaitanya Kulkarni <linux-nvme-bounces@lists.infradead.org namens chaitanya.kulkarni@wdc.com> geschreven:

    From: Mark Ruijter <MRuijter@onestopsystems.com>
    
    This patch adds a new target subsys attribute which allows user to
    optionally specify model name which then used in the
    nvmet_execute_identify_ctrl() to fill up the nvme_id_ctrl structure.
    
    The default value for the model is set to "Linux" for backward
    compatibility.
    
    Signed-off-by: Mark Ruijter <MRuijter@onestopsystems.com>
    Signed-off-by: Chaitanya Kulkarni <chaitanya.kulkarni@wdc.com>
    ---
    Hi,
    
    This patch is originally posted by Mark and later same day by me with
    the same concept. I've merged changes from both patch into one and
    cleaned the code to fit the kernel coding standards.
    
    -Regards,
    Chaitanya
    ---
     drivers/nvme/target/admin-cmd.c |  4 +--
     drivers/nvme/target/configfs.c  | 45 +++++++++++++++++++++++++++++++++
     drivers/nvme/target/core.c      |  7 +++++
     drivers/nvme/target/nvmet.h     |  2 ++
     4 files changed, 56 insertions(+), 2 deletions(-)
    
    diff --git a/drivers/nvme/target/admin-cmd.c b/drivers/nvme/target/admin-cmd.c
    index 56c21b501185..917d8f3fded7 100644
    --- a/drivers/nvme/target/admin-cmd.c
    +++ b/drivers/nvme/target/admin-cmd.c
    @@ -315,9 +315,9 @@ static void nvmet_execute_get_log_page(struct nvmet_req *req)
     static void nvmet_execute_identify_ctrl(struct nvmet_req *req)
     {
     	struct nvmet_ctrl *ctrl = req->sq->ctrl;
    +	const char *model = ctrl->subsys->model;
     	struct nvme_id_ctrl *id;
     	u16 status = 0;
    -	const char model[] = "Linux";
     
     	id = kzalloc(sizeof(*id), GFP_KERNEL);
     	if (!id) {
    @@ -332,7 +332,7 @@ static void nvmet_execute_identify_ctrl(struct nvmet_req *req)
     	memset(id->sn, ' ', sizeof(id->sn));
     	bin2hex(id->sn, &ctrl->subsys->serial,
     		min(sizeof(ctrl->subsys->serial), sizeof(id->sn) / 2));
    -	memcpy_and_pad(id->mn, sizeof(id->mn), model, sizeof(model) - 1, ' ');
    +	memcpy_and_pad(id->mn, sizeof(id->mn), model, strlen(model), ' ');
     	memcpy_and_pad(id->fr, sizeof(id->fr),
     		       UTS_RELEASE, strlen(UTS_RELEASE), ' ');
     
    diff --git a/drivers/nvme/target/configfs.c b/drivers/nvme/target/configfs.c
    index 98613a45bd3b..faf34b15b975 100644
    --- a/drivers/nvme/target/configfs.c
    +++ b/drivers/nvme/target/configfs.c
    @@ -862,10 +862,54 @@ static ssize_t nvmet_subsys_attr_serial_store(struct config_item *item,
     }
     CONFIGFS_ATTR(nvmet_subsys_, attr_serial);
     
    +static ssize_t nvmet_subsys_attr_model_show(struct config_item *item,
    +					    char *page)
    +{
    +	struct nvmet_subsys *subsys = to_subsys(item);
    +
    +	return snprintf(page, PAGE_SIZE, "%s\n", subsys->model);
    +}
    +
    +static ssize_t nvmet_subsys_attr_model_store(struct config_item *item,
    +					     const char *page, size_t count)
    +{
    +	struct nvmet_subsys *subsys = to_subsys(item);
    +	int ret = -EINVAL, pos, len;
    +	char c;
    +
    +	down_write(&nvmet_config_sem);
    +	len = strcspn(page, "\n");
    +	if (!len) {
    +		ret = -EINVAL;
    +		goto out_unlock;
    +	}
    +
    +	/* Only 20h (space) until 7eh (~) is allowed */
    +	for (pos = 0; pos < len; pos++) {
    +		c = page[pos];
    +		if (c < 0x20 || c > 0x7e) {
    +			ret = -EINVAL;
    +			goto out_unlock;
    +		}
    +	}
    +
    +	kfree(subsys->model);
    +	subsys->model = kstrndup(page, len, GFP_KERNEL);
    +	if (!subsys->model)
    +		ret = -ENOMEM;
    +
    +out_unlock:
    +	up_write(&nvmet_config_sem);
    +	return ret ? ret : count;
    +}
    +
    +CONFIGFS_ATTR(nvmet_subsys_, attr_model);
    +
     static struct configfs_attribute *nvmet_subsys_attrs[] = {
     	&nvmet_subsys_attr_attr_allow_any_host,
     	&nvmet_subsys_attr_attr_version,
     	&nvmet_subsys_attr_attr_serial,
    +	&nvmet_subsys_attr_attr_model,
     	NULL,
     };
     
    @@ -901,6 +945,7 @@ static struct config_group *nvmet_subsys_make(struct config_group *group,
     	}
     
     	subsys = nvmet_subsys_alloc(name, NVME_NQN_NVME);
    +	subsys->model = kstrdup(NVMET_DEFAULT_CTRL_MODEL, GFP_KERNEL);
     	if (IS_ERR(subsys))
     		return ERR_CAST(subsys);
     
    diff --git a/drivers/nvme/target/core.c b/drivers/nvme/target/core.c
    index 28438b833c1b..adc1eb667601 100644
    --- a/drivers/nvme/target/core.c
    +++ b/drivers/nvme/target/core.c
    @@ -1416,6 +1416,12 @@ struct nvmet_subsys *nvmet_subsys_alloc(const char *subsysnqn,
     		kfree(subsys);
     		return ERR_PTR(-ENOMEM);
     	}
    +	subsys->model = kstrdup(NVMET_DEFAULT_CTRL_MODEL, GFP_KERNEL);
    +	if (!subsys->model) {
    +		kfree(subsys->subsysnqn);
    +		kfree(subsys);
    +		return ERR_PTR(-ENOMEM);
    +	}
     
     	kref_init(&subsys->ref);
     
    @@ -1435,6 +1441,7 @@ static void nvmet_subsys_free(struct kref *ref)
     	WARN_ON_ONCE(!list_empty(&subsys->namespaces));
     
     	kfree(subsys->subsysnqn);
    +	kfree(subsys->model);
     	kfree(subsys);
     }
     
    diff --git a/drivers/nvme/target/nvmet.h b/drivers/nvme/target/nvmet.h
    index 46df45e837c9..afb6116de892 100644
    --- a/drivers/nvme/target/nvmet.h
    +++ b/drivers/nvme/target/nvmet.h
    @@ -23,6 +23,7 @@
     #define NVMET_ASYNC_EVENTS		4
     #define NVMET_ERROR_LOG_SLOTS		128
     #define NVMET_NO_ERROR_LOC		((u16)-1)
    +#define NVMET_DEFAULT_CTRL_MODEL       "Linux"
     
     /*
      * Supported optional AENs:
    @@ -222,6 +223,7 @@ struct nvmet_subsys {
     	u64			ver;
     	u64			serial;
     	char			*subsysnqn;
    +	char			*model;
     
     	struct config_group	group;
     
    -- 
    2.22.1
    
    
    _______________________________________________
    Linux-nvme mailing list
    Linux-nvme@lists.infradead.org
    http://lists.infradead.org/mailman/listinfo/linux-nvme
    


[-- Attachment #2: model_patch_patched.diff --]
[-- Type: application/octet-stream, Size: 3903 bytes --]

diff --git a/drivers/nvme/target/admin-cmd.c b/drivers/nvme/target/admin-cmd.c
index 51800a9..1f6f7d9 100644
--- a/drivers/nvme/target/admin-cmd.c
+++ b/drivers/nvme/target/admin-cmd.c
@@ -287,9 +287,9 @@ out:
 static void nvmet_execute_identify_ctrl(struct nvmet_req *req)
 {
 	struct nvmet_ctrl *ctrl = req->sq->ctrl;
+	const char *model = ctrl->subsys->model;
 	struct nvme_id_ctrl *id;
 	u16 status = 0;
-	const char model[] = "Linux";
 
 	id = kzalloc(sizeof(*id), GFP_KERNEL);
 	if (!id) {
@@ -304,7 +304,7 @@ static void nvmet_execute_identify_ctrl(struct nvmet_req *req)
 	memset(id->sn, ' ', sizeof(id->sn));
 	bin2hex(id->sn, &ctrl->subsys->serial,
 		min(sizeof(ctrl->subsys->serial), sizeof(id->sn) / 2));
-	memcpy_and_pad(id->mn, sizeof(id->mn), model, sizeof(model) - 1, ' ');
+	memcpy_and_pad(id->mn, sizeof(id->mn), model, strlen(model), ' ');
 	memcpy_and_pad(id->fr, sizeof(id->fr),
 		       UTS_RELEASE, strlen(UTS_RELEASE), ' ');
 
diff --git a/drivers/nvme/target/configfs.c b/drivers/nvme/target/configfs.c
index 98613a4..ef62853 100644
--- a/drivers/nvme/target/configfs.c
+++ b/drivers/nvme/target/configfs.c
@@ -862,10 +862,52 @@ static ssize_t nvmet_subsys_attr_serial_store(struct config_item *item,
 }
 CONFIGFS_ATTR(nvmet_subsys_, attr_serial);
 
+static ssize_t nvmet_subsys_attr_model_show(struct config_item *item,
+					    char *page)
+{
+	struct nvmet_subsys *subsys = to_subsys(item);
+
+	return snprintf(page, PAGE_SIZE, "%s\n", subsys->model);
+}
+
+static ssize_t nvmet_subsys_attr_model_store(struct config_item *item,
+					     const char *page, size_t count)
+{
+	struct nvmet_subsys *subsys = to_subsys(item);
+	int ret = -EINVAL, pos, len;
+	char c;
+
+	down_write(&nvmet_config_sem);
+	len = strcspn(page, "\n");
+	if (!len)
+		goto out_unlock;
+
+	/* Only 20h (space) until 7eh (~) is allowed */
+	for (pos = 0; pos < len; pos++) {
+		c = page[pos];
+		if (c < 0x20 || c > 0x7e)
+			goto out_unlock;
+	}
+
+	kfree(subsys->model);
+	subsys->model = kstrndup(page, len, GFP_KERNEL);
+	if (!subsys->model)
+		ret = -ENOMEM;
+	else
+		ret = count;
+
+out_unlock:
+	up_write(&nvmet_config_sem);
+	return ret;
+}
+
+CONFIGFS_ATTR(nvmet_subsys_, attr_model);
+
 static struct configfs_attribute *nvmet_subsys_attrs[] = {
 	&nvmet_subsys_attr_attr_allow_any_host,
 	&nvmet_subsys_attr_attr_version,
 	&nvmet_subsys_attr_attr_serial,
+	&nvmet_subsys_attr_attr_model,
 	NULL,
 };
 
@@ -901,6 +943,7 @@ static struct config_group *nvmet_subsys_make(struct config_group *group,
 	}
 
 	subsys = nvmet_subsys_alloc(name, NVME_NQN_NVME);
+	subsys->model = kstrdup(NVMET_DEFAULT_CTRL_MODEL, GFP_KERNEL);
 	if (IS_ERR(subsys))
 		return ERR_CAST(subsys);
 
diff --git a/drivers/nvme/target/core.c b/drivers/nvme/target/core.c
index 3a67e24..5dc90ba 100644
--- a/drivers/nvme/target/core.c
+++ b/drivers/nvme/target/core.c
@@ -1418,6 +1418,12 @@ struct nvmet_subsys *nvmet_subsys_alloc(const char *subsysnqn,
 		kfree(subsys);
 		return ERR_PTR(-ENOMEM);
 	}
+	subsys->model = kstrdup(NVMET_DEFAULT_CTRL_MODEL, GFP_KERNEL);
+	if (!subsys->model) {
+		kfree(subsys->subsysnqn);
+		kfree(subsys);
+		return ERR_PTR(-ENOMEM);
+	}
 
 	kref_init(&subsys->ref);
 
@@ -1437,6 +1443,7 @@ static void nvmet_subsys_free(struct kref *ref)
 	WARN_ON_ONCE(!list_empty(&subsys->namespaces));
 
 	kfree(subsys->subsysnqn);
+	kfree(subsys->model);
 	kfree(subsys);
 }
 
diff --git a/drivers/nvme/target/nvmet.h b/drivers/nvme/target/nvmet.h
index c51f8dd..fd0d89a 100644
--- a/drivers/nvme/target/nvmet.h
+++ b/drivers/nvme/target/nvmet.h
@@ -23,6 +23,7 @@
 #define NVMET_ASYNC_EVENTS		4
 #define NVMET_ERROR_LOG_SLOTS		128
 #define NVMET_NO_ERROR_LOC		((u16)-1)
+#define NVMET_DEFAULT_CTRL_MODEL       "Linux"
 
 /*
  * Supported optional AENs:
@@ -222,6 +223,7 @@ struct nvmet_subsys {
 	u64			ver;
 	u64			serial;
 	char			*subsysnqn;
+	char			*model;
 
 	struct config_group	group;
 

[-- Attachment #3: Type: text/plain, Size: 158 bytes --]

_______________________________________________
Linux-nvme mailing list
Linux-nvme@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-nvme

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* Re: [PATCH] nvmet: make ctrl model configurable
  2019-11-01  8:08 Chaitanya Kulkarni
@ 2019-11-11 10:34 ` Christoph Hellwig
  2019-11-11 13:31   ` Mark Ruijter
  2019-11-12  7:06   ` Chaitanya Kulkarni
  2019-11-11 11:09 ` Mark Ruijter
  1 sibling, 2 replies; 10+ messages in thread
From: Christoph Hellwig @ 2019-11-11 10:34 UTC (permalink / raw)
  To: Chaitanya Kulkarni; +Cc: hch, linux-nvme, sagi

> +	const char *model = ctrl->subsys->model;

Can we have a little nvme_controller_mode() helper that uses
subsystem->model if it is set, and otherwise the default?  That saves
memory by not duplicating the default name for every subsystem.

> +	kfree(subsys->model);
> +	subsys->model = kstrndup(page, len, GFP_KERNEL);
> +	if (!subsys->model)
> +		ret = -ENOMEM;

I don't think we should free the old model until the new one
is allocated.

Otherwise this looks good to me, but can someone also prepare a
nvmetcli patch as well?

_______________________________________________
Linux-nvme mailing list
Linux-nvme@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-nvme

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH] nvmet: make ctrl model configurable
@ 2019-11-01  8:08 Chaitanya Kulkarni
  2019-11-11 10:34 ` Christoph Hellwig
  2019-11-11 11:09 ` Mark Ruijter
  0 siblings, 2 replies; 10+ messages in thread
From: Chaitanya Kulkarni @ 2019-11-01  8:08 UTC (permalink / raw)
  To: linux-nvme; +Cc: hch, Chaitanya Kulkarni, sagi

From: Mark Ruijter <MRuijter@onestopsystems.com>

This patch adds a new target subsys attribute which allows user to
optionally specify model name which then used in the
nvmet_execute_identify_ctrl() to fill up the nvme_id_ctrl structure.

The default value for the model is set to "Linux" for backward
compatibility.

Signed-off-by: Mark Ruijter <MRuijter@onestopsystems.com>
Signed-off-by: Chaitanya Kulkarni <chaitanya.kulkarni@wdc.com>
---
Hi,

This patch is originally posted by Mark and later same day by me with
the same concept. I've merged changes from both patch into one and
cleaned the code to fit the kernel coding standards.

-Regards,
Chaitanya
---
 drivers/nvme/target/admin-cmd.c |  4 +--
 drivers/nvme/target/configfs.c  | 45 +++++++++++++++++++++++++++++++++
 drivers/nvme/target/core.c      |  7 +++++
 drivers/nvme/target/nvmet.h     |  2 ++
 4 files changed, 56 insertions(+), 2 deletions(-)

diff --git a/drivers/nvme/target/admin-cmd.c b/drivers/nvme/target/admin-cmd.c
index 56c21b501185..917d8f3fded7 100644
--- a/drivers/nvme/target/admin-cmd.c
+++ b/drivers/nvme/target/admin-cmd.c
@@ -315,9 +315,9 @@ static void nvmet_execute_get_log_page(struct nvmet_req *req)
 static void nvmet_execute_identify_ctrl(struct nvmet_req *req)
 {
 	struct nvmet_ctrl *ctrl = req->sq->ctrl;
+	const char *model = ctrl->subsys->model;
 	struct nvme_id_ctrl *id;
 	u16 status = 0;
-	const char model[] = "Linux";
 
 	id = kzalloc(sizeof(*id), GFP_KERNEL);
 	if (!id) {
@@ -332,7 +332,7 @@ static void nvmet_execute_identify_ctrl(struct nvmet_req *req)
 	memset(id->sn, ' ', sizeof(id->sn));
 	bin2hex(id->sn, &ctrl->subsys->serial,
 		min(sizeof(ctrl->subsys->serial), sizeof(id->sn) / 2));
-	memcpy_and_pad(id->mn, sizeof(id->mn), model, sizeof(model) - 1, ' ');
+	memcpy_and_pad(id->mn, sizeof(id->mn), model, strlen(model), ' ');
 	memcpy_and_pad(id->fr, sizeof(id->fr),
 		       UTS_RELEASE, strlen(UTS_RELEASE), ' ');
 
diff --git a/drivers/nvme/target/configfs.c b/drivers/nvme/target/configfs.c
index 98613a45bd3b..faf34b15b975 100644
--- a/drivers/nvme/target/configfs.c
+++ b/drivers/nvme/target/configfs.c
@@ -862,10 +862,54 @@ static ssize_t nvmet_subsys_attr_serial_store(struct config_item *item,
 }
 CONFIGFS_ATTR(nvmet_subsys_, attr_serial);
 
+static ssize_t nvmet_subsys_attr_model_show(struct config_item *item,
+					    char *page)
+{
+	struct nvmet_subsys *subsys = to_subsys(item);
+
+	return snprintf(page, PAGE_SIZE, "%s\n", subsys->model);
+}
+
+static ssize_t nvmet_subsys_attr_model_store(struct config_item *item,
+					     const char *page, size_t count)
+{
+	struct nvmet_subsys *subsys = to_subsys(item);
+	int ret = -EINVAL, pos, len;
+	char c;
+
+	down_write(&nvmet_config_sem);
+	len = strcspn(page, "\n");
+	if (!len) {
+		ret = -EINVAL;
+		goto out_unlock;
+	}
+
+	/* Only 20h (space) until 7eh (~) is allowed */
+	for (pos = 0; pos < len; pos++) {
+		c = page[pos];
+		if (c < 0x20 || c > 0x7e) {
+			ret = -EINVAL;
+			goto out_unlock;
+		}
+	}
+
+	kfree(subsys->model);
+	subsys->model = kstrndup(page, len, GFP_KERNEL);
+	if (!subsys->model)
+		ret = -ENOMEM;
+
+out_unlock:
+	up_write(&nvmet_config_sem);
+	return ret ? ret : count;
+}
+
+CONFIGFS_ATTR(nvmet_subsys_, attr_model);
+
 static struct configfs_attribute *nvmet_subsys_attrs[] = {
 	&nvmet_subsys_attr_attr_allow_any_host,
 	&nvmet_subsys_attr_attr_version,
 	&nvmet_subsys_attr_attr_serial,
+	&nvmet_subsys_attr_attr_model,
 	NULL,
 };
 
@@ -901,6 +945,7 @@ static struct config_group *nvmet_subsys_make(struct config_group *group,
 	}
 
 	subsys = nvmet_subsys_alloc(name, NVME_NQN_NVME);
+	subsys->model = kstrdup(NVMET_DEFAULT_CTRL_MODEL, GFP_KERNEL);
 	if (IS_ERR(subsys))
 		return ERR_CAST(subsys);
 
diff --git a/drivers/nvme/target/core.c b/drivers/nvme/target/core.c
index 28438b833c1b..adc1eb667601 100644
--- a/drivers/nvme/target/core.c
+++ b/drivers/nvme/target/core.c
@@ -1416,6 +1416,12 @@ struct nvmet_subsys *nvmet_subsys_alloc(const char *subsysnqn,
 		kfree(subsys);
 		return ERR_PTR(-ENOMEM);
 	}
+	subsys->model = kstrdup(NVMET_DEFAULT_CTRL_MODEL, GFP_KERNEL);
+	if (!subsys->model) {
+		kfree(subsys->subsysnqn);
+		kfree(subsys);
+		return ERR_PTR(-ENOMEM);
+	}
 
 	kref_init(&subsys->ref);
 
@@ -1435,6 +1441,7 @@ static void nvmet_subsys_free(struct kref *ref)
 	WARN_ON_ONCE(!list_empty(&subsys->namespaces));
 
 	kfree(subsys->subsysnqn);
+	kfree(subsys->model);
 	kfree(subsys);
 }
 
diff --git a/drivers/nvme/target/nvmet.h b/drivers/nvme/target/nvmet.h
index 46df45e837c9..afb6116de892 100644
--- a/drivers/nvme/target/nvmet.h
+++ b/drivers/nvme/target/nvmet.h
@@ -23,6 +23,7 @@
 #define NVMET_ASYNC_EVENTS		4
 #define NVMET_ERROR_LOG_SLOTS		128
 #define NVMET_NO_ERROR_LOC		((u16)-1)
+#define NVMET_DEFAULT_CTRL_MODEL       "Linux"
 
 /*
  * Supported optional AENs:
@@ -222,6 +223,7 @@ struct nvmet_subsys {
 	u64			ver;
 	u64			serial;
 	char			*subsysnqn;
+	char			*model;
 
 	struct config_group	group;
 
-- 
2.22.1


_______________________________________________
Linux-nvme mailing list
Linux-nvme@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-nvme

^ permalink raw reply related	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2019-11-12  7:07 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-10-30 19:48 [PATCH] nvmet: make ctrl model configurable Chaitanya Kulkarni
2019-10-30 20:08 ` Mark Ruijter
2019-10-30 20:09   ` Chaitanya Kulkarni
2019-10-30 21:43   ` Chaitanya Kulkarni
2019-11-01  8:08 Chaitanya Kulkarni
2019-11-11 10:34 ` Christoph Hellwig
2019-11-11 13:31   ` Mark Ruijter
2019-11-12  7:07     ` Chaitanya Kulkarni
2019-11-12  7:06   ` Chaitanya Kulkarni
2019-11-11 11:09 ` Mark Ruijter

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).