]>
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 | ||
172 | if (!test_bit(AFS_SERVER_FL_HAVE_EPOCH, &server->flags)) { | |
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 | |
1da177e4 | 246 | /* |
c435ee34 | 247 | * The server supplied a list of callbacks that it wanted to break. |
1da177e4 | 248 | */ |
08e0e7c8 | 249 | static void SRXAFSCB_CallBack(struct work_struct *work) |
1da177e4 | 250 | { |
08e0e7c8 | 251 | struct afs_call *call = container_of(work, struct afs_call, work); |
1da177e4 | 252 | |
08e0e7c8 | 253 | _enter(""); |
1da177e4 | 254 | |
428edade DH |
255 | /* We need to break the callbacks before sending the reply as the |
256 | * server holds up change visibility till it receives our reply so as | |
257 | * to maintain cache coherency. | |
258 | */ | |
45218193 DH |
259 | if (call->server) { |
260 | trace_afs_server(call->server, atomic_read(&call->server->usage), | |
261 | afs_server_trace_callback); | |
ffba718e | 262 | afs_break_callbacks(call->server, call->count, call->request); |
45218193 | 263 | } |
428edade DH |
264 | |
265 | afs_send_empty_reply(call); | |
341f741f | 266 | afs_put_call(call); |
08e0e7c8 | 267 | _leave(""); |
ec26815a | 268 | } |
1da177e4 | 269 | |
1da177e4 | 270 | /* |
08e0e7c8 | 271 | * deliver request data to a CB.CallBack call |
1da177e4 | 272 | */ |
d001648e | 273 | static int afs_deliver_cb_callback(struct afs_call *call) |
1da177e4 | 274 | { |
5cf9dd55 | 275 | struct afs_callback_break *cb; |
08e0e7c8 | 276 | __be32 *bp; |
08e0e7c8 DH |
277 | int ret, loop; |
278 | ||
d001648e | 279 | _enter("{%u}", call->unmarshall); |
08e0e7c8 DH |
280 | |
281 | switch (call->unmarshall) { | |
282 | case 0: | |
12bdcf33 | 283 | afs_extract_to_tmp(call); |
08e0e7c8 DH |
284 | call->unmarshall++; |
285 | ||
286 | /* extract the FID array and its count in two steps */ | |
e690c9e3 | 287 | /* fall through */ |
08e0e7c8 DH |
288 | case 1: |
289 | _debug("extract FID count"); | |
12bdcf33 | 290 | ret = afs_extract_data(call, true); |
372ee163 DH |
291 | if (ret < 0) |
292 | return ret; | |
1da177e4 | 293 | |
08e0e7c8 DH |
294 | call->count = ntohl(call->tmp); |
295 | _debug("FID count: %u", call->count); | |
296 | if (call->count > AFSCBMAX) | |
160cb957 DH |
297 | return afs_protocol_error(call, -EBADMSG, |
298 | afs_eproto_cb_fid_count); | |
08e0e7c8 | 299 | |
6da2ec56 KC |
300 | call->buffer = kmalloc(array3_size(call->count, 3, 4), |
301 | GFP_KERNEL); | |
08e0e7c8 DH |
302 | if (!call->buffer) |
303 | return -ENOMEM; | |
12bdcf33 | 304 | afs_extract_to_buf(call, call->count * 3 * 4); |
08e0e7c8 DH |
305 | call->unmarshall++; |
306 | ||
e690c9e3 | 307 | /* Fall through */ |
08e0e7c8 DH |
308 | case 2: |
309 | _debug("extract FID array"); | |
12bdcf33 | 310 | ret = afs_extract_data(call, true); |
372ee163 DH |
311 | if (ret < 0) |
312 | return ret; | |
1da177e4 | 313 | |
08e0e7c8 DH |
314 | _debug("unmarshall FID array"); |
315 | call->request = kcalloc(call->count, | |
5cf9dd55 | 316 | sizeof(struct afs_callback_break), |
08e0e7c8 DH |
317 | GFP_KERNEL); |
318 | if (!call->request) | |
319 | return -ENOMEM; | |
320 | ||
321 | cb = call->request; | |
322 | bp = call->buffer; | |
323 | for (loop = call->count; loop > 0; loop--, cb++) { | |
324 | cb->fid.vid = ntohl(*bp++); | |
325 | cb->fid.vnode = ntohl(*bp++); | |
326 | cb->fid.unique = ntohl(*bp++); | |
1da177e4 LT |
327 | } |
328 | ||
12bdcf33 | 329 | afs_extract_to_tmp(call); |
08e0e7c8 DH |
330 | call->unmarshall++; |
331 | ||
332 | /* extract the callback array and its count in two steps */ | |
e690c9e3 | 333 | /* fall through */ |
08e0e7c8 DH |
334 | case 3: |
335 | _debug("extract CB count"); | |
12bdcf33 | 336 | ret = afs_extract_data(call, true); |
372ee163 DH |
337 | if (ret < 0) |
338 | return ret; | |
1da177e4 | 339 | |
bcd89270 MD |
340 | call->count2 = ntohl(call->tmp); |
341 | _debug("CB count: %u", call->count2); | |
342 | if (call->count2 != call->count && call->count2 != 0) | |
160cb957 DH |
343 | return afs_protocol_error(call, -EBADMSG, |
344 | afs_eproto_cb_count); | |
fc276122 DH |
345 | call->iter = &call->def_iter; |
346 | iov_iter_discard(&call->def_iter, READ, call->count2 * 3 * 4); | |
08e0e7c8 | 347 | call->unmarshall++; |
08e0e7c8 | 348 | |
e690c9e3 | 349 | /* Fall through */ |
08e0e7c8 | 350 | case 4: |
06aeb297 | 351 | _debug("extract discard %zu/%u", |
fc276122 | 352 | iov_iter_count(call->iter), call->count2 * 3 * 4); |
06aeb297 | 353 | |
12bdcf33 | 354 | ret = afs_extract_data(call, false); |
372ee163 DH |
355 | if (ret < 0) |
356 | return ret; | |
1da177e4 | 357 | |
08e0e7c8 | 358 | call->unmarshall++; |
d001648e | 359 | case 5: |
1da177e4 LT |
360 | break; |
361 | } | |
362 | ||
98bf40cd | 363 | if (!afs_check_call_state(call, AFS_CALL_SV_REPLYING)) |
f51375cd | 364 | return afs_io_error(call, afs_io_error_cm_reply); |
1da177e4 | 365 | |
08e0e7c8 DH |
366 | /* we'll need the file server record as that tells us which set of |
367 | * vnodes to operate upon */ | |
3bf0fb6f | 368 | return afs_find_cm_server_by_peer(call); |
ec26815a | 369 | } |
1da177e4 | 370 | |
1da177e4 | 371 | /* |
08e0e7c8 | 372 | * allow the fileserver to request callback state (re-)initialisation |
1da177e4 | 373 | */ |
08e0e7c8 | 374 | static void SRXAFSCB_InitCallBackState(struct work_struct *work) |
1da177e4 | 375 | { |
08e0e7c8 | 376 | struct afs_call *call = container_of(work, struct afs_call, work); |
1da177e4 | 377 | |
ffba718e | 378 | _enter("{%p}", call->server); |
1da177e4 | 379 | |
ffba718e DH |
380 | if (call->server) |
381 | afs_init_callback_state(call->server); | |
08e0e7c8 | 382 | afs_send_empty_reply(call); |
341f741f | 383 | afs_put_call(call); |
08e0e7c8 | 384 | _leave(""); |
ec26815a | 385 | } |
1da177e4 | 386 | |
1da177e4 | 387 | /* |
08e0e7c8 | 388 | * deliver request data to a CB.InitCallBackState call |
1da177e4 | 389 | */ |
d001648e | 390 | static int afs_deliver_cb_init_call_back_state(struct afs_call *call) |
1da177e4 | 391 | { |
372ee163 | 392 | int ret; |
1da177e4 | 393 | |
d001648e | 394 | _enter(""); |
1da177e4 | 395 | |
12bdcf33 DH |
396 | afs_extract_discard(call, 0); |
397 | ret = afs_extract_data(call, false); | |
372ee163 DH |
398 | if (ret < 0) |
399 | return ret; | |
1da177e4 | 400 | |
08e0e7c8 DH |
401 | /* we'll need the file server record as that tells us which set of |
402 | * vnodes to operate upon */ | |
3bf0fb6f | 403 | return afs_find_cm_server_by_peer(call); |
08e0e7c8 | 404 | } |
1da177e4 | 405 | |
c35eccb1 DH |
406 | /* |
407 | * deliver request data to a CB.InitCallBackState3 call | |
408 | */ | |
d001648e | 409 | static int afs_deliver_cb_init_call_back_state3(struct afs_call *call) |
c35eccb1 | 410 | { |
41bb26f8 | 411 | struct afs_uuid *r; |
d001648e DH |
412 | unsigned loop; |
413 | __be32 *b; | |
414 | int ret; | |
c35eccb1 | 415 | |
d001648e | 416 | _enter(""); |
c35eccb1 | 417 | |
d001648e DH |
418 | _enter("{%u}", call->unmarshall); |
419 | ||
420 | switch (call->unmarshall) { | |
421 | case 0: | |
6da2ec56 | 422 | call->buffer = kmalloc_array(11, sizeof(__be32), GFP_KERNEL); |
d001648e DH |
423 | if (!call->buffer) |
424 | return -ENOMEM; | |
12bdcf33 | 425 | afs_extract_to_buf(call, 11 * sizeof(__be32)); |
d001648e DH |
426 | call->unmarshall++; |
427 | ||
e690c9e3 | 428 | /* Fall through */ |
d001648e DH |
429 | case 1: |
430 | _debug("extract UUID"); | |
12bdcf33 | 431 | ret = afs_extract_data(call, false); |
d001648e DH |
432 | switch (ret) { |
433 | case 0: break; | |
434 | case -EAGAIN: return 0; | |
435 | default: return ret; | |
436 | } | |
437 | ||
438 | _debug("unmarshall UUID"); | |
41bb26f8 | 439 | call->request = kmalloc(sizeof(struct afs_uuid), GFP_KERNEL); |
d001648e DH |
440 | if (!call->request) |
441 | return -ENOMEM; | |
442 | ||
443 | b = call->buffer; | |
444 | r = call->request; | |
ff548773 DH |
445 | r->time_low = b[0]; |
446 | r->time_mid = htons(ntohl(b[1])); | |
447 | r->time_hi_and_version = htons(ntohl(b[2])); | |
d001648e DH |
448 | r->clock_seq_hi_and_reserved = ntohl(b[3]); |
449 | r->clock_seq_low = ntohl(b[4]); | |
450 | ||
451 | for (loop = 0; loop < 6; loop++) | |
452 | r->node[loop] = ntohl(b[loop + 5]); | |
453 | ||
d001648e DH |
454 | call->unmarshall++; |
455 | ||
456 | case 2: | |
457 | break; | |
458 | } | |
c35eccb1 | 459 | |
98bf40cd | 460 | if (!afs_check_call_state(call, AFS_CALL_SV_REPLYING)) |
f51375cd | 461 | return afs_io_error(call, afs_io_error_cm_reply); |
c35eccb1 DH |
462 | |
463 | /* we'll need the file server record as that tells us which set of | |
464 | * vnodes to operate upon */ | |
3bf0fb6f | 465 | return afs_find_cm_server_by_uuid(call, call->request); |
c35eccb1 DH |
466 | } |
467 | ||
08e0e7c8 DH |
468 | /* |
469 | * allow the fileserver to see if the cache manager is still alive | |
470 | */ | |
471 | static void SRXAFSCB_Probe(struct work_struct *work) | |
472 | { | |
473 | struct afs_call *call = container_of(work, struct afs_call, work); | |
1da177e4 | 474 | |
08e0e7c8 DH |
475 | _enter(""); |
476 | afs_send_empty_reply(call); | |
341f741f | 477 | afs_put_call(call); |
08e0e7c8 DH |
478 | _leave(""); |
479 | } | |
1da177e4 | 480 | |
08e0e7c8 DH |
481 | /* |
482 | * deliver request data to a CB.Probe call | |
483 | */ | |
d001648e | 484 | static int afs_deliver_cb_probe(struct afs_call *call) |
08e0e7c8 | 485 | { |
372ee163 DH |
486 | int ret; |
487 | ||
d001648e | 488 | _enter(""); |
1da177e4 | 489 | |
12bdcf33 DH |
490 | afs_extract_discard(call, 0); |
491 | ret = afs_extract_data(call, false); | |
372ee163 DH |
492 | if (ret < 0) |
493 | return ret; | |
1da177e4 | 494 | |
98bf40cd | 495 | if (!afs_check_call_state(call, AFS_CALL_SV_REPLYING)) |
f51375cd | 496 | return afs_io_error(call, afs_io_error_cm_reply); |
3bf0fb6f | 497 | return afs_find_cm_server_by_peer(call); |
ec26815a | 498 | } |
b908fe6b | 499 | |
9396d496 DH |
500 | /* |
501 | * allow the fileserver to quickly find out if the fileserver has been rebooted | |
502 | */ | |
503 | static void SRXAFSCB_ProbeUuid(struct work_struct *work) | |
504 | { | |
505 | struct afs_call *call = container_of(work, struct afs_call, work); | |
41bb26f8 | 506 | struct afs_uuid *r = call->request; |
9396d496 | 507 | |
9396d496 DH |
508 | _enter(""); |
509 | ||
f044c884 | 510 | if (memcmp(r, &call->net->uuid, sizeof(call->net->uuid)) == 0) |
2067b2b3 | 511 | afs_send_empty_reply(call); |
9396d496 | 512 | else |
2067b2b3 DH |
513 | rxrpc_kernel_abort_call(call->net->socket, call->rxcall, |
514 | 1, 1, "K-1"); | |
9396d496 | 515 | |
341f741f | 516 | afs_put_call(call); |
9396d496 DH |
517 | _leave(""); |
518 | } | |
519 | ||
520 | /* | |
521 | * deliver request data to a CB.ProbeUuid call | |
522 | */ | |
d001648e | 523 | static int afs_deliver_cb_probe_uuid(struct afs_call *call) |
9396d496 | 524 | { |
41bb26f8 | 525 | struct afs_uuid *r; |
9396d496 DH |
526 | unsigned loop; |
527 | __be32 *b; | |
528 | int ret; | |
529 | ||
d001648e | 530 | _enter("{%u}", call->unmarshall); |
9396d496 DH |
531 | |
532 | switch (call->unmarshall) { | |
533 | case 0: | |
6da2ec56 | 534 | call->buffer = kmalloc_array(11, sizeof(__be32), GFP_KERNEL); |
9396d496 DH |
535 | if (!call->buffer) |
536 | return -ENOMEM; | |
12bdcf33 | 537 | afs_extract_to_buf(call, 11 * sizeof(__be32)); |
9396d496 DH |
538 | call->unmarshall++; |
539 | ||
e690c9e3 | 540 | /* Fall through */ |
9396d496 DH |
541 | case 1: |
542 | _debug("extract UUID"); | |
12bdcf33 | 543 | ret = afs_extract_data(call, false); |
9396d496 DH |
544 | switch (ret) { |
545 | case 0: break; | |
546 | case -EAGAIN: return 0; | |
547 | default: return ret; | |
548 | } | |
549 | ||
550 | _debug("unmarshall UUID"); | |
41bb26f8 | 551 | call->request = kmalloc(sizeof(struct afs_uuid), GFP_KERNEL); |
9396d496 DH |
552 | if (!call->request) |
553 | return -ENOMEM; | |
554 | ||
555 | b = call->buffer; | |
556 | r = call->request; | |
fe342cf7 DH |
557 | r->time_low = b[0]; |
558 | r->time_mid = htons(ntohl(b[1])); | |
559 | r->time_hi_and_version = htons(ntohl(b[2])); | |
9396d496 DH |
560 | r->clock_seq_hi_and_reserved = ntohl(b[3]); |
561 | r->clock_seq_low = ntohl(b[4]); | |
562 | ||
563 | for (loop = 0; loop < 6; loop++) | |
564 | r->node[loop] = ntohl(b[loop + 5]); | |
565 | ||
9396d496 DH |
566 | call->unmarshall++; |
567 | ||
568 | case 2: | |
9396d496 DH |
569 | break; |
570 | } | |
571 | ||
98bf40cd | 572 | if (!afs_check_call_state(call, AFS_CALL_SV_REPLYING)) |
f51375cd | 573 | return afs_io_error(call, afs_io_error_cm_reply); |
3bf0fb6f | 574 | return afs_find_cm_server_by_uuid(call, call->request); |
9396d496 DH |
575 | } |
576 | ||
b908fe6b DH |
577 | /* |
578 | * allow the fileserver to ask about the cache manager's capabilities | |
579 | */ | |
7c80bcce | 580 | static void SRXAFSCB_TellMeAboutYourself(struct work_struct *work) |
b908fe6b | 581 | { |
b908fe6b | 582 | struct afs_call *call = container_of(work, struct afs_call, work); |
35ebfc22 | 583 | int loop; |
b908fe6b DH |
584 | |
585 | struct { | |
586 | struct /* InterfaceAddr */ { | |
587 | __be32 nifs; | |
588 | __be32 uuid[11]; | |
589 | __be32 ifaddr[32]; | |
590 | __be32 netmask[32]; | |
591 | __be32 mtu[32]; | |
592 | } ia; | |
593 | struct /* Capabilities */ { | |
594 | __be32 capcount; | |
595 | __be32 caps[1]; | |
596 | } cap; | |
597 | } reply; | |
598 | ||
599 | _enter(""); | |
600 | ||
b908fe6b | 601 | memset(&reply, 0, sizeof(reply)); |
b908fe6b | 602 | |
f044c884 DH |
603 | reply.ia.uuid[0] = call->net->uuid.time_low; |
604 | reply.ia.uuid[1] = htonl(ntohs(call->net->uuid.time_mid)); | |
605 | reply.ia.uuid[2] = htonl(ntohs(call->net->uuid.time_hi_and_version)); | |
606 | reply.ia.uuid[3] = htonl((s8) call->net->uuid.clock_seq_hi_and_reserved); | |
607 | reply.ia.uuid[4] = htonl((s8) call->net->uuid.clock_seq_low); | |
b908fe6b | 608 | for (loop = 0; loop < 6; loop++) |
f044c884 | 609 | reply.ia.uuid[loop + 5] = htonl((s8) call->net->uuid.node[loop]); |
b908fe6b | 610 | |
b908fe6b DH |
611 | reply.cap.capcount = htonl(1); |
612 | reply.cap.caps[0] = htonl(AFS_CAP_ERROR_TRANSLATION); | |
613 | afs_send_simple_reply(call, &reply, sizeof(reply)); | |
341f741f | 614 | afs_put_call(call); |
b908fe6b DH |
615 | _leave(""); |
616 | } | |
617 | ||
618 | /* | |
7c80bcce | 619 | * deliver request data to a CB.TellMeAboutYourself call |
b908fe6b | 620 | */ |
d001648e | 621 | static int afs_deliver_cb_tell_me_about_yourself(struct afs_call *call) |
b908fe6b | 622 | { |
372ee163 DH |
623 | int ret; |
624 | ||
d001648e | 625 | _enter(""); |
b908fe6b | 626 | |
12bdcf33 DH |
627 | afs_extract_discard(call, 0); |
628 | ret = afs_extract_data(call, false); | |
372ee163 DH |
629 | if (ret < 0) |
630 | return ret; | |
b908fe6b | 631 | |
98bf40cd | 632 | if (!afs_check_call_state(call, AFS_CALL_SV_REPLYING)) |
f51375cd | 633 | return afs_io_error(call, afs_io_error_cm_reply); |
3bf0fb6f | 634 | return afs_find_cm_server_by_peer(call); |
b908fe6b | 635 | } |
35dbfba3 DH |
636 | |
637 | /* | |
638 | * deliver request data to a YFS CB.CallBack call | |
639 | */ | |
640 | static int afs_deliver_yfs_cb_callback(struct afs_call *call) | |
641 | { | |
642 | struct afs_callback_break *cb; | |
35dbfba3 DH |
643 | struct yfs_xdr_YFSFid *bp; |
644 | size_t size; | |
645 | int ret, loop; | |
646 | ||
647 | _enter("{%u}", call->unmarshall); | |
648 | ||
649 | switch (call->unmarshall) { | |
650 | case 0: | |
651 | afs_extract_to_tmp(call); | |
652 | call->unmarshall++; | |
653 | ||
654 | /* extract the FID array and its count in two steps */ | |
e690c9e3 | 655 | /* Fall through */ |
35dbfba3 DH |
656 | case 1: |
657 | _debug("extract FID count"); | |
658 | ret = afs_extract_data(call, true); | |
659 | if (ret < 0) | |
660 | return ret; | |
661 | ||
662 | call->count = ntohl(call->tmp); | |
663 | _debug("FID count: %u", call->count); | |
664 | if (call->count > YFSCBMAX) | |
665 | return afs_protocol_error(call, -EBADMSG, | |
666 | afs_eproto_cb_fid_count); | |
667 | ||
668 | size = array_size(call->count, sizeof(struct yfs_xdr_YFSFid)); | |
669 | call->buffer = kmalloc(size, GFP_KERNEL); | |
670 | if (!call->buffer) | |
671 | return -ENOMEM; | |
672 | afs_extract_to_buf(call, size); | |
673 | call->unmarshall++; | |
674 | ||
e690c9e3 | 675 | /* Fall through */ |
35dbfba3 DH |
676 | case 2: |
677 | _debug("extract FID array"); | |
678 | ret = afs_extract_data(call, false); | |
679 | if (ret < 0) | |
680 | return ret; | |
681 | ||
682 | _debug("unmarshall FID array"); | |
683 | call->request = kcalloc(call->count, | |
684 | sizeof(struct afs_callback_break), | |
685 | GFP_KERNEL); | |
686 | if (!call->request) | |
687 | return -ENOMEM; | |
688 | ||
689 | cb = call->request; | |
690 | bp = call->buffer; | |
691 | for (loop = call->count; loop > 0; loop--, cb++) { | |
692 | cb->fid.vid = xdr_to_u64(bp->volume); | |
693 | cb->fid.vnode = xdr_to_u64(bp->vnode.lo); | |
694 | cb->fid.vnode_hi = ntohl(bp->vnode.hi); | |
695 | cb->fid.unique = ntohl(bp->vnode.unique); | |
696 | bp++; | |
697 | } | |
698 | ||
699 | afs_extract_to_tmp(call); | |
700 | call->unmarshall++; | |
701 | ||
702 | case 3: | |
703 | break; | |
704 | } | |
705 | ||
706 | if (!afs_check_call_state(call, AFS_CALL_SV_REPLYING)) | |
707 | return afs_io_error(call, afs_io_error_cm_reply); | |
708 | ||
709 | /* We'll need the file server record as that tells us which set of | |
710 | * vnodes to operate upon. | |
711 | */ | |
3bf0fb6f | 712 | return afs_find_cm_server_by_peer(call); |
35dbfba3 | 713 | } |