diff options
author | Christoph Hellwig <hch@lst.de> | 2014-09-24 06:19:19 -0400 |
---|---|---|
committer | J. Bruce Fields <bfields@redhat.com> | 2014-09-26 16:29:29 -0400 |
commit | 0162ac2b978e18792fa8cf3c0b4304321b4a3983 (patch) | |
tree | 7b395d5baedb818afce87ec4142ea6c767ccf187 /fs | |
parent | f0b5de1b6b8b66552bcc7ae692f45940d411cf05 (diff) |
nfsd: introduce nfsd4_callback_ops
Add a higher level abstraction than the rpc_ops for callback operations.
Signed-off-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Jeff Layton <jlayton@primarydata.com>
Signed-off-by: J. Bruce Fields <bfields@redhat.com>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/nfsd/nfs4callback.c | 91 | ||||
-rw-r--r-- | fs/nfsd/nfs4state.c | 51 | ||||
-rw-r--r-- | fs/nfsd/state.h | 12 |
3 files changed, 83 insertions, 71 deletions
diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c index d97e2009e310..4fe4be1ee82e 100644 --- a/fs/nfsd/nfs4callback.c +++ b/fs/nfsd/nfs4callback.c | |||
@@ -824,18 +824,8 @@ static void nfsd4_cb_done(struct rpc_task *task, void *calldata) | |||
824 | dprintk("%s: freed slot, new seqid=%d\n", __func__, | 824 | dprintk("%s: freed slot, new seqid=%d\n", __func__, |
825 | clp->cl_cb_session->se_cb_seq_nr); | 825 | clp->cl_cb_session->se_cb_seq_nr); |
826 | } | 826 | } |
827 | } | ||
828 | 827 | ||
829 | static void nfsd4_cb_recall_done(struct rpc_task *task, void *calldata) | 828 | if (clp->cl_cb_client != task->tk_client) { |
830 | { | ||
831 | struct nfsd4_callback *cb = calldata; | ||
832 | struct nfs4_delegation *dp = to_delegation(cb); | ||
833 | struct nfs4_client *clp = cb->cb_clp; | ||
834 | struct rpc_clnt *current_rpc_client = clp->cl_cb_client; | ||
835 | |||
836 | nfsd4_cb_done(task, calldata); | ||
837 | |||
838 | if (current_rpc_client != task->tk_client) { | ||
839 | /* We're shutting down or changing cl_cb_client; leave | 829 | /* We're shutting down or changing cl_cb_client; leave |
840 | * it to nfsd4_process_cb_update to restart the call if | 830 | * it to nfsd4_process_cb_update to restart the call if |
841 | * necessary. */ | 831 | * necessary. */ |
@@ -844,45 +834,42 @@ static void nfsd4_cb_recall_done(struct rpc_task *task, void *calldata) | |||
844 | 834 | ||
845 | if (cb->cb_done) | 835 | if (cb->cb_done) |
846 | return; | 836 | return; |
847 | switch (task->tk_status) { | 837 | |
838 | switch (cb->cb_ops->done(cb, task)) { | ||
848 | case 0: | 839 | case 0: |
840 | task->tk_status = 0; | ||
841 | rpc_restart_call_prepare(task); | ||
842 | return; | ||
843 | case 1: | ||
849 | break; | 844 | break; |
850 | case -EBADHANDLE: | 845 | case -1: |
851 | case -NFS4ERR_BAD_STATEID: | ||
852 | /* Race: client probably got cb_recall | ||
853 | * before open reply granting delegation */ | ||
854 | if (dp->dl_retries--) { | ||
855 | rpc_delay(task, 2*HZ); | ||
856 | task->tk_status = 0; | ||
857 | rpc_restart_call_prepare(task); | ||
858 | return; | ||
859 | } | ||
860 | default: | ||
861 | /* Network partition? */ | 846 | /* Network partition? */ |
862 | nfsd4_mark_cb_down(clp, task->tk_status); | 847 | nfsd4_mark_cb_down(clp, task->tk_status); |
848 | break; | ||
849 | default: | ||
850 | BUG(); | ||
863 | } | 851 | } |
864 | cb->cb_done = true; | 852 | cb->cb_done = true; |
865 | } | 853 | } |
866 | 854 | ||
867 | static void nfsd4_cb_recall_release(void *calldata) | 855 | static void nfsd4_cb_release(void *calldata) |
868 | { | 856 | { |
869 | struct nfsd4_callback *cb = calldata; | 857 | struct nfsd4_callback *cb = calldata; |
870 | struct nfs4_client *clp = cb->cb_clp; | 858 | struct nfs4_client *clp = cb->cb_clp; |
871 | 859 | ||
872 | if (cb->cb_done) { | 860 | if (cb->cb_done) { |
873 | struct nfs4_delegation *dp = to_delegation(cb); | ||
874 | |||
875 | spin_lock(&clp->cl_lock); | 861 | spin_lock(&clp->cl_lock); |
876 | list_del(&cb->cb_per_client); | 862 | list_del(&cb->cb_per_client); |
877 | spin_unlock(&clp->cl_lock); | 863 | spin_unlock(&clp->cl_lock); |
878 | nfs4_put_stid(&dp->dl_stid); | 864 | |
865 | cb->cb_ops->release(cb); | ||
879 | } | 866 | } |
880 | } | 867 | } |
881 | 868 | ||
882 | static const struct rpc_call_ops nfsd4_cb_recall_ops = { | 869 | static const struct rpc_call_ops nfsd4_cb_ops = { |
883 | .rpc_call_prepare = nfsd4_cb_prepare, | 870 | .rpc_call_prepare = nfsd4_cb_prepare, |
884 | .rpc_call_done = nfsd4_cb_recall_done, | 871 | .rpc_call_done = nfsd4_cb_done, |
885 | .rpc_release = nfsd4_cb_recall_release, | 872 | .rpc_release = nfsd4_cb_release, |
886 | }; | 873 | }; |
887 | 874 | ||
888 | int nfsd4_create_callback_queue(void) | 875 | int nfsd4_create_callback_queue(void) |
@@ -911,12 +898,6 @@ void nfsd4_shutdown_callback(struct nfs4_client *clp) | |||
911 | flush_workqueue(callback_wq); | 898 | flush_workqueue(callback_wq); |
912 | } | 899 | } |
913 | 900 | ||
914 | static void nfsd4_release_cb(struct nfsd4_callback *cb) | ||
915 | { | ||
916 | if (cb->cb_ops->rpc_release) | ||
917 | cb->cb_ops->rpc_release(cb); | ||
918 | } | ||
919 | |||
920 | /* requires cl_lock: */ | 901 | /* requires cl_lock: */ |
921 | static struct nfsd4_conn * __nfsd4_find_backchannel(struct nfs4_client *clp) | 902 | static struct nfsd4_conn * __nfsd4_find_backchannel(struct nfs4_client *clp) |
922 | { | 903 | { |
@@ -983,54 +964,40 @@ static void nfsd4_process_cb_update(struct nfsd4_callback *cb) | |||
983 | } | 964 | } |
984 | 965 | ||
985 | static void | 966 | static void |
986 | nfsd4_run_callback_rpc(struct nfsd4_callback *cb) | 967 | nfsd4_run_cb_work(struct work_struct *work) |
987 | { | 968 | { |
969 | struct nfsd4_callback *cb = | ||
970 | container_of(work, struct nfsd4_callback, cb_work); | ||
988 | struct nfs4_client *clp = cb->cb_clp; | 971 | struct nfs4_client *clp = cb->cb_clp; |
989 | struct rpc_clnt *clnt; | 972 | struct rpc_clnt *clnt; |
990 | 973 | ||
974 | if (cb->cb_ops && cb->cb_ops->prepare) | ||
975 | cb->cb_ops->prepare(cb); | ||
976 | |||
991 | if (clp->cl_flags & NFSD4_CLIENT_CB_FLAG_MASK) | 977 | if (clp->cl_flags & NFSD4_CLIENT_CB_FLAG_MASK) |
992 | nfsd4_process_cb_update(cb); | 978 | nfsd4_process_cb_update(cb); |
993 | 979 | ||
994 | clnt = clp->cl_cb_client; | 980 | clnt = clp->cl_cb_client; |
995 | if (!clnt) { | 981 | if (!clnt) { |
996 | /* Callback channel broken, or client killed; give up: */ | 982 | /* Callback channel broken, or client killed; give up: */ |
997 | nfsd4_release_cb(cb); | 983 | if (cb->cb_ops && cb->cb_ops->release) |
984 | cb->cb_ops->release(cb); | ||
998 | return; | 985 | return; |
999 | } | 986 | } |
1000 | cb->cb_msg.rpc_cred = clp->cl_cb_cred; | 987 | cb->cb_msg.rpc_cred = clp->cl_cb_cred; |
1001 | rpc_call_async(clnt, &cb->cb_msg, RPC_TASK_SOFT | RPC_TASK_SOFTCONN, | 988 | rpc_call_async(clnt, &cb->cb_msg, RPC_TASK_SOFT | RPC_TASK_SOFTCONN, |
1002 | cb->cb_ops, cb); | 989 | cb->cb_ops ? &nfsd4_cb_ops : &nfsd4_cb_probe_ops, cb); |
1003 | } | ||
1004 | |||
1005 | void | ||
1006 | nfsd4_run_cb_null(struct work_struct *w) | ||
1007 | { | ||
1008 | struct nfsd4_callback *cb = container_of(w, struct nfsd4_callback, | ||
1009 | cb_work); | ||
1010 | nfsd4_run_callback_rpc(cb); | ||
1011 | } | ||
1012 | |||
1013 | void | ||
1014 | nfsd4_run_cb_recall(struct work_struct *w) | ||
1015 | { | ||
1016 | struct nfsd4_callback *cb = container_of(w, struct nfsd4_callback, | ||
1017 | cb_work); | ||
1018 | |||
1019 | nfsd4_prepare_cb_recall(to_delegation(cb)); | ||
1020 | nfsd4_run_callback_rpc(cb); | ||
1021 | } | 990 | } |
1022 | 991 | ||
1023 | void nfsd4_init_cb(struct nfsd4_callback *cb, struct nfs4_client *clp, | 992 | void nfsd4_init_cb(struct nfsd4_callback *cb, struct nfs4_client *clp, |
1024 | enum nfsd4_cb_op op) | 993 | struct nfsd4_callback_ops *ops, enum nfsd4_cb_op op) |
1025 | { | 994 | { |
1026 | cb->cb_clp = clp; | 995 | cb->cb_clp = clp; |
1027 | cb->cb_msg.rpc_proc = &nfs4_cb_procedures[op]; | 996 | cb->cb_msg.rpc_proc = &nfs4_cb_procedures[op]; |
1028 | cb->cb_msg.rpc_argp = cb; | 997 | cb->cb_msg.rpc_argp = cb; |
1029 | cb->cb_msg.rpc_resp = cb; | 998 | cb->cb_msg.rpc_resp = cb; |
1030 | if (op == NFSPROC4_CLNT_CB_NULL) | 999 | cb->cb_ops = ops; |
1031 | cb->cb_ops = &nfsd4_cb_probe_ops; | 1000 | INIT_WORK(&cb->cb_work, nfsd4_run_cb_work); |
1032 | else | ||
1033 | cb->cb_ops = &nfsd4_cb_recall_ops; | ||
1034 | INIT_LIST_HEAD(&cb->cb_per_client); | 1001 | INIT_LIST_HEAD(&cb->cb_per_client); |
1035 | cb->cb_done = true; | 1002 | cb->cb_done = true; |
1036 | } | 1003 | } |
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index a0ead0c57268..551f32d7f5c7 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c | |||
@@ -96,6 +96,8 @@ static struct kmem_cache *deleg_slab; | |||
96 | 96 | ||
97 | static void free_session(struct nfsd4_session *); | 97 | static void free_session(struct nfsd4_session *); |
98 | 98 | ||
99 | static struct nfsd4_callback_ops nfsd4_cb_recall_ops; | ||
100 | |||
99 | static bool is_session_dead(struct nfsd4_session *ses) | 101 | static bool is_session_dead(struct nfsd4_session *ses) |
100 | { | 102 | { |
101 | return ses->se_flags & NFS4_SESSION_DEAD; | 103 | return ses->se_flags & NFS4_SESSION_DEAD; |
@@ -647,8 +649,7 @@ alloc_init_deleg(struct nfs4_client *clp, struct svc_fh *current_fh) | |||
647 | dp->dl_type = NFS4_OPEN_DELEGATE_READ; | 649 | dp->dl_type = NFS4_OPEN_DELEGATE_READ; |
648 | dp->dl_retries = 1; | 650 | dp->dl_retries = 1; |
649 | nfsd4_init_cb(&dp->dl_recall, dp->dl_stid.sc_client, | 651 | nfsd4_init_cb(&dp->dl_recall, dp->dl_stid.sc_client, |
650 | NFSPROC4_CLNT_CB_RECALL); | 652 | &nfsd4_cb_recall_ops, NFSPROC4_CLNT_CB_RECALL); |
651 | INIT_WORK(&dp->dl_recall.cb_work, nfsd4_run_cb_recall); | ||
652 | return dp; | 653 | return dp; |
653 | out_dec: | 654 | out_dec: |
654 | atomic_long_dec(&num_delegations); | 655 | atomic_long_dec(&num_delegations); |
@@ -1872,8 +1873,7 @@ static struct nfs4_client *create_client(struct xdr_netobj name, | |||
1872 | free_client(clp); | 1873 | free_client(clp); |
1873 | return NULL; | 1874 | return NULL; |
1874 | } | 1875 | } |
1875 | nfsd4_init_cb(&clp->cl_cb_null, clp, NFSPROC4_CLNT_CB_NULL); | 1876 | nfsd4_init_cb(&clp->cl_cb_null, clp, NULL, NFSPROC4_CLNT_CB_NULL); |
1876 | INIT_WORK(&clp->cl_cb_null.cb_work, nfsd4_run_cb_null); | ||
1877 | clp->cl_time = get_seconds(); | 1877 | clp->cl_time = get_seconds(); |
1878 | clear_bit(0, &clp->cl_cb_slot_busy); | 1878 | clear_bit(0, &clp->cl_cb_slot_busy); |
1879 | copy_verf(clp, verf); | 1879 | copy_verf(clp, verf); |
@@ -3360,8 +3360,12 @@ nfs4_share_conflict(struct svc_fh *current_fh, unsigned int deny_type) | |||
3360 | return ret; | 3360 | return ret; |
3361 | } | 3361 | } |
3362 | 3362 | ||
3363 | void nfsd4_prepare_cb_recall(struct nfs4_delegation *dp) | 3363 | #define cb_to_delegation(cb) \ |
3364 | container_of(cb, struct nfs4_delegation, dl_recall) | ||
3365 | |||
3366 | static void nfsd4_cb_recall_prepare(struct nfsd4_callback *cb) | ||
3364 | { | 3367 | { |
3368 | struct nfs4_delegation *dp = cb_to_delegation(cb); | ||
3365 | struct nfsd_net *nn = net_generic(dp->dl_stid.sc_client->net, | 3369 | struct nfsd_net *nn = net_generic(dp->dl_stid.sc_client->net, |
3366 | nfsd_net_id); | 3370 | nfsd_net_id); |
3367 | 3371 | ||
@@ -3382,6 +3386,43 @@ void nfsd4_prepare_cb_recall(struct nfs4_delegation *dp) | |||
3382 | spin_unlock(&state_lock); | 3386 | spin_unlock(&state_lock); |
3383 | } | 3387 | } |
3384 | 3388 | ||
3389 | static int nfsd4_cb_recall_done(struct nfsd4_callback *cb, | ||
3390 | struct rpc_task *task) | ||
3391 | { | ||
3392 | struct nfs4_delegation *dp = cb_to_delegation(cb); | ||
3393 | |||
3394 | switch (task->tk_status) { | ||
3395 | case 0: | ||
3396 | return 1; | ||
3397 | case -EBADHANDLE: | ||
3398 | case -NFS4ERR_BAD_STATEID: | ||
3399 | /* | ||
3400 | * Race: client probably got cb_recall before open reply | ||
3401 | * granting delegation. | ||
3402 | */ | ||
3403 | if (dp->dl_retries--) { | ||
3404 | rpc_delay(task, 2 * HZ); | ||
3405 | return 0; | ||
3406 | } | ||
3407 | /*FALLTHRU*/ | ||
3408 | default: | ||
3409 | return -1; | ||
3410 | } | ||
3411 | } | ||
3412 | |||
3413 | static void nfsd4_cb_recall_release(struct nfsd4_callback *cb) | ||
3414 | { | ||
3415 | struct nfs4_delegation *dp = cb_to_delegation(cb); | ||
3416 | |||
3417 | nfs4_put_stid(&dp->dl_stid); | ||
3418 | } | ||
3419 | |||
3420 | static struct nfsd4_callback_ops nfsd4_cb_recall_ops = { | ||
3421 | .prepare = nfsd4_cb_recall_prepare, | ||
3422 | .done = nfsd4_cb_recall_done, | ||
3423 | .release = nfsd4_cb_recall_release, | ||
3424 | }; | ||
3425 | |||
3385 | static void nfsd_break_one_deleg(struct nfs4_delegation *dp) | 3426 | static void nfsd_break_one_deleg(struct nfs4_delegation *dp) |
3386 | { | 3427 | { |
3387 | /* | 3428 | /* |
diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h index 3c3a1903b4fa..bf52dc7b15e7 100644 --- a/fs/nfsd/state.h +++ b/fs/nfsd/state.h | |||
@@ -66,11 +66,17 @@ struct nfsd4_callback { | |||
66 | struct list_head cb_per_client; | 66 | struct list_head cb_per_client; |
67 | u32 cb_minorversion; | 67 | u32 cb_minorversion; |
68 | struct rpc_message cb_msg; | 68 | struct rpc_message cb_msg; |
69 | const struct rpc_call_ops *cb_ops; | 69 | struct nfsd4_callback_ops *cb_ops; |
70 | struct work_struct cb_work; | 70 | struct work_struct cb_work; |
71 | bool cb_done; | 71 | bool cb_done; |
72 | }; | 72 | }; |
73 | 73 | ||
74 | struct nfsd4_callback_ops { | ||
75 | void (*prepare)(struct nfsd4_callback *); | ||
76 | int (*done)(struct nfsd4_callback *, struct rpc_task *); | ||
77 | void (*release)(struct nfsd4_callback *); | ||
78 | }; | ||
79 | |||
74 | /* | 80 | /* |
75 | * A core object that represents a "common" stateid. These are generally | 81 | * A core object that represents a "common" stateid. These are generally |
76 | * embedded within the different (more specific) stateid objects and contain | 82 | * embedded within the different (more specific) stateid objects and contain |
@@ -538,13 +544,11 @@ extern struct nfs4_client_reclaim *nfsd4_find_reclaim_client(const char *recdir, | |||
538 | extern __be32 nfs4_check_open_reclaim(clientid_t *clid, | 544 | extern __be32 nfs4_check_open_reclaim(clientid_t *clid, |
539 | struct nfsd4_compound_state *cstate, struct nfsd_net *nn); | 545 | struct nfsd4_compound_state *cstate, struct nfsd_net *nn); |
540 | extern int set_callback_cred(void); | 546 | extern int set_callback_cred(void); |
541 | void nfsd4_run_cb_null(struct work_struct *w); | ||
542 | void nfsd4_run_cb_recall(struct work_struct *w); | ||
543 | extern void nfsd4_probe_callback(struct nfs4_client *clp); | 547 | extern void nfsd4_probe_callback(struct nfs4_client *clp); |
544 | extern void nfsd4_probe_callback_sync(struct nfs4_client *clp); | 548 | extern void nfsd4_probe_callback_sync(struct nfs4_client *clp); |
545 | extern void nfsd4_change_callback(struct nfs4_client *clp, struct nfs4_cb_conn *); | 549 | extern void nfsd4_change_callback(struct nfs4_client *clp, struct nfs4_cb_conn *); |
546 | extern void nfsd4_init_cb(struct nfsd4_callback *cb, struct nfs4_client *clp, | 550 | extern void nfsd4_init_cb(struct nfsd4_callback *cb, struct nfs4_client *clp, |
547 | enum nfsd4_cb_op op); | 551 | struct nfsd4_callback_ops *ops, enum nfsd4_cb_op op); |
548 | extern void nfsd4_run_cb(struct nfsd4_callback *cb); | 552 | extern void nfsd4_run_cb(struct nfsd4_callback *cb); |
549 | extern int nfsd4_create_callback_queue(void); | 553 | extern int nfsd4_create_callback_queue(void); |
550 | extern void nfsd4_destroy_callback_queue(void); | 554 | extern void nfsd4_destroy_callback_queue(void); |