aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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);