diff options
-rw-r--r-- | fs/nfsd/nfs4state.c | 67 |
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 | ||
3576 | static __be32 | ||
3577 | nfsd4_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 */ | ||
3595 | static __be32 | ||
3596 | nfsd4_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 | |||
3607 | static struct nfs4_ol_stateid * | ||
3608 | nfsd4_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 | |||
3574 | static struct nfs4_openowner * | 3622 | static struct nfs4_openowner * |
3575 | alloc_init_open_stateowner(unsigned int strhashval, struct nfsd4_open *open, | 3623 | alloc_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 | ||
3666 | retry: | ||
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); |