]>
Commit | Line | Data |
---|---|---|
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 | 19 | struct workqueue_struct *afs_cm_workqueue; |
1da177e4 | 20 | |
08e0e7c8 DH |
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 *); | |
1da177e4 | 26 | |
1da177e4 | 27 | /* |
08e0e7c8 | 28 | * CB.CallBack operation type |
1da177e4 | 29 | */ |
08e0e7c8 | 30 | static 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 | 40 | static 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 | 50 | static 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 | 61 | bool 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 | 85 | static 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 | 98 | static 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 |
118 | static 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 | 255 | static 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 |
269 | static 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 | */ | |
302 | static 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 | */ | |
314 | static 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 | } |