aboutsummaryrefslogtreecommitdiffstats
path: root/fs/lockd
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2008-04-24 14:46:16 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2008-04-24 14:46:16 -0400
commit563307b2fa15d687abc54bd980b9847ebf0e3231 (patch)
tree7f16be30217a2e66360ede97aa27d07a4ebd7e55 /fs/lockd
parent10c993a6b5418cb1026775765ba4c70ffb70853d (diff)
parent233607dbbc823caf685e778cabc49fb7f679900b (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.c184
-rw-r--r--fs/lockd/host.c20
-rw-r--r--fs/lockd/mon.c113
-rw-r--r--fs/lockd/svc.c12
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)
155int nlmclnt_proc(struct nlm_host *host, int cmd, struct file_lock *fl) 155int 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(&current->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(&current->blocked); /* Mask all signals */
181 recalc_sigpending();
182
183 call->a_flags = RPC_TASK_ASYNC;
184 }
185 spin_unlock_irqrestore(&current->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(&current->sighand->siglock, flags);
202 current->blocked = oldset;
203 recalc_sigpending();
204 spin_unlock_irqrestore(&current->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
238void nlm_release_call(struct nlm_rqst *call) 216void 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 */
269static int 249static int
270nlmclnt_call(struct nlm_rqst *req, u32 proc) 250nlmclnt_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 */
346static int __nlm_async_call(struct nlm_rqst *req, u32 proc, struct rpc_message *msg, const struct rpc_call_ops *tk_ops) 327static 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);
362out_err: 350out_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
355static 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 */
367int nlm_async_call(struct nlm_rqst *req, u32 proc, const struct rpc_call_ops *tk_ops) 369int 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
376int nlm_async_reply(struct nlm_rqst *req, u32 proc, const struct rpc_call_ops *tk_ops) 378int 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 */
394static 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)
480static int 508static int
481nlmclnt_lock(struct nlm_rqst *req, struct file_lock *fl) 509nlmclnt_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);
500again: 531again:
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);
539out_unblock: 584out_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);
544out: 586out:
545 nlm_release_call(req); 587 nlm_release_call(req);
588 return status;
589out_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 = {
671static int nlmclnt_cancel(struct nlm_host *host, int block, struct file_lock *fl) 728static 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(&current->sighand->siglock, flags); 734 " Attempting to cancel lock.\n");
680 oldset = current->blocked;
681 sigfillset(&current->blocked);
682 recalc_sigpending();
683 spin_unlock_irqrestore(&current->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(&current->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(&current->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 */
44static struct nlm_host * 44static struct nlm_host *nlm_lookup_host(int server,
45nlm_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 */
175struct nlm_host * 176struct nlm_host *nlmclnt_lookup_host(const struct sockaddr_in *sin,
176nlmclnt_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
21static struct rpc_clnt * nsm_create(void); 23static struct rpc_clnt * nsm_create(void);
22 24
23static struct rpc_program nsm_program; 25static 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
152static __be32 * 157static __be32 *xdr_encode_nsm_string(__be32 *p, char *string)
153xdr_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 */
175static __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 */
195static __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
179static int 208/*
180xdr_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 */
212static __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 */
229static __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
239static int
240xdr_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)
195static int 254static int
196xdr_encode_unmon(struct rpc_rqst *rqstp, __be32 *p, struct nsm_args *argp) 255xdr_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;
72static const unsigned long nlm_timeout_max = 20; 72static const unsigned long nlm_timeout_max = 20;
73static const int nlm_port_min = 0, nlm_port_max = 65535; 73static const int nlm_port_min = 0, nlm_port_max = 65535;
74 74
75#ifdef CONFIG_SYSCTL
75static struct ctl_table_header * nlm_sysctl_table; 76static struct ctl_table_header * nlm_sysctl_table;
77#endif
76 78
77static unsigned long get_lockd_grace_period(void) 79static unsigned long get_lockd_grace_period(void)
78{ 80{
@@ -349,6 +351,8 @@ out:
349} 351}
350EXPORT_SYMBOL(lockd_down); 352EXPORT_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
507static int __init init_nlm(void) 513static 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
513static void __exit exit_nlm(void) 523static 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
520module_init(init_nlm); 532module_init(init_nlm);