aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfs/nfs4state.c
diff options
context:
space:
mode:
authorTrond Myklebust <Trond.Myklebust@netapp.com>2013-03-16 20:54:34 -0400
committerTrond Myklebust <Trond.Myklebust@netapp.com>2013-03-25 12:04:10 -0400
commit5521abfdcf4d67c3441d4414f29e1acd7cc43380 (patch)
treed3f2554e5f066bc45fde92f338b46e0910675bd2 /fs/nfs/nfs4state.c
parent9b20614988199fb03580b335a28250922e902098 (diff)
NFSv4: Resend the READ/WRITE RPC call if a stateid change causes an error
Adds logic to ensure that if the server returns a BAD_STATEID, or other state related error, then we check if the stateid has already changed. If it has, then rather than start state recovery, we should just resend the failed RPC call with the new stateid. Allow nfs4_select_rw_stateid to notify that the stateid is unstable by having it return -EWOULDBLOCK if an RPC is underway that might change the stateid. Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Diffstat (limited to 'fs/nfs/nfs4state.c')
-rw-r--r--fs/nfs/nfs4state.c32
1 files changed, 23 insertions, 9 deletions
diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c
index 8db102c7add6..4e95bd72f480 100644
--- a/fs/nfs/nfs4state.c
+++ b/fs/nfs/nfs4state.c
@@ -989,13 +989,14 @@ int nfs4_set_lock_state(struct nfs4_state *state, struct file_lock *fl)
989 return 0; 989 return 0;
990} 990}
991 991
992static bool nfs4_copy_lock_stateid(nfs4_stateid *dst, struct nfs4_state *state, 992static int nfs4_copy_lock_stateid(nfs4_stateid *dst,
993 struct nfs4_state *state,
993 const struct nfs_lockowner *lockowner) 994 const struct nfs_lockowner *lockowner)
994{ 995{
995 struct nfs4_lock_state *lsp; 996 struct nfs4_lock_state *lsp;
996 fl_owner_t fl_owner; 997 fl_owner_t fl_owner;
997 pid_t fl_pid; 998 pid_t fl_pid;
998 bool ret = false; 999 int ret = -ENOENT;
999 1000
1000 1001
1001 if (lockowner == NULL) 1002 if (lockowner == NULL)
@@ -1010,7 +1011,10 @@ static bool nfs4_copy_lock_stateid(nfs4_stateid *dst, struct nfs4_state *state,
1010 lsp = __nfs4_find_lock_state(state, fl_owner, fl_pid, NFS4_ANY_LOCK_TYPE); 1011 lsp = __nfs4_find_lock_state(state, fl_owner, fl_pid, NFS4_ANY_LOCK_TYPE);
1011 if (lsp != NULL && test_bit(NFS_LOCK_INITIALIZED, &lsp->ls_flags) != 0) { 1012 if (lsp != NULL && test_bit(NFS_LOCK_INITIALIZED, &lsp->ls_flags) != 0) {
1012 nfs4_stateid_copy(dst, &lsp->ls_stateid); 1013 nfs4_stateid_copy(dst, &lsp->ls_stateid);
1013 ret = true; 1014 ret = 0;
1015 smp_rmb();
1016 if (!list_empty(&lsp->ls_seqid.list))
1017 ret = -EWOULDBLOCK;
1014 } 1018 }
1015 spin_unlock(&state->state_lock); 1019 spin_unlock(&state->state_lock);
1016 nfs4_put_lock_state(lsp); 1020 nfs4_put_lock_state(lsp);
@@ -1018,28 +1022,38 @@ out:
1018 return ret; 1022 return ret;
1019} 1023}
1020 1024
1021static void nfs4_copy_open_stateid(nfs4_stateid *dst, struct nfs4_state *state) 1025static int nfs4_copy_open_stateid(nfs4_stateid *dst, struct nfs4_state *state)
1022{ 1026{
1027 int ret;
1023 int seq; 1028 int seq;
1024 1029
1025 do { 1030 do {
1026 seq = read_seqbegin(&state->seqlock); 1031 seq = read_seqbegin(&state->seqlock);
1027 nfs4_stateid_copy(dst, &state->stateid); 1032 nfs4_stateid_copy(dst, &state->stateid);
1033 ret = 0;
1034 smp_rmb();
1035 if (!list_empty(&state->owner->so_seqid.list))
1036 ret = -EWOULDBLOCK;
1028 } while (read_seqretry(&state->seqlock, seq)); 1037 } while (read_seqretry(&state->seqlock, seq));
1038 return ret;
1029} 1039}
1030 1040
1031/* 1041/*
1032 * Byte-range lock aware utility to initialize the stateid of read/write 1042 * Byte-range lock aware utility to initialize the stateid of read/write
1033 * requests. 1043 * requests.
1034 */ 1044 */
1035void nfs4_select_rw_stateid(nfs4_stateid *dst, struct nfs4_state *state, 1045int nfs4_select_rw_stateid(nfs4_stateid *dst, struct nfs4_state *state,
1036 fmode_t fmode, const struct nfs_lockowner *lockowner) 1046 fmode_t fmode, const struct nfs_lockowner *lockowner)
1037{ 1047{
1048 int ret = 0;
1038 if (nfs4_copy_delegation_stateid(dst, state->inode, fmode)) 1049 if (nfs4_copy_delegation_stateid(dst, state->inode, fmode))
1039 return; 1050 goto out;
1040 if (nfs4_copy_lock_stateid(dst, state, lockowner)) 1051 ret = nfs4_copy_lock_stateid(dst, state, lockowner);
1041 return; 1052 if (ret != -ENOENT)
1042 nfs4_copy_open_stateid(dst, state); 1053 goto out;
1054 ret = nfs4_copy_open_stateid(dst, state);
1055out:
1056 return ret;
1043} 1057}
1044 1058
1045struct nfs_seqid *nfs_alloc_seqid(struct nfs_seqid_counter *counter, gfp_t gfp_mask) 1059struct nfs_seqid *nfs_alloc_seqid(struct nfs_seqid_counter *counter, gfp_t gfp_mask)