aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfsd
diff options
context:
space:
mode:
Diffstat (limited to 'fs/nfsd')
-rw-r--r--fs/nfsd/nfs4state.c52
-rw-r--r--fs/nfsd/state.h3
2 files changed, 26 insertions, 29 deletions
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 0198328c0e84..106e8fa63cdf 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -3168,6 +3168,12 @@ grace_disallows_io(struct inode *inode)
3168 return locks_in_grace() && mandatory_lock(inode); 3168 return locks_in_grace() && mandatory_lock(inode);
3169} 3169}
3170 3170
3171/* Returns true iff a is later than b: */
3172static bool stateid_generation_after(stateid_t *a, stateid_t *b)
3173{
3174 return (s32)a->si_generation - (s32)b->si_generation > 0;
3175}
3176
3171static int check_stateid_generation(stateid_t *in, stateid_t *ref, bool has_session) 3177static int check_stateid_generation(stateid_t *in, stateid_t *ref, bool has_session)
3172{ 3178{
3173 /* 3179 /*
@@ -3175,25 +3181,25 @@ static int check_stateid_generation(stateid_t *in, stateid_t *ref, bool has_sess
3175 * when it is zero. 3181 * when it is zero.
3176 */ 3182 */
3177 if (has_session && in->si_generation == 0) 3183 if (has_session && in->si_generation == 0)
3178 goto out; 3184 return nfs_ok;
3185
3186 if (in->si_generation == ref->si_generation)
3187 return nfs_ok;
3179 3188
3180 /* If the client sends us a stateid from the future, it's buggy: */ 3189 /* If the client sends us a stateid from the future, it's buggy: */
3181 if (in->si_generation > ref->si_generation) 3190 if (stateid_generation_after(in, ref))
3182 return nfserr_bad_stateid; 3191 return nfserr_bad_stateid;
3183 /* 3192 /*
3184 * The following, however, can happen. For example, if the 3193 * However, we could see a stateid from the past, even from a
3185 * client sends an open and some IO at the same time, the open 3194 * non-buggy client. For example, if the client sends a lock
3186 * may bump si_generation while the IO is still in flight. 3195 * while some IO is outstanding, the lock may bump si_generation
3187 * Thanks to hard links and renames, the client never knows what 3196 * while the IO is still in flight. The client could avoid that
3188 * file an open will affect. So it could avoid that situation 3197 * situation by waiting for responses on all the IO requests,
3189 * only by serializing all opens and IO from the same open 3198 * but better performance may result in retrying IO that
3190 * owner. To recover from the old_stateid error, the client 3199 * receives an old_stateid error if requests are rarely
3191 * will just have to retry the IO: 3200 * reordered in flight:
3192 */ 3201 */
3193 if (in->si_generation < ref->si_generation) 3202 return nfserr_old_stateid;
3194 return nfserr_old_stateid;
3195out:
3196 return nfs_ok;
3197} 3203}
3198 3204
3199static int is_delegation_stateid(stateid_t *stateid) 3205static int is_delegation_stateid(stateid_t *stateid)
@@ -3353,16 +3359,9 @@ nfsd4_free_stateid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
3353 ret = nfserr_bad_stateid; 3359 ret = nfserr_bad_stateid;
3354 goto out; 3360 goto out;
3355 } 3361 }
3356 if (stateid->si_generation != 0) { 3362 ret = check_stateid_generation(stateid, &stp->st_stateid, 1);
3357 if (stateid->si_generation < stp->st_stateid.si_generation) { 3363 if (ret)
3358 ret = nfserr_old_stateid; 3364 goto out;
3359 goto out;
3360 }
3361 if (stateid->si_generation > stp->st_stateid.si_generation) {
3362 ret = nfserr_bad_stateid;
3363 goto out;
3364 }
3365 }
3366 3365
3367 if (stp->st_type == NFS4_OPEN_STID) { 3366 if (stp->st_type == NFS4_OPEN_STID) {
3368 ret = nfserr_locks_held; 3367 ret = nfserr_locks_held;
@@ -3439,11 +3438,6 @@ nfs4_preprocess_seqid_op(struct nfsd4_compound_state *cstate, u32 seqid,
3439 return nfserr_bad_stateid; 3438 return nfserr_bad_stateid;
3440 } 3439 }
3441 3440
3442 /*
3443 * We now validate the seqid and stateid generation numbers.
3444 * For the moment, we ignore the possibility of
3445 * generation number wraparound.
3446 */
3447 if (!nfsd4_has_session(cstate) && seqid != sop->so_seqid) 3441 if (!nfsd4_has_session(cstate) && seqid != sop->so_seqid)
3448 goto check_replay; 3442 goto check_replay;
3449 3443
diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h
index a06f55bd38b6..c425717715f6 100644
--- a/fs/nfsd/state.h
+++ b/fs/nfsd/state.h
@@ -293,6 +293,9 @@ static inline void
293update_stateid(stateid_t *stateid) 293update_stateid(stateid_t *stateid)
294{ 294{
295 stateid->si_generation++; 295 stateid->si_generation++;
296 /* Wraparound recommendation from 3530bis-13 9.1.3.2: */
297 if (stateid->si_generation == 0)
298 stateid->si_generation = 1;
296} 299}
297 300
298/* A reasonable value for REPLAY_ISIZE was estimated as follows: 301/* A reasonable value for REPLAY_ISIZE was estimated as follows: