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