forked from luck/tmp_suning_uos_patched
nvmet: make ctrl model configurable
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. Reviewed-by: Christoph Hellwig <hch@lst.de> Reviewed-by: Sagi Grimberg <sagi@grimberg.me> Signed-off-by: Mark Ruijter <MRuijter@onestopsystems.com> [chaitanya.kulkarni@wdc.com *Use macro for default model, coding style fixes. *Use RCU for accessing model in for configfs and in nvmet_execute_identify_ctrl(). ] Signed-off-by: Chaitanya Kulkarni <chaitanya.kulkarni@wdc.com> Signed-off-by: Keith Busch <kbusch@kernel.org>
This commit is contained in:
parent
94a39d61f8
commit
013b7ebe5a
|
@ -322,12 +322,25 @@ 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,
|
||||||
|
struct nvmet_subsys *subsys)
|
||||||
|
{
|
||||||
|
const char *model = NVMET_DEFAULT_CTRL_MODEL;
|
||||||
|
struct nvmet_subsys_model *subsys_model;
|
||||||
|
|
||||||
|
rcu_read_lock();
|
||||||
|
subsys_model = rcu_dereference(subsys->model);
|
||||||
|
if (subsys_model)
|
||||||
|
model = subsys_model->number;
|
||||||
|
memcpy_and_pad(id->mn, sizeof(id->mn), model, strlen(model), ' ');
|
||||||
|
rcu_read_unlock();
|
||||||
|
}
|
||||||
|
|
||||||
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 nvme_id_ctrl *id;
|
struct nvme_id_ctrl *id;
|
||||||
u16 status = 0;
|
u16 status = 0;
|
||||||
const char model[] = "Linux";
|
|
||||||
|
|
||||||
id = kzalloc(sizeof(*id), GFP_KERNEL);
|
id = kzalloc(sizeof(*id), GFP_KERNEL);
|
||||||
if (!id) {
|
if (!id) {
|
||||||
|
@ -342,7 +355,7 @@ 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));
|
||||||
memcpy_and_pad(id->mn, sizeof(id->mn), model, sizeof(model) - 1, ' ');
|
nvmet_id_set_model_number(id, ctrl->subsys);
|
||||||
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), ' ');
|
||||||
|
|
||||||
|
|
|
@ -919,12 +919,78 @@ static ssize_t nvmet_subsys_attr_cntlid_max_store(struct config_item *item,
|
||||||
}
|
}
|
||||||
CONFIGFS_ATTR(nvmet_subsys_, attr_cntlid_max);
|
CONFIGFS_ATTR(nvmet_subsys_, attr_cntlid_max);
|
||||||
|
|
||||||
|
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();
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* See Section 1.5 of NVMe 1.4 */
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
struct nvmet_subsys *subsys = to_subsys(item);
|
||||||
|
struct nvmet_subsys_model *new_model;
|
||||||
|
char *new_model_number;
|
||||||
|
int pos = 0, len;
|
||||||
|
|
||||||
|
len = strcspn(page, "\n");
|
||||||
|
if (!len)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
for (pos = 0; pos < len; pos++) {
|
||||||
|
if (!nvmet_is_ascii(page[pos]))
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
new_model_number = kstrndup(page, len, GFP_KERNEL);
|
||||||
|
if (!new_model_number)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
down_write(&nvmet_config_sem);
|
||||||
|
mutex_lock(&subsys->lock);
|
||||||
|
new_model = rcu_replace_pointer(subsys->model, new_model,
|
||||||
|
mutex_is_locked(&subsys->lock));
|
||||||
|
mutex_unlock(&subsys->lock);
|
||||||
|
up_write(&nvmet_config_sem);
|
||||||
|
|
||||||
|
kfree_rcu(new_model, rcuhead);
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
CONFIGFS_ATTR(nvmet_subsys_, attr_model);
|
||||||
|
|
||||||
static struct configfs_attribute *nvmet_subsys_attrs[] = {
|
static struct configfs_attribute *nvmet_subsys_attrs[] = {
|
||||||
&nvmet_subsys_attr_attr_allow_any_host,
|
&nvmet_subsys_attr_attr_allow_any_host,
|
||||||
&nvmet_subsys_attr_attr_version,
|
&nvmet_subsys_attr_attr_version,
|
||||||
&nvmet_subsys_attr_attr_serial,
|
&nvmet_subsys_attr_attr_serial,
|
||||||
&nvmet_subsys_attr_attr_cntlid_min,
|
&nvmet_subsys_attr_attr_cntlid_min,
|
||||||
&nvmet_subsys_attr_attr_cntlid_max,
|
&nvmet_subsys_attr_attr_cntlid_max,
|
||||||
|
&nvmet_subsys_attr_attr_model,
|
||||||
NULL,
|
NULL,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1461,6 +1461,7 @@ static void nvmet_subsys_free(struct kref *ref)
|
||||||
WARN_ON_ONCE(!list_empty(&subsys->namespaces));
|
WARN_ON_ONCE(!list_empty(&subsys->namespaces));
|
||||||
|
|
||||||
kfree(subsys->subsysnqn);
|
kfree(subsys->subsysnqn);
|
||||||
|
kfree_rcu(subsys->model, rcuhead);
|
||||||
kfree(subsys);
|
kfree(subsys);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
#define NVMET_ASYNC_EVENTS 4
|
#define NVMET_ASYNC_EVENTS 4
|
||||||
#define NVMET_ERROR_LOG_SLOTS 128
|
#define NVMET_ERROR_LOG_SLOTS 128
|
||||||
#define NVMET_NO_ERROR_LOC ((u16)-1)
|
#define NVMET_NO_ERROR_LOC ((u16)-1)
|
||||||
|
#define NVMET_DEFAULT_CTRL_MODEL "Linux"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Supported optional AENs:
|
* Supported optional AENs:
|
||||||
|
@ -202,6 +203,11 @@ struct nvmet_ctrl {
|
||||||
struct nvme_error_slot slots[NVMET_ERROR_LOG_SLOTS];
|
struct nvme_error_slot slots[NVMET_ERROR_LOG_SLOTS];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
@ -229,6 +235,8 @@ 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;
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline struct nvmet_subsys *to_subsys(struct config_item *item)
|
static inline struct nvmet_subsys *to_subsys(struct config_item *item)
|
||||||
|
|
Loading…
Reference in New Issue
Block a user