aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfsd/nfs4callback.c
diff options
context:
space:
mode:
authorJonathan Herman <hermanjl@cs.unc.edu>2013-01-17 16:15:55 -0500
committerJonathan Herman <hermanjl@cs.unc.edu>2013-01-17 16:15:55 -0500
commit8dea78da5cee153b8af9c07a2745f6c55057fe12 (patch)
treea8f4d49d63b1ecc92f2fddceba0655b2472c5bd9 /fs/nfsd/nfs4callback.c
parent406089d01562f1e2bf9f089fd7637009ebaad589 (diff)
Patched in Tegra support.
Diffstat (limited to 'fs/nfsd/nfs4callback.c')
-rw-r--r--fs/nfsd/nfs4callback.c119
1 files changed, 41 insertions, 78 deletions
diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c
index 99bc85ff021..02eb4edf0ec 100644
--- a/fs/nfsd/nfs4callback.c
+++ b/fs/nfsd/nfs4callback.c
@@ -36,12 +36,9 @@
36#include <linux/slab.h> 36#include <linux/slab.h>
37#include "nfsd.h" 37#include "nfsd.h"
38#include "state.h" 38#include "state.h"
39#include "netns.h"
40 39
41#define NFSDDBG_FACILITY NFSDDBG_PROC 40#define NFSDDBG_FACILITY NFSDDBG_PROC
42 41
43static void nfsd4_mark_cb_fault(struct nfs4_client *, int reason);
44
45#define NFSPROC4_CB_NULL 0 42#define NFSPROC4_CB_NULL 0
46#define NFSPROC4_CB_COMPOUND 1 43#define NFSPROC4_CB_COMPOUND 1
47 44
@@ -354,7 +351,7 @@ static void encode_cb_recall4args(struct xdr_stream *xdr,
354 __be32 *p; 351 __be32 *p;
355 352
356 encode_nfs_cb_opnum4(xdr, OP_CB_RECALL); 353 encode_nfs_cb_opnum4(xdr, OP_CB_RECALL);
357 encode_stateid4(xdr, &dp->dl_stid.sc_stateid); 354 encode_stateid4(xdr, &dp->dl_stateid);
358 355
359 p = xdr_reserve_space(xdr, 4); 356 p = xdr_reserve_space(xdr, 4);
360 *p++ = xdr_zero; /* truncate */ 357 *p++ = xdr_zero; /* truncate */
@@ -463,8 +460,6 @@ static int decode_cb_sequence4resok(struct xdr_stream *xdr,
463 */ 460 */
464 status = 0; 461 status = 0;
465out: 462out:
466 if (status)
467 nfsd4_mark_cb_fault(cb->cb_clp, status);
468 return status; 463 return status;
469out_overflow: 464out_overflow:
470 print_overflow_msg(__func__, xdr); 465 print_overflow_msg(__func__, xdr);
@@ -606,85 +601,57 @@ static struct rpc_version nfs_cb_version4 = {
606 .procs = nfs4_cb_procedures 601 .procs = nfs4_cb_procedures
607}; 602};
608 603
609static const struct rpc_version *nfs_cb_version[] = { 604static struct rpc_version *nfs_cb_version[] = {
610 &nfs_cb_version4, 605 &nfs_cb_version4,
611}; 606};
612 607
613static const struct rpc_program cb_program; 608static struct rpc_program cb_program;
614 609
615static struct rpc_stat cb_stats = { 610static struct rpc_stat cb_stats = {
616 .program = &cb_program 611 .program = &cb_program
617}; 612};
618 613
619#define NFS4_CALLBACK 0x40000000 614#define NFS4_CALLBACK 0x40000000
620static const struct rpc_program cb_program = { 615static struct rpc_program cb_program = {
621 .name = "nfs4_cb", 616 .name = "nfs4_cb",
622 .number = NFS4_CALLBACK, 617 .number = NFS4_CALLBACK,
623 .nrvers = ARRAY_SIZE(nfs_cb_version), 618 .nrvers = ARRAY_SIZE(nfs_cb_version),
624 .version = nfs_cb_version, 619 .version = nfs_cb_version,
625 .stats = &cb_stats, 620 .stats = &cb_stats,
626 .pipe_dir_name = "nfsd4_cb", 621 .pipe_dir_name = "/nfsd4_cb",
627}; 622};
628 623
629static int max_cb_time(struct net *net) 624static int max_cb_time(void)
630{
631 struct nfsd_net *nn = net_generic(net, nfsd_net_id);
632 return max(nn->nfsd4_lease/10, (time_t)1) * HZ;
633}
634
635static struct rpc_cred *callback_cred;
636
637int set_callback_cred(void)
638{ 625{
639 if (callback_cred) 626 return max(nfsd4_lease/10, (time_t)1) * HZ;
640 return 0;
641 callback_cred = rpc_lookup_machine_cred("nfs");
642 if (!callback_cred)
643 return -ENOMEM;
644 return 0;
645} 627}
646 628
647static struct rpc_cred *get_backchannel_cred(struct nfs4_client *clp, struct rpc_clnt *client, struct nfsd4_session *ses)
648{
649 if (clp->cl_minorversion == 0) {
650 return get_rpccred(callback_cred);
651 } else {
652 struct rpc_auth *auth = client->cl_auth;
653 struct auth_cred acred = {};
654
655 acred.uid = ses->se_cb_sec.uid;
656 acred.gid = ses->se_cb_sec.gid;
657 return auth->au_ops->lookup_cred(client->cl_auth, &acred, 0);
658 }
659}
660 629
661static int setup_callback_client(struct nfs4_client *clp, struct nfs4_cb_conn *conn, struct nfsd4_session *ses) 630static int setup_callback_client(struct nfs4_client *clp, struct nfs4_cb_conn *conn, struct nfsd4_session *ses)
662{ 631{
663 struct rpc_timeout timeparms = { 632 struct rpc_timeout timeparms = {
664 .to_initval = max_cb_time(clp->net), 633 .to_initval = max_cb_time(),
665 .to_retries = 0, 634 .to_retries = 0,
666 }; 635 };
667 struct rpc_create_args args = { 636 struct rpc_create_args args = {
668 .net = clp->net, 637 .net = &init_net,
669 .address = (struct sockaddr *) &conn->cb_addr, 638 .address = (struct sockaddr *) &conn->cb_addr,
670 .addrsize = conn->cb_addrlen, 639 .addrsize = conn->cb_addrlen,
671 .saddress = (struct sockaddr *) &conn->cb_saddr, 640 .saddress = (struct sockaddr *) &conn->cb_saddr,
672 .timeout = &timeparms, 641 .timeout = &timeparms,
673 .program = &cb_program, 642 .program = &cb_program,
674 .version = 0, 643 .version = 0,
644 .authflavor = clp->cl_flavor,
675 .flags = (RPC_CLNT_CREATE_NOPING | RPC_CLNT_CREATE_QUIET), 645 .flags = (RPC_CLNT_CREATE_NOPING | RPC_CLNT_CREATE_QUIET),
676 }; 646 };
677 struct rpc_clnt *client; 647 struct rpc_clnt *client;
678 struct rpc_cred *cred;
679 648
680 if (clp->cl_minorversion == 0) { 649 if (clp->cl_minorversion == 0) {
681 if (!clp->cl_cred.cr_principal && 650 if (!clp->cl_principal && (clp->cl_flavor >= RPC_AUTH_GSS_KRB5))
682 (clp->cl_cred.cr_flavor >= RPC_AUTH_GSS_KRB5))
683 return -EINVAL; 651 return -EINVAL;
684 args.client_name = clp->cl_cred.cr_principal; 652 args.client_name = clp->cl_principal;
685 args.prognumber = conn->cb_prog, 653 args.prognumber = conn->cb_prog,
686 args.protocol = XPRT_TRANSPORT_TCP; 654 args.protocol = XPRT_TRANSPORT_TCP;
687 args.authflavor = clp->cl_cred.cr_flavor;
688 clp->cl_cb_ident = conn->cb_ident; 655 clp->cl_cb_ident = conn->cb_ident;
689 } else { 656 } else {
690 if (!conn->cb_xprt) 657 if (!conn->cb_xprt)
@@ -694,7 +661,6 @@ static int setup_callback_client(struct nfs4_client *clp, struct nfs4_cb_conn *c
694 args.bc_xprt = conn->cb_xprt; 661 args.bc_xprt = conn->cb_xprt;
695 args.prognumber = clp->cl_cb_session->se_cb_prog; 662 args.prognumber = clp->cl_cb_session->se_cb_prog;
696 args.protocol = XPRT_TRANSPORT_BC_TCP; 663 args.protocol = XPRT_TRANSPORT_BC_TCP;
697 args.authflavor = ses->se_cb_sec.flavor;
698 } 664 }
699 /* Create RPC client */ 665 /* Create RPC client */
700 client = rpc_create(&args); 666 client = rpc_create(&args);
@@ -703,14 +669,9 @@ static int setup_callback_client(struct nfs4_client *clp, struct nfs4_cb_conn *c
703 PTR_ERR(client)); 669 PTR_ERR(client));
704 return PTR_ERR(client); 670 return PTR_ERR(client);
705 } 671 }
706 cred = get_backchannel_cred(clp, client, ses);
707 if (IS_ERR(cred)) {
708 rpc_shutdown_client(client);
709 return PTR_ERR(cred);
710 }
711 clp->cl_cb_client = client; 672 clp->cl_cb_client = client;
712 clp->cl_cb_cred = cred;
713 return 0; 673 return 0;
674
714} 675}
715 676
716static void warn_no_callback_path(struct nfs4_client *clp, int reason) 677static void warn_no_callback_path(struct nfs4_client *clp, int reason)
@@ -725,12 +686,6 @@ static void nfsd4_mark_cb_down(struct nfs4_client *clp, int reason)
725 warn_no_callback_path(clp, reason); 686 warn_no_callback_path(clp, reason);
726} 687}
727 688
728static void nfsd4_mark_cb_fault(struct nfs4_client *clp, int reason)
729{
730 clp->cl_cb_state = NFSD4_CB_FAULT;
731 warn_no_callback_path(clp, reason);
732}
733
734static void nfsd4_cb_probe_done(struct rpc_task *task, void *calldata) 689static void nfsd4_cb_probe_done(struct rpc_task *task, void *calldata)
735{ 690{
736 struct nfs4_client *clp = container_of(calldata, struct nfs4_client, cl_cb_null); 691 struct nfs4_client *clp = container_of(calldata, struct nfs4_client, cl_cb_null);
@@ -747,6 +702,18 @@ static const struct rpc_call_ops nfsd4_cb_probe_ops = {
747 .rpc_call_done = nfsd4_cb_probe_done, 702 .rpc_call_done = nfsd4_cb_probe_done,
748}; 703};
749 704
705static struct rpc_cred *callback_cred;
706
707int set_callback_cred(void)
708{
709 if (callback_cred)
710 return 0;
711 callback_cred = rpc_lookup_machine_cred();
712 if (!callback_cred)
713 return -ENOMEM;
714 return 0;
715}
716
750static struct workqueue_struct *callback_wq; 717static struct workqueue_struct *callback_wq;
751 718
752static void run_nfsd4_cb(struct nfsd4_callback *cb) 719static void run_nfsd4_cb(struct nfsd4_callback *cb)
@@ -764,6 +731,7 @@ static void do_probe_callback(struct nfs4_client *clp)
764 cb->cb_msg.rpc_proc = &nfs4_cb_procedures[NFSPROC4_CLNT_CB_NULL]; 731 cb->cb_msg.rpc_proc = &nfs4_cb_procedures[NFSPROC4_CLNT_CB_NULL];
765 cb->cb_msg.rpc_argp = NULL; 732 cb->cb_msg.rpc_argp = NULL;
766 cb->cb_msg.rpc_resp = NULL; 733 cb->cb_msg.rpc_resp = NULL;
734 cb->cb_msg.rpc_cred = callback_cred;
767 735
768 cb->cb_ops = &nfsd4_cb_probe_ops; 736 cb->cb_ops = &nfsd4_cb_probe_ops;
769 737
@@ -776,8 +744,9 @@ static void do_probe_callback(struct nfs4_client *clp)
776 */ 744 */
777void nfsd4_probe_callback(struct nfs4_client *clp) 745void nfsd4_probe_callback(struct nfs4_client *clp)
778{ 746{
747 /* XXX: atomicity? Also, should we be using cl_cb_flags? */
779 clp->cl_cb_state = NFSD4_CB_UNKNOWN; 748 clp->cl_cb_state = NFSD4_CB_UNKNOWN;
780 set_bit(NFSD4_CLIENT_CB_UPDATE, &clp->cl_flags); 749 set_bit(NFSD4_CLIENT_CB_UPDATE, &clp->cl_cb_flags);
781 do_probe_callback(clp); 750 do_probe_callback(clp);
782} 751}
783 752
@@ -818,7 +787,7 @@ static void nfsd4_cb_prepare(struct rpc_task *task, void *calldata)
818{ 787{
819 struct nfsd4_callback *cb = calldata; 788 struct nfsd4_callback *cb = calldata;
820 struct nfs4_delegation *dp = container_of(cb, struct nfs4_delegation, dl_recall); 789 struct nfs4_delegation *dp = container_of(cb, struct nfs4_delegation, dl_recall);
821 struct nfs4_client *clp = dp->dl_stid.sc_client; 790 struct nfs4_client *clp = dp->dl_client;
822 u32 minorversion = clp->cl_minorversion; 791 u32 minorversion = clp->cl_minorversion;
823 792
824 cb->cb_minorversion = minorversion; 793 cb->cb_minorversion = minorversion;
@@ -840,7 +809,7 @@ static void nfsd4_cb_done(struct rpc_task *task, void *calldata)
840{ 809{
841 struct nfsd4_callback *cb = calldata; 810 struct nfsd4_callback *cb = calldata;
842 struct nfs4_delegation *dp = container_of(cb, struct nfs4_delegation, dl_recall); 811 struct nfs4_delegation *dp = container_of(cb, struct nfs4_delegation, dl_recall);
843 struct nfs4_client *clp = dp->dl_stid.sc_client; 812 struct nfs4_client *clp = dp->dl_client;
844 813
845 dprintk("%s: minorversion=%d\n", __func__, 814 dprintk("%s: minorversion=%d\n", __func__,
846 clp->cl_minorversion); 815 clp->cl_minorversion);
@@ -863,7 +832,7 @@ static void nfsd4_cb_recall_done(struct rpc_task *task, void *calldata)
863{ 832{
864 struct nfsd4_callback *cb = calldata; 833 struct nfsd4_callback *cb = calldata;
865 struct nfs4_delegation *dp = container_of(cb, struct nfs4_delegation, dl_recall); 834 struct nfs4_delegation *dp = container_of(cb, struct nfs4_delegation, dl_recall);
866 struct nfs4_client *clp = dp->dl_stid.sc_client; 835 struct nfs4_client *clp = dp->dl_client;
867 struct rpc_clnt *current_rpc_client = clp->cl_cb_client; 836 struct rpc_clnt *current_rpc_client = clp->cl_cb_client;
868 837
869 nfsd4_cb_done(task, calldata); 838 nfsd4_cb_done(task, calldata);
@@ -936,7 +905,7 @@ void nfsd4_destroy_callback_queue(void)
936/* must be called under the state lock */ 905/* must be called under the state lock */
937void nfsd4_shutdown_callback(struct nfs4_client *clp) 906void nfsd4_shutdown_callback(struct nfs4_client *clp)
938{ 907{
939 set_bit(NFSD4_CLIENT_CB_KILL, &clp->cl_flags); 908 set_bit(NFSD4_CLIENT_KILL, &clp->cl_cb_flags);
940 /* 909 /*
941 * Note this won't actually result in a null callback; 910 * Note this won't actually result in a null callback;
942 * instead, nfsd4_do_callback_rpc() will detect the killed 911 * instead, nfsd4_do_callback_rpc() will detect the killed
@@ -982,22 +951,20 @@ static void nfsd4_process_cb_update(struct nfsd4_callback *cb)
982 if (clp->cl_cb_client) { 951 if (clp->cl_cb_client) {
983 rpc_shutdown_client(clp->cl_cb_client); 952 rpc_shutdown_client(clp->cl_cb_client);
984 clp->cl_cb_client = NULL; 953 clp->cl_cb_client = NULL;
985 put_rpccred(clp->cl_cb_cred);
986 clp->cl_cb_cred = NULL;
987 } 954 }
988 if (clp->cl_cb_conn.cb_xprt) { 955 if (clp->cl_cb_conn.cb_xprt) {
989 svc_xprt_put(clp->cl_cb_conn.cb_xprt); 956 svc_xprt_put(clp->cl_cb_conn.cb_xprt);
990 clp->cl_cb_conn.cb_xprt = NULL; 957 clp->cl_cb_conn.cb_xprt = NULL;
991 } 958 }
992 if (test_bit(NFSD4_CLIENT_CB_KILL, &clp->cl_flags)) 959 if (test_bit(NFSD4_CLIENT_KILL, &clp->cl_cb_flags))
993 return; 960 return;
994 spin_lock(&clp->cl_lock); 961 spin_lock(&clp->cl_lock);
995 /* 962 /*
996 * Only serialized callback code is allowed to clear these 963 * Only serialized callback code is allowed to clear these
997 * flags; main nfsd code can only set them: 964 * flags; main nfsd code can only set them:
998 */ 965 */
999 BUG_ON(!(clp->cl_flags & NFSD4_CLIENT_CB_FLAG_MASK)); 966 BUG_ON(!clp->cl_cb_flags);
1000 clear_bit(NFSD4_CLIENT_CB_UPDATE, &clp->cl_flags); 967 clear_bit(NFSD4_CLIENT_CB_UPDATE, &clp->cl_cb_flags);
1001 memcpy(&conn, &cb->cb_clp->cl_cb_conn, sizeof(struct nfs4_cb_conn)); 968 memcpy(&conn, &cb->cb_clp->cl_cb_conn, sizeof(struct nfs4_cb_conn));
1002 c = __nfsd4_find_backchannel(clp); 969 c = __nfsd4_find_backchannel(clp);
1003 if (c) { 970 if (c) {
@@ -1009,7 +976,7 @@ static void nfsd4_process_cb_update(struct nfsd4_callback *cb)
1009 976
1010 err = setup_callback_client(clp, &conn, ses); 977 err = setup_callback_client(clp, &conn, ses);
1011 if (err) { 978 if (err) {
1012 nfsd4_mark_cb_down(clp, err); 979 warn_no_callback_path(clp, err);
1013 return; 980 return;
1014 } 981 }
1015 /* Yay, the callback channel's back! Restart any callbacks: */ 982 /* Yay, the callback channel's back! Restart any callbacks: */
@@ -1017,13 +984,13 @@ static void nfsd4_process_cb_update(struct nfsd4_callback *cb)
1017 run_nfsd4_cb(cb); 984 run_nfsd4_cb(cb);
1018} 985}
1019 986
1020static void nfsd4_do_callback_rpc(struct work_struct *w) 987void nfsd4_do_callback_rpc(struct work_struct *w)
1021{ 988{
1022 struct nfsd4_callback *cb = container_of(w, struct nfsd4_callback, cb_work); 989 struct nfsd4_callback *cb = container_of(w, struct nfsd4_callback, cb_work);
1023 struct nfs4_client *clp = cb->cb_clp; 990 struct nfs4_client *clp = cb->cb_clp;
1024 struct rpc_clnt *clnt; 991 struct rpc_clnt *clnt;
1025 992
1026 if (clp->cl_flags & NFSD4_CLIENT_CB_FLAG_MASK) 993 if (clp->cl_cb_flags)
1027 nfsd4_process_cb_update(cb); 994 nfsd4_process_cb_update(cb);
1028 995
1029 clnt = clp->cl_cb_client; 996 clnt = clp->cl_cb_client;
@@ -1032,20 +999,14 @@ static void nfsd4_do_callback_rpc(struct work_struct *w)
1032 nfsd4_release_cb(cb); 999 nfsd4_release_cb(cb);
1033 return; 1000 return;
1034 } 1001 }
1035 cb->cb_msg.rpc_cred = clp->cl_cb_cred;
1036 rpc_call_async(clnt, &cb->cb_msg, RPC_TASK_SOFT | RPC_TASK_SOFTCONN, 1002 rpc_call_async(clnt, &cb->cb_msg, RPC_TASK_SOFT | RPC_TASK_SOFTCONN,
1037 cb->cb_ops, cb); 1003 cb->cb_ops, cb);
1038} 1004}
1039 1005
1040void nfsd4_init_callback(struct nfsd4_callback *cb)
1041{
1042 INIT_WORK(&cb->cb_work, nfsd4_do_callback_rpc);
1043}
1044
1045void nfsd4_cb_recall(struct nfs4_delegation *dp) 1006void nfsd4_cb_recall(struct nfs4_delegation *dp)
1046{ 1007{
1047 struct nfsd4_callback *cb = &dp->dl_recall; 1008 struct nfsd4_callback *cb = &dp->dl_recall;
1048 struct nfs4_client *clp = dp->dl_stid.sc_client; 1009 struct nfs4_client *clp = dp->dl_client;
1049 1010
1050 dp->dl_retries = 1; 1011 dp->dl_retries = 1;
1051 cb->cb_op = dp; 1012 cb->cb_op = dp;
@@ -1053,8 +1014,10 @@ void nfsd4_cb_recall(struct nfs4_delegation *dp)
1053 cb->cb_msg.rpc_proc = &nfs4_cb_procedures[NFSPROC4_CLNT_CB_RECALL]; 1014 cb->cb_msg.rpc_proc = &nfs4_cb_procedures[NFSPROC4_CLNT_CB_RECALL];
1054 cb->cb_msg.rpc_argp = cb; 1015 cb->cb_msg.rpc_argp = cb;
1055 cb->cb_msg.rpc_resp = cb; 1016 cb->cb_msg.rpc_resp = cb;
1017 cb->cb_msg.rpc_cred = callback_cred;
1056 1018
1057 cb->cb_ops = &nfsd4_cb_recall_ops; 1019 cb->cb_ops = &nfsd4_cb_recall_ops;
1020 dp->dl_retries = 1;
1058 1021
1059 INIT_LIST_HEAD(&cb->cb_per_client); 1022 INIT_LIST_HEAD(&cb->cb_per_client);
1060 cb->cb_done = true; 1023 cb->cb_done = true;