Root/
1 | /* 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/ip.h> |
16 | #include "internal.h" |
17 | #include "afs_cm.h" |
18 | |
19 | #if 0 |
20 | struct workqueue_struct *afs_cm_workqueue; |
21 | #endif /* 0 */ |
22 | |
23 | static int afs_deliver_cb_init_call_back_state(struct afs_call *, |
24 | struct sk_buff *, bool); |
25 | static int afs_deliver_cb_init_call_back_state3(struct afs_call *, |
26 | struct sk_buff *, bool); |
27 | static int afs_deliver_cb_probe(struct afs_call *, struct sk_buff *, bool); |
28 | static int afs_deliver_cb_callback(struct afs_call *, struct sk_buff *, bool); |
29 | static int afs_deliver_cb_probe_uuid(struct afs_call *, struct sk_buff *, bool); |
30 | static int afs_deliver_cb_tell_me_about_yourself(struct afs_call *, |
31 | struct sk_buff *, bool); |
32 | static void afs_cm_destructor(struct afs_call *); |
33 | |
34 | /* |
35 | * CB.CallBack operation type |
36 | */ |
37 | static const struct afs_call_type afs_SRXCBCallBack = { |
38 | .name = "CB.CallBack", |
39 | .deliver = afs_deliver_cb_callback, |
40 | .abort_to_error = afs_abort_to_error, |
41 | .destructor = afs_cm_destructor, |
42 | }; |
43 | |
44 | /* |
45 | * CB.InitCallBackState operation type |
46 | */ |
47 | static const struct afs_call_type afs_SRXCBInitCallBackState = { |
48 | .name = "CB.InitCallBackState", |
49 | .deliver = afs_deliver_cb_init_call_back_state, |
50 | .abort_to_error = afs_abort_to_error, |
51 | .destructor = afs_cm_destructor, |
52 | }; |
53 | |
54 | /* |
55 | * CB.InitCallBackState3 operation type |
56 | */ |
57 | static const struct afs_call_type afs_SRXCBInitCallBackState3 = { |
58 | .name = "CB.InitCallBackState3", |
59 | .deliver = afs_deliver_cb_init_call_back_state3, |
60 | .abort_to_error = afs_abort_to_error, |
61 | .destructor = afs_cm_destructor, |
62 | }; |
63 | |
64 | /* |
65 | * CB.Probe operation type |
66 | */ |
67 | static const struct afs_call_type afs_SRXCBProbe = { |
68 | .name = "CB.Probe", |
69 | .deliver = afs_deliver_cb_probe, |
70 | .abort_to_error = afs_abort_to_error, |
71 | .destructor = afs_cm_destructor, |
72 | }; |
73 | |
74 | /* |
75 | * CB.ProbeUuid operation type |
76 | */ |
77 | static const struct afs_call_type afs_SRXCBProbeUuid = { |
78 | .name = "CB.ProbeUuid", |
79 | .deliver = afs_deliver_cb_probe_uuid, |
80 | .abort_to_error = afs_abort_to_error, |
81 | .destructor = afs_cm_destructor, |
82 | }; |
83 | |
84 | /* |
85 | * CB.TellMeAboutYourself operation type |
86 | */ |
87 | static const struct afs_call_type afs_SRXCBTellMeAboutYourself = { |
88 | .name = "CB.TellMeAboutYourself", |
89 | .deliver = afs_deliver_cb_tell_me_about_yourself, |
90 | .abort_to_error = afs_abort_to_error, |
91 | .destructor = afs_cm_destructor, |
92 | }; |
93 | |
94 | /* |
95 | * route an incoming cache manager call |
96 | * - return T if supported, F if not |
97 | */ |
98 | bool afs_cm_incoming_call(struct afs_call *call) |
99 | { |
100 | u32 operation_id = ntohl(call->operation_ID); |
101 | |
102 | _enter("{CB.OP %u}", operation_id); |
103 | |
104 | switch (operation_id) { |
105 | case CBCallBack: |
106 | call->type = &afs_SRXCBCallBack; |
107 | return true; |
108 | case CBInitCallBackState: |
109 | call->type = &afs_SRXCBInitCallBackState; |
110 | return true; |
111 | case CBInitCallBackState3: |
112 | call->type = &afs_SRXCBInitCallBackState3; |
113 | return true; |
114 | case CBProbe: |
115 | call->type = &afs_SRXCBProbe; |
116 | return true; |
117 | case CBTellMeAboutYourself: |
118 | call->type = &afs_SRXCBTellMeAboutYourself; |
119 | return true; |
120 | default: |
121 | return false; |
122 | } |
123 | } |
124 | |
125 | /* |
126 | * clean up a cache manager call |
127 | */ |
128 | static void afs_cm_destructor(struct afs_call *call) |
129 | { |
130 | _enter(""); |
131 | |
132 | afs_put_server(call->server); |
133 | call->server = NULL; |
134 | kfree(call->buffer); |
135 | call->buffer = NULL; |
136 | } |
137 | |
138 | /* |
139 | * allow the fileserver to see if the cache manager is still alive |
140 | */ |
141 | static void SRXAFSCB_CallBack(struct work_struct *work) |
142 | { |
143 | struct afs_call *call = container_of(work, struct afs_call, work); |
144 | |
145 | _enter(""); |
146 | |
147 | /* be sure to send the reply *before* attempting to spam the AFS server |
148 | * with FSFetchStatus requests on the vnodes with broken callbacks lest |
149 | * the AFS server get into a vicious cycle of trying to break further |
150 | * callbacks because it hadn't received completion of the CBCallBack op |
151 | * yet */ |
152 | afs_send_empty_reply(call); |
153 | |
154 | afs_break_callbacks(call->server, call->count, call->request); |
155 | _leave(""); |
156 | } |
157 | |
158 | /* |
159 | * deliver request data to a CB.CallBack call |
160 | */ |
161 | static int afs_deliver_cb_callback(struct afs_call *call, struct sk_buff *skb, |
162 | bool last) |
163 | { |
164 | struct afs_callback *cb; |
165 | struct afs_server *server; |
166 | struct in_addr addr; |
167 | __be32 *bp; |
168 | u32 tmp; |
169 | int ret, loop; |
170 | |
171 | _enter("{%u},{%u},%d", call->unmarshall, skb->len, last); |
172 | |
173 | switch (call->unmarshall) { |
174 | case 0: |
175 | call->offset = 0; |
176 | call->unmarshall++; |
177 | |
178 | /* extract the FID array and its count in two steps */ |
179 | case 1: |
180 | _debug("extract FID count"); |
181 | ret = afs_extract_data(call, skb, last, &call->tmp, 4); |
182 | switch (ret) { |
183 | case 0: break; |
184 | case -EAGAIN: return 0; |
185 | default: return ret; |
186 | } |
187 | |
188 | call->count = ntohl(call->tmp); |
189 | _debug("FID count: %u", call->count); |
190 | if (call->count > AFSCBMAX) |
191 | return -EBADMSG; |
192 | |
193 | call->buffer = kmalloc(call->count * 3 * 4, GFP_KERNEL); |
194 | if (!call->buffer) |
195 | return -ENOMEM; |
196 | call->offset = 0; |
197 | call->unmarshall++; |
198 | |
199 | case 2: |
200 | _debug("extract FID array"); |
201 | ret = afs_extract_data(call, skb, last, call->buffer, |
202 | call->count * 3 * 4); |
203 | switch (ret) { |
204 | case 0: break; |
205 | case -EAGAIN: return 0; |
206 | default: return ret; |
207 | } |
208 | |
209 | _debug("unmarshall FID array"); |
210 | call->request = kcalloc(call->count, |
211 | sizeof(struct afs_callback), |
212 | GFP_KERNEL); |
213 | if (!call->request) |
214 | return -ENOMEM; |
215 | |
216 | cb = call->request; |
217 | bp = call->buffer; |
218 | for (loop = call->count; loop > 0; loop--, cb++) { |
219 | cb->fid.vid = ntohl(*bp++); |
220 | cb->fid.vnode = ntohl(*bp++); |
221 | cb->fid.unique = ntohl(*bp++); |
222 | cb->type = AFSCM_CB_UNTYPED; |
223 | } |
224 | |
225 | call->offset = 0; |
226 | call->unmarshall++; |
227 | |
228 | /* extract the callback array and its count in two steps */ |
229 | case 3: |
230 | _debug("extract CB count"); |
231 | ret = afs_extract_data(call, skb, last, &call->tmp, 4); |
232 | switch (ret) { |
233 | case 0: break; |
234 | case -EAGAIN: return 0; |
235 | default: return ret; |
236 | } |
237 | |
238 | tmp = ntohl(call->tmp); |
239 | _debug("CB count: %u", tmp); |
240 | if (tmp != call->count && tmp != 0) |
241 | return -EBADMSG; |
242 | call->offset = 0; |
243 | call->unmarshall++; |
244 | if (tmp == 0) |
245 | goto empty_cb_array; |
246 | |
247 | case 4: |
248 | _debug("extract CB array"); |
249 | ret = afs_extract_data(call, skb, last, call->request, |
250 | call->count * 3 * 4); |
251 | switch (ret) { |
252 | case 0: break; |
253 | case -EAGAIN: return 0; |
254 | default: return ret; |
255 | } |
256 | |
257 | _debug("unmarshall CB array"); |
258 | cb = call->request; |
259 | bp = call->buffer; |
260 | for (loop = call->count; loop > 0; loop--, cb++) { |
261 | cb->version = ntohl(*bp++); |
262 | cb->expiry = ntohl(*bp++); |
263 | cb->type = ntohl(*bp++); |
264 | } |
265 | |
266 | empty_cb_array: |
267 | call->offset = 0; |
268 | call->unmarshall++; |
269 | |
270 | case 5: |
271 | _debug("trailer"); |
272 | if (skb->len != 0) |
273 | return -EBADMSG; |
274 | break; |
275 | } |
276 | |
277 | if (!last) |
278 | return 0; |
279 | |
280 | call->state = AFS_CALL_REPLYING; |
281 | |
282 | /* we'll need the file server record as that tells us which set of |
283 | * vnodes to operate upon */ |
284 | memcpy(&addr, &ip_hdr(skb)->saddr, 4); |
285 | server = afs_find_server(&addr); |
286 | if (!server) |
287 | return -ENOTCONN; |
288 | call->server = server; |
289 | |
290 | INIT_WORK(&call->work, SRXAFSCB_CallBack); |
291 | schedule_work(&call->work); |
292 | return 0; |
293 | } |
294 | |
295 | /* |
296 | * allow the fileserver to request callback state (re-)initialisation |
297 | */ |
298 | static void SRXAFSCB_InitCallBackState(struct work_struct *work) |
299 | { |
300 | struct afs_call *call = container_of(work, struct afs_call, work); |
301 | |
302 | _enter("{%p}", call->server); |
303 | |
304 | afs_init_callback_state(call->server); |
305 | afs_send_empty_reply(call); |
306 | _leave(""); |
307 | } |
308 | |
309 | /* |
310 | * deliver request data to a CB.InitCallBackState call |
311 | */ |
312 | static int afs_deliver_cb_init_call_back_state(struct afs_call *call, |
313 | struct sk_buff *skb, |
314 | bool last) |
315 | { |
316 | struct afs_server *server; |
317 | struct in_addr addr; |
318 | |
319 | _enter(",{%u},%d", skb->len, last); |
320 | |
321 | if (skb->len > 0) |
322 | return -EBADMSG; |
323 | if (!last) |
324 | return 0; |
325 | |
326 | /* no unmarshalling required */ |
327 | call->state = AFS_CALL_REPLYING; |
328 | |
329 | /* we'll need the file server record as that tells us which set of |
330 | * vnodes to operate upon */ |
331 | memcpy(&addr, &ip_hdr(skb)->saddr, 4); |
332 | server = afs_find_server(&addr); |
333 | if (!server) |
334 | return -ENOTCONN; |
335 | call->server = server; |
336 | |
337 | INIT_WORK(&call->work, SRXAFSCB_InitCallBackState); |
338 | schedule_work(&call->work); |
339 | return 0; |
340 | } |
341 | |
342 | /* |
343 | * deliver request data to a CB.InitCallBackState3 call |
344 | */ |
345 | static int afs_deliver_cb_init_call_back_state3(struct afs_call *call, |
346 | struct sk_buff *skb, |
347 | bool last) |
348 | { |
349 | struct afs_server *server; |
350 | struct in_addr addr; |
351 | |
352 | _enter(",{%u},%d", skb->len, last); |
353 | |
354 | if (!last) |
355 | return 0; |
356 | |
357 | /* no unmarshalling required */ |
358 | call->state = AFS_CALL_REPLYING; |
359 | |
360 | /* we'll need the file server record as that tells us which set of |
361 | * vnodes to operate upon */ |
362 | memcpy(&addr, &ip_hdr(skb)->saddr, 4); |
363 | server = afs_find_server(&addr); |
364 | if (!server) |
365 | return -ENOTCONN; |
366 | call->server = server; |
367 | |
368 | INIT_WORK(&call->work, SRXAFSCB_InitCallBackState); |
369 | schedule_work(&call->work); |
370 | return 0; |
371 | } |
372 | |
373 | /* |
374 | * allow the fileserver to see if the cache manager is still alive |
375 | */ |
376 | static void SRXAFSCB_Probe(struct work_struct *work) |
377 | { |
378 | struct afs_call *call = container_of(work, struct afs_call, work); |
379 | |
380 | _enter(""); |
381 | afs_send_empty_reply(call); |
382 | _leave(""); |
383 | } |
384 | |
385 | /* |
386 | * deliver request data to a CB.Probe call |
387 | */ |
388 | static int afs_deliver_cb_probe(struct afs_call *call, struct sk_buff *skb, |
389 | bool last) |
390 | { |
391 | _enter(",{%u},%d", skb->len, last); |
392 | |
393 | if (skb->len > 0) |
394 | return -EBADMSG; |
395 | if (!last) |
396 | return 0; |
397 | |
398 | /* no unmarshalling required */ |
399 | call->state = AFS_CALL_REPLYING; |
400 | |
401 | INIT_WORK(&call->work, SRXAFSCB_Probe); |
402 | schedule_work(&call->work); |
403 | return 0; |
404 | } |
405 | |
406 | /* |
407 | * allow the fileserver to quickly find out if the fileserver has been rebooted |
408 | */ |
409 | static void SRXAFSCB_ProbeUuid(struct work_struct *work) |
410 | { |
411 | struct afs_call *call = container_of(work, struct afs_call, work); |
412 | struct afs_uuid *r = call->request; |
413 | |
414 | struct { |
415 | __be32 match; |
416 | } reply; |
417 | |
418 | _enter(""); |
419 | |
420 | |
421 | if (memcmp(r, &afs_uuid, sizeof(afs_uuid)) == 0) |
422 | reply.match = htonl(0); |
423 | else |
424 | reply.match = htonl(1); |
425 | |
426 | afs_send_simple_reply(call, &reply, sizeof(reply)); |
427 | _leave(""); |
428 | } |
429 | |
430 | /* |
431 | * deliver request data to a CB.ProbeUuid call |
432 | */ |
433 | static int afs_deliver_cb_probe_uuid(struct afs_call *call, struct sk_buff *skb, |
434 | bool last) |
435 | { |
436 | struct afs_uuid *r; |
437 | unsigned loop; |
438 | __be32 *b; |
439 | int ret; |
440 | |
441 | _enter("{%u},{%u},%d", call->unmarshall, skb->len, last); |
442 | |
443 | if (skb->len > 0) |
444 | return -EBADMSG; |
445 | if (!last) |
446 | return 0; |
447 | |
448 | switch (call->unmarshall) { |
449 | case 0: |
450 | call->offset = 0; |
451 | call->buffer = kmalloc(11 * sizeof(__be32), GFP_KERNEL); |
452 | if (!call->buffer) |
453 | return -ENOMEM; |
454 | call->unmarshall++; |
455 | |
456 | case 1: |
457 | _debug("extract UUID"); |
458 | ret = afs_extract_data(call, skb, last, call->buffer, |
459 | 11 * sizeof(__be32)); |
460 | switch (ret) { |
461 | case 0: break; |
462 | case -EAGAIN: return 0; |
463 | default: return ret; |
464 | } |
465 | |
466 | _debug("unmarshall UUID"); |
467 | call->request = kmalloc(sizeof(struct afs_uuid), GFP_KERNEL); |
468 | if (!call->request) |
469 | return -ENOMEM; |
470 | |
471 | b = call->buffer; |
472 | r = call->request; |
473 | r->time_low = ntohl(b[0]); |
474 | r->time_mid = ntohl(b[1]); |
475 | r->time_hi_and_version = ntohl(b[2]); |
476 | r->clock_seq_hi_and_reserved = ntohl(b[3]); |
477 | r->clock_seq_low = ntohl(b[4]); |
478 | |
479 | for (loop = 0; loop < 6; loop++) |
480 | r->node[loop] = ntohl(b[loop + 5]); |
481 | |
482 | call->offset = 0; |
483 | call->unmarshall++; |
484 | |
485 | case 2: |
486 | _debug("trailer"); |
487 | if (skb->len != 0) |
488 | return -EBADMSG; |
489 | break; |
490 | } |
491 | |
492 | if (!last) |
493 | return 0; |
494 | |
495 | call->state = AFS_CALL_REPLYING; |
496 | |
497 | INIT_WORK(&call->work, SRXAFSCB_ProbeUuid); |
498 | schedule_work(&call->work); |
499 | return 0; |
500 | } |
501 | |
502 | /* |
503 | * allow the fileserver to ask about the cache manager's capabilities |
504 | */ |
505 | static void SRXAFSCB_TellMeAboutYourself(struct work_struct *work) |
506 | { |
507 | struct afs_interface *ifs; |
508 | struct afs_call *call = container_of(work, struct afs_call, work); |
509 | int loop, nifs; |
510 | |
511 | struct { |
512 | struct /* InterfaceAddr */ { |
513 | __be32 nifs; |
514 | __be32 uuid[11]; |
515 | __be32 ifaddr[32]; |
516 | __be32 netmask[32]; |
517 | __be32 mtu[32]; |
518 | } ia; |
519 | struct /* Capabilities */ { |
520 | __be32 capcount; |
521 | __be32 caps[1]; |
522 | } cap; |
523 | } reply; |
524 | |
525 | _enter(""); |
526 | |
527 | nifs = 0; |
528 | ifs = kcalloc(32, sizeof(*ifs), GFP_KERNEL); |
529 | if (ifs) { |
530 | nifs = afs_get_ipv4_interfaces(ifs, 32, false); |
531 | if (nifs < 0) { |
532 | kfree(ifs); |
533 | ifs = NULL; |
534 | nifs = 0; |
535 | } |
536 | } |
537 | |
538 | memset(&reply, 0, sizeof(reply)); |
539 | reply.ia.nifs = htonl(nifs); |
540 | |
541 | reply.ia.uuid[0] = htonl(afs_uuid.time_low); |
542 | reply.ia.uuid[1] = htonl(afs_uuid.time_mid); |
543 | reply.ia.uuid[2] = htonl(afs_uuid.time_hi_and_version); |
544 | reply.ia.uuid[3] = htonl((s8) afs_uuid.clock_seq_hi_and_reserved); |
545 | reply.ia.uuid[4] = htonl((s8) afs_uuid.clock_seq_low); |
546 | for (loop = 0; loop < 6; loop++) |
547 | reply.ia.uuid[loop + 5] = htonl((s8) afs_uuid.node[loop]); |
548 | |
549 | if (ifs) { |
550 | for (loop = 0; loop < nifs; loop++) { |
551 | reply.ia.ifaddr[loop] = ifs[loop].address.s_addr; |
552 | reply.ia.netmask[loop] = ifs[loop].netmask.s_addr; |
553 | reply.ia.mtu[loop] = htonl(ifs[loop].mtu); |
554 | } |
555 | kfree(ifs); |
556 | } |
557 | |
558 | reply.cap.capcount = htonl(1); |
559 | reply.cap.caps[0] = htonl(AFS_CAP_ERROR_TRANSLATION); |
560 | afs_send_simple_reply(call, &reply, sizeof(reply)); |
561 | |
562 | _leave(""); |
563 | } |
564 | |
565 | /* |
566 | * deliver request data to a CB.TellMeAboutYourself call |
567 | */ |
568 | static int afs_deliver_cb_tell_me_about_yourself(struct afs_call *call, |
569 | struct sk_buff *skb, bool last) |
570 | { |
571 | _enter(",{%u},%d", skb->len, last); |
572 | |
573 | if (skb->len > 0) |
574 | return -EBADMSG; |
575 | if (!last) |
576 | return 0; |
577 | |
578 | /* no unmarshalling required */ |
579 | call->state = AFS_CALL_REPLYING; |
580 | |
581 | INIT_WORK(&call->work, SRXAFSCB_TellMeAboutYourself); |
582 | schedule_work(&call->work); |
583 | return 0; |
584 | } |
585 |
Branches:
ben-wpan
ben-wpan-stefan
javiroman/ks7010
jz-2.6.34
jz-2.6.34-rc5
jz-2.6.34-rc6
jz-2.6.34-rc7
jz-2.6.35
jz-2.6.36
jz-2.6.37
jz-2.6.38
jz-2.6.39
jz-3.0
jz-3.1
jz-3.11
jz-3.12
jz-3.13
jz-3.15
jz-3.16
jz-3.18-dt
jz-3.2
jz-3.3
jz-3.4
jz-3.5
jz-3.6
jz-3.6-rc2-pwm
jz-3.9
jz-3.9-clk
jz-3.9-rc8
jz47xx
jz47xx-2.6.38
master
Tags:
od-2011-09-04
od-2011-09-18
v2.6.34-rc5
v2.6.34-rc6
v2.6.34-rc7
v3.9