|
@@ -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);
|
|
|
}
|
|
|
|