[AFS]: Add security support.
[linux-2.6.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 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_probe(struct afs_call *, struct sk_buff *, bool);
24 static int afs_deliver_cb_callback(struct afs_call *, struct sk_buff *, bool);
25 static void afs_cm_destructor(struct afs_call *);
26
27 /*
28  * CB.CallBack operation type
29  */
30 static const struct afs_call_type afs_SRXCBCallBack = {
31         .name           = "CB.CallBack",
32         .deliver        = afs_deliver_cb_callback,
33         .abort_to_error = afs_abort_to_error,
34         .destructor     = afs_cm_destructor,
35 };
36
37 /*
38  * CB.InitCallBackState operation type
39  */
40 static const struct afs_call_type afs_SRXCBInitCallBackState = {
41         .name           = "CB.InitCallBackState",
42         .deliver        = afs_deliver_cb_init_call_back_state,
43         .abort_to_error = afs_abort_to_error,
44         .destructor     = afs_cm_destructor,
45 };
46
47 /*
48  * CB.Probe operation type
49  */
50 static const struct afs_call_type afs_SRXCBProbe = {
51         .name           = "CB.Probe",
52         .deliver        = afs_deliver_cb_probe,
53         .abort_to_error = afs_abort_to_error,
54         .destructor     = afs_cm_destructor,
55 };
56
57 /*
58  * route an incoming cache manager call
59  * - return T if supported, F if not
60  */
61 bool afs_cm_incoming_call(struct afs_call *call)
62 {
63         u32 operation_id = ntohl(call->operation_ID);
64
65         _enter("{CB.OP %u}", operation_id);
66
67         switch (operation_id) {
68         case CBCallBack:
69                 call->type = &afs_SRXCBCallBack;
70                 return true;
71         case CBInitCallBackState:
72                 call->type = &afs_SRXCBInitCallBackState;
73                 return true;
74         case CBProbe:
75                 call->type = &afs_SRXCBProbe;
76                 return true;
77         default:
78                 return false;
79         }
80 }
81
82 /*
83  * clean up a cache manager call
84  */
85 static void afs_cm_destructor(struct afs_call *call)
86 {
87         _enter("");
88
89         afs_put_server(call->server);
90         call->server = NULL;
91         kfree(call->buffer);
92         call->buffer = NULL;
93 }
94
95 /*
96  * allow the fileserver to see if the cache manager is still alive
97  */
98 static void SRXAFSCB_CallBack(struct work_struct *work)
99 {
100         struct afs_call *call = container_of(work, struct afs_call, work);
101
102         _enter("");
103
104         /* be sure to send the reply *before* attempting to spam the AFS server
105          * with FSFetchStatus requests on the vnodes with broken callbacks lest
106          * the AFS server get into a vicious cycle of trying to break further
107          * callbacks because it hadn't received completion of the CBCallBack op
108          * yet */
109         afs_send_empty_reply(call);
110
111         afs_break_callbacks(call->server, call->count, call->request);
112         _leave("");
113 }
114
115 /*
116  * deliver request data to a CB.CallBack call
117  */
118 static int afs_deliver_cb_callback(struct afs_call *call, struct sk_buff *skb,
119                                    bool last)
120 {
121         struct afs_callback *cb;
122         struct afs_server *server;
123         struct in_addr addr;
124         __be32 *bp;
125         u32 tmp;
126         int ret, loop;
127
128         _enter("{%u},{%u},%d", call->unmarshall, skb->len, last);
129
130         switch (call->unmarshall) {
131         case 0:
132                 call->offset = 0;
133                 call->unmarshall++;
134
135                 /* extract the FID array and its count in two steps */
136         case 1:
137                 _debug("extract FID count");
138                 ret = afs_extract_data(call, skb, last, &call->tmp, 4);
139                 switch (ret) {
140                 case 0:         break;
141                 case -EAGAIN:   return 0;
142                 default:        return ret;
143                 }
144
145                 call->count = ntohl(call->tmp);
146                 _debug("FID count: %u", call->count);
147                 if (call->count > AFSCBMAX)
148                         return -EBADMSG;
149
150                 call->buffer = kmalloc(call->count * 3 * 4, GFP_KERNEL);
151                 if (!call->buffer)
152                         return -ENOMEM;
153                 call->offset = 0;
154                 call->unmarshall++;
155
156         case 2:
157                 _debug("extract FID array");
158                 ret = afs_extract_data(call, skb, last, call->buffer,
159                                        call->count * 3 * 4);
160                 switch (ret) {
161                 case 0:         break;
162                 case -EAGAIN:   return 0;
163                 default:        return ret;
164                 }
165
166                 _debug("unmarshall FID array");
167                 call->request = kcalloc(call->count,
168                                         sizeof(struct afs_callback),
169                                         GFP_KERNEL);
170                 if (!call->request)
171                         return -ENOMEM;
172
173                 cb = call->request;
174                 bp = call->buffer;
175                 for (loop = call->count; loop > 0; loop--, cb++) {
176                         cb->fid.vid     = ntohl(*bp++);
177                         cb->fid.vnode   = ntohl(*bp++);
178                         cb->fid.unique  = ntohl(*bp++);
179                         cb->type        = AFSCM_CB_UNTYPED;
180                 }
181
182                 call->offset = 0;
183                 call->unmarshall++;
184
185                 /* extract the callback array and its count in two steps */
186         case 3:
187                 _debug("extract CB count");
188                 ret = afs_extract_data(call, skb, last, &call->tmp, 4);
189                 switch (ret) {
190                 case 0:         break;
191                 case -EAGAIN:   return 0;
192                 default:        return ret;
193                 }
194
195                 tmp = ntohl(call->tmp);
196                 _debug("CB count: %u", tmp);
197                 if (tmp != call->count && tmp != 0)
198                         return -EBADMSG;
199                 call->offset = 0;
200                 call->unmarshall++;
201                 if (tmp == 0)
202                         goto empty_cb_array;
203
204         case 4:
205                 _debug("extract CB array");
206                 ret = afs_extract_data(call, skb, last, call->request,
207                                        call->count * 3 * 4);
208                 switch (ret) {
209                 case 0:         break;
210                 case -EAGAIN:   return 0;
211                 default:        return ret;
212                 }
213
214                 _debug("unmarshall CB array");
215                 cb = call->request;
216                 bp = call->buffer;
217                 for (loop = call->count; loop > 0; loop--, cb++) {
218                         cb->version     = ntohl(*bp++);
219                         cb->expiry      = ntohl(*bp++);
220                         cb->type        = ntohl(*bp++);
221                 }
222
223         empty_cb_array:
224                 call->offset = 0;
225                 call->unmarshall++;
226
227         case 5:
228                 _debug("trailer");
229                 if (skb->len != 0)
230                         return -EBADMSG;
231                 break;
232         }
233
234         if (!last)
235                 return 0;
236
237         call->state = AFS_CALL_REPLYING;
238
239         /* we'll need the file server record as that tells us which set of
240          * vnodes to operate upon */
241         memcpy(&addr, &ip_hdr(skb)->saddr, 4);
242         server = afs_find_server(&addr);
243         if (!server)
244                 return -ENOTCONN;
245         call->server = server;
246
247         INIT_WORK(&call->work, SRXAFSCB_CallBack);
248         schedule_work(&call->work);
249         return 0;
250 }
251
252 /*
253  * allow the fileserver to request callback state (re-)initialisation
254  */
255 static void SRXAFSCB_InitCallBackState(struct work_struct *work)
256 {
257         struct afs_call *call = container_of(work, struct afs_call, work);
258
259         _enter("{%p}", call->server);
260
261         afs_init_callback_state(call->server);
262         afs_send_empty_reply(call);
263         _leave("");
264 }
265
266 /*
267  * deliver request data to a CB.InitCallBackState call
268  */
269 static int afs_deliver_cb_init_call_back_state(struct afs_call *call,
270                                                struct sk_buff *skb,
271                                                bool last)
272 {
273         struct afs_server *server;
274         struct in_addr addr;
275
276         _enter(",{%u},%d", skb->len, last);
277
278         if (skb->len > 0)
279                 return -EBADMSG;
280         if (!last)
281                 return 0;
282
283         /* no unmarshalling required */
284         call->state = AFS_CALL_REPLYING;
285
286         /* we'll need the file server record as that tells us which set of
287          * vnodes to operate upon */
288         memcpy(&addr, &ip_hdr(skb)->saddr, 4);
289         server = afs_find_server(&addr);
290         if (!server)
291                 return -ENOTCONN;
292         call->server = server;
293
294         INIT_WORK(&call->work, SRXAFSCB_InitCallBackState);
295         schedule_work(&call->work);
296         return 0;
297 }
298
299 /*
300  * allow the fileserver to see if the cache manager is still alive
301  */
302 static void SRXAFSCB_Probe(struct work_struct *work)
303 {
304         struct afs_call *call = container_of(work, struct afs_call, work);
305
306         _enter("");
307         afs_send_empty_reply(call);
308         _leave("");
309 }
310
311 /*
312  * deliver request data to a CB.Probe call
313  */
314 static int afs_deliver_cb_probe(struct afs_call *call, struct sk_buff *skb,
315                                 bool last)
316 {
317         _enter(",{%u},%d", skb->len, last);
318
319         if (skb->len > 0)
320                 return -EBADMSG;
321         if (!last)
322                 return 0;
323
324         /* no unmarshalling required */
325         call->state = AFS_CALL_REPLYING;
326
327         INIT_WORK(&call->work, SRXAFSCB_Probe);
328         schedule_work(&call->work);
329         return 0;
330 }