aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorNeilBrown <neilb@suse.de>2014-07-13 21:28:20 -0400
committerTrond Myklebust <trond.myklebust@primarydata.com>2014-08-03 17:14:11 -0400
commitd51ac1a8e9b86b2d17d349bb256869cab6522787 (patch)
treeddb2dc1a448c67d512465eaee7c73cfdbbe4bf23 /fs
parent49317a7fdaa462b09b9bb4942b64c3a3316bd564 (diff)
NFS: prepare for RCU-walk support but pushing tests later in code.
nfs_lookup_revalidate, nfs4_lookup_revalidate, and nfs_permission all need to understand and handle RCU-walk for NFS to gain the benefits of RCU-walk for cached information. Currently these functions all immediately return -ECHILD if the relevant flag (LOOKUP_RCU or MAY_NOT_BLOCK) is set. This patch pushes those tests later in the code so that we only abort immediately before we enter rcu-unsafe code. As subsequent patches make that rcu-unsafe code rcu-safe, several of these new tests will disappear. With this patch there are several paths through the code which will no longer return -ECHILD during an RCU-walk. However these are mostly error paths or other uninteresting cases. A noteworthy change in nfs_lookup_revalidate is that we don't take (or put) the reference to ->d_parent when LOOKUP_RCU is set. Rather we rcu_dereference ->d_parent, and check that ->d_inode is not NULL. We also check that ->d_parent hasn't changed after all the tests. In nfs4_lookup_revalidate we simply avoid testing LOOKUP_RCU on the path that only calls nfs_lookup_revalidate() as that function already performs the required test. Signed-off-by: NeilBrown <neilb@suse.de> Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
Diffstat (limited to 'fs')
-rw-r--r--fs/nfs/dir.c45
1 files changed, 33 insertions, 12 deletions
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c
index 0090dae1acd3..ea12e58dfd85 100644
--- a/fs/nfs/dir.c
+++ b/fs/nfs/dir.c
@@ -1088,21 +1088,30 @@ static int nfs_lookup_revalidate(struct dentry *dentry, unsigned int flags)
1088 struct nfs4_label *label = NULL; 1088 struct nfs4_label *label = NULL;
1089 int error; 1089 int error;
1090 1090
1091 if (flags & LOOKUP_RCU) 1091 if (flags & LOOKUP_RCU) {
1092 return -ECHILD; 1092 parent = rcu_dereference(dentry->d_parent);
1093 1093 dir = ACCESS_ONCE(parent->d_inode);
1094 parent = dget_parent(dentry); 1094 if (!dir)
1095 dir = parent->d_inode; 1095 return -ECHILD;
1096 } else {
1097 parent = dget_parent(dentry);
1098 dir = parent->d_inode;
1099 }
1096 nfs_inc_stats(dir, NFSIOS_DENTRYREVALIDATE); 1100 nfs_inc_stats(dir, NFSIOS_DENTRYREVALIDATE);
1097 inode = dentry->d_inode; 1101 inode = dentry->d_inode;
1098 1102
1099 if (!inode) { 1103 if (!inode) {
1104 if (flags & LOOKUP_RCU)
1105 return -ECHILD;
1106
1100 if (nfs_neg_need_reval(dir, dentry, flags)) 1107 if (nfs_neg_need_reval(dir, dentry, flags))
1101 goto out_bad; 1108 goto out_bad;
1102 goto out_valid_noent; 1109 goto out_valid_noent;
1103 } 1110 }
1104 1111
1105 if (is_bad_inode(inode)) { 1112 if (is_bad_inode(inode)) {
1113 if (flags & LOOKUP_RCU)
1114 return -ECHILD;
1106 dfprintk(LOOKUPCACHE, "%s: %pd2 has dud inode\n", 1115 dfprintk(LOOKUPCACHE, "%s: %pd2 has dud inode\n",
1107 __func__, dentry); 1116 __func__, dentry);
1108 goto out_bad; 1117 goto out_bad;
@@ -1111,6 +1120,9 @@ static int nfs_lookup_revalidate(struct dentry *dentry, unsigned int flags)
1111 if (NFS_PROTO(dir)->have_delegation(inode, FMODE_READ)) 1120 if (NFS_PROTO(dir)->have_delegation(inode, FMODE_READ))
1112 goto out_set_verifier; 1121 goto out_set_verifier;
1113 1122
1123 if (flags & LOOKUP_RCU)
1124 return -ECHILD;
1125
1114 /* Force a full look up iff the parent directory has changed */ 1126 /* Force a full look up iff the parent directory has changed */
1115 if (!nfs_is_exclusive_create(dir, flags) && nfs_check_verifier(dir, dentry)) { 1127 if (!nfs_is_exclusive_create(dir, flags) && nfs_check_verifier(dir, dentry)) {
1116 if (nfs_lookup_verify_inode(inode, flags)) 1128 if (nfs_lookup_verify_inode(inode, flags))
@@ -1153,13 +1165,18 @@ out_set_verifier:
1153 /* Success: notify readdir to use READDIRPLUS */ 1165 /* Success: notify readdir to use READDIRPLUS */
1154 nfs_advise_use_readdirplus(dir); 1166 nfs_advise_use_readdirplus(dir);
1155 out_valid_noent: 1167 out_valid_noent:
1156 dput(parent); 1168 if (flags & LOOKUP_RCU) {
1169 if (parent != rcu_dereference(dentry->d_parent))
1170 return -ECHILD;
1171 } else
1172 dput(parent);
1157 dfprintk(LOOKUPCACHE, "NFS: %s(%pd2) is valid\n", 1173 dfprintk(LOOKUPCACHE, "NFS: %s(%pd2) is valid\n",
1158 __func__, dentry); 1174 __func__, dentry);
1159 return 1; 1175 return 1;
1160out_zap_parent: 1176out_zap_parent:
1161 nfs_zap_caches(dir); 1177 nfs_zap_caches(dir);
1162 out_bad: 1178 out_bad:
1179 WARN_ON(flags & LOOKUP_RCU);
1163 nfs_free_fattr(fattr); 1180 nfs_free_fattr(fattr);
1164 nfs_free_fhandle(fhandle); 1181 nfs_free_fhandle(fhandle);
1165 nfs4_label_free(label); 1182 nfs4_label_free(label);
@@ -1185,6 +1202,7 @@ out_zap_parent:
1185 __func__, dentry); 1202 __func__, dentry);
1186 return 0; 1203 return 0;
1187out_error: 1204out_error:
1205 WARN_ON(flags & LOOKUP_RCU);
1188 nfs_free_fattr(fattr); 1206 nfs_free_fattr(fattr);
1189 nfs_free_fhandle(fhandle); 1207 nfs_free_fhandle(fhandle);
1190 nfs4_label_free(label); 1208 nfs4_label_free(label);
@@ -1532,9 +1550,6 @@ static int nfs4_lookup_revalidate(struct dentry *dentry, unsigned int flags)
1532 struct inode *inode; 1550 struct inode *inode;
1533 int ret = 0; 1551 int ret = 0;
1534 1552
1535 if (flags & LOOKUP_RCU)
1536 return -ECHILD;
1537
1538 if (!(flags & LOOKUP_OPEN) || (flags & LOOKUP_DIRECTORY)) 1553 if (!(flags & LOOKUP_OPEN) || (flags & LOOKUP_DIRECTORY))
1539 goto no_open; 1554 goto no_open;
1540 if (d_mountpoint(dentry)) 1555 if (d_mountpoint(dentry))
@@ -1551,6 +1566,9 @@ static int nfs4_lookup_revalidate(struct dentry *dentry, unsigned int flags)
1551 struct dentry *parent; 1566 struct dentry *parent;
1552 struct inode *dir; 1567 struct inode *dir;
1553 1568
1569 if (flags & LOOKUP_RCU)
1570 return -ECHILD;
1571
1554 parent = dget_parent(dentry); 1572 parent = dget_parent(dentry);
1555 dir = parent->d_inode; 1573 dir = parent->d_inode;
1556 if (!nfs_neg_need_reval(dir, dentry, flags)) 1574 if (!nfs_neg_need_reval(dir, dentry, flags))
@@ -2348,9 +2366,6 @@ int nfs_permission(struct inode *inode, int mask)
2348 struct rpc_cred *cred; 2366 struct rpc_cred *cred;
2349 int res = 0; 2367 int res = 0;
2350 2368
2351 if (mask & MAY_NOT_BLOCK)
2352 return -ECHILD;
2353
2354 nfs_inc_stats(inode, NFSIOS_VFSACCESS); 2369 nfs_inc_stats(inode, NFSIOS_VFSACCESS);
2355 2370
2356 if ((mask & (MAY_READ | MAY_WRITE | MAY_EXEC)) == 0) 2371 if ((mask & (MAY_READ | MAY_WRITE | MAY_EXEC)) == 0)
@@ -2377,6 +2392,9 @@ force_lookup:
2377 if (!NFS_PROTO(inode)->access) 2392 if (!NFS_PROTO(inode)->access)
2378 goto out_notsup; 2393 goto out_notsup;
2379 2394
2395 if (mask & MAY_NOT_BLOCK)
2396 return -ECHILD;
2397
2380 cred = rpc_lookup_cred(); 2398 cred = rpc_lookup_cred();
2381 if (!IS_ERR(cred)) { 2399 if (!IS_ERR(cred)) {
2382 res = nfs_do_access(inode, cred, mask); 2400 res = nfs_do_access(inode, cred, mask);
@@ -2391,6 +2409,9 @@ out:
2391 inode->i_sb->s_id, inode->i_ino, mask, res); 2409 inode->i_sb->s_id, inode->i_ino, mask, res);
2392 return res; 2410 return res;
2393out_notsup: 2411out_notsup:
2412 if (mask & MAY_NOT_BLOCK)
2413 return -ECHILD;
2414
2394 res = nfs_revalidate_inode(NFS_SERVER(inode), inode); 2415 res = nfs_revalidate_inode(NFS_SERVER(inode), inode);
2395 if (res == 0) 2416 if (res == 0)
2396 res = generic_permission(inode, mask); 2417 res = generic_permission(inode, mask);