diff options
-rw-r--r-- | include/linux/sunrpc/clnt.h | 4 | ||||
-rw-r--r-- | include/linux/sunrpc/sched.h | 5 | ||||
-rw-r--r-- | net/sunrpc/clnt.c | 5 | ||||
-rw-r--r-- | net/sunrpc/sched.c | 117 |
4 files changed, 83 insertions, 48 deletions
diff --git a/include/linux/sunrpc/clnt.h b/include/linux/sunrpc/clnt.h index 66611423c8ee..0801ab5407ce 100644 --- a/include/linux/sunrpc/clnt.h +++ b/include/linux/sunrpc/clnt.h | |||
@@ -26,6 +26,8 @@ struct rpc_inode; | |||
26 | struct rpc_clnt { | 26 | struct rpc_clnt { |
27 | atomic_t cl_count; /* Number of clones */ | 27 | atomic_t cl_count; /* Number of clones */ |
28 | atomic_t cl_users; /* number of references */ | 28 | atomic_t cl_users; /* number of references */ |
29 | struct list_head cl_clients; /* Global list of clients */ | ||
30 | struct list_head cl_tasks; /* List of tasks */ | ||
29 | struct rpc_xprt * cl_xprt; /* transport */ | 31 | struct rpc_xprt * cl_xprt; /* transport */ |
30 | struct rpc_procinfo * cl_procinfo; /* procedure info */ | 32 | struct rpc_procinfo * cl_procinfo; /* procedure info */ |
31 | u32 cl_prog, /* RPC program number */ | 33 | u32 cl_prog, /* RPC program number */ |
@@ -122,6 +124,8 @@ struct rpc_clnt *rpc_clone_client(struct rpc_clnt *); | |||
122 | int rpc_shutdown_client(struct rpc_clnt *); | 124 | int rpc_shutdown_client(struct rpc_clnt *); |
123 | int rpc_destroy_client(struct rpc_clnt *); | 125 | int rpc_destroy_client(struct rpc_clnt *); |
124 | void rpc_release_client(struct rpc_clnt *); | 126 | void rpc_release_client(struct rpc_clnt *); |
127 | void rpc_register_client(struct rpc_clnt *); | ||
128 | void rpc_unregister_client(struct rpc_clnt *); | ||
125 | int rpcb_register(u32, u32, int, unsigned short, int *); | 129 | int rpcb_register(u32, u32, int, unsigned short, int *); |
126 | void rpcb_getport(struct rpc_task *); | 130 | void rpcb_getport(struct rpc_task *); |
127 | 131 | ||
diff --git a/include/linux/sunrpc/sched.h b/include/linux/sunrpc/sched.h index 2047fb202a13..3387b008cdfc 100644 --- a/include/linux/sunrpc/sched.h +++ b/include/linux/sunrpc/sched.h | |||
@@ -110,11 +110,6 @@ struct rpc_task { | |||
110 | if (!list_empty(head) && \ | 110 | if (!list_empty(head) && \ |
111 | ((task=list_entry((head)->next, struct rpc_task, u.tk_wait.list)),1)) | 111 | ((task=list_entry((head)->next, struct rpc_task, u.tk_wait.list)),1)) |
112 | 112 | ||
113 | /* .. and walking list of all tasks */ | ||
114 | #define alltask_for_each(task, pos, head) \ | ||
115 | list_for_each(pos, head) \ | ||
116 | if ((task=list_entry(pos, struct rpc_task, tk_task)),1) | ||
117 | |||
118 | typedef void (*rpc_action)(struct rpc_task *); | 113 | typedef void (*rpc_action)(struct rpc_task *); |
119 | 114 | ||
120 | struct rpc_call_ops { | 115 | struct rpc_call_ops { |
diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index d8fbee40a19c..6631ece14983 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c | |||
@@ -148,6 +148,7 @@ static struct rpc_clnt * rpc_new_client(struct rpc_xprt *xprt, char *servname, s | |||
148 | if (clnt->cl_metrics == NULL) | 148 | if (clnt->cl_metrics == NULL) |
149 | goto out_no_stats; | 149 | goto out_no_stats; |
150 | clnt->cl_program = program; | 150 | clnt->cl_program = program; |
151 | INIT_LIST_HEAD(&clnt->cl_tasks); | ||
151 | 152 | ||
152 | if (!xprt_bound(clnt->cl_xprt)) | 153 | if (!xprt_bound(clnt->cl_xprt)) |
153 | clnt->cl_autobind = 1; | 154 | clnt->cl_autobind = 1; |
@@ -172,6 +173,7 @@ static struct rpc_clnt * rpc_new_client(struct rpc_xprt *xprt, char *servname, s | |||
172 | if (clnt->cl_nodelen > UNX_MAXNODENAME) | 173 | if (clnt->cl_nodelen > UNX_MAXNODENAME) |
173 | clnt->cl_nodelen = UNX_MAXNODENAME; | 174 | clnt->cl_nodelen = UNX_MAXNODENAME; |
174 | memcpy(clnt->cl_nodename, utsname()->nodename, clnt->cl_nodelen); | 175 | memcpy(clnt->cl_nodename, utsname()->nodename, clnt->cl_nodelen); |
176 | rpc_register_client(clnt); | ||
175 | return clnt; | 177 | return clnt; |
176 | 178 | ||
177 | out_no_auth: | 179 | out_no_auth: |
@@ -283,9 +285,11 @@ rpc_clone_client(struct rpc_clnt *clnt) | |||
283 | new->cl_autobind = 0; | 285 | new->cl_autobind = 0; |
284 | new->cl_oneshot = 0; | 286 | new->cl_oneshot = 0; |
285 | new->cl_dead = 0; | 287 | new->cl_dead = 0; |
288 | INIT_LIST_HEAD(&new->cl_tasks); | ||
286 | rpc_init_rtt(&new->cl_rtt_default, clnt->cl_xprt->timeout.to_initval); | 289 | rpc_init_rtt(&new->cl_rtt_default, clnt->cl_xprt->timeout.to_initval); |
287 | if (new->cl_auth) | 290 | if (new->cl_auth) |
288 | atomic_inc(&new->cl_auth->au_count); | 291 | atomic_inc(&new->cl_auth->au_count); |
292 | rpc_register_client(new); | ||
289 | return new; | 293 | return new; |
290 | out_no_path: | 294 | out_no_path: |
291 | rpc_free_iostats(new->cl_metrics); | 295 | rpc_free_iostats(new->cl_metrics); |
@@ -357,6 +361,7 @@ rpc_destroy_client(struct rpc_clnt *clnt) | |||
357 | if (clnt->cl_server != clnt->cl_inline_name) | 361 | if (clnt->cl_server != clnt->cl_inline_name) |
358 | kfree(clnt->cl_server); | 362 | kfree(clnt->cl_server); |
359 | out_free: | 363 | out_free: |
364 | rpc_unregister_client(clnt); | ||
360 | rpc_free_iostats(clnt->cl_metrics); | 365 | rpc_free_iostats(clnt->cl_metrics); |
361 | clnt->cl_metrics = NULL; | 366 | clnt->cl_metrics = NULL; |
362 | xprt_put(clnt->cl_xprt); | 367 | xprt_put(clnt->cl_xprt); |
diff --git a/net/sunrpc/sched.c b/net/sunrpc/sched.c index 944d75396fb3..6309f3b52c53 100644 --- a/net/sunrpc/sched.c +++ b/net/sunrpc/sched.c | |||
@@ -50,9 +50,10 @@ static void rpc_release_task(struct rpc_task *task); | |||
50 | static RPC_WAITQ(delay_queue, "delayq"); | 50 | static RPC_WAITQ(delay_queue, "delayq"); |
51 | 51 | ||
52 | /* | 52 | /* |
53 | * All RPC tasks are linked into this list | 53 | * All RPC clients are linked into this list |
54 | */ | 54 | */ |
55 | static LIST_HEAD(all_tasks); | 55 | static LIST_HEAD(all_clients); |
56 | static DECLARE_WAIT_QUEUE_HEAD(client_kill_wait); | ||
56 | 57 | ||
57 | /* | 58 | /* |
58 | * rpciod-related stuff | 59 | * rpciod-related stuff |
@@ -277,7 +278,8 @@ static void rpc_set_active(struct rpc_task *task) | |||
277 | task->tk_pid = rpc_task_id++; | 278 | task->tk_pid = rpc_task_id++; |
278 | #endif | 279 | #endif |
279 | /* Add to global list of all tasks */ | 280 | /* Add to global list of all tasks */ |
280 | list_add_tail(&task->tk_task, &all_tasks); | 281 | if (task->tk_client) |
282 | list_add_tail(&task->tk_task, &task->tk_client->cl_tasks); | ||
281 | spin_unlock(&rpc_sched_lock); | 283 | spin_unlock(&rpc_sched_lock); |
282 | } | 284 | } |
283 | 285 | ||
@@ -818,6 +820,7 @@ void rpc_init_task(struct rpc_task *task, struct rpc_clnt *clnt, int flags, cons | |||
818 | if (tk_ops->rpc_call_prepare != NULL) | 820 | if (tk_ops->rpc_call_prepare != NULL) |
819 | task->tk_action = rpc_prepare_task; | 821 | task->tk_action = rpc_prepare_task; |
820 | task->tk_calldata = calldata; | 822 | task->tk_calldata = calldata; |
823 | INIT_LIST_HEAD(&task->tk_task); | ||
821 | 824 | ||
822 | /* Initialize retry counters */ | 825 | /* Initialize retry counters */ |
823 | task->tk_garb_retry = 2; | 826 | task->tk_garb_retry = 2; |
@@ -920,11 +923,12 @@ static void rpc_release_task(struct rpc_task *task) | |||
920 | #endif | 923 | #endif |
921 | dprintk("RPC: %5u release task\n", task->tk_pid); | 924 | dprintk("RPC: %5u release task\n", task->tk_pid); |
922 | 925 | ||
923 | /* Remove from global task list */ | 926 | if (!list_empty(&task->tk_task)) { |
924 | spin_lock(&rpc_sched_lock); | 927 | /* Remove from client task list */ |
925 | list_del(&task->tk_task); | 928 | spin_lock(&rpc_sched_lock); |
926 | spin_unlock(&rpc_sched_lock); | 929 | list_del(&task->tk_task); |
927 | 930 | spin_unlock(&rpc_sched_lock); | |
931 | } | ||
928 | BUG_ON (RPC_IS_QUEUED(task)); | 932 | BUG_ON (RPC_IS_QUEUED(task)); |
929 | 933 | ||
930 | /* Synchronously delete any running timer */ | 934 | /* Synchronously delete any running timer */ |
@@ -966,42 +970,52 @@ EXPORT_SYMBOL(rpc_run_task); | |||
966 | * Kill all tasks for the given client. | 970 | * Kill all tasks for the given client. |
967 | * XXX: kill their descendants as well? | 971 | * XXX: kill their descendants as well? |
968 | */ | 972 | */ |
969 | void rpc_killall_tasks(struct rpc_clnt *clnt) | 973 | static void rpc_killall_tasks_locked(struct list_head *head) |
970 | { | 974 | { |
971 | struct rpc_task *rovr; | 975 | struct rpc_task *rovr; |
972 | struct list_head *le; | ||
973 | 976 | ||
974 | dprintk("RPC: killing all tasks for client %p\n", clnt); | ||
975 | 977 | ||
976 | /* | 978 | list_for_each_entry(rovr, head, tk_task) { |
977 | * Spin lock all_tasks to prevent changes... | ||
978 | */ | ||
979 | spin_lock(&rpc_sched_lock); | ||
980 | alltask_for_each(rovr, le, &all_tasks) { | ||
981 | if (! RPC_IS_ACTIVATED(rovr)) | 979 | if (! RPC_IS_ACTIVATED(rovr)) |
982 | continue; | 980 | continue; |
983 | if (!clnt || rovr->tk_client == clnt) { | 981 | if (!(rovr->tk_flags & RPC_TASK_KILLED)) { |
984 | rovr->tk_flags |= RPC_TASK_KILLED; | 982 | rovr->tk_flags |= RPC_TASK_KILLED; |
985 | rpc_exit(rovr, -EIO); | 983 | rpc_exit(rovr, -EIO); |
986 | rpc_wake_up_task(rovr); | 984 | rpc_wake_up_task(rovr); |
987 | } | 985 | } |
988 | } | 986 | } |
987 | } | ||
988 | |||
989 | void rpc_killall_tasks(struct rpc_clnt *clnt) | ||
990 | { | ||
991 | dprintk("RPC: killing all tasks for client %p\n", clnt); | ||
992 | /* | ||
993 | * Spin lock all_tasks to prevent changes... | ||
994 | */ | ||
995 | spin_lock(&rpc_sched_lock); | ||
996 | rpc_killall_tasks_locked(&clnt->cl_tasks); | ||
989 | spin_unlock(&rpc_sched_lock); | 997 | spin_unlock(&rpc_sched_lock); |
990 | } | 998 | } |
991 | 999 | ||
992 | static void rpciod_killall(void) | 1000 | static void rpciod_killall(void) |
993 | { | 1001 | { |
1002 | struct rpc_clnt *clnt; | ||
994 | unsigned long flags; | 1003 | unsigned long flags; |
995 | 1004 | ||
996 | while (!list_empty(&all_tasks)) { | 1005 | for(;;) { |
997 | clear_thread_flag(TIF_SIGPENDING); | 1006 | clear_thread_flag(TIF_SIGPENDING); |
998 | rpc_killall_tasks(NULL); | 1007 | |
1008 | spin_lock(&rpc_sched_lock); | ||
1009 | list_for_each_entry(clnt, &all_clients, cl_clients) | ||
1010 | rpc_killall_tasks_locked(&clnt->cl_tasks); | ||
1011 | spin_unlock(&rpc_sched_lock); | ||
999 | flush_workqueue(rpciod_workqueue); | 1012 | flush_workqueue(rpciod_workqueue); |
1000 | if (!list_empty(&all_tasks)) { | 1013 | if (!list_empty(&all_clients)) |
1001 | dprintk("RPC: rpciod_killall: waiting for tasks " | 1014 | break; |
1015 | dprintk("RPC: rpciod_killall: waiting for tasks " | ||
1002 | "to exit\n"); | 1016 | "to exit\n"); |
1003 | yield(); | 1017 | wait_event_timeout(client_kill_wait, |
1004 | } | 1018 | list_empty(&all_clients), 1*HZ); |
1005 | } | 1019 | } |
1006 | 1020 | ||
1007 | spin_lock_irqsave(¤t->sighand->siglock, flags); | 1021 | spin_lock_irqsave(¤t->sighand->siglock, flags); |
@@ -1009,6 +1023,22 @@ static void rpciod_killall(void) | |||
1009 | spin_unlock_irqrestore(¤t->sighand->siglock, flags); | 1023 | spin_unlock_irqrestore(¤t->sighand->siglock, flags); |
1010 | } | 1024 | } |
1011 | 1025 | ||
1026 | void rpc_register_client(struct rpc_clnt *clnt) | ||
1027 | { | ||
1028 | spin_lock(&rpc_sched_lock); | ||
1029 | list_add(&clnt->cl_clients, &all_clients); | ||
1030 | spin_unlock(&rpc_sched_lock); | ||
1031 | } | ||
1032 | |||
1033 | void rpc_unregister_client(struct rpc_clnt *clnt) | ||
1034 | { | ||
1035 | spin_lock(&rpc_sched_lock); | ||
1036 | list_del(&clnt->cl_clients); | ||
1037 | if (list_empty(&all_clients)) | ||
1038 | wake_up(&client_kill_wait); | ||
1039 | spin_unlock(&rpc_sched_lock); | ||
1040 | } | ||
1041 | |||
1012 | /* | 1042 | /* |
1013 | * Start up the rpciod process if it's not already running. | 1043 | * Start up the rpciod process if it's not already running. |
1014 | */ | 1044 | */ |
@@ -1071,32 +1101,33 @@ rpciod_down(void) | |||
1071 | #ifdef RPC_DEBUG | 1101 | #ifdef RPC_DEBUG |
1072 | void rpc_show_tasks(void) | 1102 | void rpc_show_tasks(void) |
1073 | { | 1103 | { |
1074 | struct list_head *le; | 1104 | struct rpc_clnt *clnt; |
1075 | struct rpc_task *t; | 1105 | struct rpc_task *t; |
1076 | 1106 | ||
1077 | spin_lock(&rpc_sched_lock); | 1107 | spin_lock(&rpc_sched_lock); |
1078 | if (list_empty(&all_tasks)) { | 1108 | if (list_empty(&all_clients)) |
1079 | spin_unlock(&rpc_sched_lock); | 1109 | goto out; |
1080 | return; | ||
1081 | } | ||
1082 | printk("-pid- proc flgs status -client- -prog- --rqstp- -timeout " | 1110 | printk("-pid- proc flgs status -client- -prog- --rqstp- -timeout " |
1083 | "-rpcwait -action- ---ops--\n"); | 1111 | "-rpcwait -action- ---ops--\n"); |
1084 | alltask_for_each(t, le, &all_tasks) { | 1112 | list_for_each_entry(clnt, &all_clients, cl_clients) { |
1085 | const char *rpc_waitq = "none"; | 1113 | list_for_each_entry(t, &clnt->cl_tasks, tk_task) { |
1086 | 1114 | const char *rpc_waitq = "none"; | |
1087 | if (RPC_IS_QUEUED(t)) | 1115 | |
1088 | rpc_waitq = rpc_qname(t->u.tk_wait.rpc_waitq); | 1116 | if (RPC_IS_QUEUED(t)) |
1089 | 1117 | rpc_waitq = rpc_qname(t->u.tk_wait.rpc_waitq); | |
1090 | printk("%5u %04d %04x %6d %8p %6d %8p %8ld %8s %8p %8p\n", | 1118 | |
1091 | t->tk_pid, | 1119 | printk("%5u %04d %04x %6d %8p %6d %8p %8ld %8s %8p %8p\n", |
1092 | (t->tk_msg.rpc_proc ? t->tk_msg.rpc_proc->p_proc : -1), | 1120 | t->tk_pid, |
1093 | t->tk_flags, t->tk_status, | 1121 | (t->tk_msg.rpc_proc ? t->tk_msg.rpc_proc->p_proc : -1), |
1094 | t->tk_client, | 1122 | t->tk_flags, t->tk_status, |
1095 | (t->tk_client ? t->tk_client->cl_prog : 0), | 1123 | t->tk_client, |
1096 | t->tk_rqstp, t->tk_timeout, | 1124 | (t->tk_client ? t->tk_client->cl_prog : 0), |
1097 | rpc_waitq, | 1125 | t->tk_rqstp, t->tk_timeout, |
1098 | t->tk_action, t->tk_ops); | 1126 | rpc_waitq, |
1127 | t->tk_action, t->tk_ops); | ||
1128 | } | ||
1099 | } | 1129 | } |
1130 | out: | ||
1100 | spin_unlock(&rpc_sched_lock); | 1131 | spin_unlock(&rpc_sched_lock); |
1101 | } | 1132 | } |
1102 | #endif | 1133 | #endif |