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