diff options
| author | J. Bruce Fields <bfields@redhat.com> | 2011-01-10 16:44:41 -0500 |
|---|---|---|
| committer | J. Bruce Fields <bfields@redhat.com> | 2011-01-11 15:04:11 -0500 |
| commit | 5ce8ba25d657a71d6d8cdb05a2b90c5ae7debfda (patch) | |
| tree | 831d815e91e23de373fe7fdc7a54b3eb098067f5 | |
| parent | 3ff3600e7eab16301e824293e8f49b9990bd4641 (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.c | 34 | ||||
| -rw-r--r-- | fs/nfsd/nfs4state.c | 1 | ||||
| -rw-r--r-- | fs/nfsd/state.h | 3 |
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 | ||
| 711 | static void nfsd4_cb_recall_release(void *calldata) | 719 | static 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 | ||
| 719 | static const struct rpc_call_ops nfsd4_cb_recall_ops = { | 733 | static 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 | ||
| 815 | void nfsd4_do_callback_rpc(struct work_struct *w) | 834 | void nfsd4_do_callback_rpc(struct work_struct *w) |
| @@ -834,10 +853,11 @@ void nfsd4_do_callback_rpc(struct work_struct *w) | |||
| 834 | void nfsd4_cb_recall(struct nfs4_delegation *dp) | 853 | void 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 { | |||
| 68 | struct nfsd4_callback { | 68 | struct 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 | ||
| 77 | struct nfs4_delegation { | 79 | struct 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; |
