MLK-16479 mmc: fix potential dead lock when get mmc host index
authorHaibo Chen <haibo.chen@nxp.com>
Mon, 18 Sep 2017 08:55:52 +0000 (16:55 +0800)
committerNitin Garg <nitin.garg@nxp.com>
Mon, 19 Mar 2018 20:38:34 +0000 (15:38 -0500)
When open some kernel debug options including LOCKDEP, hot plug sd
will meet the following dump message:

[  883.769343] BUG: sleeping function called from invalid context at /home/b29397/work/projects/linux-imx/kernel/locki
ng/mutex.c:620
[  883.781212] in_atomic(): 1, irqs_disabled(): 0, pid: 1497, name: kworker/0:2
[  883.788307] 4 locks held by kworker/0:2/1497:
[  883.792697]  #0:  ("events_freezable"){.+.+.+}, at: [<ffff2000080db228>] process_one_work+0x120/0x3b8
[  883.802021]  #1:  ((&(&host->detect)->work)){+.+.+.}, at: [<ffff2000080db228>] process_one_work+0x120/0x3b8
[  883.811854]  #2:  (&dev->mutex){......}, at: [<ffff200008630b3c>] __device_attach+0x28/0x154
[  883.820388]  #3:  (mmc_blk_lock){+.+...}, at: [<ffff200008962414>] mmc_blk_alloc_req+0x60/0x3f8
[  883.829181] CPU: 0 PID: 1497 Comm: kworker/0:2 Not tainted 4.9.11-03102-gd9ab0a1-dirty #523
[  883.837542] Hardware name: Freescale i.MX8QXP MEK (DT)
[  883.842692] Workqueue: events_freezable mmc_rescan
[  883.847490] Call trace:
[  883.849945] [<ffff200008089234>] dump_backtrace+0x0/0x1e0
[  883.855354] [<ffff200008089428>] show_stack+0x14/0x1c
[  883.860413] [<ffff2000084046f4>] dump_stack+0xb0/0xec
[  883.865468] [<ffff2000080e8540>] ___might_sleep+0x144/0x1e4
[  883.871044] [<ffff2000080e8634>] __might_sleep+0x54/0x88
[  883.876364] [<ffff200008bfc99c>] mutex_lock_nested+0x3c/0x3cc
[  883.882113] [<ffff2000089cd164>] of_alias_get_id+0x34/0x98
[  883.887602] [<ffff20000895258c>] mmc_get_reserved_index+0x1c/0x24
[  883.893702] [<ffff20000896241c>] mmc_blk_alloc_req+0x68/0x3f8
[  883.899450] [<ffff2000089640d0>] mmc_blk_probe+0x74/0x2c0
[  883.904856] [<ffff2000089553b4>] mmc_bus_probe+0x1c/0x24
[  883.910174] [<ffff200008630fe4>] driver_probe_device+0x27c/0x418
[  883.916182] [<ffff200008631360>] __device_attach_driver+0x98/0x130
[  883.922370] [<ffff20000862ed48>] bus_for_each_drv+0x54/0x94
[  883.927947] [<ffff200008630bdc>] __device_attach+0xc8/0x154
[  883.933525] [<ffff200008631540>] device_initial_probe+0x10/0x18
[  883.939450] [<ffff20000862ff98>] bus_probe_device+0x94/0x9c
[  883.945026] [<ffff20000862dd08>] device_add+0x40c/0x58c
[  883.950257] [<ffff20000895589c>] mmc_add_card+0xf0/0x2a4
[  883.955576] [<ffff20000895bb78>] mmc_attach_sd+0x94/0x138
[  883.960975] [<ffff200008955070>] mmc_rescan+0x2d8/0x350
[  883.966208] [<ffff2000080db294>] process_one_work+0x18c/0x3b8
[  883.971959] [<ffff2000080db518>] worker_thread+0x58/0x440
[  883.977362] [<ffff2000080e1f48>] kthread+0xe0/0xf4
[  883.982157] [<ffff200008083680>] ret_from_fork+0x10/0x50

This is caused by commit 6e9e049fac59 ("mmc: Allow setting slot index via
devicetree alias"). Function mmc_get_reserved_index(), ida_simple_get() and
mmc_get_reserved_index() do not need addtional lock protect, these function
already contain the mutex_lock() inside. Only ida_get_new_above() need
required lock. spin_lock() nested with mutex_lock() or spin_lock() may cause
dead lock.
This patch fix the potential dead lock.

Fixes: 6e9e049fac59 ("mmc: Allow setting slot index via devicetree alias")
Reported-by: Peter Chen <peter.chen@nxp.com>
Signed-off-by: Haibo Chen <haibo.chen@nxp.com>
drivers/mmc/core/block.c
drivers/mmc/core/host.c

index f2dd4dd..e5802f6 100644 (file)
@@ -2108,16 +2108,17 @@ again:
        if (!ida_pre_get(&mmc_blk_ida, GFP_KERNEL))
                return ERR_PTR(-ENOMEM);
 
-       spin_lock(&mmc_blk_lock);
        devidx = mmc_get_reserved_index(card->host);
        if (devidx >= 0)
                devidx = ida_simple_get(&mmc_blk_ida, devidx, devidx,
                                        GFP_NOWAIT);
        ret = 0;
-       if (devidx < 0)
+       if (devidx < 0) {
+               spin_lock(&mmc_blk_lock);
                ret = ida_get_new_above(&mmc_blk_ida,
                                        mmc_first_nonreserved_index(), &devidx);
-       spin_unlock(&mmc_blk_lock);
+               spin_unlock(&mmc_blk_lock);
+       }
 
        if (ret == -EAGAIN)
                goto again;
index 8792817..882844c 100644 (file)
@@ -375,9 +375,8 @@ again:
                return NULL;
        }
 
-       spin_lock(&mmc_host_lock);
-
        alias_id = mmc_get_reserved_index(host);
+
        if (alias_id >= 0) {
                min_idx = alias_id;
                max_idx = alias_id + 1;
@@ -386,6 +385,8 @@ again:
                max_idx = 0;
        }
 
+       spin_lock(&mmc_host_lock);
+
        err = ida_get_new_above(&mmc_host_ida, min_idx, &host->index);
        if (!err) {
                if (host->index > max_idx) {