From: NeilBrown <[email protected]> NFS uses the results of readdir to prime the dcache. Using d_alloc_parallel() can block if there is a concurrent lookup. Blocking in that case is pointless as the lookup will add info to the dcache and there is no value in the readdir waiting to see if it should add the info too.
Also this call to d_alloc_parallel() is made while the parent directory is locked. A proposed change to locking will lock the parent later, after d_alloc_parallel(). This means it won't be safe to wait in d_alloc_parallel() while holding the directory lock. So change to use d_alloc_noblock(), and use try_lookup_noperm() rather than full_name_hash and d_lookup. Signed-off-by: NeilBrown <[email protected]> --- fs/nfs/dir.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index ffba4de3df01..4b73ec59bbcc 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c @@ -750,15 +750,14 @@ void nfs_prime_dcache(struct dentry *parent, struct nfs_entry *entry, if (filename.len == 2 && filename.name[1] == '.') return; } - filename.hash = full_name_hash(parent, filename.name, filename.len); - dentry = d_lookup(parent, &filename); + dentry = try_lookup_noperm(&filename, parent); again: - if (!dentry) { - dentry = d_alloc_parallel(parent, &filename); - if (IS_ERR(dentry)) - return; - } + if (!dentry) + dentry = d_alloc_noblock(parent, &filename); + if (IS_ERR(dentry)) + return; + if (!d_in_lookup(dentry)) { /* Is there a mountpoint here? If so, just exit */ if (!nfs_fsid_equal(&NFS_SB(dentry->d_sb)->fsid, -- 2.50.0.107.gf914562f5916.dirty
