]> git.karo-electronics.de Git - linux-beck.git/commitdiff
nvme: fix nvme_ns_remove() deadlock
authorMing Lin <ming.l@ssi.samsung.com>
Mon, 25 Apr 2016 21:20:19 +0000 (14:20 -0700)
committerJens Axboe <axboe@fb.com>
Mon, 2 May 2016 15:16:13 +0000 (09:16 -0600)
On receipt of a namespace attribute changed AER, we acquire the
namespace mutex lock before proceeding to scan and validate the
namespace list. In case of namespace detach/delete command,
nvme_ns_remove function deadlocks trying to acquire the already held
lock.

All callers, except nvme_remove_namespaces(), of nvme_ns_remove()
already held namespaces_mutex. So we can simply fix the deadlock by
not acquiring the mutex in nvme_ns_remove() and acquiring it in
nvme_remove_namespaces().

Reported-by: Sunad Bhandary S <sunad.s@samsung.com>
Signed-off-by: Ming Lin <ming.l@ssi.samsung.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Keith Busch <keith.busch@intel.com>
Reviewed-by: Sagi Grimerg <sagi@grimberg.me>
Signed-off-by: Jens Axboe <axboe@fb.com>
drivers/nvme/host/core.c

index 3428c02324030d83878350f13fdec1cedc980674..2de248bd462b96c1469905d906efa9c6679c5d0b 100644 (file)
@@ -1452,6 +1452,8 @@ static void nvme_alloc_ns(struct nvme_ctrl *ctrl, unsigned nsid)
 
 static void nvme_ns_remove(struct nvme_ns *ns)
 {
+       lockdep_assert_held(&ns->ctrl->namespaces_mutex);
+
        if (test_and_set_bit(NVME_NS_REMOVING, &ns->flags))
                return;
 
@@ -1464,9 +1466,7 @@ static void nvme_ns_remove(struct nvme_ns *ns)
                blk_mq_abort_requeue_list(ns->queue);
                blk_cleanup_queue(ns->queue);
        }
-       mutex_lock(&ns->ctrl->namespaces_mutex);
        list_del_init(&ns->list);
-       mutex_unlock(&ns->ctrl->namespaces_mutex);
        synchronize_rcu();
        nvme_put_ns(ns);
 }
@@ -1580,8 +1580,10 @@ 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);
 }
 EXPORT_SYMBOL_GPL(nvme_remove_namespaces);