aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorTrond Myklebust <trond.myklebust@primarydata.com>2014-11-12 14:44:49 -0500
committerTrond Myklebust <trond.myklebust@primarydata.com>2014-11-12 17:01:33 -0500
commit0c116cadd94b16b30b1dd90d38b2784d9b39b01a (patch)
tree05de2078e0257bead5b569bf03f6dcaad234760d /fs
parent4dfd4f7af0afd201706ad186352ca423b0f17d4b (diff)
NFSv4.1: nfs41_clear_delegation_stateid shouldn't trust NFS_DELEGATED_STATE
This patch removes the assumption made previously, that we only need to check the delegation stateid when it matches the stateid on a cached open. If we believe that we hold a delegation for this file, then we must assume that its stateid may have been revoked or expired too. If we don't test it then our state recovery process may end up caching open/lock state in a situation where it should not. We therefore rename the function nfs41_clear_delegation_stateid as nfs41_check_delegation_stateid, and change it to always run through the delegation stateid test and recovery process as outlined in RFC5661. http://lkml.kernel.org/r/CAN-5tyHwG=Cn2Q9KsHWadewjpTTy_K26ee+UnSvHvG4192p-Xw@mail.gmail.com Cc: stable@vger.kernel.org Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
Diffstat (limited to 'fs')
-rw-r--r--fs/nfs/nfs4proc.c42
1 files changed, 17 insertions, 25 deletions
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index bdd880bddba4..3b98fe752ef8 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -2132,45 +2132,37 @@ static int nfs40_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *st
2132} 2132}
2133 2133
2134#if defined(CONFIG_NFS_V4_1) 2134#if defined(CONFIG_NFS_V4_1)
2135static void nfs41_clear_delegation_stateid(struct nfs4_state *state) 2135static void nfs41_check_delegation_stateid(struct nfs4_state *state)
2136{ 2136{
2137 struct nfs_server *server = NFS_SERVER(state->inode); 2137 struct nfs_server *server = NFS_SERVER(state->inode);
2138 nfs4_stateid *stateid = &state->stateid; 2138 nfs4_stateid stateid;
2139 struct nfs_delegation *delegation; 2139 struct nfs_delegation *delegation;
2140 struct rpc_cred *cred = NULL; 2140 struct rpc_cred *cred;
2141 int status = -NFS4ERR_BAD_STATEID; 2141 int status;
2142
2143 /* If a state reset has been done, test_stateid is unneeded */
2144 if (test_bit(NFS_DELEGATED_STATE, &state->flags) == 0)
2145 return;
2146 2142
2147 /* Get the delegation credential for use by test/free_stateid */ 2143 /* Get the delegation credential for use by test/free_stateid */
2148 rcu_read_lock(); 2144 rcu_read_lock();
2149 delegation = rcu_dereference(NFS_I(state->inode)->delegation); 2145 delegation = rcu_dereference(NFS_I(state->inode)->delegation);
2150 if (delegation != NULL && 2146 if (delegation == NULL) {
2151 nfs4_stateid_match(&delegation->stateid, stateid)) {
2152 cred = get_rpccred(delegation->cred);
2153 rcu_read_unlock();
2154 status = nfs41_test_stateid(server, stateid, cred);
2155 trace_nfs4_test_delegation_stateid(state, NULL, status);
2156 } else
2157 rcu_read_unlock(); 2147 rcu_read_unlock();
2148 return;
2149 }
2150
2151 nfs4_stateid_copy(&stateid, &delegation->stateid);
2152 cred = get_rpccred(delegation->cred);
2153 rcu_read_unlock();
2154 status = nfs41_test_stateid(server, &stateid, cred);
2155 trace_nfs4_test_delegation_stateid(state, NULL, status);
2158 2156
2159 if (status != NFS_OK) { 2157 if (status != NFS_OK) {
2160 /* Free the stateid unless the server explicitly 2158 /* Free the stateid unless the server explicitly
2161 * informs us the stateid is unrecognized. */ 2159 * informs us the stateid is unrecognized. */
2162 if (status != -NFS4ERR_BAD_STATEID) 2160 if (status != -NFS4ERR_BAD_STATEID)
2163 nfs41_free_stateid(server, stateid, cred); 2161 nfs41_free_stateid(server, &stateid, cred);
2164 nfs_remove_bad_delegation(state->inode); 2162 nfs_finish_clear_delegation_stateid(state);
2165
2166 write_seqlock(&state->seqlock);
2167 nfs4_stateid_copy(&state->stateid, &state->open_stateid);
2168 write_sequnlock(&state->seqlock);
2169 clear_bit(NFS_DELEGATED_STATE, &state->flags);
2170 } 2163 }
2171 2164
2172 if (cred != NULL) 2165 put_rpccred(cred);
2173 put_rpccred(cred);
2174} 2166}
2175 2167
2176/** 2168/**
@@ -2214,7 +2206,7 @@ static int nfs41_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *st
2214{ 2206{
2215 int status; 2207 int status;
2216 2208
2217 nfs41_clear_delegation_stateid(state); 2209 nfs41_check_delegation_stateid(state);
2218 status = nfs41_check_open_stateid(state); 2210 status = nfs41_check_open_stateid(state);
2219 if (status != NFS_OK) 2211 if (status != NFS_OK)
2220 status = nfs4_open_expired(sp, state); 2212 status = nfs4_open_expired(sp, state);