|
@@ -1088,21 +1088,30 @@ static int nfs_lookup_revalidate(struct dentry *dentry, unsigned int flags)
|
|
|
struct nfs4_label *label = NULL;
|
|
|
int error;
|
|
|
|
|
|
- if (flags & LOOKUP_RCU)
|
|
|
- return -ECHILD;
|
|
|
-
|
|
|
- parent = dget_parent(dentry);
|
|
|
- dir = parent->d_inode;
|
|
|
+ if (flags & LOOKUP_RCU) {
|
|
|
+ parent = rcu_dereference(dentry->d_parent);
|
|
|
+ dir = ACCESS_ONCE(parent->d_inode);
|
|
|
+ if (!dir)
|
|
|
+ return -ECHILD;
|
|
|
+ } else {
|
|
|
+ parent = dget_parent(dentry);
|
|
|
+ dir = parent->d_inode;
|
|
|
+ }
|
|
|
nfs_inc_stats(dir, NFSIOS_DENTRYREVALIDATE);
|
|
|
inode = dentry->d_inode;
|
|
|
|
|
|
if (!inode) {
|
|
|
+ if (flags & LOOKUP_RCU)
|
|
|
+ return -ECHILD;
|
|
|
+
|
|
|
if (nfs_neg_need_reval(dir, dentry, flags))
|
|
|
goto out_bad;
|
|
|
goto out_valid_noent;
|
|
|
}
|
|
|
|
|
|
if (is_bad_inode(inode)) {
|
|
|
+ if (flags & LOOKUP_RCU)
|
|
|
+ return -ECHILD;
|
|
|
dfprintk(LOOKUPCACHE, "%s: %pd2 has dud inode\n",
|
|
|
__func__, dentry);
|
|
|
goto out_bad;
|
|
@@ -1111,6 +1120,9 @@ static int nfs_lookup_revalidate(struct dentry *dentry, unsigned int flags)
|
|
|
if (NFS_PROTO(dir)->have_delegation(inode, FMODE_READ))
|
|
|
goto out_set_verifier;
|
|
|
|
|
|
+ if (flags & LOOKUP_RCU)
|
|
|
+ return -ECHILD;
|
|
|
+
|
|
|
/* Force a full look up iff the parent directory has changed */
|
|
|
if (!nfs_is_exclusive_create(dir, flags) && nfs_check_verifier(dir, dentry)) {
|
|
|
if (nfs_lookup_verify_inode(inode, flags))
|
|
@@ -1153,13 +1165,18 @@ out_set_verifier:
|
|
|
/* Success: notify readdir to use READDIRPLUS */
|
|
|
nfs_advise_use_readdirplus(dir);
|
|
|
out_valid_noent:
|
|
|
- dput(parent);
|
|
|
+ if (flags & LOOKUP_RCU) {
|
|
|
+ if (parent != rcu_dereference(dentry->d_parent))
|
|
|
+ return -ECHILD;
|
|
|
+ } else
|
|
|
+ dput(parent);
|
|
|
dfprintk(LOOKUPCACHE, "NFS: %s(%pd2) is valid\n",
|
|
|
__func__, dentry);
|
|
|
return 1;
|
|
|
out_zap_parent:
|
|
|
nfs_zap_caches(dir);
|
|
|
out_bad:
|
|
|
+ WARN_ON(flags & LOOKUP_RCU);
|
|
|
nfs_free_fattr(fattr);
|
|
|
nfs_free_fhandle(fhandle);
|
|
|
nfs4_label_free(label);
|
|
@@ -1185,6 +1202,7 @@ out_zap_parent:
|
|
|
__func__, dentry);
|
|
|
return 0;
|
|
|
out_error:
|
|
|
+ WARN_ON(flags & LOOKUP_RCU);
|
|
|
nfs_free_fattr(fattr);
|
|
|
nfs_free_fhandle(fhandle);
|
|
|
nfs4_label_free(label);
|
|
@@ -1532,9 +1550,6 @@ static int nfs4_lookup_revalidate(struct dentry *dentry, unsigned int flags)
|
|
|
struct inode *inode;
|
|
|
int ret = 0;
|
|
|
|
|
|
- if (flags & LOOKUP_RCU)
|
|
|
- return -ECHILD;
|
|
|
-
|
|
|
if (!(flags & LOOKUP_OPEN) || (flags & LOOKUP_DIRECTORY))
|
|
|
goto no_open;
|
|
|
if (d_mountpoint(dentry))
|
|
@@ -1551,6 +1566,9 @@ static int nfs4_lookup_revalidate(struct dentry *dentry, unsigned int flags)
|
|
|
struct dentry *parent;
|
|
|
struct inode *dir;
|
|
|
|
|
|
+ if (flags & LOOKUP_RCU)
|
|
|
+ return -ECHILD;
|
|
|
+
|
|
|
parent = dget_parent(dentry);
|
|
|
dir = parent->d_inode;
|
|
|
if (!nfs_neg_need_reval(dir, dentry, flags))
|
|
@@ -2348,9 +2366,6 @@ int nfs_permission(struct inode *inode, int mask)
|
|
|
struct rpc_cred *cred;
|
|
|
int res = 0;
|
|
|
|
|
|
- if (mask & MAY_NOT_BLOCK)
|
|
|
- return -ECHILD;
|
|
|
-
|
|
|
nfs_inc_stats(inode, NFSIOS_VFSACCESS);
|
|
|
|
|
|
if ((mask & (MAY_READ | MAY_WRITE | MAY_EXEC)) == 0)
|
|
@@ -2377,6 +2392,9 @@ force_lookup:
|
|
|
if (!NFS_PROTO(inode)->access)
|
|
|
goto out_notsup;
|
|
|
|
|
|
+ if (mask & MAY_NOT_BLOCK)
|
|
|
+ return -ECHILD;
|
|
|
+
|
|
|
cred = rpc_lookup_cred();
|
|
|
if (!IS_ERR(cred)) {
|
|
|
res = nfs_do_access(inode, cred, mask);
|
|
@@ -2391,6 +2409,9 @@ out:
|
|
|
inode->i_sb->s_id, inode->i_ino, mask, res);
|
|
|
return res;
|
|
|
out_notsup:
|
|
|
+ if (mask & MAY_NOT_BLOCK)
|
|
|
+ return -ECHILD;
|
|
|
+
|
|
|
res = nfs_revalidate_inode(NFS_SERVER(inode), inode);
|
|
|
if (res == 0)
|
|
|
res = generic_permission(inode, mask);
|