lightnvm: remove nested lock conflict with mm
authorMatias Bjørling <m@bjorling.me>
Thu, 7 Jul 2016 07:54:17 +0000 (09:54 +0200)
committerJens Axboe <axboe@fb.com>
Thu, 7 Jul 2016 14:51:52 +0000 (08:51 -0600)
If a media manager tries to initialize it targets upon media manager
initialization, the media manager will need to know which target types
are available in LightNVM. The lists of which managers and target types
are available shares the same lock.

Therefore, on initialization, the nvm_lock is taken by LightNVM core,
which later leads to a deadlock when target types are enumerated by the
media manager.

Add an exclusive lock for target types to resolve this conflict.

Signed-off-by: Matias Bjørling <m@bjorling.me>
Signed-off-by: Jens Axboe <axboe@fb.com>
drivers/lightnvm/core.c

index 8afb04cc4d5ab90f8bea340d7bbab92e34865815..04469e0c84ce2a4dbb9b6f238b414c8a931e2408 100644 (file)
@@ -28,6 +28,7 @@
 #include <linux/sched/sysctl.h>
 
 static LIST_HEAD(nvm_tgt_types);
+static DECLARE_RWSEM(nvm_tgtt_lock);
 static LIST_HEAD(nvm_mgrs);
 static LIST_HEAD(nvm_devices);
 static DECLARE_RWSEM(nvm_lock);
@@ -37,7 +38,7 @@ struct nvm_tgt_type *nvm_find_target_type(const char *name, int lock)
        struct nvm_tgt_type *tmp, *tt = NULL;
 
        if (lock)
-               down_write(&nvm_lock);
+               down_write(&nvm_tgtt_lock);
 
        list_for_each_entry(tmp, &nvm_tgt_types, list)
                if (!strcmp(name, tmp->name)) {
@@ -46,7 +47,7 @@ struct nvm_tgt_type *nvm_find_target_type(const char *name, int lock)
                }
 
        if (lock)
-               up_write(&nvm_lock);
+               up_write(&nvm_tgtt_lock);
        return tt;
 }
 EXPORT_SYMBOL(nvm_find_target_type);
@@ -55,12 +56,12 @@ int nvm_register_tgt_type(struct nvm_tgt_type *tt)
 {
        int ret = 0;
 
-       down_write(&nvm_lock);
+       down_write(&nvm_tgtt_lock);
        if (nvm_find_target_type(tt->name, 0))
                ret = -EEXIST;
        else
                list_add(&tt->list, &nvm_tgt_types);
-       up_write(&nvm_lock);
+       up_write(&nvm_tgtt_lock);
 
        return ret;
 }