summaryrefslogtreecommitdiffstats
path: root/fs/cifs/readdir.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/cifs/readdir.c')
-rw-r--r--fs/cifs/readdir.c55
1 files changed, 29 insertions, 26 deletions
diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c
index 4cfb4d9f88e2..867439c21001 100644
--- a/fs/cifs/readdir.c
+++ b/fs/cifs/readdir.c
@@ -80,18 +80,32 @@ cifs_prime_dcache(struct dentry *parent, struct qstr *name,
struct inode *inode;
struct super_block *sb = parent->d_sb;
struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
+ DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wq);
cifs_dbg(FYI, "%s: for %s\n", __func__, name->name);
dentry = d_hash_and_lookup(parent, name);
+ 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.
+ */
+ if (fattr->cf_flags & CIFS_FATTR_NEED_REVAL)
+ return;
+retry:
+ dentry = d_alloc_parallel(parent, name, &wq);
+ }
if (IS_ERR(dentry))
return;
-
- if (dentry) {
+ if (!d_in_lookup(dentry)) {
inode = d_inode(dentry);
if (inode) {
- if (d_mountpoint(dentry))
- goto out;
+ if (d_mountpoint(dentry)) {
+ dput(dentry);
+ return;
+ }
/*
* If we're generating inode numbers, then we don't
* want to clobber the existing one with the one that
@@ -106,33 +120,22 @@ cifs_prime_dcache(struct dentry *parent, struct qstr *name,
(inode->i_mode & S_IFMT) ==
(fattr->cf_mode & S_IFMT)) {
cifs_fattr_to_inode(inode, fattr);
- goto out;
+ dput(dentry);
+ return;
}
}
d_invalidate(dentry);
dput(dentry);
+ goto retry;
+ } else {
+ inode = cifs_iget(sb, fattr);
+ if (!inode)
+ inode = ERR_PTR(-ENOMEM);
+ alias = d_splice_alias(inode, dentry);
+ d_lookup_done(dentry);
+ if (alias && !IS_ERR(alias))
+ dput(alias);
}
-
- /*
- * 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 (fattr->cf_flags & CIFS_FATTR_NEED_REVAL)
- return;
-
- dentry = d_alloc(parent, name);
- if (!dentry)
- return;
-
- inode = cifs_iget(sb, fattr);
- if (!inode)
- goto out;
-
- alias = d_splice_alias(inode, dentry);
- if (alias && !IS_ERR(alias))
- dput(alias);
-out:
dput(dentry);
}