blob: c7141175391b77cd40e61d809689d3a8c4f644e7 [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);
25static void afs_cm_destructor(struct afs_call *);
Linus Torvalds1da177e2005-04-16 15:20:36 -070026
David Howells08e0e7c2007-04-26 15:55:03 -070027/*
28 * CB.CallBack operation type
29 */
30static 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,
Linus Torvalds1da177e2005-04-16 15:20:36 -070034};
35
David Howells08e0e7c2007-04-26 15:55:03 -070036/*
37 * CB.InitCallBackState operation type
38 */
39static 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,
Linus Torvalds1da177e2005-04-16 15:20:36 -070043};
44
David Howells08e0e7c2007-04-26 15:55:03 -070045/*
46 * CB.Probe operation type
47 */
48static 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};
Linus Torvalds1da177e2005-04-16 15:20:36 -070053
Linus Torvalds1da177e2005-04-16 15:20:36 -070054/*
David Howells08e0e7c2007-04-26 15:55:03 -070055 * route an incoming cache manager call
56 * - return T if supported, F if not
Linus Torvalds1da177e2005-04-16 15:20:36 -070057 */
David Howells08e0e7c2007-04-26 15:55:03 -070058bool afs_cm_incoming_call(struct afs_call *call)
Linus Torvalds1da177e2005-04-16 15:20:36 -070059{
David Howells08e0e7c2007-04-26 15:55:03 -070060 u32 operation_id = ntohl(call->operation_ID);
Linus Torvalds1da177e2005-04-16 15:20:36 -070061
David Howells08e0e7c2007-04-26 15:55:03 -070062 _enter("{CB.OP %u}", operation_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -070063
David Howells08e0e7c2007-04-26 15:55:03 -070064 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 }
David Howellsec268152007-04-26 15:49:28 -070077}
Linus Torvalds1da177e2005-04-16 15:20:36 -070078
Linus Torvalds1da177e2005-04-16 15:20:36 -070079/*
David Howells08e0e7c2007-04-26 15:55:03 -070080 * clean up a cache manager call
Linus Torvalds1da177e2005-04-16 15:20:36 -070081 */
David Howells08e0e7c2007-04-26 15:55:03 -070082static void afs_cm_destructor(struct afs_call *call)
Linus Torvalds1da177e2005-04-16 15:20:36 -070083{
David Howells08e0e7c2007-04-26 15:55:03 -070084 _enter("");
Linus Torvalds1da177e2005-04-16 15:20:36 -070085
David Howells08e0e7c2007-04-26 15:55:03 -070086 afs_put_server(call->server);
87 call->server = NULL;
88 kfree(call->buffer);
89 call->buffer = NULL;
David Howellsec268152007-04-26 15:49:28 -070090}
Linus Torvalds1da177e2005-04-16 15:20:36 -070091
Linus Torvalds1da177e2005-04-16 15:20:36 -070092/*
David Howells08e0e7c2007-04-26 15:55:03 -070093 * allow the fileserver to see if the cache manager is still alive
Linus Torvalds1da177e2005-04-16 15:20:36 -070094 */
David Howells08e0e7c2007-04-26 15:55:03 -070095static void SRXAFSCB_CallBack(struct work_struct *work)
Linus Torvalds1da177e2005-04-16 15:20:36 -070096{
David Howells08e0e7c2007-04-26 15:55:03 -070097 struct afs_call *call = container_of(work, struct afs_call, work);
Linus Torvalds1da177e2005-04-16 15:20:36 -070098
David Howells08e0e7c2007-04-26 15:55:03 -070099 _enter("");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700100
David Howells08e0e7c2007-04-26 15:55:03 -0700101 /* 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);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700107
David Howells08e0e7c2007-04-26 15:55:03 -0700108 afs_break_callbacks(call->server, call->count, call->request);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700109 _leave("");
David Howellsec268152007-04-26 15:49:28 -0700110}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700111
Linus Torvalds1da177e2005-04-16 15:20:36 -0700112/*
David Howells08e0e7c2007-04-26 15:55:03 -0700113 * deliver request data to a CB.CallBack call
Linus Torvalds1da177e2005-04-16 15:20:36 -0700114 */
David Howells08e0e7c2007-04-26 15:55:03 -0700115static int afs_deliver_cb_callback(struct afs_call *call, struct sk_buff *skb,
116 bool last)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700117{
David Howells08e0e7c2007-04-26 15:55:03 -0700118 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;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700228 break;
229 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700230
David Howells08e0e7c2007-04-26 15:55:03 -0700231 if (!last)
232 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700233
David Howells08e0e7c2007-04-26 15:55:03 -0700234 call->state = AFS_CALL_REPLYING;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700235
David Howells08e0e7c2007-04-26 15:55:03 -0700236 /* 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;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700243
David Howells08e0e7c2007-04-26 15:55:03 -0700244 INIT_WORK(&call->work, SRXAFSCB_CallBack);
245 schedule_work(&call->work);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700246 return 0;
David Howellsec268152007-04-26 15:49:28 -0700247}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700248
Linus Torvalds1da177e2005-04-16 15:20:36 -0700249/*
David Howells08e0e7c2007-04-26 15:55:03 -0700250 * allow the fileserver to request callback state (re-)initialisation
Linus Torvalds1da177e2005-04-16 15:20:36 -0700251 */
David Howells08e0e7c2007-04-26 15:55:03 -0700252static void SRXAFSCB_InitCallBackState(struct work_struct *work)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700253{
David Howells08e0e7c2007-04-26 15:55:03 -0700254 struct afs_call *call = container_of(work, struct afs_call, work);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700255
David Howells08e0e7c2007-04-26 15:55:03 -0700256 _enter("{%p}", call->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700257
David Howells08e0e7c2007-04-26 15:55:03 -0700258 afs_init_callback_state(call->server);
259 afs_send_empty_reply(call);
260 _leave("");
David Howellsec268152007-04-26 15:49:28 -0700261}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700262
Linus Torvalds1da177e2005-04-16 15:20:36 -0700263/*
David Howells08e0e7c2007-04-26 15:55:03 -0700264 * deliver request data to a CB.InitCallBackState call
Linus Torvalds1da177e2005-04-16 15:20:36 -0700265 */
David Howells08e0e7c2007-04-26 15:55:03 -0700266static int afs_deliver_cb_init_call_back_state(struct afs_call *call,
267 struct sk_buff *skb,
268 bool last)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700269{
270 struct afs_server *server;
David Howells08e0e7c2007-04-26 15:55:03 -0700271 struct in_addr addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700272
David Howells08e0e7c2007-04-26 15:55:03 -0700273 _enter(",{%u},%d", skb->len, last);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700274
David Howells08e0e7c2007-04-26 15:55:03 -0700275 if (skb->len > 0)
276 return -EBADMSG;
277 if (!last)
278 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700279
David Howells08e0e7c2007-04-26 15:55:03 -0700280 /* no unmarshalling required */
281 call->state = AFS_CALL_REPLYING;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700282
David Howells08e0e7c2007-04-26 15:55:03 -0700283 /* 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;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700290
David Howells08e0e7c2007-04-26 15:55:03 -0700291 INIT_WORK(&call->work, SRXAFSCB_InitCallBackState);
292 schedule_work(&call->work);
293 return 0;
David Howellsec268152007-04-26 15:49:28 -0700294}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700295
Linus Torvalds1da177e2005-04-16 15:20:36 -0700296/*
David Howells08e0e7c2007-04-26 15:55:03 -0700297 * allow the fileserver to see if the cache manager is still alive
Linus Torvalds1da177e2005-04-16 15:20:36 -0700298 */
David Howells08e0e7c2007-04-26 15:55:03 -0700299static void SRXAFSCB_Probe(struct work_struct *work)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700300{
David Howells08e0e7c2007-04-26 15:55:03 -0700301 struct afs_call *call = container_of(work, struct afs_call, work);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700302
David Howells08e0e7c2007-04-26 15:55:03 -0700303 _enter("");
304 afs_send_empty_reply(call);
305 _leave("");
David Howellsec268152007-04-26 15:49:28 -0700306}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700307
Linus Torvalds1da177e2005-04-16 15:20:36 -0700308/*
David Howells08e0e7c2007-04-26 15:55:03 -0700309 * deliver request data to a CB.Probe call
Linus Torvalds1da177e2005-04-16 15:20:36 -0700310 */
David Howells08e0e7c2007-04-26 15:55:03 -0700311static int afs_deliver_cb_probe(struct afs_call *call, struct sk_buff *skb,
312 bool last)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700313{
David Howells08e0e7c2007-04-26 15:55:03 -0700314 _enter(",{%u},%d", skb->len, last);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700315
David Howells08e0e7c2007-04-26 15:55:03 -0700316 if (skb->len > 0)
317 return -EBADMSG;
318 if (!last)
319 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700320
David Howells08e0e7c2007-04-26 15:55:03 -0700321 /* no unmarshalling required */
322 call->state = AFS_CALL_REPLYING;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700323
David Howells08e0e7c2007-04-26 15:55:03 -0700324 INIT_WORK(&call->work, SRXAFSCB_Probe);
325 schedule_work(&call->work);
326 return 0;
David Howellsec268152007-04-26 15:49:28 -0700327}