]>
Commit | Line | Data |
---|---|---|
ec26815a | 1 | /* AFS Cache Manager Service |
1da177e4 LT |
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> | |
08e0e7c8 | 15 | #include <linux/ip.h> |
1da177e4 | 16 | #include "internal.h" |
08e0e7c8 | 17 | #include "afs_cm.h" |
1da177e4 | 18 | |
c1206a2c | 19 | #if 0 |
08e0e7c8 | 20 | struct workqueue_struct *afs_cm_workqueue; |
c1206a2c | 21 | #endif /* 0 */ |
1da177e4 | 22 | |
08e0e7c8 DH |
23 | static int afs_deliver_cb_init_call_back_state(struct afs_call *, |
24 | struct sk_buff *, bool); | |
c35eccb1 DH |
25 | static int afs_deliver_cb_init_call_back_state3(struct afs_call *, |
26 | struct sk_buff *, bool); | |
08e0e7c8 DH |
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); | |
b908fe6b DH |
29 | static int afs_deliver_cb_get_capabilities(struct afs_call *, struct sk_buff *, |
30 | bool); | |
08e0e7c8 | 31 | static void afs_cm_destructor(struct afs_call *); |
1da177e4 | 32 | |
1da177e4 | 33 | /* |
08e0e7c8 | 34 | * CB.CallBack operation type |
1da177e4 | 35 | */ |
08e0e7c8 | 36 | static const struct afs_call_type afs_SRXCBCallBack = { |
00d3b7a4 | 37 | .name = "CB.CallBack", |
08e0e7c8 DH |
38 | .deliver = afs_deliver_cb_callback, |
39 | .abort_to_error = afs_abort_to_error, | |
40 | .destructor = afs_cm_destructor, | |
41 | }; | |
1da177e4 | 42 | |
1da177e4 | 43 | /* |
08e0e7c8 | 44 | * CB.InitCallBackState operation type |
1da177e4 | 45 | */ |
08e0e7c8 | 46 | static const struct afs_call_type afs_SRXCBInitCallBackState = { |
00d3b7a4 | 47 | .name = "CB.InitCallBackState", |
08e0e7c8 DH |
48 | .deliver = afs_deliver_cb_init_call_back_state, |
49 | .abort_to_error = afs_abort_to_error, | |
50 | .destructor = afs_cm_destructor, | |
51 | }; | |
1da177e4 | 52 | |
c35eccb1 DH |
53 | /* |
54 | * CB.InitCallBackState3 operation type | |
55 | */ | |
56 | static const struct afs_call_type afs_SRXCBInitCallBackState3 = { | |
57 | .name = "CB.InitCallBackState3", | |
58 | .deliver = afs_deliver_cb_init_call_back_state3, | |
59 | .abort_to_error = afs_abort_to_error, | |
60 | .destructor = afs_cm_destructor, | |
61 | }; | |
62 | ||
1da177e4 | 63 | /* |
08e0e7c8 | 64 | * CB.Probe operation type |
1da177e4 | 65 | */ |
08e0e7c8 | 66 | static const struct afs_call_type afs_SRXCBProbe = { |
00d3b7a4 | 67 | .name = "CB.Probe", |
08e0e7c8 DH |
68 | .deliver = afs_deliver_cb_probe, |
69 | .abort_to_error = afs_abort_to_error, | |
70 | .destructor = afs_cm_destructor, | |
71 | }; | |
1da177e4 | 72 | |
b908fe6b DH |
73 | /* |
74 | * CB.GetCapabilities operation type | |
75 | */ | |
76 | static const struct afs_call_type afs_SRXCBGetCapabilites = { | |
77 | .name = "CB.GetCapabilities", | |
78 | .deliver = afs_deliver_cb_get_capabilities, | |
79 | .abort_to_error = afs_abort_to_error, | |
80 | .destructor = afs_cm_destructor, | |
81 | }; | |
82 | ||
1da177e4 | 83 | /* |
08e0e7c8 DH |
84 | * route an incoming cache manager call |
85 | * - return T if supported, F if not | |
1da177e4 | 86 | */ |
08e0e7c8 | 87 | bool afs_cm_incoming_call(struct afs_call *call) |
1da177e4 | 88 | { |
08e0e7c8 DH |
89 | u32 operation_id = ntohl(call->operation_ID); |
90 | ||
91 | _enter("{CB.OP %u}", operation_id); | |
92 | ||
93 | switch (operation_id) { | |
94 | case CBCallBack: | |
95 | call->type = &afs_SRXCBCallBack; | |
96 | return true; | |
97 | case CBInitCallBackState: | |
98 | call->type = &afs_SRXCBInitCallBackState; | |
99 | return true; | |
c35eccb1 DH |
100 | case CBInitCallBackState3: |
101 | call->type = &afs_SRXCBInitCallBackState3; | |
102 | return true; | |
08e0e7c8 DH |
103 | case CBProbe: |
104 | call->type = &afs_SRXCBProbe; | |
105 | return true; | |
b908fe6b DH |
106 | case CBGetCapabilities: |
107 | call->type = &afs_SRXCBGetCapabilites; | |
108 | return true; | |
08e0e7c8 DH |
109 | default: |
110 | return false; | |
1da177e4 | 111 | } |
ec26815a | 112 | } |
1da177e4 | 113 | |
1da177e4 | 114 | /* |
08e0e7c8 | 115 | * clean up a cache manager call |
1da177e4 | 116 | */ |
08e0e7c8 | 117 | static void afs_cm_destructor(struct afs_call *call) |
1da177e4 | 118 | { |
08e0e7c8 DH |
119 | _enter(""); |
120 | ||
121 | afs_put_server(call->server); | |
122 | call->server = NULL; | |
123 | kfree(call->buffer); | |
124 | call->buffer = NULL; | |
ec26815a | 125 | } |
1da177e4 | 126 | |
1da177e4 | 127 | /* |
08e0e7c8 | 128 | * allow the fileserver to see if the cache manager is still alive |
1da177e4 | 129 | */ |
08e0e7c8 | 130 | static void SRXAFSCB_CallBack(struct work_struct *work) |
1da177e4 | 131 | { |
08e0e7c8 | 132 | struct afs_call *call = container_of(work, struct afs_call, work); |
1da177e4 | 133 | |
08e0e7c8 | 134 | _enter(""); |
1da177e4 | 135 | |
08e0e7c8 DH |
136 | /* be sure to send the reply *before* attempting to spam the AFS server |
137 | * with FSFetchStatus requests on the vnodes with broken callbacks lest | |
138 | * the AFS server get into a vicious cycle of trying to break further | |
139 | * callbacks because it hadn't received completion of the CBCallBack op | |
140 | * yet */ | |
141 | afs_send_empty_reply(call); | |
1da177e4 | 142 | |
08e0e7c8 DH |
143 | afs_break_callbacks(call->server, call->count, call->request); |
144 | _leave(""); | |
ec26815a | 145 | } |
1da177e4 | 146 | |
1da177e4 | 147 | /* |
08e0e7c8 | 148 | * deliver request data to a CB.CallBack call |
1da177e4 | 149 | */ |
08e0e7c8 DH |
150 | static int afs_deliver_cb_callback(struct afs_call *call, struct sk_buff *skb, |
151 | bool last) | |
1da177e4 | 152 | { |
08e0e7c8 DH |
153 | struct afs_callback *cb; |
154 | struct afs_server *server; | |
155 | struct in_addr addr; | |
156 | __be32 *bp; | |
157 | u32 tmp; | |
158 | int ret, loop; | |
159 | ||
160 | _enter("{%u},{%u},%d", call->unmarshall, skb->len, last); | |
161 | ||
162 | switch (call->unmarshall) { | |
163 | case 0: | |
164 | call->offset = 0; | |
165 | call->unmarshall++; | |
166 | ||
167 | /* extract the FID array and its count in two steps */ | |
168 | case 1: | |
169 | _debug("extract FID count"); | |
170 | ret = afs_extract_data(call, skb, last, &call->tmp, 4); | |
171 | switch (ret) { | |
172 | case 0: break; | |
173 | case -EAGAIN: return 0; | |
174 | default: return ret; | |
1da177e4 | 175 | } |
1da177e4 | 176 | |
08e0e7c8 DH |
177 | call->count = ntohl(call->tmp); |
178 | _debug("FID count: %u", call->count); | |
179 | if (call->count > AFSCBMAX) | |
180 | return -EBADMSG; | |
181 | ||
182 | call->buffer = kmalloc(call->count * 3 * 4, GFP_KERNEL); | |
183 | if (!call->buffer) | |
184 | return -ENOMEM; | |
185 | call->offset = 0; | |
186 | call->unmarshall++; | |
187 | ||
188 | case 2: | |
189 | _debug("extract FID array"); | |
190 | ret = afs_extract_data(call, skb, last, call->buffer, | |
191 | call->count * 3 * 4); | |
192 | switch (ret) { | |
193 | case 0: break; | |
194 | case -EAGAIN: return 0; | |
195 | default: return ret; | |
1da177e4 | 196 | } |
1da177e4 | 197 | |
08e0e7c8 DH |
198 | _debug("unmarshall FID array"); |
199 | call->request = kcalloc(call->count, | |
200 | sizeof(struct afs_callback), | |
201 | GFP_KERNEL); | |
202 | if (!call->request) | |
203 | return -ENOMEM; | |
204 | ||
205 | cb = call->request; | |
206 | bp = call->buffer; | |
207 | for (loop = call->count; loop > 0; loop--, cb++) { | |
208 | cb->fid.vid = ntohl(*bp++); | |
209 | cb->fid.vnode = ntohl(*bp++); | |
210 | cb->fid.unique = ntohl(*bp++); | |
211 | cb->type = AFSCM_CB_UNTYPED; | |
1da177e4 LT |
212 | } |
213 | ||
08e0e7c8 DH |
214 | call->offset = 0; |
215 | call->unmarshall++; | |
216 | ||
217 | /* extract the callback array and its count in two steps */ | |
218 | case 3: | |
219 | _debug("extract CB count"); | |
220 | ret = afs_extract_data(call, skb, last, &call->tmp, 4); | |
221 | switch (ret) { | |
222 | case 0: break; | |
223 | case -EAGAIN: return 0; | |
224 | default: return ret; | |
225 | } | |
1da177e4 | 226 | |
08e0e7c8 DH |
227 | tmp = ntohl(call->tmp); |
228 | _debug("CB count: %u", tmp); | |
229 | if (tmp != call->count && tmp != 0) | |
230 | return -EBADMSG; | |
231 | call->offset = 0; | |
232 | call->unmarshall++; | |
233 | if (tmp == 0) | |
234 | goto empty_cb_array; | |
235 | ||
236 | case 4: | |
237 | _debug("extract CB array"); | |
238 | ret = afs_extract_data(call, skb, last, call->request, | |
239 | call->count * 3 * 4); | |
240 | switch (ret) { | |
241 | case 0: break; | |
242 | case -EAGAIN: return 0; | |
243 | default: return ret; | |
1da177e4 | 244 | } |
1da177e4 | 245 | |
08e0e7c8 DH |
246 | _debug("unmarshall CB array"); |
247 | cb = call->request; | |
248 | bp = call->buffer; | |
249 | for (loop = call->count; loop > 0; loop--, cb++) { | |
250 | cb->version = ntohl(*bp++); | |
251 | cb->expiry = ntohl(*bp++); | |
252 | cb->type = ntohl(*bp++); | |
253 | } | |
1da177e4 | 254 | |
08e0e7c8 DH |
255 | empty_cb_array: |
256 | call->offset = 0; | |
257 | call->unmarshall++; | |
1da177e4 | 258 | |
08e0e7c8 DH |
259 | case 5: |
260 | _debug("trailer"); | |
261 | if (skb->len != 0) | |
262 | return -EBADMSG; | |
1da177e4 LT |
263 | break; |
264 | } | |
265 | ||
08e0e7c8 DH |
266 | if (!last) |
267 | return 0; | |
1da177e4 | 268 | |
08e0e7c8 | 269 | call->state = AFS_CALL_REPLYING; |
1da177e4 | 270 | |
08e0e7c8 DH |
271 | /* we'll need the file server record as that tells us which set of |
272 | * vnodes to operate upon */ | |
273 | memcpy(&addr, &ip_hdr(skb)->saddr, 4); | |
274 | server = afs_find_server(&addr); | |
275 | if (!server) | |
276 | return -ENOTCONN; | |
277 | call->server = server; | |
278 | ||
279 | INIT_WORK(&call->work, SRXAFSCB_CallBack); | |
280 | schedule_work(&call->work); | |
281 | return 0; | |
ec26815a | 282 | } |
1da177e4 | 283 | |
1da177e4 | 284 | /* |
08e0e7c8 | 285 | * allow the fileserver to request callback state (re-)initialisation |
1da177e4 | 286 | */ |
08e0e7c8 | 287 | static void SRXAFSCB_InitCallBackState(struct work_struct *work) |
1da177e4 | 288 | { |
08e0e7c8 | 289 | struct afs_call *call = container_of(work, struct afs_call, work); |
1da177e4 | 290 | |
08e0e7c8 | 291 | _enter("{%p}", call->server); |
1da177e4 | 292 | |
08e0e7c8 DH |
293 | afs_init_callback_state(call->server); |
294 | afs_send_empty_reply(call); | |
295 | _leave(""); | |
ec26815a | 296 | } |
1da177e4 | 297 | |
1da177e4 | 298 | /* |
08e0e7c8 | 299 | * deliver request data to a CB.InitCallBackState call |
1da177e4 | 300 | */ |
08e0e7c8 DH |
301 | static int afs_deliver_cb_init_call_back_state(struct afs_call *call, |
302 | struct sk_buff *skb, | |
303 | bool last) | |
1da177e4 LT |
304 | { |
305 | struct afs_server *server; | |
08e0e7c8 | 306 | struct in_addr addr; |
1da177e4 | 307 | |
08e0e7c8 | 308 | _enter(",{%u},%d", skb->len, last); |
1da177e4 | 309 | |
08e0e7c8 DH |
310 | if (skb->len > 0) |
311 | return -EBADMSG; | |
312 | if (!last) | |
313 | return 0; | |
1da177e4 | 314 | |
08e0e7c8 DH |
315 | /* no unmarshalling required */ |
316 | call->state = AFS_CALL_REPLYING; | |
1da177e4 | 317 | |
08e0e7c8 DH |
318 | /* we'll need the file server record as that tells us which set of |
319 | * vnodes to operate upon */ | |
320 | memcpy(&addr, &ip_hdr(skb)->saddr, 4); | |
321 | server = afs_find_server(&addr); | |
322 | if (!server) | |
323 | return -ENOTCONN; | |
324 | call->server = server; | |
1da177e4 | 325 | |
08e0e7c8 DH |
326 | INIT_WORK(&call->work, SRXAFSCB_InitCallBackState); |
327 | schedule_work(&call->work); | |
328 | return 0; | |
329 | } | |
1da177e4 | 330 | |
c35eccb1 DH |
331 | /* |
332 | * deliver request data to a CB.InitCallBackState3 call | |
333 | */ | |
334 | static int afs_deliver_cb_init_call_back_state3(struct afs_call *call, | |
335 | struct sk_buff *skb, | |
336 | bool last) | |
337 | { | |
338 | struct afs_server *server; | |
339 | struct in_addr addr; | |
340 | ||
341 | _enter(",{%u},%d", skb->len, last); | |
342 | ||
343 | if (!last) | |
344 | return 0; | |
345 | ||
346 | /* no unmarshalling required */ | |
347 | call->state = AFS_CALL_REPLYING; | |
348 | ||
349 | /* we'll need the file server record as that tells us which set of | |
350 | * vnodes to operate upon */ | |
351 | memcpy(&addr, &ip_hdr(skb)->saddr, 4); | |
352 | server = afs_find_server(&addr); | |
353 | if (!server) | |
354 | return -ENOTCONN; | |
355 | call->server = server; | |
356 | ||
357 | INIT_WORK(&call->work, SRXAFSCB_InitCallBackState); | |
358 | schedule_work(&call->work); | |
359 | return 0; | |
360 | } | |
361 | ||
08e0e7c8 DH |
362 | /* |
363 | * allow the fileserver to see if the cache manager is still alive | |
364 | */ | |
365 | static void SRXAFSCB_Probe(struct work_struct *work) | |
366 | { | |
367 | struct afs_call *call = container_of(work, struct afs_call, work); | |
1da177e4 | 368 | |
08e0e7c8 DH |
369 | _enter(""); |
370 | afs_send_empty_reply(call); | |
371 | _leave(""); | |
372 | } | |
1da177e4 | 373 | |
08e0e7c8 DH |
374 | /* |
375 | * deliver request data to a CB.Probe call | |
376 | */ | |
377 | static int afs_deliver_cb_probe(struct afs_call *call, struct sk_buff *skb, | |
378 | bool last) | |
379 | { | |
380 | _enter(",{%u},%d", skb->len, last); | |
1da177e4 | 381 | |
08e0e7c8 DH |
382 | if (skb->len > 0) |
383 | return -EBADMSG; | |
384 | if (!last) | |
385 | return 0; | |
1da177e4 | 386 | |
08e0e7c8 DH |
387 | /* no unmarshalling required */ |
388 | call->state = AFS_CALL_REPLYING; | |
1da177e4 | 389 | |
08e0e7c8 DH |
390 | INIT_WORK(&call->work, SRXAFSCB_Probe); |
391 | schedule_work(&call->work); | |
392 | return 0; | |
ec26815a | 393 | } |
b908fe6b DH |
394 | |
395 | /* | |
396 | * allow the fileserver to ask about the cache manager's capabilities | |
397 | */ | |
398 | static void SRXAFSCB_GetCapabilities(struct work_struct *work) | |
399 | { | |
400 | struct afs_interface *ifs; | |
401 | struct afs_call *call = container_of(work, struct afs_call, work); | |
402 | int loop, nifs; | |
403 | ||
404 | struct { | |
405 | struct /* InterfaceAddr */ { | |
406 | __be32 nifs; | |
407 | __be32 uuid[11]; | |
408 | __be32 ifaddr[32]; | |
409 | __be32 netmask[32]; | |
410 | __be32 mtu[32]; | |
411 | } ia; | |
412 | struct /* Capabilities */ { | |
413 | __be32 capcount; | |
414 | __be32 caps[1]; | |
415 | } cap; | |
416 | } reply; | |
417 | ||
418 | _enter(""); | |
419 | ||
420 | nifs = 0; | |
421 | ifs = kcalloc(32, sizeof(*ifs), GFP_KERNEL); | |
422 | if (ifs) { | |
423 | nifs = afs_get_ipv4_interfaces(ifs, 32, false); | |
424 | if (nifs < 0) { | |
425 | kfree(ifs); | |
426 | ifs = NULL; | |
427 | nifs = 0; | |
428 | } | |
429 | } | |
430 | ||
431 | memset(&reply, 0, sizeof(reply)); | |
432 | reply.ia.nifs = htonl(nifs); | |
433 | ||
434 | reply.ia.uuid[0] = htonl(afs_uuid.time_low); | |
435 | reply.ia.uuid[1] = htonl(afs_uuid.time_mid); | |
436 | reply.ia.uuid[2] = htonl(afs_uuid.time_hi_and_version); | |
437 | reply.ia.uuid[3] = htonl((s8) afs_uuid.clock_seq_hi_and_reserved); | |
438 | reply.ia.uuid[4] = htonl((s8) afs_uuid.clock_seq_low); | |
439 | for (loop = 0; loop < 6; loop++) | |
440 | reply.ia.uuid[loop + 5] = htonl((s8) afs_uuid.node[loop]); | |
441 | ||
442 | if (ifs) { | |
443 | for (loop = 0; loop < nifs; loop++) { | |
444 | reply.ia.ifaddr[loop] = ifs[loop].address.s_addr; | |
445 | reply.ia.netmask[loop] = ifs[loop].netmask.s_addr; | |
446 | reply.ia.mtu[loop] = htonl(ifs[loop].mtu); | |
447 | } | |
5b35fad9 | 448 | kfree(ifs); |
b908fe6b DH |
449 | } |
450 | ||
451 | reply.cap.capcount = htonl(1); | |
452 | reply.cap.caps[0] = htonl(AFS_CAP_ERROR_TRANSLATION); | |
453 | afs_send_simple_reply(call, &reply, sizeof(reply)); | |
454 | ||
455 | _leave(""); | |
456 | } | |
457 | ||
458 | /* | |
459 | * deliver request data to a CB.GetCapabilities call | |
460 | */ | |
461 | static int afs_deliver_cb_get_capabilities(struct afs_call *call, | |
462 | struct sk_buff *skb, bool last) | |
463 | { | |
464 | _enter(",{%u},%d", skb->len, last); | |
465 | ||
466 | if (skb->len > 0) | |
467 | return -EBADMSG; | |
468 | if (!last) | |
469 | return 0; | |
470 | ||
471 | /* no unmarshalling required */ | |
472 | call->state = AFS_CALL_REPLYING; | |
473 | ||
474 | INIT_WORK(&call->work, SRXAFSCB_GetCapabilities); | |
475 | schedule_work(&call->work); | |
476 | return 0; | |
477 | } |