diff options
Diffstat (limited to 'drivers/nvme/target/core.c')
| -rw-r--r-- | drivers/nvme/target/core.c | 54 |
1 files changed, 37 insertions, 17 deletions
diff --git a/drivers/nvme/target/core.c b/drivers/nvme/target/core.c index 43871a8f56ca..8353950f346f 100644 --- a/drivers/nvme/target/core.c +++ b/drivers/nvme/target/core.c @@ -446,20 +446,27 @@ u16 nvmet_req_find_ns(struct nvmet_req *req) { u32 nsid = le32_to_cpu(req->cmd->common.nsid); struct nvmet_subsys *subsys = nvmet_req_subsys(req); + u16 status = NVME_SC_SUCCESS; + rcu_read_lock(); req->ns = xa_load(&subsys->namespaces, nsid); - if (unlikely(!req->ns || !req->ns->enabled)) { + if (unlikely(!req->ns) || + !test_bit(NVMET_NS_IO_LIVE, &req->ns->flags) || + !percpu_ref_tryget_live_rcu(&req->ns->ref)) { req->error_loc = offsetof(struct nvme_common_command, nsid); - if (!req->ns) /* ns doesn't exist! */ - return NVME_SC_INVALID_NS | NVME_STATUS_DNR; + if (!req->ns) { /* ns doesn't exist! */ + status = NVME_SC_INVALID_NS | NVME_STATUS_DNR; + goto unlock; + } /* ns exists but it's disabled */ req->ns = NULL; - return NVME_SC_INTERNAL_PATH_ERROR; + status = NVME_SC_INTERNAL_PATH_ERROR; } +unlock: + rcu_read_unlock(); - percpu_ref_get(&req->ns->ref); - return NVME_SC_SUCCESS; + return status; } static void nvmet_destroy_namespace(struct percpu_ref *ref) @@ -623,6 +630,7 @@ int nvmet_ns_enable(struct nvmet_ns *ns) ns->enabled = true; xa_set_mark(&subsys->namespaces, ns->nsid, NVMET_NS_ENABLED); nvmet_debugfs_ns_setup(ns); + set_bit(NVMET_NS_IO_LIVE, &ns->flags); ret = 0; out_unlock: mutex_unlock(&subsys->lock); @@ -643,11 +651,11 @@ void nvmet_ns_disable(struct nvmet_ns *ns) struct nvmet_subsys *subsys = ns->subsys; struct nvmet_ctrl *ctrl; + if (!test_and_clear_bit(NVMET_NS_IO_LIVE, &ns->flags)) + return; + mutex_lock(&subsys->lock); - if (!ns->enabled) - goto out_unlock; - ns->enabled = false; xa_clear_mark(&subsys->namespaces, ns->nsid, NVMET_NS_ENABLED); nvmet_debugfs_ns_free(ns); @@ -675,7 +683,7 @@ void nvmet_ns_disable(struct nvmet_ns *ns) mutex_lock(&subsys->lock); nvmet_ns_changed(subsys, ns->nsid); nvmet_ns_dev_disable(ns); -out_unlock: + ns->enabled = false; mutex_unlock(&subsys->lock); } @@ -811,6 +819,8 @@ static void __nvmet_req_complete(struct nvmet_req *req, u16 status) nvmet_pr_put_ns_pc_ref(pc_ref); if (ns) nvmet_put_namespace(ns); + + nvmet_put_passthru_ref(req); } void nvmet_req_complete(struct nvmet_req *req, u16 status) @@ -1187,6 +1197,7 @@ bool nvmet_req_init(struct nvmet_req *req, struct nvmet_sq *sq, req->error_loc = NVMET_NO_ERROR_LOC; req->error_slba = 0; req->pc_ref = NULL; + req->p.ref_held = false; /* no support for fused commands yet */ if (unlikely(flags & (NVME_CMD_FUSE_FIRST | NVME_CMD_FUSE_SECOND))) { @@ -1227,7 +1238,7 @@ bool nvmet_req_init(struct nvmet_req *req, struct nvmet_sq *sq, goto fail; } - if (sq->ctrl) + if (sq->ctrl && sq->ctrl->tbkas) sq->ctrl->reset_tbkas = true; return true; @@ -1317,7 +1328,7 @@ static int nvmet_req_alloc_p2pmem_sgls(struct pci_dev *p2p_dev, return 0; out_free_sg: - pci_p2pmem_free_sgl(req->p2p_dev, req->sg); + pci_p2pmem_free_sgl(p2p_dev, req->sg); out_err: return -ENOMEM; } @@ -1637,8 +1648,16 @@ struct nvmet_ctrl *nvmet_alloc_ctrl(struct nvmet_alloc_ctrl_args *args) #ifdef CONFIG_NVME_TARGET_PASSTHRU /* By default, set loop targets to clear IDS by default */ - if (ctrl->port->disc_addr.trtype == NVMF_TRTYPE_LOOP) - subsys->clear_ids = 1; + if (ctrl->port->disc_addr.trtype == NVMF_TRTYPE_LOOP) { + mutex_lock(&subsys->lock); + subsys->passthru = nvmet_subsys_passthru(subsys); + if (!subsys->passthru) { + mutex_unlock(&subsys->lock); + goto out_free_ctrl; + } + subsys->passthru->clear_ids = 1; + mutex_unlock(&subsys->lock); + } #endif INIT_WORK(&ctrl->async_event_work, nvmet_async_event_work); @@ -1648,6 +1667,8 @@ struct nvmet_ctrl *nvmet_alloc_ctrl(struct nvmet_alloc_ctrl_args *args) INIT_DELAYED_WORK(&ctrl->ka_work, nvmet_keep_alive_timer); memcpy(ctrl->hostnqn, args->hostnqn, NVMF_NQN_SIZE); + if (args->hostid) + uuid_copy(&ctrl->hostid, args->hostid); kref_init(&ctrl->ref); ctrl->subsys = subsys; @@ -1677,6 +1698,7 @@ struct nvmet_ctrl *nvmet_alloc_ctrl(struct nvmet_alloc_ctrl_args *args) mutex_lock(&subsys->lock); ctrl->max_qid = subsys->max_qid; + ctrl->tbkas = subsys->tbkas; ctrl->sqs = kzalloc_objs(struct nvmet_sq *, ctrl->max_qid + 1); if (!ctrl->sqs) @@ -1706,9 +1728,6 @@ struct nvmet_ctrl *nvmet_alloc_ctrl(struct nvmet_alloc_ctrl_args *args) nvmet_start_keep_alive_timer(ctrl); - if (args->hostid) - uuid_copy(&ctrl->hostid, args->hostid); - dhchap_status = nvmet_setup_auth(ctrl, args->sq, false); if (dhchap_status) { pr_err("Failed to setup authentication, dhchap status %u\n", @@ -1865,6 +1884,7 @@ struct nvmet_subsys *nvmet_subsys_alloc(const char *subsysnqn, } subsys->ieee_oui = 0; + subsys->tbkas = true; subsys->firmware_rev = kstrndup(UTS_RELEASE, NVMET_FR_MAX_SIZE, GFP_KERNEL); if (!subsys->firmware_rev) { |
