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