blob: a6af3acf016e9984b0fad7de1a658112287bf57c [file] [log] [blame]
David Howellsec268152007-04-26 15:49:28 -07001/* AFS Cache Manager Service
Linus Torvalds1da177e2005-04-16 15:20:36 -07002 *
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>
David Howells08e0e7c2007-04-26 15:55:03 -070015#include <linux/ip.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070016#include "internal.h"
David Howells08e0e7c2007-04-26 15:55:03 -070017#include "afs_cm.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070018
David Howells08e0e7c2007-04-26 15:55:03 -070019struct workqueue_struct *afs_cm_workqueue;
Linus Torvalds1da177e2005-04-16 15:20:36 -070020
David Howells08e0e7c2007-04-26 15:55:03 -070021static 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);
David Howellsb908fe62007-04-26 15:58:17 -070025static int afs_deliver_cb_get_capabilities(struct afs_call *, struct sk_buff *,
26 bool);
David Howells08e0e7c2007-04-26 15:55:03 -070027static void afs_cm_destructor(struct afs_call *);
Linus Torvalds1da177e2005-04-16 15:20:36 -070028
David Howells08e0e7c2007-04-26 15:55:03 -070029/*
30 * CB.CallBack operation type
31 */
32static const struct afs_call_type afs_SRXCBCallBack = {
David Howells00d3b7a2007-04-26 15:57:07 -070033 .name = "CB.CallBack",
David Howells08e0e7c2007-04-26 15:55:03 -070034 .deliver = afs_deliver_cb_callback,
35 .abort_to_error = afs_abort_to_error,
36 .destructor = afs_cm_destructor,
Linus Torvalds1da177e2005-04-16 15:20:36 -070037};
38
David Howells08e0e7c2007-04-26 15:55:03 -070039/*
40 * CB.InitCallBackState operation type
41 */
42static const struct afs_call_type afs_SRXCBInitCallBackState = {
David Howells00d3b7a2007-04-26 15:57:07 -070043 .name = "CB.InitCallBackState",
David Howells08e0e7c2007-04-26 15:55:03 -070044 .deliver = afs_deliver_cb_init_call_back_state,
45 .abort_to_error = afs_abort_to_error,
46 .destructor = afs_cm_destructor,
Linus Torvalds1da177e2005-04-16 15:20:36 -070047};
48
David Howells08e0e7c2007-04-26 15:55:03 -070049/*
50 * CB.Probe operation type
51 */
52static const struct afs_call_type afs_SRXCBProbe = {
David Howells00d3b7a2007-04-26 15:57:07 -070053 .name = "CB.Probe",
David Howells08e0e7c2007-04-26 15:55:03 -070054 .deliver = afs_deliver_cb_probe,
55 .abort_to_error = afs_abort_to_error,
56 .destructor = afs_cm_destructor,
57};
Linus Torvalds1da177e2005-04-16 15:20:36 -070058
Linus Torvalds1da177e2005-04-16 15:20:36 -070059/*
David Howellsb908fe62007-04-26 15:58:17 -070060 * 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
69/*
David Howells08e0e7c2007-04-26 15:55:03 -070070 * route an incoming cache manager call
71 * - return T if supported, F if not
Linus Torvalds1da177e2005-04-16 15:20:36 -070072 */
David Howells08e0e7c2007-04-26 15:55:03 -070073bool afs_cm_incoming_call(struct afs_call *call)
Linus Torvalds1da177e2005-04-16 15:20:36 -070074{
David Howells08e0e7c2007-04-26 15:55:03 -070075 u32 operation_id = ntohl(call->operation_ID);
Linus Torvalds1da177e2005-04-16 15:20:36 -070076
David Howells08e0e7c2007-04-26 15:55:03 -070077 _enter("{CB.OP %u}", operation_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -070078
David Howells08e0e7c2007-04-26 15:55:03 -070079 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;
David Howellsb908fe62007-04-26 15:58:17 -070089 case CBGetCapabilities:
90 call->type = &afs_SRXCBGetCapabilites;
91 return true;
David Howells08e0e7c2007-04-26 15:55:03 -070092 default:
93 return false;
94 }
David Howellsec268152007-04-26 15:49:28 -070095}
Linus Torvalds1da177e2005-04-16 15:20:36 -070096
Linus Torvalds1da177e2005-04-16 15:20:36 -070097/*
David Howells08e0e7c2007-04-26 15:55:03 -070098 * clean up a cache manager call
Linus Torvalds1da177e2005-04-16 15:20:36 -070099 */
David Howells08e0e7c2007-04-26 15:55:03 -0700100static void afs_cm_destructor(struct afs_call *call)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700101{
David Howells08e0e7c2007-04-26 15:55:03 -0700102 _enter("");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700103
David Howells08e0e7c2007-04-26 15:55:03 -0700104 afs_put_server(call->server);
105 call->server = NULL;
106 kfree(call->buffer);
107 call->buffer = NULL;
David Howellsec268152007-04-26 15:49:28 -0700108}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700109
Linus Torvalds1da177e2005-04-16 15:20:36 -0700110/*
David Howells08e0e7c2007-04-26 15:55:03 -0700111 * allow the fileserver to see if the cache manager is still alive
Linus Torvalds1da177e2005-04-16 15:20:36 -0700112 */
David Howells08e0e7c2007-04-26 15:55:03 -0700113static void SRXAFSCB_CallBack(struct work_struct *work)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700114{
David Howells08e0e7c2007-04-26 15:55:03 -0700115 struct afs_call *call = container_of(work, struct afs_call, work);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700116
David Howells08e0e7c2007-04-26 15:55:03 -0700117 _enter("");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700118
David Howells08e0e7c2007-04-26 15:55:03 -0700119 /* 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);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700125
David Howells08e0e7c2007-04-26 15:55:03 -0700126 afs_break_callbacks(call->server, call->count, call->request);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700127 _leave("");
David Howellsec268152007-04-26 15:49:28 -0700128}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700129
Linus Torvalds1da177e2005-04-16 15:20:36 -0700130/*
David Howells08e0e7c2007-04-26 15:55:03 -0700131 * deliver request data to a CB.CallBack call
Linus Torvalds1da177e2005-04-16 15:20:36 -0700132 */
David Howells08e0e7c2007-04-26 15:55:03 -0700133static int afs_deliver_cb_callback(struct afs_call *call, struct sk_buff *skb,
134 bool last)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700135{
David Howells08e0e7c2007-04-26 15:55:03 -0700136 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;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700246 break;
247 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700248
David Howells08e0e7c2007-04-26 15:55:03 -0700249 if (!last)
250 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700251
David Howells08e0e7c2007-04-26 15:55:03 -0700252 call->state = AFS_CALL_REPLYING;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700253
David Howells08e0e7c2007-04-26 15:55:03 -0700254 /* 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;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700261
David Howells08e0e7c2007-04-26 15:55:03 -0700262 INIT_WORK(&call->work, SRXAFSCB_CallBack);
263 schedule_work(&call->work);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700264 return 0;
David Howellsec268152007-04-26 15:49:28 -0700265}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700266
Linus Torvalds1da177e2005-04-16 15:20:36 -0700267/*
David Howells08e0e7c2007-04-26 15:55:03 -0700268 * allow the fileserver to request callback state (re-)initialisation
Linus Torvalds1da177e2005-04-16 15:20:36 -0700269 */
David Howells08e0e7c2007-04-26 15:55:03 -0700270static void SRXAFSCB_InitCallBackState(struct work_struct *work)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700271{
David Howells08e0e7c2007-04-26 15:55:03 -0700272 struct afs_call *call = container_of(work, struct afs_call, work);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700273
David Howells08e0e7c2007-04-26 15:55:03 -0700274 _enter("{%p}", call->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700275
David Howells08e0e7c2007-04-26 15:55:03 -0700276 afs_init_callback_state(call->server);
277 afs_send_empty_reply(call);
278 _leave("");
David Howellsec268152007-04-26 15:49:28 -0700279}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700280
Linus Torvalds1da177e2005-04-16 15:20:36 -0700281/*
David Howells08e0e7c2007-04-26 15:55:03 -0700282 * deliver request data to a CB.InitCallBackState call
Linus Torvalds1da177e2005-04-16 15:20:36 -0700283 */
David Howells08e0e7c2007-04-26 15:55:03 -0700284static int afs_deliver_cb_init_call_back_state(struct afs_call *call,
285 struct sk_buff *skb,
286 bool last)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700287{
288 struct afs_server *server;
David Howells08e0e7c2007-04-26 15:55:03 -0700289 struct in_addr addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700290
David Howells08e0e7c2007-04-26 15:55:03 -0700291 _enter(",{%u},%d", skb->len, last);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700292
David Howells08e0e7c2007-04-26 15:55:03 -0700293 if (skb->len > 0)
294 return -EBADMSG;
295 if (!last)
296 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700297
David Howells08e0e7c2007-04-26 15:55:03 -0700298 /* no unmarshalling required */
299 call->state = AFS_CALL_REPLYING;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700300
David Howells08e0e7c2007-04-26 15:55:03 -0700301 /* 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;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700308
David Howells08e0e7c2007-04-26 15:55:03 -0700309 INIT_WORK(&call->work, SRXAFSCB_InitCallBackState);
310 schedule_work(&call->work);
311 return 0;
David Howellsec268152007-04-26 15:49:28 -0700312}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700313
Linus Torvalds1da177e2005-04-16 15:20:36 -0700314/*
David Howells08e0e7c2007-04-26 15:55:03 -0700315 * allow the fileserver to see if the cache manager is still alive
Linus Torvalds1da177e2005-04-16 15:20:36 -0700316 */
David Howells08e0e7c2007-04-26 15:55:03 -0700317static void SRXAFSCB_Probe(struct work_struct *work)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700318{
David Howells08e0e7c2007-04-26 15:55:03 -0700319 struct afs_call *call = container_of(work, struct afs_call, work);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700320
David Howells08e0e7c2007-04-26 15:55:03 -0700321 _enter("");
322 afs_send_empty_reply(call);
323 _leave("");
David Howellsec268152007-04-26 15:49:28 -0700324}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700325
Linus Torvalds1da177e2005-04-16 15:20:36 -0700326/*
David Howells08e0e7c2007-04-26 15:55:03 -0700327 * deliver request data to a CB.Probe call
Linus Torvalds1da177e2005-04-16 15:20:36 -0700328 */
David Howells08e0e7c2007-04-26 15:55:03 -0700329static int afs_deliver_cb_probe(struct afs_call *call, struct sk_buff *skb,
330 bool last)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700331{
David Howells08e0e7c2007-04-26 15:55:03 -0700332 _enter(",{%u},%d", skb->len, last);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700333
David Howells08e0e7c2007-04-26 15:55:03 -0700334 if (skb->len > 0)
335 return -EBADMSG;
336 if (!last)
337 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700338
David Howells08e0e7c2007-04-26 15:55:03 -0700339 /* no unmarshalling required */
340 call->state = AFS_CALL_REPLYING;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700341
David Howells08e0e7c2007-04-26 15:55:03 -0700342 INIT_WORK(&call->work, SRXAFSCB_Probe);
343 schedule_work(&call->work);
344 return 0;
David Howellsec268152007-04-26 15:49:28 -0700345}
David Howellsb908fe62007-04-26 15:58:17 -0700346
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}