mirror of https://gitee.com/openkylin/linux.git
nvmet: implement the changed namespaces log
Just keep a per-controller buffer of changed namespaces and copy it out in the get log page implementation. Signed-off-by: Christoph Hellwig <hch@lst.de> Reviewed-by: Sagi Grimberg <sagi@grimberg.me> Reviewed-by: Daniel Verkamp <daniel.verkamp@intel.com>
This commit is contained in:
parent
8ab0805f11
commit
c16734ea98
|
@ -126,6 +126,29 @@ static void nvmet_execute_get_log_page_smart(struct nvmet_req *req)
|
||||||
nvmet_req_complete(req, status);
|
nvmet_req_complete(req, status);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void nvmet_execute_get_log_changed_ns(struct nvmet_req *req)
|
||||||
|
{
|
||||||
|
struct nvmet_ctrl *ctrl = req->sq->ctrl;
|
||||||
|
u16 status = NVME_SC_INTERNAL;
|
||||||
|
size_t len;
|
||||||
|
|
||||||
|
if (req->data_len != NVME_MAX_CHANGED_NAMESPACES * sizeof(__le32))
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
mutex_lock(&ctrl->lock);
|
||||||
|
if (ctrl->nr_changed_ns == U32_MAX)
|
||||||
|
len = sizeof(__le32);
|
||||||
|
else
|
||||||
|
len = ctrl->nr_changed_ns * sizeof(__le32);
|
||||||
|
status = nvmet_copy_to_sgl(req, 0, ctrl->changed_ns_list, len);
|
||||||
|
if (!status)
|
||||||
|
status = nvmet_zero_sgl(req, len, req->data_len - len);
|
||||||
|
ctrl->nr_changed_ns = 0;
|
||||||
|
mutex_unlock(&ctrl->lock);
|
||||||
|
out:
|
||||||
|
nvmet_req_complete(req, 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;
|
||||||
|
@ -543,6 +566,9 @@ u16 nvmet_parse_admin_cmd(struct nvmet_req *req)
|
||||||
*/
|
*/
|
||||||
req->execute = nvmet_execute_get_log_page_noop;
|
req->execute = nvmet_execute_get_log_page_noop;
|
||||||
return 0;
|
return 0;
|
||||||
|
case NVME_LOG_CHANGED_NS:
|
||||||
|
req->execute = nvmet_execute_get_log_changed_ns;
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case nvme_admin_identify:
|
case nvme_admin_identify:
|
||||||
|
|
|
@ -144,6 +144,42 @@ static void nvmet_add_async_event(struct nvmet_ctrl *ctrl, u8 event_type,
|
||||||
schedule_work(&ctrl->async_event_work);
|
schedule_work(&ctrl->async_event_work);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void nvmet_add_to_changed_ns_log(struct nvmet_ctrl *ctrl, __le32 nsid)
|
||||||
|
{
|
||||||
|
u32 i;
|
||||||
|
|
||||||
|
mutex_lock(&ctrl->lock);
|
||||||
|
if (ctrl->nr_changed_ns > NVME_MAX_CHANGED_NAMESPACES)
|
||||||
|
goto out_unlock;
|
||||||
|
|
||||||
|
for (i = 0; i < ctrl->nr_changed_ns; i++) {
|
||||||
|
if (ctrl->changed_ns_list[i] == nsid)
|
||||||
|
goto out_unlock;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ctrl->nr_changed_ns == NVME_MAX_CHANGED_NAMESPACES) {
|
||||||
|
ctrl->changed_ns_list[0] = cpu_to_le32(0xffffffff);
|
||||||
|
ctrl->nr_changed_ns = U32_MAX;
|
||||||
|
goto out_unlock;
|
||||||
|
}
|
||||||
|
|
||||||
|
ctrl->changed_ns_list[ctrl->nr_changed_ns++] = nsid;
|
||||||
|
out_unlock:
|
||||||
|
mutex_unlock(&ctrl->lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void nvmet_ns_changed(struct nvmet_subsys *subsys, u32 nsid)
|
||||||
|
{
|
||||||
|
struct nvmet_ctrl *ctrl;
|
||||||
|
|
||||||
|
list_for_each_entry(ctrl, &subsys->ctrls, subsys_entry) {
|
||||||
|
nvmet_add_to_changed_ns_log(ctrl, cpu_to_le32(nsid));
|
||||||
|
nvmet_add_async_event(ctrl, NVME_AER_TYPE_NOTICE,
|
||||||
|
NVME_AER_NOTICE_NS_CHANGED,
|
||||||
|
NVME_LOG_CHANGED_NS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int nvmet_register_transport(const struct nvmet_fabrics_ops *ops)
|
int nvmet_register_transport(const struct nvmet_fabrics_ops *ops)
|
||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
@ -287,7 +323,6 @@ static void nvmet_ns_dev_disable(struct nvmet_ns *ns)
|
||||||
int nvmet_ns_enable(struct nvmet_ns *ns)
|
int nvmet_ns_enable(struct nvmet_ns *ns)
|
||||||
{
|
{
|
||||||
struct nvmet_subsys *subsys = ns->subsys;
|
struct nvmet_subsys *subsys = ns->subsys;
|
||||||
struct nvmet_ctrl *ctrl;
|
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
mutex_lock(&subsys->lock);
|
mutex_lock(&subsys->lock);
|
||||||
|
@ -326,9 +361,7 @@ int nvmet_ns_enable(struct nvmet_ns *ns)
|
||||||
list_add_tail_rcu(&ns->dev_link, &old->dev_link);
|
list_add_tail_rcu(&ns->dev_link, &old->dev_link);
|
||||||
}
|
}
|
||||||
|
|
||||||
list_for_each_entry(ctrl, &subsys->ctrls, subsys_entry)
|
nvmet_ns_changed(subsys, ns->nsid);
|
||||||
nvmet_add_async_event(ctrl, NVME_AER_TYPE_NOTICE, 0, 0);
|
|
||||||
|
|
||||||
ns->enabled = true;
|
ns->enabled = true;
|
||||||
ret = 0;
|
ret = 0;
|
||||||
out_unlock:
|
out_unlock:
|
||||||
|
@ -342,7 +375,6 @@ int nvmet_ns_enable(struct nvmet_ns *ns)
|
||||||
void nvmet_ns_disable(struct nvmet_ns *ns)
|
void nvmet_ns_disable(struct nvmet_ns *ns)
|
||||||
{
|
{
|
||||||
struct nvmet_subsys *subsys = ns->subsys;
|
struct nvmet_subsys *subsys = ns->subsys;
|
||||||
struct nvmet_ctrl *ctrl;
|
|
||||||
|
|
||||||
mutex_lock(&subsys->lock);
|
mutex_lock(&subsys->lock);
|
||||||
if (!ns->enabled)
|
if (!ns->enabled)
|
||||||
|
@ -368,9 +400,7 @@ void nvmet_ns_disable(struct nvmet_ns *ns)
|
||||||
percpu_ref_exit(&ns->ref);
|
percpu_ref_exit(&ns->ref);
|
||||||
|
|
||||||
mutex_lock(&subsys->lock);
|
mutex_lock(&subsys->lock);
|
||||||
list_for_each_entry(ctrl, &subsys->ctrls, subsys_entry)
|
nvmet_ns_changed(subsys, ns->nsid);
|
||||||
nvmet_add_async_event(ctrl, NVME_AER_TYPE_NOTICE, 0, 0);
|
|
||||||
|
|
||||||
nvmet_ns_dev_disable(ns);
|
nvmet_ns_dev_disable(ns);
|
||||||
out_unlock:
|
out_unlock:
|
||||||
mutex_unlock(&subsys->lock);
|
mutex_unlock(&subsys->lock);
|
||||||
|
@ -832,11 +862,16 @@ u16 nvmet_alloc_ctrl(const char *subsysnqn, const char *hostnqn,
|
||||||
kref_init(&ctrl->ref);
|
kref_init(&ctrl->ref);
|
||||||
ctrl->subsys = subsys;
|
ctrl->subsys = subsys;
|
||||||
|
|
||||||
|
ctrl->changed_ns_list = kmalloc_array(NVME_MAX_CHANGED_NAMESPACES,
|
||||||
|
sizeof(__le32), GFP_KERNEL);
|
||||||
|
if (!ctrl->changed_ns_list)
|
||||||
|
goto out_free_ctrl;
|
||||||
|
|
||||||
ctrl->cqs = kcalloc(subsys->max_qid + 1,
|
ctrl->cqs = kcalloc(subsys->max_qid + 1,
|
||||||
sizeof(struct nvmet_cq *),
|
sizeof(struct nvmet_cq *),
|
||||||
GFP_KERNEL);
|
GFP_KERNEL);
|
||||||
if (!ctrl->cqs)
|
if (!ctrl->cqs)
|
||||||
goto out_free_ctrl;
|
goto out_free_changed_ns_list;
|
||||||
|
|
||||||
ctrl->sqs = kcalloc(subsys->max_qid + 1,
|
ctrl->sqs = kcalloc(subsys->max_qid + 1,
|
||||||
sizeof(struct nvmet_sq *),
|
sizeof(struct nvmet_sq *),
|
||||||
|
@ -894,6 +929,8 @@ u16 nvmet_alloc_ctrl(const char *subsysnqn, const char *hostnqn,
|
||||||
kfree(ctrl->sqs);
|
kfree(ctrl->sqs);
|
||||||
out_free_cqs:
|
out_free_cqs:
|
||||||
kfree(ctrl->cqs);
|
kfree(ctrl->cqs);
|
||||||
|
out_free_changed_ns_list:
|
||||||
|
kfree(ctrl->changed_ns_list);
|
||||||
out_free_ctrl:
|
out_free_ctrl:
|
||||||
kfree(ctrl);
|
kfree(ctrl);
|
||||||
out_put_subsystem:
|
out_put_subsystem:
|
||||||
|
@ -920,6 +957,7 @@ static void nvmet_ctrl_free(struct kref *ref)
|
||||||
|
|
||||||
kfree(ctrl->sqs);
|
kfree(ctrl->sqs);
|
||||||
kfree(ctrl->cqs);
|
kfree(ctrl->cqs);
|
||||||
|
kfree(ctrl->changed_ns_list);
|
||||||
kfree(ctrl);
|
kfree(ctrl);
|
||||||
|
|
||||||
nvmet_subsys_put(subsys);
|
nvmet_subsys_put(subsys);
|
||||||
|
|
|
@ -135,6 +135,9 @@ struct nvmet_ctrl {
|
||||||
|
|
||||||
const struct nvmet_fabrics_ops *ops;
|
const struct nvmet_fabrics_ops *ops;
|
||||||
|
|
||||||
|
__le32 *changed_ns_list;
|
||||||
|
u32 nr_changed_ns;
|
||||||
|
|
||||||
char subsysnqn[NVMF_NQN_FIELD_LEN];
|
char subsysnqn[NVMF_NQN_FIELD_LEN];
|
||||||
char hostnqn[NVMF_NQN_FIELD_LEN];
|
char hostnqn[NVMF_NQN_FIELD_LEN];
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue