[PATCH v2 07/18] fsnotify: reduce i_lock hold time in fsnotify_set_children_dentry_flags()
NeilBrown <[email protected]>
| Newsgroups | org.kernel.vger.linux-fsdevel,org.kernel.vger.autofs,org.kernel.vger.ceph-devel,org.kernel.vger.linux-kernel,org.kernel.vger.linux-nfs |
|---|---|
| Message-ID | <[email protected]> |
From: NeilBrown <[email protected]> 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 is easily done with d_find_alias(). 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 <[email protected]> --- fs/notify/fsnotify.c | 33 +++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/fs/notify/fsnotify.c b/fs/notify/fsnotify.c index 90a2121fc54a..4a383d4d8a7b 100644 --- a/fs/notify/fsnotify.c +++ b/fs/notify/fsnotify.c @@ -71,27 +71,28 @@ 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 */ + alias = d_find_alias(inode); + + 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); } - spin_unlock(&inode->i_lock); + dput(alias); } /* -- 2.50.0.107.gf914562f5916.dirty