diff options
-rw-r--r-- | fs/afs/cmservice.c | 41 | ||||
-rw-r--r-- | fs/afs/internal.h | 9 | ||||
-rw-r--r-- | fs/afs/rxrpc.c | 153 | ||||
-rw-r--r-- | include/trace/events/afs.h | 75 |
4 files changed, 199 insertions, 79 deletions
diff --git a/fs/afs/cmservice.c b/fs/afs/cmservice.c index a2e1e02005f6..e349a3316303 100644 --- a/fs/afs/cmservice.c +++ b/fs/afs/cmservice.c | |||
@@ -24,6 +24,11 @@ static int afs_deliver_cb_callback(struct afs_call *); | |||
24 | static int afs_deliver_cb_probe_uuid(struct afs_call *); | 24 | static int afs_deliver_cb_probe_uuid(struct afs_call *); |
25 | static int afs_deliver_cb_tell_me_about_yourself(struct afs_call *); | 25 | static int afs_deliver_cb_tell_me_about_yourself(struct afs_call *); |
26 | static void afs_cm_destructor(struct afs_call *); | 26 | static void afs_cm_destructor(struct afs_call *); |
27 | static void SRXAFSCB_CallBack(struct work_struct *); | ||
28 | static void SRXAFSCB_InitCallBackState(struct work_struct *); | ||
29 | static void SRXAFSCB_Probe(struct work_struct *); | ||
30 | static void SRXAFSCB_ProbeUuid(struct work_struct *); | ||
31 | static void SRXAFSCB_TellMeAboutYourself(struct work_struct *); | ||
27 | 32 | ||
28 | #define CM_NAME(name) \ | 33 | #define CM_NAME(name) \ |
29 | const char afs_SRXCB##name##_name[] __tracepoint_string = \ | 34 | const char afs_SRXCB##name##_name[] __tracepoint_string = \ |
@@ -38,6 +43,7 @@ static const struct afs_call_type afs_SRXCBCallBack = { | |||
38 | .deliver = afs_deliver_cb_callback, | 43 | .deliver = afs_deliver_cb_callback, |
39 | .abort_to_error = afs_abort_to_error, | 44 | .abort_to_error = afs_abort_to_error, |
40 | .destructor = afs_cm_destructor, | 45 | .destructor = afs_cm_destructor, |
46 | .work = SRXAFSCB_CallBack, | ||
41 | }; | 47 | }; |
42 | 48 | ||
43 | /* | 49 | /* |
@@ -49,6 +55,7 @@ static const struct afs_call_type afs_SRXCBInitCallBackState = { | |||
49 | .deliver = afs_deliver_cb_init_call_back_state, | 55 | .deliver = afs_deliver_cb_init_call_back_state, |
50 | .abort_to_error = afs_abort_to_error, | 56 | .abort_to_error = afs_abort_to_error, |
51 | .destructor = afs_cm_destructor, | 57 | .destructor = afs_cm_destructor, |
58 | .work = SRXAFSCB_InitCallBackState, | ||
52 | }; | 59 | }; |
53 | 60 | ||
54 | /* | 61 | /* |
@@ -60,6 +67,7 @@ static const struct afs_call_type afs_SRXCBInitCallBackState3 = { | |||
60 | .deliver = afs_deliver_cb_init_call_back_state3, | 67 | .deliver = afs_deliver_cb_init_call_back_state3, |
61 | .abort_to_error = afs_abort_to_error, | 68 | .abort_to_error = afs_abort_to_error, |
62 | .destructor = afs_cm_destructor, | 69 | .destructor = afs_cm_destructor, |
70 | .work = SRXAFSCB_InitCallBackState, | ||
63 | }; | 71 | }; |
64 | 72 | ||
65 | /* | 73 | /* |
@@ -71,6 +79,7 @@ static const struct afs_call_type afs_SRXCBProbe = { | |||
71 | .deliver = afs_deliver_cb_probe, | 79 | .deliver = afs_deliver_cb_probe, |
72 | .abort_to_error = afs_abort_to_error, | 80 | .abort_to_error = afs_abort_to_error, |
73 | .destructor = afs_cm_destructor, | 81 | .destructor = afs_cm_destructor, |
82 | .work = SRXAFSCB_Probe, | ||
74 | }; | 83 | }; |
75 | 84 | ||
76 | /* | 85 | /* |
@@ -82,6 +91,7 @@ static const struct afs_call_type afs_SRXCBProbeUuid = { | |||
82 | .deliver = afs_deliver_cb_probe_uuid, | 91 | .deliver = afs_deliver_cb_probe_uuid, |
83 | .abort_to_error = afs_abort_to_error, | 92 | .abort_to_error = afs_abort_to_error, |
84 | .destructor = afs_cm_destructor, | 93 | .destructor = afs_cm_destructor, |
94 | .work = SRXAFSCB_ProbeUuid, | ||
85 | }; | 95 | }; |
86 | 96 | ||
87 | /* | 97 | /* |
@@ -93,6 +103,7 @@ static const struct afs_call_type afs_SRXCBTellMeAboutYourself = { | |||
93 | .deliver = afs_deliver_cb_tell_me_about_yourself, | 103 | .deliver = afs_deliver_cb_tell_me_about_yourself, |
94 | .abort_to_error = afs_abort_to_error, | 104 | .abort_to_error = afs_abort_to_error, |
95 | .destructor = afs_cm_destructor, | 105 | .destructor = afs_cm_destructor, |
106 | .work = SRXAFSCB_TellMeAboutYourself, | ||
96 | }; | 107 | }; |
97 | 108 | ||
98 | /* | 109 | /* |
@@ -163,6 +174,7 @@ static void SRXAFSCB_CallBack(struct work_struct *work) | |||
163 | afs_send_empty_reply(call); | 174 | afs_send_empty_reply(call); |
164 | 175 | ||
165 | afs_break_callbacks(call->server, call->count, call->request); | 176 | afs_break_callbacks(call->server, call->count, call->request); |
177 | afs_put_call(call); | ||
166 | _leave(""); | 178 | _leave(""); |
167 | } | 179 | } |
168 | 180 | ||
@@ -284,9 +296,7 @@ static int afs_deliver_cb_callback(struct afs_call *call) | |||
284 | return -ENOTCONN; | 296 | return -ENOTCONN; |
285 | call->server = server; | 297 | call->server = server; |
286 | 298 | ||
287 | INIT_WORK(&call->work, SRXAFSCB_CallBack); | 299 | return afs_queue_call_work(call); |
288 | queue_work(afs_wq, &call->work); | ||
289 | return 0; | ||
290 | } | 300 | } |
291 | 301 | ||
292 | /* | 302 | /* |
@@ -300,6 +310,7 @@ static void SRXAFSCB_InitCallBackState(struct work_struct *work) | |||
300 | 310 | ||
301 | afs_init_callback_state(call->server); | 311 | afs_init_callback_state(call->server); |
302 | afs_send_empty_reply(call); | 312 | afs_send_empty_reply(call); |
313 | afs_put_call(call); | ||
303 | _leave(""); | 314 | _leave(""); |
304 | } | 315 | } |
305 | 316 | ||
@@ -330,9 +341,7 @@ static int afs_deliver_cb_init_call_back_state(struct afs_call *call) | |||
330 | return -ENOTCONN; | 341 | return -ENOTCONN; |
331 | call->server = server; | 342 | call->server = server; |
332 | 343 | ||
333 | INIT_WORK(&call->work, SRXAFSCB_InitCallBackState); | 344 | return afs_queue_call_work(call); |
334 | queue_work(afs_wq, &call->work); | ||
335 | return 0; | ||
336 | } | 345 | } |
337 | 346 | ||
338 | /* | 347 | /* |
@@ -404,9 +413,7 @@ static int afs_deliver_cb_init_call_back_state3(struct afs_call *call) | |||
404 | return -ENOTCONN; | 413 | return -ENOTCONN; |
405 | call->server = server; | 414 | call->server = server; |
406 | 415 | ||
407 | INIT_WORK(&call->work, SRXAFSCB_InitCallBackState); | 416 | return afs_queue_call_work(call); |
408 | queue_work(afs_wq, &call->work); | ||
409 | return 0; | ||
410 | } | 417 | } |
411 | 418 | ||
412 | /* | 419 | /* |
@@ -418,6 +425,7 @@ static void SRXAFSCB_Probe(struct work_struct *work) | |||
418 | 425 | ||
419 | _enter(""); | 426 | _enter(""); |
420 | afs_send_empty_reply(call); | 427 | afs_send_empty_reply(call); |
428 | afs_put_call(call); | ||
421 | _leave(""); | 429 | _leave(""); |
422 | } | 430 | } |
423 | 431 | ||
@@ -437,9 +445,7 @@ static int afs_deliver_cb_probe(struct afs_call *call) | |||
437 | /* no unmarshalling required */ | 445 | /* no unmarshalling required */ |
438 | call->state = AFS_CALL_REPLYING; | 446 | call->state = AFS_CALL_REPLYING; |
439 | 447 | ||
440 | INIT_WORK(&call->work, SRXAFSCB_Probe); | 448 | return afs_queue_call_work(call); |
441 | queue_work(afs_wq, &call->work); | ||
442 | return 0; | ||
443 | } | 449 | } |
444 | 450 | ||
445 | /* | 451 | /* |
@@ -462,6 +468,7 @@ static void SRXAFSCB_ProbeUuid(struct work_struct *work) | |||
462 | reply.match = htonl(1); | 468 | reply.match = htonl(1); |
463 | 469 | ||
464 | afs_send_simple_reply(call, &reply, sizeof(reply)); | 470 | afs_send_simple_reply(call, &reply, sizeof(reply)); |
471 | afs_put_call(call); | ||
465 | _leave(""); | 472 | _leave(""); |
466 | } | 473 | } |
467 | 474 | ||
@@ -520,9 +527,7 @@ static int afs_deliver_cb_probe_uuid(struct afs_call *call) | |||
520 | 527 | ||
521 | call->state = AFS_CALL_REPLYING; | 528 | call->state = AFS_CALL_REPLYING; |
522 | 529 | ||
523 | INIT_WORK(&call->work, SRXAFSCB_ProbeUuid); | 530 | return afs_queue_call_work(call); |
524 | queue_work(afs_wq, &call->work); | ||
525 | return 0; | ||
526 | } | 531 | } |
527 | 532 | ||
528 | /* | 533 | /* |
@@ -584,7 +589,7 @@ static void SRXAFSCB_TellMeAboutYourself(struct work_struct *work) | |||
584 | reply.cap.capcount = htonl(1); | 589 | reply.cap.capcount = htonl(1); |
585 | reply.cap.caps[0] = htonl(AFS_CAP_ERROR_TRANSLATION); | 590 | reply.cap.caps[0] = htonl(AFS_CAP_ERROR_TRANSLATION); |
586 | afs_send_simple_reply(call, &reply, sizeof(reply)); | 591 | afs_send_simple_reply(call, &reply, sizeof(reply)); |
587 | 592 | afs_put_call(call); | |
588 | _leave(""); | 593 | _leave(""); |
589 | } | 594 | } |
590 | 595 | ||
@@ -604,7 +609,5 @@ static int afs_deliver_cb_tell_me_about_yourself(struct afs_call *call) | |||
604 | /* no unmarshalling required */ | 609 | /* no unmarshalling required */ |
605 | call->state = AFS_CALL_REPLYING; | 610 | call->state = AFS_CALL_REPLYING; |
606 | 611 | ||
607 | INIT_WORK(&call->work, SRXAFSCB_TellMeAboutYourself); | 612 | return afs_queue_call_work(call); |
608 | queue_work(afs_wq, &call->work); | ||
609 | return 0; | ||
610 | } | 613 | } |
diff --git a/fs/afs/internal.h b/fs/afs/internal.h index b411670d5f67..65504e218d35 100644 --- a/fs/afs/internal.h +++ b/fs/afs/internal.h | |||
@@ -66,7 +66,7 @@ enum afs_call_state { | |||
66 | struct afs_call { | 66 | struct afs_call { |
67 | const struct afs_call_type *type; /* type of call */ | 67 | const struct afs_call_type *type; /* type of call */ |
68 | wait_queue_head_t waitq; /* processes awaiting completion */ | 68 | wait_queue_head_t waitq; /* processes awaiting completion */ |
69 | struct work_struct async_work; /* asynchronous work processor */ | 69 | struct work_struct async_work; /* async I/O processor */ |
70 | struct work_struct work; /* actual work processor */ | 70 | struct work_struct work; /* actual work processor */ |
71 | struct rxrpc_call *rxcall; /* RxRPC call handle */ | 71 | struct rxrpc_call *rxcall; /* RxRPC call handle */ |
72 | struct key *key; /* security for this call */ | 72 | struct key *key; /* security for this call */ |
@@ -82,6 +82,7 @@ struct afs_call { | |||
82 | pgoff_t first; /* first page in mapping to deal with */ | 82 | pgoff_t first; /* first page in mapping to deal with */ |
83 | pgoff_t last; /* last page in mapping to deal with */ | 83 | pgoff_t last; /* last page in mapping to deal with */ |
84 | size_t offset; /* offset into received data store */ | 84 | size_t offset; /* offset into received data store */ |
85 | atomic_t usage; | ||
85 | enum afs_call_state state; | 86 | enum afs_call_state state; |
86 | int error; /* error code */ | 87 | int error; /* error code */ |
87 | u32 abort_code; /* Remote abort ID or 0 */ | 88 | u32 abort_code; /* Remote abort ID or 0 */ |
@@ -115,6 +116,9 @@ struct afs_call_type { | |||
115 | 116 | ||
116 | /* clean up a call */ | 117 | /* clean up a call */ |
117 | void (*destructor)(struct afs_call *call); | 118 | void (*destructor)(struct afs_call *call); |
119 | |||
120 | /* Work function */ | ||
121 | void (*work)(struct work_struct *work); | ||
118 | }; | 122 | }; |
119 | 123 | ||
120 | /* | 124 | /* |
@@ -591,9 +595,12 @@ extern void afs_proc_cell_remove(struct afs_cell *); | |||
591 | * rxrpc.c | 595 | * rxrpc.c |
592 | */ | 596 | */ |
593 | extern struct socket *afs_socket; | 597 | extern struct socket *afs_socket; |
598 | extern atomic_t afs_outstanding_calls; | ||
594 | 599 | ||
595 | extern int afs_open_socket(void); | 600 | extern int afs_open_socket(void); |
596 | extern void afs_close_socket(void); | 601 | extern void afs_close_socket(void); |
602 | extern void afs_put_call(struct afs_call *); | ||
603 | extern int afs_queue_call_work(struct afs_call *); | ||
597 | extern int afs_make_call(struct in_addr *, struct afs_call *, gfp_t, bool); | 604 | extern int afs_make_call(struct in_addr *, struct afs_call *, gfp_t, bool); |
598 | extern struct afs_call *afs_alloc_flat_call(const struct afs_call_type *, | 605 | extern struct afs_call *afs_alloc_flat_call(const struct afs_call_type *, |
599 | size_t, size_t); | 606 | size_t, size_t); |
diff --git a/fs/afs/rxrpc.c b/fs/afs/rxrpc.c index ec1e41f929d1..95f42872b787 100644 --- a/fs/afs/rxrpc.c +++ b/fs/afs/rxrpc.c | |||
@@ -19,9 +19,8 @@ | |||
19 | struct socket *afs_socket; /* my RxRPC socket */ | 19 | struct socket *afs_socket; /* my RxRPC socket */ |
20 | static struct workqueue_struct *afs_async_calls; | 20 | static struct workqueue_struct *afs_async_calls; |
21 | static struct afs_call *afs_spare_incoming_call; | 21 | static struct afs_call *afs_spare_incoming_call; |
22 | static atomic_t afs_outstanding_calls; | 22 | atomic_t afs_outstanding_calls; |
23 | 23 | ||
24 | static void afs_free_call(struct afs_call *); | ||
25 | static void afs_wake_up_call_waiter(struct sock *, struct rxrpc_call *, unsigned long); | 24 | static void afs_wake_up_call_waiter(struct sock *, struct rxrpc_call *, unsigned long); |
26 | static int afs_wait_for_call_to_complete(struct afs_call *); | 25 | static int afs_wait_for_call_to_complete(struct afs_call *); |
27 | static void afs_wake_up_async_call(struct sock *, struct rxrpc_call *, unsigned long); | 26 | static void afs_wake_up_async_call(struct sock *, struct rxrpc_call *, unsigned long); |
@@ -112,9 +111,11 @@ void afs_close_socket(void) | |||
112 | { | 111 | { |
113 | _enter(""); | 112 | _enter(""); |
114 | 113 | ||
114 | kernel_listen(afs_socket, 0); | ||
115 | flush_workqueue(afs_async_calls); | ||
116 | |||
115 | if (afs_spare_incoming_call) { | 117 | if (afs_spare_incoming_call) { |
116 | atomic_inc(&afs_outstanding_calls); | 118 | afs_put_call(afs_spare_incoming_call); |
117 | afs_free_call(afs_spare_incoming_call); | ||
118 | afs_spare_incoming_call = NULL; | 119 | afs_spare_incoming_call = NULL; |
119 | } | 120 | } |
120 | 121 | ||
@@ -123,7 +124,6 @@ void afs_close_socket(void) | |||
123 | TASK_UNINTERRUPTIBLE); | 124 | TASK_UNINTERRUPTIBLE); |
124 | _debug("no outstanding calls"); | 125 | _debug("no outstanding calls"); |
125 | 126 | ||
126 | flush_workqueue(afs_async_calls); | ||
127 | kernel_sock_shutdown(afs_socket, SHUT_RDWR); | 127 | kernel_sock_shutdown(afs_socket, SHUT_RDWR); |
128 | flush_workqueue(afs_async_calls); | 128 | flush_workqueue(afs_async_calls); |
129 | sock_release(afs_socket); | 129 | sock_release(afs_socket); |
@@ -134,44 +134,79 @@ void afs_close_socket(void) | |||
134 | } | 134 | } |
135 | 135 | ||
136 | /* | 136 | /* |
137 | * free a call | 137 | * Allocate a call. |
138 | */ | 138 | */ |
139 | static void afs_free_call(struct afs_call *call) | 139 | static struct afs_call *afs_alloc_call(const struct afs_call_type *type, |
140 | gfp_t gfp) | ||
140 | { | 141 | { |
141 | _debug("DONE %p{%s} [%d]", | 142 | struct afs_call *call; |
142 | call, call->type->name, atomic_read(&afs_outstanding_calls)); | 143 | int o; |
143 | 144 | ||
144 | ASSERTCMP(call->rxcall, ==, NULL); | 145 | call = kzalloc(sizeof(*call), gfp); |
145 | ASSERT(!work_pending(&call->async_work)); | 146 | if (!call) |
146 | ASSERT(call->type->name != NULL); | 147 | return NULL; |
147 | 148 | ||
148 | kfree(call->request); | 149 | call->type = type; |
149 | kfree(call); | 150 | atomic_set(&call->usage, 1); |
151 | INIT_WORK(&call->async_work, afs_process_async_call); | ||
152 | init_waitqueue_head(&call->waitq); | ||
150 | 153 | ||
151 | if (atomic_dec_and_test(&afs_outstanding_calls)) | 154 | o = atomic_inc_return(&afs_outstanding_calls); |
152 | wake_up_atomic_t(&afs_outstanding_calls); | 155 | trace_afs_call(call, afs_call_trace_alloc, 1, o, |
156 | __builtin_return_address(0)); | ||
157 | return call; | ||
153 | } | 158 | } |
154 | 159 | ||
155 | /* | 160 | /* |
156 | * End a call but do not free it | 161 | * Dispose of a reference on a call. |
157 | */ | 162 | */ |
158 | static void afs_end_call_nofree(struct afs_call *call) | 163 | void afs_put_call(struct afs_call *call) |
159 | { | 164 | { |
160 | if (call->rxcall) { | 165 | int n = atomic_dec_return(&call->usage); |
161 | rxrpc_kernel_end_call(afs_socket, call->rxcall); | 166 | int o = atomic_read(&afs_outstanding_calls); |
162 | call->rxcall = NULL; | 167 | |
168 | trace_afs_call(call, afs_call_trace_put, n + 1, o, | ||
169 | __builtin_return_address(0)); | ||
170 | |||
171 | ASSERTCMP(n, >=, 0); | ||
172 | if (n == 0) { | ||
173 | ASSERT(!work_pending(&call->async_work)); | ||
174 | ASSERT(call->type->name != NULL); | ||
175 | |||
176 | if (call->rxcall) { | ||
177 | rxrpc_kernel_end_call(afs_socket, call->rxcall); | ||
178 | call->rxcall = NULL; | ||
179 | } | ||
180 | if (call->type->destructor) | ||
181 | call->type->destructor(call); | ||
182 | |||
183 | kfree(call->request); | ||
184 | kfree(call); | ||
185 | |||
186 | o = atomic_dec_return(&afs_outstanding_calls); | ||
187 | trace_afs_call(call, afs_call_trace_free, 0, o, | ||
188 | __builtin_return_address(0)); | ||
189 | if (o == 0) | ||
190 | wake_up_atomic_t(&afs_outstanding_calls); | ||
163 | } | 191 | } |
164 | if (call->type->destructor) | ||
165 | call->type->destructor(call); | ||
166 | } | 192 | } |
167 | 193 | ||
168 | /* | 194 | /* |
169 | * End a call and free it | 195 | * Queue the call for actual work. Returns 0 unconditionally for convenience. |
170 | */ | 196 | */ |
171 | static void afs_end_call(struct afs_call *call) | 197 | int afs_queue_call_work(struct afs_call *call) |
172 | { | 198 | { |
173 | afs_end_call_nofree(call); | 199 | int u = atomic_inc_return(&call->usage); |
174 | afs_free_call(call); | 200 | |
201 | trace_afs_call(call, afs_call_trace_work, u, | ||
202 | atomic_read(&afs_outstanding_calls), | ||
203 | __builtin_return_address(0)); | ||
204 | |||
205 | INIT_WORK(&call->work, call->type->work); | ||
206 | |||
207 | if (!queue_work(afs_wq, &call->work)) | ||
208 | afs_put_call(call); | ||
209 | return 0; | ||
175 | } | 210 | } |
176 | 211 | ||
177 | /* | 212 | /* |
@@ -182,25 +217,19 @@ struct afs_call *afs_alloc_flat_call(const struct afs_call_type *type, | |||
182 | { | 217 | { |
183 | struct afs_call *call; | 218 | struct afs_call *call; |
184 | 219 | ||
185 | call = kzalloc(sizeof(*call), GFP_NOFS); | 220 | call = afs_alloc_call(type, GFP_NOFS); |
186 | if (!call) | 221 | if (!call) |
187 | goto nomem_call; | 222 | goto nomem_call; |
188 | 223 | ||
189 | _debug("CALL %p{%s} [%d]", | ||
190 | call, type->name, atomic_read(&afs_outstanding_calls)); | ||
191 | atomic_inc(&afs_outstanding_calls); | ||
192 | |||
193 | call->type = type; | ||
194 | call->request_size = request_size; | ||
195 | call->reply_max = reply_max; | ||
196 | |||
197 | if (request_size) { | 224 | if (request_size) { |
225 | call->request_size = request_size; | ||
198 | call->request = kmalloc(request_size, GFP_NOFS); | 226 | call->request = kmalloc(request_size, GFP_NOFS); |
199 | if (!call->request) | 227 | if (!call->request) |
200 | goto nomem_free; | 228 | goto nomem_free; |
201 | } | 229 | } |
202 | 230 | ||
203 | if (reply_max) { | 231 | if (reply_max) { |
232 | call->reply_max = reply_max; | ||
204 | call->buffer = kmalloc(reply_max, GFP_NOFS); | 233 | call->buffer = kmalloc(reply_max, GFP_NOFS); |
205 | if (!call->buffer) | 234 | if (!call->buffer) |
206 | goto nomem_free; | 235 | goto nomem_free; |
@@ -210,7 +239,7 @@ struct afs_call *afs_alloc_flat_call(const struct afs_call_type *type, | |||
210 | return call; | 239 | return call; |
211 | 240 | ||
212 | nomem_free: | 241 | nomem_free: |
213 | afs_free_call(call); | 242 | afs_put_call(call); |
214 | nomem_call: | 243 | nomem_call: |
215 | return NULL; | 244 | return NULL; |
216 | } | 245 | } |
@@ -315,7 +344,6 @@ int afs_make_call(struct in_addr *addr, struct afs_call *call, gfp_t gfp, | |||
315 | atomic_read(&afs_outstanding_calls)); | 344 | atomic_read(&afs_outstanding_calls)); |
316 | 345 | ||
317 | call->async = async; | 346 | call->async = async; |
318 | INIT_WORK(&call->async_work, afs_process_async_call); | ||
319 | 347 | ||
320 | memset(&srx, 0, sizeof(srx)); | 348 | memset(&srx, 0, sizeof(srx)); |
321 | srx.srx_family = AF_RXRPC; | 349 | srx.srx_family = AF_RXRPC; |
@@ -378,7 +406,7 @@ int afs_make_call(struct in_addr *addr, struct afs_call *call, gfp_t gfp, | |||
378 | error_do_abort: | 406 | error_do_abort: |
379 | rxrpc_kernel_abort_call(afs_socket, rxcall, RX_USER_ABORT, -ret, "KSD"); | 407 | rxrpc_kernel_abort_call(afs_socket, rxcall, RX_USER_ABORT, -ret, "KSD"); |
380 | error_kill_call: | 408 | error_kill_call: |
381 | afs_end_call(call); | 409 | afs_put_call(call); |
382 | _leave(" = %d", ret); | 410 | _leave(" = %d", ret); |
383 | return ret; | 411 | return ret; |
384 | } | 412 | } |
@@ -448,7 +476,7 @@ static void afs_deliver_to_call(struct afs_call *call) | |||
448 | 476 | ||
449 | done: | 477 | done: |
450 | if (call->state == AFS_CALL_COMPLETE && call->incoming) | 478 | if (call->state == AFS_CALL_COMPLETE && call->incoming) |
451 | afs_end_call(call); | 479 | afs_put_call(call); |
452 | out: | 480 | out: |
453 | _leave(""); | 481 | _leave(""); |
454 | return; | 482 | return; |
@@ -505,7 +533,7 @@ static int afs_wait_for_call_to_complete(struct afs_call *call) | |||
505 | } | 533 | } |
506 | 534 | ||
507 | _debug("call complete"); | 535 | _debug("call complete"); |
508 | afs_end_call(call); | 536 | afs_put_call(call); |
509 | _leave(" = %d", ret); | 537 | _leave(" = %d", ret); |
510 | return ret; | 538 | return ret; |
511 | } | 539 | } |
@@ -529,14 +557,25 @@ static void afs_wake_up_async_call(struct sock *sk, struct rxrpc_call *rxcall, | |||
529 | unsigned long call_user_ID) | 557 | unsigned long call_user_ID) |
530 | { | 558 | { |
531 | struct afs_call *call = (struct afs_call *)call_user_ID; | 559 | struct afs_call *call = (struct afs_call *)call_user_ID; |
560 | int u; | ||
532 | 561 | ||
533 | trace_afs_notify_call(rxcall, call); | 562 | trace_afs_notify_call(rxcall, call); |
534 | call->need_attention = true; | 563 | call->need_attention = true; |
535 | queue_work(afs_async_calls, &call->async_work); | 564 | |
565 | u = __atomic_add_unless(&call->usage, 1, 0); | ||
566 | if (u != 0) { | ||
567 | trace_afs_call(call, afs_call_trace_wake, u, | ||
568 | atomic_read(&afs_outstanding_calls), | ||
569 | __builtin_return_address(0)); | ||
570 | |||
571 | if (!queue_work(afs_async_calls, &call->async_work)) | ||
572 | afs_put_call(call); | ||
573 | } | ||
536 | } | 574 | } |
537 | 575 | ||
538 | /* | 576 | /* |
539 | * delete an asynchronous call | 577 | * Delete an asynchronous call. The work item carries a ref to the call struct |
578 | * that we need to release. | ||
540 | */ | 579 | */ |
541 | static void afs_delete_async_call(struct work_struct *work) | 580 | static void afs_delete_async_call(struct work_struct *work) |
542 | { | 581 | { |
@@ -544,13 +583,14 @@ static void afs_delete_async_call(struct work_struct *work) | |||
544 | 583 | ||
545 | _enter(""); | 584 | _enter(""); |
546 | 585 | ||
547 | afs_free_call(call); | 586 | afs_put_call(call); |
548 | 587 | ||
549 | _leave(""); | 588 | _leave(""); |
550 | } | 589 | } |
551 | 590 | ||
552 | /* | 591 | /* |
553 | * perform processing on an asynchronous call | 592 | * Perform I/O processing on an asynchronous call. The work item carries a ref |
593 | * to the call struct that we either need to release or to pass on. | ||
554 | */ | 594 | */ |
555 | static void afs_process_async_call(struct work_struct *work) | 595 | static void afs_process_async_call(struct work_struct *work) |
556 | { | 596 | { |
@@ -566,15 +606,16 @@ static void afs_process_async_call(struct work_struct *work) | |||
566 | if (call->state == AFS_CALL_COMPLETE) { | 606 | if (call->state == AFS_CALL_COMPLETE) { |
567 | call->reply = NULL; | 607 | call->reply = NULL; |
568 | 608 | ||
569 | /* kill the call */ | 609 | /* We have two refs to release - one from the alloc and one |
570 | afs_end_call_nofree(call); | 610 | * queued with the work item - and we can't just deallocate the |
571 | 611 | * call because the work item may be queued again. | |
572 | /* we can't just delete the call because the work item may be | 612 | */ |
573 | * queued */ | ||
574 | call->async_work.func = afs_delete_async_call; | 613 | call->async_work.func = afs_delete_async_call; |
575 | queue_work(afs_async_calls, &call->async_work); | 614 | if (!queue_work(afs_async_calls, &call->async_work)) |
615 | afs_put_call(call); | ||
576 | } | 616 | } |
577 | 617 | ||
618 | afs_put_call(call); | ||
578 | _leave(""); | 619 | _leave(""); |
579 | } | 620 | } |
580 | 621 | ||
@@ -594,12 +635,10 @@ static void afs_charge_preallocation(struct work_struct *work) | |||
594 | 635 | ||
595 | for (;;) { | 636 | for (;;) { |
596 | if (!call) { | 637 | if (!call) { |
597 | call = kzalloc(sizeof(struct afs_call), GFP_KERNEL); | 638 | call = afs_alloc_call(&afs_RXCMxxxx, GFP_KERNEL); |
598 | if (!call) | 639 | if (!call) |
599 | break; | 640 | break; |
600 | 641 | ||
601 | INIT_WORK(&call->async_work, afs_process_async_call); | ||
602 | call->type = &afs_RXCMxxxx; | ||
603 | call->async = true; | 642 | call->async = true; |
604 | call->state = AFS_CALL_AWAIT_OP_ID; | 643 | call->state = AFS_CALL_AWAIT_OP_ID; |
605 | init_waitqueue_head(&call->waitq); | 644 | init_waitqueue_head(&call->waitq); |
@@ -624,9 +663,8 @@ static void afs_rx_discard_new_call(struct rxrpc_call *rxcall, | |||
624 | { | 663 | { |
625 | struct afs_call *call = (struct afs_call *)user_call_ID; | 664 | struct afs_call *call = (struct afs_call *)user_call_ID; |
626 | 665 | ||
627 | atomic_inc(&afs_outstanding_calls); | ||
628 | call->rxcall = NULL; | 666 | call->rxcall = NULL; |
629 | afs_free_call(call); | 667 | afs_put_call(call); |
630 | } | 668 | } |
631 | 669 | ||
632 | /* | 670 | /* |
@@ -635,7 +673,6 @@ static void afs_rx_discard_new_call(struct rxrpc_call *rxcall, | |||
635 | static void afs_rx_new_call(struct sock *sk, struct rxrpc_call *rxcall, | 673 | static void afs_rx_new_call(struct sock *sk, struct rxrpc_call *rxcall, |
636 | unsigned long user_call_ID) | 674 | unsigned long user_call_ID) |
637 | { | 675 | { |
638 | atomic_inc(&afs_outstanding_calls); | ||
639 | queue_work(afs_wq, &afs_charge_preallocation_work); | 676 | queue_work(afs_wq, &afs_charge_preallocation_work); |
640 | } | 677 | } |
641 | 678 | ||
@@ -699,7 +736,6 @@ void afs_send_empty_reply(struct afs_call *call) | |||
699 | rxrpc_kernel_abort_call(afs_socket, call->rxcall, | 736 | rxrpc_kernel_abort_call(afs_socket, call->rxcall, |
700 | RX_USER_ABORT, ENOMEM, "KOO"); | 737 | RX_USER_ABORT, ENOMEM, "KOO"); |
701 | default: | 738 | default: |
702 | afs_end_call(call); | ||
703 | _leave(" [error]"); | 739 | _leave(" [error]"); |
704 | return; | 740 | return; |
705 | } | 741 | } |
@@ -738,7 +774,6 @@ void afs_send_simple_reply(struct afs_call *call, const void *buf, size_t len) | |||
738 | rxrpc_kernel_abort_call(afs_socket, call->rxcall, | 774 | rxrpc_kernel_abort_call(afs_socket, call->rxcall, |
739 | RX_USER_ABORT, ENOMEM, "KOO"); | 775 | RX_USER_ABORT, ENOMEM, "KOO"); |
740 | } | 776 | } |
741 | afs_end_call(call); | ||
742 | _leave(" [error]"); | 777 | _leave(" [error]"); |
743 | } | 778 | } |
744 | 779 | ||
diff --git a/include/trace/events/afs.h b/include/trace/events/afs.h index 845907b04ff4..8b95c16b7045 100644 --- a/include/trace/events/afs.h +++ b/include/trace/events/afs.h | |||
@@ -16,6 +16,51 @@ | |||
16 | 16 | ||
17 | #include <linux/tracepoint.h> | 17 | #include <linux/tracepoint.h> |
18 | 18 | ||
19 | /* | ||
20 | * Define enums for tracing information. | ||
21 | */ | ||
22 | #ifndef __AFS_DECLARE_TRACE_ENUMS_ONCE_ONLY | ||
23 | #define __AFS_DECLARE_TRACE_ENUMS_ONCE_ONLY | ||
24 | |||
25 | enum afs_call_trace { | ||
26 | afs_call_trace_alloc, | ||
27 | afs_call_trace_free, | ||
28 | afs_call_trace_put, | ||
29 | afs_call_trace_wake, | ||
30 | afs_call_trace_work, | ||
31 | }; | ||
32 | |||
33 | #endif /* end __AFS_DECLARE_TRACE_ENUMS_ONCE_ONLY */ | ||
34 | |||
35 | /* | ||
36 | * Declare tracing information enums and their string mappings for display. | ||
37 | */ | ||
38 | #define afs_call_traces \ | ||
39 | EM(afs_call_trace_alloc, "ALLOC") \ | ||
40 | EM(afs_call_trace_free, "FREE ") \ | ||
41 | EM(afs_call_trace_put, "PUT ") \ | ||
42 | EM(afs_call_trace_wake, "WAKE ") \ | ||
43 | E_(afs_call_trace_work, "WORK ") | ||
44 | |||
45 | /* | ||
46 | * Export enum symbols via userspace. | ||
47 | */ | ||
48 | #undef EM | ||
49 | #undef E_ | ||
50 | #define EM(a, b) TRACE_DEFINE_ENUM(a); | ||
51 | #define E_(a, b) TRACE_DEFINE_ENUM(a); | ||
52 | |||
53 | afs_call_traces; | ||
54 | |||
55 | /* | ||
56 | * Now redefine the EM() and E_() macros to map the enums to the strings that | ||
57 | * will be printed in the output. | ||
58 | */ | ||
59 | #undef EM | ||
60 | #undef E_ | ||
61 | #define EM(a, b) { a, b }, | ||
62 | #define E_(a, b) { a, b } | ||
63 | |||
19 | TRACE_EVENT(afs_recv_data, | 64 | TRACE_EVENT(afs_recv_data, |
20 | TP_PROTO(struct afs_call *call, unsigned count, unsigned offset, | 65 | TP_PROTO(struct afs_call *call, unsigned count, unsigned offset, |
21 | bool want_more, int ret), | 66 | bool want_more, int ret), |
@@ -103,6 +148,36 @@ TRACE_EVENT(afs_cb_call, | |||
103 | __entry->op) | 148 | __entry->op) |
104 | ); | 149 | ); |
105 | 150 | ||
151 | TRACE_EVENT(afs_call, | ||
152 | TP_PROTO(struct afs_call *call, enum afs_call_trace op, | ||
153 | int usage, int outstanding, const void *where), | ||
154 | |||
155 | TP_ARGS(call, op, usage, outstanding, where), | ||
156 | |||
157 | TP_STRUCT__entry( | ||
158 | __field(struct afs_call *, call ) | ||
159 | __field(int, op ) | ||
160 | __field(int, usage ) | ||
161 | __field(int, outstanding ) | ||
162 | __field(const void *, where ) | ||
163 | ), | ||
164 | |||
165 | TP_fast_assign( | ||
166 | __entry->call = call; | ||
167 | __entry->op = op; | ||
168 | __entry->usage = usage; | ||
169 | __entry->outstanding = outstanding; | ||
170 | __entry->where = where; | ||
171 | ), | ||
172 | |||
173 | TP_printk("c=%p %s u=%d o=%d sp=%pSR", | ||
174 | __entry->call, | ||
175 | __print_symbolic(__entry->op, afs_call_traces), | ||
176 | __entry->usage, | ||
177 | __entry->outstanding, | ||
178 | __entry->where) | ||
179 | ); | ||
180 | |||
106 | #endif /* _TRACE_AFS_H */ | 181 | #endif /* _TRACE_AFS_H */ |
107 | 182 | ||
108 | /* This part must be outside protection */ | 183 | /* This part must be outside protection */ |