[PATCH v3 08/11] nfs: Don't hold i_lock while walking ->d_children list
From: NeilBrown
Date: Tue Aug 25 2026 - 18:26:58 EST
From: NeilBrown <neil@xxxxxxxxxx>
Instead of taking i_lock in nfs_clear_verifier_delegated(), take it only
when it is actually needed.
This means i_lock isn't held while testing the type S_IFMT of the inode,
but that cannot change so it doesn't matter.
In nfs_clear_verifier_file(), simply take i_lock for the whole function
while enumerating the aliases.
In nfs_clear_verifier_directory(), use d_find_alias() (which takes
i_lock) to find and get the one alias, then dput() it when we are done.
The import result here is that we don't hold any other spinlock when
walking the d_children list.
Signed-off-by: NeilBrown <neil@xxxxxxxxxx>
---
fs/nfs/dir.c | 9 ++++-----
1 file changed, 4 insertions(+), 5 deletions(-)
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c
index 748c8388c4f0..a5f6fa57fa39 100644
--- a/fs/nfs/dir.c
+++ b/fs/nfs/dir.c
@@ -1469,6 +1469,7 @@ static void nfs_clear_verifier_file(struct inode *inode)
struct dentry *alias;
struct inode *dir;
+ guard(spinlock)(&inode->i_lock);
for_each_alias(alias, inode) {
spin_lock(&alias->d_lock);
dir = d_inode_rcu(alias->d_parent);
@@ -1485,10 +1486,9 @@ static void nfs_clear_verifier_directory(struct inode *dir)
struct dentry *dentry;
struct inode *inode;
- if (hlist_empty(&dir->i_dentry))
+ this_parent = d_find_alias(dir);
+ if (!this_parent)
return;
- this_parent =
- hlist_entry(dir->i_dentry.first, struct dentry, d_alias);
spin_lock(&this_parent->d_lock);
nfs_unset_verifier_delegated(&this_parent->d_time);
@@ -1503,6 +1503,7 @@ static void nfs_clear_verifier_directory(struct inode *dir)
nfs_unset_verifier_delegated(&dentry->d_time);
spin_unlock(&dentry->d_lock);
}
+ dput(this_parent);
}
/**
@@ -1519,12 +1520,10 @@ void nfs_clear_verifier_delegated(struct inode *inode)
{
if (!inode)
return;
- spin_lock(&inode->i_lock);
if (S_ISREG(inode->i_mode))
nfs_clear_verifier_file(inode);
else if (S_ISDIR(inode->i_mode))
nfs_clear_verifier_directory(inode);
- spin_unlock(&inode->i_lock);
}
EXPORT_SYMBOL_GPL(nfs_clear_verifier_delegated);
#endif /* IS_ENABLED(CONFIG_NFS_V4) */
--
2.50.0.107.gf914562f5916.dirty