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
3 changed files with 76 additions and 9 deletions
|
@ -126,6 +126,29 @@ static void nvmet_execute_get_log_page_smart(struct nvmet_req *req)
|
|||
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)
|
||||
{
|
||||
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;
|
||||
return 0;
|
||||
case NVME_LOG_CHANGED_NS:
|
||||
req->execute = nvmet_execute_get_log_changed_ns;
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
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);
|
||||
}
|
||||
|
||||
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 ret = 0;
|
||||
|
@ -287,7 +323,6 @@ static void nvmet_ns_dev_disable(struct nvmet_ns *ns)
|
|||
int nvmet_ns_enable(struct nvmet_ns *ns)
|
||||
{
|
||||
struct nvmet_subsys *subsys = ns->subsys;
|
||||
struct nvmet_ctrl *ctrl;
|
||||
int ret = 0;
|
||||
|
||||
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_for_each_entry(ctrl, &subsys->ctrls, subsys_entry)
|
||||
nvmet_add_async_event(ctrl, NVME_AER_TYPE_NOTICE, 0, 0);
|
||||
|
||||
nvmet_ns_changed(subsys, ns->nsid);
|
||||
ns->enabled = true;
|
||||
ret = 0;
|
||||
out_unlock:
|
||||
|
@ -342,7 +375,6 @@ int nvmet_ns_enable(struct nvmet_ns *ns)
|
|||
void nvmet_ns_disable(struct nvmet_ns *ns)
|
||||
{
|
||||
struct nvmet_subsys *subsys = ns->subsys;
|
||||
struct nvmet_ctrl *ctrl;
|
||||
|
||||
mutex_lock(&subsys->lock);
|
||||
if (!ns->enabled)
|
||||
|
@ -368,9 +400,7 @@ void nvmet_ns_disable(struct nvmet_ns *ns)
|
|||
percpu_ref_exit(&ns->ref);
|
||||
|
||||
mutex_lock(&subsys->lock);
|
||||
list_for_each_entry(ctrl, &subsys->ctrls, subsys_entry)
|
||||
nvmet_add_async_event(ctrl, NVME_AER_TYPE_NOTICE, 0, 0);
|
||||
|
||||
nvmet_ns_changed(subsys, ns->nsid);
|
||||
nvmet_ns_dev_disable(ns);
|
||||
out_unlock:
|
||||
mutex_unlock(&subsys->lock);
|
||||
|
@ -832,11 +862,16 @@ u16 nvmet_alloc_ctrl(const char *subsysnqn, const char *hostnqn,
|
|||
kref_init(&ctrl->ref);
|
||||
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,
|
||||
sizeof(struct nvmet_cq *),
|
||||
GFP_KERNEL);
|
||||
if (!ctrl->cqs)
|
||||
goto out_free_ctrl;
|
||||
goto out_free_changed_ns_list;
|
||||
|
||||
ctrl->sqs = kcalloc(subsys->max_qid + 1,
|
||||
sizeof(struct nvmet_sq *),
|
||||
|
@ -894,6 +929,8 @@ u16 nvmet_alloc_ctrl(const char *subsysnqn, const char *hostnqn,
|
|||
kfree(ctrl->sqs);
|
||||
out_free_cqs:
|
||||
kfree(ctrl->cqs);
|
||||
out_free_changed_ns_list:
|
||||
kfree(ctrl->changed_ns_list);
|
||||
out_free_ctrl:
|
||||
kfree(ctrl);
|
||||
out_put_subsystem:
|
||||
|
@ -920,6 +957,7 @@ static void nvmet_ctrl_free(struct kref *ref)
|
|||
|
||||
kfree(ctrl->sqs);
|
||||
kfree(ctrl->cqs);
|
||||
kfree(ctrl->changed_ns_list);
|
||||
kfree(ctrl);
|
||||
|
||||
nvmet_subsys_put(subsys);
|
||||
|
|
|
@ -135,6 +135,9 @@ struct nvmet_ctrl {
|
|||
|
||||
const struct nvmet_fabrics_ops *ops;
|
||||
|
||||
__le32 *changed_ns_list;
|
||||
u32 nr_changed_ns;
|
||||
|
||||
char subsysnqn[NVMF_NQN_FIELD_LEN];
|
||||
char hostnqn[NVMF_NQN_FIELD_LEN];
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue