mirror of
https://github.com/torvalds/linux.git
synced 2026-04-18 14:53:58 -04:00
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:
committed by
Christoph Hellwig
parent
32feb6de47
commit
d9f273b758
@@ -1118,16 +1118,12 @@ static ssize_t nvmet_subsys_attr_model_show(struct config_item *item,
|
||||
char *page)
|
||||
{
|
||||
struct nvmet_subsys *subsys = to_subsys(item);
|
||||
struct nvmet_subsys_model *subsys_model;
|
||||
char *model = NVMET_DEFAULT_CTRL_MODEL;
|
||||
int ret;
|
||||
|
||||
rcu_read_lock();
|
||||
subsys_model = rcu_dereference(subsys->model);
|
||||
if (subsys_model)
|
||||
model = subsys_model->number;
|
||||
ret = snprintf(page, PAGE_SIZE, "%s\n", model);
|
||||
rcu_read_unlock();
|
||||
mutex_lock(&subsys->lock);
|
||||
ret = snprintf(page, PAGE_SIZE, "%s\n", subsys->model_number ?
|
||||
subsys->model_number : NVMET_DEFAULT_CTRL_MODEL);
|
||||
mutex_unlock(&subsys->lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -1138,14 +1134,17 @@ static bool nvmet_is_ascii(const char c)
|
||||
return c >= 0x20 && c <= 0x7e;
|
||||
}
|
||||
|
||||
static ssize_t nvmet_subsys_attr_model_store(struct config_item *item,
|
||||
const char *page, size_t count)
|
||||
static ssize_t nvmet_subsys_attr_model_store_locked(struct nvmet_subsys *subsys,
|
||||
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;
|
||||
|
||||
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");
|
||||
if (!len)
|
||||
return -EINVAL;
|
||||
@@ -1155,28 +1154,25 @@ static ssize_t nvmet_subsys_attr_model_store(struct config_item *item,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
new_model_number = kmemdup_nul(page, len, GFP_KERNEL);
|
||||
if (!new_model_number)
|
||||
subsys->model_number = kmemdup_nul(page, len, GFP_KERNEL);
|
||||
if (!subsys->model_number)
|
||||
return -ENOMEM;
|
||||
return count;
|
||||
}
|
||||
|
||||
new_model = kzalloc(sizeof(*new_model) + len + 1, GFP_KERNEL);
|
||||
if (!new_model) {
|
||||
kfree(new_model_number);
|
||||
return -ENOMEM;
|
||||
}
|
||||
memcpy(new_model->number, new_model_number, len);
|
||||
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);
|
||||
ssize_t ret;
|
||||
|
||||
down_write(&nvmet_config_sem);
|
||||
mutex_lock(&subsys->lock);
|
||||
new_model = rcu_replace_pointer(subsys->model, new_model,
|
||||
mutex_is_locked(&subsys->lock));
|
||||
ret = nvmet_subsys_attr_model_store_locked(subsys, page, count);
|
||||
mutex_unlock(&subsys->lock);
|
||||
up_write(&nvmet_config_sem);
|
||||
|
||||
kfree_rcu(new_model, rcuhead);
|
||||
kfree(new_model_number);
|
||||
|
||||
return count;
|
||||
return ret;
|
||||
}
|
||||
CONFIGFS_ATTR(nvmet_subsys_, attr_model);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user