aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTrond Myklebust <trond.myklebust@primarydata.com>2017-11-03 08:00:10 -0400
committerJ. Bruce Fields <bfields@redhat.com>2017-11-27 16:45:10 -0500
commit15ca08d3299682dc49bad73251677b2c5017ef08 (patch)
tree7ec15aa6f9733c2692b060d72a507b1e4ac4c470
parent4fbd8d194f06c8a3fd2af1ce560ddb31f7ec8323 (diff)
nfsd: Fix stateid races between OPEN and CLOSE
Open file stateids can linger on the nfs4_file list of stateids even after they have been closed. In order to avoid reusing such a stateid, and confusing the client, we need to recheck the nfs4_stid's type after taking the mutex. Otherwise, we risk reusing an old stateid that was already closed, which will confuse clients that expect new stateids to conform to RFC7530 Sections 9.1.4.2 and 16.2.5 or RFC5661 Sections 8.2.2 and 18.2.4. Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com> Cc: stable@vger.kernel.org Signed-off-by: J. Bruce Fields <bfields@redhat.com>
-rw-r--r--fs/nfsd/nfs4state.c67
1 files changed, 59 insertions, 8 deletions
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index b82817767b9d..ee8fde2dfa92 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -3562,7 +3562,9 @@ nfsd4_find_existing_open(struct nfs4_file *fp, struct nfsd4_open *open)
3562 /* ignore lock owners */ 3562 /* ignore lock owners */
3563 if (local->st_stateowner->so_is_open_owner == 0) 3563 if (local->st_stateowner->so_is_open_owner == 0)
3564 continue; 3564 continue;
3565 if (local->st_stateowner == &oo->oo_owner) { 3565 if (local->st_stateowner != &oo->oo_owner)
3566 continue;
3567 if (local->st_stid.sc_type == NFS4_OPEN_STID) {
3566 ret = local; 3568 ret = local;
3567 refcount_inc(&ret->st_stid.sc_count); 3569 refcount_inc(&ret->st_stid.sc_count);
3568 break; 3570 break;
@@ -3571,6 +3573,52 @@ nfsd4_find_existing_open(struct nfs4_file *fp, struct nfsd4_open *open)
3571 return ret; 3573 return ret;
3572} 3574}
3573 3575
3576static __be32
3577nfsd4_verify_open_stid(struct nfs4_stid *s)
3578{
3579 __be32 ret = nfs_ok;
3580
3581 switch (s->sc_type) {
3582 default:
3583 break;
3584 case NFS4_CLOSED_STID:
3585 case NFS4_CLOSED_DELEG_STID:
3586 ret = nfserr_bad_stateid;
3587 break;
3588 case NFS4_REVOKED_DELEG_STID:
3589 ret = nfserr_deleg_revoked;
3590 }
3591 return ret;
3592}
3593
3594/* Lock the stateid st_mutex, and deal with races with CLOSE */
3595static __be32
3596nfsd4_lock_ol_stateid(struct nfs4_ol_stateid *stp)
3597{
3598 __be32 ret;
3599
3600 mutex_lock(&stp->st_mutex);
3601 ret = nfsd4_verify_open_stid(&stp->st_stid);
3602 if (ret != nfs_ok)
3603 mutex_unlock(&stp->st_mutex);
3604 return ret;
3605}
3606
3607static struct nfs4_ol_stateid *
3608nfsd4_find_and_lock_existing_open(struct nfs4_file *fp, struct nfsd4_open *open)
3609{
3610 struct nfs4_ol_stateid *stp;
3611 for (;;) {
3612 spin_lock(&fp->fi_lock);
3613 stp = nfsd4_find_existing_open(fp, open);
3614 spin_unlock(&fp->fi_lock);
3615 if (!stp || nfsd4_lock_ol_stateid(stp) == nfs_ok)
3616 break;
3617 nfs4_put_stid(&stp->st_stid);
3618 }
3619 return stp;
3620}
3621
3574static struct nfs4_openowner * 3622static struct nfs4_openowner *
3575alloc_init_open_stateowner(unsigned int strhashval, struct nfsd4_open *open, 3623alloc_init_open_stateowner(unsigned int strhashval, struct nfsd4_open *open,
3576 struct nfsd4_compound_state *cstate) 3624 struct nfsd4_compound_state *cstate)
@@ -3615,6 +3663,7 @@ init_open_stateid(struct nfs4_file *fp, struct nfsd4_open *open)
3615 mutex_init(&stp->st_mutex); 3663 mutex_init(&stp->st_mutex);
3616 mutex_lock(&stp->st_mutex); 3664 mutex_lock(&stp->st_mutex);
3617 3665
3666retry:
3618 spin_lock(&oo->oo_owner.so_client->cl_lock); 3667 spin_lock(&oo->oo_owner.so_client->cl_lock);
3619 spin_lock(&fp->fi_lock); 3668 spin_lock(&fp->fi_lock);
3620 3669
@@ -3639,7 +3688,11 @@ out_unlock:
3639 spin_unlock(&fp->fi_lock); 3688 spin_unlock(&fp->fi_lock);
3640 spin_unlock(&oo->oo_owner.so_client->cl_lock); 3689 spin_unlock(&oo->oo_owner.so_client->cl_lock);
3641 if (retstp) { 3690 if (retstp) {
3642 mutex_lock(&retstp->st_mutex); 3691 /* Handle races with CLOSE */
3692 if (nfsd4_lock_ol_stateid(retstp) != nfs_ok) {
3693 nfs4_put_stid(&retstp->st_stid);
3694 goto retry;
3695 }
3643 /* To keep mutex tracking happy */ 3696 /* To keep mutex tracking happy */
3644 mutex_unlock(&stp->st_mutex); 3697 mutex_unlock(&stp->st_mutex);
3645 stp = retstp; 3698 stp = retstp;
@@ -4460,9 +4513,7 @@ nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nf
4460 status = nfs4_check_deleg(cl, open, &dp); 4513 status = nfs4_check_deleg(cl, open, &dp);
4461 if (status) 4514 if (status)
4462 goto out; 4515 goto out;
4463 spin_lock(&fp->fi_lock); 4516 stp = nfsd4_find_and_lock_existing_open(fp, open);
4464 stp = nfsd4_find_existing_open(fp, open);
4465 spin_unlock(&fp->fi_lock);
4466 } else { 4517 } else {
4467 open->op_file = NULL; 4518 open->op_file = NULL;
4468 status = nfserr_bad_stateid; 4519 status = nfserr_bad_stateid;
@@ -4476,7 +4527,6 @@ nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nf
4476 */ 4527 */
4477 if (stp) { 4528 if (stp) {
4478 /* Stateid was found, this is an OPEN upgrade */ 4529 /* Stateid was found, this is an OPEN upgrade */
4479 mutex_lock(&stp->st_mutex);
4480 status = nfs4_upgrade_open(rqstp, fp, current_fh, stp, open); 4530 status = nfs4_upgrade_open(rqstp, fp, current_fh, stp, open);
4481 if (status) { 4531 if (status) {
4482 mutex_unlock(&stp->st_mutex); 4532 mutex_unlock(&stp->st_mutex);
@@ -5367,7 +5417,6 @@ static void nfsd4_close_open_stateid(struct nfs4_ol_stateid *s)
5367 bool unhashed; 5417 bool unhashed;
5368 LIST_HEAD(reaplist); 5418 LIST_HEAD(reaplist);
5369 5419
5370 s->st_stid.sc_type = NFS4_CLOSED_STID;
5371 spin_lock(&clp->cl_lock); 5420 spin_lock(&clp->cl_lock);
5372 unhashed = unhash_open_stateid(s, &reaplist); 5421 unhashed = unhash_open_stateid(s, &reaplist);
5373 5422
@@ -5407,10 +5456,12 @@ nfsd4_close(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
5407 nfsd4_bump_seqid(cstate, status); 5456 nfsd4_bump_seqid(cstate, status);
5408 if (status) 5457 if (status)
5409 goto out; 5458 goto out;
5459
5460 stp->st_stid.sc_type = NFS4_CLOSED_STID;
5410 nfs4_inc_and_copy_stateid(&close->cl_stateid, &stp->st_stid); 5461 nfs4_inc_and_copy_stateid(&close->cl_stateid, &stp->st_stid);
5411 mutex_unlock(&stp->st_mutex);
5412 5462
5413 nfsd4_close_open_stateid(stp); 5463 nfsd4_close_open_stateid(stp);
5464 mutex_unlock(&stp->st_mutex);
5414 5465
5415 /* put reference from nfs4_preprocess_seqid_op */ 5466 /* put reference from nfs4_preprocess_seqid_op */
5416 nfs4_put_stid(&stp->st_stid); 5467 nfs4_put_stid(&stp->st_stid);