]>
Commit | Line | Data |
---|---|---|
2874c5fd | 1 | // SPDX-License-Identifier: GPL-2.0-or-later |
ec26815a | 2 | /* AFS Cache Manager Service |
1da177e4 LT |
3 | * |
4 | * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved. | |
5 | * Written by David Howells (dhowells@redhat.com) | |
1da177e4 LT |
6 | */ |
7 | ||
8 | #include <linux/module.h> | |
9 | #include <linux/init.h> | |
5a0e3ad6 | 10 | #include <linux/slab.h> |
1da177e4 | 11 | #include <linux/sched.h> |
08e0e7c8 | 12 | #include <linux/ip.h> |
1da177e4 | 13 | #include "internal.h" |
08e0e7c8 | 14 | #include "afs_cm.h" |
35dbfba3 | 15 | #include "protocol_yfs.h" |
1da177e4 | 16 | |
d001648e DH |
17 | static int afs_deliver_cb_init_call_back_state(struct afs_call *); |
18 | static int afs_deliver_cb_init_call_back_state3(struct afs_call *); | |
19 | static int afs_deliver_cb_probe(struct afs_call *); | |
20 | static int afs_deliver_cb_callback(struct afs_call *); | |
21 | static int afs_deliver_cb_probe_uuid(struct afs_call *); | |
22 | static int afs_deliver_cb_tell_me_about_yourself(struct afs_call *); | |
08e0e7c8 | 23 | static void afs_cm_destructor(struct afs_call *); |
341f741f DH |
24 | static void SRXAFSCB_CallBack(struct work_struct *); |
25 | static void SRXAFSCB_InitCallBackState(struct work_struct *); | |
26 | static void SRXAFSCB_Probe(struct work_struct *); | |
27 | static void SRXAFSCB_ProbeUuid(struct work_struct *); | |
28 | static void SRXAFSCB_TellMeAboutYourself(struct work_struct *); | |
1da177e4 | 29 | |
35dbfba3 DH |
30 | static int afs_deliver_yfs_cb_callback(struct afs_call *); |
31 | ||
8e8d7f13 | 32 | #define CM_NAME(name) \ |
d2abfa86 | 33 | char afs_SRXCB##name##_name[] __tracepoint_string = \ |
8e8d7f13 DH |
34 | "CB." #name |
35 | ||
1da177e4 | 36 | /* |
08e0e7c8 | 37 | * CB.CallBack operation type |
1da177e4 | 38 | */ |
8e8d7f13 | 39 | static CM_NAME(CallBack); |
08e0e7c8 | 40 | static const struct afs_call_type afs_SRXCBCallBack = { |
8e8d7f13 | 41 | .name = afs_SRXCBCallBack_name, |
08e0e7c8 | 42 | .deliver = afs_deliver_cb_callback, |
08e0e7c8 | 43 | .destructor = afs_cm_destructor, |
341f741f | 44 | .work = SRXAFSCB_CallBack, |
08e0e7c8 | 45 | }; |
1da177e4 | 46 | |
1da177e4 | 47 | /* |
08e0e7c8 | 48 | * CB.InitCallBackState operation type |
1da177e4 | 49 | */ |
8e8d7f13 | 50 | static CM_NAME(InitCallBackState); |
08e0e7c8 | 51 | static const struct afs_call_type afs_SRXCBInitCallBackState = { |
8e8d7f13 | 52 | .name = afs_SRXCBInitCallBackState_name, |
08e0e7c8 | 53 | .deliver = afs_deliver_cb_init_call_back_state, |
08e0e7c8 | 54 | .destructor = afs_cm_destructor, |
341f741f | 55 | .work = SRXAFSCB_InitCallBackState, |
08e0e7c8 | 56 | }; |
1da177e4 | 57 | |
c35eccb1 DH |
58 | /* |
59 | * CB.InitCallBackState3 operation type | |
60 | */ | |
8e8d7f13 | 61 | static CM_NAME(InitCallBackState3); |
c35eccb1 | 62 | static const struct afs_call_type afs_SRXCBInitCallBackState3 = { |
8e8d7f13 | 63 | .name = afs_SRXCBInitCallBackState3_name, |
c35eccb1 | 64 | .deliver = afs_deliver_cb_init_call_back_state3, |
c35eccb1 | 65 | .destructor = afs_cm_destructor, |
341f741f | 66 | .work = SRXAFSCB_InitCallBackState, |
c35eccb1 DH |
67 | }; |
68 | ||
1da177e4 | 69 | /* |
08e0e7c8 | 70 | * CB.Probe operation type |
1da177e4 | 71 | */ |
8e8d7f13 | 72 | static CM_NAME(Probe); |
08e0e7c8 | 73 | static const struct afs_call_type afs_SRXCBProbe = { |
8e8d7f13 | 74 | .name = afs_SRXCBProbe_name, |
08e0e7c8 | 75 | .deliver = afs_deliver_cb_probe, |
08e0e7c8 | 76 | .destructor = afs_cm_destructor, |
341f741f | 77 | .work = SRXAFSCB_Probe, |
08e0e7c8 | 78 | }; |
1da177e4 | 79 | |
9396d496 DH |
80 | /* |
81 | * CB.ProbeUuid operation type | |
82 | */ | |
8e8d7f13 | 83 | static CM_NAME(ProbeUuid); |
9396d496 | 84 | static const struct afs_call_type afs_SRXCBProbeUuid = { |
8e8d7f13 | 85 | .name = afs_SRXCBProbeUuid_name, |
9396d496 | 86 | .deliver = afs_deliver_cb_probe_uuid, |
9396d496 | 87 | .destructor = afs_cm_destructor, |
341f741f | 88 | .work = SRXAFSCB_ProbeUuid, |
9396d496 DH |
89 | }; |
90 | ||
b908fe6b | 91 | /* |
7c80bcce | 92 | * CB.TellMeAboutYourself operation type |
b908fe6b | 93 | */ |
8e8d7f13 | 94 | static CM_NAME(TellMeAboutYourself); |
7c80bcce | 95 | static const struct afs_call_type afs_SRXCBTellMeAboutYourself = { |
8e8d7f13 | 96 | .name = afs_SRXCBTellMeAboutYourself_name, |
7c80bcce | 97 | .deliver = afs_deliver_cb_tell_me_about_yourself, |
b908fe6b | 98 | .destructor = afs_cm_destructor, |
341f741f | 99 | .work = SRXAFSCB_TellMeAboutYourself, |
b908fe6b DH |
100 | }; |
101 | ||
35dbfba3 DH |
102 | /* |
103 | * YFS CB.CallBack operation type | |
104 | */ | |
105 | static CM_NAME(YFS_CallBack); | |
106 | static const struct afs_call_type afs_SRXYFSCB_CallBack = { | |
107 | .name = afs_SRXCBYFS_CallBack_name, | |
108 | .deliver = afs_deliver_yfs_cb_callback, | |
109 | .destructor = afs_cm_destructor, | |
110 | .work = SRXAFSCB_CallBack, | |
111 | }; | |
112 | ||
1da177e4 | 113 | /* |
08e0e7c8 DH |
114 | * route an incoming cache manager call |
115 | * - return T if supported, F if not | |
1da177e4 | 116 | */ |
08e0e7c8 | 117 | bool afs_cm_incoming_call(struct afs_call *call) |
1da177e4 | 118 | { |
35dbfba3 | 119 | _enter("{%u, CB.OP %u}", call->service_id, call->operation_ID); |
08e0e7c8 | 120 | |
3bf0fb6f DH |
121 | call->epoch = rxrpc_kernel_get_epoch(call->net->socket, call->rxcall); |
122 | ||
50a2c953 | 123 | switch (call->operation_ID) { |
08e0e7c8 DH |
124 | case CBCallBack: |
125 | call->type = &afs_SRXCBCallBack; | |
126 | return true; | |
127 | case CBInitCallBackState: | |
128 | call->type = &afs_SRXCBInitCallBackState; | |
129 | return true; | |
c35eccb1 DH |
130 | case CBInitCallBackState3: |
131 | call->type = &afs_SRXCBInitCallBackState3; | |
132 | return true; | |
08e0e7c8 DH |
133 | case CBProbe: |
134 | call->type = &afs_SRXCBProbe; | |
135 | return true; | |
f4b3526d DH |
136 | case CBProbeUuid: |
137 | call->type = &afs_SRXCBProbeUuid; | |
138 | return true; | |
7c80bcce DH |
139 | case CBTellMeAboutYourself: |
140 | call->type = &afs_SRXCBTellMeAboutYourself; | |
b908fe6b | 141 | return true; |
35dbfba3 DH |
142 | case YFSCBCallBack: |
143 | if (call->service_id != YFS_CM_SERVICE) | |
144 | return false; | |
145 | call->type = &afs_SRXYFSCB_CallBack; | |
146 | return true; | |
08e0e7c8 DH |
147 | default: |
148 | return false; | |
1da177e4 | 149 | } |
ec26815a | 150 | } |
1da177e4 | 151 | |
3bf0fb6f DH |
152 | /* |
153 | * Record a probe to the cache manager from a server. | |
154 | */ | |
155 | static int afs_record_cm_probe(struct afs_call *call, struct afs_server *server) | |
156 | { | |
157 | _enter(""); | |
158 | ||
159 | if (test_bit(AFS_SERVER_FL_HAVE_EPOCH, &server->flags) && | |
f6cbb368 | 160 | !afs_is_probing_server(server)) { |
3bf0fb6f DH |
161 | if (server->cm_epoch == call->epoch) |
162 | return 0; | |
163 | ||
164 | if (!server->probe.said_rebooted) { | |
165 | pr_notice("kAFS: FS rebooted %pU\n", &server->uuid); | |
166 | server->probe.said_rebooted = true; | |
167 | } | |
168 | } | |
169 | ||
170 | spin_lock(&server->probe_lock); | |
171 | ||
69cf3978 | 172 | if (!test_and_set_bit(AFS_SERVER_FL_HAVE_EPOCH, &server->flags)) { |
3bf0fb6f DH |
173 | server->cm_epoch = call->epoch; |
174 | server->probe.cm_epoch = call->epoch; | |
175 | goto out; | |
176 | } | |
177 | ||
178 | if (server->probe.cm_probed && | |
179 | call->epoch != server->probe.cm_epoch && | |
180 | !server->probe.said_inconsistent) { | |
181 | pr_notice("kAFS: FS endpoints inconsistent %pU\n", | |
182 | &server->uuid); | |
183 | server->probe.said_inconsistent = true; | |
184 | } | |
185 | ||
186 | if (!server->probe.cm_probed || call->epoch == server->cm_epoch) | |
187 | server->probe.cm_epoch = server->cm_epoch; | |
188 | ||
189 | out: | |
190 | server->probe.cm_probed = true; | |
191 | spin_unlock(&server->probe_lock); | |
192 | return 0; | |
193 | } | |
194 | ||
195 | /* | |
196 | * Find the server record by peer address and record a probe to the cache | |
197 | * manager from a server. | |
198 | */ | |
199 | static int afs_find_cm_server_by_peer(struct afs_call *call) | |
200 | { | |
201 | struct sockaddr_rxrpc srx; | |
202 | struct afs_server *server; | |
203 | ||
204 | rxrpc_kernel_get_peer(call->net->socket, call->rxcall, &srx); | |
205 | ||
206 | server = afs_find_server(call->net, &srx); | |
207 | if (!server) { | |
208 | trace_afs_cm_no_server(call, &srx); | |
209 | return 0; | |
210 | } | |
211 | ||
ffba718e | 212 | call->server = server; |
3bf0fb6f DH |
213 | return afs_record_cm_probe(call, server); |
214 | } | |
215 | ||
216 | /* | |
217 | * Find the server record by server UUID and record a probe to the cache | |
218 | * manager from a server. | |
219 | */ | |
220 | static int afs_find_cm_server_by_uuid(struct afs_call *call, | |
221 | struct afs_uuid *uuid) | |
222 | { | |
223 | struct afs_server *server; | |
224 | ||
225 | rcu_read_lock(); | |
226 | server = afs_find_server_by_uuid(call->net, call->request); | |
227 | rcu_read_unlock(); | |
228 | if (!server) { | |
229 | trace_afs_cm_no_server_u(call, call->request); | |
230 | return 0; | |
231 | } | |
232 | ||
ffba718e | 233 | call->server = server; |
3bf0fb6f DH |
234 | return afs_record_cm_probe(call, server); |
235 | } | |
236 | ||
1da177e4 | 237 | /* |
428edade | 238 | * Clean up a cache manager call. |
1da177e4 | 239 | */ |
08e0e7c8 | 240 | static void afs_cm_destructor(struct afs_call *call) |
1da177e4 | 241 | { |
08e0e7c8 DH |
242 | kfree(call->buffer); |
243 | call->buffer = NULL; | |
ec26815a | 244 | } |
1da177e4 | 245 | |
dde9f095 DH |
246 | /* |
247 | * Abort a service call from within an action function. | |
248 | */ | |
249 | static void afs_abort_service_call(struct afs_call *call, u32 abort_code, int error, | |
250 | const char *why) | |
251 | { | |
252 | rxrpc_kernel_abort_call(call->net->socket, call->rxcall, | |
253 | abort_code, error, why); | |
254 | afs_set_call_complete(call, error, 0); | |
255 | } | |
256 | ||
1da177e4 | 257 | /* |
c435ee34 | 258 | * The server supplied a list of callbacks that it wanted to break. |
1da177e4 | 259 | */ |
08e0e7c8 | 260 | static void SRXAFSCB_CallBack(struct work_struct *work) |
1da177e4 | 261 | { |
08e0e7c8 | 262 | struct afs_call *call = container_of(work, struct afs_call, work); |
1da177e4 | 263 | |
08e0e7c8 | 264 | _enter(""); |
1da177e4 | 265 | |
428edade DH |
266 | /* We need to break the callbacks before sending the reply as the |
267 | * server holds up change visibility till it receives our reply so as | |
268 | * to maintain cache coherency. | |
269 | */ | |
45218193 | 270 | if (call->server) { |
977e5f8e DH |
271 | trace_afs_server(call->server, |
272 | atomic_read(&call->server->ref), | |
273 | atomic_read(&call->server->active), | |
45218193 | 274 | afs_server_trace_callback); |
ffba718e | 275 | afs_break_callbacks(call->server, call->count, call->request); |
45218193 | 276 | } |
428edade DH |
277 | |
278 | afs_send_empty_reply(call); | |
341f741f | 279 | afs_put_call(call); |
08e0e7c8 | 280 | _leave(""); |
ec26815a | 281 | } |
1da177e4 | 282 | |
1da177e4 | 283 | /* |
08e0e7c8 | 284 | * deliver request data to a CB.CallBack call |
1da177e4 | 285 | */ |
d001648e | 286 | static int afs_deliver_cb_callback(struct afs_call *call) |
1da177e4 | 287 | { |
5cf9dd55 | 288 | struct afs_callback_break *cb; |
08e0e7c8 | 289 | __be32 *bp; |
08e0e7c8 DH |
290 | int ret, loop; |
291 | ||
d001648e | 292 | _enter("{%u}", call->unmarshall); |
08e0e7c8 DH |
293 | |
294 | switch (call->unmarshall) { | |
295 | case 0: | |
12bdcf33 | 296 | afs_extract_to_tmp(call); |
08e0e7c8 DH |
297 | call->unmarshall++; |
298 | ||
299 | /* extract the FID array and its count in two steps */ | |
e690c9e3 | 300 | /* fall through */ |
08e0e7c8 DH |
301 | case 1: |
302 | _debug("extract FID count"); | |
12bdcf33 | 303 | ret = afs_extract_data(call, true); |
372ee163 DH |
304 | if (ret < 0) |
305 | return ret; | |
1da177e4 | 306 | |
08e0e7c8 DH |
307 | call->count = ntohl(call->tmp); |
308 | _debug("FID count: %u", call->count); | |
309 | if (call->count > AFSCBMAX) | |
7126ead9 | 310 | return afs_protocol_error(call, afs_eproto_cb_fid_count); |
08e0e7c8 | 311 | |
6da2ec56 KC |
312 | call->buffer = kmalloc(array3_size(call->count, 3, 4), |
313 | GFP_KERNEL); | |
08e0e7c8 DH |
314 | if (!call->buffer) |
315 | return -ENOMEM; | |
12bdcf33 | 316 | afs_extract_to_buf(call, call->count * 3 * 4); |
08e0e7c8 DH |
317 | call->unmarshall++; |
318 | ||
e690c9e3 | 319 | /* Fall through */ |
08e0e7c8 DH |
320 | case 2: |
321 | _debug("extract FID array"); | |
12bdcf33 | 322 | ret = afs_extract_data(call, true); |
372ee163 DH |
323 | if (ret < 0) |
324 | return ret; | |
1da177e4 | 325 | |
08e0e7c8 DH |
326 | _debug("unmarshall FID array"); |
327 | call->request = kcalloc(call->count, | |
5cf9dd55 | 328 | sizeof(struct afs_callback_break), |
08e0e7c8 DH |
329 | GFP_KERNEL); |
330 | if (!call->request) | |
331 | return -ENOMEM; | |
332 | ||
333 | cb = call->request; | |
334 | bp = call->buffer; | |
335 | for (loop = call->count; loop > 0; loop--, cb++) { | |
336 | cb->fid.vid = ntohl(*bp++); | |
337 | cb->fid.vnode = ntohl(*bp++); | |
338 | cb->fid.unique = ntohl(*bp++); | |
1da177e4 LT |
339 | } |
340 | ||
12bdcf33 | 341 | afs_extract_to_tmp(call); |
08e0e7c8 DH |
342 | call->unmarshall++; |
343 | ||
344 | /* extract the callback array and its count in two steps */ | |
e690c9e3 | 345 | /* fall through */ |
08e0e7c8 DH |
346 | case 3: |
347 | _debug("extract CB count"); | |
12bdcf33 | 348 | ret = afs_extract_data(call, true); |
372ee163 DH |
349 | if (ret < 0) |
350 | return ret; | |
1da177e4 | 351 | |
bcd89270 MD |
352 | call->count2 = ntohl(call->tmp); |
353 | _debug("CB count: %u", call->count2); | |
354 | if (call->count2 != call->count && call->count2 != 0) | |
7126ead9 | 355 | return afs_protocol_error(call, afs_eproto_cb_count); |
fc276122 DH |
356 | call->iter = &call->def_iter; |
357 | iov_iter_discard(&call->def_iter, READ, call->count2 * 3 * 4); | |
08e0e7c8 | 358 | call->unmarshall++; |
08e0e7c8 | 359 | |
e690c9e3 | 360 | /* Fall through */ |
08e0e7c8 | 361 | case 4: |
06aeb297 | 362 | _debug("extract discard %zu/%u", |
fc276122 | 363 | iov_iter_count(call->iter), call->count2 * 3 * 4); |
06aeb297 | 364 | |
12bdcf33 | 365 | ret = afs_extract_data(call, false); |
372ee163 DH |
366 | if (ret < 0) |
367 | return ret; | |
1da177e4 | 368 | |
08e0e7c8 | 369 | call->unmarshall++; |
d001648e | 370 | case 5: |
1da177e4 LT |
371 | break; |
372 | } | |
373 | ||
98bf40cd | 374 | if (!afs_check_call_state(call, AFS_CALL_SV_REPLYING)) |
f51375cd | 375 | return afs_io_error(call, afs_io_error_cm_reply); |
1da177e4 | 376 | |
08e0e7c8 DH |
377 | /* we'll need the file server record as that tells us which set of |
378 | * vnodes to operate upon */ | |
3bf0fb6f | 379 | return afs_find_cm_server_by_peer(call); |
ec26815a | 380 | } |
1da177e4 | 381 | |
1da177e4 | 382 | /* |
08e0e7c8 | 383 | * allow the fileserver to request callback state (re-)initialisation |
1da177e4 | 384 | */ |
08e0e7c8 | 385 | static void SRXAFSCB_InitCallBackState(struct work_struct *work) |
1da177e4 | 386 | { |
08e0e7c8 | 387 | struct afs_call *call = container_of(work, struct afs_call, work); |
1da177e4 | 388 | |
ffba718e | 389 | _enter("{%p}", call->server); |
1da177e4 | 390 | |
ffba718e DH |
391 | if (call->server) |
392 | afs_init_callback_state(call->server); | |
08e0e7c8 | 393 | afs_send_empty_reply(call); |
341f741f | 394 | afs_put_call(call); |
08e0e7c8 | 395 | _leave(""); |
ec26815a | 396 | } |
1da177e4 | 397 | |
1da177e4 | 398 | /* |
08e0e7c8 | 399 | * deliver request data to a CB.InitCallBackState call |
1da177e4 | 400 | */ |
d001648e | 401 | static int afs_deliver_cb_init_call_back_state(struct afs_call *call) |
1da177e4 | 402 | { |
372ee163 | 403 | int ret; |
1da177e4 | 404 | |
d001648e | 405 | _enter(""); |
1da177e4 | 406 | |
12bdcf33 DH |
407 | afs_extract_discard(call, 0); |
408 | ret = afs_extract_data(call, false); | |
372ee163 DH |
409 | if (ret < 0) |
410 | return ret; | |
1da177e4 | 411 | |
08e0e7c8 DH |
412 | /* we'll need the file server record as that tells us which set of |
413 | * vnodes to operate upon */ | |
3bf0fb6f | 414 | return afs_find_cm_server_by_peer(call); |
08e0e7c8 | 415 | } |
1da177e4 | 416 | |
c35eccb1 DH |
417 | /* |
418 | * deliver request data to a CB.InitCallBackState3 call | |
419 | */ | |
d001648e | 420 | static int afs_deliver_cb_init_call_back_state3(struct afs_call *call) |
c35eccb1 | 421 | { |
41bb26f8 | 422 | struct afs_uuid *r; |
d001648e DH |
423 | unsigned loop; |
424 | __be32 *b; | |
425 | int ret; | |
c35eccb1 | 426 | |
d001648e | 427 | _enter(""); |
c35eccb1 | 428 | |
d001648e DH |
429 | _enter("{%u}", call->unmarshall); |
430 | ||
431 | switch (call->unmarshall) { | |
432 | case 0: | |
6da2ec56 | 433 | call->buffer = kmalloc_array(11, sizeof(__be32), GFP_KERNEL); |
d001648e DH |
434 | if (!call->buffer) |
435 | return -ENOMEM; | |
12bdcf33 | 436 | afs_extract_to_buf(call, 11 * sizeof(__be32)); |
d001648e DH |
437 | call->unmarshall++; |
438 | ||
e690c9e3 | 439 | /* Fall through */ |
d001648e DH |
440 | case 1: |
441 | _debug("extract UUID"); | |
12bdcf33 | 442 | ret = afs_extract_data(call, false); |
d001648e DH |
443 | switch (ret) { |
444 | case 0: break; | |
445 | case -EAGAIN: return 0; | |
446 | default: return ret; | |
447 | } | |
448 | ||
449 | _debug("unmarshall UUID"); | |
41bb26f8 | 450 | call->request = kmalloc(sizeof(struct afs_uuid), GFP_KERNEL); |
d001648e DH |
451 | if (!call->request) |
452 | return -ENOMEM; | |
453 | ||
454 | b = call->buffer; | |
455 | r = call->request; | |
ff548773 DH |
456 | r->time_low = b[0]; |
457 | r->time_mid = htons(ntohl(b[1])); | |
458 | r->time_hi_and_version = htons(ntohl(b[2])); | |
d001648e DH |
459 | r->clock_seq_hi_and_reserved = ntohl(b[3]); |
460 | r->clock_seq_low = ntohl(b[4]); | |
461 | ||
462 | for (loop = 0; loop < 6; loop++) | |
463 | r->node[loop] = ntohl(b[loop + 5]); | |
464 | ||
d001648e DH |
465 | call->unmarshall++; |
466 | ||
467 | case 2: | |
468 | break; | |
469 | } | |
c35eccb1 | 470 | |
98bf40cd | 471 | if (!afs_check_call_state(call, AFS_CALL_SV_REPLYING)) |
f51375cd | 472 | return afs_io_error(call, afs_io_error_cm_reply); |
c35eccb1 DH |
473 | |
474 | /* we'll need the file server record as that tells us which set of | |
475 | * vnodes to operate upon */ | |
3bf0fb6f | 476 | return afs_find_cm_server_by_uuid(call, call->request); |
c35eccb1 DH |
477 | } |
478 | ||
08e0e7c8 DH |
479 | /* |
480 | * allow the fileserver to see if the cache manager is still alive | |
481 | */ | |
482 | static void SRXAFSCB_Probe(struct work_struct *work) | |
483 | { | |
484 | struct afs_call *call = container_of(work, struct afs_call, work); | |
1da177e4 | 485 | |
08e0e7c8 DH |
486 | _enter(""); |
487 | afs_send_empty_reply(call); | |
341f741f | 488 | afs_put_call(call); |
08e0e7c8 DH |
489 | _leave(""); |
490 | } | |
1da177e4 | 491 | |
08e0e7c8 DH |
492 | /* |
493 | * deliver request data to a CB.Probe call | |
494 | */ | |
d001648e | 495 | static int afs_deliver_cb_probe(struct afs_call *call) |
08e0e7c8 | 496 | { |
372ee163 DH |
497 | int ret; |
498 | ||
d001648e | 499 | _enter(""); |
1da177e4 | 500 | |
12bdcf33 DH |
501 | afs_extract_discard(call, 0); |
502 | ret = afs_extract_data(call, false); | |
372ee163 DH |
503 | if (ret < 0) |
504 | return ret; | |
1da177e4 | 505 | |
98bf40cd | 506 | if (!afs_check_call_state(call, AFS_CALL_SV_REPLYING)) |
f51375cd | 507 | return afs_io_error(call, afs_io_error_cm_reply); |
3bf0fb6f | 508 | return afs_find_cm_server_by_peer(call); |
ec26815a | 509 | } |
b908fe6b | 510 | |
9396d496 DH |
511 | /* |
512 | * allow the fileserver to quickly find out if the fileserver has been rebooted | |
513 | */ | |
514 | static void SRXAFSCB_ProbeUuid(struct work_struct *work) | |
515 | { | |
516 | struct afs_call *call = container_of(work, struct afs_call, work); | |
41bb26f8 | 517 | struct afs_uuid *r = call->request; |
9396d496 | 518 | |
9396d496 DH |
519 | _enter(""); |
520 | ||
f044c884 | 521 | if (memcmp(r, &call->net->uuid, sizeof(call->net->uuid)) == 0) |
2067b2b3 | 522 | afs_send_empty_reply(call); |
9396d496 | 523 | else |
dde9f095 | 524 | afs_abort_service_call(call, 1, 1, "K-1"); |
9396d496 | 525 | |
341f741f | 526 | afs_put_call(call); |
9396d496 DH |
527 | _leave(""); |
528 | } | |
529 | ||
530 | /* | |
531 | * deliver request data to a CB.ProbeUuid call | |
532 | */ | |
d001648e | 533 | static int afs_deliver_cb_probe_uuid(struct afs_call *call) |
9396d496 | 534 | { |
41bb26f8 | 535 | struct afs_uuid *r; |
9396d496 DH |
536 | unsigned loop; |
537 | __be32 *b; | |
538 | int ret; | |
539 | ||
d001648e | 540 | _enter("{%u}", call->unmarshall); |
9396d496 DH |
541 | |
542 | switch (call->unmarshall) { | |
543 | case 0: | |
6da2ec56 | 544 | call->buffer = kmalloc_array(11, sizeof(__be32), GFP_KERNEL); |
9396d496 DH |
545 | if (!call->buffer) |
546 | return -ENOMEM; | |
12bdcf33 | 547 | afs_extract_to_buf(call, 11 * sizeof(__be32)); |
9396d496 DH |
548 | call->unmarshall++; |
549 | ||
e690c9e3 | 550 | /* Fall through */ |
9396d496 DH |
551 | case 1: |
552 | _debug("extract UUID"); | |
12bdcf33 | 553 | ret = afs_extract_data(call, false); |
9396d496 DH |
554 | switch (ret) { |
555 | case 0: break; | |
556 | case -EAGAIN: return 0; | |
557 | default: return ret; | |
558 | } | |
559 | ||
560 | _debug("unmarshall UUID"); | |
41bb26f8 | 561 | call->request = kmalloc(sizeof(struct afs_uuid), GFP_KERNEL); |
9396d496 DH |
562 | if (!call->request) |
563 | return -ENOMEM; | |
564 | ||
565 | b = call->buffer; | |
566 | r = call->request; | |
fe342cf7 DH |
567 | r->time_low = b[0]; |
568 | r->time_mid = htons(ntohl(b[1])); | |
569 | r->time_hi_and_version = htons(ntohl(b[2])); | |
9396d496 DH |
570 | r->clock_seq_hi_and_reserved = ntohl(b[3]); |
571 | r->clock_seq_low = ntohl(b[4]); | |
572 | ||
573 | for (loop = 0; loop < 6; loop++) | |
574 | r->node[loop] = ntohl(b[loop + 5]); | |
575 | ||
9396d496 DH |
576 | call->unmarshall++; |
577 | ||
578 | case 2: | |
9396d496 DH |
579 | break; |
580 | } | |
581 | ||
98bf40cd | 582 | if (!afs_check_call_state(call, AFS_CALL_SV_REPLYING)) |
f51375cd | 583 | return afs_io_error(call, afs_io_error_cm_reply); |
3bf0fb6f | 584 | return afs_find_cm_server_by_uuid(call, call->request); |
9396d496 DH |
585 | } |
586 | ||
b908fe6b DH |
587 | /* |
588 | * allow the fileserver to ask about the cache manager's capabilities | |
589 | */ | |
7c80bcce | 590 | static void SRXAFSCB_TellMeAboutYourself(struct work_struct *work) |
b908fe6b | 591 | { |
b908fe6b | 592 | struct afs_call *call = container_of(work, struct afs_call, work); |
35ebfc22 | 593 | int loop; |
b908fe6b DH |
594 | |
595 | struct { | |
596 | struct /* InterfaceAddr */ { | |
597 | __be32 nifs; | |
598 | __be32 uuid[11]; | |
599 | __be32 ifaddr[32]; | |
600 | __be32 netmask[32]; | |
601 | __be32 mtu[32]; | |
602 | } ia; | |
603 | struct /* Capabilities */ { | |
604 | __be32 capcount; | |
605 | __be32 caps[1]; | |
606 | } cap; | |
607 | } reply; | |
608 | ||
609 | _enter(""); | |
610 | ||
b908fe6b | 611 | memset(&reply, 0, sizeof(reply)); |
b908fe6b | 612 | |
f044c884 DH |
613 | reply.ia.uuid[0] = call->net->uuid.time_low; |
614 | reply.ia.uuid[1] = htonl(ntohs(call->net->uuid.time_mid)); | |
615 | reply.ia.uuid[2] = htonl(ntohs(call->net->uuid.time_hi_and_version)); | |
616 | reply.ia.uuid[3] = htonl((s8) call->net->uuid.clock_seq_hi_and_reserved); | |
617 | reply.ia.uuid[4] = htonl((s8) call->net->uuid.clock_seq_low); | |
b908fe6b | 618 | for (loop = 0; loop < 6; loop++) |
f044c884 | 619 | reply.ia.uuid[loop + 5] = htonl((s8) call->net->uuid.node[loop]); |
b908fe6b | 620 | |
b908fe6b DH |
621 | reply.cap.capcount = htonl(1); |
622 | reply.cap.caps[0] = htonl(AFS_CAP_ERROR_TRANSLATION); | |
623 | afs_send_simple_reply(call, &reply, sizeof(reply)); | |
341f741f | 624 | afs_put_call(call); |
b908fe6b DH |
625 | _leave(""); |
626 | } | |
627 | ||
628 | /* | |
7c80bcce | 629 | * deliver request data to a CB.TellMeAboutYourself call |
b908fe6b | 630 | */ |
d001648e | 631 | static int afs_deliver_cb_tell_me_about_yourself(struct afs_call *call) |
b908fe6b | 632 | { |
372ee163 DH |
633 | int ret; |
634 | ||
d001648e | 635 | _enter(""); |
b908fe6b | 636 | |
12bdcf33 DH |
637 | afs_extract_discard(call, 0); |
638 | ret = afs_extract_data(call, false); | |
372ee163 DH |
639 | if (ret < 0) |
640 | return ret; | |
b908fe6b | 641 | |
98bf40cd | 642 | if (!afs_check_call_state(call, AFS_CALL_SV_REPLYING)) |
f51375cd | 643 | return afs_io_error(call, afs_io_error_cm_reply); |
3bf0fb6f | 644 | return afs_find_cm_server_by_peer(call); |
b908fe6b | 645 | } |
35dbfba3 DH |
646 | |
647 | /* | |
648 | * deliver request data to a YFS CB.CallBack call | |
649 | */ | |
650 | static int afs_deliver_yfs_cb_callback(struct afs_call *call) | |
651 | { | |
652 | struct afs_callback_break *cb; | |
35dbfba3 DH |
653 | struct yfs_xdr_YFSFid *bp; |
654 | size_t size; | |
655 | int ret, loop; | |
656 | ||
657 | _enter("{%u}", call->unmarshall); | |
658 | ||
659 | switch (call->unmarshall) { | |
660 | case 0: | |
661 | afs_extract_to_tmp(call); | |
662 | call->unmarshall++; | |
663 | ||
664 | /* extract the FID array and its count in two steps */ | |
e690c9e3 | 665 | /* Fall through */ |
35dbfba3 DH |
666 | case 1: |
667 | _debug("extract FID count"); | |
668 | ret = afs_extract_data(call, true); | |
669 | if (ret < 0) | |
670 | return ret; | |
671 | ||
672 | call->count = ntohl(call->tmp); | |
673 | _debug("FID count: %u", call->count); | |
674 | if (call->count > YFSCBMAX) | |
7126ead9 | 675 | return afs_protocol_error(call, afs_eproto_cb_fid_count); |
35dbfba3 DH |
676 | |
677 | size = array_size(call->count, sizeof(struct yfs_xdr_YFSFid)); | |
678 | call->buffer = kmalloc(size, GFP_KERNEL); | |
679 | if (!call->buffer) | |
680 | return -ENOMEM; | |
681 | afs_extract_to_buf(call, size); | |
682 | call->unmarshall++; | |
683 | ||
e690c9e3 | 684 | /* Fall through */ |
35dbfba3 DH |
685 | case 2: |
686 | _debug("extract FID array"); | |
687 | ret = afs_extract_data(call, false); | |
688 | if (ret < 0) | |
689 | return ret; | |
690 | ||
691 | _debug("unmarshall FID array"); | |
692 | call->request = kcalloc(call->count, | |
693 | sizeof(struct afs_callback_break), | |
694 | GFP_KERNEL); | |
695 | if (!call->request) | |
696 | return -ENOMEM; | |
697 | ||
698 | cb = call->request; | |
699 | bp = call->buffer; | |
700 | for (loop = call->count; loop > 0; loop--, cb++) { | |
701 | cb->fid.vid = xdr_to_u64(bp->volume); | |
702 | cb->fid.vnode = xdr_to_u64(bp->vnode.lo); | |
703 | cb->fid.vnode_hi = ntohl(bp->vnode.hi); | |
704 | cb->fid.unique = ntohl(bp->vnode.unique); | |
705 | bp++; | |
706 | } | |
707 | ||
708 | afs_extract_to_tmp(call); | |
709 | call->unmarshall++; | |
710 | ||
711 | case 3: | |
712 | break; | |
713 | } | |
714 | ||
715 | if (!afs_check_call_state(call, AFS_CALL_SV_REPLYING)) | |
716 | return afs_io_error(call, afs_io_error_cm_reply); | |
717 | ||
718 | /* We'll need the file server record as that tells us which set of | |
719 | * vnodes to operate upon. | |
720 | */ | |
3bf0fb6f | 721 | return afs_find_cm_server_by_peer(call); |
35dbfba3 | 722 | } |