aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfsd/state.h
diff options
context:
space:
mode:
authorJeff Layton <jlayton@poochiereds.net>2015-09-17 07:47:08 -0400
committerJ. Bruce Fields <bfields@redhat.com>2015-10-12 17:31:03 -0400
commit35a92fe8770ce54c5eb275cd76128645bea2d200 (patch)
tree3c844e8991d12036688ece6073cd6f2d4cd17b13 /fs/nfsd/state.h
parent3be7f32878e742cf3c17b435c90e198862457706 (diff)
nfsd: serialize state seqid morphing operations
Andrew was seeing a race occur when an OPEN and OPEN_DOWNGRADE were running in parallel. The server would receive the OPEN_DOWNGRADE first and check its seqid, but then an OPEN would race in and bump it. The OPEN_DOWNGRADE would then complete and bump the seqid again. The result was that the OPEN_DOWNGRADE would be applied after the OPEN, even though it should have been rejected since the seqid changed. The only recourse we have here I think is to serialize operations that bump the seqid in a stateid, particularly when we're given a seqid in the call. To address this, we add a new rw_semaphore to the nfs4_ol_stateid struct. We do a down_write prior to checking the seqid after looking up the stateid to ensure that nothing else is going to bump it while we're operating on it. In the case of OPEN, we do a down_read, as the call doesn't contain a seqid. Those can run in parallel -- we just need to serialize them when there is a concurrent OPEN_DOWNGRADE or CLOSE. LOCK and LOCKU however always take the write lock as there is no opportunity for parallelizing those. Reported-and-Tested-by: Andrew W Elble <aweits@rit.edu> Signed-off-by: Jeff Layton <jeff.layton@primarydata.com> Cc: stable@vger.kernel.org Signed-off-by: J. Bruce Fields <bfields@redhat.com>
Diffstat (limited to 'fs/nfsd/state.h')
-rw-r--r--fs/nfsd/state.h19
1 files changed, 10 insertions, 9 deletions
diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h
index 583ffc13cae2..31bde12feefe 100644
--- a/fs/nfsd/state.h
+++ b/fs/nfsd/state.h
@@ -534,15 +534,16 @@ struct nfs4_file {
534 * Better suggestions welcome. 534 * Better suggestions welcome.
535 */ 535 */
536struct nfs4_ol_stateid { 536struct nfs4_ol_stateid {
537 struct nfs4_stid st_stid; /* must be first field */ 537 struct nfs4_stid st_stid;
538 struct list_head st_perfile; 538 struct list_head st_perfile;
539 struct list_head st_perstateowner; 539 struct list_head st_perstateowner;
540 struct list_head st_locks; 540 struct list_head st_locks;
541 struct nfs4_stateowner * st_stateowner; 541 struct nfs4_stateowner *st_stateowner;
542 struct nfs4_clnt_odstate * st_clnt_odstate; 542 struct nfs4_clnt_odstate *st_clnt_odstate;
543 unsigned char st_access_bmap; 543 unsigned char st_access_bmap;
544 unsigned char st_deny_bmap; 544 unsigned char st_deny_bmap;
545 struct nfs4_ol_stateid * st_openstp; 545 struct nfs4_ol_stateid *st_openstp;
546 struct rw_semaphore st_rwsem;
546}; 547};
547 548
548static inline struct nfs4_ol_stateid *openlockstateid(struct nfs4_stid *s) 549static inline struct nfs4_ol_stateid *openlockstateid(struct nfs4_stid *s)