Skip to content

Commit d9f273b

Browse files
mgurtovoyChristoph Hellwig
authored andcommitted
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 <[email protected]> Signed-off-by: Christoph Hellwig <[email protected]>
1 parent 32feb6d commit d9f273b

File tree

4 files changed

+50
-45
lines changed

4 files changed

+50
-45
lines changed

drivers/nvme/target/admin-cmd.c

Lines changed: 25 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -313,27 +313,40 @@ static void nvmet_execute_get_log_page(struct nvmet_req *req)
313313
nvmet_req_complete(req, NVME_SC_INVALID_FIELD | NVME_SC_DNR);
314314
}
315315

316-
static void nvmet_id_set_model_number(struct nvme_id_ctrl *id,
317-
struct nvmet_subsys *subsys)
316+
static u16 nvmet_set_model_number(struct nvmet_subsys *subsys)
318317
{
319-
const char *model = NVMET_DEFAULT_CTRL_MODEL;
320-
struct nvmet_subsys_model *subsys_model;
318+
u16 status = 0;
319+
320+
mutex_lock(&subsys->lock);
321+
if (!subsys->model_number) {
322+
subsys->model_number =
323+
kstrdup(NVMET_DEFAULT_CTRL_MODEL, GFP_KERNEL);
324+
if (!subsys->model_number)
325+
status = NVME_SC_INTERNAL;
326+
}
327+
mutex_unlock(&subsys->lock);
321328

322-
rcu_read_lock();
323-
subsys_model = rcu_dereference(subsys->model);
324-
if (subsys_model)
325-
model = subsys_model->number;
326-
memcpy_and_pad(id->mn, sizeof(id->mn), model, strlen(model), ' ');
327-
rcu_read_unlock();
329+
return status;
328330
}
329331

