[PATCH v1 04/12] fsnotify: reduce i_lock hold time in fsnotify_set_children_dentry_flags()

From: NeilBrown

Date: Sun Aug 02 2026 - 21:38:23 EST


From: NeilBrown <neil@xxxxxxxxxx>

Rather than hold i_lock across a d_children walk, dget() a reference to
the dentry and drop the i_lock before the walk.

This requires that we dput() which can sleep. Now that no locks are
held across calls to fsnotify_set_children_dentry_flags(), this is safe.

Signed-off-by: NeilBrown <neil@xxxxxxxxxx>
---
fs/notify/fsnotify.c | 35 ++++++++++++++++++++---------------
1 file changed, 20 insertions(+), 15 deletions(-)

diff --git a/fs/notify/fsnotify.c b/fs/notify/fsnotify.c
index 90a2121fc54a..aa94c0fa7686 100644
--- a/fs/notify/fsnotify.c
+++ b/fs/notify/fsnotify.c
@@ -71,27 +71,32 @@ void fsnotify_sb_free(struct super_block *sb)
*/
void fsnotify_set_children_dentry_flags(struct inode *inode)
{
- struct dentry *alias;
+ struct dentry *alias, *child;

if (!S_ISDIR(inode->i_mode))
return;

spin_lock(&inode->i_lock);
- /* run all of the dentries associated with this inode. Since this is a
- * directory, there damn well better only be one item on this list */
- for_each_alias(alias, inode) {
- struct dentry *child;
-
- /* run all of the children of the original inode and fix their
- * d_flags to indicate parental interest (their parent is the
- * original inode) */
- d_for_each_positive_child(child, alias) {
- spin_lock_nested(&child->d_lock, DENTRY_D_LOCK_NESTED);
- child->d_flags |= DCACHE_FSNOTIFY_PARENT_WATCHED;
- spin_unlock(&child->d_lock);
- }
- }
+ /* Find the dentry for inode - there can only be one */
+ for_each_alias(alias, inode)
+ break;
+ dget(alias);
spin_unlock(&inode->i_lock);
+
+ if (!alias)
+ return;
+
+ /*
+ * run all of the children of the original inode and fix their
+ * d_flags to indicate parental interest (their parent is the
+ * original inode)
+ */
+ d_for_each_positive_child(child, alias) {
+ spin_lock_nested(&child->d_lock, DENTRY_D_LOCK_NESTED);
+ child->d_flags |= DCACHE_FSNOTIFY_PARENT_WATCHED;
+ spin_unlock(&child->d_lock);
+ }
+ dput(alias);
}

/*
--
2.50.0.107.gf914562f5916.dirty