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