330332
static void nvmet_execute_identify_ctrl(struct nvmet_req *req)
331333
{
332334
struct nvmet_ctrl *ctrl = req->sq->ctrl;
335+
struct nvmet_subsys *subsys = ctrl->subsys;
333336
struct nvme_id_ctrl *id;
334337
u32 cmd_capsule_size;
335338
u16 status = 0;
336339

340+
/*
341+
* If there is no model number yet, set it now. It will then remain
342+
* stable for the life time of the subsystem.
343+
*/
344+
if (!subsys->model_number) {
345+
status = nvmet_set_model_number(subsys);
346+
if (status)
347+
goto out;
348+
}
349+
337350
id = kzalloc(sizeof(*id), GFP_KERNEL);
338351
if (!id) {
339352
status = NVME_SC_INTERNAL;
@@ -347,7 +360,8 @@ static void nvmet_execute_identify_ctrl(struct nvmet_req *req)
347360
memset(id->sn, ' ', sizeof(id->sn));
348361
bin2hex(id->sn, &ctrl->subsys->serial,
349362
min(sizeof(ctrl->subsys->serial), sizeof(id->sn) / 2));
350-
nvmet_id_set_model_number(id, ctrl->subsys);
363+
memcpy_and_pad(id->mn, sizeof(id->mn), subsys->model_number,
364+
strlen(subsys->model_number), ' ');
351365
memcpy_and_pad(id->fr, sizeof(id->fr),
352366
UTS_RELEASE, strlen(UTS_RELEASE), ' ');
353367

drivers/nvme/target/configfs.c

Lines changed: 23 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1118,16 +1118,12 @@ static ssize_t nvmet_subsys_attr_model_show(struct config_item *item,
11181118
char *page)
11191119
{
11201120
struct nvmet_subsys *subsys = to_subsys(item);
1121-
struct nvmet_subsys_model *subsys_model;
1122-
char *model = NVMET_DEFAULT_CTRL_MODEL;
11231121
int ret;
11241122

1125-
rcu_read_lock();
1126-
subsys_model = rcu_dereference(subsys->model);
1127-
if (subsys_model)
1128-
model = subsys_model->number;
1129-
ret = snprintf(page, PAGE_SIZE, "%s\n", model);
1130-
rcu_read_unlock();
1123+
mutex_lock(&subsys->lock);
1124+
ret = snprintf(page, PAGE_SIZE, "%s\n", subsys->model_number ?
1125+
subsys->model_number : NVMET_DEFAULT_CTRL_MODEL);
1126+
mutex_unlock(&subsys->lock);
11311127

11321128
return ret;
11331129
}
@@ -1138,14 +1134,17 @@ static bool nvmet_is_ascii(const char c)
11381134
return c >= 0x20 && c <= 0x7e;
11391135
}
11401136

1141-
static ssize_t nvmet_subsys_attr_model_store(struct config_item *item,
1142-
const char *page, size_t count)
1137+
static ssize_t nvmet_subsys_attr_model_store_locked(struct nvmet_subsys *subsys,
1138+
const char *page, size_t count)
11431139
{
1144-
struct nvmet_subsys *subsys = to_subsys(item);
1145-
struct nvmet_subsys_model *new_model;
1146-
char *new_model_number;
11471140
int pos = 0, len;
11481141

1142+
if (subsys->model_number) {
1143+
pr_err("Can't set model number. %s is already assigned\n",
1144+
subsys->model_number);
1145+
return -EINVAL;
1146+
}
1147+
11491148
len = strcspn(page, "\n");
11501149
if (!len)
11511150
return -EINVAL;
@@ -1155,28 +1154,25 @@ static ssize_t nvmet_subsys_attr_model_store(struct config_item *item,
11551154
return -EINVAL;
11561155
}
11571156

1158-
new_model_number = kmemdup_nul(page, len, GFP_KERNEL);
1159-
if (!new_model_number)
1157+
subsys->model_number = kmemdup_nul(page, len, GFP_KERNEL);
1158+
if (!subsys->model_number)
11601159
return -ENOMEM;
1160+
return count;
1161+
}
11611162

1162-
new_model = kzalloc(sizeof(*new_model) + len + 1, GFP_KERNEL);
1163-
if (!new_model) {
1164-
kfree(new_model_number);
1165-
return -ENOMEM;
1166-
}
1167-
memcpy(new_model->number, new_model_number, len);
1163+
static ssize_t nvmet_subsys_attr_model_store(struct config_item *item,
1164+
const char *page, size_t count)
1165+
{
1166+
struct nvmet_subsys *subsys = to_subsys(item);
1167+
ssize_t ret;
11681168

11691169
down_write(&nvmet_config_sem);
11701170
mutex_lock(&subsys->lock);
1171-
new_model = rcu_replace_pointer(subsys->model, new_model,
1172-
mutex_is_locked(&subsys->lock));
1171+
ret = nvmet_subsys_attr_model_store_locked(subsys, page, count);
11731172
mutex_unlock(&subsys->lock);
11741173
up_write(&nvmet_config_sem);
11751174

1176-
kfree_rcu(new_model, rcuhead);
1177-
kfree(new_model_number);
1178-
1179-
return count;
1175+
return ret;
11801176
}
11811177
CONFIGFS_ATTR(nvmet_subsys_, attr_model);
11821178

drivers/nvme/target/core.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1532,7 +1532,7 @@ static void nvmet_subsys_free(struct kref *ref)
15321532
nvmet_passthru_subsys_free(subsys);
15331533

15341534
kfree(subsys->subsysnqn);
1535-
kfree_rcu(subsys->model, rcuhead);
1535+
kfree(subsys->model_number);
15361536
kfree(subsys);
15371537
}
15381538

drivers/nvme/target/nvmet.h

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -208,11 +208,6 @@ struct nvmet_ctrl {
208208
bool pi_support;
209209
};
210210

211-
struct nvmet_subsys_model {
212-
struct rcu_head rcuhead;
213-
char number[];
214-
};
215-
216211
struct nvmet_subsys {
217212
enum nvme_subsys_type type;
218213

@@ -242,7 +237,7 @@ struct nvmet_subsys {
242237
struct config_group namespaces_group;
243238
struct config_group allowed_hosts_group;
244239

245-
struct nvmet_subsys_model __rcu *model;
240+
char *model_number;
246241

247242
#ifdef CONFIG_NVME_TARGET_PASSTHRU
248243
struct nvme_ctrl *passthru_ctrl;

0 commit comments

Comments
 (0)