aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfsd/nfs4state.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/nfsd/nfs4state.c')
-rw-r--r--fs/nfsd/nfs4state.c65
1 files changed, 48 insertions, 17 deletions
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 8410ca275db1..a204d7e109d4 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -4903,6 +4903,32 @@ nfsd4_test_stateid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
4903 return nfs_ok; 4903 return nfs_ok;
4904} 4904}
4905 4905
4906static __be32
4907nfsd4_free_lock_stateid(stateid_t *stateid, struct nfs4_stid *s)
4908{
4909 struct nfs4_ol_stateid *stp = openlockstateid(s);
4910 __be32 ret;
4911
4912 mutex_lock(&stp->st_mutex);
4913
4914 ret = check_stateid_generation(stateid, &s->sc_stateid, 1);
4915 if (ret)
4916 goto out;
4917
4918 ret = nfserr_locks_held;
4919 if (check_for_locks(stp->st_stid.sc_file,
4920 lockowner(stp->st_stateowner)))
4921 goto out;
4922
4923 release_lock_stateid(stp);
4924 ret = nfs_ok;
4925
4926out:
4927 mutex_unlock(&stp->st_mutex);
4928 nfs4_put_stid(s);
4929 return ret;
4930}
4931
4906__be32 4932__be32
4907nfsd4_free_stateid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, 4933nfsd4_free_stateid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
4908 struct nfsd4_free_stateid *free_stateid) 4934 struct nfsd4_free_stateid *free_stateid)
@@ -4910,7 +4936,6 @@ nfsd4_free_stateid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
4910 stateid_t *stateid = &free_stateid->fr_stateid; 4936 stateid_t *stateid = &free_stateid->fr_stateid;
4911 struct nfs4_stid *s; 4937 struct nfs4_stid *s;
4912 struct nfs4_delegation *dp; 4938 struct nfs4_delegation *dp;
4913 struct nfs4_ol_stateid *stp;
4914 struct nfs4_client *cl = cstate->session->se_client; 4939 struct nfs4_client *cl = cstate->session->se_client;
4915 __be32 ret = nfserr_bad_stateid; 4940 __be32 ret = nfserr_bad_stateid;
4916 4941
@@ -4929,18 +4954,9 @@ nfsd4_free_stateid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
4929 ret = nfserr_locks_held; 4954 ret = nfserr_locks_held;
4930 break; 4955 break;
4931 case NFS4_LOCK_STID: 4956 case NFS4_LOCK_STID:
4932 ret = check_stateid_generation(stateid, &s->sc_stateid, 1); 4957 atomic_inc(&s->sc_count);
4933 if (ret)
4934 break;
4935 stp = openlockstateid(s);
4936 ret = nfserr_locks_held;
4937 if (check_for_locks(stp->st_stid.sc_file,
4938 lockowner(stp->st_stateowner)))
4939 break;
4940 WARN_ON(!unhash_lock_stateid(stp));
4941 spin_unlock(&cl->cl_lock); 4958 spin_unlock(&cl->cl_lock);
4942 nfs4_put_stid(s); 4959 ret = nfsd4_free_lock_stateid(stateid, s);
4943 ret = nfs_ok;
4944 goto out; 4960 goto out;
4945 case NFS4_REVOKED_DELEG_STID: 4961 case NFS4_REVOKED_DELEG_STID:
4946 dp = delegstateid(s); 4962 dp = delegstateid(s);
@@ -5507,7 +5523,7 @@ static __be32
5507lookup_or_create_lock_state(struct nfsd4_compound_state *cstate, 5523lookup_or_create_lock_state(struct nfsd4_compound_state *cstate,
5508 struct nfs4_ol_stateid *ost, 5524 struct nfs4_ol_stateid *ost,
5509 struct nfsd4_lock *lock, 5525 struct nfsd4_lock *lock,
5510 struct nfs4_ol_stateid **lst, bool *new) 5526 struct nfs4_ol_stateid **plst, bool *new)
5511{ 5527{
5512 __be32 status; 5528 __be32 status;
5513 struct nfs4_file *fi = ost->st_stid.sc_file; 5529 struct nfs4_file *fi = ost->st_stid.sc_file;
@@ -5515,7 +5531,9 @@ lookup_or_create_lock_state(struct nfsd4_compound_state *cstate,
5515 struct nfs4_client *cl = oo->oo_owner.so_client; 5531 struct nfs4_client *cl = oo->oo_owner.so_client;
5516 struct inode *inode = d_inode(cstate->current_fh.fh_dentry); 5532 struct inode *inode = d_inode(cstate->current_fh.fh_dentry);
5517 struct nfs4_lockowner *lo; 5533 struct nfs4_lockowner *lo;
5534 struct nfs4_ol_stateid *lst;
5518 unsigned int strhashval; 5535 unsigned int strhashval;
5536 bool hashed;
5519 5537
5520 lo = find_lockowner_str(cl, &lock->lk_new_owner); 5538 lo = find_lockowner_str(cl, &lock->lk_new_owner);
5521 if (!lo) { 5539 if (!lo) {
@@ -5531,12 +5549,27 @@ lookup_or_create_lock_state(struct nfsd4_compound_state *cstate,
5531 goto out; 5549 goto out;
5532 } 5550 }
5533 5551
5534 *lst = find_or_create_lock_stateid(lo, fi, inode, ost, new); 5552retry:
5535 if (*lst == NULL) { 5553 lst = find_or_create_lock_stateid(lo, fi, inode, ost, new);
5554 if (lst == NULL) {
5536 status = nfserr_jukebox; 5555 status = nfserr_jukebox;
5537 goto out; 5556 goto out;
5538 } 5557 }
5558
5559 mutex_lock(&lst->st_mutex);
5560
5561 /* See if it's still hashed to avoid race with FREE_STATEID */
5562 spin_lock(&cl->cl_lock);
5563 hashed = !list_empty(&lst->st_perfile);
5564 spin_unlock(&cl->cl_lock);
5565
5566 if (!hashed) {
5567 mutex_unlock(&lst->st_mutex);
5568 nfs4_put_stid(&lst->st_stid);
5569 goto retry;
5570 }
5539 status = nfs_ok; 5571 status = nfs_ok;
5572 *plst = lst;
5540out: 5573out:
5541 nfs4_put_stateowner(&lo->lo_owner); 5574 nfs4_put_stateowner(&lo->lo_owner);
5542 return status; 5575 return status;
@@ -5603,8 +5636,6 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
5603 goto out; 5636 goto out;
5604 status = lookup_or_create_lock_state(cstate, open_stp, lock, 5637 status = lookup_or_create_lock_state(cstate, open_stp, lock,
5605 &lock_stp, &new); 5638 &lock_stp, &new);
5606 if (status == nfs_ok)
5607 mutex_lock(&lock_stp->st_mutex);
5608 } else { 5639 } else {
5609 status = nfs4_preprocess_seqid_op(cstate, 5640 status = nfs4_preprocess_seqid_op(cstate,
5610 lock->lk_old_lock_seqid, 5641 lock->lk_old_lock_seqid,