]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blame - fs/afs/cmservice.c
[AFS]: Add support for the CB.GetCapabilities operation.
[mirror_ubuntu-bionic-kernel.git] / fs / afs / cmservice.c
CommitLineData
ec26815a 1/* AFS Cache Manager Service
1da177e4
LT
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>
08e0e7c8 15#include <linux/ip.h>
1da177e4 16#include "internal.h"
08e0e7c8 17#include "afs_cm.h"
1da177e4 18
08e0e7c8 19struct workqueue_struct *afs_cm_workqueue;
1da177e4 20
08e0e7c8
DH
21static int afs_deliver_cb_init_call_back_state(struct afs_call *,
22 struct sk_buff *, bool);
23static int afs_deliver_cb_probe(struct afs_call *, struct sk_buff *, bool);
24static int afs_deliver_cb_callback(struct afs_call *, struct sk_buff *, bool);
b908fe6b
DH
25static int afs_deliver_cb_get_capabilities(struct afs_call *, struct sk_buff *,
26 bool);
08e0e7c8 27static void afs_cm_destructor(struct afs_call *);
1da177e4 28
1da177e4 29/*
08e0e7c8 30 * CB.CallBack operation type
1da177e4 31 */
08e0e7c8 32static const struct afs_call_type afs_SRXCBCallBack = {
00d3b7a4 33 .name = "CB.CallBack",
08e0e7c8
DH
34 .deliver = afs_deliver_cb_callback,
35 .abort_to_error = afs_abort_to_error,
36 .destructor = afs_cm_destructor,
37};
1da177e4 38
1da177e4 39/*
08e0e7c8 40 * CB.InitCallBackState operation type
1da177e4 41 */
08e0e7c8 42static const struct afs_call_type afs_SRXCBInitCallBackState = {
00d3b7a4 43 .name = "CB.InitCallBackState",
08e0e7c8
DH
44 .deliver = afs_deliver_cb_init_call_back_state,
45 .abort_to_error = afs_abort_to_error,
46 .destructor = afs_cm_destructor,
47};
1da177e4 48
1da177e4 49/*
08e0e7c8 50 * CB.Probe operation type
1da177e4 51 */
08e0e7c8 52static const struct afs_call_type afs_SRXCBProbe = {
00d3b7a4 53 .name = "CB.Probe",
08e0e7c8
DH
54 .deliver = afs_deliver_cb_probe,
55 .abort_to_error = afs_abort_to_error,
56 .destructor = afs_cm_destructor,
57};
1da177e4 58
b908fe6b
DH
59/*
60 * CB.GetCapabilities operation type
61 */
62static 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
1da177e4 69/*
08e0e7c8
DH
70 * route an incoming cache manager call
71 * - return T if supported, F if not
1da177e4 72 */
08e0e7c8 73bool afs_cm_incoming_call(struct afs_call *call)
1da177e4 74{
08e0e7c8
DH
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;
b908fe6b
DH
89 case CBGetCapabilities:
90 call->type = &afs_SRXCBGetCapabilites;
91 return true;
08e0e7c8
DH
92 default:
93 return false;
1da177e4 94 }
ec26815a 95}
1da177e4 96
1da177e4 97/*
08e0e7c8 98 * clean up a cache manager call
1da177e4 99 */
08e0e7c8 100static void afs_cm_destructor(struct afs_call *call)
1da177e4 101{
08e0e7c8
DH
102 _enter("");
103
104 afs_put_server(call->server);
105 call->server = NULL;
106 kfree(call->buffer);
107 call->buffer = NULL;
ec26815a 108}
1da177e4 109
1da177e4 110/*
08e0e7c8 111 * allow the fileserver to see if the cache manager is still alive
1da177e4 112 */
08e0e7c8 113static void SRXAFSCB_CallBack(struct work_struct *work)
1da177e4 114{
08e0e7c8 115 struct afs_call *call = container_of(work, struct afs_call, work);
1da177e4 116
08e0e7c8 117 _enter("");
1da177e4 118
08e0e7c8
DH
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);
1da177e4 125
08e0e7c8
DH
126 afs_break_callbacks(call->server, call->count, call->request);
127 _leave("");
ec26815a 128}
1da177e4 129
1da177e4 130/*
08e0e7c8 131 * deliver request data to a CB.CallBack call
1da177e4 132 */
08e0e7c8
DH
133static int afs_deliver_cb_callback(struct afs_call *call, struct sk_buff *skb,
134 bool last)
1da177e4 135{
08e0e7c8
DH
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;
1da177e4 158 }
1da177e4 159
08e0e7c8
DH
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;
1da177e4 179 }
1da177e4 180
08e0e7c8
DH
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;
1da177e4
LT
195 }
196
08e0e7c8
DH
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 }
1da177e4 209
08e0e7c8
DH
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;
1da177e4 227 }
1da177e4 228
08e0e7c8
DH
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 }
1da177e4 237
08e0e7c8
DH
238 empty_cb_array:
239 call->offset = 0;
240 call->unmarshall++;
1da177e4 241
08e0e7c8
DH
242 case 5:
243 _debug("trailer");
244 if (skb->len != 0)
245 return -EBADMSG;
1da177e4
LT
246 break;
247 }
248
08e0e7c8
DH
249 if (!last)
250 return 0;
1da177e4 251
08e0e7c8 252 call->state = AFS_CALL_REPLYING;
1da177e4 253
08e0e7c8
DH
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;
ec26815a 265}
1da177e4 266
1da177e4 267/*
08e0e7c8 268 * allow the fileserver to request callback state (re-)initialisation
1da177e4 269 */
08e0e7c8 270static void SRXAFSCB_InitCallBackState(struct work_struct *work)
1da177e4 271{
08e0e7c8 272 struct afs_call *call = container_of(work, struct afs_call, work);
1da177e4 273
08e0e7c8 274 _enter("{%p}", call->server);
1da177e4 275
08e0e7c8
DH
276 afs_init_callback_state(call->server);
277 afs_send_empty_reply(call);
278 _leave("");
ec26815a 279}
1da177e4 280
1da177e4 281/*
08e0e7c8 282 * deliver request data to a CB.InitCallBackState call
1da177e4 283 */
08e0e7c8
DH
284static int afs_deliver_cb_init_call_back_state(struct afs_call *call,
285 struct sk_buff *skb,
286 bool last)
1da177e4
LT
287{
288 struct afs_server *server;
08e0e7c8 289 struct in_addr addr;
1da177e4 290
08e0e7c8 291 _enter(",{%u},%d", skb->len, last);
1da177e4 292
08e0e7c8
DH
293 if (skb->len > 0)
294 return -EBADMSG;
295 if (!last)
296 return 0;
1da177e4 297
08e0e7c8
DH
298 /* no unmarshalling required */
299 call->state = AFS_CALL_REPLYING;
1da177e4 300
08e0e7c8
DH
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;
1da177e4 308
08e0e7c8
DH
309 INIT_WORK(&call->work, SRXAFSCB_InitCallBackState);
310 schedule_work(&call->work);
311 return 0;
312}
1da177e4 313
08e0e7c8
DH
314/*
315 * allow the fileserver to see if the cache manager is still alive
316 */
317static void SRXAFSCB_Probe(struct work_struct *work)
318{
319 struct afs_call *call = container_of(work, struct afs_call, work);
1da177e4 320
08e0e7c8
DH
321 _enter("");
322 afs_send_empty_reply(call);
323 _leave("");
324}
1da177e4 325
08e0e7c8
DH
326/*
327 * deliver request data to a CB.Probe call
328 */
329static int afs_deliver_cb_probe(struct afs_call *call, struct sk_buff *skb,
330 bool last)
331{
332 _enter(",{%u},%d", skb->len, last);
1da177e4 333
08e0e7c8
DH
334 if (skb->len > 0)
335 return -EBADMSG;
336 if (!last)
337 return 0;
1da177e4 338
08e0e7c8
DH
339 /* no unmarshalling required */
340 call->state = AFS_CALL_REPLYING;
1da177e4 341
08e0e7c8
DH
342 INIT_WORK(&call->work, SRXAFSCB_Probe);
343 schedule_work(&call->work);
344 return 0;
ec26815a 345}
b908fe6b
DH
346
347/*
348 * allow the fileserver to ask about the cache manager's capabilities
349 */
350static 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 */
412static 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}