diff options
author | Trond Myklebust <trond.myklebust@fys.uio.no> | 2005-01-04 21:41:11 +0100 |
---|---|---|
committer | Trond Myklebust <trond.myklebust@fys.uio.no> | 2005-01-04 21:41:11 +0100 |
commit | e46e9c893582e0ef43e7e7b187d548252648dd5c (patch) | |
tree | f2dc8615e8d9881c8b5a2013c8520b4643b69eff /fs | |
parent | a635179e268fd1d7a09f01a2e644ca25aee884e5 (diff) | |
download | history-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.c | 14 |
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; } /* |