[AFS]: Add support for the CB.GetCapabilities operation.
[linux-2.6/kmemtrace.git] / fs / afs / cmservice.c
bloba6af3acf016e9984b0fad7de1a658112287bf57c
1 /* AFS Cache Manager Service
3 * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
4 * Written by David Howells (dhowells@redhat.com)
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.
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"
19 struct workqueue_struct *afs_cm_workqueue;
21 static int afs_deliver_cb_init_call_back_state(struct afs_call *,
22 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);
25 static int afs_deliver_cb_get_capabilities(struct afs_call *, struct sk_buff *,
26 bool);
27 static void afs_cm_destructor(struct afs_call *);
30 * CB.CallBack operation type
32 static const struct afs_call_type afs_SRXCBCallBack = {
33 .name = "CB.CallBack",
34 .deliver = afs_deliver_cb_callback,
35 .abort_to_error = afs_abort_to_error,
36 .destructor = afs_cm_destructor,
40 * CB.InitCallBackState operation type
42 static const struct afs_call_type afs_SRXCBInitCallBackState = {
43 .name = "CB.InitCallBackState",
44 .deliver = afs_deliver_cb_init_call_back_state,
45 .abort_to_error = afs_abort_to_error,
46 .destructor = afs_cm_destructor,
50 * CB.Probe operation type
52 static const struct afs_call_type afs_SRXCBProbe = {
53 .name = "CB.Probe",
54 .deliver = afs_deliver_cb_probe,
55 .abort_to_error = afs_abort_to_error,
56 .destructor = afs_cm_destructor,
60 * CB.GetCapabilities operation type
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,
70 * route an incoming cache manager call
71 * - return T if supported, F if not
73 bool afs_cm_incoming_call(struct afs_call *call)
75 u32 operation_id = ntohl(call->operation_ID);
77 _enter("{CB.OP %u}", operation_id);
79 switch (operation_id) {
80 case CBCallBack:
81 call->type = &afs_SRXCBCallBack;
82 return true;
83 case CBInitCallBackState:
84 call->type = &afs_SRXCBInitCallBackState;
85 return true;
86 case CBProbe:
87 call->type = &afs_SRXCBProbe;
88 return true;
89 case CBGetCapabilities:
90 call->type = &afs_SRXCBGetCapabilites;
91 return true;
92 default:
93 return false;
98 * clean up a cache manager call
100 static void afs_cm_destructor(struct afs_call *call)
102 _enter("");
104 afs_put_server(call->server);
105 call->server = NULL;
106 kfree(call->buffer);
107 call->buffer = NULL;
111 * allow the fileserver to see if the cache manager is still alive
113 static void SRXAFSCB_CallBack(struct work_struct *work)
115 struct afs_call *call = container_of(work, struct afs_call, work);
117 _enter("");
119 /* be sure to send the reply *before* attempting to spam the AFS server
120 * with FSFetchStatus requests on the vnodes with broken callbacks lest
121 * the AFS server get into a vicious cycle of trying to break further
122 * callbacks because it hadn't received completion of the CBCallBack op
123 * yet */
124 afs_send_empty_reply(call);
126 afs_break_callbacks(call->server, call->count, call->request);
127 _leave("");
131 * deliver request data to a CB.CallBack call
133 static int afs_deliver_cb_callback(struct afs_call *call, struct sk_buff *skb,
134 bool last)
136 struct afs_callback *cb;
137 struct afs_server *server;
138 struct in_addr addr;
139 __be32 *bp;
140 u32 tmp;
141 int ret, loop;
143 _enter("{%u},{%u},%d", call->unmarshall, skb->len, last);
145 switch (call->unmarshall) {
146 case 0:
147 call->offset = 0;
148 call->unmarshall++;
150 /* extract the FID array and its count in two steps */
151 case 1:
152 _debug("extract FID count");
153 ret = afs_extract_data(call, skb, last, &call->tmp, 4);
154 switch (ret) {
155 case 0: break;
156 case -EAGAIN: return 0;
157 default: return ret;
160 call->count = ntohl(call->tmp);
161 _debug("FID count: %u", call->count);
162 if (call->count > AFSCBMAX)
163 return -EBADMSG;
165 call->buffer = kmalloc(call->count * 3 * 4, GFP_KERNEL);
166 if (!call->buffer)
167 return -ENOMEM;
168 call->offset = 0;
169 call->unmarshall++;
171 case 2:
172 _debug("extract FID array");
173 ret = afs_extract_data(call, skb, last, call->buffer,
174 call->count * 3 * 4);
175 switch (ret) {
176 case 0: break;
177 case -EAGAIN: return 0;
178 default: return ret;
181 _debug("unmarshall FID array");
182 call->request = kcalloc(call->count,
183 sizeof(struct afs_callback),
184 GFP_KERNEL);
185 if (!call->request)
186 return -ENOMEM;
188 cb = call->request;
189 bp = call->buffer;
190 for (loop = call->count; loop > 0; loop--, cb++) {
191 cb->fid.vid = ntohl(*bp++);
192 cb->fid.vnode = ntohl(*bp++);
193 cb->fid.unique = ntohl(*bp++);
194 cb->type = AFSCM_CB_UNTYPED;
197 call->offset = 0;
198 call->unmarshall++;
200 /* extract the callback array and its count in two steps */
201 case 3:
202 _debug("extract CB count");
203 ret = afs_extract_data(call, skb, last, &call->tmp, 4);
204 switch (ret) {
205 case 0: break;
206 case -EAGAIN: return 0;
207 default: return ret;
210 tmp = ntohl(call->tmp);
211 _debug("CB count: %u", tmp);
212 if (tmp != call->count && tmp != 0)
213 return -EBADMSG;
214 call->offset = 0;
215 call->unmarshall++;
216 if (tmp == 0)
217 goto empty_cb_array;
219 case 4:
220 _debug("extract CB array");
221 ret = afs_extract_data(call, skb, last, call->request,
222 call->count * 3 * 4);
223 switch (ret) {
224 case 0: break;
225 case -EAGAIN: return 0;
226 default: return ret;
229 _debug("unmarshall CB array");
230 cb = call->request;
231 bp = call->buffer;
232 for (loop = call->count; loop > 0; loop--, cb++) {
233 cb->version = ntohl(*bp++);
234 cb->expiry = ntohl(*bp++);
235 cb->type = ntohl(*bp++);
238 empty_cb_array:
239 call->offset = 0;
240 call->unmarshall++;
242 case 5:
243 _debug("trailer");
244 if (skb->len != 0)
245 return -EBADMSG;
246 break;
249 if (!last)
250 return 0;
252 call->state = AFS_CALL_REPLYING;
254 /* we'll need the file server record as that tells us which set of
255 * vnodes to operate upon */
256 memcpy(&addr, &ip_hdr(skb)->saddr, 4);
257 server = afs_find_server(&addr);
258 if (!server)
259 return -ENOTCONN;
260 call->server = server;
262 INIT_WORK(&call->work, SRXAFSCB_CallBack);
263 schedule_work(&call->work);
264 return 0;
268 * allow the fileserver to request callback state (re-)initialisation
270 static void SRXAFSCB_InitCallBackState(struct work_struct *work)
272 struct afs_call *call = container_of(work, struct afs_call, work);
274 _enter("{%p}", call->server);
276 afs_init_callback_state(call->server);
277 afs_send_empty_reply(call);
278 _leave("");
282 * deliver request data to a CB.InitCallBackState call
284 static int afs_deliver_cb_init_call_back_state(struct afs_call *call,
285 struct sk_buff *skb,
286 bool last)
288 struct afs_server *server;
289 struct in_addr addr;
291 _enter(",{%u},%d", skb->len, last);
293 if (skb->len > 0)
294 return -EBADMSG;
295 if (!last)
296 return 0;
298 /* no unmarshalling required */
299 call->state = AFS_CALL_REPLYING;
301 /* we'll need the file server record as that tells us which set of
302 * vnodes to operate upon */
303 memcpy(&addr, &ip_hdr(skb)->saddr, 4);
304 server = afs_find_server(&addr);
305 if (!server)
306 return -ENOTCONN;
307 call->server = server;
309 INIT_WORK(&call->work, SRXAFSCB_InitCallBackState);
310 schedule_work(&call->work);
311 return 0;
315 * allow the fileserver to see if the cache manager is still alive
317 static void SRXAFSCB_Probe(struct work_struct *work)
319 struct afs_call *call = container_of(work, struct afs_call, work);
321 _enter("");
322 afs_send_empty_reply(call);
323 _leave("");
327 * deliver request data to a CB.Probe call
329 static int afs_deliver_cb_probe(struct afs_call *call, struct sk_buff *skb,
330 bool last)
332 _enter(",{%u},%d", skb->len, last);
334 if (skb->len > 0)
335 return -EBADMSG;
336 if (!last)
337 return 0;
339 /* no unmarshalling required */
340 call->state = AFS_CALL_REPLYING;
342 INIT_WORK(&call->work, SRXAFSCB_Probe);
343 schedule_work(&call->work);
344 return 0;
348 * allow the fileserver to ask about the cache manager's capabilities
350 static void SRXAFSCB_GetCapabilities(struct work_struct *work)
352 struct afs_interface *ifs;
353 struct afs_call *call = container_of(work, struct afs_call, work);
354 int loop, nifs;
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;
370 _enter("");
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;
383 memset(&reply, 0, sizeof(reply));
384 reply.ia.nifs = htonl(nifs);
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]);
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);
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));
406 _leave("");
410 * deliver request data to a CB.GetCapabilities call
412 static int afs_deliver_cb_get_capabilities(struct afs_call *call,
413 struct sk_buff *skb, bool last)
415 _enter(",{%u},%d", skb->len, last);
417 if (skb->len > 0)
418 return -EBADMSG;
419 if (!last)
420 return 0;
422 /* no unmarshalling required */
423 call->state = AFS_CALL_REPLYING;
425 INIT_WORK(&call->work, SRXAFSCB_GetCapabilities);
426 schedule_work(&call->work);
427 return 0;