Skip to content

Commit 5ceb9d7

Browse files
author
Trond Myklebust
committed
NFS: Refactor nfs_lookup_revalidate()
Refactor the code in nfs_lookup_revalidate() as a stepping stone towards optimising and fixing nfs4_lookup_revalidate(). Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
1 parent be189f7 commit 5ceb9d7

File tree

1 file changed

+126
-96
lines changed

1 file changed

+126
-96
lines changed

fs/nfs/dir.c

Lines changed: 126 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -1072,6 +1072,100 @@ int nfs_neg_need_reval(struct inode *dir, struct dentry *dentry,
10721072
return !nfs_check_verifier(dir, dentry, flags & LOOKUP_RCU);
10731073
}
10741074

1075+
static int
1076+
nfs_lookup_revalidate_done(struct inode *dir, struct dentry *dentry,
1077+
struct inode *inode, int error)
1078+
{
1079+
switch (error) {
1080+
case 1:
1081+
dfprintk(LOOKUPCACHE, "NFS: %s(%pd2) is valid\n",
1082+
__func__, dentry);
1083+
return 1;
1084+
case 0:
1085+
nfs_mark_for_revalidate(dir);
1086+
if (inode && S_ISDIR(inode->i_mode)) {
1087+
/* Purge readdir caches. */
1088+
nfs_zap_caches(inode);
1089+
/*
1090+
* We can't d_drop the root of a disconnected tree:
1091+
* its d_hash is on the s_anon list and d_drop() would hide
1092+
* it from shrink_dcache_for_unmount(), leading to busy
1093+
* inodes on unmount and further oopses.
1094+
*/
1095+
if (IS_ROOT(dentry))
1096+
return 1;
1097+
}
1098+
dfprintk(LOOKUPCACHE, "NFS: %s(%pd2) is invalid\n",
1099+
__func__, dentry);
1100+
return 0;
1101+
}
1102+
dfprintk(LOOKUPCACHE, "NFS: %s(%pd2) lookup returned error %d\n",
1103+
__func__, dentry, error);
1104+
return error;
1105+
}
1106+
1107+
static int
1108+
nfs_lookup_revalidate_negative(struct inode *dir, struct dentry *dentry,
1109+
unsigned int flags)
1110+
{
1111+
int ret = 1;
1112+
if (nfs_neg_need_reval(dir, dentry, flags)) {
1113+
if (flags & LOOKUP_RCU)
1114+
return -ECHILD;
1115+
ret = 0;
1116+
}
1117+
return nfs_lookup_revalidate_done(dir, dentry, NULL, ret);
1118+
}
1119+
1120+
static int
1121+
nfs_lookup_revalidate_delegated(struct inode *dir, struct dentry *dentry,
1122+
struct inode *inode)
1123+
{
1124+
nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
1125+
return nfs_lookup_revalidate_done(dir, dentry, inode, 1);
1126+
}
1127+
1128+
static int
1129+
nfs_lookup_revalidate_dentry(struct inode *dir, struct dentry *dentry,
1130+
struct inode *inode)
1131+
{
1132+
struct nfs_fh *fhandle;
1133+
struct nfs_fattr *fattr;
1134+
struct nfs4_label *label;
1135+
int ret;
1136+
1137+
ret = -ENOMEM;
1138+
fhandle = nfs_alloc_fhandle();
1139+
fattr = nfs_alloc_fattr();
1140+
label = nfs4_label_alloc(NFS_SERVER(inode), GFP_KERNEL);
1141+
if (fhandle == NULL || fattr == NULL || IS_ERR(label))
1142+
goto out;
1143+
1144+
ret = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, fhandle, fattr, label);
1145+
if (ret < 0) {
1146+
if (ret == -ESTALE || ret == -ENOENT)
1147+
ret = 0;
1148+
goto out;
1149+
}
1150+
ret = 0;
1151+
if (nfs_compare_fh(NFS_FH(inode), fhandle))
1152+
goto out;
1153+
if (nfs_refresh_inode(inode, fattr) < 0)
1154+
goto out;
1155+
1156+
nfs_setsecurity(inode, fattr, label);
1157+
nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
1158+
1159+
/* set a readdirplus hint that we had a cache miss */
1160+
nfs_force_use_readdirplus(dir);
1161+
ret = 1;
1162+
out:
1163+
nfs_free_fattr(fattr);
1164+
nfs_free_fhandle(fhandle);
1165+
nfs4_label_free(label);
1166+
return nfs_lookup_revalidate_done(dir, dentry, inode, ret);
1167+
}
1168+
10751169
/*
10761170
* This is called every time the dcache has a lookup hit,
10771171
* and we should check whether we can really trust that
@@ -1083,58 +1177,36 @@ int nfs_neg_need_reval(struct inode *dir, struct dentry *dentry,
10831177
* If the parent directory is seen to have changed, we throw out the
10841178
* cached dentry and do a new lookup.
10851179
*/
1086-
static int nfs_lookup_revalidate(struct dentry *dentry, unsigned int flags)
1180+
static int
1181+
nfs_do_lookup_revalidate(struct inode *dir, struct dentry *dentry,
1182+
unsigned int flags)
10871183
{
1088-
struct inode *dir;
10891184
struct inode *inode;
1090-
struct dentry *parent;
1091-
struct nfs_fh *fhandle = NULL;
1092-
struct nfs_fattr *fattr = NULL;
1093-
struct nfs4_label *label = NULL;
10941185
int error;
10951186

1096-
if (flags & LOOKUP_RCU) {
1097-
parent = READ_ONCE(dentry->d_parent);
1098-
dir = d_inode_rcu(parent);
1099-
if (!dir)
1100-
return -ECHILD;
1101-
} else {
1102-
parent = dget_parent(dentry);
1103-
dir = d_inode(parent);
1104-
}
11051187
nfs_inc_stats(dir, NFSIOS_DENTRYREVALIDATE);
11061188
inode = d_inode(dentry);
11071189

1108-
if (!inode) {
1109-
if (nfs_neg_need_reval(dir, dentry, flags)) {
1110-
if (flags & LOOKUP_RCU)
1111-
return -ECHILD;
1112-
goto out_bad;
1113-
}
1114-
goto out_valid;
1115-
}
1190+
if (!inode)
1191+
return nfs_lookup_revalidate_negative(dir, dentry, flags);
11161192

11171193
if (is_bad_inode(inode)) {
1118-
if (flags & LOOKUP_RCU)
1119-
return -ECHILD;
11201194
dfprintk(LOOKUPCACHE, "%s: %pd2 has dud inode\n",
11211195
__func__, dentry);
11221196
goto out_bad;
11231197
}
11241198

11251199
if (NFS_PROTO(dir)->have_delegation(inode, FMODE_READ))
1126-
goto out_set_verifier;
1200+
return nfs_lookup_revalidate_delegated(dir, dentry, inode);
11271201

11281202
/* Force a full look up iff the parent directory has changed */
11291203
if (!(flags & (LOOKUP_EXCL | LOOKUP_REVAL)) &&
11301204
nfs_check_verifier(dir, dentry, flags & LOOKUP_RCU)) {
11311205
error = nfs_lookup_verify_inode(inode, flags);
11321206
if (error) {
1133-
if (flags & LOOKUP_RCU)
1134-
return -ECHILD;
11351207
if (error == -ESTALE)
1136-
goto out_zap_parent;
1137-
goto out_error;
1208+
nfs_zap_caches(dir);
1209+
goto out_bad;
11381210
}
11391211
nfs_advise_use_readdirplus(dir);
11401212
goto out_valid;
@@ -1146,81 +1218,39 @@ static int nfs_lookup_revalidate(struct dentry *dentry, unsigned int flags)
11461218
if (NFS_STALE(inode))
11471219
goto out_bad;
11481220

1149-
error = -ENOMEM;
1150-
fhandle = nfs_alloc_fhandle();
1151-
fattr = nfs_alloc_fattr();
1152-
if (fhandle == NULL || fattr == NULL)
1153-
goto out_error;
1154-
1155-
label = nfs4_label_alloc(NFS_SERVER(inode), GFP_NOWAIT);
1156-
if (IS_ERR(label))
1157-
goto out_error;
1158-
11591221
trace_nfs_lookup_revalidate_enter(dir, dentry, flags);
1160-
error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, fhandle, fattr, label);
1222+
error = nfs_lookup_revalidate_dentry(dir, dentry, inode);
11611223
trace_nfs_lookup_revalidate_exit(dir, dentry, flags, error);
1162-
if (error == -ESTALE || error == -ENOENT)
1163-
goto out_bad;
1164-
if (error)
1165-
goto out_error;
1166-
if (nfs_compare_fh(NFS_FH(inode), fhandle))
1167-
goto out_bad;
1168-
if ((error = nfs_refresh_inode(inode, fattr)) != 0)
1169-
goto out_bad;
1170-
1171-
nfs_setsecurity(inode, fattr, label);
1172-
1173-
nfs_free_fattr(fattr);
1174-
nfs_free_fhandle(fhandle);
1175-
nfs4_label_free(label);
1224+
return error;
1225+
out_valid:
1226+
return nfs_lookup_revalidate_done(dir, dentry, inode, 1);
1227+
out_bad:
1228+
if (flags & LOOKUP_RCU)
1229+
return -ECHILD;
1230+
return nfs_lookup_revalidate_done(dir, dentry, inode, 0);
1231+
}
11761232

