diff options
Diffstat (limited to 'fs')
-rw-r--r-- | fs/nfsd/nfs4state.c | 118 |
1 files changed, 76 insertions, 42 deletions
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 123b47105c0d..5f1a91a9cd35 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c | |||
@@ -4046,8 +4046,8 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
4046 | struct nfs4_lockowner *lock_sop = NULL; | 4046 | struct nfs4_lockowner *lock_sop = NULL; |
4047 | struct nfs4_ol_stateid *lock_stp; | 4047 | struct nfs4_ol_stateid *lock_stp; |
4048 | struct file *filp = NULL; | 4048 | struct file *filp = NULL; |
4049 | struct file_lock file_lock; | 4049 | struct file_lock *file_lock = NULL; |
4050 | struct file_lock conflock; | 4050 | struct file_lock *conflock = NULL; |
4051 | __be32 status = 0; | 4051 | __be32 status = 0; |
4052 | bool new_state = false; | 4052 | bool new_state = false; |
4053 | int lkflg; | 4053 | int lkflg; |
@@ -4117,21 +4117,28 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
4117 | if (!locks_in_grace(SVC_NET(rqstp)) && lock->lk_reclaim) | 4117 | if (!locks_in_grace(SVC_NET(rqstp)) && lock->lk_reclaim) |
4118 | goto out; | 4118 | goto out; |
4119 | 4119 | ||
4120 | locks_init_lock(&file_lock); | 4120 | file_lock = locks_alloc_lock(); |
4121 | if (!file_lock) { | ||
4122 | dprintk("NFSD: %s: unable to allocate lock!\n", __func__); | ||
4123 | status = nfserr_jukebox; | ||
4124 | goto out; | ||
4125 | } | ||
4126 | |||
4127 | locks_init_lock(file_lock); | ||
4121 | switch (lock->lk_type) { | 4128 | switch (lock->lk_type) { |
4122 | case NFS4_READ_LT: | 4129 | case NFS4_READ_LT: |
4123 | case NFS4_READW_LT: | 4130 | case NFS4_READW_LT: |
4124 | filp = find_readable_file(lock_stp->st_file); | 4131 | filp = find_readable_file(lock_stp->st_file); |
4125 | if (filp) | 4132 | if (filp) |
4126 | get_lock_access(lock_stp, NFS4_SHARE_ACCESS_READ); | 4133 | get_lock_access(lock_stp, NFS4_SHARE_ACCESS_READ); |
4127 | file_lock.fl_type = F_RDLCK; | 4134 | file_lock->fl_type = F_RDLCK; |
4128 | break; | 4135 | break; |
4129 | case NFS4_WRITE_LT: | 4136 | case NFS4_WRITE_LT: |
4130 | case NFS4_WRITEW_LT: | 4137 | case NFS4_WRITEW_LT: |
4131 | filp = find_writeable_file(lock_stp->st_file); | 4138 | filp = find_writeable_file(lock_stp->st_file); |
4132 | if (filp) | 4139 | if (filp) |
4133 | get_lock_access(lock_stp, NFS4_SHARE_ACCESS_WRITE); | 4140 | get_lock_access(lock_stp, NFS4_SHARE_ACCESS_WRITE); |
4134 | file_lock.fl_type = F_WRLCK; | 4141 | file_lock->fl_type = F_WRLCK; |
4135 | break; | 4142 | break; |
4136 | default: | 4143 | default: |
4137 | status = nfserr_inval; | 4144 | status = nfserr_inval; |
@@ -4141,17 +4148,23 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
4141 | status = nfserr_openmode; | 4148 | status = nfserr_openmode; |
4142 | goto out; | 4149 | goto out; |
4143 | } | 4150 | } |
4144 | file_lock.fl_owner = (fl_owner_t)lock_sop; | 4151 | file_lock->fl_owner = (fl_owner_t)lock_sop; |
4145 | file_lock.fl_pid = current->tgid; | 4152 | file_lock->fl_pid = current->tgid; |
4146 | file_lock.fl_file = filp; | 4153 | file_lock->fl_file = filp; |
4147 | file_lock.fl_flags = FL_POSIX; | 4154 | file_lock->fl_flags = FL_POSIX; |
4148 | file_lock.fl_lmops = &nfsd_posix_mng_ops; | 4155 | file_lock->fl_lmops = &nfsd_posix_mng_ops; |
4149 | 4156 | file_lock->fl_start = lock->lk_offset; | |
4150 | file_lock.fl_start = lock->lk_offset; | 4157 | file_lock->fl_end = last_byte_offset(lock->lk_offset, lock->lk_length); |
4151 | file_lock.fl_end = last_byte_offset(lock->lk_offset, lock->lk_length); | 4158 | nfs4_transform_lock_offset(file_lock); |
4152 | nfs4_transform_lock_offset(&file_lock); | 4159 | |
4160 | conflock = locks_alloc_lock(); | ||
4161 | if (!conflock) { | ||
4162 | dprintk("NFSD: %s: unable to allocate lock!\n", __func__); | ||
4163 | status = nfserr_jukebox; | ||
4164 | goto out; | ||
4165 | } | ||
4153 | 4166 | ||
4154 | err = vfs_lock_file(filp, F_SETLK, &file_lock, &conflock); | 4167 | err = vfs_lock_file(filp, F_SETLK, file_lock, conflock); |
4155 | switch (-err) { | 4168 | switch (-err) { |
4156 | case 0: /* success! */ | 4169 | case 0: /* success! */ |
4157 | update_stateid(&lock_stp->st_stid.sc_stateid); | 4170 | update_stateid(&lock_stp->st_stid.sc_stateid); |
@@ -4162,7 +4175,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
4162 | case (EAGAIN): /* conflock holds conflicting lock */ | 4175 | case (EAGAIN): /* conflock holds conflicting lock */ |
4163 | status = nfserr_denied; | 4176 | status = nfserr_denied; |
4164 | dprintk("NFSD: nfsd4_lock: conflicting lock found!\n"); | 4177 | dprintk("NFSD: nfsd4_lock: conflicting lock found!\n"); |
4165 | nfs4_set_lock_denied(&conflock, &lock->lk_denied); | 4178 | nfs4_set_lock_denied(conflock, &lock->lk_denied); |
4166 | break; | 4179 | break; |
4167 | case (EDEADLK): | 4180 | case (EDEADLK): |
4168 | status = nfserr_deadlock; | 4181 | status = nfserr_deadlock; |
@@ -4177,6 +4190,10 @@ out: | |||
4177 | release_lockowner(lock_sop); | 4190 | release_lockowner(lock_sop); |
4178 | if (!cstate->replay_owner) | 4191 | if (!cstate->replay_owner) |
4179 | nfs4_unlock_state(); | 4192 | nfs4_unlock_state(); |
4193 | if (file_lock) | ||
4194 | locks_free_lock(file_lock); | ||
4195 | if (conflock) | ||
4196 | locks_free_lock(conflock); | ||
4180 | return status; | 4197 | return status; |
4181 | } | 4198 | } |
4182 | 4199 | ||
@@ -4205,7 +4222,7 @@ nfsd4_lockt(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
4205 | struct nfsd4_lockt *lockt) | 4222 | struct nfsd4_lockt *lockt) |
4206 | { | 4223 | { |
4207 | struct inode *inode; | 4224 | struct inode *inode; |
4208 | struct file_lock file_lock; | 4225 | struct file_lock *file_lock = NULL; |
4209 | struct nfs4_lockowner *lo; | 4226 | struct nfs4_lockowner *lo; |
4210 | __be32 status; | 4227 | __be32 status; |
4211 | struct nfsd_net *nn = net_generic(&init_net, nfsd_net_id); | 4228 | struct nfsd_net *nn = net_generic(&init_net, nfsd_net_id); |
@@ -4226,15 +4243,21 @@ nfsd4_lockt(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
4226 | goto out; | 4243 | goto out; |
4227 | 4244 | ||
4228 | inode = cstate->current_fh.fh_dentry->d_inode; | 4245 | inode = cstate->current_fh.fh_dentry->d_inode; |
4229 | locks_init_lock(&file_lock); | 4246 | file_lock = locks_alloc_lock(); |
4247 | if (!file_lock) { | ||
4248 | dprintk("NFSD: %s: unable to allocate lock!\n", __func__); | ||
4249 | status = nfserr_jukebox; | ||
4250 | goto out; | ||
4251 | } | ||
4252 | locks_init_lock(file_lock); | ||
4230 | switch (lockt->lt_type) { | 4253 | switch (lockt->lt_type) { |
4231 | case NFS4_READ_LT: | 4254 | case NFS4_READ_LT: |
4232 | case NFS4_READW_LT: | 4255 | case NFS4_READW_LT: |
4233 | file_lock.fl_type = F_RDLCK; | 4256 | file_lock->fl_type = F_RDLCK; |
4234 | break; | 4257 | break; |
4235 | case NFS4_WRITE_LT: | 4258 | case NFS4_WRITE_LT: |
4236 | case NFS4_WRITEW_LT: | 4259 | case NFS4_WRITEW_LT: |
4237 | file_lock.fl_type = F_WRLCK; | 4260 | file_lock->fl_type = F_WRLCK; |
4238 | break; | 4261 | break; |
4239 | default: | 4262 | default: |
4240 | dprintk("NFSD: nfs4_lockt: bad lock type!\n"); | 4263 | dprintk("NFSD: nfs4_lockt: bad lock type!\n"); |
@@ -4244,25 +4267,27 @@ nfsd4_lockt(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
4244 | 4267 | ||
4245 | lo = find_lockowner_str(inode, &lockt->lt_clientid, &lockt->lt_owner); | 4268 | lo = find_lockowner_str(inode, &lockt->lt_clientid, &lockt->lt_owner); |
4246 | if (lo) | 4269 | if (lo) |
4247 | file_lock.fl_owner = (fl_owner_t)lo; | 4270 | file_lock->fl_owner = (fl_owner_t)lo; |
4248 | file_lock.fl_pid = current->tgid; | 4271 | file_lock->fl_pid = current->tgid; |
4249 | file_lock.fl_flags = FL_POSIX; | 4272 | file_lock->fl_flags = FL_POSIX; |
4250 | 4273 | ||
4251 | file_lock.fl_start = lockt->lt_offset; | 4274 | file_lock->fl_start = lockt->lt_offset; |
4252 | file_lock.fl_end = last_byte_offset(lockt->lt_offset, lockt->lt_length); | 4275 | file_lock->fl_end = last_byte_offset(lockt->lt_offset, lockt->lt_length); |
4253 | 4276 | ||
4254 | nfs4_transform_lock_offset(&file_lock); | 4277 | nfs4_transform_lock_offset(file_lock); |
4255 | 4278 | ||
4256 | status = nfsd_test_lock(rqstp, &cstate->current_fh, &file_lock); | 4279 | status = nfsd_test_lock(rqstp, &cstate->current_fh, file_lock); |
4257 | if (status) | 4280 | if (status) |
4258 | goto out; | 4281 | goto out; |
4259 | 4282 | ||
4260 | if (file_lock.fl_type != F_UNLCK) { | 4283 | if (file_lock->fl_type != F_UNLCK) { |
4261 | status = nfserr_denied; | 4284 | status = nfserr_denied; |
4262 | nfs4_set_lock_denied(&file_lock, &lockt->lt_denied); | 4285 | nfs4_set_lock_denied(file_lock, &lockt->lt_denied); |
4263 | } | 4286 | } |
4264 | out: | 4287 | out: |
4265 | nfs4_unlock_state(); | 4288 | nfs4_unlock_state(); |
4289 | if (file_lock) | ||
4290 | locks_free_lock(file_lock); | ||
4266 | return status; | 4291 | return status; |
4267 | } | 4292 | } |
4268 | 4293 | ||
@@ -4272,7 +4297,7 @@ nfsd4_locku(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
4272 | { | 4297 | { |
4273 | struct nfs4_ol_stateid *stp; | 4298 | struct nfs4_ol_stateid *stp; |
4274 | struct file *filp = NULL; | 4299 | struct file *filp = NULL; |
4275 | struct file_lock file_lock; | 4300 | struct file_lock *file_lock = NULL; |
4276 | __be32 status; | 4301 | __be32 status; |
4277 | int err; | 4302 | int err; |
4278 | 4303 | ||
@@ -4294,22 +4319,29 @@ nfsd4_locku(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
4294 | status = nfserr_lock_range; | 4319 | status = nfserr_lock_range; |
4295 | goto out; | 4320 | goto out; |
4296 | } | 4321 | } |
4297 | locks_init_lock(&file_lock); | 4322 | file_lock = locks_alloc_lock(); |
4298 | file_lock.fl_type = F_UNLCK; | 4323 | if (!file_lock) { |
4299 | file_lock.fl_owner = (fl_owner_t)lockowner(stp->st_stateowner); | 4324 | dprintk("NFSD: %s: unable to allocate lock!\n", __func__); |
4300 | file_lock.fl_pid = current->tgid; | 4325 | status = nfserr_jukebox; |
4301 | file_lock.fl_file = filp; | 4326 | goto out; |
4302 | file_lock.fl_flags = FL_POSIX; | 4327 | } |
4303 | file_lock.fl_lmops = &nfsd_posix_mng_ops; | 4328 | locks_init_lock(file_lock); |
4304 | file_lock.fl_start = locku->lu_offset; | 4329 | file_lock->fl_type = F_UNLCK; |
4305 | 4330 | file_lock->fl_owner = (fl_owner_t)lockowner(stp->st_stateowner); | |
4306 | file_lock.fl_end = last_byte_offset(locku->lu_offset, locku->lu_length); | 4331 | file_lock->fl_pid = current->tgid; |
4307 | nfs4_transform_lock_offset(&file_lock); | 4332 | file_lock->fl_file = filp; |
4333 | file_lock->fl_flags = FL_POSIX; | ||
4334 | file_lock->fl_lmops = &nfsd_posix_mng_ops; | ||
4335 | file_lock->fl_start = locku->lu_offset; | ||
4336 | |||
4337 | file_lock->fl_end = last_byte_offset(locku->lu_offset, | ||
4338 | locku->lu_length); | ||
4339 | nfs4_transform_lock_offset(file_lock); | ||
4308 | 4340 | ||
4309 | /* | 4341 | /* |
4310 | * Try to unlock the file in the VFS. | 4342 | * Try to unlock the file in the VFS. |
4311 | */ | 4343 | */ |
4312 | err = vfs_lock_file(filp, F_SETLK, &file_lock, NULL); | 4344 | err = vfs_lock_file(filp, F_SETLK, file_lock, NULL); |
4313 | if (err) { | 4345 | if (err) { |
4314 | dprintk("NFSD: nfs4_locku: vfs_lock_file failed!\n"); | 4346 | dprintk("NFSD: nfs4_locku: vfs_lock_file failed!\n"); |
4315 | goto out_nfserr; | 4347 | goto out_nfserr; |
@@ -4323,6 +4355,8 @@ nfsd4_locku(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | |||
4323 | out: | 4355 | out: |
4324 | if (!cstate->replay_owner) | 4356 | if (!cstate->replay_owner) |
4325 | nfs4_unlock_state(); | 4357 | nfs4_unlock_state(); |
4358 | if (file_lock) | ||
4359 | locks_free_lock(file_lock); | ||
4326 | return status; | 4360 | return status; |
4327 | 4361 | ||
4328 | out_nfserr: | 4362 | out_nfserr: |