OSDN Git Service

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