]> git.proxmox.com Git - mirror_ubuntu-kernels.git/blame - fs/afs/vlclient.c
afs: Fix documentation on # vs % prefix in mount source specification
[mirror_ubuntu-kernels.git] / fs / afs / vlclient.c
CommitLineData
ec26815a 1/* AFS Volume Location Service client
1da177e4
LT
2 *
3 * Copyright (C) 2002 Red Hat, Inc. All Rights Reserved.
4 * Written by David Howells (dhowells@redhat.com)
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
5a0e3ad6 12#include <linux/gfp.h>
1da177e4
LT
13#include <linux/init.h>
14#include <linux/sched.h>
4d9df986 15#include "afs_fs.h"
1da177e4
LT
16#include "internal.h"
17
1da177e4 18/*
d2ddc776 19 * Deliver reply data to a VL.GetEntryByNameU call.
1da177e4 20 */
d2ddc776 21static int afs_deliver_vl_get_entry_by_name_u(struct afs_call *call)
1da177e4 22{
d2ddc776
DH
23 struct afs_uvldbentry__xdr *uvldb;
24 struct afs_vldb_entry *entry;
25 bool new_only = false;
08e0e7c8 26 u32 tmp;
d2ddc776 27 int i, ret;
1da177e4 28
d001648e 29 _enter("");
1da177e4 30
d001648e 31 ret = afs_transfer_reply(call);
372ee163
DH
32 if (ret < 0)
33 return ret;
1da177e4 34
08e0e7c8 35 /* unmarshall the reply once we've received all of it */
d2ddc776 36 uvldb = call->buffer;
97e3043a 37 entry = call->reply[0];
d2ddc776
DH
38
39 for (i = 0; i < ARRAY_SIZE(uvldb->name) - 1; i++)
40 entry->name[i] = (u8)ntohl(uvldb->name[i]);
41 entry->name[i] = 0;
42 entry->name_len = strlen(entry->name);
43
44 /* If there is a new replication site that we can use, ignore all the
45 * sites that aren't marked as new.
46 */
47 for (i = 0; i < AFS_NMAXNSERVERS; i++) {
48 tmp = ntohl(uvldb->serverFlags[i]);
49 if (!(tmp & AFS_VLSF_DONTUSE) &&
50 (tmp & AFS_VLSF_NEWREPSITE))
51 new_only = true;
4d9df986 52 }
1da177e4 53
d2ddc776
DH
54 for (i = 0; i < AFS_NMAXNSERVERS; i++) {
55 struct afs_uuid__xdr *xdr;
56 struct afs_uuid *uuid;
57 int j;
1da177e4 58
d2ddc776
DH
59 tmp = ntohl(uvldb->serverFlags[i]);
60 if (tmp & AFS_VLSF_DONTUSE ||
61 (new_only && !(tmp & AFS_VLSF_NEWREPSITE)))
62 continue;
1da177e4 63 if (tmp & AFS_VLSF_RWVOL)
d2ddc776 64 entry->fs_mask[i] |= AFS_VOL_VTM_RW;
1da177e4 65 if (tmp & AFS_VLSF_ROVOL)
d2ddc776 66 entry->fs_mask[i] |= AFS_VOL_VTM_RO;
1da177e4 67 if (tmp & AFS_VLSF_BACKVOL)
d2ddc776
DH
68 entry->fs_mask[i] |= AFS_VOL_VTM_BAK;
69 if (!entry->fs_mask[i])
70 continue;
71
72 xdr = &uvldb->serverNumber[i];
73 uuid = (struct afs_uuid *)&entry->fs_server[i];
74 uuid->time_low = xdr->time_low;
75 uuid->time_mid = htons(ntohl(xdr->time_mid));
76 uuid->time_hi_and_version = htons(ntohl(xdr->time_hi_and_version));
77 uuid->clock_seq_hi_and_reserved = (u8)ntohl(xdr->clock_seq_hi_and_reserved);
78 uuid->clock_seq_low = (u8)ntohl(xdr->clock_seq_low);
79 for (j = 0; j < 6; j++)
80 uuid->node[j] = (u8)ntohl(xdr->node[j]);
1da177e4 81
d2ddc776
DH
82 entry->nr_servers++;
83 }
1da177e4 84
d2ddc776
DH
85 for (i = 0; i < AFS_MAXTYPES; i++)
86 entry->vid[i] = ntohl(uvldb->volumeId[i]);
1da177e4 87
d2ddc776 88 tmp = ntohl(uvldb->flags);
1da177e4 89 if (tmp & AFS_VLF_RWEXISTS)
d2ddc776 90 __set_bit(AFS_VLDB_HAS_RW, &entry->flags);
1da177e4 91 if (tmp & AFS_VLF_ROEXISTS)
d2ddc776 92 __set_bit(AFS_VLDB_HAS_RO, &entry->flags);
1da177e4 93 if (tmp & AFS_VLF_BACKEXISTS)
d2ddc776 94 __set_bit(AFS_VLDB_HAS_BAK, &entry->flags);
08e0e7c8 95
d2ddc776
DH
96 if (!(tmp & (AFS_VLF_RWEXISTS | AFS_VLF_ROEXISTS | AFS_VLF_BACKEXISTS))) {
97 entry->error = -ENOMEDIUM;
98 __set_bit(AFS_VLDB_QUERY_ERROR, &entry->flags);
99 }
100
101 __set_bit(AFS_VLDB_QUERY_VALID, &entry->flags);
08e0e7c8
DH
102 _leave(" = 0 [done]");
103 return 0;
ec26815a 104}
1da177e4 105
d2ddc776
DH
106static void afs_destroy_vl_get_entry_by_name_u(struct afs_call *call)
107{
108 kfree(call->reply[0]);
109 afs_flat_call_destructor(call);
110}
1da177e4 111
08e0e7c8 112/*
d2ddc776 113 * VL.GetEntryByNameU operation type.
08e0e7c8 114 */
d2ddc776
DH
115static const struct afs_call_type afs_RXVLGetEntryByNameU = {
116 .name = "VL.GetEntryByNameU",
117 .deliver = afs_deliver_vl_get_entry_by_name_u,
118 .destructor = afs_destroy_vl_get_entry_by_name_u,
08e0e7c8 119};
1da177e4 120
1da177e4 121/*
d2ddc776
DH
122 * Dispatch a get volume entry by name or ID operation (uuid variant). If the
123 * volname is a decimal number then it's a volume ID not a volume name.
1da177e4 124 */
d2ddc776
DH
125struct afs_vldb_entry *afs_vl_get_entry_by_name_u(struct afs_net *net,
126 struct afs_addr_cursor *ac,
127 struct key *key,
128 const char *volname,
129 int volnamesz)
1da177e4 130{
d2ddc776 131 struct afs_vldb_entry *entry;
08e0e7c8 132 struct afs_call *call;
d2ddc776 133 size_t reqsz, padsz;
08e0e7c8 134 __be32 *bp;
1da177e4 135
08e0e7c8 136 _enter("");
1da177e4 137
08e0e7c8
DH
138 padsz = (4 - (volnamesz & 3)) & 3;
139 reqsz = 8 + volnamesz + padsz;
1da177e4 140
d2ddc776
DH
141 entry = kzalloc(sizeof(struct afs_vldb_entry), GFP_KERNEL);
142 if (!entry)
143 return ERR_PTR(-ENOMEM);
144
145 call = afs_alloc_flat_call(net, &afs_RXVLGetEntryByNameU, reqsz,
146 sizeof(struct afs_uvldbentry__xdr));
147 if (!call) {
148 kfree(entry);
149 return ERR_PTR(-ENOMEM);
150 }
1da177e4 151
00d3b7a4 152 call->key = key;
97e3043a 153 call->reply[0] = entry;
d2ddc776 154 call->ret_reply0 = true;
1da177e4 155
d2ddc776 156 /* Marshall the parameters */
08e0e7c8 157 bp = call->request;
d2ddc776 158 *bp++ = htonl(VLGETENTRYBYNAMEU);
08e0e7c8
DH
159 *bp++ = htonl(volnamesz);
160 memcpy(bp, volname, volnamesz);
161 if (padsz > 0)
d2ddc776 162 memset((void *)bp + volnamesz, 0, padsz);
08e0e7c8 163
d2ddc776 164 return (struct afs_vldb_entry *)afs_make_call(ac, call, GFP_KERNEL, false);
ec26815a 165}
1da177e4 166
1da177e4 167/*
d2ddc776
DH
168 * Deliver reply data to a VL.GetAddrsU call.
169 *
170 * GetAddrsU(IN ListAddrByAttributes *inaddr,
171 * OUT afsUUID *uuidp1,
172 * OUT uint32_t *uniquifier,
173 * OUT uint32_t *nentries,
174 * OUT bulkaddrs *blkaddrs);
1da177e4 175 */
d2ddc776 176static int afs_deliver_vl_get_addrs_u(struct afs_call *call)
1da177e4 177{
d2ddc776
DH
178 struct afs_addr_list *alist;
179 __be32 *bp;
180 u32 uniquifier, nentries, count;
181 int i, ret;
182
183 _enter("{%u,%zu/%u}", call->unmarshall, call->offset, call->count);
184
185again:
186 switch (call->unmarshall) {
187 case 0:
188 call->offset = 0;
189 call->unmarshall++;
190
191 /* Extract the returned uuid, uniquifier, nentries and blkaddrs size */
192 case 1:
193 ret = afs_extract_data(call, call->buffer,
194 sizeof(struct afs_uuid__xdr) + 3 * sizeof(__be32),
195 true);
196 if (ret < 0)
197 return ret;
198
199 bp = call->buffer + sizeof(struct afs_uuid__xdr);
200 uniquifier = ntohl(*bp++);
201 nentries = ntohl(*bp++);
202 count = ntohl(*bp);
203
204 nentries = min(nentries, count);
205 alist = afs_alloc_addrlist(nentries, FS_SERVICE, AFS_FS_PORT);
206 if (!alist)
207 return -ENOMEM;
208 alist->version = uniquifier;
209 call->reply[0] = alist;
210 call->count = count;
211 call->count2 = nentries;
212 call->offset = 0;
213 call->unmarshall++;
214
215 /* Extract entries */
216 case 2:
217 count = min(call->count, 4U);
218 ret = afs_extract_data(call, call->buffer,
219 count * sizeof(__be32),
220 call->count > 4);
221 if (ret < 0)
222 return ret;
223
224 alist = call->reply[0];
225 bp = call->buffer;
226 for (i = 0; i < count; i++)
227 if (alist->nr_addrs < call->count2)
bf99a53c 228 afs_merge_fs_addr4(alist, *bp++, AFS_FS_PORT);
d2ddc776
DH
229
230 call->count -= count;
231 if (call->count > 0)
232 goto again;
233 call->offset = 0;
234 call->unmarshall++;
235 break;
236 }
237
238 _leave(" = 0 [done]");
239 return 0;
240}
241
242static void afs_vl_get_addrs_u_destructor(struct afs_call *call)
243{
244 afs_put_server(call->net, (struct afs_server *)call->reply[0]);
245 kfree(call->reply[1]);
246 return afs_flat_call_destructor(call);
247}
248
249/*
250 * VL.GetAddrsU operation type.
251 */
252static const struct afs_call_type afs_RXVLGetAddrsU = {
253 .name = "VL.GetAddrsU",
254 .deliver = afs_deliver_vl_get_addrs_u,
255 .destructor = afs_vl_get_addrs_u_destructor,
256};
257
258/*
259 * Dispatch an operation to get the addresses for a server, where the server is
260 * nominated by UUID.
261 */
262struct afs_addr_list *afs_vl_get_addrs_u(struct afs_net *net,
263 struct afs_addr_cursor *ac,
264 struct key *key,
265 const uuid_t *uuid)
266{
267 struct afs_ListAddrByAttributes__xdr *r;
268 const struct afs_uuid *u = (const struct afs_uuid *)uuid;
08e0e7c8 269 struct afs_call *call;
1da177e4 270 __be32 *bp;
d2ddc776 271 int i;
1da177e4 272
08e0e7c8 273 _enter("");
1da177e4 274
d2ddc776
DH
275 call = afs_alloc_flat_call(net, &afs_RXVLGetAddrsU,
276 sizeof(__be32) + sizeof(struct afs_ListAddrByAttributes__xdr),
277 sizeof(struct afs_uuid__xdr) + 3 * sizeof(__be32));
08e0e7c8 278 if (!call)
d2ddc776 279 return ERR_PTR(-ENOMEM);
1da177e4 280
00d3b7a4 281 call->key = key;
d2ddc776
DH
282 call->reply[0] = NULL;
283 call->ret_reply0 = true;
1da177e4 284
d2ddc776 285 /* Marshall the parameters */
08e0e7c8 286 bp = call->request;
d2ddc776
DH
287 *bp++ = htonl(VLGETADDRSU);
288 r = (struct afs_ListAddrByAttributes__xdr *)bp;
289 r->Mask = htonl(AFS_VLADDR_UUID);
290 r->ipaddr = 0;
291 r->index = 0;
292 r->spare = 0;
293 r->uuid.time_low = u->time_low;
294 r->uuid.time_mid = htonl(ntohs(u->time_mid));
295 r->uuid.time_hi_and_version = htonl(ntohs(u->time_hi_and_version));
296 r->uuid.clock_seq_hi_and_reserved = htonl(u->clock_seq_hi_and_reserved);
297 r->uuid.clock_seq_low = htonl(u->clock_seq_low);
298 for (i = 0; i < 6; i++)
299 r->uuid.node[i] = ntohl(u->node[i]);
1da177e4 300
d2ddc776 301 return (struct afs_addr_list *)afs_make_call(ac, call, GFP_KERNEL, false);
ec26815a 302}
bf99a53c
DH
303
304/*
305 * Deliver reply data to an VL.GetCapabilities operation.
306 */
307static int afs_deliver_vl_get_capabilities(struct afs_call *call)
308{
309 u32 count;
310 int ret;
311
312 _enter("{%u,%zu/%u}", call->unmarshall, call->offset, call->count);
313
314again:
315 switch (call->unmarshall) {
316 case 0:
317 call->offset = 0;
318 call->unmarshall++;
319
320 /* Extract the capabilities word count */
321 case 1:
322 ret = afs_extract_data(call, &call->tmp,
323 1 * sizeof(__be32),
324 true);
325 if (ret < 0)
326 return ret;
327
328 count = ntohl(call->tmp);
329
330 call->count = count;
331 call->count2 = count;
332 call->offset = 0;
333 call->unmarshall++;
334
335 /* Extract capabilities words */
336 case 2:
337 count = min(call->count, 16U);
338 ret = afs_extract_data(call, call->buffer,
339 count * sizeof(__be32),
340 call->count > 16);
341 if (ret < 0)
342 return ret;
343
344 /* TODO: Examine capabilities */
345
346 call->count -= count;
347 if (call->count > 0)
348 goto again;
349 call->offset = 0;
350 call->unmarshall++;
351 break;
352 }
353
354 call->reply[0] = (void *)(unsigned long)call->service_id;
355
356 _leave(" = 0 [done]");
357 return 0;
358}
359
360/*
361 * VL.GetCapabilities operation type
362 */
363static const struct afs_call_type afs_RXVLGetCapabilities = {
364 .name = "VL.GetCapabilities",
365 .deliver = afs_deliver_vl_get_capabilities,
366 .destructor = afs_flat_call_destructor,
367};
368
369/*
370 * Probe a fileserver for the capabilities that it supports. This can
371 * return up to 196 words.
372 *
373 * We use this to probe for service upgrade to determine what the server at the
374 * other end supports.
375 */
376int afs_vl_get_capabilities(struct afs_net *net,
377 struct afs_addr_cursor *ac,
378 struct key *key)
379{
380 struct afs_call *call;
381 __be32 *bp;
382
383 _enter("");
384
385 call = afs_alloc_flat_call(net, &afs_RXVLGetCapabilities, 1 * 4, 16 * 4);
386 if (!call)
387 return -ENOMEM;
388
389 call->key = key;
390 call->upgrade = true; /* Let's see if this is a YFS server */
391 call->reply[0] = (void *)VLGETCAPABILITIES;
392 call->ret_reply0 = true;
393
394 /* marshall the parameters */
395 bp = call->request;
396 *bp++ = htonl(VLGETCAPABILITIES);
397
398 /* Can't take a ref on server */
399 return afs_make_call(ac, call, GFP_KERNEL, false);
400}
401
402/*
403 * Deliver reply data to a YFSVL.GetEndpoints call.
404 *
405 * GetEndpoints(IN yfsServerAttributes *attr,
406 * OUT opr_uuid *uuid,
407 * OUT afs_int32 *uniquifier,
408 * OUT endpoints *fsEndpoints,
409 * OUT endpoints *volEndpoints)
410 */
411static int afs_deliver_yfsvl_get_endpoints(struct afs_call *call)
412{
413 struct afs_addr_list *alist;
414 __be32 *bp;
415 u32 uniquifier, size;
416 int ret;
417
418 _enter("{%u,%zu/%u,%u}", call->unmarshall, call->offset, call->count, call->count2);
419
420again:
421 switch (call->unmarshall) {
422 case 0:
423 call->offset = 0;
424 call->unmarshall = 1;
425
426 /* Extract the returned uuid, uniquifier, fsEndpoints count and
427 * either the first fsEndpoint type or the volEndpoints
428 * count if there are no fsEndpoints. */
429 case 1:
430 ret = afs_extract_data(call, call->buffer,
431 sizeof(uuid_t) +
432 3 * sizeof(__be32),
433 true);
434 if (ret < 0)
435 return ret;
436
437 bp = call->buffer + sizeof(uuid_t);
438 uniquifier = ntohl(*bp++);
439 call->count = ntohl(*bp++);
440 call->count2 = ntohl(*bp); /* Type or next count */
441
442 if (call->count > YFS_MAXENDPOINTS)
443 return -EBADMSG;
444
445 alist = afs_alloc_addrlist(call->count, FS_SERVICE, AFS_FS_PORT);
446 if (!alist)
447 return -ENOMEM;
448 alist->version = uniquifier;
449 call->reply[0] = alist;
450 call->offset = 0;
451
452 if (call->count == 0)
453 goto extract_volendpoints;
454
455 call->unmarshall = 2;
456
457 /* Extract fsEndpoints[] entries */
458 case 2:
459 switch (call->count2) {
460 case YFS_ENDPOINT_IPV4:
461 size = sizeof(__be32) * (1 + 1 + 1);
462 break;
463 case YFS_ENDPOINT_IPV6:
464 size = sizeof(__be32) * (1 + 4 + 1);
465 break;
466 default:
467 return -EBADMSG;
468 }
469
470 size += sizeof(__be32);
471 ret = afs_extract_data(call, call->buffer, size, true);
472 if (ret < 0)
473 return ret;
474
475 alist = call->reply[0];
476 bp = call->buffer;
477 switch (call->count2) {
478 case YFS_ENDPOINT_IPV4:
479 if (ntohl(bp[0]) != sizeof(__be32) * 2)
480 return -EBADMSG;
481 afs_merge_fs_addr4(alist, bp[1], ntohl(bp[2]));
482 bp += 3;
483 break;
484 case YFS_ENDPOINT_IPV6:
485 if (ntohl(bp[0]) != sizeof(__be32) * 5)
486 return -EBADMSG;
487 afs_merge_fs_addr6(alist, bp + 1, ntohl(bp[5]));
488 bp += 6;
489 break;
490 default:
491 return -EBADMSG;
492 }
493
494 /* Got either the type of the next entry or the count of
495 * volEndpoints if no more fsEndpoints.
496 */
497 call->count2 = htonl(*bp++);
498
499 call->offset = 0;
500 call->count--;
501 if (call->count > 0)
502 goto again;
503
504 extract_volendpoints:
505 /* Extract the list of volEndpoints. */
506 call->count = call->count2;
507 if (!call->count)
508 goto end;
509 if (call->count > YFS_MAXENDPOINTS)
510 return -EBADMSG;
511
512 call->unmarshall = 3;
513
514 /* Extract the type of volEndpoints[0]. Normally we would
515 * extract the type of the next endpoint when we extract the
516 * data of the current one, but this is the first...
517 */
518 case 3:
519 ret = afs_extract_data(call, call->buffer, sizeof(__be32), true);
520 if (ret < 0)
521 return ret;
522
523 bp = call->buffer;
524 call->count2 = htonl(*bp++);
525 call->offset = 0;
526 call->unmarshall = 4;
527
528 /* Extract volEndpoints[] entries */
529 case 4:
530 switch (call->count2) {
531 case YFS_ENDPOINT_IPV4:
532 size = sizeof(__be32) * (1 + 1 + 1);
533 break;
534 case YFS_ENDPOINT_IPV6:
535 size = sizeof(__be32) * (1 + 4 + 1);
536 break;
537 default:
538 return -EBADMSG;
539 }
540
541 if (call->count > 1)
542 size += sizeof(__be32);
543 ret = afs_extract_data(call, call->buffer, size, true);
544 if (ret < 0)
545 return ret;
546
547 bp = call->buffer;
548 switch (call->count2) {
549 case YFS_ENDPOINT_IPV4:
550 if (ntohl(bp[0]) != sizeof(__be32) * 2)
551 return -EBADMSG;
552 bp += 3;
553 break;
554 case YFS_ENDPOINT_IPV6:
555 if (ntohl(bp[0]) != sizeof(__be32) * 5)
556 return -EBADMSG;
557 bp += 6;
558 break;
559 default:
560 return -EBADMSG;
561 }
562
563 /* Got either the type of the next entry or the count of
564 * volEndpoints if no more fsEndpoints.
565 */
566 call->offset = 0;
567 call->count--;
568 if (call->count > 0) {
569 call->count2 = htonl(*bp++);
570 goto again;
571 }
572
573 end:
574 call->unmarshall = 5;
575
576 /* Done */
577 case 5:
578 ret = afs_extract_data(call, call->buffer, 0, false);
579 if (ret < 0)
580 return ret;
581 call->unmarshall = 6;
582
583 case 6:
584 break;
585 }
586
587 alist = call->reply[0];
588
589 /* Start with IPv6 if available. */
590 if (alist->nr_ipv4 < alist->nr_addrs)
591 alist->index = alist->nr_ipv4;
592
593 _leave(" = 0 [done]");
594 return 0;
595}
596
597/*
598 * YFSVL.GetEndpoints operation type.
599 */
600static const struct afs_call_type afs_YFSVLGetEndpoints = {
601 .name = "VL.GetEndpoints",
602 .deliver = afs_deliver_yfsvl_get_endpoints,
603 .destructor = afs_vl_get_addrs_u_destructor,
604};
605
606/*
607 * Dispatch an operation to get the addresses for a server, where the server is
608 * nominated by UUID.
609 */
610struct afs_addr_list *afs_yfsvl_get_endpoints(struct afs_net *net,
611 struct afs_addr_cursor *ac,
612 struct key *key,
613 const uuid_t *uuid)
614{
615 struct afs_call *call;
616 __be32 *bp;
617
618 _enter("");
619
620 call = afs_alloc_flat_call(net, &afs_YFSVLGetEndpoints,
621 sizeof(__be32) * 2 + sizeof(*uuid),
622 sizeof(struct in6_addr) + sizeof(__be32) * 3);
623 if (!call)
624 return ERR_PTR(-ENOMEM);
625
626 call->key = key;
627 call->reply[0] = NULL;
628 call->ret_reply0 = true;
629
630 /* Marshall the parameters */
631 bp = call->request;
632 *bp++ = htonl(YVLGETENDPOINTS);
633 *bp++ = htonl(YFS_SERVER_UUID);
634 memcpy(bp, uuid, sizeof(*uuid)); /* Type opr_uuid */
635
636 return (struct afs_addr_list *)afs_make_call(ac, call, GFP_KERNEL, false);
637}