Skip to content

Commit a1147b8

Browse files
trondmyamschuma-ntap
authored andcommitted
NFS: Fix up directory verifier races
In order to avoid having our dentry revalidation race with an update of the directory on the server, we need to store the verifier before the RPC calls to LOOKUP and READDIR. Signed-off-by: Trond Myklebust <[email protected]> Reviewed-by: Benjamin Coddington <[email protected]> Tested-by: Benjamin Coddington <[email protected]> Signed-off-by: Anna Schumaker <[email protected]>
1 parent bb6d3fb commit a1147b8

File tree

1 file changed

+14
-7
lines changed

1 file changed

+14
-7
lines changed

fs/nfs/dir.c

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,7 @@ typedef struct {
155155
loff_t current_index;
156156
decode_dirent_t decode;
157157

158+
unsigned long dir_verifier;
158159
unsigned long timestamp;
159160
unsigned long gencount;
160161
unsigned int cache_entry_index;
@@ -353,6 +354,7 @@ int nfs_readdir_xdr_filler(struct page **pages, nfs_readdir_descriptor_t *desc,
353354
again:
354355
timestamp = jiffies;
355356
gencount = nfs_inc_attr_generation_counter();
357+
desc->dir_verifier = nfs_save_change_attribute(inode);
356358
error = NFS_PROTO(inode)->readdir(file_dentry(file), cred, entry->cookie, pages,
357359
NFS_SERVER(inode)->dtsize, desc->plus);
358360
if (error < 0) {
@@ -455,13 +457,13 @@ void nfs_force_use_readdirplus(struct inode *dir)
455457
}
456458

457459
static
458-
void nfs_prime_dcache(struct dentry *parent, struct nfs_entry *entry)
460+
void nfs_prime_dcache(struct dentry *parent, struct nfs_entry *entry,
461+
unsigned long dir_verifier)
459462
{
460463
struct qstr filename = QSTR_INIT(entry->name, entry->len);
461464
DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wq);
462465
struct dentry *dentry;
463466
struct dentry *alias;
464-
struct inode *dir = d_inode(parent);
465467
struct inode *inode;
466468
int status;
467469

@@ -500,7 +502,7 @@ void nfs_prime_dcache(struct dentry *parent, struct nfs_entry *entry)
500502
if (nfs_same_file(dentry, entry)) {
501503
if (!entry->fh->size)
502504
goto out;
503-
nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
505+
nfs_set_verifier(dentry, dir_verifier);
504506
status = nfs_refresh_inode(d_inode(dentry), entry->fattr);
505507
if (!status)
506508
nfs_setsecurity(d_inode(dentry), entry->fattr, entry->label);
@@ -526,7 +528,7 @@ void nfs_prime_dcache(struct dentry *parent, struct nfs_entry *entry)
526528
dput(dentry);
527529
dentry = alias;
528530
}
529-
nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
531+
nfs_set_verifier(dentry, dir_verifier);
530532
out:
531533
dput(dentry);
532534
}
@@ -564,7 +566,8 @@ int nfs_readdir_page_filler(nfs_readdir_descriptor_t *desc, struct nfs_entry *en
564566
count++;
565567

566568
if (desc->plus)
567-
nfs_prime_dcache(file_dentry(desc->file), entry);
569+
nfs_prime_dcache(file_dentry(desc->file), entry,
570+
desc->dir_verifier);
568571

569572
status = nfs_readdir_add_to_array(entry, page);
570573
if (status != 0)
@@ -1159,6 +1162,7 @@ nfs_lookup_revalidate_dentry(struct inode *dir, struct dentry *dentry,
11591162
struct nfs_fh *fhandle;
11601163
struct nfs_fattr *fattr;
11611164
struct nfs4_label *label;
1165+
unsigned long dir_verifier;
11621166
int ret;
11631167

11641168
ret = -ENOMEM;
@@ -1168,6 +1172,7 @@ nfs_lookup_revalidate_dentry(struct inode *dir, struct dentry *dentry,
11681172
if (fhandle == NULL || fattr == NULL || IS_ERR(label))
11691173
goto out;
11701174

1175+
dir_verifier = nfs_save_change_attribute(dir);
11711176
ret = NFS_PROTO(dir)->lookup(dir, dentry, fhandle, fattr, label);
11721177
if (ret < 0) {
11731178
switch (ret) {
@@ -1188,7 +1193,7 @@ nfs_lookup_revalidate_dentry(struct inode *dir, struct dentry *dentry,
11881193
goto out;
11891194

11901195
nfs_setsecurity(inode, fattr, label);
1191-
nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
1196+
nfs_set_verifier(dentry, dir_verifier);
11921197

11931198
/* set a readdirplus hint that we had a cache miss */
11941199
nfs_force_use_readdirplus(dir);
@@ -1415,6 +1420,7 @@ struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, unsigned in
14151420
struct nfs_fh *fhandle = NULL;
14161421
struct nfs_fattr *fattr = NULL;
14171422
struct nfs4_label *label = NULL;
1423+
unsigned long dir_verifier;
14181424
int error;
14191425

14201426
dfprintk(VFS, "NFS: lookup(%pd2)\n", dentry);
@@ -1440,6 +1446,7 @@ struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, unsigned in
14401446
if (IS_ERR(label))
14411447
goto out;
14421448

1449+
dir_verifier = nfs_save_change_attribute(dir);
14431450
trace_nfs_lookup_enter(dir, dentry, flags);
14441451
error = NFS_PROTO(dir)->lookup(dir, dentry, fhandle, fattr, label);
14451452
if (error == -ENOENT)
@@ -1463,7 +1470,7 @@ struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, unsigned in
14631470
goto out_label;
14641471
dentry = res;
14651472
}
1466-
nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
1473+
nfs_set_verifier(dentry, dir_verifier);
14671474
out_label:
14681475
trace_nfs_lookup_exit(dir, dentry, flags, error);
14691476
nfs4_label_free(label);

0 commit comments

Comments
 (0)