diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2008-04-24 14:46:16 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2008-04-24 14:46:16 -0400 |
commit | 563307b2fa15d687abc54bd980b9847ebf0e3231 (patch) | |
tree | 7f16be30217a2e66360ede97aa27d07a4ebd7e55 /fs/lockd | |
parent | 10c993a6b5418cb1026775765ba4c70ffb70853d (diff) | |
parent | 233607dbbc823caf685e778cabc49fb7f679900b (diff) |
Merge git://git.linux-nfs.org/projects/trondmy/nfs-2.6
* git://git.linux-nfs.org/projects/trondmy/nfs-2.6: (80 commits)
SUNRPC: Invalidate the RPCSEC_GSS session if the server dropped the request
make nfs_automount_list static
NFS: remove duplicate flags assignment from nfs_validate_mount_data
NFS - fix potential NULL pointer dereference v2
SUNRPC: Don't change the RPCSEC_GSS context on a credential that is in use
SUNRPC: Fix a race in gss_refresh_upcall()
SUNRPC: Don't disconnect more than once if retransmitting NFSv4 requests
SUNRPC: Remove the unused export of xprt_force_disconnect
SUNRPC: remove XS_SENDMSG_RETRY
SUNRPC: Protect creds against early garbage collection
NFSv4: Attempt to use machine credentials in SETCLIENTID calls
NFSv4: Reintroduce machine creds
NFSv4: Don't use cred->cr_ops->cr_name in nfs4_proc_setclientid()
nfs: fix printout of multiword bitfields
nfs: return negative error value from nfs{,4}_stat_to_errno
NLM/lockd: Ensure client locking calls use correct credentials
NFS: Remove the buggy lock-if-signalled case from do_setlk()
NLM/lockd: Fix a race when cancelling a blocking lock
NLM/lockd: Ensure that nlmclnt_cancel() returns results of the CANCEL call
NLM: Remove the signal masking in nlmclnt_proc/nlmclnt_cancel
...
Diffstat (limited to 'fs/lockd')
-rw-r--r-- | fs/lockd/clntproc.c | 184 | ||||
-rw-r--r-- | fs/lockd/host.c | 20 | ||||
-rw-r--r-- | fs/lockd/mon.c | 113 | ||||
-rw-r--r-- | fs/lockd/svc.c | 12 |
4 files changed, 227 insertions, 102 deletions
diff --git a/fs/lockd/clntproc.c b/fs/lockd/clntproc.c index b6b74a60e1eb..40b16f23e49a 100644 --- a/fs/lockd/clntproc.c +++ b/fs/lockd/clntproc.c | |||
@@ -155,8 +155,6 @@ static void nlmclnt_release_lockargs(struct nlm_rqst *req) | |||
155 | int nlmclnt_proc(struct nlm_host *host, int cmd, struct file_lock *fl) | 155 | int nlmclnt_proc(struct nlm_host *host, int cmd, struct file_lock *fl) |
156 | { | 156 | { |
157 | struct nlm_rqst *call; | 157 | struct nlm_rqst *call; |
158 | sigset_t oldset; | ||
159 | unsigned long flags; | ||
160 | int status; | 158 | int status; |
161 | 159 | ||
162 | nlm_get_host(host); | 160 | nlm_get_host(host); |
@@ -168,22 +166,6 @@ int nlmclnt_proc(struct nlm_host *host, int cmd, struct file_lock *fl) | |||
168 | /* Set up the argument struct */ | 166 | /* Set up the argument struct */ |
169 | nlmclnt_setlockargs(call, fl); | 167 | nlmclnt_setlockargs(call, fl); |
170 | 168 | ||
171 | /* Keep the old signal mask */ | ||
172 | spin_lock_irqsave(¤t->sighand->siglock, flags); | ||
173 | oldset = current->blocked; | ||
174 | |||
175 | /* If we're cleaning up locks because the process is exiting, | ||
176 | * perform the RPC call asynchronously. */ | ||
177 | if ((IS_SETLK(cmd) || IS_SETLKW(cmd)) | ||
178 | && fl->fl_type == F_UNLCK | ||
179 | && (current->flags & PF_EXITING)) { | ||
180 | sigfillset(¤t->blocked); /* Mask all signals */ | ||
181 | recalc_sigpending(); | ||
182 | |||
183 | call->a_flags = RPC_TASK_ASYNC; | ||
184 | } | ||
185 | spin_unlock_irqrestore(¤t->sighand->siglock, flags); | ||
186 | |||
187 | if (IS_SETLK(cmd) || IS_SETLKW(cmd)) { | 169 | if (IS_SETLK(cmd) || IS_SETLKW(cmd)) { |
188 | if (fl->fl_type != F_UNLCK) { | 170 | if (fl->fl_type != F_UNLCK) { |
189 | call->a_args.block = IS_SETLKW(cmd) ? 1 : 0; | 171 | call->a_args.block = IS_SETLKW(cmd) ? 1 : 0; |
@@ -198,11 +180,6 @@ int nlmclnt_proc(struct nlm_host *host, int cmd, struct file_lock *fl) | |||
198 | fl->fl_ops->fl_release_private(fl); | 180 | fl->fl_ops->fl_release_private(fl); |
199 | fl->fl_ops = NULL; | 181 | fl->fl_ops = NULL; |
200 | 182 | ||
201 | spin_lock_irqsave(¤t->sighand->siglock, flags); | ||
202 | current->blocked = oldset; | ||
203 | recalc_sigpending(); | ||
204 | spin_unlock_irqrestore(¤t->sighand->siglock, flags); | ||
205 | |||
206 | dprintk("lockd: clnt proc returns %d\n", status); | 183 | dprintk("lockd: clnt proc returns %d\n", status); |
207 | return status; | 184 | return status; |
208 | } | 185 | } |
@@ -221,6 +198,7 @@ struct nlm_rqst *nlm_alloc_call(struct nlm_host *host) | |||
221 | for(;;) { | 198 | for(;;) { |
222 | call = kzalloc(sizeof(*call), GFP_KERNEL); | 199 | call = kzalloc(sizeof(*call), GFP_KERNEL); |
223 | if (call != NULL) { | 200 | if (call != NULL) { |
201 | atomic_set(&call->a_count, 1); | ||
224 | locks_init_lock(&call->a_args.lock.fl); | 202 | locks_init_lock(&call->a_args.lock.fl); |
225 | locks_init_lock(&call->a_res.lock.fl); | 203 | locks_init_lock(&call->a_res.lock.fl); |
226 | call->a_host = host; | 204 | call->a_host = host; |
@@ -237,6 +215,8 @@ struct nlm_rqst *nlm_alloc_call(struct nlm_host *host) | |||
237 | 215 | ||
238 | void nlm_release_call(struct nlm_rqst *call) | 216 | void nlm_release_call(struct nlm_rqst *call) |
239 | { | 217 | { |
218 | if (!atomic_dec_and_test(&call->a_count)) | ||
219 | return; | ||
240 | nlm_release_host(call->a_host); | 220 | nlm_release_host(call->a_host); |
241 | nlmclnt_release_lockargs(call); | 221 | nlmclnt_release_lockargs(call); |
242 | kfree(call); | 222 | kfree(call); |
@@ -267,7 +247,7 @@ static int nlm_wait_on_grace(wait_queue_head_t *queue) | |||
267 | * Generic NLM call | 247 | * Generic NLM call |
268 | */ | 248 | */ |
269 | static int | 249 | static int |
270 | nlmclnt_call(struct nlm_rqst *req, u32 proc) | 250 | nlmclnt_call(struct rpc_cred *cred, struct nlm_rqst *req, u32 proc) |
271 | { | 251 | { |
272 | struct nlm_host *host = req->a_host; | 252 | struct nlm_host *host = req->a_host; |
273 | struct rpc_clnt *clnt; | 253 | struct rpc_clnt *clnt; |
@@ -276,6 +256,7 @@ nlmclnt_call(struct nlm_rqst *req, u32 proc) | |||
276 | struct rpc_message msg = { | 256 | struct rpc_message msg = { |
277 | .rpc_argp = argp, | 257 | .rpc_argp = argp, |
278 | .rpc_resp = resp, | 258 | .rpc_resp = resp, |
259 | .rpc_cred = cred, | ||
279 | }; | 260 | }; |
280 | int status; | 261 | int status; |
281 | 262 | ||
@@ -343,10 +324,16 @@ in_grace_period: | |||
343 | /* | 324 | /* |
344 | * Generic NLM call, async version. | 325 | * Generic NLM call, async version. |
345 | */ | 326 | */ |
346 | static int __nlm_async_call(struct nlm_rqst *req, u32 proc, struct rpc_message *msg, const struct rpc_call_ops *tk_ops) | 327 | static struct rpc_task *__nlm_async_call(struct nlm_rqst *req, u32 proc, struct rpc_message *msg, const struct rpc_call_ops *tk_ops) |
347 | { | 328 | { |
348 | struct nlm_host *host = req->a_host; | 329 | struct nlm_host *host = req->a_host; |
349 | struct rpc_clnt *clnt; | 330 | struct rpc_clnt *clnt; |
331 | struct rpc_task_setup task_setup_data = { | ||
332 | .rpc_message = msg, | ||
333 | .callback_ops = tk_ops, | ||
334 | .callback_data = req, | ||
335 | .flags = RPC_TASK_ASYNC, | ||
336 | }; | ||
350 | 337 | ||
351 | dprintk("lockd: call procedure %d on %s (async)\n", | 338 | dprintk("lockd: call procedure %d on %s (async)\n", |
352 | (int)proc, host->h_name); | 339 | (int)proc, host->h_name); |
@@ -356,21 +343,36 @@ static int __nlm_async_call(struct nlm_rqst *req, u32 proc, struct rpc_message * | |||
356 | if (clnt == NULL) | 343 | if (clnt == NULL) |
357 | goto out_err; | 344 | goto out_err; |
358 | msg->rpc_proc = &clnt->cl_procinfo[proc]; | 345 | msg->rpc_proc = &clnt->cl_procinfo[proc]; |
346 | task_setup_data.rpc_client = clnt; | ||
359 | 347 | ||
360 | /* bootstrap and kick off the async RPC call */ | 348 | /* bootstrap and kick off the async RPC call */ |
361 | return rpc_call_async(clnt, msg, RPC_TASK_ASYNC, tk_ops, req); | 349 | return rpc_run_task(&task_setup_data); |
362 | out_err: | 350 | out_err: |
363 | tk_ops->rpc_release(req); | 351 | tk_ops->rpc_release(req); |
364 | return -ENOLCK; | 352 | return ERR_PTR(-ENOLCK); |
365 | } | 353 | } |
366 | 354 | ||
355 | static int nlm_do_async_call(struct nlm_rqst *req, u32 proc, struct rpc_message *msg, const struct rpc_call_ops *tk_ops) | ||
356 | { | ||
357 | struct rpc_task *task; | ||
358 | |||
359 | task = __nlm_async_call(req, proc, msg, tk_ops); | ||
360 | if (IS_ERR(task)) | ||
361 | return PTR_ERR(task); | ||
362 | rpc_put_task(task); | ||
363 | return 0; | ||
364 | } | ||
365 | |||
366 | /* | ||
367 | * NLM asynchronous call. | ||
368 | */ | ||
367 | int nlm_async_call(struct nlm_rqst *req, u32 proc, const struct rpc_call_ops *tk_ops) | 369 | int nlm_async_call(struct nlm_rqst *req, u32 proc, const struct rpc_call_ops *tk_ops) |
368 | { | 370 | { |
369 | struct rpc_message msg = { | 371 | struct rpc_message msg = { |
370 | .rpc_argp = &req->a_args, | 372 | .rpc_argp = &req->a_args, |
371 | .rpc_resp = &req->a_res, | 373 | .rpc_resp = &req->a_res, |
372 | }; | 374 | }; |
373 | return __nlm_async_call(req, proc, &msg, tk_ops); | 375 | return nlm_do_async_call(req, proc, &msg, tk_ops); |
374 | } | 376 | } |
375 | 377 | ||
376 | int nlm_async_reply(struct nlm_rqst *req, u32 proc, const struct rpc_call_ops *tk_ops) | 378 | int nlm_async_reply(struct nlm_rqst *req, u32 proc, const struct rpc_call_ops *tk_ops) |
@@ -378,7 +380,33 @@ int nlm_async_reply(struct nlm_rqst *req, u32 proc, const struct rpc_call_ops *t | |||
378 | struct rpc_message msg = { | 380 | struct rpc_message msg = { |
379 | .rpc_argp = &req->a_res, | 381 | .rpc_argp = &req->a_res, |
380 | }; | 382 | }; |
381 | return __nlm_async_call(req, proc, &msg, tk_ops); | 383 | return nlm_do_async_call(req, proc, &msg, tk_ops); |
384 | } | ||
385 | |||
386 | /* | ||
387 | * NLM client asynchronous call. | ||
388 | * | ||
389 | * Note that although the calls are asynchronous, and are therefore | ||
390 | * guaranteed to complete, we still always attempt to wait for | ||
391 | * completion in order to be able to correctly track the lock | ||
392 | * state. | ||
393 | */ | ||
394 | static int nlmclnt_async_call(struct rpc_cred *cred, struct nlm_rqst *req, u32 proc, const struct rpc_call_ops *tk_ops) | ||
395 | { | ||
396 | struct rpc_message msg = { | ||
397 | .rpc_argp = &req->a_args, | ||
398 | .rpc_resp = &req->a_res, | ||
399 | .rpc_cred = cred, | ||
400 | }; | ||
401 | struct rpc_task *task; | ||
402 | int err; | ||
403 | |||
404 | task = __nlm_async_call(req, proc, &msg, tk_ops); | ||
405 | if (IS_ERR(task)) | ||
406 | return PTR_ERR(task); | ||
407 | err = rpc_wait_for_completion_task(task); | ||
408 | rpc_put_task(task); | ||
409 | return err; | ||
382 | } | 410 | } |
383 | 411 | ||
384 | /* | 412 | /* |
@@ -389,7 +417,7 @@ nlmclnt_test(struct nlm_rqst *req, struct file_lock *fl) | |||
389 | { | 417 | { |
390 | int status; | 418 | int status; |
391 | 419 | ||
392 | status = nlmclnt_call(req, NLMPROC_TEST); | 420 | status = nlmclnt_call(nfs_file_cred(fl->fl_file), req, NLMPROC_TEST); |
393 | if (status < 0) | 421 | if (status < 0) |
394 | goto out; | 422 | goto out; |
395 | 423 | ||
@@ -480,10 +508,12 @@ static int do_vfs_lock(struct file_lock *fl) | |||
480 | static int | 508 | static int |
481 | nlmclnt_lock(struct nlm_rqst *req, struct file_lock *fl) | 509 | nlmclnt_lock(struct nlm_rqst *req, struct file_lock *fl) |
482 | { | 510 | { |
511 | struct rpc_cred *cred = nfs_file_cred(fl->fl_file); | ||
483 | struct nlm_host *host = req->a_host; | 512 | struct nlm_host *host = req->a_host; |
484 | struct nlm_res *resp = &req->a_res; | 513 | struct nlm_res *resp = &req->a_res; |
485 | struct nlm_wait *block = NULL; | 514 | struct nlm_wait *block = NULL; |
486 | unsigned char fl_flags = fl->fl_flags; | 515 | unsigned char fl_flags = fl->fl_flags; |
516 | unsigned char fl_type; | ||
487 | int status = -ENOLCK; | 517 | int status = -ENOLCK; |
488 | 518 | ||
489 | if (nsm_monitor(host) < 0) { | 519 | if (nsm_monitor(host) < 0) { |
@@ -493,18 +523,22 @@ nlmclnt_lock(struct nlm_rqst *req, struct file_lock *fl) | |||
493 | } | 523 | } |
494 | fl->fl_flags |= FL_ACCESS; | 524 | fl->fl_flags |= FL_ACCESS; |
495 | status = do_vfs_lock(fl); | 525 | status = do_vfs_lock(fl); |
526 | fl->fl_flags = fl_flags; | ||
496 | if (status < 0) | 527 | if (status < 0) |
497 | goto out; | 528 | goto out; |
498 | 529 | ||
499 | block = nlmclnt_prepare_block(host, fl); | 530 | block = nlmclnt_prepare_block(host, fl); |
500 | again: | 531 | again: |
532 | /* | ||
533 | * Initialise resp->status to a valid non-zero value, | ||
534 | * since 0 == nlm_lck_granted | ||
535 | */ | ||
536 | resp->status = nlm_lck_blocked; | ||
501 | for(;;) { | 537 | for(;;) { |
502 | /* Reboot protection */ | 538 | /* Reboot protection */ |
503 | fl->fl_u.nfs_fl.state = host->h_state; | 539 | fl->fl_u.nfs_fl.state = host->h_state; |
504 | status = nlmclnt_call(req, NLMPROC_LOCK); | 540 | status = nlmclnt_call(cred, req, NLMPROC_LOCK); |
505 | if (status < 0) | 541 | if (status < 0) |
506 | goto out_unblock; | ||
507 | if (!req->a_args.block) | ||
508 | break; | 542 | break; |
509 | /* Did a reclaimer thread notify us of a server reboot? */ | 543 | /* Did a reclaimer thread notify us of a server reboot? */ |
510 | if (resp->status == nlm_lck_denied_grace_period) | 544 | if (resp->status == nlm_lck_denied_grace_period) |
@@ -513,15 +547,22 @@ again: | |||
513 | break; | 547 | break; |
514 | /* Wait on an NLM blocking lock */ | 548 | /* Wait on an NLM blocking lock */ |
515 | status = nlmclnt_block(block, req, NLMCLNT_POLL_TIMEOUT); | 549 | status = nlmclnt_block(block, req, NLMCLNT_POLL_TIMEOUT); |
516 | /* if we were interrupted. Send a CANCEL request to the server | ||
517 | * and exit | ||
518 | */ | ||
519 | if (status < 0) | 550 | if (status < 0) |
520 | goto out_unblock; | 551 | break; |
521 | if (resp->status != nlm_lck_blocked) | 552 | if (resp->status != nlm_lck_blocked) |
522 | break; | 553 | break; |
523 | } | 554 | } |
524 | 555 | ||
556 | /* if we were interrupted while blocking, then cancel the lock request | ||
557 | * and exit | ||
558 | */ | ||
559 | if (resp->status == nlm_lck_blocked) { | ||
560 | if (!req->a_args.block) | ||
561 | goto out_unlock; | ||
562 | if (nlmclnt_cancel(host, req->a_args.block, fl) == 0) | ||
563 | goto out_unblock; | ||
564 | } | ||
565 | |||
525 | if (resp->status == nlm_granted) { | 566 | if (resp->status == nlm_granted) { |
526 | down_read(&host->h_rwsem); | 567 | down_read(&host->h_rwsem); |
527 | /* Check whether or not the server has rebooted */ | 568 | /* Check whether or not the server has rebooted */ |
@@ -530,20 +571,34 @@ again: | |||
530 | goto again; | 571 | goto again; |
531 | } | 572 | } |
532 | /* Ensure the resulting lock will get added to granted list */ | 573 | /* Ensure the resulting lock will get added to granted list */ |
533 | fl->fl_flags = fl_flags | FL_SLEEP; | 574 | fl->fl_flags |= FL_SLEEP; |
534 | if (do_vfs_lock(fl) < 0) | 575 | if (do_vfs_lock(fl) < 0) |
535 | printk(KERN_WARNING "%s: VFS is out of sync with lock manager!\n", __FUNCTION__); | 576 | printk(KERN_WARNING "%s: VFS is out of sync with lock manager!\n", __FUNCTION__); |
536 | up_read(&host->h_rwsem); | 577 | up_read(&host->h_rwsem); |
578 | fl->fl_flags = fl_flags; | ||
579 | status = 0; | ||
537 | } | 580 | } |
581 | if (status < 0) | ||
582 | goto out_unlock; | ||
538 | status = nlm_stat_to_errno(resp->status); | 583 | status = nlm_stat_to_errno(resp->status); |
539 | out_unblock: | 584 | out_unblock: |
540 | nlmclnt_finish_block(block); | 585 | nlmclnt_finish_block(block); |
541 | /* Cancel the blocked request if it is still pending */ | ||
542 | if (resp->status == nlm_lck_blocked) | ||
543 | nlmclnt_cancel(host, req->a_args.block, fl); | ||
544 | out: | 586 | out: |
545 | nlm_release_call(req); | 587 | nlm_release_call(req); |
588 | return status; | ||
589 | out_unlock: | ||
590 | /* Fatal error: ensure that we remove the lock altogether */ | ||
591 | dprintk("lockd: lock attempt ended in fatal error.\n" | ||
592 | " Attempting to unlock.\n"); | ||
593 | nlmclnt_finish_block(block); | ||
594 | fl_type = fl->fl_type; | ||
595 | fl->fl_type = F_UNLCK; | ||
596 | down_read(&host->h_rwsem); | ||
597 | do_vfs_lock(fl); | ||
598 | up_read(&host->h_rwsem); | ||
599 | fl->fl_type = fl_type; | ||
546 | fl->fl_flags = fl_flags; | 600 | fl->fl_flags = fl_flags; |
601 | nlmclnt_async_call(cred, req, NLMPROC_UNLOCK, &nlmclnt_unlock_ops); | ||
547 | return status; | 602 | return status; |
548 | } | 603 | } |
549 | 604 | ||
@@ -567,8 +622,8 @@ nlmclnt_reclaim(struct nlm_host *host, struct file_lock *fl) | |||
567 | nlmclnt_setlockargs(req, fl); | 622 | nlmclnt_setlockargs(req, fl); |
568 | req->a_args.reclaim = 1; | 623 | req->a_args.reclaim = 1; |
569 | 624 | ||
570 | if ((status = nlmclnt_call(req, NLMPROC_LOCK)) >= 0 | 625 | status = nlmclnt_call(nfs_file_cred(fl->fl_file), req, NLMPROC_LOCK); |
571 | && req->a_res.status == nlm_granted) | 626 | if (status >= 0 && req->a_res.status == nlm_granted) |
572 | return 0; | 627 | return 0; |
573 | 628 | ||
574 | printk(KERN_WARNING "lockd: failed to reclaim lock for pid %d " | 629 | printk(KERN_WARNING "lockd: failed to reclaim lock for pid %d " |
@@ -598,7 +653,8 @@ nlmclnt_unlock(struct nlm_rqst *req, struct file_lock *fl) | |||
598 | { | 653 | { |
599 | struct nlm_host *host = req->a_host; | 654 | struct nlm_host *host = req->a_host; |
600 | struct nlm_res *resp = &req->a_res; | 655 | struct nlm_res *resp = &req->a_res; |
601 | int status = 0; | 656 | int status; |
657 | unsigned char fl_flags = fl->fl_flags; | ||
602 | 658 | ||
603 | /* | 659 | /* |
604 | * Note: the server is supposed to either grant us the unlock | 660 | * Note: the server is supposed to either grant us the unlock |
@@ -607,16 +663,17 @@ nlmclnt_unlock(struct nlm_rqst *req, struct file_lock *fl) | |||
607 | */ | 663 | */ |
608 | fl->fl_flags |= FL_EXISTS; | 664 | fl->fl_flags |= FL_EXISTS; |
609 | down_read(&host->h_rwsem); | 665 | down_read(&host->h_rwsem); |
610 | if (do_vfs_lock(fl) == -ENOENT) { | 666 | status = do_vfs_lock(fl); |
611 | up_read(&host->h_rwsem); | 667 | up_read(&host->h_rwsem); |
668 | fl->fl_flags = fl_flags; | ||
669 | if (status == -ENOENT) { | ||
670 | status = 0; | ||
612 | goto out; | 671 | goto out; |
613 | } | 672 | } |
614 | up_read(&host->h_rwsem); | ||
615 | |||
616 | if (req->a_flags & RPC_TASK_ASYNC) | ||
617 | return nlm_async_call(req, NLMPROC_UNLOCK, &nlmclnt_unlock_ops); | ||
618 | 673 | ||
619 | status = nlmclnt_call(req, NLMPROC_UNLOCK); | 674 | atomic_inc(&req->a_count); |
675 | status = nlmclnt_async_call(nfs_file_cred(fl->fl_file), req, | ||
676 | NLMPROC_UNLOCK, &nlmclnt_unlock_ops); | ||
620 | if (status < 0) | 677 | if (status < 0) |
621 | goto out; | 678 | goto out; |
622 | 679 | ||
@@ -671,16 +728,10 @@ static const struct rpc_call_ops nlmclnt_unlock_ops = { | |||
671 | static int nlmclnt_cancel(struct nlm_host *host, int block, struct file_lock *fl) | 728 | static int nlmclnt_cancel(struct nlm_host *host, int block, struct file_lock *fl) |
672 | { | 729 | { |
673 | struct nlm_rqst *req; | 730 | struct nlm_rqst *req; |
674 | unsigned long flags; | 731 | int status; |
675 | sigset_t oldset; | ||
676 | int status; | ||
677 | 732 | ||
678 | /* Block all signals while setting up call */ | 733 | dprintk("lockd: blocking lock attempt was interrupted by a signal.\n" |
679 | spin_lock_irqsave(¤t->sighand->siglock, flags); | 734 | " Attempting to cancel lock.\n"); |
680 | oldset = current->blocked; | ||
681 | sigfillset(¤t->blocked); | ||
682 | recalc_sigpending(); | ||
683 | spin_unlock_irqrestore(¤t->sighand->siglock, flags); | ||
684 | 735 | ||
685 | req = nlm_alloc_call(nlm_get_host(host)); | 736 | req = nlm_alloc_call(nlm_get_host(host)); |
686 | if (!req) | 737 | if (!req) |
@@ -690,13 +741,12 @@ static int nlmclnt_cancel(struct nlm_host *host, int block, struct file_lock *fl | |||
690 | nlmclnt_setlockargs(req, fl); | 741 | nlmclnt_setlockargs(req, fl); |
691 | req->a_args.block = block; | 742 | req->a_args.block = block; |
692 | 743 | ||
693 | status = nlm_async_call(req, NLMPROC_CANCEL, &nlmclnt_cancel_ops); | 744 | atomic_inc(&req->a_count); |
694 | 745 | status = nlmclnt_async_call(nfs_file_cred(fl->fl_file), req, | |
695 | spin_lock_irqsave(¤t->sighand->siglock, flags); | 746 | NLMPROC_CANCEL, &nlmclnt_cancel_ops); |
696 | current->blocked = oldset; | 747 | if (status == 0 && req->a_res.status == nlm_lck_denied) |
697 | recalc_sigpending(); | 748 | status = -ENOLCK; |
698 | spin_unlock_irqrestore(¤t->sighand->siglock, flags); | 749 | nlm_release_call(req); |
699 | |||
700 | return status; | 750 | return status; |
701 | } | 751 | } |
702 | 752 | ||
diff --git a/fs/lockd/host.c b/fs/lockd/host.c index c7854791898f..a17664c7eacc 100644 --- a/fs/lockd/host.c +++ b/fs/lockd/host.c | |||
@@ -41,11 +41,12 @@ static struct nsm_handle * nsm_find(const struct sockaddr_in *sin, | |||
41 | /* | 41 | /* |
42 | * Common host lookup routine for server & client | 42 | * Common host lookup routine for server & client |
43 | */ | 43 | */ |
44 | static struct nlm_host * | 44 | static struct nlm_host *nlm_lookup_host(int server, |
45 | nlm_lookup_host(int server, const struct sockaddr_in *sin, | 45 | const struct sockaddr_in *sin, |
46 | int proto, int version, const char *hostname, | 46 | int proto, u32 version, |
47 | unsigned int hostname_len, | 47 | const char *hostname, |
48 | const struct sockaddr_in *ssin) | 48 | unsigned int hostname_len, |
49 | const struct sockaddr_in *ssin) | ||
49 | { | 50 | { |
50 | struct hlist_head *chain; | 51 | struct hlist_head *chain; |
51 | struct hlist_node *pos; | 52 | struct hlist_node *pos; |
@@ -54,7 +55,7 @@ nlm_lookup_host(int server, const struct sockaddr_in *sin, | |||
54 | int hash; | 55 | int hash; |
55 | 56 | ||
56 | dprintk("lockd: nlm_lookup_host("NIPQUAD_FMT"->"NIPQUAD_FMT | 57 | dprintk("lockd: nlm_lookup_host("NIPQUAD_FMT"->"NIPQUAD_FMT |
57 | ", p=%d, v=%d, my role=%s, name=%.*s)\n", | 58 | ", p=%d, v=%u, my role=%s, name=%.*s)\n", |
58 | NIPQUAD(ssin->sin_addr.s_addr), | 59 | NIPQUAD(ssin->sin_addr.s_addr), |
59 | NIPQUAD(sin->sin_addr.s_addr), proto, version, | 60 | NIPQUAD(sin->sin_addr.s_addr), proto, version, |
60 | server? "server" : "client", | 61 | server? "server" : "client", |
@@ -172,9 +173,10 @@ nlm_destroy_host(struct nlm_host *host) | |||
172 | /* | 173 | /* |
173 | * Find an NLM server handle in the cache. If there is none, create it. | 174 | * Find an NLM server handle in the cache. If there is none, create it. |
174 | */ | 175 | */ |
175 | struct nlm_host * | 176 | struct nlm_host *nlmclnt_lookup_host(const struct sockaddr_in *sin, |
176 | nlmclnt_lookup_host(const struct sockaddr_in *sin, int proto, int version, | 177 | int proto, u32 version, |
177 | const char *hostname, unsigned int hostname_len) | 178 | const char *hostname, |
179 | unsigned int hostname_len) | ||
178 | { | 180 | { |
179 | struct sockaddr_in ssin = {0}; | 181 | struct sockaddr_in ssin = {0}; |
180 | 182 | ||
diff --git a/fs/lockd/mon.c b/fs/lockd/mon.c index 908b23fadd05..e4d563543b11 100644 --- a/fs/lockd/mon.c +++ b/fs/lockd/mon.c | |||
@@ -18,6 +18,8 @@ | |||
18 | 18 | ||
19 | #define NLMDBG_FACILITY NLMDBG_MONITOR | 19 | #define NLMDBG_FACILITY NLMDBG_MONITOR |
20 | 20 | ||
21 | #define XDR_ADDRBUF_LEN (20) | ||
22 | |||
21 | static struct rpc_clnt * nsm_create(void); | 23 | static struct rpc_clnt * nsm_create(void); |
22 | 24 | ||
23 | static struct rpc_program nsm_program; | 25 | static struct rpc_program nsm_program; |
@@ -147,28 +149,55 @@ nsm_create(void) | |||
147 | 149 | ||
148 | /* | 150 | /* |
149 | * XDR functions for NSM. | 151 | * XDR functions for NSM. |
152 | * | ||
153 | * See http://www.opengroup.org/ for details on the Network | ||
154 | * Status Monitor wire protocol. | ||
150 | */ | 155 | */ |
151 | 156 | ||
152 | static __be32 * | 157 | static __be32 *xdr_encode_nsm_string(__be32 *p, char *string) |
153 | xdr_encode_common(struct rpc_rqst *rqstp, __be32 *p, struct nsm_args *argp) | ||
154 | { | 158 | { |
155 | char buffer[20], *name; | 159 | size_t len = strlen(string); |
156 | 160 | ||
157 | /* | 161 | if (len > SM_MAXSTRLEN) |
158 | * Use the dotted-quad IP address of the remote host as | 162 | len = SM_MAXSTRLEN; |
159 | * identifier. Linux statd always looks up the canonical | 163 | return xdr_encode_opaque(p, string, len); |
160 | * hostname first for whatever remote hostname it receives, | 164 | } |
161 | * so this works alright. | 165 | |
162 | */ | 166 | /* |
163 | if (nsm_use_hostnames) { | 167 | * "mon_name" specifies the host to be monitored. |
164 | name = argp->mon_name; | 168 | * |
165 | } else { | 169 | * Linux uses a text version of the IP address of the remote |
166 | sprintf(buffer, "%u.%u.%u.%u", NIPQUAD(argp->addr)); | 170 | * host as the host identifier (the "mon_name" argument). |
171 | * | ||
172 | * Linux statd always looks up the canonical hostname first for | ||
173 | * whatever remote hostname it receives, so this works alright. | ||
174 | */ | ||
175 | static __be32 *xdr_encode_mon_name(__be32 *p, struct nsm_args *argp) | ||
176 | { | ||
177 | char buffer[XDR_ADDRBUF_LEN + 1]; | ||
178 | char *name = argp->mon_name; | ||
179 | |||
180 | if (!nsm_use_hostnames) { | ||
181 | snprintf(buffer, XDR_ADDRBUF_LEN, | ||
182 | NIPQUAD_FMT, NIPQUAD(argp->addr)); | ||
167 | name = buffer; | 183 | name = buffer; |
168 | } | 184 | } |
169 | if (!(p = xdr_encode_string(p, name)) | 185 | |
170 | || !(p = xdr_encode_string(p, utsname()->nodename))) | 186 | return xdr_encode_nsm_string(p, name); |
187 | } | ||
188 | |||
189 | /* | ||
190 | * The "my_id" argument specifies the hostname and RPC procedure | ||
191 | * to be called when the status manager receives notification | ||
192 | * (via the SM_NOTIFY call) that the state of host "mon_name" | ||
193 | * has changed. | ||
194 | */ | ||
195 | static __be32 *xdr_encode_my_id(__be32 *p, struct nsm_args *argp) | ||
196 | { | ||
197 | p = xdr_encode_nsm_string(p, utsname()->nodename); | ||
198 | if (!p) | ||
171 | return ERR_PTR(-EIO); | 199 | return ERR_PTR(-EIO); |
200 | |||
172 | *p++ = htonl(argp->prog); | 201 | *p++ = htonl(argp->prog); |
173 | *p++ = htonl(argp->vers); | 202 | *p++ = htonl(argp->vers); |
174 | *p++ = htonl(argp->proc); | 203 | *p++ = htonl(argp->proc); |
@@ -176,18 +205,48 @@ xdr_encode_common(struct rpc_rqst *rqstp, __be32 *p, struct nsm_args *argp) | |||
176 | return p; | 205 | return p; |
177 | } | 206 | } |
178 | 207 | ||
179 | static int | 208 | /* |
180 | xdr_encode_mon(struct rpc_rqst *rqstp, __be32 *p, struct nsm_args *argp) | 209 | * The "mon_id" argument specifies the non-private arguments |
210 | * of an SM_MON or SM_UNMON call. | ||
211 | */ | ||
212 | static __be32 *xdr_encode_mon_id(__be32 *p, struct nsm_args *argp) | ||
181 | { | 213 | { |
182 | p = xdr_encode_common(rqstp, p, argp); | 214 | p = xdr_encode_mon_name(p, argp); |
183 | if (IS_ERR(p)) | 215 | if (!p) |
184 | return PTR_ERR(p); | 216 | return ERR_PTR(-EIO); |
185 | 217 | ||
186 | /* Surprise - there may even be room for an IPv6 address now */ | 218 | return xdr_encode_my_id(p, argp); |
219 | } | ||
220 | |||
221 | /* | ||
222 | * The "priv" argument may contain private information required | ||
223 | * by the SM_MON call. This information will be supplied in the | ||
224 | * SM_NOTIFY call. | ||
225 | * | ||
226 | * Linux provides the raw IP address of the monitored host, | ||
227 | * left in network byte order. | ||
228 | */ | ||
229 | static __be32 *xdr_encode_priv(__be32 *p, struct nsm_args *argp) | ||
230 | { | ||
187 | *p++ = argp->addr; | 231 | *p++ = argp->addr; |
188 | *p++ = 0; | 232 | *p++ = 0; |
189 | *p++ = 0; | 233 | *p++ = 0; |
190 | *p++ = 0; | 234 | *p++ = 0; |
235 | |||
236 | return p; | ||
237 | } | ||
238 | |||
239 | static int | ||
240 | xdr_encode_mon(struct rpc_rqst *rqstp, __be32 *p, struct nsm_args *argp) | ||
241 | { | ||
242 | p = xdr_encode_mon_id(p, argp); | ||
243 | if (IS_ERR(p)) | ||
244 | return PTR_ERR(p); | ||
245 | |||
246 | p = xdr_encode_priv(p, argp); | ||
247 | if (IS_ERR(p)) | ||
248 | return PTR_ERR(p); | ||
249 | |||
191 | rqstp->rq_slen = xdr_adjust_iovec(rqstp->rq_svec, p); | 250 | rqstp->rq_slen = xdr_adjust_iovec(rqstp->rq_svec, p); |
192 | return 0; | 251 | return 0; |
193 | } | 252 | } |
@@ -195,7 +254,7 @@ xdr_encode_mon(struct rpc_rqst *rqstp, __be32 *p, struct nsm_args *argp) | |||
195 | static int | 254 | static int |
196 | xdr_encode_unmon(struct rpc_rqst *rqstp, __be32 *p, struct nsm_args *argp) | 255 | xdr_encode_unmon(struct rpc_rqst *rqstp, __be32 *p, struct nsm_args *argp) |
197 | { | 256 | { |
198 | p = xdr_encode_common(rqstp, p, argp); | 257 | p = xdr_encode_mon_id(p, argp); |
199 | if (IS_ERR(p)) | 258 | if (IS_ERR(p)) |
200 | return PTR_ERR(p); | 259 | return PTR_ERR(p); |
201 | rqstp->rq_slen = xdr_adjust_iovec(rqstp->rq_svec, p); | 260 | rqstp->rq_slen = xdr_adjust_iovec(rqstp->rq_svec, p); |
@@ -220,9 +279,11 @@ xdr_decode_stat(struct rpc_rqst *rqstp, __be32 *p, struct nsm_res *resp) | |||
220 | } | 279 | } |
221 | 280 | ||
222 | #define SM_my_name_sz (1+XDR_QUADLEN(SM_MAXSTRLEN)) | 281 | #define SM_my_name_sz (1+XDR_QUADLEN(SM_MAXSTRLEN)) |
223 | #define SM_my_id_sz (3+1+SM_my_name_sz) | 282 | #define SM_my_id_sz (SM_my_name_sz+3) |
224 | #define SM_mon_id_sz (1+XDR_QUADLEN(20)+SM_my_id_sz) | 283 | #define SM_mon_name_sz (1+XDR_QUADLEN(SM_MAXSTRLEN)) |
225 | #define SM_mon_sz (SM_mon_id_sz+4) | 284 | #define SM_mon_id_sz (SM_mon_name_sz+SM_my_id_sz) |
285 | #define SM_priv_sz (XDR_QUADLEN(SM_PRIV_SIZE)) | ||
286 | #define SM_mon_sz (SM_mon_id_sz+SM_priv_sz) | ||
226 | #define SM_monres_sz 2 | 287 | #define SM_monres_sz 2 |
227 | #define SM_unmonres_sz 1 | 288 | #define SM_unmonres_sz 1 |
228 | 289 | ||
diff --git a/fs/lockd/svc.c b/fs/lockd/svc.c index cf977bbcf303..2169af4d5455 100644 --- a/fs/lockd/svc.c +++ b/fs/lockd/svc.c | |||
@@ -72,7 +72,9 @@ static const unsigned long nlm_timeout_min = 3; | |||
72 | static const unsigned long nlm_timeout_max = 20; | 72 | static const unsigned long nlm_timeout_max = 20; |
73 | static const int nlm_port_min = 0, nlm_port_max = 65535; | 73 | static const int nlm_port_min = 0, nlm_port_max = 65535; |
74 | 74 | ||
75 | #ifdef CONFIG_SYSCTL | ||
75 | static struct ctl_table_header * nlm_sysctl_table; | 76 | static struct ctl_table_header * nlm_sysctl_table; |
77 | #endif | ||
76 | 78 | ||
77 | static unsigned long get_lockd_grace_period(void) | 79 | static unsigned long get_lockd_grace_period(void) |
78 | { | 80 | { |
@@ -349,6 +351,8 @@ out: | |||
349 | } | 351 | } |
350 | EXPORT_SYMBOL(lockd_down); | 352 | EXPORT_SYMBOL(lockd_down); |
351 | 353 | ||
354 | #ifdef CONFIG_SYSCTL | ||
355 | |||
352 | /* | 356 | /* |
353 | * Sysctl parameters (same as module parameters, different interface). | 357 | * Sysctl parameters (same as module parameters, different interface). |
354 | */ | 358 | */ |
@@ -433,6 +437,8 @@ static ctl_table nlm_sysctl_root[] = { | |||
433 | { .ctl_name = 0 } | 437 | { .ctl_name = 0 } |
434 | }; | 438 | }; |
435 | 439 | ||
440 | #endif /* CONFIG_SYSCTL */ | ||
441 | |||
436 | /* | 442 | /* |
437 | * Module (and sysfs) parameters. | 443 | * Module (and sysfs) parameters. |
438 | */ | 444 | */ |
@@ -506,15 +512,21 @@ module_param(nsm_use_hostnames, bool, 0644); | |||
506 | 512 | ||
507 | static int __init init_nlm(void) | 513 | static int __init init_nlm(void) |
508 | { | 514 | { |
515 | #ifdef CONFIG_SYSCTL | ||
509 | nlm_sysctl_table = register_sysctl_table(nlm_sysctl_root); | 516 | nlm_sysctl_table = register_sysctl_table(nlm_sysctl_root); |
510 | return nlm_sysctl_table ? 0 : -ENOMEM; | 517 | return nlm_sysctl_table ? 0 : -ENOMEM; |
518 | #else | ||
519 | return 0; | ||
520 | #endif | ||
511 | } | 521 | } |
512 | 522 | ||
513 | static void __exit exit_nlm(void) | 523 | static void __exit exit_nlm(void) |
514 | { | 524 | { |
515 | /* FIXME: delete all NLM clients */ | 525 | /* FIXME: delete all NLM clients */ |
516 | nlm_shutdown_hosts(); | 526 | nlm_shutdown_hosts(); |
527 | #ifdef CONFIG_SYSCTL | ||
517 | unregister_sysctl_table(nlm_sysctl_table); | 528 | unregister_sysctl_table(nlm_sysctl_table); |
529 | #endif | ||
518 | } | 530 | } |
519 | 531 | ||
520 | module_init(init_nlm); | 532 | module_init(init_nlm); |