linux/fs/afs/vlclient.c
<<
>>
Prefs
   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 */
  21static 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
 111static 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 */
 120static 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 */
 131struct 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 */
 183static 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
 192again:
 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
 249static 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 */
 259static 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 */
 270struct 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 */
 316static 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
 323again:
 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 */
 372static 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 */
 386int 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 */
 422static 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
 431again:
 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 */
 611static 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 */
 622struct 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}
 651