Linux kernel & device driver programming

Cross-Referenced Linux and Device Driver Code

[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ]
Version: [ 2.6.11.8 ] [ 2.6.25 ] [ 2.6.25.8 ] [ 2.6.31.13 ] Architecture: [ i386 ]
  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 }
478 
  This page was automatically generated by the LXR engine.