]>
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) && | |
160 | !test_bit(AFS_SERVER_FL_PROBING, &server->flags)) { | |
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 DH |
270 | if (call->server) { |
271 | trace_afs_server(call->server, atomic_read(&call->server->usage), | |
272 | afs_server_trace_callback); | |
ffba718e | 273 | afs_break_callbacks(call->server, call->count, call->request); |
45218193 | 274 | } |
428edade DH |
275 | |
276 | afs_send_empty_reply(call); | |
341f741f | 277 | afs_put_call(call); |
08e0e7c8 | 278 | _leave(""); |
ec26815a | 279 | } |
1da177e4 | 280 | |
1da177e4 | 281 | /* |
08e0e7c8 | 282 | * deliver request data to a CB.CallBack call |
1da177e4 | 283 | */ |
d001648e | 284 | static int afs_deliver_cb_callback(struct afs_call *call) |
1da177e4 | 285 | { |
5cf9dd55 | 286 | struct afs_callback_break *cb; |
08e0e7c8 | 287 | __be32 *bp; |
08e0e7c8 DH |
288 | int ret, loop; |
289 | ||
d001648e | 290 | _enter("{%u}", call->unmarshall); |
08e0e7c8 DH |
291 | |
292 | switch (call->unmarshall) { | |
293 | case 0: | |
12bdcf33 | 294 | afs_extract_to_tmp(call); |
08e0e7c8 DH |
295 | call->unmarshall++; |
296 | ||
297 | /* extract the FID array and its count in two steps */ | |
e690c9e3 | 298 | /* fall through */ |
08e0e7c8 DH |
299 | case 1: |
300 | _debug("extract FID count"); | |
12bdcf33 | 301 | ret = afs_extract_data(call, true); |
372ee163 DH |
302 | if (ret < 0) |
303 | return ret; | |
1da177e4 | 304 | |
08e0e7c8 DH |
305 | call->count = ntohl(call->tmp); |
306 | _debug("FID count: %u", call->count); | |
307 | if (call->count > AFSCBMAX) | |
160cb957 DH |
308 | return afs_protocol_error(call, -EBADMSG, |
309 | afs_eproto_cb_fid_count); | |
08e0e7c8 | 310 | |
6da2ec56 KC |
311 | call->buffer = kmalloc(array3_size(call->count, 3, 4), |
312 | GFP_KERNEL); | |
08e0e7c8 DH |
313 | if (!call->buffer) |
314 | return -ENOMEM; | |
12bdcf33 | 315 | afs_extract_to_buf(call, call->count * 3 * 4); |
08e0e7c8 DH |
316 | call->unmarshall++; |
317 | ||
e690c9e3 | 318 | /* Fall through */ |
08e0e7c8 DH |
319 | case 2: |
320 | _debug("extract FID array"); | |
12bdcf33 | 321 | ret = afs_extract_data(call, true); |
372ee163 DH |
322 | if (ret < 0) |
323 | return ret; | |
1da177e4 | 324 | |
08e0e7c8 DH |
325 | _debug("unmarshall FID array"); |
326 | call->request = kcalloc(call->count, | |
5cf9dd55 | 327 | sizeof(struct afs_callback_break), |
08e0e7c8 DH |
328 | GFP_KERNEL); |
329 | if (!call->request) | |
330 | return -ENOMEM; | |
331 | ||
332 | cb = call->request; | |
333 | bp = call->buffer; | |
334 | for (loop = call->count; loop > 0; loop--, cb++) { | |
335 | cb->fid.vid = ntohl(*bp++); | |
336 | cb->fid.vnode = ntohl(*bp++); | |
337 | cb->fid.unique = ntohl(*bp++); | |
1da177e4 LT |
338 | } |
339 | ||
12bdcf33 | 340 | afs_extract_to_tmp(call); |
08e0e7c8 DH |
341 | call->unmarshall++; |
342 | ||
343 | /* extract the callback array and its count in two steps */ | |
e690c9e3 | 344 | /* fall through */ |
08e0e7c8 DH |
345 | case 3: |
346 | _debug("extract CB count"); | |
12bdcf33 | 347 | ret = afs_extract_data(call, true); |
372ee163 DH |
348 | if (ret < 0) |
349 | return ret; | |
1da177e4 | 350 | |
bcd89270 MD |
351 | call->count2 = ntohl(call->tmp); |
352 | _debug("CB count: %u", call->count2); | |
353 | if (call->count2 != call->count && call->count2 != 0) | |
160cb957 DH |
354 | return afs_protocol_error(call, -EBADMSG, |
355 | 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) | |
675 | return afs_protocol_error(call, -EBADMSG, | |
676 | afs_eproto_cb_fid_count); | |
677 | ||
678 | size = array_size(call->count, sizeof(struct yfs_xdr_YFSFid)); | |
679 | call->buffer = kmalloc(size, GFP_KERNEL); | |
680 | if (!call->buffer) | |
681 | return -ENOMEM; | |
682 | afs_extract_to_buf(call, size); | |
683 | call->unmarshall++; | |
684 | ||
e690c9e3 | 685 | /* Fall through */ |
35dbfba3 DH |
686 | case 2: |
687 | _debug("extract FID array"); | |
688 | ret = afs_extract_data(call, false); | |
689 | if (ret < 0) | |
690 | return ret; | |
691 | ||
692 | _debug("unmarshall FID array"); | |
693 | call->request = kcalloc(call->count, | |
694 | sizeof(struct afs_callback_break), | |
695 | GFP_KERNEL); | |
696 | if (!call->request) | |
697 | return -ENOMEM; | |
698 | ||
699 | cb = call->request; | |
700 | bp = call->buffer; | |
701 | for (loop = call->count; loop > 0; loop--, cb++) { | |
702 | cb->fid.vid = xdr_to_u64(bp->volume); | |
703 | cb->fid.vnode = xdr_to_u64(bp->vnode.lo); | |
704 | cb->fid.vnode_hi = ntohl(bp->vnode.hi); | |
705 | cb->fid.unique = ntohl(bp->vnode.unique); | |
706 | bp++; | |
707 | } | |
708 | ||
709 | afs_extract_to_tmp(call); | |
710 | call->unmarshall++; | |
711 | ||
712 | case 3: | |
713 | break; | |
714 | } | |
715 | ||
716 | if (!afs_check_call_state(call, AFS_CALL_SV_REPLYING)) | |
717 | return afs_io_error(call, afs_io_error_cm_reply); | |
718 | ||
719 | /* We'll need the file server record as that tells us which set of | |
720 | * vnodes to operate upon. | |
721 | */ | |
3bf0fb6f | 722 | return afs_find_cm_server_by_peer(call); |
35dbfba3 | 723 | } |