summaryrefslogtreecommitdiffstats
path: root/fs/nfs
diff options
context:
space:
mode:
authorChuck Lever <chuck.lever@oracle.com>2012-07-11 16:30:05 -0400
committerTrond Myklebust <Trond.Myklebust@netapp.com>2012-07-16 14:48:53 -0400
commiteb64cf964d453f8b559a8c0c2625952dbbcb5838 (patch)
treeb6ac6d9cfdee8d8ae1710d6f2fb25520d7d2a576 /fs/nfs
parent89af2739589365bf0dd2023c6a076b22ccd530f9 (diff)
downloadlinux-stable-eb64cf964d453f8b559a8c0c2625952dbbcb5838.tar.gz
linux-stable-eb64cf964d453f8b559a8c0c2625952dbbcb5838.tar.bz2
linux-stable-eb64cf964d453f8b559a8c0c2625952dbbcb5838.zip
NFS: State reclaim clears OPEN and LOCK state
The "state->flags & flags" test in nfs41_check_expired_stateid() allows the state manager to squelch a TEST_STATEID operation when it is known for sure that a state ID is no longer valid. If the lease was purged, for example, the client already knows that state ID is now defunct. But open recovery is still needed for that inode. To force a call to nfs4_open_expired(), change the default return value for nfs41_check_expired_stateid() to force open recovery, and the default return value for nfs41_check_locks() to force lock recovery, if the requested flags are clear. Fix suggested by Bryan Schumaker. Also, the presence of a delegation state ID must not prevent normal open recovery. The delegation state ID must be cleared if it was revoked, but once cleared I don't think it's presence or absence has any bearing on whether open recovery is still needed. So the logic is adjusted to ignore the TEST_STATEID result for the delegation state ID. Signed-off-by: Chuck Lever <chuck.lever@oracle.com> Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Diffstat (limited to 'fs/nfs')
-rw-r--r--fs/nfs/nfs4proc.c23
1 files changed, 12 insertions, 11 deletions
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index afd61d72837d..d1c1016cd505 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -1758,8 +1758,8 @@ static int nfs4_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *sta
#if defined(CONFIG_NFS_V4_1)
static int nfs41_check_expired_stateid(struct nfs4_state *state, nfs4_stateid *stateid, unsigned int flags)
{
- int status = NFS_OK;
struct nfs_server *server = NFS_SERVER(state->inode);
+ int status = -NFS4ERR_BAD_STATEID;
if (state->flags & flags) {
status = nfs41_test_stateid(server, stateid);
@@ -1774,16 +1774,17 @@ static int nfs41_check_expired_stateid(struct nfs4_state *state, nfs4_stateid *s
static int nfs41_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *state)
{
- int deleg_status, open_status;
int deleg_flags = 1 << NFS_DELEGATED_STATE;
int open_flags = (1 << NFS_O_RDONLY_STATE) | (1 << NFS_O_WRONLY_STATE) | (1 << NFS_O_RDWR_STATE);
+ int status;
- deleg_status = nfs41_check_expired_stateid(state, &state->stateid, deleg_flags);
- open_status = nfs41_check_expired_stateid(state, &state->open_stateid, open_flags);
+ nfs41_check_expired_stateid(state, &state->stateid, deleg_flags);
+ status = nfs41_check_expired_stateid(state, &state->open_stateid,
+ open_flags);
- if ((deleg_status == NFS_OK) && (open_status == NFS_OK))
- return NFS_OK;
- return nfs4_open_expired(sp, state);
+ if (status != NFS_OK)
+ status = nfs4_open_expired(sp, state);
+ return status;
}
#endif
@@ -4690,7 +4691,7 @@ out:
#if defined(CONFIG_NFS_V4_1)
static int nfs41_check_expired_locks(struct nfs4_state *state)
{
- int status, ret = NFS_OK;
+ int status, ret = -NFS4ERR_BAD_STATEID;
struct nfs4_lock_state *lsp;
struct nfs_server *server = NFS_SERVER(state->inode);
@@ -4716,9 +4717,9 @@ static int nfs41_lock_expired(struct nfs4_state *state, struct file_lock *reques
if (test_bit(LK_STATE_IN_USE, &state->flags))
status = nfs41_check_expired_locks(state);
- if (status == NFS_OK)
- return status;
- return nfs4_lock_expired(state, request);
+ if (status != NFS_OK)
+ status = nfs4_lock_expired(state, request);
+ return status;
}
#endif