]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blob - fs/afs/cmservice.c
47b71c8947f91221ac9551b75a5dfa91810d2bd8
[linux-2.6-omap-h63xx.git] / fs / afs / cmservice.c
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_get_capabilities(struct afs_call *, struct sk_buff *,
30                                            bool);
31 static void afs_cm_destructor(struct afs_call *);
32
33 /*
34  * CB.CallBack operation type
35  */
36 static const struct afs_call_type afs_SRXCBCallBack = {
37         .name           = "CB.CallBack",
38         .deliver        = afs_deliver_cb_callback,
39         .abort_to_error = afs_abort_to_error,
40         .destructor     = afs_cm_destructor,
41 };
42
43 /*
44  * CB.InitCallBackState operation type
45  */
46 static const struct afs_call_type afs_SRXCBInitCallBackState = {
47         .name           = "CB.InitCallBackState",
48         .deliver        = afs_deliver_cb_init_call_back_state,
49         .abort_to_error = afs_abort_to_error,
50         .destructor     = afs_cm_destructor,
51 };
52
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
63 /*
64  * CB.Probe operation type
65  */
66 static const struct afs_call_type afs_SRXCBProbe = {
67         .name           = "CB.Probe",
68         .deliver        = afs_deliver_cb_probe,
69         .abort_to_error = afs_abort_to_error,
70         .destructor     = afs_cm_destructor,
71 };
72
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
83 /*
84  * route an incoming cache manager call
85  * - return T if supported, F if not
86  */
87 bool afs_cm_incoming_call(struct afs_call *call)
88 {
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;
100         case CBInitCallBackState3:
101                 call->type = &afs_SRXCBInitCallBackState3;
102                 return true;
103         case CBProbe:
104                 call->type = &afs_SRXCBProbe;
105                 return true;
106         case CBGetCapabilities:
107                 call->type = &afs_SRXCBGetCapabilites;
108                 return true;
109         default:
110                 return false;
111         }
112 }
113
114 /*
115  * clean up a cache manager call
116  */
117 static void afs_cm_destructor(struct afs_call *call)
118 {
119         _enter("");
120
121         afs_put_server(call->server);
122         call->server = NULL;
123         kfree(call->buffer);
124         call->buffer = NULL;
125 }
126
127 /*
128  * allow the fileserver to see if the cache manager is still alive
129  */
130 static void SRXAFSCB_CallBack(struct work_struct *work)
131 {
132         struct afs_call *call = container_of(work, struct afs_call, work);
133
134         _enter("");
135
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);
142
143         afs_break_callbacks(call->server, call->count, call->request);
144         _leave("");
145 }
146
147 /*
148  * deliver request data to a CB.CallBack call
149  */
150 static int afs_deliver_cb_callback(struct afs_call *call, struct sk_buff *skb,
151                                    bool last)
152 {
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;
175                 }
176
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;
196                 }
197
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;
212                 }
213
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                 }
226
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;
244                 }
245
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                 }
254
255         empty_cb_array:
256                 call->offset = 0;
257                 call->unmarshall++;
258
259         case 5:
260                 _debug("trailer");
261                 if (skb->len != 0)
262                         return -EBADMSG;
263                 break;
264         }
265
266         if (!last)
267                 return 0;
268
269         call->state = AFS_CALL_REPLYING;
270
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;
282 }
283
284 /*
285  * allow the fileserver to request callback state (re-)initialisation
286  */
287 static void SRXAFSCB_InitCallBackState(struct work_struct *work)
288 {
289         struct afs_call *call = container_of(work, struct afs_call, work);
290
291         _enter("{%p}", call->server);
292
293         afs_init_callback_state(call->server);
294         afs_send_empty_reply(call);
295         _leave("");
296 }
297
298 /*
299  * deliver request data to a CB.InitCallBackState call
300  */
301 static int afs_deliver_cb_init_call_back_state(struct afs_call *call,
302                                                struct sk_buff *skb,
303                                                bool last)
304 {
305         struct afs_server *server;
306         struct in_addr addr;
307
308         _enter(",{%u},%d", skb->len, last);
309
310         if (skb->len > 0)
311                 return -EBADMSG;
312         if (!last)
313                 return 0;
314
315         /* no unmarshalling required */
316         call->state = AFS_CALL_REPLYING;
317
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;
325
326         INIT_WORK(&call->work, SRXAFSCB_InitCallBackState);
327         schedule_work(&call->work);
328         return 0;
329 }
330
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
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);
368
369         _enter("");
370         afs_send_empty_reply(call);
371         _leave("");
372 }
373
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);
381
382         if (skb->len > 0)
383                 return -EBADMSG;
384         if (!last)
385                 return 0;
386
387         /* no unmarshalling required */
388         call->state = AFS_CALL_REPLYING;
389
390         INIT_WORK(&call->work, SRXAFSCB_Probe);
391         schedule_work(&call->work);
392         return 0;
393 }
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                 }
448                 kfree(ifs);
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 }