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