@@ -108,6 +108,12 @@ int debugfs_file_get(struct dentry *dentry)
kfree(fsd);
fsd = READ_ONCE(dentry->d_fsdata);
}
+#ifdef CONFIG_LOCKDEP
+ fsd->lock_name = kasprintf(GFP_KERNEL, "debugfs:%pd", dentry);
+ lockdep_register_key(&fsd->key);
+ lockdep_init_map(&fsd->lockdep_map, fsd->lock_name ?: "debugfs",
+ &fsd->key, 0);
+#endif
}
/*
@@ -124,6 +130,8 @@ int debugfs_file_get(struct dentry *dentry)
if (!refcount_inc_not_zero(&fsd->active_users))
return -EIO;
+ lock_map_acquire_read(&fsd->lockdep_map);
+
return 0;
}
EXPORT_SYMBOL_GPL(debugfs_file_get);
@@ -141,6 +149,8 @@ void debugfs_file_put(struct dentry *dentry)
{
struct debugfs_fsdata *fsd = READ_ONCE(dentry->d_fsdata);
+ lock_map_release(&fsd->lockdep_map);
+
if (refcount_dec_and_test(&fsd->active_users))
complete(&fsd->active_users_drained);
}
@@ -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);
}
@@ -7,6 +7,7 @@
#ifndef _DEBUGFS_INTERNAL_H_
#define _DEBUGFS_INTERNAL_H_
+#include <linux/lockdep.h>
struct file_operations;
@@ -23,6 +24,11 @@ struct debugfs_fsdata {
struct {
refcount_t active_users;
struct completion active_users_drained;
+#ifdef CONFIG_LOCKDEP
+ struct lockdep_map lockdep_map;
+ struct lock_class_key key;
+ char *lock_name;
+#endif
};
};
};