Skip to content

Commit 0c8c7c5

Browse files
scottmayhewTrond Myklebust
authored andcommitted
nfs: don't invalidate dentries on transient errors
This is a slight variation on a patch previously proposed by Neil Brown that never got merged. Prior to commit 5ceb9d7 ("NFS: Refactor nfs_lookup_revalidate()"), any error from nfs_lookup_verify_inode() other than -ESTALE would result in nfs_lookup_revalidate() returning that error (-ESTALE is mapped to zero). Since that commit, all errors result in nfs_lookup_revalidate() returning zero, resulting in dentries being invalidated where they previously were not (particularly in the case of -ERESTARTSYS). Fix it by passing the actual error code to nfs_lookup_revalidate_done(), and leaving the decision on whether to map the error code to zero or one to nfs_lookup_revalidate_done(). A simple reproducer is to run the following python code in a subdirectory of an NFS mount (not in the root of the NFS mount): ---8<--- import os import multiprocessing import time if __name__=="__main__": multiprocessing.set_start_method("spawn") count = 0 while True: try: os.getcwd() pool = multiprocessing.Pool(10) pool.close() pool.terminate() count += 1 except Exception as e: print(f"Failed after {count} iterations") print(e) break ---8<--- Prior to commit 5ceb9d7, the above code would run indefinitely. After commit 5ceb9d7, it fails almost immediately with -ENOENT. Signed-off-by: Scott Mayhew <[email protected]> Signed-off-by: Trond Myklebust <[email protected]>
1 parent a527c3b commit 0c8c7c5

File tree

1 file changed

+13
-14
lines changed

1 file changed

+13
-14
lines changed

fs/nfs/dir.c

Lines changed: 13 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1627,7 +1627,16 @@ nfs_lookup_revalidate_done(struct inode *dir, struct dentry *dentry,
16271627
switch (error) {
16281628
case 1:
16291629
break;
1630-
case 0:
1630+
case -ETIMEDOUT:
1631+
if (inode && (IS_ROOT(dentry) ||
1632+
NFS_SERVER(inode)->flags & NFS_MOUNT_SOFTREVAL))
1633+
error = 1;
1634+
break;
1635+
case -ESTALE:
1636+
case -ENOENT:
1637+
error = 0;
1638+
fallthrough;
1639+
default:
16311640
/*
16321641
* We can't d_drop the root of a disconnected tree:
16331642
* its d_hash is on the s_anon list and d_drop() would hide
@@ -1682,18 +1691,8 @@ static int nfs_lookup_revalidate_dentry(struct inode *dir,
16821691

16831692
dir_verifier = nfs_save_change_attribute(dir);
16841693
ret = NFS_PROTO(dir)->lookup(dir, dentry, fhandle, fattr);
1685-
if (ret < 0) {
1686-
switch (ret) {
1687-
case -ESTALE:
1688-
case -ENOENT:
1689-
ret = 0;
1690-
break;
1691-
case -ETIMEDOUT:
1692-
if (NFS_SERVER(inode)->flags & NFS_MOUNT_SOFTREVAL)
1693-
ret = 1;
1694-
}
1694+
if (ret < 0)
16951695
goto out;
1696-
}
16971696

16981697
/* Request help from readdirplus */
16991698
nfs_lookup_advise_force_readdirplus(dir, flags);
@@ -1737,7 +1736,7 @@ nfs_do_lookup_revalidate(struct inode *dir, struct dentry *dentry,
17371736
unsigned int flags)
17381737
{
17391738
struct inode *inode;
1740-
int error;
1739+
int error = 0;
17411740

17421741
nfs_inc_stats(dir, NFSIOS_DENTRYREVALIDATE);
17431742
inode = d_inode(dentry);
@@ -1782,7 +1781,7 @@ nfs_do_lookup_revalidate(struct inode *dir, struct dentry *dentry,
17821781
out_bad:
17831782
if (flags & LOOKUP_RCU)
17841783
return -ECHILD;
1785-
return nfs_lookup_revalidate_done(dir, dentry, inode, 0);
1784+
return nfs_lookup_revalidate_done(dir, dentry, inode, error);
17861785
}
17871786

17881787
static int

0 commit comments

Comments
 (0)