]> git.proxmox.com Git - mirror_ubuntu-zesty-kernel.git/blame - fs/afs/cmservice.c
[AFS]: Update the AFS fs documentation.
[mirror_ubuntu-zesty-kernel.git] / fs / afs / cmservice.c
CommitLineData
ec26815a 1/* AFS Cache Manager Service
1da177e4
LT
2 *
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>
08e0e7c8 15#include <linux/ip.h>
1da177e4 16#include "internal.h"
08e0e7c8 17#include "afs_cm.h"
1da177e4 18
08e0e7c8 19struct workqueue_struct *afs_cm_workqueue;
1da177e4 20
08e0e7c8
DH
21static 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 *);
1da177e4 26
1da177e4 27/*
08e0e7c8 28 * CB.CallBack operation type
1da177e4 29 */
08e0e7c8 30static const struct afs_call_type afs_SRXCBCallBack = {
00d3b7a4 31 .name = "CB.CallBack",
08e0e7c8
DH
32 .deliver = afs_deliver_cb_callback,
33 .abort_to_error = afs_abort_to_error,
34 .destructor = afs_cm_destructor,
35};
1da177e4 36
1da177e4 37/*
08e0e7c8 38 * CB.InitCallBackState operation type
1da177e4 39 */
08e0e7c8 40static const struct afs_call_type afs_SRXCBInitCallBackState = {
00d3b7a4 41 .name = "CB.InitCallBackState",
08e0e7c8
DH
42 .deliver = afs_deliver_cb_init_call_back_state,
43 .abort_to_error = afs_abort_to_error,
44 .destructor = afs_cm_destructor,
45};
1da177e4 46
1da177e4 47/*
08e0e7c8 48 * CB.Probe operation type
1da177e4 49 */
08e0e7c8 50static const struct afs_call_type afs_SRXCBProbe = {
00d3b7a4 51 .name = "CB.Probe",
08e0e7c8
DH
52 .deliver = afs_deliver_cb_probe,
53 .abort_to_error = afs_abort_to_error,
54 .destructor = afs_cm_destructor,
55};
1da177e4 56
1da177e4 57/*
08e0e7c8
DH
58 * route an incoming cache manager call
59 * - return T if supported, F if not
1da177e4 60 */
08e0e7c8 61bool afs_cm_incoming_call(struct afs_call *call)
1da177e4 62{
08e0e7c8
DH
63 u32 operation_id = ntohl(call->operation_ID);
64
65 _enter("{CB.OP %u}", operation_id);
66
67 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;
1da177e4 79 }
ec26815a 80}
1da177e4 81
1da177e4 82/*
08e0e7c8 83 * clean up a cache manager call
1da177e4 84 */
08e0e7c8 85static void afs_cm_destructor(struct afs_call *call)
1da177e4 86{
08e0e7c8
DH
87 _enter("");
88
89 afs_put_server(call->server);
90 call->server = NULL;
91 kfree(call->buffer);
92 call->buffer = NULL;
ec26815a 93}
1da177e4 94
1da177e4 95/*
08e0e7c8 96 * allow the fileserver to see if the cache manager is still alive
1da177e4 97 */
08e0e7c8 98static void SRXAFSCB_CallBack(struct work_struct *work)
1da177e4 99{
08e0e7c8 100 struct afs_call *call = container_of(work, struct afs_call, work);
1da177e4 101
08e0e7c8 102 _enter("");
1da177e4 103
08e0e7c8
DH
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
108 * yet */
109 afs_send_empty_reply(call);
1da177e4 110
08e0e7c8
DH
111 afs_break_callbacks(call->server, call->count, call->request);
112 _leave("");
ec26815a 113}
1da177e4 114
1da177e4 115/*
08e0e7c8 116 * deliver request data to a CB.CallBack call
1da177e4 117 */
08e0e7c8
DH
118static int afs_deliver_cb_callback(struct afs_call *call, struct sk_buff *skb,
119 bool last)
1da177e4 120{
08e0e7c8
DH
121 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;
1da177e4 143 }
1da177e4 144
08e0e7c8
DH
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;
1da177e4 164 }
1da177e4 165
08e0e7c8
DH
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;
1da177e4
LT
180 }
181
08e0e7c8
DH
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 }
1da177e4 194
08e0e7c8
DH
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;
1da177e4 212 }
1da177e4 213
08e0e7c8
DH
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 }
1da177e4 222
08e0e7c8
DH
223 empty_cb_array:
224 call->offset = 0;
225 call->unmarshall++;
1da177e4 226
08e0e7c8
DH
227 case 5:
228 _debug("trailer");
229 if (skb->len != 0)
230 return -EBADMSG;
1da177e4
LT
231 break;
232 }
233
08e0e7c8
DH
234 if (!last)
235 return 0;
1da177e4 236
08e0e7c8 237 call->state = AFS_CALL_REPLYING;
1da177e4 238
08e0e7c8
DH
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);
243 if (!server)
244 return -ENOTCONN;
245 call->server = server;
246
247 INIT_WORK(&call->work, SRXAFSCB_CallBack);
248 schedule_work(&call->work);
249 return 0;
ec26815a 250}
1da177e4 251
1da177e4 252/*
08e0e7c8 253 * allow the fileserver to request callback state (re-)initialisation
1da177e4 254 */
08e0e7c8 255static void SRXAFSCB_InitCallBackState(struct work_struct *work)
1da177e4 256{
08e0e7c8 257 struct afs_call *call = container_of(work, struct afs_call, work);
1da177e4 258
08e0e7c8 259 _enter("{%p}", call->server);
1da177e4 260
08e0e7c8
DH
261 afs_init_callback_state(call->server);
262 afs_send_empty_reply(call);
263 _leave("");
ec26815a 264}
1da177e4 265
1da177e4 266/*
08e0e7c8 267 * deliver request data to a CB.InitCallBackState call
1da177e4 268 */
08e0e7c8
DH
269static int afs_deliver_cb_init_call_back_state(struct afs_call *call,
270 struct sk_buff *skb,
271 bool last)
1da177e4
LT
272{
273 struct afs_server *server;
08e0e7c8 274 struct in_addr addr;
1da177e4 275
08e0e7c8 276 _enter(",{%u},%d", skb->len, last);
1da177e4 277
08e0e7c8
DH
278 if (skb->len > 0)
279 return -EBADMSG;
280 if (!last)
281 return 0;
1da177e4 282
08e0e7c8
DH
283 /* no unmarshalling required */
284 call->state = AFS_CALL_REPLYING;
1da177e4 285
08e0e7c8
DH
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);
290 if (!server)
291 return -ENOTCONN;
292 call->server = server;
1da177e4 293
08e0e7c8
DH
294 INIT_WORK(&call->work, SRXAFSCB_InitCallBackState);
295 schedule_work(&call->work);
296 return 0;
297}
1da177e4 298
08e0e7c8
DH
299/*
300 * allow the fileserver to see if the cache manager is still alive
301 */
302static void SRXAFSCB_Probe(struct work_struct *work)
303{
304 struct afs_call *call = container_of(work, struct afs_call, work);
1da177e4 305
08e0e7c8
DH
306 _enter("");
307 afs_send_empty_reply(call);
308 _leave("");
309}
1da177e4 310
08e0e7c8
DH
311/*
312 * deliver request data to a CB.Probe call
313 */
314static int afs_deliver_cb_probe(struct afs_call *call, struct sk_buff *skb,
315 bool last)
316{
317 _enter(",{%u},%d", skb->len, last);
1da177e4 318
08e0e7c8
DH
319 if (skb->len > 0)
320 return -EBADMSG;
321 if (!last)
322 return 0;
1da177e4 323
08e0e7c8
DH
324 /* no unmarshalling required */
325 call->state = AFS_CALL_REPLYING;
1da177e4 326
08e0e7c8
DH
327 INIT_WORK(&call->work, SRXAFSCB_Probe);
328 schedule_work(&call->work);
329 return 0;
ec26815a 330}