Skip to content

Commit

Permalink
nvme: synchronize access to ctrl->namespaces
Browse files Browse the repository at this point in the history
Currently traversal and modification of ctrl->namespaces happens completely
unsynchronized, which can be fixed by the addition of a simple mutex.

Note: nvme_dev_ioctl will be handled in the next patch.

Signed-off-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Sagi Grimberg <sagig@mellanox.com>
Acked-by: Keith Busch <keith.busch@intel.com>
Signed-off-by: Jens Axboe <axboe@fb.com>
  • Loading branch information
Christoph Hellwig authored and Jens Axboe committed Jan 12, 2016
1 parent 363c9aa commit 69d3b8a
Show file tree
Hide file tree
Showing 2 changed files with 18 additions and 0 deletions.
17 changes: 17 additions & 0 deletions drivers/nvme/host/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -1034,6 +1034,8 @@ static struct nvme_ns *nvme_find_ns(struct nvme_ctrl *ctrl, unsigned nsid)
{
struct nvme_ns *ns;

lockdep_assert_held(&ctrl->namespaces_mutex);

list_for_each_entry(ns, &ctrl->namespaces, list) {
if (ns->ns_id == nsid)
return ns;
Expand All @@ -1049,6 +1051,8 @@ static void nvme_alloc_ns(struct nvme_ctrl *ctrl, unsigned nsid)
struct gendisk *disk;
int node = dev_to_node(ctrl->dev);

lockdep_assert_held(&ctrl->namespaces_mutex);

ns = kzalloc_node(sizeof(*ns), GFP_KERNEL, node);
if (!ns)
return;
Expand Down Expand Up @@ -1118,6 +1122,8 @@ static void nvme_ns_remove(struct nvme_ns *ns)
bool kill = nvme_io_incapable(ns->ctrl) &&
!blk_queue_dying(ns->queue);

lockdep_assert_held(&ns->ctrl->namespaces_mutex);

if (kill)
blk_set_queue_dying(ns->queue);
if (ns->disk->flags & GENHD_FL_UP) {
Expand Down Expand Up @@ -1188,6 +1194,8 @@ static void __nvme_scan_namespaces(struct nvme_ctrl *ctrl, unsigned nn)
struct nvme_ns *ns, *next;
unsigned i;

lockdep_assert_held(&ctrl->namespaces_mutex);

for (i = 1; i <= nn; i++)
nvme_validate_ns(ctrl, i);

Expand All @@ -1205,6 +1213,7 @@ void nvme_scan_namespaces(struct nvme_ctrl *ctrl)
if (nvme_identify_ctrl(ctrl, &id))
return;

mutex_lock(&ctrl->namespaces_mutex);
nn = le32_to_cpu(id->nn);
if (ctrl->vs >= NVME_VS(1, 1) &&
!(ctrl->quirks & NVME_QUIRK_IDENTIFY_CNS)) {
Expand All @@ -1214,15 +1223,18 @@ void nvme_scan_namespaces(struct nvme_ctrl *ctrl)
__nvme_scan_namespaces(ctrl, le32_to_cpup(&id->nn));
done:
list_sort(NULL, &ctrl->namespaces, ns_cmp);
mutex_unlock(&ctrl->namespaces_mutex);
kfree(id);
}

void nvme_remove_namespaces(struct nvme_ctrl *ctrl)
{
struct nvme_ns *ns, *next;

mutex_lock(&ctrl->namespaces_mutex);
list_for_each_entry_safe(ns, next, &ctrl->namespaces, list)
nvme_ns_remove(ns);
mutex_unlock(&ctrl->namespaces_mutex);
}

static DEFINE_IDA(nvme_instance_ida);
Expand Down Expand Up @@ -1290,6 +1302,7 @@ int nvme_init_ctrl(struct nvme_ctrl *ctrl, struct device *dev,
int ret;

INIT_LIST_HEAD(&ctrl->namespaces);
mutex_init(&ctrl->namespaces_mutex);
kref_init(&ctrl->kref);
ctrl->dev = dev;
ctrl->ops = ops;
Expand Down Expand Up @@ -1332,6 +1345,7 @@ void nvme_freeze_queues(struct nvme_ctrl *ctrl)
{
struct nvme_ns *ns;

mutex_lock(&ctrl->namespaces_mutex);
list_for_each_entry(ns, &ctrl->namespaces, list) {
blk_mq_freeze_queue_start(ns->queue);

Expand All @@ -1342,18 +1356,21 @@ void nvme_freeze_queues(struct nvme_ctrl *ctrl)
blk_mq_cancel_requeue_work(ns->queue);
blk_mq_stop_hw_queues(ns->queue);
}
mutex_unlock(&ctrl->namespaces_mutex);
}

void nvme_unfreeze_queues(struct nvme_ctrl *ctrl)
{
struct nvme_ns *ns;

mutex_lock(&ctrl->namespaces_mutex);
list_for_each_entry(ns, &ctrl->namespaces, list) {
queue_flag_clear_unlocked(QUEUE_FLAG_STOPPED, ns->queue);
blk_mq_unfreeze_queue(ns->queue);
blk_mq_start_stopped_hw_queues(ns->queue, true);
blk_mq_kick_requeue_list(ns->queue);
}
mutex_unlock(&ctrl->namespaces_mutex);
}

int __init nvme_core_init(void)
Expand Down
1 change: 1 addition & 0 deletions drivers/nvme/host/nvme.h
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ struct nvme_ctrl {
int instance;
struct blk_mq_tag_set *tagset;
struct list_head namespaces;
struct mutex namespaces_mutex;
struct device *device; /* char device */
struct list_head node;

Expand Down

0 comments on commit 69d3b8a

Please sign in to comment.