1 /* AFS Cache Manager Service
3 * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
4 * Written by David Howells (dhowells@redhat.com)
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.
12 #include <linux/module.h>
13 #include <linux/init.h>
14 #include <linux/sched.h>
19 struct workqueue_struct *afs_cm_workqueue;
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 void afs_cm_destructor(struct afs_call *);
28 * CB.CallBack operation type
30 static const struct afs_call_type afs_SRXCBCallBack = {
31 .name = "CB.CallBack",
32 .deliver = afs_deliver_cb_callback,
33 .abort_to_error = afs_abort_to_error,
34 .destructor = afs_cm_destructor,
38 * CB.InitCallBackState operation type
40 static const struct afs_call_type afs_SRXCBInitCallBackState = {
41 .name = "CB.InitCallBackState",
42 .deliver = afs_deliver_cb_init_call_back_state,
43 .abort_to_error = afs_abort_to_error,
44 .destructor = afs_cm_destructor,
48 * CB.Probe operation type
50 static const struct afs_call_type afs_SRXCBProbe = {
52 .deliver = afs_deliver_cb_probe,
53 .abort_to_error = afs_abort_to_error,
54 .destructor = afs_cm_destructor,
58 * route an incoming cache manager call
59 * - return T if supported, F if not
61 bool afs_cm_incoming_call(struct afs_call *call)
63 u32 operation_id = ntohl(call->operation_ID);
65 _enter("{CB.OP %u}", operation_id);
67 switch (operation_id) {
69 call->type = &afs_SRXCBCallBack;
71 case CBInitCallBackState:
72 call->type = &afs_SRXCBInitCallBackState;
75 call->type = &afs_SRXCBProbe;
83 * clean up a cache manager call
85 static void afs_cm_destructor(struct afs_call *call)
89 afs_put_server(call->server);
96 * allow the fileserver to see if the cache manager is still alive
98 static void SRXAFSCB_CallBack(struct work_struct *work)
100 struct afs_call *call = container_of(work, struct afs_call, work);
104 /* 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
109 afs_send_empty_reply(call);
111 afs_break_callbacks(call->server, call->count, call->request);
116 * deliver request data to a CB.CallBack call
118 static int afs_deliver_cb_callback(struct afs_call *call, struct sk_buff *skb,
121 struct afs_callback *cb;
122 struct afs_server *server;
128 _enter("{%u},{%u},%d", call->unmarshall, skb->len, last);
130 switch (call->unmarshall) {
135 /* extract the FID array and its count in two steps */
137 _debug("extract FID count");
138 ret = afs_extract_data(call, skb, last, &call->tmp, 4);
141 case -EAGAIN: return 0;
145 call->count = ntohl(call->tmp);
146 _debug("FID count: %u", call->count);
147 if (call->count > AFSCBMAX)
150 call->buffer = kmalloc(call->count * 3 * 4, GFP_KERNEL);
157 _debug("extract FID array");
158 ret = afs_extract_data(call, skb, last, call->buffer,
159 call->count * 3 * 4);
162 case -EAGAIN: return 0;
166 _debug("unmarshall FID array");
167 call->request = kcalloc(call->count,
168 sizeof(struct afs_callback),
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;
185 /* extract the callback array and its count in two steps */
187 _debug("extract CB count");
188 ret = afs_extract_data(call, skb, last, &call->tmp, 4);
191 case -EAGAIN: return 0;
195 tmp = ntohl(call->tmp);
196 _debug("CB count: %u", tmp);
197 if (tmp != call->count && tmp != 0)
205 _debug("extract CB array");
206 ret = afs_extract_data(call, skb, last, call->request,
207 call->count * 3 * 4);
210 case -EAGAIN: return 0;
214 _debug("unmarshall CB array");
217 for (loop = call->count; loop > 0; loop--, cb++) {
218 cb->version = ntohl(*bp++);
219 cb->expiry = ntohl(*bp++);
220 cb->type = ntohl(*bp++);
237 call->state = AFS_CALL_REPLYING;
239 /* 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);
245 call->server = server;
247 INIT_WORK(&call->work, SRXAFSCB_CallBack);
248 schedule_work(&call->work);
253 * allow the fileserver to request callback state (re-)initialisation
255 static void SRXAFSCB_InitCallBackState(struct work_struct *work)
257 struct afs_call *call = container_of(work, struct afs_call, work);
259 _enter("{%p}", call->server);
261 afs_init_callback_state(call->server);
262 afs_send_empty_reply(call);
267 * deliver request data to a CB.InitCallBackState call
269 static int afs_deliver_cb_init_call_back_state(struct afs_call *call,
273 struct afs_server *server;
276 _enter(",{%u},%d", skb->len, last);
283 /* no unmarshalling required */
284 call->state = AFS_CALL_REPLYING;
286 /* 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);
292 call->server = server;
294 INIT_WORK(&call->work, SRXAFSCB_InitCallBackState);
295 schedule_work(&call->work);
300 * allow the fileserver to see if the cache manager is still alive
302 static void SRXAFSCB_Probe(struct work_struct *work)
304 struct afs_call *call = container_of(work, struct afs_call, work);
307 afs_send_empty_reply(call);
312 * deliver request data to a CB.Probe call
314 static int afs_deliver_cb_probe(struct afs_call *call, struct sk_buff *skb,
317 _enter(",{%u},%d", skb->len, last);
324 /* no unmarshalling required */
325 call->state = AFS_CALL_REPLYING;
327 INIT_WORK(&call->work, SRXAFSCB_Probe);
328 schedule_work(&call->work);