diff options
-rw-r--r-- | fs/nfsd/nfs4state.c | 45 |
1 files changed, 33 insertions, 12 deletions
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 749608b914b4..eaa5f9ebf444 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c | |||
@@ -4754,6 +4754,7 @@ find_lockowner_str(clientid_t *clid, struct xdr_netobj *owner, | |||
4754 | continue; | 4754 | continue; |
4755 | if (!same_owner_str(so, owner, clid)) | 4755 | if (!same_owner_str(so, owner, clid)) |
4756 | continue; | 4756 | continue; |
4757 | atomic_inc(&so->so_count); | ||
4757 | return lockowner(so); | 4758 | return lockowner(so); |
4758 | } | 4759 | } |
4759 | return NULL; | 4760 | return NULL; |
@@ -4787,9 +4788,7 @@ alloc_init_lock_stateowner(unsigned int strhashval, struct nfs4_client *clp, str | |||
4787 | return NULL; | 4788 | return NULL; |
4788 | INIT_LIST_HEAD(&lo->lo_owner.so_stateids); | 4789 | INIT_LIST_HEAD(&lo->lo_owner.so_stateids); |
4789 | lo->lo_owner.so_is_open_owner = 0; | 4790 | lo->lo_owner.so_is_open_owner = 0; |
4790 | /* It is the openowner seqid that will be incremented in encode in the | 4791 | lo->lo_owner.so_seqid = lock->lk_new_lock_seqid; |
4791 | * case of new lockowners; so increment the lock seqid manually: */ | ||
4792 | lo->lo_owner.so_seqid = lock->lk_new_lock_seqid + 1; | ||
4793 | lo->lo_owner.so_ops = &lockowner_ops; | 4792 | lo->lo_owner.so_ops = &lockowner_ops; |
4794 | list_add(&lo->lo_owner.so_strhash, &nn->ownerstr_hashtbl[strhashval]); | 4793 | list_add(&lo->lo_owner.so_strhash, &nn->ownerstr_hashtbl[strhashval]); |
4795 | return lo; | 4794 | return lo; |
@@ -4895,6 +4894,7 @@ lookup_or_create_lock_state(struct nfsd4_compound_state *cstate, | |||
4895 | struct nfsd4_lock *lock, | 4894 | struct nfsd4_lock *lock, |
4896 | struct nfs4_ol_stateid **lst, bool *new) | 4895 | struct nfs4_ol_stateid **lst, bool *new) |
4897 | { | 4896 | { |
4897 | __be32 status; | ||
4898 | struct nfs4_file *fi = ost->st_stid.sc_file; | 4898 | struct nfs4_file *fi = ost->st_stid.sc_file; |
4899 | struct nfs4_openowner *oo = openowner(ost->st_stateowner); | 4899 | struct nfs4_openowner *oo = openowner(ost->st_stateowner); |
4900 | struct nfs4_client *cl = oo->oo_owner.so_client; | 4900 | struct nfs4_client *cl = oo->oo_owner.so_client; |
@@ -4910,19 +4910,26 @@ lookup_or_create_lock_state(struct nfsd4_compound_state *cstate, | |||
4910 | lo = alloc_init_lock_stateowner(strhashval, cl, ost, lock); | 4910 | lo = alloc_init_lock_stateowner(strhashval, cl, ost, lock); |
4911 | if (lo == NULL) | 4911 | if (lo == NULL) |
4912 | return nfserr_jukebox; | 4912 | return nfserr_jukebox; |
4913 | /* FIXME: extra reference for new lockowners for the client */ | ||
4914 | atomic_inc(&lo->lo_owner.so_count); | ||
4913 | } else { | 4915 | } else { |
4914 | /* with an existing lockowner, seqids must be the same */ | 4916 | /* with an existing lockowner, seqids must be the same */ |
4917 | status = nfserr_bad_seqid; | ||
4915 | if (!cstate->minorversion && | 4918 | if (!cstate->minorversion && |
4916 | lock->lk_new_lock_seqid != lo->lo_owner.so_seqid) | 4919 | lock->lk_new_lock_seqid != lo->lo_owner.so_seqid) |
4917 | return nfserr_bad_seqid; | 4920 | goto out; |
4918 | } | 4921 | } |
4919 | 4922 | ||
4920 | *lst = find_or_create_lock_stateid(lo, fi, inode, ost, new); | 4923 | *lst = find_or_create_lock_stateid(lo, fi, inode, ost, new); |
4921 | if (*lst == NULL) { | 4924 | if (*lst == NULL) { |
4922 | release_lockowner_if_empty(lo); | 4925 | release_lockowner_if_empty(lo); |
4923 | return nfserr_jukebox; | 4926 | status = nfserr_jukebox; |
4927 | goto out; | ||
4924 | } | 4928 | } |
4925 | return nfs_ok; | 4929 | status = nfs_ok; |
4930 | out: | ||
4931 | nfs4_put_stateowner(&lo->lo_owner); | ||
4932 | return status; | ||
4926 | } | 4933 | } |
4927 | 4934 | ||
4928 | /* | 4935 | /* |
@@ -4941,9 +4948,9 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
4941 | struct file_lock *file_lock = NULL; | 4948 | struct file_lock *file_lock = NULL; |
4942 | struct file_lock *conflock = NULL; | 4949 | struct file_lock *conflock = NULL; |
4943 | __be32 status = 0; | 4950 | __be32 status = 0; |
4944 | bool new_state = false; | ||
4945 | int lkflg; | 4951 | int lkflg; |
4946 | int err; | 4952 | int err; |
4953 | bool new = false; | ||
4947 | struct net *net = SVC_NET(rqstp); | 4954 | struct net *net = SVC_NET(rqstp); |
4948 | struct nfsd_net *nn = net_generic(net, nfsd_net_id); | 4955 | struct nfsd_net *nn = net_generic(net, nfsd_net_id); |
4949 | 4956 | ||
@@ -4986,7 +4993,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
4986 | &lock->v.new.clientid)) | 4993 | &lock->v.new.clientid)) |
4987 | goto out; | 4994 | goto out; |
4988 | status = lookup_or_create_lock_state(cstate, open_stp, lock, | 4995 | status = lookup_or_create_lock_state(cstate, open_stp, lock, |
4989 | &lock_stp, &new_state); | 4996 | &lock_stp, &new); |
4990 | } else { | 4997 | } else { |
4991 | status = nfs4_preprocess_seqid_op(cstate, | 4998 | status = nfs4_preprocess_seqid_op(cstate, |
4992 | lock->lk_old_lock_seqid, | 4999 | lock->lk_old_lock_seqid, |
@@ -5085,12 +5092,24 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
5085 | out: | 5092 | out: |
5086 | if (filp) | 5093 | if (filp) |
5087 | fput(filp); | 5094 | fput(filp); |
5088 | if (lock_stp) | 5095 | if (lock_stp) { |
5096 | /* Bump seqid manually if the 4.0 replay owner is openowner */ | ||
5097 | if (cstate->replay_owner && | ||
5098 | cstate->replay_owner != &lock_sop->lo_owner && | ||
5099 | seqid_mutating_err(ntohl(status))) | ||
5100 | lock_sop->lo_owner.so_seqid++; | ||
5101 | |||
5102 | /* | ||
5103 | * If this is a new, never-before-used stateid, and we are | ||
5104 | * returning an error, then just go ahead and release it. | ||
5105 | */ | ||
5106 | if (status && new) | ||
5107 | release_lock_stateid(lock_stp); | ||
5108 | |||
5089 | nfs4_put_stid(&lock_stp->st_stid); | 5109 | nfs4_put_stid(&lock_stp->st_stid); |
5110 | } | ||
5090 | if (open_stp) | 5111 | if (open_stp) |
5091 | nfs4_put_stid(&open_stp->st_stid); | 5112 | nfs4_put_stid(&open_stp->st_stid); |
5092 | if (status && new_state) | ||
5093 | release_lock_stateid(lock_stp); | ||
5094 | nfsd4_bump_seqid(cstate, status); | 5113 | nfsd4_bump_seqid(cstate, status); |
5095 | nfs4_unlock_state(); | 5114 | nfs4_unlock_state(); |
5096 | if (file_lock) | 5115 | if (file_lock) |
@@ -5125,7 +5144,7 @@ nfsd4_lockt(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
5125 | struct nfsd4_lockt *lockt) | 5144 | struct nfsd4_lockt *lockt) |
5126 | { | 5145 | { |
5127 | struct file_lock *file_lock = NULL; | 5146 | struct file_lock *file_lock = NULL; |
5128 | struct nfs4_lockowner *lo; | 5147 | struct nfs4_lockowner *lo = NULL; |
5129 | __be32 status; | 5148 | __be32 status; |
5130 | struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); | 5149 | struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); |
5131 | 5150 | ||
@@ -5188,6 +5207,8 @@ nfsd4_lockt(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
5188 | nfs4_set_lock_denied(file_lock, &lockt->lt_denied); | 5207 | nfs4_set_lock_denied(file_lock, &lockt->lt_denied); |
5189 | } | 5208 | } |
5190 | out: | 5209 | out: |
5210 | if (lo) | ||
5211 | nfs4_put_stateowner(&lo->lo_owner); | ||
5191 | nfs4_unlock_state(); | 5212 | nfs4_unlock_state(); |
5192 | if (file_lock) | 5213 | if (file_lock) |
5193 | locks_free_lock(file_lock); | 5214 | locks_free_lock(file_lock); |