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