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 .deliver = afs_deliver_cb_callback,
32 .abort_to_error = afs_abort_to_error,
33 .destructor = afs_cm_destructor,
37 * CB.InitCallBackState operation type
39 static 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,
46 * CB.Probe operation type
48 static 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,
55 * route an incoming cache manager call
56 * - return T if supported, F if not
58 bool afs_cm_incoming_call(struct afs_call *call)
60 u32 operation_id = ntohl(call->operation_ID);
62 _enter("{CB.OP %u}", operation_id);
64 switch (operation_id) {
66 call->type = &afs_SRXCBCallBack;
68 case CBInitCallBackState:
69 call->type = &afs_SRXCBInitCallBackState;
72 call->type = &afs_SRXCBProbe;
80 * clean up a cache manager call
82 static void afs_cm_destructor(struct afs_call *call)
86 afs_put_server(call->server);
93 * allow the fileserver to see if the cache manager is still alive
95 static void SRXAFSCB_CallBack(struct work_struct *work)
97 struct afs_call *call = container_of(work, struct afs_call, work);
101 /* 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
106 afs_send_empty_reply(call);
108 afs_break_callbacks(call->server, call->count, call->request);
113 * deliver request data to a CB.CallBack call
115 static int afs_deliver_cb_callback(struct afs_call *call, struct sk_buff *skb,
118 struct afs_callback *cb;
119 struct afs_server *server;
125 _enter("{%u},{%u},%d", call->unmarshall, skb->len, last);
127 switch (call->unmarshall) {
132 /* extract the FID array and its count in two steps */
134 _debug("extract FID count");
135 ret = afs_extract_data(call, skb, last, &call->tmp, 4);
138 case -EAGAIN: return 0;
142 call->count = ntohl(call->tmp);
143 _debug("FID count: %u", call->count);
144 if (call->count > AFSCBMAX)
147 call->buffer = kmalloc(call->count * 3 * 4, GFP_KERNEL);
154 _debug("extract FID array");
155 ret = afs_extract_data(call, skb, last, call->buffer,
156 call->count * 3 * 4);
159 case -EAGAIN: return 0;
163 _debug("unmarshall FID array");
164 call->request = kcalloc(call->count,
165 sizeof(struct afs_callback),
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;
182 /* extract the callback array and its count in two steps */
184 _debug("extract CB count");
185 ret = afs_extract_data(call, skb, last, &call->tmp, 4);
188 case -EAGAIN: return 0;
192 tmp = ntohl(call->tmp);
193 _debug("CB count: %u", tmp);
194 if (tmp != call->count && tmp != 0)
202 _debug("extract CB array");
203 ret = afs_extract_data(call, skb, last, call->request,
204 call->count * 3 * 4);
207 case -EAGAIN: return 0;
211 _debug("unmarshall CB array");
214 for (loop = call->count; loop > 0; loop--, cb++) {
215 cb->version = ntohl(*bp++);
216 cb->expiry = ntohl(*bp++);
217 cb->type = ntohl(*bp++);
234 call->state = AFS_CALL_REPLYING;
236 /* 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);
242 call->server = server;
244 INIT_WORK(&call->work, SRXAFSCB_CallBack);
245 schedule_work(&call->work);
250 * allow the fileserver to request callback state (re-)initialisation
252 static void SRXAFSCB_InitCallBackState(struct work_struct *work)
254 struct afs_call *call = container_of(work, struct afs_call, work);
256 _enter("{%p}", call->server);
258 afs_init_callback_state(call->server);
259 afs_send_empty_reply(call);
264 * deliver request data to a CB.InitCallBackState call
266 static int afs_deliver_cb_init_call_back_state(struct afs_call *call,
270 struct afs_server *server;
273 _enter(",{%u},%d", skb->len, last);
280 /* no unmarshalling required */
281 call->state = AFS_CALL_REPLYING;
283 /* 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);
289 call->server = server;
291 INIT_WORK(&call->work, SRXAFSCB_InitCallBackState);
292 schedule_work(&call->work);
297 * allow the fileserver to see if the cache manager is still alive
299 static void SRXAFSCB_Probe(struct work_struct *work)
301 struct afs_call *call = container_of(work, struct afs_call, work);
304 afs_send_empty_reply(call);
309 * deliver request data to a CB.Probe call
311 static int afs_deliver_cb_probe(struct afs_call *call, struct sk_buff *skb,
314 _enter(",{%u},%d", skb->len, last);
321 /* no unmarshalling required */
322 call->state = AFS_CALL_REPLYING;
324 INIT_WORK(&call->work, SRXAFSCB_Probe);
325 schedule_work(&call->work);