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