summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjdike <[email protected]>2019-07-17 12:18:24 -0400
committerTony Hutter <[email protected]>2019-09-25 11:27:49 -0700
commit4c98586dafab4518a7eea8db9a19271e99ae3110 (patch)
tree7bf7d681f656322c0771cd387553e6826c54702f
parentceb516ac2f4c2ddffcea8a6d282312dd941d3296 (diff)
Fix lockdep recursive locking false positive in dbuf_destroy
lockdep reports a possible recursive lock in dbuf_destroy. It is true that dbuf_destroy is acquiring the dn_dbufs_mtx on one dnode while holding it on another dnode. However, it is impossible for these to be the same dnode because, among other things,dbuf_destroy checks MUTEX_HELD before acquiring the mutex. This fix defines a class NESTED_SINGLE == 1 and changes that lock to call mutex_enter_nested with a subclass of NESTED_SINGLE. In order to make the userspace code compile, include/sys/zfs_context.h now defines mutex_enter_nested and NESTED_SINGLE. This is the lockdep report: [ 122.950921] ============================================ [ 122.950921] WARNING: possible recursive locking detected [ 122.950921] 4.19.29-4.19.0-debug-d69edad5368c1166 #1 Tainted: G O [ 122.950921] -------------------------------------------- [ 122.950921] dbu_evict/1457 is trying to acquire lock: [ 122.950921] 0000000083e9cbcf (&dn->dn_dbufs_mtx){+.+.}, at: dbuf_destroy+0x3c0/0xdb0 [zfs] [ 122.950921] but task is already holding lock: [ 122.950921] 0000000055523987 (&dn->dn_dbufs_mtx){+.+.}, at: dnode_evict_dbufs+0x90/0x740 [zfs] [ 122.950921] other info that might help us debug this: [ 122.950921] Possible unsafe locking scenario: [ 122.950921] CPU0 [ 122.950921] ---- [ 122.950921] lock(&dn->dn_dbufs_mtx); [ 122.950921] lock(&dn->dn_dbufs_mtx); [ 122.950921] *** DEADLOCK *** [ 122.950921] May be due to missing lock nesting notation [ 122.950921] 1 lock held by dbu_evict/1457: [ 122.950921] #0: 0000000055523987 (&dn->dn_dbufs_mtx){+.+.}, at: dnode_evict_dbufs+0x90/0x740 [zfs] [ 122.950921] stack backtrace: [ 122.950921] CPU: 0 PID: 1457 Comm: dbu_evict Tainted: G O 4.19.29-4.19.0-debug-d69edad5368c1166 #1 [ 122.950921] Hardware name: Supermicro H8SSL-I2/H8SSL-I2, BIOS 080011 03/13/2009 [ 122.950921] Call Trace: [ 122.950921] dump_stack+0x91/0xeb [ 122.950921] __lock_acquire+0x2ca7/0x4f10 [ 122.950921] lock_acquire+0x153/0x330 [ 122.950921] dbuf_destroy+0x3c0/0xdb0 [zfs] [ 122.950921] dbuf_evict_one+0x1cc/0x3d0 [zfs] [ 122.950921] dbuf_rele_and_unlock+0xb84/0xd60 [zfs] [ 122.950921] dnode_evict_dbufs+0x3a6/0x740 [zfs] [ 122.950921] dmu_objset_evict+0x7a/0x500 [zfs] [ 122.950921] dsl_dataset_evict_async+0x70/0x480 [zfs] [ 122.950921] taskq_thread+0x979/0x1480 [spl] [ 122.950921] kthread+0x2e7/0x3e0 [ 122.950921] ret_from_fork+0x27/0x50 Reviewed-by: Tony Hutter <[email protected]> Reviewed-by: Brian Behlendorf <[email protected]> Signed-off-by: Jeff Dike <[email protected]> Closes #8984
-rw-r--r--include/spl/sys/mutex.h2
-rw-r--r--include/sys/zfs_context.h2
-rw-r--r--module/zfs/dbuf.c3
3 files changed, 6 insertions, 1 deletions
diff --git a/include/spl/sys/mutex.h b/include/spl/sys/mutex.h
index ed0cd4932..a61f35c61 100644
--- a/include/spl/sys/mutex.h
+++ b/include/spl/sys/mutex.h
@@ -127,6 +127,8 @@ spl_mutex_lockdep_on_maybe(kmutex_t *mp) \
})
/* END CSTYLED */
+#define NESTED_SINGLE 1
+
#ifdef CONFIG_DEBUG_LOCK_ALLOC
#define mutex_enter_nested(mp, subclass) \
{ \
diff --git a/include/sys/zfs_context.h b/include/sys/zfs_context.h
index e3fa2e61b..598b86a7a 100644
--- a/include/sys/zfs_context.h
+++ b/include/sys/zfs_context.h
@@ -257,6 +257,8 @@ extern void mutex_enter(kmutex_t *mp);
extern void mutex_exit(kmutex_t *mp);
extern int mutex_tryenter(kmutex_t *mp);
+#define NESTED_SINGLE 1
+#define mutex_enter_nested(mp, class) mutex_enter(mp)
/*
* RW locks
*/
diff --git a/module/zfs/dbuf.c b/module/zfs/dbuf.c
index 07e616f6f..94c49b3ef 100644
--- a/module/zfs/dbuf.c
+++ b/module/zfs/dbuf.c
@@ -2591,7 +2591,8 @@ dbuf_destroy(dmu_buf_impl_t *db)
if (db->db_blkid != DMU_BONUS_BLKID) {
boolean_t needlock = !MUTEX_HELD(&dn->dn_dbufs_mtx);
if (needlock)
- mutex_enter(&dn->dn_dbufs_mtx);
+ mutex_enter_nested(&dn->dn_dbufs_mtx,
+ NESTED_SINGLE);
avl_remove(&dn->dn_dbufs, db);
atomic_dec_32(&dn->dn_dbufs_count);
membar_producer();