aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorOleg Drokin <green@linuxhacker.ru>2016-06-14 23:28:04 -0400
committerJ. Bruce Fields <bfields@redhat.com>2016-06-15 22:03:31 -0400
commitfeb9dad5209280085d5b0c094fa67e7a8d75c81a (patch)
treef7af4bd1e0c206528e71706bd62064fbea7082ad /fs
parent39a9beab5acb83176e8b9a4f0778749a09341f1f (diff)
nfsd: Always lock state exclusively.
It used to be the case that state had an rwlock that was locked for write by downgrades, but for read for upgrades (opens). Well, the problem is if there are two competing opens for the same state, they step on each other toes potentially leading to leaking file descriptors from the state structure, since access mode is a bitmap only set once. Signed-off-by: Oleg Drokin <green@linuxhacker.ru> Cc: stable@vger.kernel.org Signed-off-by: J. Bruce Fields <bfields@redhat.com>
Diffstat (limited to 'fs')
-rw-r--r--fs/nfsd/nfs4state.c40
-rw-r--r--fs/nfsd/state.h2
2 files changed, 21 insertions, 21 deletions
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index f5f82e145018..c927d36d8ac6 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -3502,7 +3502,7 @@ init_open_stateid(struct nfs4_ol_stateid *stp, struct nfs4_file *fp,
3502 stp->st_access_bmap = 0; 3502 stp->st_access_bmap = 0;
3503 stp->st_deny_bmap = 0; 3503 stp->st_deny_bmap = 0;
3504 stp->st_openstp = NULL; 3504 stp->st_openstp = NULL;
3505 init_rwsem(&stp->st_rwsem); 3505 mutex_init(&stp->st_mutex);
3506 list_add(&stp->st_perstateowner, &oo->oo_owner.so_stateids); 3506 list_add(&stp->st_perstateowner, &oo->oo_owner.so_stateids);
3507 list_add(&stp->st_perfile, &fp->fi_stateids); 3507 list_add(&stp->st_perfile, &fp->fi_stateids);
3508 3508
@@ -4335,10 +4335,10 @@ nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nf
4335 */ 4335 */
4336 if (stp) { 4336 if (stp) {
4337 /* Stateid was found, this is an OPEN upgrade */ 4337 /* Stateid was found, this is an OPEN upgrade */
4338 down_read(&stp->st_rwsem); 4338 mutex_lock(&stp->st_mutex);
4339 status = nfs4_upgrade_open(rqstp, fp, current_fh, stp, open); 4339 status = nfs4_upgrade_open(rqstp, fp, current_fh, stp, open);
4340 if (status) { 4340 if (status) {
4341 up_read(&stp->st_rwsem); 4341 mutex_unlock(&stp->st_mutex);
4342 goto out; 4342 goto out;
4343 } 4343 }
4344 } else { 4344 } else {
@@ -4348,19 +4348,19 @@ nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nf
4348 if (swapstp) { 4348 if (swapstp) {
4349 nfs4_put_stid(&stp->st_stid); 4349 nfs4_put_stid(&stp->st_stid);
4350 stp = swapstp; 4350 stp = swapstp;
4351 down_read(&stp->st_rwsem); 4351 mutex_lock(&stp->st_mutex);
4352 status = nfs4_upgrade_open(rqstp, fp, current_fh, 4352 status = nfs4_upgrade_open(rqstp, fp, current_fh,
4353 stp, open); 4353 stp, open);
4354 if (status) { 4354 if (status) {
4355 up_read(&stp->st_rwsem); 4355 mutex_unlock(&stp->st_mutex);
4356 goto out; 4356 goto out;
4357 } 4357 }
4358 goto upgrade_out; 4358 goto upgrade_out;
4359 } 4359 }
4360 down_read(&stp->st_rwsem); 4360 mutex_lock(&stp->st_mutex);
4361 status = nfs4_get_vfs_file(rqstp, fp, current_fh, stp, open); 4361 status = nfs4_get_vfs_file(rqstp, fp, current_fh, stp, open);
4362 if (status) { 4362 if (status) {
4363 up_read(&stp->st_rwsem); 4363 mutex_unlock(&stp->st_mutex);
4364 release_open_stateid(stp); 4364 release_open_stateid(stp);
4365 goto out; 4365 goto out;
4366 } 4366 }
@@ -4372,7 +4372,7 @@ nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nf
4372 } 4372 }
4373upgrade_out: 4373upgrade_out:
4374 nfs4_inc_and_copy_stateid(&open->op_stateid, &stp->st_stid); 4374 nfs4_inc_and_copy_stateid(&open->op_stateid, &stp->st_stid);
4375 up_read(&stp->st_rwsem); 4375 mutex_unlock(&stp->st_mutex);
4376 4376
4377 if (nfsd4_has_session(&resp->cstate)) { 4377 if (nfsd4_has_session(&resp->cstate)) {
4378 if (open->op_deleg_want & NFS4_SHARE_WANT_NO_DELEG) { 4378 if (open->op_deleg_want & NFS4_SHARE_WANT_NO_DELEG) {
@@ -4977,12 +4977,12 @@ static __be32 nfs4_seqid_op_checks(struct nfsd4_compound_state *cstate, stateid_
4977 * revoked delegations are kept only for free_stateid. 4977 * revoked delegations are kept only for free_stateid.
4978 */ 4978 */
4979 return nfserr_bad_stateid; 4979 return nfserr_bad_stateid;
4980 down_write(&stp->st_rwsem); 4980 mutex_lock(&stp->st_mutex);
4981 status = check_stateid_generation(stateid, &stp->st_stid.sc_stateid, nfsd4_has_session(cstate)); 4981 status = check_stateid_generation(stateid, &stp->st_stid.sc_stateid, nfsd4_has_session(cstate));
4982 if (status == nfs_ok) 4982 if (status == nfs_ok)
4983 status = nfs4_check_fh(current_fh, &stp->st_stid); 4983 status = nfs4_check_fh(current_fh, &stp->st_stid);
4984 if (status != nfs_ok) 4984 if (status != nfs_ok)
4985 up_write(&stp->st_rwsem); 4985 mutex_unlock(&stp->st_mutex);
4986 return status; 4986 return status;
4987} 4987}
4988 4988
@@ -5030,7 +5030,7 @@ static __be32 nfs4_preprocess_confirmed_seqid_op(struct nfsd4_compound_state *cs
5030 return status; 5030 return status;
5031 oo = openowner(stp->st_stateowner); 5031 oo = openowner(stp->st_stateowner);
5032 if (!(oo->oo_flags & NFS4_OO_CONFIRMED)) { 5032 if (!(oo->oo_flags & NFS4_OO_CONFIRMED)) {
5033 up_write(&stp->st_rwsem); 5033 mutex_unlock(&stp->st_mutex);
5034 nfs4_put_stid(&stp->st_stid); 5034 nfs4_put_stid(&stp->st_stid);
5035 return nfserr_bad_stateid; 5035 return nfserr_bad_stateid;
5036 } 5036 }
@@ -5062,12 +5062,12 @@ nfsd4_open_confirm(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
5062 oo = openowner(stp->st_stateowner); 5062 oo = openowner(stp->st_stateowner);
5063 status = nfserr_bad_stateid; 5063 status = nfserr_bad_stateid;
5064 if (oo->oo_flags & NFS4_OO_CONFIRMED) { 5064 if (oo->oo_flags & NFS4_OO_CONFIRMED) {
5065 up_write(&stp->st_rwsem); 5065 mutex_unlock(&stp->st_mutex);
5066 goto put_stateid; 5066 goto put_stateid;
5067 } 5067 }
5068 oo->oo_flags |= NFS4_OO_CONFIRMED; 5068 oo->oo_flags |= NFS4_OO_CONFIRMED;
5069 nfs4_inc_and_copy_stateid(&oc->oc_resp_stateid, &stp->st_stid); 5069 nfs4_inc_and_copy_stateid(&oc->oc_resp_stateid, &stp->st_stid);
5070 up_write(&stp->st_rwsem); 5070 mutex_unlock(&stp->st_mutex);
5071 dprintk("NFSD: %s: success, seqid=%d stateid=" STATEID_FMT "\n", 5071 dprintk("NFSD: %s: success, seqid=%d stateid=" STATEID_FMT "\n",
5072 __func__, oc->oc_seqid, STATEID_VAL(&stp->st_stid.sc_stateid)); 5072 __func__, oc->oc_seqid, STATEID_VAL(&stp->st_stid.sc_stateid));
5073 5073
@@ -5143,7 +5143,7 @@ nfsd4_open_downgrade(struct svc_rqst *rqstp,
5143 nfs4_inc_and_copy_stateid(&od->od_stateid, &stp->st_stid); 5143 nfs4_inc_and_copy_stateid(&od->od_stateid, &stp->st_stid);
5144 status = nfs_ok; 5144 status = nfs_ok;
5145put_stateid: 5145put_stateid:
5146 up_write(&stp->st_rwsem); 5146 mutex_unlock(&stp->st_mutex);
5147 nfs4_put_stid(&stp->st_stid); 5147 nfs4_put_stid(&stp->st_stid);
5148out: 5148out:
5149 nfsd4_bump_seqid(cstate, status); 5149 nfsd4_bump_seqid(cstate, status);
@@ -5196,7 +5196,7 @@ nfsd4_close(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
5196 if (status) 5196 if (status)
5197 goto out; 5197 goto out;
5198 nfs4_inc_and_copy_stateid(&close->cl_stateid, &stp->st_stid); 5198 nfs4_inc_and_copy_stateid(&close->cl_stateid, &stp->st_stid);
5199 up_write(&stp->st_rwsem); 5199 mutex_unlock(&stp->st_mutex);
5200 5200
5201 nfsd4_close_open_stateid(stp); 5201 nfsd4_close_open_stateid(stp);
5202 5202
@@ -5422,7 +5422,7 @@ init_lock_stateid(struct nfs4_ol_stateid *stp, struct nfs4_lockowner *lo,
5422 stp->st_access_bmap = 0; 5422 stp->st_access_bmap = 0;
5423 stp->st_deny_bmap = open_stp->st_deny_bmap; 5423 stp->st_deny_bmap = open_stp->st_deny_bmap;
5424 stp->st_openstp = open_stp; 5424 stp->st_openstp = open_stp;
5425 init_rwsem(&stp->st_rwsem); 5425 mutex_init(&stp->st_mutex);
5426 list_add(&stp->st_locks, &open_stp->st_locks); 5426 list_add(&stp->st_locks, &open_stp->st_locks);
5427 list_add(&stp->st_perstateowner, &lo->lo_owner.so_stateids); 5427 list_add(&stp->st_perstateowner, &lo->lo_owner.so_stateids);
5428 spin_lock(&fp->fi_lock); 5428 spin_lock(&fp->fi_lock);
@@ -5591,7 +5591,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
5591 &open_stp, nn); 5591 &open_stp, nn);
5592 if (status) 5592 if (status)
5593 goto out; 5593 goto out;
5594 up_write(&open_stp->st_rwsem); 5594 mutex_unlock(&open_stp->st_mutex);
5595 open_sop = openowner(open_stp->st_stateowner); 5595 open_sop = openowner(open_stp->st_stateowner);
5596 status = nfserr_bad_stateid; 5596 status = nfserr_bad_stateid;
5597 if (!same_clid(&open_sop->oo_owner.so_client->cl_clientid, 5597 if (!same_clid(&open_sop->oo_owner.so_client->cl_clientid,
@@ -5600,7 +5600,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
5600 status = lookup_or_create_lock_state(cstate, open_stp, lock, 5600 status = lookup_or_create_lock_state(cstate, open_stp, lock,
5601 &lock_stp, &new); 5601 &lock_stp, &new);
5602 if (status == nfs_ok) 5602 if (status == nfs_ok)
5603 down_write(&lock_stp->st_rwsem); 5603 mutex_lock(&lock_stp->st_mutex);
5604 } else { 5604 } else {
5605 status = nfs4_preprocess_seqid_op(cstate, 5605 status = nfs4_preprocess_seqid_op(cstate,
5606 lock->lk_old_lock_seqid, 5606 lock->lk_old_lock_seqid,
@@ -5704,7 +5704,7 @@ out:
5704 seqid_mutating_err(ntohl(status))) 5704 seqid_mutating_err(ntohl(status)))
5705 lock_sop->lo_owner.so_seqid++; 5705 lock_sop->lo_owner.so_seqid++;
5706 5706
5707 up_write(&lock_stp->st_rwsem); 5707 mutex_unlock(&lock_stp->st_mutex);
5708 5708
5709 /* 5709 /*
5710 * If this is a new, never-before-used stateid, and we are 5710 * If this is a new, never-before-used stateid, and we are
@@ -5874,7 +5874,7 @@ nfsd4_locku(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
5874fput: 5874fput:
5875 fput(filp); 5875 fput(filp);
5876put_stateid: 5876put_stateid:
5877 up_write(&stp->st_rwsem); 5877 mutex_unlock(&stp->st_mutex);
5878 nfs4_put_stid(&stp->st_stid); 5878 nfs4_put_stid(&stp->st_stid);
5879out: 5879out:
5880 nfsd4_bump_seqid(cstate, status); 5880 nfsd4_bump_seqid(cstate, status);
diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h
index 986e51e5ceac..64053eadeb81 100644
--- a/fs/nfsd/state.h
+++ b/fs/nfsd/state.h
@@ -535,7 +535,7 @@ struct nfs4_ol_stateid {
535 unsigned char st_access_bmap; 535 unsigned char st_access_bmap;
536 unsigned char st_deny_bmap; 536 unsigned char st_deny_bmap;
537 struct nfs4_ol_stateid *st_openstp; 537 struct nfs4_ol_stateid *st_openstp;
538 struct rw_semaphore st_rwsem; 538 struct mutex st_mutex;
539}; 539};
540 540
541static inline struct nfs4_ol_stateid *openlockstateid(struct nfs4_stid *s) 541static inline struct nfs4_ol_stateid *openlockstateid(struct nfs4_stid *s)