diff options
Diffstat (limited to 'fs/nfsd/nfs4state.c')
-rw-r--r-- | fs/nfsd/nfs4state.c | 65 |
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 | ||
4906 | static __be32 | ||
4907 | nfsd4_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 | |||
4926 | out: | ||
4927 | mutex_unlock(&stp->st_mutex); | ||
4928 | nfs4_put_stid(s); | ||
4929 | return ret; | ||
4930 | } | ||
4931 | |||
4906 | __be32 | 4932 | __be32 |
4907 | nfsd4_free_stateid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | 4933 | nfsd4_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 | |||
5507 | lookup_or_create_lock_state(struct nfsd4_compound_state *cstate, | 5523 | lookup_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); | 5552 | retry: |
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; | ||
5540 | out: | 5573 | out: |
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, |