nvmet: model_number must be immutable once set
In case we have already established connection to nvmf target, it shouldn't be allowed to change the model_number. E.g. if someone will identify ctrl and get model_number of "my_model" later on will change the model_numbel via configfs to "my_new_model" this will break the NVMe specification for "Get Log Page – Persistent Event Log" that refers to Model Number as: "This field contains the same value as reported in the Model Number field of the Identify Controller data structure, bytes 63:24." Although it doesn't mentioned explicitly that this field can't be changed, we can assume it. So allow setting this field only once: using configfs or in the first identify ctrl operation. Signed-off-by: Max Gurtovoy <mgurtovoy@nvidia.com> Signed-off-by: Christoph Hellwig <hch@lst.de>
This commit is contained in:
parent
32feb6de47
commit
d9f273b758
@ -313,27 +313,40 @@ static void nvmet_execute_get_log_page(struct nvmet_req *req)
|
|||||||
nvmet_req_complete(req, NVME_SC_INVALID_FIELD | NVME_SC_DNR);
|
nvmet_req_complete(req, NVME_SC_INVALID_FIELD | NVME_SC_DNR);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void nvmet_id_set_model_number(struct nvme_id_ctrl *id,
|
static u16 nvmet_set_model_number(struct nvmet_subsys *subsys)
|
||||||
struct nvmet_subsys *subsys)
|
|
||||||
{
|
{
|
||||||
const char *model = NVMET_DEFAULT_CTRL_MODEL;
|
u16 status = 0;
|
||||||
struct nvmet_subsys_model *subsys_model;
|
|
||||||
|
|
||||||
rcu_read_lock();
|
mutex_lock(&subsys->lock);
|
||||||
subsys_model = rcu_dereference(subsys->model);
|
if (!subsys->model_number) {
|
||||||
if (subsys_model)
|
subsys->model_number =
|
||||||
model = subsys_model->number;
|
kstrdup(NVMET_DEFAULT_CTRL_MODEL, GFP_KERNEL);
|
||||||
memcpy_and_pad(id->mn, sizeof(id->mn), model, strlen(model), ' ');
|
if (!subsys->model_number)
|
||||||
rcu_read_unlock();
|
status = NVME_SC_INTERNAL;
|
||||||
|
}
|
||||||
|
mutex_unlock(&subsys->lock);
|
||||||
|
|
||||||
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void nvmet_execute_identify_ctrl(struct nvmet_req *req)
|
static void nvmet_execute_identify_ctrl(struct nvmet_req *req)
|
||||||
{
|
{
|
||||||
struct nvmet_ctrl *ctrl = req->sq->ctrl;
|
struct nvmet_ctrl *ctrl = req->sq->ctrl;
|
||||||
|
struct nvmet_subsys *subsys = ctrl->subsys;
|
||||||
struct nvme_id_ctrl *id;
|
struct nvme_id_ctrl *id;
|
||||||
u32 cmd_capsule_size;
|
u32 cmd_capsule_size;
|
||||||
u16 status = 0;
|
u16 status = 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If there is no model number yet, set it now. It will then remain
|
||||||
|
* stable for the life time of the subsystem.
|
||||||
|
*/
|
||||||
|
if (!subsys->model_number) {
|
||||||
|
status = nvmet_set_model_number(subsys);
|
||||||
|
if (status)
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
id = kzalloc(sizeof(*id), GFP_KERNEL);
|
id = kzalloc(sizeof(*id), GFP_KERNEL);
|
||||||
if (!id) {
|
if (!id) {
|
||||||
status = NVME_SC_INTERNAL;
|
status = NVME_SC_INTERNAL;
|
||||||
@ -347,7 +360,8 @@ static void nvmet_execute_identify_ctrl(struct nvmet_req *req)
|
|||||||
memset(id->sn, ' ', sizeof(id->sn));
|
memset(id->sn, ' ', sizeof(id->sn));
|
||||||
bin2hex(id->sn, &ctrl->subsys->serial,
|
bin2hex(id->sn, &ctrl->subsys->serial,
|
||||||
min(sizeof(ctrl->subsys->serial), sizeof(id->sn) / 2));
|
min(sizeof(ctrl->subsys->serial), sizeof(id->sn) / 2));
|
||||||
nvmet_id_set_model_number(id, ctrl->subsys);
|
memcpy_and_pad(id->mn, sizeof(id->mn), subsys->model_number,
|
||||||
|
strlen(subsys->model_number), ' ');
|
||||||
memcpy_and_pad(id->fr, sizeof(id->fr),
|
memcpy_and_pad(id->fr, sizeof(id->fr),
|
||||||
UTS_RELEASE, strlen(UTS_RELEASE), ' ');
|
UTS_RELEASE, strlen(UTS_RELEASE), ' ');
|
||||||
|
|
||||||
|
@ -1118,16 +1118,12 @@ static ssize_t nvmet_subsys_attr_model_show(struct config_item *item,
|
|||||||
char *page)
|
char *page)
|
||||||
{
|
{
|
||||||
struct nvmet_subsys *subsys = to_subsys(item);
|
struct nvmet_subsys *subsys = to_subsys(item);
|
||||||
struct nvmet_subsys_model *subsys_model;
|
|
||||||
char *model = NVMET_DEFAULT_CTRL_MODEL;
|
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
rcu_read_lock();
|
mutex_lock(&subsys->lock);
|
||||||
subsys_model = rcu_dereference(subsys->model);
|
ret = snprintf(page, PAGE_SIZE, "%s\n", subsys->model_number ?
|
||||||
if (subsys_model)
|
subsys->model_number : NVMET_DEFAULT_CTRL_MODEL);
|
||||||
model = subsys_model->number;
|
mutex_unlock(&subsys->lock);
|
||||||
ret = snprintf(page, PAGE_SIZE, "%s\n", model);
|
|
||||||
rcu_read_unlock();
|
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@ -1138,14 +1134,17 @@ static bool nvmet_is_ascii(const char c)
|
|||||||
return c >= 0x20 && c <= 0x7e;
|
return c >= 0x20 && c <= 0x7e;
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t nvmet_subsys_attr_model_store(struct config_item *item,
|
static ssize_t nvmet_subsys_attr_model_store_locked(struct nvmet_subsys *subsys,
|
||||||
const char *page, size_t count)
|
const char *page, size_t count)
|
||||||
{
|
{
|
||||||
struct nvmet_subsys *subsys = to_subsys(item);
|
|
||||||
struct nvmet_subsys_model *new_model;
|
|
||||||
char *new_model_number;
|
|
||||||
int pos = 0, len;
|
int pos = 0, len;
|
||||||
|
|
||||||
|
if (subsys->model_number) {
|
||||||
|
pr_err("Can't set model number. %s is already assigned\n",
|
||||||
|
subsys->model_number);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
len = strcspn(page, "\n");
|
len = strcspn(page, "\n");
|
||||||
if (!len)
|
if (!len)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
@ -1155,28 +1154,25 @@ static ssize_t nvmet_subsys_attr_model_store(struct config_item *item,
|
|||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
new_model_number = kmemdup_nul(page, len, GFP_KERNEL);
|
subsys->model_number = kmemdup_nul(page, len, GFP_KERNEL);
|
||||||
if (!new_model_number)
|
if (!subsys->model_number)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
new_model = kzalloc(sizeof(*new_model) + len + 1, GFP_KERNEL);
|
static ssize_t nvmet_subsys_attr_model_store(struct config_item *item,
|
||||||
if (!new_model) {
|
const char *page, size_t count)
|
||||||
kfree(new_model_number);
|
{
|
||||||
return -ENOMEM;
|
struct nvmet_subsys *subsys = to_subsys(item);
|
||||||
}
|
ssize_t ret;
|
||||||
memcpy(new_model->number, new_model_number, len);
|
|
||||||
|
|
||||||
down_write(&nvmet_config_sem);
|
down_write(&nvmet_config_sem);
|
||||||
mutex_lock(&subsys->lock);
|
mutex_lock(&subsys->lock);
|
||||||
new_model = rcu_replace_pointer(subsys->model, new_model,
|
ret = nvmet_subsys_attr_model_store_locked(subsys, page, count);
|
||||||
mutex_is_locked(&subsys->lock));
|
|
||||||
mutex_unlock(&subsys->lock);
|
mutex_unlock(&subsys->lock);
|
||||||
up_write(&nvmet_config_sem);
|
up_write(&nvmet_config_sem);
|
||||||
|
|
||||||
kfree_rcu(new_model, rcuhead);
|
return ret;
|
||||||
kfree(new_model_number);
|
|
||||||
|
|
||||||
return count;
|
|
||||||
}
|
}
|
||||||
CONFIGFS_ATTR(nvmet_subsys_, attr_model);
|
CONFIGFS_ATTR(nvmet_subsys_, attr_model);
|
||||||
|
|
||||||
|
@ -1532,7 +1532,7 @@ static void nvmet_subsys_free(struct kref *ref)
|
|||||||
nvmet_passthru_subsys_free(subsys);
|
nvmet_passthru_subsys_free(subsys);
|
||||||
|
|
||||||
kfree(subsys->subsysnqn);
|
kfree(subsys->subsysnqn);
|
||||||
kfree_rcu(subsys->model, rcuhead);
|
kfree(subsys->model_number);
|
||||||
kfree(subsys);
|
kfree(subsys);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -208,11 +208,6 @@ struct nvmet_ctrl {
|
|||||||
bool pi_support;
|
bool pi_support;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct nvmet_subsys_model {
|
|
||||||
struct rcu_head rcuhead;
|
|
||||||
char number[];
|
|
||||||
};
|
|
||||||
|
|
||||||
struct nvmet_subsys {
|
struct nvmet_subsys {
|
||||||
enum nvme_subsys_type type;
|
enum nvme_subsys_type type;
|
||||||
|
|
||||||
@ -242,7 +237,7 @@ struct nvmet_subsys {
|
|||||||
struct config_group namespaces_group;
|
struct config_group namespaces_group;
|
||||||
struct config_group allowed_hosts_group;
|
struct config_group allowed_hosts_group;
|
||||||
|
|
||||||
struct nvmet_subsys_model __rcu *model;
|
char *model_number;
|
||||||
|
|
||||||
#ifdef CONFIG_NVME_TARGET_PASSTHRU
|
#ifdef CONFIG_NVME_TARGET_PASSTHRU
|
||||||
struct nvme_ctrl *passthru_ctrl;
|
struct nvme_ctrl *passthru_ctrl;
|
||||||
|
Loading…
Reference in New Issue
Block a user