aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJ. Bruce Fields <bfields@redhat.com>2011-01-10 16:44:41 -0500
committerJ. Bruce Fields <bfields@redhat.com>2011-01-11 15:04:11 -0500
commit5ce8ba25d657a71d6d8cdb05a2b90c5ae7debfda (patch)
tree831d815e91e23de373fe7fdc7a54b3eb098067f5
parent3ff3600e7eab16301e824293e8f49b9990bd4641 (diff)
nfsd4: allow restarting callbacks
If we lose the backchannel and then the client repairs the problem, resend any callbacks. We use a new cb_done flag to track whether there is still work to be done for the callback or whether it can be destroyed with the rpc. Signed-off-by: J. Bruce Fields <bfields@redhat.com>
-rw-r--r--fs/nfsd/nfs4callback.c34
-rw-r--r--fs/nfsd/nfs4state.c1
-rw-r--r--fs/nfsd/state.h3
3 files changed, 32 insertions, 6 deletions
diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c
index 69955e98e086..f1d9dd45553a 100644
--- a/fs/nfsd/nfs4callback.c
+++ b/fs/nfsd/nfs4callback.c
@@ -639,6 +639,10 @@ static void nfsd4_cb_prepare(struct rpc_task *task, void *calldata)
639 if (!nfsd41_cb_get_slot(clp, task)) 639 if (!nfsd41_cb_get_slot(clp, task))
640 return; 640 return;
641 } 641 }
642 cb->cb_done = false;
643 spin_lock(&clp->cl_lock);
644 list_add(&cb->cb_per_client, &clp->cl_callbacks);
645 spin_unlock(&clp->cl_lock);
642 rpc_call_start(task); 646 rpc_call_start(task);
643} 647}
644 648
@@ -681,8 +685,11 @@ static void nfsd4_cb_recall_done(struct rpc_task *task, void *calldata)
681 return; 685 return;
682 } 686 }
683 687
688 if (cb->cb_done)
689 return;
684 switch (task->tk_status) { 690 switch (task->tk_status) {
685 case 0: 691 case 0:
692 cb->cb_done = true;
686 return; 693 return;
687 case -EBADHANDLE: 694 case -EBADHANDLE:
688 case -NFS4ERR_BAD_STATEID: 695 case -NFS4ERR_BAD_STATEID:
@@ -695,7 +702,7 @@ static void nfsd4_cb_recall_done(struct rpc_task *task, void *calldata)
695 if (current_rpc_client != task->tk_client) { 702 if (current_rpc_client != task->tk_client) {
696 /* queue a callback on the new connection: */ 703 /* queue a callback on the new connection: */
697 atomic_inc(&dp->dl_count); 704 atomic_inc(&dp->dl_count);
698 nfsd4_cb_recall(dp); 705 run_nfsd4_cb(&dp->dl_recall);
699 return; 706 return;
700 } 707 }
701 } 708 }
@@ -704,16 +711,23 @@ static void nfsd4_cb_recall_done(struct rpc_task *task, void *calldata)
704 task->tk_status = 0; 711 task->tk_status = 0;
705 rpc_restart_call_prepare(task); 712 rpc_restart_call_prepare(task);
706 return; 713 return;
707 } else 714 }
708 nfsd4_mark_cb_down(clp, task->tk_status); 715 nfsd4_mark_cb_down(clp, task->tk_status);
716 cb->cb_done = true;
709} 717}
710 718
711static void nfsd4_cb_recall_release(void *calldata) 719static void nfsd4_cb_recall_release(void *calldata)
712{ 720{
713 struct nfsd4_callback *cb = calldata; 721 struct nfsd4_callback *cb = calldata;
722 struct nfs4_client *clp = cb->cb_clp;
714 struct nfs4_delegation *dp = container_of(cb, struct nfs4_delegation, dl_recall); 723 struct nfs4_delegation *dp = container_of(cb, struct nfs4_delegation, dl_recall);
715 724
716 nfs4_put_delegation(dp); 725 if (cb->cb_done) {
726 spin_lock(&clp->cl_lock);
727 list_del(&cb->cb_per_client);
728 spin_unlock(&clp->cl_lock);
729 nfs4_put_delegation(dp);
730 }
717} 731}
718 732
719static const struct rpc_call_ops nfsd4_cb_recall_ops = { 733static const struct rpc_call_ops nfsd4_cb_recall_ops = {
@@ -808,8 +822,13 @@ static void nfsd4_process_cb_update(struct nfsd4_callback *cb)
808 spin_unlock(&clp->cl_lock); 822 spin_unlock(&clp->cl_lock);
809 823
810 err = setup_callback_client(clp, &conn, ses); 824 err = setup_callback_client(clp, &conn, ses);
811 if (err) 825 if (err) {
812 warn_no_callback_path(clp, err); 826 warn_no_callback_path(clp, err);
827 return;
828 }
829 /* Yay, the callback channel's back! Restart any callbacks: */
830 list_for_each_entry(cb, &clp->cl_callbacks, cb_per_client)
831 run_nfsd4_cb(cb);
813} 832}
814 833
815void nfsd4_do_callback_rpc(struct work_struct *w) 834void nfsd4_do_callback_rpc(struct work_struct *w)
@@ -834,10 +853,11 @@ void nfsd4_do_callback_rpc(struct work_struct *w)
834void nfsd4_cb_recall(struct nfs4_delegation *dp) 853void nfsd4_cb_recall(struct nfs4_delegation *dp)
835{ 854{
836 struct nfsd4_callback *cb = &dp->dl_recall; 855 struct nfsd4_callback *cb = &dp->dl_recall;
856 struct nfs4_client *clp = dp->dl_client;
837 857
838 dp->dl_retries = 1; 858 dp->dl_retries = 1;
839 cb->cb_op = dp; 859 cb->cb_op = dp;
840 cb->cb_clp = dp->dl_client; 860 cb->cb_clp = clp;
841 cb->cb_msg.rpc_proc = &nfs4_cb_procedures[NFSPROC4_CLNT_CB_RECALL]; 861 cb->cb_msg.rpc_proc = &nfs4_cb_procedures[NFSPROC4_CLNT_CB_RECALL];
842 cb->cb_msg.rpc_argp = cb; 862 cb->cb_msg.rpc_argp = cb;
843 cb->cb_msg.rpc_resp = cb; 863 cb->cb_msg.rpc_resp = cb;
@@ -846,5 +866,7 @@ void nfsd4_cb_recall(struct nfs4_delegation *dp)
846 cb->cb_ops = &nfsd4_cb_recall_ops; 866 cb->cb_ops = &nfsd4_cb_recall_ops;
847 dp->dl_retries = 1; 867 dp->dl_retries = 1;
848 868
869 cb->cb_done = true;
870
849 run_nfsd4_cb(&dp->dl_recall); 871 run_nfsd4_cb(&dp->dl_recall);
850} 872}
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 408957cf6016..6e1f9aadd439 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -1077,6 +1077,7 @@ static struct nfs4_client *create_client(struct xdr_netobj name, char *recdir,
1077 INIT_LIST_HEAD(&clp->cl_openowners); 1077 INIT_LIST_HEAD(&clp->cl_openowners);
1078 INIT_LIST_HEAD(&clp->cl_delegations); 1078 INIT_LIST_HEAD(&clp->cl_delegations);
1079 INIT_LIST_HEAD(&clp->cl_lru); 1079 INIT_LIST_HEAD(&clp->cl_lru);
1080 INIT_LIST_HEAD(&clp->cl_callbacks);
1080 spin_lock_init(&clp->cl_lock); 1081 spin_lock_init(&clp->cl_lock);
1081 INIT_WORK(&clp->cl_cb_null.cb_work, nfsd4_do_callback_rpc); 1082 INIT_WORK(&clp->cl_cb_null.cb_work, nfsd4_do_callback_rpc);
1082 clp->cl_time = get_seconds(); 1083 clp->cl_time = get_seconds();
diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h
index 4e5bdfd9169c..3074656ba7bf 100644
--- a/fs/nfsd/state.h
+++ b/fs/nfsd/state.h
@@ -68,10 +68,12 @@ typedef struct {
68struct nfsd4_callback { 68struct nfsd4_callback {
69 void *cb_op; 69 void *cb_op;
70 struct nfs4_client *cb_clp; 70 struct nfs4_client *cb_clp;
71 struct list_head cb_per_client;
71 u32 cb_minorversion; 72 u32 cb_minorversion;
72 struct rpc_message cb_msg; 73 struct rpc_message cb_msg;
73 const struct rpc_call_ops *cb_ops; 74 const struct rpc_call_ops *cb_ops;
74 struct work_struct cb_work; 75 struct work_struct cb_work;
76 bool cb_done;
75}; 77};
76 78
77struct nfs4_delegation { 79struct nfs4_delegation {
@@ -248,6 +250,7 @@ struct nfs4_client {
248 int cl_cb_state; 250 int cl_cb_state;
249 struct nfsd4_callback cl_cb_null; 251 struct nfsd4_callback cl_cb_null;
250 struct nfsd4_session *cl_cb_session; 252 struct nfsd4_session *cl_cb_session;
253 struct list_head cl_callbacks; /* list of in-progress callbacks */
251 254
252 /* for all client information that callback code might need: */ 255 /* for all client information that callback code might need: */
253 spinlock_t cl_lock; 256 spinlock_t cl_lock;