From: NeilBrown cifs 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_trylock(). As d_alloc_trylock() includes a try_lookup we don't need both. Rearrange the code so we can choose either a try_lookup or d_alloc_trylock. Signed-off-by: NeilBrown --- fs/smb/client/readdir.c | 50 ++++++++++++++++++++--------------------- 1 file changed, 24 insertions(+), 26 deletions(-) diff --git a/fs/smb/client/readdir.c b/fs/smb/client/readdir.c index 32a75afca8f5..19d0c77046ab 100644 --- a/fs/smb/client/readdir.c +++ b/fs/smb/client/readdir.c @@ -77,36 +77,34 @@ cifs_prime_dcache(struct dentry *parent, struct qstr *name, cifs_dbg(FYI, "%s: for %s\n", __func__, name->name); - dentry = try_lookup_noperm(name, parent); - if (!dentry) { - /* - * If we know that the inode will need to be revalidated - * immediately, then don't create a new dentry for it. - * We'll end up doing an on the wire call either way and - * this spares us an invalidation. - */ -retry: - if (posix) { - switch (fattr->cf_mode & S_IFMT) { - case S_IFLNK: - case S_IFBLK: - case S_IFCHR: - reparse_need_reval = true; - break; - default: - break; - } - } else if (fattr->cf_cifsattrs & ATTR_REPARSE_POINT) { + /* + * If we know that the inode will need to be revalidated + * immediately, then don't create a new dentry for it. + * We'll end up doing an on the wire call either way and + * this spares us an invalidation. + */ + if (posix) { + switch (fattr->cf_mode & S_IFMT) { + case S_IFLNK: + case S_IFBLK: + case S_IFCHR: reparse_need_reval = true; + break; + default: + break; } + } else if (fattr->cf_cifsattrs & ATTR_REPARSE_POINT) { + reparse_need_reval = true; + } - if (reparse_need_reval || - (fattr->cf_flags & CIFS_FATTR_NEED_REVAL)) - return; +retry: + if (reparse_need_reval || + (fattr->cf_flags & CIFS_FATTR_NEED_REVAL)) + dentry = try_lookup_noperm(name, parent); + else + dentry = d_alloc_trylock(parent, name); - dentry = d_alloc_parallel(parent, name); - } - if (IS_ERR(dentry)) + if (!dentry || IS_ERR(dentry)) return; if (!d_in_lookup(dentry)) { inode = d_inode(dentry); -- 2.50.0.107.gf914562f5916.dirty