summaryrefslogtreecommitdiffstats
path: root/fs/debugfs/inode.c
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2023-11-24 17:25:25 +0100
committerJohannes Berg <johannes.berg@intel.com>2023-11-27 11:24:50 +0100
commitf4acfcd4deb158b96595250cc332901b282d15b0 (patch)
treebc06b650955d9bbc41bd889f8f497ecb92e1416b /fs/debugfs/inode.c
parent0ed04a1847a10297595ac24dc7d46b35fb35f90a (diff)
downloadlinux-stable-f4acfcd4deb158b96595250cc332901b282d15b0.tar.gz
linux-stable-f4acfcd4deb158b96595250cc332901b282d15b0.tar.bz2
linux-stable-f4acfcd4deb158b96595250cc332901b282d15b0.zip
debugfs: annotate debugfs handlers vs. removal with lockdep
When you take a lock in a debugfs handler but also try to remove the debugfs file under that lock, things can deadlock since the removal has to wait for all users to finish. Add lockdep annotations in debugfs_file_get()/_put() to catch such issues. Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Diffstat (limited to 'fs/debugfs/inode.c')
-rw-r--r--fs/debugfs/inode.c12
1 files changed, 12 insertions, 0 deletions
diff --git a/fs/debugfs/inode.c b/fs/debugfs/inode.c
index dcde4199a625..80f4f000dcc1 100644
--- a/fs/debugfs/inode.c
+++ b/fs/debugfs/inode.c
@@ -241,6 +241,14 @@ static void debugfs_release_dentry(struct dentry *dentry)
if ((unsigned long)fsd & DEBUGFS_FSDATA_IS_REAL_FOPS_BIT)
return;
+ /* check it wasn't a dir (no fsdata) or automount (no real_fops) */
+ if (fsd && fsd->real_fops) {
+#ifdef CONFIG_LOCKDEP
+ lockdep_unregister_key(&fsd->key);
+ kfree(fsd->lock_name);
+#endif
+ }
+
kfree(fsd);
}
@@ -744,6 +752,10 @@ static void __debugfs_file_removed(struct dentry *dentry)
fsd = READ_ONCE(dentry->d_fsdata);
if ((unsigned long)fsd & DEBUGFS_FSDATA_IS_REAL_FOPS_BIT)
return;
+
+ lock_map_acquire(&fsd->lockdep_map);
+ lock_map_release(&fsd->lockdep_map);
+
if (!refcount_dec_and_test(&fsd->active_users))
wait_for_completion(&fsd->active_users_drained);
}