blob: c3ec57a237bfb16443bd94d29619caa7bf620d06 [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 = {
David Howells00d3b7a2007-04-26 15:57:07 -070031 .name = "CB.CallBack",
David Howells08e0e7c2007-04-26 15:55:03 -070032 .deliver = afs_deliver_cb_callback,
33 .abort_to_error = afs_abort_to_error,
34 .destructor = afs_cm_destructor,
Linus Torvalds1da177e2005-04-16 15:20:36 -070035};
36
David Howells08e0e7c2007-04-26 15:55:03 -070037/*
38 * CB.InitCallBackState operation type
39 */
40static const struct afs_call_type afs_SRXCBInitCallBackState = {
David Howells00d3b7a2007-04-26 15:57:07 -070041 .name = "CB.InitCallBackState",
David Howells08e0e7c2007-04-26 15:55:03 -070042 .deliver = afs_deliver_cb_init_call_back_state,
43 .abort_to_error = afs_abort_to_error,
44 .destructor = afs_cm_destructor,
Linus Torvalds1da177e2005-04-16 15:20:36 -070045};
46
David Howells08e0e7c2007-04-26 15:55:03 -070047/*
48 * CB.Probe operation type
49 */
50static const struct afs_call_type afs_SRXCBProbe = {
David Howells00d3b7a2007-04-26 15:57:07 -070051 .name = "CB.Probe",
David Howells08e0e7c2007-04-26 15:55:03 -070052 .deliver = afs_deliver_cb_probe,
53 .abort_to_error = afs_abort_to_error,
54 .destructor = afs_cm_destructor,
55};
Linus Torvalds1da177e2005-04-16 15:20:36 -070056
Linus Torvalds1da177e2005-04-16 15:20:36 -070057/*
David Howells08e0e7c2007-04-26 15:55:03 -070058 * route an incoming cache manager call
59 * - return T if supported, F if not
Linus Torvalds1da177e2005-04-16 15:20:36 -070060 */
David Howells08e0e7c2007-04-26 15:55:03 -070061bool afs_cm_incoming_call(struct afs_call *call)
Linus Torvalds1da177e2005-04-16 15:20:36 -070062{
David Howells08e0e7c2007-04-26 15:55:03 -070063 u32 operation_id = ntohl(call->operation_ID);
Linus Torvalds1da177e2005-04-16 15:20:36 -070064
David Howells08e0e7c2007-04-26 15:55:03 -070065 _enter("{CB.OP %u}", operation_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -070066
David Howells08e0e7c2007-04-26 15:55:03 -070067 switch (operation_id) {
68 case CBCallBack:
69 call->type = &afs_SRXCBCallBack;
70 return true;
71 case CBInitCallBackState:
72 call->type = &afs_SRXCBInitCallBackState;
73 return true;
74 case CBProbe:
75 call->type = &afs_SRXCBProbe;
76 return true;
77 default:
78 return false;
79 }
David Howellsec268152007-04-26 15:49:28 -070080}
Linus Torvalds1da177e2005-04-16 15:20:36 -070081
Linus Torvalds1da177e2005-04-16 15:20:36 -070082/*
David Howells08e0e7c2007-04-26 15:55:03 -070083 * clean up a cache manager call
Linus Torvalds1da177e2005-04-16 15:20:36 -070084 */
David Howells08e0e7c2007-04-26 15:55:03 -070085static void afs_cm_destructor(struct afs_call *call)
Linus Torvalds1da177e2005-04-16 15:20:36 -070086{
David Howells08e0e7c2007-04-26 15:55:03 -070087 _enter("");
Linus Torvalds1da177e2005-04-16 15:20:36 -070088
David Howells08e0e7c2007-04-26 15:55:03 -070089 afs_put_server(call->server);
90 call->server = NULL;
91 kfree(call->buffer);
92 call->buffer = NULL;
David Howellsec268152007-04-26 15:49:28 -070093}
Linus Torvalds1da177e2005-04-16 15:20:36 -070094
Linus Torvalds1da177e2005-04-16 15:20:36 -070095/*
David Howells08e0e7c2007-04-26 15:55:03 -070096 * allow the fileserver to see if the cache manager is still alive
Linus Torvalds1da177e2005-04-16 15:20:36 -070097 */
David Howells08e0e7c2007-04-26 15:55:03 -070098static void SRXAFSCB_CallBack(struct work_struct *work)
Linus Torvalds1da177e2005-04-16 15:20:36 -070099{
David Howells08e0e7c2007-04-26 15:55:03 -0700100 struct afs_call *call = container_of(work, struct afs_call, work);
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 /* be sure to send the reply *before* attempting to spam the AFS server
105 * with FSFetchStatus requests on the vnodes with broken callbacks lest
106 * the AFS server get into a vicious cycle of trying to break further
107 * callbacks because it hadn't received completion of the CBCallBack op
108 * yet */
109 afs_send_empty_reply(call);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700110
David Howells08e0e7c2007-04-26 15:55:03 -0700111 afs_break_callbacks(call->server, call->count, call->request);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700112 _leave("");
David Howellsec268152007-04-26 15:49:28 -0700113}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700114
Linus Torvalds1da177e2005-04-16 15:20:36 -0700115/*
David Howells08e0e7c2007-04-26 15:55:03 -0700116 * deliver request data to a CB.CallBack call
Linus Torvalds1da177e2005-04-16 15:20:36 -0700117 */
David Howells08e0e7c2007-04-26 15:55:03 -0700118static int afs_deliver_cb_callback(struct afs_call *call, struct sk_buff *skb,
119 bool last)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700120{
David Howells08e0e7c2007-04-26 15:55:03 -0700121 struct afs_callback *cb;
122 struct afs_server *server;
123 struct in_addr addr;
124 __be32 *bp;
125 u32 tmp;
126 int ret, loop;
127
128 _enter("{%u},{%u},%d", call->unmarshall, skb->len, last);
129
130 switch (call->unmarshall) {
131 case 0:
132 call->offset = 0;
133 call->unmarshall++;
134
135 /* extract the FID array and its count in two steps */
136 case 1:
137 _debug("extract FID count");
138 ret = afs_extract_data(call, skb, last, &call->tmp, 4);
139 switch (ret) {
140 case 0: break;
141 case -EAGAIN: return 0;
142 default: return ret;
143 }
144
145 call->count = ntohl(call->tmp);
146 _debug("FID count: %u", call->count);
147 if (call->count > AFSCBMAX)
148 return -EBADMSG;
149
150 call->buffer = kmalloc(call->count * 3 * 4, GFP_KERNEL);
151 if (!call->buffer)
152 return -ENOMEM;
153 call->offset = 0;
154 call->unmarshall++;
155
156 case 2:
157 _debug("extract FID array");
158 ret = afs_extract_data(call, skb, last, call->buffer,
159 call->count * 3 * 4);
160 switch (ret) {
161 case 0: break;
162 case -EAGAIN: return 0;
163 default: return ret;
164 }
165
166 _debug("unmarshall FID array");
167 call->request = kcalloc(call->count,
168 sizeof(struct afs_callback),
169 GFP_KERNEL);
170 if (!call->request)
171 return -ENOMEM;
172
173 cb = call->request;
174 bp = call->buffer;
175 for (loop = call->count; loop > 0; loop--, cb++) {
176 cb->fid.vid = ntohl(*bp++);
177 cb->fid.vnode = ntohl(*bp++);
178 cb->fid.unique = ntohl(*bp++);
179 cb->type = AFSCM_CB_UNTYPED;
180 }
181
182 call->offset = 0;
183 call->unmarshall++;
184
185 /* extract the callback array and its count in two steps */
186 case 3:
187 _debug("extract CB count");
188 ret = afs_extract_data(call, skb, last, &call->tmp, 4);
189 switch (ret) {
190 case 0: break;
191 case -EAGAIN: return 0;
192 default: return ret;
193 }
194
195 tmp = ntohl(call->tmp);
196 _debug("CB count: %u", tmp);
197 if (tmp != call->count && tmp != 0)
198 return -EBADMSG;
199 call->offset = 0;
200 call->unmarshall++;
201 if (tmp == 0)
202 goto empty_cb_array;
203
204 case 4:
205 _debug("extract CB array");
206 ret = afs_extract_data(call, skb, last, call->request,
207 call->count * 3 * 4);
208 switch (ret) {
209 case 0: break;
210 case -EAGAIN: return 0;
211 default: return ret;
212 }
213
214 _debug("unmarshall CB array");
215 cb = call->request;
216 bp = call->buffer;
217 for (loop = call->count; loop > 0; loop--, cb++) {
218 cb->version = ntohl(*bp++);
219 cb->expiry = ntohl(*bp++);
220 cb->type = ntohl(*bp++);
221 }
222
223 empty_cb_array:
224 call->offset = 0;
225 call->unmarshall++;
226
227 case 5:
228 _debug("trailer");
229 if (skb->len != 0)
230 return -EBADMSG;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700231 break;
232 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700233
David Howells08e0e7c2007-04-26 15:55:03 -0700234 if (!last)
235 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700236
David Howells08e0e7c2007-04-26 15:55:03 -0700237 call->state = AFS_CALL_REPLYING;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700238
David Howells08e0e7c2007-04-26 15:55:03 -0700239 /* we'll need the file server record as that tells us which set of
240 * vnodes to operate upon */
241 memcpy(&addr, &ip_hdr(skb)->saddr, 4);
242 server = afs_find_server(&addr);
243 if (!server)
244 return -ENOTCONN;
245 call->server = server;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700246
David Howells08e0e7c2007-04-26 15:55:03 -0700247 INIT_WORK(&call->work, SRXAFSCB_CallBack);
248 schedule_work(&call->work);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700249 return 0;
David Howellsec268152007-04-26 15:49:28 -0700250}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700251
Linus Torvalds1da177e2005-04-16 15:20:36 -0700252/*
David Howells08e0e7c2007-04-26 15:55:03 -0700253 * allow the fileserver to request callback state (re-)initialisation
Linus Torvalds1da177e2005-04-16 15:20:36 -0700254 */
David Howells08e0e7c2007-04-26 15:55:03 -0700255static void SRXAFSCB_InitCallBackState(struct work_struct *work)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700256{
David Howells08e0e7c2007-04-26 15:55:03 -0700257 struct afs_call *call = container_of(work, struct afs_call, work);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700258
David Howells08e0e7c2007-04-26 15:55:03 -0700259 _enter("{%p}", call->server);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700260
David Howells08e0e7c2007-04-26 15:55:03 -0700261 afs_init_callback_state(call->server);
262 afs_send_empty_reply(call);
263 _leave("");
David Howellsec268152007-04-26 15:49:28 -0700264}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700265
Linus Torvalds1da177e2005-04-16 15:20:36 -0700266/*
David Howells08e0e7c2007-04-26 15:55:03 -0700267 * deliver request data to a CB.InitCallBackState call
Linus Torvalds1da177e2005-04-16 15:20:36 -0700268 */
David Howells08e0e7c2007-04-26 15:55:03 -0700269static int afs_deliver_cb_init_call_back_state(struct afs_call *call,
270 struct sk_buff *skb,
271 bool last)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700272{
273 struct afs_server *server;
David Howells08e0e7c2007-04-26 15:55:03 -0700274 struct in_addr addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700275
David Howells08e0e7c2007-04-26 15:55:03 -0700276 _enter(",{%u},%d", skb->len, last);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700277
David Howells08e0e7c2007-04-26 15:55:03 -0700278 if (skb->len > 0)
279 return -EBADMSG;
280 if (!last)
281 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700282
David Howells08e0e7c2007-04-26 15:55:03 -0700283 /* no unmarshalling required */
284 call->state = AFS_CALL_REPLYING;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700285
David Howells08e0e7c2007-04-26 15:55:03 -0700286 /* we'll need the file server record as that tells us which set of
287 * vnodes to operate upon */
288 memcpy(&addr, &ip_hdr(skb)->saddr, 4);
289 server = afs_find_server(&addr);
290 if (!server)
291 return -ENOTCONN;
292 call->server = server;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700293
David Howells08e0e7c2007-04-26 15:55:03 -0700294 INIT_WORK(&call->work, SRXAFSCB_InitCallBackState);
295 schedule_work(&call->work);
296 return 0;
David Howellsec268152007-04-26 15:49:28 -0700297}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700298
Linus Torvalds1da177e2005-04-16 15:20:36 -0700299/*
David Howells08e0e7c2007-04-26 15:55:03 -0700300 * allow the fileserver to see if the cache manager is still alive
Linus Torvalds1da177e2005-04-16 15:20:36 -0700301 */
David Howells08e0e7c2007-04-26 15:55:03 -0700302static void SRXAFSCB_Probe(struct work_struct *work)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700303{
David Howells08e0e7c2007-04-26 15:55:03 -0700304 struct afs_call *call = container_of(work, struct afs_call, work);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700305
David Howells08e0e7c2007-04-26 15:55:03 -0700306 _enter("");
307 afs_send_empty_reply(call);
308 _leave("");
David Howellsec268152007-04-26 15:49:28 -0700309}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700310
Linus Torvalds1da177e2005-04-16 15:20:36 -0700311/*
David Howells08e0e7c2007-04-26 15:55:03 -0700312 * deliver request data to a CB.Probe call
Linus Torvalds1da177e2005-04-16 15:20:36 -0700313 */
David Howells08e0e7c2007-04-26 15:55:03 -0700314static int afs_deliver_cb_probe(struct afs_call *call, struct sk_buff *skb,
315 bool last)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700316{
David Howells08e0e7c2007-04-26 15:55:03 -0700317 _enter(",{%u},%d", skb->len, last);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700318
David Howells08e0e7c2007-04-26 15:55:03 -0700319 if (skb->len > 0)
320 return -EBADMSG;
321 if (!last)
322 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700323
David Howells08e0e7c2007-04-26 15:55:03 -0700324 /* no unmarshalling required */
325 call->state = AFS_CALL_REPLYING;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700326
David Howells08e0e7c2007-04-26 15:55:03 -0700327 INIT_WORK(&call->work, SRXAFSCB_Probe);
328 schedule_work(&call->work);
329 return 0;
David Howellsec268152007-04-26 15:49:28 -0700330}