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