aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfsd/nfs4callback.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/nfsd/nfs4callback.c')
-rw-r--r--fs/nfsd/nfs4callback.c140
1 files changed, 92 insertions, 48 deletions
diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c
index 7e32bd394e86..eb78e7e22077 100644
--- a/fs/nfsd/nfs4callback.c
+++ b/fs/nfsd/nfs4callback.c
@@ -32,6 +32,7 @@
32 */ 32 */
33 33
34#include <linux/sunrpc/clnt.h> 34#include <linux/sunrpc/clnt.h>
35#include <linux/sunrpc/svc_xprt.h>
35#include <linux/slab.h> 36#include <linux/slab.h>
36#include "nfsd.h" 37#include "nfsd.h"
37#include "state.h" 38#include "state.h"
@@ -79,11 +80,6 @@ enum nfs_cb_opnum4 {
79 cb_sequence_dec_sz + \ 80 cb_sequence_dec_sz + \
80 op_dec_sz) 81 op_dec_sz)
81 82
82struct nfs4_rpc_args {
83 void *args_op;
84 struct nfsd4_cb_sequence args_seq;
85};
86
87/* 83/*
88* Generic encode routines from fs/nfs/nfs4xdr.c 84* Generic encode routines from fs/nfs/nfs4xdr.c
89*/ 85*/
@@ -428,13 +424,19 @@ static struct rpc_procinfo nfs4_cb_procedures[] = {
428}; 424};
429 425
430static struct rpc_version nfs_cb_version4 = { 426static struct rpc_version nfs_cb_version4 = {
427/*
428 * Note on the callback rpc program version number: despite language in rfc
429 * 5661 section 18.36.3 requiring servers to use 4 in this field, the
430 * official xdr descriptions for both 4.0 and 4.1 specify version 1, and
431 * in practice that appears to be what implementations use. The section
432 * 18.36.3 language is expected to be fixed in an erratum.
433 */
431 .number = 1, 434 .number = 1,
432 .nrprocs = ARRAY_SIZE(nfs4_cb_procedures), 435 .nrprocs = ARRAY_SIZE(nfs4_cb_procedures),
433 .procs = nfs4_cb_procedures 436 .procs = nfs4_cb_procedures
434}; 437};
435 438
436static struct rpc_version * nfs_cb_version[] = { 439static struct rpc_version * nfs_cb_version[] = {
437 NULL,
438 &nfs_cb_version4, 440 &nfs_cb_version4,
439}; 441};
440 442
@@ -456,15 +458,14 @@ static struct rpc_program cb_program = {
456 458
457static int max_cb_time(void) 459static int max_cb_time(void)
458{ 460{
459 return max(NFSD_LEASE_TIME/10, (time_t)1) * HZ; 461 return max(nfsd4_lease/10, (time_t)1) * HZ;
460} 462}
461 463
462/* Reference counting, callback cleanup, etc., all look racy as heck. 464/* Reference counting, callback cleanup, etc., all look racy as heck.
463 * And why is cb_set an atomic? */ 465 * And why is cl_cb_set an atomic? */
464 466
465int setup_callback_client(struct nfs4_client *clp) 467int setup_callback_client(struct nfs4_client *clp, struct nfs4_cb_conn *cb)
466{ 468{
467 struct nfs4_cb_conn *cb = &clp->cl_cb_conn;
468 struct rpc_timeout timeparms = { 469 struct rpc_timeout timeparms = {
469 .to_initval = max_cb_time(), 470 .to_initval = max_cb_time(),
470 .to_retries = 0, 471 .to_retries = 0,
@@ -476,7 +477,7 @@ int setup_callback_client(struct nfs4_client *clp)
476 .timeout = &timeparms, 477 .timeout = &timeparms,
477 .program = &cb_program, 478 .program = &cb_program,
478 .prognumber = cb->cb_prog, 479 .prognumber = cb->cb_prog,
479 .version = nfs_cb_version[1]->number, 480 .version = 0,
480 .authflavor = clp->cl_flavor, 481 .authflavor = clp->cl_flavor,
481 .flags = (RPC_CLNT_CREATE_NOPING | RPC_CLNT_CREATE_QUIET), 482 .flags = (RPC_CLNT_CREATE_NOPING | RPC_CLNT_CREATE_QUIET),
482 .client_name = clp->cl_principal, 483 .client_name = clp->cl_principal,
@@ -486,7 +487,7 @@ int setup_callback_client(struct nfs4_client *clp)
486 if (!clp->cl_principal && (clp->cl_flavor >= RPC_AUTH_GSS_KRB5)) 487 if (!clp->cl_principal && (clp->cl_flavor >= RPC_AUTH_GSS_KRB5))
487 return -EINVAL; 488 return -EINVAL;
488 if (cb->cb_minorversion) { 489 if (cb->cb_minorversion) {
489 args.bc_xprt = clp->cl_cb_xprt; 490 args.bc_xprt = cb->cb_xprt;
490 args.protocol = XPRT_TRANSPORT_BC_TCP; 491 args.protocol = XPRT_TRANSPORT_BC_TCP;
491 } 492 }
492 /* Create RPC client */ 493 /* Create RPC client */
@@ -496,7 +497,7 @@ int setup_callback_client(struct nfs4_client *clp)
496 PTR_ERR(client)); 497 PTR_ERR(client));
497 return PTR_ERR(client); 498 return PTR_ERR(client);
498 } 499 }
499 cb->cb_client = client; 500 nfsd4_set_callback_client(clp, client);
500 return 0; 501 return 0;
501 502
502} 503}
@@ -514,8 +515,7 @@ static void nfsd4_cb_probe_done(struct rpc_task *task, void *calldata)
514 if (task->tk_status) 515 if (task->tk_status)
515 warn_no_callback_path(clp, task->tk_status); 516 warn_no_callback_path(clp, task->tk_status);
516 else 517 else
517 atomic_set(&clp->cl_cb_conn.cb_set, 1); 518 atomic_set(&clp->cl_cb_set, 1);
518 put_nfs4_client(clp);
519} 519}
520 520
521static const struct rpc_call_ops nfsd4_cb_probe_ops = { 521static const struct rpc_call_ops nfsd4_cb_probe_ops = {
@@ -537,7 +537,6 @@ int set_callback_cred(void)
537 537
538void do_probe_callback(struct nfs4_client *clp) 538void do_probe_callback(struct nfs4_client *clp)
539{ 539{
540 struct nfs4_cb_conn *cb = &clp->cl_cb_conn;
541 struct rpc_message msg = { 540 struct rpc_message msg = {
542 .rpc_proc = &nfs4_cb_procedures[NFSPROC4_CLNT_CB_NULL], 541 .rpc_proc = &nfs4_cb_procedures[NFSPROC4_CLNT_CB_NULL],
543 .rpc_argp = clp, 542 .rpc_argp = clp,
@@ -545,34 +544,27 @@ void do_probe_callback(struct nfs4_client *clp)
545 }; 544 };
546 int status; 545 int status;
547 546
548 status = rpc_call_async(cb->cb_client, &msg, 547 status = rpc_call_async(clp->cl_cb_client, &msg,
549 RPC_TASK_SOFT | RPC_TASK_SOFTCONN, 548 RPC_TASK_SOFT | RPC_TASK_SOFTCONN,
550 &nfsd4_cb_probe_ops, (void *)clp); 549 &nfsd4_cb_probe_ops, (void *)clp);
551 if (status) { 550 if (status)
552 warn_no_callback_path(clp, status); 551 warn_no_callback_path(clp, status);
553 put_nfs4_client(clp);
554 }
555} 552}
556 553
557/* 554/*
558 * Set up the callback client and put a NFSPROC4_CB_NULL on the wire... 555 * Set up the callback client and put a NFSPROC4_CB_NULL on the wire...
559 */ 556 */
560void 557void nfsd4_probe_callback(struct nfs4_client *clp, struct nfs4_cb_conn *cb)
561nfsd4_probe_callback(struct nfs4_client *clp)
562{ 558{
563 int status; 559 int status;
564 560
565 BUG_ON(atomic_read(&clp->cl_cb_conn.cb_set)); 561 BUG_ON(atomic_read(&clp->cl_cb_set));
566 562
567 status = setup_callback_client(clp); 563 status = setup_callback_client(clp, cb);
568 if (status) { 564 if (status) {
569 warn_no_callback_path(clp, status); 565 warn_no_callback_path(clp, status);
570 return; 566 return;
571 } 567 }
572
573 /* the task holds a reference to the nfs4_client struct */
574 atomic_inc(&clp->cl_count);
575
576 do_probe_callback(clp); 568 do_probe_callback(clp);
577} 569}
578 570
@@ -658,18 +650,32 @@ static void nfsd4_cb_done(struct rpc_task *task, void *calldata)
658 } 650 }
659} 651}
660 652
653
661static void nfsd4_cb_recall_done(struct rpc_task *task, void *calldata) 654static void nfsd4_cb_recall_done(struct rpc_task *task, void *calldata)
662{ 655{
663 struct nfs4_delegation *dp = calldata; 656 struct nfs4_delegation *dp = calldata;
664 struct nfs4_client *clp = dp->dl_client; 657 struct nfs4_client *clp = dp->dl_client;
658 struct rpc_clnt *current_rpc_client = clp->cl_cb_client;
665 659
666 nfsd4_cb_done(task, calldata); 660 nfsd4_cb_done(task, calldata);
667 661
662 if (current_rpc_client == NULL) {
663 /* We're shutting down; give up. */
664 /* XXX: err, or is it ok just to fall through
665 * and rpc_restart_call? */
666 return;
667 }
668
668 switch (task->tk_status) { 669 switch (task->tk_status) {
669 case -EIO: 670 case -EIO:
670 /* Network partition? */ 671 /* Network partition? */
671 atomic_set(&clp->cl_cb_conn.cb_set, 0); 672 atomic_set(&clp->cl_cb_set, 0);
672 warn_no_callback_path(clp, task->tk_status); 673 warn_no_callback_path(clp, task->tk_status);
674 if (current_rpc_client != task->tk_client) {
675 /* queue a callback on the new connection: */
676 nfsd4_cb_recall(dp);
677 return;
678 }
673 case -EBADHANDLE: 679 case -EBADHANDLE:
674 case -NFS4ERR_BAD_STATEID: 680 case -NFS4ERR_BAD_STATEID:
675 /* Race: client probably got cb_recall 681 /* Race: client probably got cb_recall
@@ -677,7 +683,7 @@ static void nfsd4_cb_recall_done(struct rpc_task *task, void *calldata)
677 break; 683 break;
678 default: 684 default:
679 /* success, or error we can't handle */ 685 /* success, or error we can't handle */
680 goto done; 686 return;
681 } 687 }
682 if (dp->dl_retries--) { 688 if (dp->dl_retries--) {
683 rpc_delay(task, 2*HZ); 689 rpc_delay(task, 2*HZ);
@@ -685,20 +691,16 @@ static void nfsd4_cb_recall_done(struct rpc_task *task, void *calldata)
685 rpc_restart_call(task); 691 rpc_restart_call(task);
686 return; 692 return;
687 } else { 693 } else {
688 atomic_set(&clp->cl_cb_conn.cb_set, 0); 694 atomic_set(&clp->cl_cb_set, 0);
689 warn_no_callback_path(clp, task->tk_status); 695 warn_no_callback_path(clp, task->tk_status);
690 } 696 }
691done:
692 kfree(task->tk_msg.rpc_argp);
693} 697}
694 698
695static void nfsd4_cb_recall_release(void *calldata) 699static void nfsd4_cb_recall_release(void *calldata)
696{ 700{
697 struct nfs4_delegation *dp = calldata; 701 struct nfs4_delegation *dp = calldata;
698 struct nfs4_client *clp = dp->dl_client;
699 702
700 nfs4_put_delegation(dp); 703 nfs4_put_delegation(dp);
701 put_nfs4_client(clp);
702} 704}
703 705
704static const struct rpc_call_ops nfsd4_cb_recall_ops = { 706static const struct rpc_call_ops nfsd4_cb_recall_ops = {
@@ -707,33 +709,75 @@ static const struct rpc_call_ops nfsd4_cb_recall_ops = {
707 .rpc_release = nfsd4_cb_recall_release, 709 .rpc_release = nfsd4_cb_recall_release,
708}; 710};
709 711
712static struct workqueue_struct *callback_wq;
713
714int nfsd4_create_callback_queue(void)
715{
716 callback_wq = create_singlethread_workqueue("nfsd4_callbacks");
717 if (!callback_wq)
718 return -ENOMEM;
719 return 0;
720}
721
722void nfsd4_destroy_callback_queue(void)
723{
724 destroy_workqueue(callback_wq);
725}
726
727/* must be called under the state lock */
728void nfsd4_set_callback_client(struct nfs4_client *clp, struct rpc_clnt *new)
729{
730 struct rpc_clnt *old = clp->cl_cb_client;
731
732 clp->cl_cb_client = new;
733 /*
734 * After this, any work that saw the old value of cl_cb_client will
735 * be gone:
736 */
737 flush_workqueue(callback_wq);
738 /* So we can safely shut it down: */
739 if (old)
740 rpc_shutdown_client(old);
741}
742
710/* 743/*
711 * called with dp->dl_count inc'ed. 744 * called with dp->dl_count inc'ed.
712 */ 745 */
713void 746static void _nfsd4_cb_recall(struct nfs4_delegation *dp)
714nfsd4_cb_recall(struct nfs4_delegation *dp)
715{ 747{
716 struct nfs4_client *clp = dp->dl_client; 748 struct nfs4_client *clp = dp->dl_client;
717 struct rpc_clnt *clnt = clp->cl_cb_conn.cb_client; 749 struct rpc_clnt *clnt = clp->cl_cb_client;
718 struct nfs4_rpc_args *args; 750 struct nfs4_rpc_args *args = &dp->dl_recall.cb_args;
719 struct rpc_message msg = { 751 struct rpc_message msg = {
720 .rpc_proc = &nfs4_cb_procedures[NFSPROC4_CLNT_CB_RECALL], 752 .rpc_proc = &nfs4_cb_procedures[NFSPROC4_CLNT_CB_RECALL],
721 .rpc_cred = callback_cred 753 .rpc_cred = callback_cred
722 }; 754 };
723 int status = -ENOMEM; 755 int status;
756
757 if (clnt == NULL)
758 return; /* Client is shutting down; give up. */
724 759
725 args = kzalloc(sizeof(*args), GFP_KERNEL);
726 if (!args)
727 goto out;
728 args->args_op = dp; 760 args->args_op = dp;
729 msg.rpc_argp = args; 761 msg.rpc_argp = args;
730 dp->dl_retries = 1; 762 dp->dl_retries = 1;
731 status = rpc_call_async(clnt, &msg, RPC_TASK_SOFT, 763 status = rpc_call_async(clnt, &msg, RPC_TASK_SOFT,
732 &nfsd4_cb_recall_ops, dp); 764 &nfsd4_cb_recall_ops, dp);
733out: 765 if (status)
734 if (status) {
735 kfree(args);
736 put_nfs4_client(clp);
737 nfs4_put_delegation(dp); 766 nfs4_put_delegation(dp);
738 } 767}
768
769void nfsd4_do_callback_rpc(struct work_struct *w)
770{
771 /* XXX: for now, just send off delegation recall. */
772 /* In future, generalize to handle any sort of callback. */
773 struct nfsd4_callback *c = container_of(w, struct nfsd4_callback, cb_work);
774 struct nfs4_delegation *dp = container_of(c, struct nfs4_delegation, dl_recall);
775
776 _nfsd4_cb_recall(dp);
777}
778
779
780void nfsd4_cb_recall(struct nfs4_delegation *dp)
781{
782 queue_work(callback_wq, &dp->dl_recall.cb_work);
739} 783}