aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorTrond Myklebust <trond.myklebust@fys.uio.no>2005-01-04 21:41:11 +0100
committerTrond Myklebust <trond.myklebust@fys.uio.no>2005-01-04 21:41:11 +0100
commite46e9c893582e0ef43e7e7b187d548252648dd5c (patch)
treef2dc8615e8d9881c8b5a2013c8520b4643b69eff /fs
parenta635179e268fd1d7a09f01a2e644ca25aee884e5 (diff)
downloadhistory-e46e9c893582e0ef43e7e7b187d548252648dd5c.tar.gz
NFSv2/v3/v4: ESTALE should not be a permanent condition on directories.
Although it usually means that someone has deleted a file on the server, the ESTALE error may also indicate that the sysadmin has used exportfs to deny our client access to the server. Most NFS implementations therefore consider it a non-permanent condition, and allow inodes to "recover" when the sysadmin re-enables access. If, however, you want to work with broken servers, like unfsd, that reuse filehandles for new files after the original file gets deleted, then "recovery" is impossible, since it may be that the filehandle now points to a different file. Note that this is broken server behaviour that may happen even without us ever seeing the ESTALE error. In order to minimize (but we can never eliminate entirely) this race condition on unfsd servers, Linux has traditionally made ESTALE a permanent condition on all filehandles except the root filehandle. The problem is that if we apply this strict staleness criterion to directories (particularly so for he current directory), then all processes will need to re-walk the path starting from the mount point, in order to recover from the sysadmin intervention case. As this is not usual on other *NIX implementations, and may in any case be undermined by caching rules etc, this is being seen as a usability problem. This patch makes ESTALE a non-permanent condition on directories, but preserves the current behaviour for non-directories. Signed-off-by: Trond Myklebust <trond.myklebust@fys.uio.no>
Diffstat (limited to 'fs')
-rw-r--r--fs/nfs/inode.c14
1 files changed, 7 insertions, 7 deletions
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
index e2188dd7526ce7..c2706fd0854d70 100644
--- a/fs/nfs/inode.c
+++ b/fs/nfs/inode.c
@@ -605,7 +605,7 @@ nfs_find_actor(struct inode *inode, void *opaque)
return 0;
if (nfs_compare_fh(NFS_FH(inode), fh))
return 0;
- if (is_bad_inode(inode))
+ if (is_bad_inode(inode) || NFS_STALE(inode))
return 0;
return 1;
}
@@ -949,7 +949,7 @@ __nfs_revalidate_inode(struct nfs_server *server, struct inode *inode)
lock_kernel();
if (!inode || is_bad_inode(inode))
goto out_nowait;
- if (NFS_STALE(inode) && inode != inode->i_sb->s_root->d_inode)
+ if (NFS_STALE(inode))
goto out_nowait;
while (NFS_REVALIDATING(inode)) {
@@ -973,9 +973,9 @@ __nfs_revalidate_inode(struct nfs_server *server, struct inode *inode)
inode->i_sb->s_id,
(long long)NFS_FILEID(inode), status);
if (status == -ESTALE) {
- NFS_FLAGS(inode) |= NFS_INO_STALE;
- if (inode != inode->i_sb->s_root->d_inode)
- remove_inode_hash(inode);
+ nfs_zap_caches(inode);
+ if (!S_ISDIR(inode->i_mode))
+ NFS_FLAGS(inode) |= NFS_INO_STALE;
}
goto out;
}
@@ -1014,7 +1014,6 @@ __nfs_revalidate_inode(struct nfs_server *server, struct inode *inode)
inode->i_sb->s_id,
(long long)NFS_FILEID(inode));
- NFS_FLAGS(inode) &= ~NFS_INO_STALE;
out:
NFS_FLAGS(inode) &= ~NFS_INO_REVALIDATING;
wake_up(&nfsi->nfs_i_wait);
@@ -1335,7 +1334,8 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr, unsign
*/
nfs_invalidate_inode(inode);
out_err:
- return -EIO;
+ NFS_FLAGS(inode) |= NFS_INO_STALE;
+ return -ESTALE;
}
/*