aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfsd/nfs4callback.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2011-01-14 16:17:26 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2011-01-14 16:17:26 -0500
commit18bce371ae09af6c20ee62c1092a4d1d0e84dd49 (patch)
treef3467fafd8e49392e3f6efef7b88a7b4dd3b7b06 /fs/nfsd/nfs4callback.c
parentec08bdb148767f1193f5f3028749ed865ac27181 (diff)
parenta8f2800b4f7b76cecb7209cb6a7d2b14904fc711 (diff)
Merge branch 'for-2.6.38' of git://linux-nfs.org/~bfields/linux
* 'for-2.6.38' of git://linux-nfs.org/~bfields/linux: (62 commits) nfsd4: fix callback restarting nfsd: break lease on unlink, link, and rename nfsd4: break lease on nfsd setattr nfsd: don't support msnfs export option nfsd4: initialize cb_per_client nfsd4: allow restarting callbacks nfsd4: simplify nfsd4_cb_prepare nfsd4: give out delegations more quickly in 4.1 case nfsd4: add helper function to run callbacks nfsd4: make sure sequence flags are set after destroy_session nfsd4: re-probe callback on connection loss nfsd4: set sequence flag when backchannel is down nfsd4: keep finer-grained callback status rpc: allow xprt_class->setup to return a preexisting xprt rpc: keep backchannel xprt as long as server connection rpc: move sk_bc_xprt to svc_xprt nfsd4: allow backchannel recovery nfsd4: support BIND_CONN_TO_SESSION nfsd4: modify session list under cl_lock Documentation: fl_mylease no longer exists ... Fix up conflicts in fs/nfsd/vfs.c with the vfs-scale work. The vfs-scale work touched some msnfs cases, and this merge removes support for that entirely, so the conflict was trivial to resolve.
Diffstat (limited to 'fs/nfsd/nfs4callback.c')
-rw-r--r--fs/nfsd/nfs4callback.c151
1 files changed, 99 insertions, 52 deletions
diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c
index 21a63da305ff..3be975e18919 100644
--- a/fs/nfsd/nfs4callback.c
+++ b/fs/nfsd/nfs4callback.c
@@ -628,10 +628,8 @@ static int max_cb_time(void)
628 return max(nfsd4_lease/10, (time_t)1) * HZ; 628 return max(nfsd4_lease/10, (time_t)1) * HZ;
629} 629}
630 630
631/* Reference counting, callback cleanup, etc., all look racy as heck.
632 * And why is cl_cb_set an atomic? */
633 631
634int setup_callback_client(struct nfs4_client *clp, struct nfs4_cb_conn *conn) 632static int setup_callback_client(struct nfs4_client *clp, struct nfs4_cb_conn *conn, struct nfsd4_session *ses)
635{ 633{
636 struct rpc_timeout timeparms = { 634 struct rpc_timeout timeparms = {
637 .to_initval = max_cb_time(), 635 .to_initval = max_cb_time(),
@@ -641,6 +639,7 @@ int setup_callback_client(struct nfs4_client *clp, struct nfs4_cb_conn *conn)
641 .net = &init_net, 639 .net = &init_net,
642 .address = (struct sockaddr *) &conn->cb_addr, 640 .address = (struct sockaddr *) &conn->cb_addr,
643 .addrsize = conn->cb_addrlen, 641 .addrsize = conn->cb_addrlen,
642 .saddress = (struct sockaddr *) &conn->cb_saddr,
644 .timeout = &timeparms, 643 .timeout = &timeparms,
645 .program = &cb_program, 644 .program = &cb_program,
646 .version = 0, 645 .version = 0,
@@ -657,6 +656,10 @@ int setup_callback_client(struct nfs4_client *clp, struct nfs4_cb_conn *conn)
657 args.protocol = XPRT_TRANSPORT_TCP; 656 args.protocol = XPRT_TRANSPORT_TCP;
658 clp->cl_cb_ident = conn->cb_ident; 657 clp->cl_cb_ident = conn->cb_ident;
659 } else { 658 } else {
659 if (!conn->cb_xprt)
660 return -EINVAL;
661 clp->cl_cb_conn.cb_xprt = conn->cb_xprt;
662 clp->cl_cb_session = ses;
660 args.bc_xprt = conn->cb_xprt; 663 args.bc_xprt = conn->cb_xprt;
661 args.prognumber = clp->cl_cb_session->se_cb_prog; 664 args.prognumber = clp->cl_cb_session->se_cb_prog;
662 args.protocol = XPRT_TRANSPORT_BC_TCP; 665 args.protocol = XPRT_TRANSPORT_BC_TCP;
@@ -679,14 +682,20 @@ static void warn_no_callback_path(struct nfs4_client *clp, int reason)
679 (int)clp->cl_name.len, clp->cl_name.data, reason); 682 (int)clp->cl_name.len, clp->cl_name.data, reason);
680} 683}
681 684
685static void nfsd4_mark_cb_down(struct nfs4_client *clp, int reason)
686{
687 clp->cl_cb_state = NFSD4_CB_DOWN;
688 warn_no_callback_path(clp, reason);
689}
690
682static void nfsd4_cb_probe_done(struct rpc_task *task, void *calldata) 691static void nfsd4_cb_probe_done(struct rpc_task *task, void *calldata)
683{ 692{
684 struct nfs4_client *clp = container_of(calldata, struct nfs4_client, cl_cb_null); 693 struct nfs4_client *clp = container_of(calldata, struct nfs4_client, cl_cb_null);
685 694
686 if (task->tk_status) 695 if (task->tk_status)
687 warn_no_callback_path(clp, task->tk_status); 696 nfsd4_mark_cb_down(clp, task->tk_status);
688 else 697 else
689 atomic_set(&clp->cl_cb_set, 1); 698 clp->cl_cb_state = NFSD4_CB_UP;
690} 699}
691 700
692static const struct rpc_call_ops nfsd4_cb_probe_ops = { 701static const struct rpc_call_ops nfsd4_cb_probe_ops = {
@@ -709,6 +718,11 @@ int set_callback_cred(void)
709 718
710static struct workqueue_struct *callback_wq; 719static struct workqueue_struct *callback_wq;
711 720
721static void run_nfsd4_cb(struct nfsd4_callback *cb)
722{
723 queue_work(callback_wq, &cb->cb_work);
724}
725
712static void do_probe_callback(struct nfs4_client *clp) 726static void do_probe_callback(struct nfs4_client *clp)
713{ 727{
714 struct nfsd4_callback *cb = &clp->cl_cb_null; 728 struct nfsd4_callback *cb = &clp->cl_cb_null;
@@ -723,7 +737,7 @@ static void do_probe_callback(struct nfs4_client *clp)
723 737
724 cb->cb_ops = &nfsd4_cb_probe_ops; 738 cb->cb_ops = &nfsd4_cb_probe_ops;
725 739
726 queue_work(callback_wq, &cb->cb_work); 740 run_nfsd4_cb(cb);
727} 741}
728 742
729/* 743/*
@@ -732,14 +746,21 @@ static void do_probe_callback(struct nfs4_client *clp)
732 */ 746 */
733void nfsd4_probe_callback(struct nfs4_client *clp) 747void nfsd4_probe_callback(struct nfs4_client *clp)
734{ 748{
749 /* XXX: atomicity? Also, should we be using cl_cb_flags? */
750 clp->cl_cb_state = NFSD4_CB_UNKNOWN;
735 set_bit(NFSD4_CLIENT_CB_UPDATE, &clp->cl_cb_flags); 751 set_bit(NFSD4_CLIENT_CB_UPDATE, &clp->cl_cb_flags);
736 do_probe_callback(clp); 752 do_probe_callback(clp);
737} 753}
738 754
739void nfsd4_change_callback(struct nfs4_client *clp, struct nfs4_cb_conn *conn) 755void nfsd4_probe_callback_sync(struct nfs4_client *clp)
740{ 756{
741 BUG_ON(atomic_read(&clp->cl_cb_set)); 757 nfsd4_probe_callback(clp);
758 flush_workqueue(callback_wq);
759}
742 760
761void nfsd4_change_callback(struct nfs4_client *clp, struct nfs4_cb_conn *conn)
762{
763 clp->cl_cb_state = NFSD4_CB_UNKNOWN;
743 spin_lock(&clp->cl_lock); 764 spin_lock(&clp->cl_lock);
744 memcpy(&clp->cl_cb_conn, conn, sizeof(struct nfs4_cb_conn)); 765 memcpy(&clp->cl_cb_conn, conn, sizeof(struct nfs4_cb_conn));
745 spin_unlock(&clp->cl_lock); 766 spin_unlock(&clp->cl_lock);
@@ -750,24 +771,14 @@ void nfsd4_change_callback(struct nfs4_client *clp, struct nfs4_cb_conn *conn)
750 * If the slot is available, then mark it busy. Otherwise, set the 771 * If the slot is available, then mark it busy. Otherwise, set the
751 * thread for sleeping on the callback RPC wait queue. 772 * thread for sleeping on the callback RPC wait queue.
752 */ 773 */
753static int nfsd41_cb_setup_sequence(struct nfs4_client *clp, 774static bool nfsd41_cb_get_slot(struct nfs4_client *clp, struct rpc_task *task)
754 struct rpc_task *task)
755{ 775{
756 u32 *ptr = (u32 *)clp->cl_cb_session->se_sessionid.data;
757 int status = 0;
758
759 dprintk("%s: %u:%u:%u:%u\n", __func__,
760 ptr[0], ptr[1], ptr[2], ptr[3]);
761
762 if (test_and_set_bit(0, &clp->cl_cb_slot_busy) != 0) { 776 if (test_and_set_bit(0, &clp->cl_cb_slot_busy) != 0) {
763 rpc_sleep_on(&clp->cl_cb_waitq, task, NULL); 777 rpc_sleep_on(&clp->cl_cb_waitq, task, NULL);
764 dprintk("%s slot is busy\n", __func__); 778 dprintk("%s slot is busy\n", __func__);
765 status = -EAGAIN; 779 return false;
766 goto out;
767 } 780 }
768out: 781 return true;
769 dprintk("%s status=%d\n", __func__, status);
770 return status;
771} 782}
772 783
773/* 784/*
@@ -780,20 +791,19 @@ static void nfsd4_cb_prepare(struct rpc_task *task, void *calldata)
780 struct nfs4_delegation *dp = container_of(cb, struct nfs4_delegation, dl_recall); 791 struct nfs4_delegation *dp = container_of(cb, struct nfs4_delegation, dl_recall);
781 struct nfs4_client *clp = dp->dl_client; 792 struct nfs4_client *clp = dp->dl_client;
782 u32 minorversion = clp->cl_minorversion; 793 u32 minorversion = clp->cl_minorversion;
783 int status = 0;
784 794
785 cb->cb_minorversion = minorversion; 795 cb->cb_minorversion = minorversion;
786 if (minorversion) { 796 if (minorversion) {
787 status = nfsd41_cb_setup_sequence(clp, task); 797 if (!nfsd41_cb_get_slot(clp, task))
788 if (status) {
789 if (status != -EAGAIN) {
790 /* terminate rpc task */
791 task->tk_status = status;
792 task->tk_action = NULL;
793 }
794 return; 798 return;
795 }
796 } 799 }
800 spin_lock(&clp->cl_lock);
801 if (list_empty(&cb->cb_per_client)) {
802 /* This is the first call, not a restart */
803 cb->cb_done = false;
804 list_add(&cb->cb_per_client, &clp->cl_callbacks);
805 }
806 spin_unlock(&clp->cl_lock);
797 rpc_call_start(task); 807 rpc_call_start(task);
798} 808}
799 809
@@ -829,15 +839,18 @@ static void nfsd4_cb_recall_done(struct rpc_task *task, void *calldata)
829 839
830 nfsd4_cb_done(task, calldata); 840 nfsd4_cb_done(task, calldata);
831 841
832 if (current_rpc_client == NULL) { 842 if (current_rpc_client != task->tk_client) {
833 /* We're shutting down; give up. */ 843 /* We're shutting down or changing cl_cb_client; leave
834 /* XXX: err, or is it ok just to fall through 844 * it to nfsd4_process_cb_update to restart the call if
835 * and rpc_restart_call? */ 845 * necessary. */
836 return; 846 return;
837 } 847 }
838 848
849 if (cb->cb_done)
850 return;
839 switch (task->tk_status) { 851 switch (task->tk_status) {
840 case 0: 852 case 0:
853 cb->cb_done = true;
841 return; 854 return;
842 case -EBADHANDLE: 855 case -EBADHANDLE:
843 case -NFS4ERR_BAD_STATEID: 856 case -NFS4ERR_BAD_STATEID:
@@ -846,32 +859,30 @@ static void nfsd4_cb_recall_done(struct rpc_task *task, void *calldata)
846 break; 859 break;
847 default: 860 default:
848 /* Network partition? */ 861 /* Network partition? */
849 atomic_set(&clp->cl_cb_set, 0); 862 nfsd4_mark_cb_down(clp, task->tk_status);
850 warn_no_callback_path(clp, task->tk_status);
851 if (current_rpc_client != task->tk_client) {
852 /* queue a callback on the new connection: */
853 atomic_inc(&dp->dl_count);
854 nfsd4_cb_recall(dp);
855 return;
856 }
857 } 863 }
858 if (dp->dl_retries--) { 864 if (dp->dl_retries--) {
859 rpc_delay(task, 2*HZ); 865 rpc_delay(task, 2*HZ);
860 task->tk_status = 0; 866 task->tk_status = 0;
861 rpc_restart_call_prepare(task); 867 rpc_restart_call_prepare(task);
862 return; 868 return;
863 } else {
864 atomic_set(&clp->cl_cb_set, 0);
865 warn_no_callback_path(clp, task->tk_status);
866 } 869 }
870 nfsd4_mark_cb_down(clp, task->tk_status);
871 cb->cb_done = true;
867} 872}
868 873
869static void nfsd4_cb_recall_release(void *calldata) 874static void nfsd4_cb_recall_release(void *calldata)
870{ 875{
871 struct nfsd4_callback *cb = calldata; 876 struct nfsd4_callback *cb = calldata;
877 struct nfs4_client *clp = cb->cb_clp;
872 struct nfs4_delegation *dp = container_of(cb, struct nfs4_delegation, dl_recall); 878 struct nfs4_delegation *dp = container_of(cb, struct nfs4_delegation, dl_recall);
873 879
874 nfs4_put_delegation(dp); 880 if (cb->cb_done) {
881 spin_lock(&clp->cl_lock);
882 list_del(&cb->cb_per_client);
883 spin_unlock(&clp->cl_lock);
884 nfs4_put_delegation(dp);
885 }
875} 886}
876 887
877static const struct rpc_call_ops nfsd4_cb_recall_ops = { 888static const struct rpc_call_ops nfsd4_cb_recall_ops = {
@@ -906,16 +917,33 @@ void nfsd4_shutdown_callback(struct nfs4_client *clp)
906 flush_workqueue(callback_wq); 917 flush_workqueue(callback_wq);
907} 918}
908 919
909void nfsd4_release_cb(struct nfsd4_callback *cb) 920static void nfsd4_release_cb(struct nfsd4_callback *cb)
910{ 921{
911 if (cb->cb_ops->rpc_release) 922 if (cb->cb_ops->rpc_release)
912 cb->cb_ops->rpc_release(cb); 923 cb->cb_ops->rpc_release(cb);
913} 924}
914 925
915void nfsd4_process_cb_update(struct nfsd4_callback *cb) 926/* requires cl_lock: */
927static struct nfsd4_conn * __nfsd4_find_backchannel(struct nfs4_client *clp)
928{
929 struct nfsd4_session *s;
930 struct nfsd4_conn *c;
931
932 list_for_each_entry(s, &clp->cl_sessions, se_perclnt) {
933 list_for_each_entry(c, &s->se_conns, cn_persession) {
934 if (c->cn_flags & NFS4_CDFC4_BACK)
935 return c;
936 }
937 }
938 return NULL;
939}
940
941static void nfsd4_process_cb_update(struct nfsd4_callback *cb)
916{ 942{
917 struct nfs4_cb_conn conn; 943 struct nfs4_cb_conn conn;
918 struct nfs4_client *clp = cb->cb_clp; 944 struct nfs4_client *clp = cb->cb_clp;
945 struct nfsd4_session *ses = NULL;
946 struct nfsd4_conn *c;
919 int err; 947 int err;
920 948
921 /* 949 /*
@@ -926,6 +954,10 @@ void nfsd4_process_cb_update(struct nfsd4_callback *cb)
926 rpc_shutdown_client(clp->cl_cb_client); 954 rpc_shutdown_client(clp->cl_cb_client);
927 clp->cl_cb_client = NULL; 955 clp->cl_cb_client = NULL;
928 } 956 }
957 if (clp->cl_cb_conn.cb_xprt) {
958 svc_xprt_put(clp->cl_cb_conn.cb_xprt);
959 clp->cl_cb_conn.cb_xprt = NULL;
960 }
929 if (test_bit(NFSD4_CLIENT_KILL, &clp->cl_cb_flags)) 961 if (test_bit(NFSD4_CLIENT_KILL, &clp->cl_cb_flags))
930 return; 962 return;
931 spin_lock(&clp->cl_lock); 963 spin_lock(&clp->cl_lock);
@@ -936,11 +968,22 @@ void nfsd4_process_cb_update(struct nfsd4_callback *cb)
936 BUG_ON(!clp->cl_cb_flags); 968 BUG_ON(!clp->cl_cb_flags);
937 clear_bit(NFSD4_CLIENT_CB_UPDATE, &clp->cl_cb_flags); 969 clear_bit(NFSD4_CLIENT_CB_UPDATE, &clp->cl_cb_flags);
938 memcpy(&conn, &cb->cb_clp->cl_cb_conn, sizeof(struct nfs4_cb_conn)); 970 memcpy(&conn, &cb->cb_clp->cl_cb_conn, sizeof(struct nfs4_cb_conn));
971 c = __nfsd4_find_backchannel(clp);
972 if (c) {
973 svc_xprt_get(c->cn_xprt);
974 conn.cb_xprt = c->cn_xprt;
975 ses = c->cn_session;
976 }
939 spin_unlock(&clp->cl_lock); 977 spin_unlock(&clp->cl_lock);
940 978
941 err = setup_callback_client(clp, &conn); 979 err = setup_callback_client(clp, &conn, ses);
942 if (err) 980 if (err) {
943 warn_no_callback_path(clp, err); 981 warn_no_callback_path(clp, err);
982 return;
983 }
984 /* Yay, the callback channel's back! Restart any callbacks: */
985 list_for_each_entry(cb, &clp->cl_callbacks, cb_per_client)
986 run_nfsd4_cb(cb);
944} 987}
945 988
946void nfsd4_do_callback_rpc(struct work_struct *w) 989void nfsd4_do_callback_rpc(struct work_struct *w)
@@ -965,10 +1008,11 @@ void nfsd4_do_callback_rpc(struct work_struct *w)
965void nfsd4_cb_recall(struct nfs4_delegation *dp) 1008void nfsd4_cb_recall(struct nfs4_delegation *dp)
966{ 1009{
967 struct nfsd4_callback *cb = &dp->dl_recall; 1010 struct nfsd4_callback *cb = &dp->dl_recall;
1011 struct nfs4_client *clp = dp->dl_client;
968 1012
969 dp->dl_retries = 1; 1013 dp->dl_retries = 1;
970 cb->cb_op = dp; 1014 cb->cb_op = dp;
971 cb->cb_clp = dp->dl_client; 1015 cb->cb_clp = clp;
972 cb->cb_msg.rpc_proc = &nfs4_cb_procedures[NFSPROC4_CLNT_CB_RECALL]; 1016 cb->cb_msg.rpc_proc = &nfs4_cb_procedures[NFSPROC4_CLNT_CB_RECALL];
973 cb->cb_msg.rpc_argp = cb; 1017 cb->cb_msg.rpc_argp = cb;
974 cb->cb_msg.rpc_resp = cb; 1018 cb->cb_msg.rpc_resp = cb;
@@ -977,5 +1021,8 @@ void nfsd4_cb_recall(struct nfs4_delegation *dp)
977 cb->cb_ops = &nfsd4_cb_recall_ops; 1021 cb->cb_ops = &nfsd4_cb_recall_ops;
978 dp->dl_retries = 1; 1022 dp->dl_retries = 1;
979 1023
980 queue_work(callback_wq, &dp->dl_recall.cb_work); 1024 INIT_LIST_HEAD(&cb->cb_per_client);
1025 cb->cb_done = true;
1026
1027 run_nfsd4_cb(&dp->dl_recall);
981} 1028}