diff options
Diffstat (limited to 'fs/afs/cmservice.c')
-rw-r--r-- | fs/afs/cmservice.c | 652 |
1 files changed, 652 insertions, 0 deletions
diff --git a/fs/afs/cmservice.c b/fs/afs/cmservice.c new file mode 100644 index 000000000000..0a57fd7c726f --- /dev/null +++ b/fs/afs/cmservice.c | |||
@@ -0,0 +1,652 @@ | |||
1 | /* cmservice.c: AFS Cache Manager Service | ||
2 | * | ||
3 | * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved. | ||
4 | * Written by David Howells (dhowells@redhat.com) | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public License | ||
8 | * as published by the Free Software Foundation; either version | ||
9 | * 2 of the License, or (at your option) any later version. | ||
10 | */ | ||
11 | |||
12 | #include <linux/module.h> | ||
13 | #include <linux/init.h> | ||
14 | #include <linux/sched.h> | ||
15 | #include <linux/completion.h> | ||
16 | #include "server.h" | ||
17 | #include "cell.h" | ||
18 | #include "transport.h" | ||
19 | #include <rxrpc/rxrpc.h> | ||
20 | #include <rxrpc/transport.h> | ||
21 | #include <rxrpc/connection.h> | ||
22 | #include <rxrpc/call.h> | ||
23 | #include "cmservice.h" | ||
24 | #include "internal.h" | ||
25 | |||
26 | static unsigned afscm_usage; /* AFS cache manager usage count */ | ||
27 | static struct rw_semaphore afscm_sem; /* AFS cache manager start/stop semaphore */ | ||
28 | |||
29 | static int afscm_new_call(struct rxrpc_call *call); | ||
30 | static void afscm_attention(struct rxrpc_call *call); | ||
31 | static void afscm_error(struct rxrpc_call *call); | ||
32 | static void afscm_aemap(struct rxrpc_call *call); | ||
33 | |||
34 | static void _SRXAFSCM_CallBack(struct rxrpc_call *call); | ||
35 | static void _SRXAFSCM_InitCallBackState(struct rxrpc_call *call); | ||
36 | static void _SRXAFSCM_Probe(struct rxrpc_call *call); | ||
37 | |||
38 | typedef void (*_SRXAFSCM_xxxx_t)(struct rxrpc_call *call); | ||
39 | |||
40 | static const struct rxrpc_operation AFSCM_ops[] = { | ||
41 | { | ||
42 | .id = 204, | ||
43 | .asize = RXRPC_APP_MARK_EOF, | ||
44 | .name = "CallBack", | ||
45 | .user = _SRXAFSCM_CallBack, | ||
46 | }, | ||
47 | { | ||
48 | .id = 205, | ||
49 | .asize = RXRPC_APP_MARK_EOF, | ||
50 | .name = "InitCallBackState", | ||
51 | .user = _SRXAFSCM_InitCallBackState, | ||
52 | }, | ||
53 | { | ||
54 | .id = 206, | ||
55 | .asize = RXRPC_APP_MARK_EOF, | ||
56 | .name = "Probe", | ||
57 | .user = _SRXAFSCM_Probe, | ||
58 | }, | ||
59 | #if 0 | ||
60 | { | ||
61 | .id = 207, | ||
62 | .asize = RXRPC_APP_MARK_EOF, | ||
63 | .name = "GetLock", | ||
64 | .user = _SRXAFSCM_GetLock, | ||
65 | }, | ||
66 | { | ||
67 | .id = 208, | ||
68 | .asize = RXRPC_APP_MARK_EOF, | ||
69 | .name = "GetCE", | ||
70 | .user = _SRXAFSCM_GetCE, | ||
71 | }, | ||
72 | { | ||
73 | .id = 209, | ||
74 | .asize = RXRPC_APP_MARK_EOF, | ||
75 | .name = "GetXStatsVersion", | ||
76 | .user = _SRXAFSCM_GetXStatsVersion, | ||
77 | }, | ||
78 | { | ||
79 | .id = 210, | ||
80 | .asize = RXRPC_APP_MARK_EOF, | ||
81 | .name = "GetXStats", | ||
82 | .user = _SRXAFSCM_GetXStats, | ||
83 | } | ||
84 | #endif | ||
85 | }; | ||
86 | |||
87 | static struct rxrpc_service AFSCM_service = { | ||
88 | .name = "AFS/CM", | ||
89 | .owner = THIS_MODULE, | ||
90 | .link = LIST_HEAD_INIT(AFSCM_service.link), | ||
91 | .new_call = afscm_new_call, | ||
92 | .service_id = 1, | ||
93 | .attn_func = afscm_attention, | ||
94 | .error_func = afscm_error, | ||
95 | .aemap_func = afscm_aemap, | ||
96 | .ops_begin = &AFSCM_ops[0], | ||
97 | .ops_end = &AFSCM_ops[sizeof(AFSCM_ops) / sizeof(AFSCM_ops[0])], | ||
98 | }; | ||
99 | |||
100 | static DECLARE_COMPLETION(kafscmd_alive); | ||
101 | static DECLARE_COMPLETION(kafscmd_dead); | ||
102 | static DECLARE_WAIT_QUEUE_HEAD(kafscmd_sleepq); | ||
103 | static LIST_HEAD(kafscmd_attention_list); | ||
104 | static LIST_HEAD(afscm_calls); | ||
105 | static DEFINE_SPINLOCK(afscm_calls_lock); | ||
106 | static DEFINE_SPINLOCK(kafscmd_attention_lock); | ||
107 | static int kafscmd_die; | ||
108 | |||
109 | /*****************************************************************************/ | ||
110 | /* | ||
111 | * AFS Cache Manager kernel thread | ||
112 | */ | ||
113 | static int kafscmd(void *arg) | ||
114 | { | ||
115 | DECLARE_WAITQUEUE(myself, current); | ||
116 | |||
117 | struct rxrpc_call *call; | ||
118 | _SRXAFSCM_xxxx_t func; | ||
119 | int die; | ||
120 | |||
121 | printk("kAFS: Started kafscmd %d\n", current->pid); | ||
122 | |||
123 | daemonize("kafscmd"); | ||
124 | |||
125 | complete(&kafscmd_alive); | ||
126 | |||
127 | /* loop around looking for things to attend to */ | ||
128 | do { | ||
129 | if (list_empty(&kafscmd_attention_list)) { | ||
130 | set_current_state(TASK_INTERRUPTIBLE); | ||
131 | add_wait_queue(&kafscmd_sleepq, &myself); | ||
132 | |||
133 | for (;;) { | ||
134 | set_current_state(TASK_INTERRUPTIBLE); | ||
135 | if (!list_empty(&kafscmd_attention_list) || | ||
136 | signal_pending(current) || | ||
137 | kafscmd_die) | ||
138 | break; | ||
139 | |||
140 | schedule(); | ||
141 | } | ||
142 | |||
143 | remove_wait_queue(&kafscmd_sleepq, &myself); | ||
144 | set_current_state(TASK_RUNNING); | ||
145 | } | ||
146 | |||
147 | die = kafscmd_die; | ||
148 | |||
149 | /* dequeue the next call requiring attention */ | ||
150 | call = NULL; | ||
151 | spin_lock(&kafscmd_attention_lock); | ||
152 | |||
153 | if (!list_empty(&kafscmd_attention_list)) { | ||
154 | call = list_entry(kafscmd_attention_list.next, | ||
155 | struct rxrpc_call, | ||
156 | app_attn_link); | ||
157 | list_del_init(&call->app_attn_link); | ||
158 | die = 0; | ||
159 | } | ||
160 | |||
161 | spin_unlock(&kafscmd_attention_lock); | ||
162 | |||
163 | if (call) { | ||
164 | /* act upon it */ | ||
165 | _debug("@@@ Begin Attend Call %p", call); | ||
166 | |||
167 | func = call->app_user; | ||
168 | if (func) | ||
169 | func(call); | ||
170 | |||
171 | rxrpc_put_call(call); | ||
172 | |||
173 | _debug("@@@ End Attend Call %p", call); | ||
174 | } | ||
175 | |||
176 | } while(!die); | ||
177 | |||
178 | /* and that's all */ | ||
179 | complete_and_exit(&kafscmd_dead, 0); | ||
180 | |||
181 | } /* end kafscmd() */ | ||
182 | |||
183 | /*****************************************************************************/ | ||
184 | /* | ||
185 | * handle a call coming in to the cache manager | ||
186 | * - if I want to keep the call, I must increment its usage count | ||
187 | * - the return value will be negated and passed back in an abort packet if | ||
188 | * non-zero | ||
189 | * - serialised by virtue of there only being one krxiod | ||
190 | */ | ||
191 | static int afscm_new_call(struct rxrpc_call *call) | ||
192 | { | ||
193 | _enter("%p{cid=%u u=%d}", | ||
194 | call, ntohl(call->call_id), atomic_read(&call->usage)); | ||
195 | |||
196 | rxrpc_get_call(call); | ||
197 | |||
198 | /* add to my current call list */ | ||
199 | spin_lock(&afscm_calls_lock); | ||
200 | list_add(&call->app_link,&afscm_calls); | ||
201 | spin_unlock(&afscm_calls_lock); | ||
202 | |||
203 | _leave(" = 0"); | ||
204 | return 0; | ||
205 | |||
206 | } /* end afscm_new_call() */ | ||
207 | |||
208 | /*****************************************************************************/ | ||
209 | /* | ||
210 | * queue on the kafscmd queue for attention | ||
211 | */ | ||
212 | static void afscm_attention(struct rxrpc_call *call) | ||
213 | { | ||
214 | _enter("%p{cid=%u u=%d}", | ||
215 | call, ntohl(call->call_id), atomic_read(&call->usage)); | ||
216 | |||
217 | spin_lock(&kafscmd_attention_lock); | ||
218 | |||
219 | if (list_empty(&call->app_attn_link)) { | ||
220 | list_add_tail(&call->app_attn_link, &kafscmd_attention_list); | ||
221 | rxrpc_get_call(call); | ||
222 | } | ||
223 | |||
224 | spin_unlock(&kafscmd_attention_lock); | ||
225 | |||
226 | wake_up(&kafscmd_sleepq); | ||
227 | |||
228 | _leave(" {u=%d}", atomic_read(&call->usage)); | ||
229 | } /* end afscm_attention() */ | ||
230 | |||
231 | /*****************************************************************************/ | ||
232 | /* | ||
233 | * handle my call being aborted | ||
234 | * - clean up, dequeue and put my ref to the call | ||
235 | */ | ||
236 | static void afscm_error(struct rxrpc_call *call) | ||
237 | { | ||
238 | int removed; | ||
239 | |||
240 | _enter("%p{est=%s ac=%u er=%d}", | ||
241 | call, | ||
242 | rxrpc_call_error_states[call->app_err_state], | ||
243 | call->app_abort_code, | ||
244 | call->app_errno); | ||
245 | |||
246 | spin_lock(&kafscmd_attention_lock); | ||
247 | |||
248 | if (list_empty(&call->app_attn_link)) { | ||
249 | list_add_tail(&call->app_attn_link, &kafscmd_attention_list); | ||
250 | rxrpc_get_call(call); | ||
251 | } | ||
252 | |||
253 | spin_unlock(&kafscmd_attention_lock); | ||
254 | |||
255 | removed = 0; | ||
256 | spin_lock(&afscm_calls_lock); | ||
257 | if (!list_empty(&call->app_link)) { | ||
258 | list_del_init(&call->app_link); | ||
259 | removed = 1; | ||
260 | } | ||
261 | spin_unlock(&afscm_calls_lock); | ||
262 | |||
263 | if (removed) | ||
264 | rxrpc_put_call(call); | ||
265 | |||
266 | wake_up(&kafscmd_sleepq); | ||
267 | |||
268 | _leave(""); | ||
269 | } /* end afscm_error() */ | ||
270 | |||
271 | /*****************************************************************************/ | ||
272 | /* | ||
273 | * map afs abort codes to/from Linux error codes | ||
274 | * - called with call->lock held | ||
275 | */ | ||
276 | static void afscm_aemap(struct rxrpc_call *call) | ||
277 | { | ||
278 | switch (call->app_err_state) { | ||
279 | case RXRPC_ESTATE_LOCAL_ABORT: | ||
280 | call->app_abort_code = -call->app_errno; | ||
281 | break; | ||
282 | case RXRPC_ESTATE_PEER_ABORT: | ||
283 | call->app_errno = -ECONNABORTED; | ||
284 | break; | ||
285 | default: | ||
286 | break; | ||
287 | } | ||
288 | } /* end afscm_aemap() */ | ||
289 | |||
290 | /*****************************************************************************/ | ||
291 | /* | ||
292 | * start the cache manager service if not already started | ||
293 | */ | ||
294 | int afscm_start(void) | ||
295 | { | ||
296 | int ret; | ||
297 | |||
298 | down_write(&afscm_sem); | ||
299 | if (!afscm_usage) { | ||
300 | ret = kernel_thread(kafscmd, NULL, 0); | ||
301 | if (ret < 0) | ||
302 | goto out; | ||
303 | |||
304 | wait_for_completion(&kafscmd_alive); | ||
305 | |||
306 | ret = rxrpc_add_service(afs_transport, &AFSCM_service); | ||
307 | if (ret < 0) | ||
308 | goto kill; | ||
309 | |||
310 | afs_kafstimod_add_timer(&afs_mntpt_expiry_timer, | ||
311 | afs_mntpt_expiry_timeout * HZ); | ||
312 | } | ||
313 | |||
314 | afscm_usage++; | ||
315 | up_write(&afscm_sem); | ||
316 | |||
317 | return 0; | ||
318 | |||
319 | kill: | ||
320 | kafscmd_die = 1; | ||
321 | wake_up(&kafscmd_sleepq); | ||
322 | wait_for_completion(&kafscmd_dead); | ||
323 | |||
324 | out: | ||
325 | up_write(&afscm_sem); | ||
326 | return ret; | ||
327 | |||
328 | } /* end afscm_start() */ | ||
329 | |||
330 | /*****************************************************************************/ | ||
331 | /* | ||
332 | * stop the cache manager service | ||
333 | */ | ||
334 | void afscm_stop(void) | ||
335 | { | ||
336 | struct rxrpc_call *call; | ||
337 | |||
338 | down_write(&afscm_sem); | ||
339 | |||
340 | BUG_ON(afscm_usage == 0); | ||
341 | afscm_usage--; | ||
342 | |||
343 | if (afscm_usage == 0) { | ||
344 | /* don't want more incoming calls */ | ||
345 | rxrpc_del_service(afs_transport, &AFSCM_service); | ||
346 | |||
347 | /* abort any calls I've still got open (the afscm_error() will | ||
348 | * dequeue them) */ | ||
349 | spin_lock(&afscm_calls_lock); | ||
350 | while (!list_empty(&afscm_calls)) { | ||
351 | call = list_entry(afscm_calls.next, | ||
352 | struct rxrpc_call, | ||
353 | app_link); | ||
354 | |||
355 | list_del_init(&call->app_link); | ||
356 | rxrpc_get_call(call); | ||
357 | spin_unlock(&afscm_calls_lock); | ||
358 | |||
359 | rxrpc_call_abort(call, -ESRCH); /* abort, dequeue and | ||
360 | * put */ | ||
361 | |||
362 | _debug("nuking active call %08x.%d", | ||
363 | ntohl(call->conn->conn_id), | ||
364 | ntohl(call->call_id)); | ||
365 | rxrpc_put_call(call); | ||
366 | rxrpc_put_call(call); | ||
367 | |||
368 | spin_lock(&afscm_calls_lock); | ||
369 | } | ||
370 | spin_unlock(&afscm_calls_lock); | ||
371 | |||
372 | /* get rid of my daemon */ | ||
373 | kafscmd_die = 1; | ||
374 | wake_up(&kafscmd_sleepq); | ||
375 | wait_for_completion(&kafscmd_dead); | ||
376 | |||
377 | /* dispose of any calls waiting for attention */ | ||
378 | spin_lock(&kafscmd_attention_lock); | ||
379 | while (!list_empty(&kafscmd_attention_list)) { | ||
380 | call = list_entry(kafscmd_attention_list.next, | ||
381 | struct rxrpc_call, | ||
382 | app_attn_link); | ||
383 | |||
384 | list_del_init(&call->app_attn_link); | ||
385 | spin_unlock(&kafscmd_attention_lock); | ||
386 | |||
387 | rxrpc_put_call(call); | ||
388 | |||
389 | spin_lock(&kafscmd_attention_lock); | ||
390 | } | ||
391 | spin_unlock(&kafscmd_attention_lock); | ||
392 | |||
393 | afs_kafstimod_del_timer(&afs_mntpt_expiry_timer); | ||
394 | } | ||
395 | |||
396 | up_write(&afscm_sem); | ||
397 | |||
398 | } /* end afscm_stop() */ | ||
399 | |||
400 | /*****************************************************************************/ | ||
401 | /* | ||
402 | * handle the fileserver breaking a set of callbacks | ||
403 | */ | ||
404 | static void _SRXAFSCM_CallBack(struct rxrpc_call *call) | ||
405 | { | ||
406 | struct afs_server *server; | ||
407 | size_t count, qty, tmp; | ||
408 | int ret = 0, removed; | ||
409 | |||
410 | _enter("%p{acs=%s}", call, rxrpc_call_states[call->app_call_state]); | ||
411 | |||
412 | server = afs_server_get_from_peer(call->conn->peer); | ||
413 | |||
414 | switch (call->app_call_state) { | ||
415 | /* we've received the last packet | ||
416 | * - drain all the data from the call and send the reply | ||
417 | */ | ||
418 | case RXRPC_CSTATE_SRVR_GOT_ARGS: | ||
419 | ret = -EBADMSG; | ||
420 | qty = call->app_ready_qty; | ||
421 | if (qty < 8 || qty > 50 * (6 * 4) + 8) | ||
422 | break; | ||
423 | |||
424 | { | ||
425 | struct afs_callback *cb, *pcb; | ||
426 | int loop; | ||
427 | __be32 *fp, *bp; | ||
428 | |||
429 | fp = rxrpc_call_alloc_scratch(call, qty); | ||
430 | |||
431 | /* drag the entire argument block out to the scratch | ||
432 | * space */ | ||
433 | ret = rxrpc_call_read_data(call, fp, qty, 0); | ||
434 | if (ret < 0) | ||
435 | break; | ||
436 | |||
437 | /* and unmarshall the parameter block */ | ||
438 | ret = -EBADMSG; | ||
439 | count = ntohl(*fp++); | ||
440 | if (count>AFSCBMAX || | ||
441 | (count * (3 * 4) + 8 != qty && | ||
442 | count * (6 * 4) + 8 != qty)) | ||
443 | break; | ||
444 | |||
445 | bp = fp + count*3; | ||
446 | tmp = ntohl(*bp++); | ||
447 | if (tmp > 0 && tmp != count) | ||
448 | break; | ||
449 | if (tmp == 0) | ||
450 | bp = NULL; | ||
451 | |||
452 | pcb = cb = rxrpc_call_alloc_scratch_s( | ||
453 | call, struct afs_callback); | ||
454 | |||
455 | for (loop = count - 1; loop >= 0; loop--) { | ||
456 | pcb->fid.vid = ntohl(*fp++); | ||
457 | pcb->fid.vnode = ntohl(*fp++); | ||
458 | pcb->fid.unique = ntohl(*fp++); | ||
459 | if (bp) { | ||
460 | pcb->version = ntohl(*bp++); | ||
461 | pcb->expiry = ntohl(*bp++); | ||
462 | pcb->type = ntohl(*bp++); | ||
463 | } | ||
464 | else { | ||
465 | pcb->version = 0; | ||
466 | pcb->expiry = 0; | ||
467 | pcb->type = AFSCM_CB_UNTYPED; | ||
468 | } | ||
469 | pcb++; | ||
470 | } | ||
471 | |||
472 | /* invoke the actual service routine */ | ||
473 | ret = SRXAFSCM_CallBack(server, count, cb); | ||
474 | if (ret < 0) | ||
475 | break; | ||
476 | } | ||
477 | |||
478 | /* send the reply */ | ||
479 | ret = rxrpc_call_write_data(call, 0, NULL, RXRPC_LAST_PACKET, | ||
480 | GFP_KERNEL, 0, &count); | ||
481 | if (ret < 0) | ||
482 | break; | ||
483 | break; | ||
484 | |||
485 | /* operation complete */ | ||
486 | case RXRPC_CSTATE_COMPLETE: | ||
487 | call->app_user = NULL; | ||
488 | removed = 0; | ||
489 | spin_lock(&afscm_calls_lock); | ||
490 | if (!list_empty(&call->app_link)) { | ||
491 | list_del_init(&call->app_link); | ||
492 | removed = 1; | ||
493 | } | ||
494 | spin_unlock(&afscm_calls_lock); | ||
495 | |||
496 | if (removed) | ||
497 | rxrpc_put_call(call); | ||
498 | break; | ||
499 | |||
500 | /* operation terminated on error */ | ||
501 | case RXRPC_CSTATE_ERROR: | ||
502 | call->app_user = NULL; | ||
503 | break; | ||
504 | |||
505 | default: | ||
506 | break; | ||
507 | } | ||
508 | |||
509 | if (ret < 0) | ||
510 | rxrpc_call_abort(call, ret); | ||
511 | |||
512 | afs_put_server(server); | ||
513 | |||
514 | _leave(" = %d", ret); | ||
515 | |||
516 | } /* end _SRXAFSCM_CallBack() */ | ||
517 | |||
518 | /*****************************************************************************/ | ||
519 | /* | ||
520 | * handle the fileserver asking us to initialise our callback state | ||
521 | */ | ||
522 | static void _SRXAFSCM_InitCallBackState(struct rxrpc_call *call) | ||
523 | { | ||
524 | struct afs_server *server; | ||
525 | size_t count; | ||
526 | int ret = 0, removed; | ||
527 | |||
528 | _enter("%p{acs=%s}", call, rxrpc_call_states[call->app_call_state]); | ||
529 | |||
530 | server = afs_server_get_from_peer(call->conn->peer); | ||
531 | |||
532 | switch (call->app_call_state) { | ||
533 | /* we've received the last packet - drain all the data from the | ||
534 | * call */ | ||
535 | case RXRPC_CSTATE_SRVR_GOT_ARGS: | ||
536 | /* shouldn't be any args */ | ||
537 | ret = -EBADMSG; | ||
538 | break; | ||
539 | |||
540 | /* send the reply when asked for it */ | ||
541 | case RXRPC_CSTATE_SRVR_SND_REPLY: | ||
542 | /* invoke the actual service routine */ | ||
543 | ret = SRXAFSCM_InitCallBackState(server); | ||
544 | if (ret < 0) | ||
545 | break; | ||
546 | |||
547 | ret = rxrpc_call_write_data(call, 0, NULL, RXRPC_LAST_PACKET, | ||
548 | GFP_KERNEL, 0, &count); | ||
549 | if (ret < 0) | ||
550 | break; | ||
551 | break; | ||
552 | |||
553 | /* operation complete */ | ||
554 | case RXRPC_CSTATE_COMPLETE: | ||
555 | call->app_user = NULL; | ||
556 | removed = 0; | ||
557 | spin_lock(&afscm_calls_lock); | ||
558 | if (!list_empty(&call->app_link)) { | ||
559 | list_del_init(&call->app_link); | ||
560 | removed = 1; | ||
561 | } | ||
562 | spin_unlock(&afscm_calls_lock); | ||
563 | |||
564 | if (removed) | ||
565 | rxrpc_put_call(call); | ||
566 | break; | ||
567 | |||
568 | /* operation terminated on error */ | ||
569 | case RXRPC_CSTATE_ERROR: | ||
570 | call->app_user = NULL; | ||
571 | break; | ||
572 | |||
573 | default: | ||
574 | break; | ||
575 | } | ||
576 | |||
577 | if (ret < 0) | ||
578 | rxrpc_call_abort(call, ret); | ||
579 | |||
580 | afs_put_server(server); | ||
581 | |||
582 | _leave(" = %d", ret); | ||
583 | |||
584 | } /* end _SRXAFSCM_InitCallBackState() */ | ||
585 | |||
586 | /*****************************************************************************/ | ||
587 | /* | ||
588 | * handle a probe from a fileserver | ||
589 | */ | ||
590 | static void _SRXAFSCM_Probe(struct rxrpc_call *call) | ||
591 | { | ||
592 | struct afs_server *server; | ||
593 | size_t count; | ||
594 | int ret = 0, removed; | ||
595 | |||
596 | _enter("%p{acs=%s}", call, rxrpc_call_states[call->app_call_state]); | ||
597 | |||
598 | server = afs_server_get_from_peer(call->conn->peer); | ||
599 | |||
600 | switch (call->app_call_state) { | ||
601 | /* we've received the last packet - drain all the data from the | ||
602 | * call */ | ||
603 | case RXRPC_CSTATE_SRVR_GOT_ARGS: | ||
604 | /* shouldn't be any args */ | ||
605 | ret = -EBADMSG; | ||
606 | break; | ||
607 | |||
608 | /* send the reply when asked for it */ | ||
609 | case RXRPC_CSTATE_SRVR_SND_REPLY: | ||
610 | /* invoke the actual service routine */ | ||
611 | ret = SRXAFSCM_Probe(server); | ||
612 | if (ret < 0) | ||
613 | break; | ||
614 | |||
615 | ret = rxrpc_call_write_data(call, 0, NULL, RXRPC_LAST_PACKET, | ||
616 | GFP_KERNEL, 0, &count); | ||
617 | if (ret < 0) | ||
618 | break; | ||
619 | break; | ||
620 | |||
621 | /* operation complete */ | ||
622 | case RXRPC_CSTATE_COMPLETE: | ||
623 | call->app_user = NULL; | ||
624 | removed = 0; | ||
625 | spin_lock(&afscm_calls_lock); | ||
626 | if (!list_empty(&call->app_link)) { | ||
627 | list_del_init(&call->app_link); | ||
628 | removed = 1; | ||
629 | } | ||
630 | spin_unlock(&afscm_calls_lock); | ||
631 | |||
632 | if (removed) | ||
633 | rxrpc_put_call(call); | ||
634 | break; | ||
635 | |||
636 | /* operation terminated on error */ | ||
637 | case RXRPC_CSTATE_ERROR: | ||
638 | call->app_user = NULL; | ||
639 | break; | ||
640 | |||
641 | default: | ||
642 | break; | ||
643 | } | ||
644 | |||
645 | if (ret < 0) | ||
646 | rxrpc_call_abort(call, ret); | ||
647 | |||
648 | afs_put_server(server); | ||
649 | |||
650 | _leave(" = %d", ret); | ||
651 | |||
652 | } /* end _SRXAFSCM_Probe() */ | ||