diff options
Diffstat (limited to 'fs/afs/cmservice.c')
-rw-r--r-- | fs/afs/cmservice.c | 98 |
1 files changed, 98 insertions, 0 deletions
diff --git a/fs/afs/cmservice.c b/fs/afs/cmservice.c index c3ec57a237bf..a6af3acf016e 100644 --- a/fs/afs/cmservice.c +++ b/fs/afs/cmservice.c | |||
@@ -22,6 +22,8 @@ static int afs_deliver_cb_init_call_back_state(struct afs_call *, | |||
22 | struct sk_buff *, bool); | 22 | struct sk_buff *, bool); |
23 | static int afs_deliver_cb_probe(struct afs_call *, struct sk_buff *, bool); | 23 | static int afs_deliver_cb_probe(struct afs_call *, struct sk_buff *, bool); |
24 | static int afs_deliver_cb_callback(struct afs_call *, struct sk_buff *, bool); | 24 | static int afs_deliver_cb_callback(struct afs_call *, struct sk_buff *, bool); |
25 | static int afs_deliver_cb_get_capabilities(struct afs_call *, struct sk_buff *, | ||
26 | bool); | ||
25 | static void afs_cm_destructor(struct afs_call *); | 27 | static void afs_cm_destructor(struct afs_call *); |
26 | 28 | ||
27 | /* | 29 | /* |
@@ -55,6 +57,16 @@ static const struct afs_call_type afs_SRXCBProbe = { | |||
55 | }; | 57 | }; |
56 | 58 | ||
57 | /* | 59 | /* |
60 | * CB.GetCapabilities operation type | ||
61 | */ | ||
62 | static const struct afs_call_type afs_SRXCBGetCapabilites = { | ||
63 | .name = "CB.GetCapabilities", | ||
64 | .deliver = afs_deliver_cb_get_capabilities, | ||
65 | .abort_to_error = afs_abort_to_error, | ||
66 | .destructor = afs_cm_destructor, | ||
67 | }; | ||
68 | |||
69 | /* | ||
58 | * route an incoming cache manager call | 70 | * route an incoming cache manager call |
59 | * - return T if supported, F if not | 71 | * - return T if supported, F if not |
60 | */ | 72 | */ |
@@ -74,6 +86,9 @@ bool afs_cm_incoming_call(struct afs_call *call) | |||
74 | case CBProbe: | 86 | case CBProbe: |
75 | call->type = &afs_SRXCBProbe; | 87 | call->type = &afs_SRXCBProbe; |
76 | return true; | 88 | return true; |
89 | case CBGetCapabilities: | ||
90 | call->type = &afs_SRXCBGetCapabilites; | ||
91 | return true; | ||
77 | default: | 92 | default: |
78 | return false; | 93 | return false; |
79 | } | 94 | } |
@@ -328,3 +343,86 @@ static int afs_deliver_cb_probe(struct afs_call *call, struct sk_buff *skb, | |||
328 | schedule_work(&call->work); | 343 | schedule_work(&call->work); |
329 | return 0; | 344 | return 0; |
330 | } | 345 | } |
346 | |||
347 | /* | ||
348 | * allow the fileserver to ask about the cache manager's capabilities | ||
349 | */ | ||
350 | static void SRXAFSCB_GetCapabilities(struct work_struct *work) | ||
351 | { | ||
352 | struct afs_interface *ifs; | ||
353 | struct afs_call *call = container_of(work, struct afs_call, work); | ||
354 | int loop, nifs; | ||
355 | |||
356 | struct { | ||
357 | struct /* InterfaceAddr */ { | ||
358 | __be32 nifs; | ||
359 | __be32 uuid[11]; | ||
360 | __be32 ifaddr[32]; | ||
361 | __be32 netmask[32]; | ||
362 | __be32 mtu[32]; | ||
363 | } ia; | ||
364 | struct /* Capabilities */ { | ||
365 | __be32 capcount; | ||
366 | __be32 caps[1]; | ||
367 | } cap; | ||
368 | } reply; | ||
369 | |||
370 | _enter(""); | ||
371 | |||
372 | nifs = 0; | ||
373 | ifs = kcalloc(32, sizeof(*ifs), GFP_KERNEL); | ||
374 | if (ifs) { | ||
375 | nifs = afs_get_ipv4_interfaces(ifs, 32, false); | ||
376 | if (nifs < 0) { | ||
377 | kfree(ifs); | ||
378 | ifs = NULL; | ||
379 | nifs = 0; | ||
380 | } | ||
381 | } | ||
382 | |||
383 | memset(&reply, 0, sizeof(reply)); | ||
384 | reply.ia.nifs = htonl(nifs); | ||
385 | |||
386 | reply.ia.uuid[0] = htonl(afs_uuid.time_low); | ||
387 | reply.ia.uuid[1] = htonl(afs_uuid.time_mid); | ||
388 | reply.ia.uuid[2] = htonl(afs_uuid.time_hi_and_version); | ||
389 | reply.ia.uuid[3] = htonl((s8) afs_uuid.clock_seq_hi_and_reserved); | ||
390 | reply.ia.uuid[4] = htonl((s8) afs_uuid.clock_seq_low); | ||
391 | for (loop = 0; loop < 6; loop++) | ||
392 | reply.ia.uuid[loop + 5] = htonl((s8) afs_uuid.node[loop]); | ||
393 | |||
394 | if (ifs) { | ||
395 | for (loop = 0; loop < nifs; loop++) { | ||
396 | reply.ia.ifaddr[loop] = ifs[loop].address.s_addr; | ||
397 | reply.ia.netmask[loop] = ifs[loop].netmask.s_addr; | ||
398 | reply.ia.mtu[loop] = htonl(ifs[loop].mtu); | ||
399 | } | ||
400 | } | ||
401 | |||
402 | reply.cap.capcount = htonl(1); | ||
403 | reply.cap.caps[0] = htonl(AFS_CAP_ERROR_TRANSLATION); | ||
404 | afs_send_simple_reply(call, &reply, sizeof(reply)); | ||
405 | |||
406 | _leave(""); | ||
407 | } | ||
408 | |||
409 | /* | ||
410 | * deliver request data to a CB.GetCapabilities call | ||
411 | */ | ||
412 | static int afs_deliver_cb_get_capabilities(struct afs_call *call, | ||
413 | struct sk_buff *skb, bool last) | ||
414 | { | ||
415 | _enter(",{%u},%d", skb->len, last); | ||
416 | |||
417 | if (skb->len > 0) | ||
418 | return -EBADMSG; | ||
419 | if (!last) | ||
420 | return 0; | ||
421 | |||
422 | /* no unmarshalling required */ | ||
423 | call->state = AFS_CALL_REPLYING; | ||
424 | |||
425 | INIT_WORK(&call->work, SRXAFSCB_GetCapabilities); | ||
426 | schedule_work(&call->work); | ||
427 | return 0; | ||
428 | } | ||