1177-
/* set a readdirplus hint that we had a cache miss */
1178-
nfs_force_use_readdirplus(dir);
1233+
static int
1234+
nfs_lookup_revalidate(struct dentry *dentry, unsigned int flags)
1235+
{
1236+
struct dentry *parent;
1237+
struct inode *dir;
1238+
int ret;
11791239

1180-
out_set_verifier:
1181-
nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
1182-
out_valid:
11831240
if (flags & LOOKUP_RCU) {
1241+
parent = READ_ONCE(dentry->d_parent);
1242+
dir = d_inode_rcu(parent);
1243+
if (!dir)
1244+
return -ECHILD;
1245+
ret = nfs_do_lookup_revalidate(dir, dentry, flags);
11841246
if (parent != READ_ONCE(dentry->d_parent))
11851247
return -ECHILD;
1186-
} else
1248+
} else {
1249+
parent = dget_parent(dentry);
1250+
ret = nfs_do_lookup_revalidate(d_inode(parent), dentry, flags);
11871251
dput(parent);
1188-
dfprintk(LOOKUPCACHE, "NFS: %s(%pd2) is valid\n",
1189-
__func__, dentry);
1190-
return 1;
1191-
out_zap_parent:
1192-
nfs_zap_caches(dir);
1193-
out_bad:
1194-
WARN_ON(flags & LOOKUP_RCU);
1195-
nfs_free_fattr(fattr);
1196-
nfs_free_fhandle(fhandle);
1197-
nfs4_label_free(label);
1198-
nfs_mark_for_revalidate(dir);
1199-
if (inode && S_ISDIR(inode->i_mode)) {
1200-
/* Purge readdir caches. */
1201-
nfs_zap_caches(inode);
1202-
/*
1203-
* We can't d_drop the root of a disconnected tree:
1204-
* its d_hash is on the s_anon list and d_drop() would hide
1205-
* it from shrink_dcache_for_unmount(), leading to busy
1206-
* inodes on unmount and further oopses.
1207-
*/
1208-
if (IS_ROOT(dentry))
1209-
goto out_valid;
12101252
}
1211-
dput(parent);
1212-
dfprintk(LOOKUPCACHE, "NFS: %s(%pd2) is invalid\n",
1213-
__func__, dentry);
1214-
return 0;
1215-
out_error:
1216-
WARN_ON(flags & LOOKUP_RCU);
1217-
nfs_free_fattr(fattr);
1218-
nfs_free_fhandle(fhandle);
1219-
nfs4_label_free(label);
1220-
dput(parent);
1221-
dfprintk(LOOKUPCACHE, "NFS: %s(%pd2) lookup returned error %d\n",
1222-
__func__, dentry, error);
1223-
return error;
1253+
return ret;
12241254
}
12251255

12261256
/*

0 commit comments

Comments
 (0)