diff options
Diffstat (limited to 'fs/lockd/clntproc.c')
-rw-r--r-- | fs/lockd/clntproc.c | 317 |
1 files changed, 119 insertions, 198 deletions
diff --git a/fs/lockd/clntproc.c b/fs/lockd/clntproc.c index 970b6a6aa337..f96e38155b5c 100644 --- a/fs/lockd/clntproc.c +++ b/fs/lockd/clntproc.c | |||
@@ -132,59 +132,18 @@ static void nlmclnt_setlockargs(struct nlm_rqst *req, struct file_lock *fl) | |||
132 | memcpy(&lock->fh, NFS_FH(fl->fl_file->f_dentry->d_inode), sizeof(struct nfs_fh)); | 132 | memcpy(&lock->fh, NFS_FH(fl->fl_file->f_dentry->d_inode), sizeof(struct nfs_fh)); |
133 | lock->caller = system_utsname.nodename; | 133 | lock->caller = system_utsname.nodename; |
134 | lock->oh.data = req->a_owner; | 134 | lock->oh.data = req->a_owner; |
135 | lock->oh.len = sprintf(req->a_owner, "%d@%s", | 135 | lock->oh.len = snprintf(req->a_owner, sizeof(req->a_owner), "%u@%s", |
136 | current->pid, system_utsname.nodename); | 136 | (unsigned int)fl->fl_u.nfs_fl.owner->pid, |
137 | locks_copy_lock(&lock->fl, fl); | 137 | system_utsname.nodename); |
138 | lock->svid = fl->fl_u.nfs_fl.owner->pid; | ||
139 | lock->fl.fl_start = fl->fl_start; | ||
140 | lock->fl.fl_end = fl->fl_end; | ||
141 | lock->fl.fl_type = fl->fl_type; | ||
138 | } | 142 | } |
139 | 143 | ||
140 | static void nlmclnt_release_lockargs(struct nlm_rqst *req) | 144 | static void nlmclnt_release_lockargs(struct nlm_rqst *req) |
141 | { | 145 | { |
142 | struct file_lock *fl = &req->a_args.lock.fl; | 146 | BUG_ON(req->a_args.lock.fl.fl_ops != NULL); |
143 | |||
144 | if (fl->fl_ops && fl->fl_ops->fl_release_private) | ||
145 | fl->fl_ops->fl_release_private(fl); | ||
146 | } | ||
147 | |||
148 | /* | ||
149 | * Initialize arguments for GRANTED call. The nlm_rqst structure | ||
150 | * has been cleared already. | ||
151 | */ | ||
152 | int | ||
153 | nlmclnt_setgrantargs(struct nlm_rqst *call, struct nlm_lock *lock) | ||
154 | { | ||
155 | locks_copy_lock(&call->a_args.lock.fl, &lock->fl); | ||
156 | memcpy(&call->a_args.lock.fh, &lock->fh, sizeof(call->a_args.lock.fh)); | ||
157 | call->a_args.lock.caller = system_utsname.nodename; | ||
158 | call->a_args.lock.oh.len = lock->oh.len; | ||
159 | |||
160 | /* set default data area */ | ||
161 | call->a_args.lock.oh.data = call->a_owner; | ||
162 | |||
163 | if (lock->oh.len > NLMCLNT_OHSIZE) { | ||
164 | void *data = kmalloc(lock->oh.len, GFP_KERNEL); | ||
165 | if (!data) { | ||
166 | nlmclnt_freegrantargs(call); | ||
167 | return 0; | ||
168 | } | ||
169 | call->a_args.lock.oh.data = (u8 *) data; | ||
170 | } | ||
171 | |||
172 | memcpy(call->a_args.lock.oh.data, lock->oh.data, lock->oh.len); | ||
173 | return 1; | ||
174 | } | ||
175 | |||
176 | void | ||
177 | nlmclnt_freegrantargs(struct nlm_rqst *call) | ||
178 | { | ||
179 | struct file_lock *fl = &call->a_args.lock.fl; | ||
180 | /* | ||
181 | * Check whether we allocated memory for the owner. | ||
182 | */ | ||
183 | if (call->a_args.lock.oh.data != (u8 *) call->a_owner) { | ||
184 | kfree(call->a_args.lock.oh.data); | ||
185 | } | ||
186 | if (fl->fl_ops && fl->fl_ops->fl_release_private) | ||
187 | fl->fl_ops->fl_release_private(fl); | ||
188 | } | 147 | } |
189 | 148 | ||
190 | /* | 149 | /* |
@@ -193,9 +152,8 @@ nlmclnt_freegrantargs(struct nlm_rqst *call) | |||
193 | int | 152 | int |
194 | nlmclnt_proc(struct inode *inode, int cmd, struct file_lock *fl) | 153 | nlmclnt_proc(struct inode *inode, int cmd, struct file_lock *fl) |
195 | { | 154 | { |
196 | struct nfs_server *nfssrv = NFS_SERVER(inode); | ||
197 | struct nlm_host *host; | 155 | struct nlm_host *host; |
198 | struct nlm_rqst reqst, *call = &reqst; | 156 | struct nlm_rqst *call; |
199 | sigset_t oldset; | 157 | sigset_t oldset; |
200 | unsigned long flags; | 158 | unsigned long flags; |
201 | int status, proto, vers; | 159 | int status, proto, vers; |
@@ -209,23 +167,17 @@ nlmclnt_proc(struct inode *inode, int cmd, struct file_lock *fl) | |||
209 | /* Retrieve transport protocol from NFS client */ | 167 | /* Retrieve transport protocol from NFS client */ |
210 | proto = NFS_CLIENT(inode)->cl_xprt->prot; | 168 | proto = NFS_CLIENT(inode)->cl_xprt->prot; |
211 | 169 | ||
212 | if (!(host = nlmclnt_lookup_host(NFS_ADDR(inode), proto, vers))) | 170 | host = nlmclnt_lookup_host(NFS_ADDR(inode), proto, vers); |
171 | if (host == NULL) | ||
213 | return -ENOLCK; | 172 | return -ENOLCK; |
214 | 173 | ||
215 | /* Create RPC client handle if not there, and copy soft | 174 | call = nlm_alloc_call(host); |
216 | * and intr flags from NFS client. */ | 175 | if (call == NULL) |
217 | if (host->h_rpcclnt == NULL) { | 176 | return -ENOMEM; |
218 | struct rpc_clnt *clnt; | ||
219 | 177 | ||
220 | /* Bind an rpc client to this host handle (does not | 178 | nlmclnt_locks_init_private(fl, host); |
221 | * perform a portmapper lookup) */ | 179 | /* Set up the argument struct */ |
222 | if (!(clnt = nlm_bind_host(host))) { | 180 | nlmclnt_setlockargs(call, fl); |
223 | status = -ENOLCK; | ||
224 | goto done; | ||
225 | } | ||
226 | clnt->cl_softrtry = nfssrv->client->cl_softrtry; | ||
227 | clnt->cl_intr = nfssrv->client->cl_intr; | ||
228 | } | ||
229 | 181 | ||
230 | /* Keep the old signal mask */ | 182 | /* Keep the old signal mask */ |
231 | spin_lock_irqsave(¤t->sighand->siglock, flags); | 183 | spin_lock_irqsave(¤t->sighand->siglock, flags); |
@@ -238,26 +190,10 @@ nlmclnt_proc(struct inode *inode, int cmd, struct file_lock *fl) | |||
238 | && (current->flags & PF_EXITING)) { | 190 | && (current->flags & PF_EXITING)) { |
239 | sigfillset(¤t->blocked); /* Mask all signals */ | 191 | sigfillset(¤t->blocked); /* Mask all signals */ |
240 | recalc_sigpending(); | 192 | recalc_sigpending(); |
241 | spin_unlock_irqrestore(¤t->sighand->siglock, flags); | ||
242 | 193 | ||
243 | call = nlmclnt_alloc_call(); | ||
244 | if (!call) { | ||
245 | status = -ENOMEM; | ||
246 | goto out_restore; | ||
247 | } | ||
248 | call->a_flags = RPC_TASK_ASYNC; | 194 | call->a_flags = RPC_TASK_ASYNC; |
249 | } else { | ||
250 | spin_unlock_irqrestore(¤t->sighand->siglock, flags); | ||
251 | memset(call, 0, sizeof(*call)); | ||
252 | locks_init_lock(&call->a_args.lock.fl); | ||
253 | locks_init_lock(&call->a_res.lock.fl); | ||
254 | } | 195 | } |
255 | call->a_host = host; | 196 | spin_unlock_irqrestore(¤t->sighand->siglock, flags); |
256 | |||
257 | nlmclnt_locks_init_private(fl, host); | ||
258 | |||
259 | /* Set up the argument struct */ | ||
260 | nlmclnt_setlockargs(call, fl); | ||
261 | 197 | ||
262 | if (IS_SETLK(cmd) || IS_SETLKW(cmd)) { | 198 | if (IS_SETLK(cmd) || IS_SETLKW(cmd)) { |
263 | if (fl->fl_type != F_UNLCK) { | 199 | if (fl->fl_type != F_UNLCK) { |
@@ -270,41 +206,58 @@ nlmclnt_proc(struct inode *inode, int cmd, struct file_lock *fl) | |||
270 | else | 206 | else |
271 | status = -EINVAL; | 207 | status = -EINVAL; |
272 | 208 | ||
273 | out_restore: | 209 | fl->fl_ops->fl_release_private(fl); |
210 | fl->fl_ops = NULL; | ||
211 | |||
274 | spin_lock_irqsave(¤t->sighand->siglock, flags); | 212 | spin_lock_irqsave(¤t->sighand->siglock, flags); |
275 | current->blocked = oldset; | 213 | current->blocked = oldset; |
276 | recalc_sigpending(); | 214 | recalc_sigpending(); |
277 | spin_unlock_irqrestore(¤t->sighand->siglock, flags); | 215 | spin_unlock_irqrestore(¤t->sighand->siglock, flags); |
278 | 216 | ||
279 | done: | ||
280 | dprintk("lockd: clnt proc returns %d\n", status); | 217 | dprintk("lockd: clnt proc returns %d\n", status); |
281 | nlm_release_host(host); | ||
282 | return status; | 218 | return status; |
283 | } | 219 | } |
284 | EXPORT_SYMBOL(nlmclnt_proc); | 220 | EXPORT_SYMBOL(nlmclnt_proc); |
285 | 221 | ||
286 | /* | 222 | /* |
287 | * Allocate an NLM RPC call struct | 223 | * Allocate an NLM RPC call struct |
224 | * | ||
225 | * Note: the caller must hold a reference to host. In case of failure, | ||
226 | * this reference will be released. | ||
288 | */ | 227 | */ |
289 | struct nlm_rqst * | 228 | struct nlm_rqst *nlm_alloc_call(struct nlm_host *host) |
290 | nlmclnt_alloc_call(void) | ||
291 | { | 229 | { |
292 | struct nlm_rqst *call; | 230 | struct nlm_rqst *call; |
293 | 231 | ||
294 | while (!signalled()) { | 232 | for(;;) { |
295 | call = (struct nlm_rqst *) kmalloc(sizeof(struct nlm_rqst), GFP_KERNEL); | 233 | call = kzalloc(sizeof(*call), GFP_KERNEL); |
296 | if (call) { | 234 | if (call != NULL) { |
297 | memset(call, 0, sizeof(*call)); | ||
298 | locks_init_lock(&call->a_args.lock.fl); | 235 | locks_init_lock(&call->a_args.lock.fl); |
299 | locks_init_lock(&call->a_res.lock.fl); | 236 | locks_init_lock(&call->a_res.lock.fl); |
237 | call->a_host = host; | ||
300 | return call; | 238 | return call; |
301 | } | 239 | } |
302 | printk("nlmclnt_alloc_call: failed, waiting for memory\n"); | 240 | if (signalled()) |
241 | break; | ||
242 | printk("nlm_alloc_call: failed, waiting for memory\n"); | ||
303 | schedule_timeout_interruptible(5*HZ); | 243 | schedule_timeout_interruptible(5*HZ); |
304 | } | 244 | } |
245 | nlm_release_host(host); | ||
305 | return NULL; | 246 | return NULL; |
306 | } | 247 | } |
307 | 248 | ||
249 | void nlm_release_call(struct nlm_rqst *call) | ||
250 | { | ||
251 | nlm_release_host(call->a_host); | ||
252 | nlmclnt_release_lockargs(call); | ||
253 | kfree(call); | ||
254 | } | ||
255 | |||
256 | static void nlmclnt_rpc_release(void *data) | ||
257 | { | ||
258 | return nlm_release_call(data); | ||
259 | } | ||
260 | |||
308 | static int nlm_wait_on_grace(wait_queue_head_t *queue) | 261 | static int nlm_wait_on_grace(wait_queue_head_t *queue) |
309 | { | 262 | { |
310 | DEFINE_WAIT(wait); | 263 | DEFINE_WAIT(wait); |
@@ -401,57 +354,45 @@ in_grace_period: | |||
401 | /* | 354 | /* |
402 | * Generic NLM call, async version. | 355 | * Generic NLM call, async version. |
403 | */ | 356 | */ |
404 | int nlmsvc_async_call(struct nlm_rqst *req, u32 proc, const struct rpc_call_ops *tk_ops) | 357 | static int __nlm_async_call(struct nlm_rqst *req, u32 proc, struct rpc_message *msg, const struct rpc_call_ops *tk_ops) |
405 | { | 358 | { |
406 | struct nlm_host *host = req->a_host; | 359 | struct nlm_host *host = req->a_host; |
407 | struct rpc_clnt *clnt; | 360 | struct rpc_clnt *clnt; |
408 | struct rpc_message msg = { | 361 | int status = -ENOLCK; |
409 | .rpc_argp = &req->a_args, | ||
410 | .rpc_resp = &req->a_res, | ||
411 | }; | ||
412 | int status; | ||
413 | 362 | ||
414 | dprintk("lockd: call procedure %d on %s (async)\n", | 363 | dprintk("lockd: call procedure %d on %s (async)\n", |
415 | (int)proc, host->h_name); | 364 | (int)proc, host->h_name); |
416 | 365 | ||
417 | /* If we have no RPC client yet, create one. */ | 366 | /* If we have no RPC client yet, create one. */ |
418 | if ((clnt = nlm_bind_host(host)) == NULL) | 367 | clnt = nlm_bind_host(host); |
419 | return -ENOLCK; | 368 | if (clnt == NULL) |
420 | msg.rpc_proc = &clnt->cl_procinfo[proc]; | 369 | goto out_err; |
370 | msg->rpc_proc = &clnt->cl_procinfo[proc]; | ||
421 | 371 | ||
422 | /* bootstrap and kick off the async RPC call */ | 372 | /* bootstrap and kick off the async RPC call */ |
423 | status = rpc_call_async(clnt, &msg, RPC_TASK_ASYNC, tk_ops, req); | 373 | status = rpc_call_async(clnt, msg, RPC_TASK_ASYNC, tk_ops, req); |
424 | 374 | if (status == 0) | |
375 | return 0; | ||
376 | out_err: | ||
377 | nlm_release_call(req); | ||
425 | return status; | 378 | return status; |
426 | } | 379 | } |
427 | 380 | ||
428 | static int nlmclnt_async_call(struct nlm_rqst *req, u32 proc, const struct rpc_call_ops *tk_ops) | 381 | int nlm_async_call(struct nlm_rqst *req, u32 proc, const struct rpc_call_ops *tk_ops) |
429 | { | 382 | { |
430 | struct nlm_host *host = req->a_host; | ||
431 | struct rpc_clnt *clnt; | ||
432 | struct nlm_args *argp = &req->a_args; | ||
433 | struct nlm_res *resp = &req->a_res; | ||
434 | struct rpc_message msg = { | 383 | struct rpc_message msg = { |
435 | .rpc_argp = argp, | 384 | .rpc_argp = &req->a_args, |
436 | .rpc_resp = resp, | 385 | .rpc_resp = &req->a_res, |
437 | }; | 386 | }; |
438 | int status; | 387 | return __nlm_async_call(req, proc, &msg, tk_ops); |
439 | 388 | } | |
440 | dprintk("lockd: call procedure %d on %s (async)\n", | ||
441 | (int)proc, host->h_name); | ||
442 | |||
443 | /* If we have no RPC client yet, create one. */ | ||
444 | if ((clnt = nlm_bind_host(host)) == NULL) | ||
445 | return -ENOLCK; | ||
446 | msg.rpc_proc = &clnt->cl_procinfo[proc]; | ||
447 | 389 | ||
448 | /* Increment host refcount */ | 390 | int nlm_async_reply(struct nlm_rqst *req, u32 proc, const struct rpc_call_ops *tk_ops) |
449 | nlm_get_host(host); | 391 | { |
450 | /* bootstrap and kick off the async RPC call */ | 392 | struct rpc_message msg = { |
451 | status = rpc_call_async(clnt, &msg, RPC_TASK_ASYNC, tk_ops, req); | 393 | .rpc_argp = &req->a_res, |
452 | if (status < 0) | 394 | }; |
453 | nlm_release_host(host); | 395 | return __nlm_async_call(req, proc, &msg, tk_ops); |
454 | return status; | ||
455 | } | 396 | } |
456 | 397 | ||
457 | /* | 398 | /* |
@@ -463,36 +404,41 @@ nlmclnt_test(struct nlm_rqst *req, struct file_lock *fl) | |||
463 | int status; | 404 | int status; |
464 | 405 | ||
465 | status = nlmclnt_call(req, NLMPROC_TEST); | 406 | status = nlmclnt_call(req, NLMPROC_TEST); |
466 | nlmclnt_release_lockargs(req); | ||
467 | if (status < 0) | 407 | if (status < 0) |
468 | return status; | 408 | goto out; |
469 | 409 | ||
470 | status = req->a_res.status; | 410 | switch (req->a_res.status) { |
471 | if (status == NLM_LCK_GRANTED) { | 411 | case NLM_LCK_GRANTED: |
472 | fl->fl_type = F_UNLCK; | 412 | fl->fl_type = F_UNLCK; |
473 | } if (status == NLM_LCK_DENIED) { | 413 | break; |
474 | /* | 414 | case NLM_LCK_DENIED: |
475 | * Report the conflicting lock back to the application. | 415 | /* |
476 | */ | 416 | * Report the conflicting lock back to the application. |
477 | locks_copy_lock(fl, &req->a_res.lock.fl); | 417 | */ |
478 | fl->fl_pid = 0; | 418 | fl->fl_start = req->a_res.lock.fl.fl_start; |
479 | } else { | 419 | fl->fl_end = req->a_res.lock.fl.fl_start; |
480 | return nlm_stat_to_errno(req->a_res.status); | 420 | fl->fl_type = req->a_res.lock.fl.fl_type; |
421 | fl->fl_pid = 0; | ||
422 | break; | ||
423 | default: | ||
424 | status = nlm_stat_to_errno(req->a_res.status); | ||
481 | } | 425 | } |
482 | 426 | out: | |
483 | return 0; | 427 | nlm_release_call(req); |
428 | return status; | ||
484 | } | 429 | } |
485 | 430 | ||
486 | static void nlmclnt_locks_copy_lock(struct file_lock *new, struct file_lock *fl) | 431 | static void nlmclnt_locks_copy_lock(struct file_lock *new, struct file_lock *fl) |
487 | { | 432 | { |
488 | memcpy(&new->fl_u.nfs_fl, &fl->fl_u.nfs_fl, sizeof(new->fl_u.nfs_fl)); | 433 | new->fl_u.nfs_fl.state = fl->fl_u.nfs_fl.state; |
489 | nlm_get_lockowner(new->fl_u.nfs_fl.owner); | 434 | new->fl_u.nfs_fl.owner = nlm_get_lockowner(fl->fl_u.nfs_fl.owner); |
435 | list_add_tail(&new->fl_u.nfs_fl.list, &fl->fl_u.nfs_fl.owner->host->h_granted); | ||
490 | } | 436 | } |
491 | 437 | ||
492 | static void nlmclnt_locks_release_private(struct file_lock *fl) | 438 | static void nlmclnt_locks_release_private(struct file_lock *fl) |
493 | { | 439 | { |
440 | list_del(&fl->fl_u.nfs_fl.list); | ||
494 | nlm_put_lockowner(fl->fl_u.nfs_fl.owner); | 441 | nlm_put_lockowner(fl->fl_u.nfs_fl.owner); |
495 | fl->fl_ops = NULL; | ||
496 | } | 442 | } |
497 | 443 | ||
498 | static struct file_lock_operations nlmclnt_lock_ops = { | 444 | static struct file_lock_operations nlmclnt_lock_ops = { |
@@ -504,8 +450,8 @@ static void nlmclnt_locks_init_private(struct file_lock *fl, struct nlm_host *ho | |||
504 | { | 450 | { |
505 | BUG_ON(fl->fl_ops != NULL); | 451 | BUG_ON(fl->fl_ops != NULL); |
506 | fl->fl_u.nfs_fl.state = 0; | 452 | fl->fl_u.nfs_fl.state = 0; |
507 | fl->fl_u.nfs_fl.flags = 0; | ||
508 | fl->fl_u.nfs_fl.owner = nlm_find_lockowner(host, fl->fl_owner); | 453 | fl->fl_u.nfs_fl.owner = nlm_find_lockowner(host, fl->fl_owner); |
454 | INIT_LIST_HEAD(&fl->fl_u.nfs_fl.list); | ||
509 | fl->fl_ops = &nlmclnt_lock_ops; | 455 | fl->fl_ops = &nlmclnt_lock_ops; |
510 | } | 456 | } |
511 | 457 | ||
@@ -552,57 +498,52 @@ nlmclnt_lock(struct nlm_rqst *req, struct file_lock *fl) | |||
552 | { | 498 | { |
553 | struct nlm_host *host = req->a_host; | 499 | struct nlm_host *host = req->a_host; |
554 | struct nlm_res *resp = &req->a_res; | 500 | struct nlm_res *resp = &req->a_res; |
555 | long timeout; | 501 | struct nlm_wait *block = NULL; |
556 | int status; | 502 | int status = -ENOLCK; |
557 | 503 | ||
558 | if (!host->h_monitored && nsm_monitor(host) < 0) { | 504 | if (!host->h_monitored && nsm_monitor(host) < 0) { |
559 | printk(KERN_NOTICE "lockd: failed to monitor %s\n", | 505 | printk(KERN_NOTICE "lockd: failed to monitor %s\n", |
560 | host->h_name); | 506 | host->h_name); |
561 | status = -ENOLCK; | ||
562 | goto out; | 507 | goto out; |
563 | } | 508 | } |
564 | 509 | ||
565 | if (req->a_args.block) { | 510 | block = nlmclnt_prepare_block(host, fl); |
566 | status = nlmclnt_prepare_block(req, host, fl); | ||
567 | if (status < 0) | ||
568 | goto out; | ||
569 | } | ||
570 | for(;;) { | 511 | for(;;) { |
571 | status = nlmclnt_call(req, NLMPROC_LOCK); | 512 | status = nlmclnt_call(req, NLMPROC_LOCK); |
572 | if (status < 0) | 513 | if (status < 0) |
573 | goto out_unblock; | 514 | goto out_unblock; |
574 | if (resp->status != NLM_LCK_BLOCKED) | 515 | if (!req->a_args.block) |
575 | break; | 516 | break; |
576 | /* Wait on an NLM blocking lock */ | ||
577 | timeout = nlmclnt_block(req, NLMCLNT_POLL_TIMEOUT); | ||
578 | /* Did a reclaimer thread notify us of a server reboot? */ | 517 | /* Did a reclaimer thread notify us of a server reboot? */ |
579 | if (resp->status == NLM_LCK_DENIED_GRACE_PERIOD) | 518 | if (resp->status == NLM_LCK_DENIED_GRACE_PERIOD) |
580 | continue; | 519 | continue; |
581 | if (resp->status != NLM_LCK_BLOCKED) | 520 | if (resp->status != NLM_LCK_BLOCKED) |
582 | break; | 521 | break; |
583 | if (timeout >= 0) | 522 | /* Wait on an NLM blocking lock */ |
584 | continue; | 523 | status = nlmclnt_block(block, req, NLMCLNT_POLL_TIMEOUT); |
585 | /* We were interrupted. Send a CANCEL request to the server | 524 | /* if we were interrupted. Send a CANCEL request to the server |
586 | * and exit | 525 | * and exit |
587 | */ | 526 | */ |
588 | status = (int)timeout; | 527 | if (status < 0) |
589 | goto out_unblock; | 528 | goto out_unblock; |
529 | if (resp->status != NLM_LCK_BLOCKED) | ||
530 | break; | ||
590 | } | 531 | } |
591 | 532 | ||
592 | if (resp->status == NLM_LCK_GRANTED) { | 533 | if (resp->status == NLM_LCK_GRANTED) { |
593 | fl->fl_u.nfs_fl.state = host->h_state; | 534 | fl->fl_u.nfs_fl.state = host->h_state; |
594 | fl->fl_u.nfs_fl.flags |= NFS_LCK_GRANTED; | ||
595 | fl->fl_flags |= FL_SLEEP; | 535 | fl->fl_flags |= FL_SLEEP; |
536 | /* Ensure the resulting lock will get added to granted list */ | ||
596 | do_vfs_lock(fl); | 537 | do_vfs_lock(fl); |
597 | } | 538 | } |
598 | status = nlm_stat_to_errno(resp->status); | 539 | status = nlm_stat_to_errno(resp->status); |
599 | out_unblock: | 540 | out_unblock: |
600 | nlmclnt_finish_block(req); | 541 | nlmclnt_finish_block(block); |
601 | /* Cancel the blocked request if it is still pending */ | 542 | /* Cancel the blocked request if it is still pending */ |
602 | if (resp->status == NLM_LCK_BLOCKED) | 543 | if (resp->status == NLM_LCK_BLOCKED) |
603 | nlmclnt_cancel(host, req->a_args.block, fl); | 544 | nlmclnt_cancel(host, req->a_args.block, fl); |
604 | out: | 545 | out: |
605 | nlmclnt_release_lockargs(req); | 546 | nlm_release_call(req); |
606 | return status; | 547 | return status; |
607 | } | 548 | } |
608 | 549 | ||
@@ -658,10 +599,6 @@ nlmclnt_unlock(struct nlm_rqst *req, struct file_lock *fl) | |||
658 | struct nlm_res *resp = &req->a_res; | 599 | struct nlm_res *resp = &req->a_res; |
659 | int status; | 600 | int status; |
660 | 601 | ||
661 | /* Clean the GRANTED flag now so the lock doesn't get | ||
662 | * reclaimed while we're stuck in the unlock call. */ | ||
663 | fl->fl_u.nfs_fl.flags &= ~NFS_LCK_GRANTED; | ||
664 | |||
665 | /* | 602 | /* |
666 | * Note: the server is supposed to either grant us the unlock | 603 | * Note: the server is supposed to either grant us the unlock |
667 | * request, or to deny it with NLM_LCK_DENIED_GRACE_PERIOD. In either | 604 | * request, or to deny it with NLM_LCK_DENIED_GRACE_PERIOD. In either |
@@ -669,32 +606,24 @@ nlmclnt_unlock(struct nlm_rqst *req, struct file_lock *fl) | |||
669 | */ | 606 | */ |
670 | do_vfs_lock(fl); | 607 | do_vfs_lock(fl); |
671 | 608 | ||
672 | if (req->a_flags & RPC_TASK_ASYNC) { | 609 | if (req->a_flags & RPC_TASK_ASYNC) |
673 | status = nlmclnt_async_call(req, NLMPROC_UNLOCK, | 610 | return nlm_async_call(req, NLMPROC_UNLOCK, &nlmclnt_unlock_ops); |
674 | &nlmclnt_unlock_ops); | ||
675 | /* Hrmf... Do the unlock early since locks_remove_posix() | ||
676 | * really expects us to free the lock synchronously */ | ||
677 | if (status < 0) { | ||
678 | nlmclnt_release_lockargs(req); | ||
679 | kfree(req); | ||
680 | } | ||
681 | return status; | ||
682 | } | ||
683 | 611 | ||
684 | status = nlmclnt_call(req, NLMPROC_UNLOCK); | 612 | status = nlmclnt_call(req, NLMPROC_UNLOCK); |
685 | nlmclnt_release_lockargs(req); | ||
686 | if (status < 0) | 613 | if (status < 0) |
687 | return status; | 614 | goto out; |
688 | 615 | ||
616 | status = 0; | ||
689 | if (resp->status == NLM_LCK_GRANTED) | 617 | if (resp->status == NLM_LCK_GRANTED) |
690 | return 0; | 618 | goto out; |
691 | 619 | ||
692 | if (resp->status != NLM_LCK_DENIED_NOLOCKS) | 620 | if (resp->status != NLM_LCK_DENIED_NOLOCKS) |
693 | printk("lockd: unexpected unlock status: %d\n", resp->status); | 621 | printk("lockd: unexpected unlock status: %d\n", resp->status); |
694 | |||
695 | /* What to do now? I'm out of my depth... */ | 622 | /* What to do now? I'm out of my depth... */ |
696 | 623 | status = -ENOLCK; | |
697 | return -ENOLCK; | 624 | out: |
625 | nlm_release_call(req); | ||
626 | return status; | ||
698 | } | 627 | } |
699 | 628 | ||
700 | static void nlmclnt_unlock_callback(struct rpc_task *task, void *data) | 629 | static void nlmclnt_unlock_callback(struct rpc_task *task, void *data) |
@@ -716,9 +645,6 @@ static void nlmclnt_unlock_callback(struct rpc_task *task, void *data) | |||
716 | if (status != NLM_LCK_GRANTED) | 645 | if (status != NLM_LCK_GRANTED) |
717 | printk(KERN_WARNING "lockd: unexpected unlock status: %d\n", status); | 646 | printk(KERN_WARNING "lockd: unexpected unlock status: %d\n", status); |
718 | die: | 647 | die: |
719 | nlm_release_host(req->a_host); | ||
720 | nlmclnt_release_lockargs(req); | ||
721 | kfree(req); | ||
722 | return; | 648 | return; |
723 | retry_rebind: | 649 | retry_rebind: |
724 | nlm_rebind_host(req->a_host); | 650 | nlm_rebind_host(req->a_host); |
@@ -728,6 +654,7 @@ die: | |||
728 | 654 | ||
729 | static const struct rpc_call_ops nlmclnt_unlock_ops = { | 655 | static const struct rpc_call_ops nlmclnt_unlock_ops = { |
730 | .rpc_call_done = nlmclnt_unlock_callback, | 656 | .rpc_call_done = nlmclnt_unlock_callback, |
657 | .rpc_release = nlmclnt_rpc_release, | ||
731 | }; | 658 | }; |
732 | 659 | ||
733 | /* | 660 | /* |
@@ -749,20 +676,15 @@ static int nlmclnt_cancel(struct nlm_host *host, int block, struct file_lock *fl | |||
749 | recalc_sigpending(); | 676 | recalc_sigpending(); |
750 | spin_unlock_irqrestore(¤t->sighand->siglock, flags); | 677 | spin_unlock_irqrestore(¤t->sighand->siglock, flags); |
751 | 678 | ||
752 | req = nlmclnt_alloc_call(); | 679 | req = nlm_alloc_call(nlm_get_host(host)); |
753 | if (!req) | 680 | if (!req) |
754 | return -ENOMEM; | 681 | return -ENOMEM; |
755 | req->a_host = host; | ||
756 | req->a_flags = RPC_TASK_ASYNC; | 682 | req->a_flags = RPC_TASK_ASYNC; |
757 | 683 | ||
758 | nlmclnt_setlockargs(req, fl); | 684 | nlmclnt_setlockargs(req, fl); |
759 | req->a_args.block = block; | 685 | req->a_args.block = block; |
760 | 686 | ||
761 | status = nlmclnt_async_call(req, NLMPROC_CANCEL, &nlmclnt_cancel_ops); | 687 | status = nlm_async_call(req, NLMPROC_CANCEL, &nlmclnt_cancel_ops); |
762 | if (status < 0) { | ||
763 | nlmclnt_release_lockargs(req); | ||
764 | kfree(req); | ||
765 | } | ||
766 | 688 | ||
767 | spin_lock_irqsave(¤t->sighand->siglock, flags); | 689 | spin_lock_irqsave(¤t->sighand->siglock, flags); |
768 | current->blocked = oldset; | 690 | current->blocked = oldset; |
@@ -791,6 +713,7 @@ static void nlmclnt_cancel_callback(struct rpc_task *task, void *data) | |||
791 | switch (req->a_res.status) { | 713 | switch (req->a_res.status) { |
792 | case NLM_LCK_GRANTED: | 714 | case NLM_LCK_GRANTED: |
793 | case NLM_LCK_DENIED_GRACE_PERIOD: | 715 | case NLM_LCK_DENIED_GRACE_PERIOD: |
716 | case NLM_LCK_DENIED: | ||
794 | /* Everything's good */ | 717 | /* Everything's good */ |
795 | break; | 718 | break; |
796 | case NLM_LCK_DENIED_NOLOCKS: | 719 | case NLM_LCK_DENIED_NOLOCKS: |
@@ -802,9 +725,6 @@ static void nlmclnt_cancel_callback(struct rpc_task *task, void *data) | |||
802 | } | 725 | } |
803 | 726 | ||
804 | die: | 727 | die: |
805 | nlm_release_host(req->a_host); | ||
806 | nlmclnt_release_lockargs(req); | ||
807 | kfree(req); | ||
808 | return; | 728 | return; |
809 | 729 | ||
810 | retry_cancel: | 730 | retry_cancel: |
@@ -818,6 +738,7 @@ retry_cancel: | |||
818 | 738 | ||
819 | static const struct rpc_call_ops nlmclnt_cancel_ops = { | 739 | static const struct rpc_call_ops nlmclnt_cancel_ops = { |
820 | .rpc_call_done = nlmclnt_cancel_callback, | 740 | .rpc_call_done = nlmclnt_cancel_callback, |
741 | .rpc_release = nlmclnt_rpc_release, | ||
821 | }; | 742 | }; |
822 | 743 | ||
823 | /* | 744 | /* |