linux/fs/nfs/nfs4filelayoutdev.c
<<
>>
Prefs
   1/*
   2 *  Device operations for the pnfs nfs4 file layout driver.
   3 *
   4 *  Copyright (c) 2002
   5 *  The Regents of the University of Michigan
   6 *  All Rights Reserved
   7 *
   8 *  Dean Hildebrand <dhildebz@umich.edu>
   9 *  Garth Goodson   <Garth.Goodson@netapp.com>
  10 *
  11 *  Permission is granted to use, copy, create derivative works, and
  12 *  redistribute this software and such derivative works for any purpose,
  13 *  so long as the name of the University of Michigan is not used in
  14 *  any advertising or publicity pertaining to the use or distribution
  15 *  of this software without specific, written prior authorization. If
  16 *  the above copyright notice or any other identification of the
  17 *  University of Michigan is included in any copy of any portion of
  18 *  this software, then the disclaimer below must also be included.
  19 *
  20 *  This software is provided as is, without representation or warranty
  21 *  of any kind either express or implied, including without limitation
  22 *  the implied warranties of merchantability, fitness for a particular
  23 *  purpose, or noninfringement.  The Regents of the University of
  24 *  Michigan shall not be liable for any damages, including special,
  25 *  indirect, incidental, or consequential damages, with respect to any
  26 *  claim arising out of or in connection with the use of the software,
  27 *  even if it has been or is hereafter advised of the possibility of
  28 *  such damages.
  29 */
  30
  31#include <linux/nfs_fs.h>
  32#include <linux/vmalloc.h>
  33#include <linux/module.h>
  34
  35#include "internal.h"
  36#include "nfs4filelayout.h"
  37
  38#define NFSDBG_FACILITY         NFSDBG_PNFS_LD
  39
  40static unsigned int dataserver_timeo = NFS4_DEF_DS_TIMEO;
  41static unsigned int dataserver_retrans = NFS4_DEF_DS_RETRANS;
  42
  43/*
  44 * Data server cache
  45 *
  46 * Data servers can be mapped to different device ids.
  47 * nfs4_pnfs_ds reference counting
  48 *   - set to 1 on allocation
  49 *   - incremented when a device id maps a data server already in the cache.
  50 *   - decremented when deviceid is removed from the cache.
  51 */
  52static DEFINE_SPINLOCK(nfs4_ds_cache_lock);
  53static LIST_HEAD(nfs4_data_server_cache);
  54
  55/* Debug routines */
  56void
  57print_ds(struct nfs4_pnfs_ds *ds)
  58{
  59        if (ds == NULL) {
  60                printk("%s NULL device\n", __func__);
  61                return;
  62        }
  63        printk("        ds %s\n"
  64                "        ref count %d\n"
  65                "        client %p\n"
  66                "        cl_exchange_flags %x\n",
  67                ds->ds_remotestr,
  68                atomic_read(&ds->ds_count), ds->ds_clp,
  69                ds->ds_clp ? ds->ds_clp->cl_exchange_flags : 0);
  70}
  71
  72static bool
  73same_sockaddr(struct sockaddr *addr1, struct sockaddr *addr2)
  74{
  75        struct sockaddr_in *a, *b;
  76        struct sockaddr_in6 *a6, *b6;
  77
  78        if (addr1->sa_family != addr2->sa_family)
  79                return false;
  80
  81        switch (addr1->sa_family) {
  82        case AF_INET:
  83                a = (struct sockaddr_in *)addr1;
  84                b = (struct sockaddr_in *)addr2;
  85
  86                if (a->sin_addr.s_addr == b->sin_addr.s_addr &&
  87                    a->sin_port == b->sin_port)
  88                        return true;
  89                break;
  90
  91        case AF_INET6:
  92                a6 = (struct sockaddr_in6 *)addr1;
  93                b6 = (struct sockaddr_in6 *)addr2;
  94
  95                /* LINKLOCAL addresses must have matching scope_id */
  96                if (ipv6_addr_scope(&a6->sin6_addr) ==
  97                    IPV6_ADDR_SCOPE_LINKLOCAL &&
  98                    a6->sin6_scope_id != b6->sin6_scope_id)
  99                        return false;
 100
 101                if (ipv6_addr_equal(&a6->sin6_addr, &b6->sin6_addr) &&
 102                    a6->sin6_port == b6->sin6_port)
 103                        return true;
 104                break;
 105
 106        default:
 107                dprintk("%s: unhandled address family: %u\n",
 108                        __func__, addr1->sa_family);
 109                return false;
 110        }
 111
 112        return false;
 113}
 114
 115static bool
 116_same_data_server_addrs_locked(const struct list_head *dsaddrs1,
 117                               const struct list_head *dsaddrs2)
 118{
 119        struct nfs4_pnfs_ds_addr *da1, *da2;
 120
 121        /* step through both lists, comparing as we go */
 122        for (da1 = list_first_entry(dsaddrs1, typeof(*da1), da_node),
 123             da2 = list_first_entry(dsaddrs2, typeof(*da2), da_node);
 124             da1 != NULL && da2 != NULL;
 125             da1 = list_entry(da1->da_node.next, typeof(*da1), da_node),
 126             da2 = list_entry(da2->da_node.next, typeof(*da2), da_node)) {
 127                if (!same_sockaddr((struct sockaddr *)&da1->da_addr,
 128                                   (struct sockaddr *)&da2->da_addr))
 129                        return false;
 130        }
 131        if (da1 == NULL && da2 == NULL)
 132                return true;
 133
 134        return false;
 135}
 136
 137/*
 138 * Lookup DS by addresses.  nfs4_ds_cache_lock is held
 139 */
 140static struct nfs4_pnfs_ds *
 141_data_server_lookup_locked(const struct list_head *dsaddrs)
 142{
 143        struct nfs4_pnfs_ds *ds;
 144
 145        list_for_each_entry(ds, &nfs4_data_server_cache, ds_node)
 146                if (_same_data_server_addrs_locked(&ds->ds_addrs, dsaddrs))
 147                        return ds;
 148        return NULL;
 149}
 150
 151/*
 152 * Create an rpc connection to the nfs4_pnfs_ds data server
 153 * Currently only supports IPv4 and IPv6 addresses
 154 */
 155static int
 156nfs4_ds_connect(struct nfs_server *mds_srv, struct nfs4_pnfs_ds *ds)
 157{
 158        struct nfs_client *clp = ERR_PTR(-EIO);
 159        struct nfs4_pnfs_ds_addr *da;
 160        int status = 0;
 161
 162        dprintk("--> %s DS %s au_flavor %d\n", __func__, ds->ds_remotestr,
 163                mds_srv->nfs_client->cl_rpcclient->cl_auth->au_flavor);
 164
 165        BUG_ON(list_empty(&ds->ds_addrs));
 166
 167        list_for_each_entry(da, &ds->ds_addrs, da_node) {
 168                dprintk("%s: DS %s: trying address %s\n",
 169                        __func__, ds->ds_remotestr, da->da_remotestr);
 170
 171                clp = nfs4_set_ds_client(mds_srv->nfs_client,
 172                                        (struct sockaddr *)&da->da_addr,
 173                                        da->da_addrlen, IPPROTO_TCP,
 174                                        dataserver_timeo, dataserver_retrans);
 175                if (!IS_ERR(clp))
 176                        break;
 177        }
 178
 179        if (IS_ERR(clp)) {
 180                status = PTR_ERR(clp);
 181                goto out;
 182        }
 183
 184        status = nfs4_init_ds_session(clp, mds_srv->nfs_client->cl_lease_time);
 185        if (status)
 186                goto out_put;
 187
 188        ds->ds_clp = clp;
 189        dprintk("%s [new] addr: %s\n", __func__, ds->ds_remotestr);
 190out:
 191        return status;
 192out_put:
 193        nfs_put_client(clp);
 194        goto out;
 195}
 196
 197static void
 198destroy_ds(struct nfs4_pnfs_ds *ds)
 199{
 200        struct nfs4_pnfs_ds_addr *da;
 201
 202        dprintk("--> %s\n", __func__);
 203        ifdebug(FACILITY)
 204                print_ds(ds);
 205
 206        if (ds->ds_clp)
 207                nfs_put_client(ds->ds_clp);
 208
 209        while (!list_empty(&ds->ds_addrs)) {
 210                da = list_first_entry(&ds->ds_addrs,
 211                                      struct nfs4_pnfs_ds_addr,
 212                                      da_node);
 213                list_del_init(&da->da_node);
 214                kfree(da->da_remotestr);
 215                kfree(da);
 216        }
 217
 218        kfree(ds->ds_remotestr);
 219        kfree(ds);
 220}
 221
 222void
 223nfs4_fl_free_deviceid(struct nfs4_file_layout_dsaddr *dsaddr)
 224{
 225        struct nfs4_pnfs_ds *ds;
 226        int i;
 227
 228        nfs4_print_deviceid(&dsaddr->id_node.deviceid);
 229
 230        for (i = 0; i < dsaddr->ds_num; i++) {
 231                ds = dsaddr->ds_list[i];
 232                if (ds != NULL) {
 233                        if (atomic_dec_and_lock(&ds->ds_count,
 234                                                &nfs4_ds_cache_lock)) {
 235                                list_del_init(&ds->ds_node);
 236                                spin_unlock(&nfs4_ds_cache_lock);
 237                                destroy_ds(ds);
 238                        }
 239                }
 240        }
 241        kfree(dsaddr->stripe_indices);
 242        kfree(dsaddr);
 243}
 244
 245/*
 246 * Create a string with a human readable address and port to avoid
 247 * complicated setup around many dprinks.
 248 */
 249static char *
 250nfs4_pnfs_remotestr(struct list_head *dsaddrs, gfp_t gfp_flags)
 251{
 252        struct nfs4_pnfs_ds_addr *da;
 253        char *remotestr;
 254        size_t len;
 255        char *p;
 256
 257        len = 3;        /* '{', '}' and eol */
 258        list_for_each_entry(da, dsaddrs, da_node) {
 259                len += strlen(da->da_remotestr) + 1;    /* string plus comma */
 260        }
 261
 262        remotestr = kzalloc(len, gfp_flags);
 263        if (!remotestr)
 264                return NULL;
 265
 266        p = remotestr;
 267        *(p++) = '{';
 268        len--;
 269        list_for_each_entry(da, dsaddrs, da_node) {
 270                size_t ll = strlen(da->da_remotestr);
 271
 272                if (ll > len)
 273                        goto out_err;
 274
 275                memcpy(p, da->da_remotestr, ll);
 276                p += ll;
 277                len -= ll;
 278
 279                if (len < 1)
 280                        goto out_err;
 281                (*p++) = ',';
 282                len--;
 283        }
 284        if (len < 2)
 285                goto out_err;
 286        *(p++) = '}';
 287        *p = '\0';
 288        return remotestr;
 289out_err:
 290        kfree(remotestr);
 291        return NULL;
 292}
 293
 294static struct nfs4_pnfs_ds *
 295nfs4_pnfs_ds_add(struct list_head *dsaddrs, gfp_t gfp_flags)
 296{
 297        struct nfs4_pnfs_ds *tmp_ds, *ds = NULL;
 298        char *remotestr;
 299
 300        if (list_empty(dsaddrs)) {
 301                dprintk("%s: no addresses defined\n", __func__);
 302                goto out;
 303        }
 304
 305        ds = kzalloc(sizeof(*ds), gfp_flags);
 306        if (!ds)
 307                goto out;
 308
 309        /* this is only used for debugging, so it's ok if its NULL */
 310        remotestr = nfs4_pnfs_remotestr(dsaddrs, gfp_flags);
 311
 312        spin_lock(&nfs4_ds_cache_lock);
 313        tmp_ds = _data_server_lookup_locked(dsaddrs);
 314        if (tmp_ds == NULL) {
 315                INIT_LIST_HEAD(&ds->ds_addrs);
 316                list_splice_init(dsaddrs, &ds->ds_addrs);
 317                ds->ds_remotestr = remotestr;
 318                atomic_set(&ds->ds_count, 1);
 319                INIT_LIST_HEAD(&ds->ds_node);
 320                ds->ds_clp = NULL;
 321                list_add(&ds->ds_node, &nfs4_data_server_cache);
 322                dprintk("%s add new data server %s\n", __func__,
 323                        ds->ds_remotestr);
 324        } else {
 325                kfree(remotestr);
 326                kfree(ds);
 327                atomic_inc(&tmp_ds->ds_count);
 328                dprintk("%s data server %s found, inc'ed ds_count to %d\n",
 329                        __func__, tmp_ds->ds_remotestr,
 330                        atomic_read(&tmp_ds->ds_count));
 331                ds = tmp_ds;
 332        }
 333        spin_unlock(&nfs4_ds_cache_lock);
 334out:
 335        return ds;
 336}
 337
 338/*
 339 * Currently only supports ipv4, ipv6 and one multi-path address.
 340 */
 341static struct nfs4_pnfs_ds_addr *
 342decode_ds_addr(struct net *net, struct xdr_stream *streamp, gfp_t gfp_flags)
 343{
 344        struct nfs4_pnfs_ds_addr *da = NULL;
 345        char *buf, *portstr;
 346        __be16 port;
 347        int nlen, rlen;
 348        int tmp[2];
 349        __be32 *p;
 350        char *netid, *match_netid;
 351        size_t len, match_netid_len;
 352        char *startsep = "";
 353        char *endsep = "";
 354
 355
 356        /* r_netid */
 357        p = xdr_inline_decode(streamp, 4);
 358        if (unlikely(!p))
 359                goto out_err;
 360        nlen = be32_to_cpup(p++);
 361
 362        p = xdr_inline_decode(streamp, nlen);
 363        if (unlikely(!p))
 364                goto out_err;
 365
 366        netid = kmalloc(nlen+1, gfp_flags);
 367        if (unlikely(!netid))
 368                goto out_err;
 369
 370        netid[nlen] = '\0';
 371        memcpy(netid, p, nlen);
 372
 373        /* r_addr: ip/ip6addr with port in dec octets - see RFC 5665 */
 374        p = xdr_inline_decode(streamp, 4);
 375        if (unlikely(!p))
 376                goto out_free_netid;
 377        rlen = be32_to_cpup(p);
 378
 379        p = xdr_inline_decode(streamp, rlen);
 380        if (unlikely(!p))
 381                goto out_free_netid;
 382
 383        /* port is ".ABC.DEF", 8 chars max */
 384        if (rlen > INET6_ADDRSTRLEN + IPV6_SCOPE_ID_LEN + 8) {
 385                dprintk("%s: Invalid address, length %d\n", __func__,
 386                        rlen);
 387                goto out_free_netid;
 388        }
 389        buf = kmalloc(rlen + 1, gfp_flags);
 390        if (!buf) {
 391                dprintk("%s: Not enough memory\n", __func__);
 392                goto out_free_netid;
 393        }
 394        buf[rlen] = '\0';
 395        memcpy(buf, p, rlen);
 396
 397        /* replace port '.' with '-' */
 398        portstr = strrchr(buf, '.');
 399        if (!portstr) {
 400                dprintk("%s: Failed finding expected dot in port\n",
 401                        __func__);
 402                goto out_free_buf;
 403        }
 404        *portstr = '-';
 405
 406        /* find '.' between address and port */
 407        portstr = strrchr(buf, '.');
 408        if (!portstr) {
 409                dprintk("%s: Failed finding expected dot between address and "
 410                        "port\n", __func__);
 411                goto out_free_buf;
 412        }
 413        *portstr = '\0';
 414
 415        da = kzalloc(sizeof(*da), gfp_flags);
 416        if (unlikely(!da))
 417                goto out_free_buf;
 418
 419        INIT_LIST_HEAD(&da->da_node);
 420
 421        if (!rpc_pton(net, buf, portstr-buf, (struct sockaddr *)&da->da_addr,
 422                      sizeof(da->da_addr))) {
 423                dprintk("%s: error parsing address %s\n", __func__, buf);
 424                goto out_free_da;
 425        }
 426
 427        portstr++;
 428        sscanf(portstr, "%d-%d", &tmp[0], &tmp[1]);
 429        port = htons((tmp[0] << 8) | (tmp[1]));
 430
 431        switch (da->da_addr.ss_family) {
 432        case AF_INET:
 433                ((struct sockaddr_in *)&da->da_addr)->sin_port = port;
 434                da->da_addrlen = sizeof(struct sockaddr_in);
 435                match_netid = "tcp";
 436                match_netid_len = 3;
 437                break;
 438
 439        case AF_INET6:
 440                ((struct sockaddr_in6 *)&da->da_addr)->sin6_port = port;
 441                da->da_addrlen = sizeof(struct sockaddr_in6);
 442                match_netid = "tcp6";
 443                match_netid_len = 4;
 444                startsep = "[";
 445                endsep = "]";
 446                break;
 447
 448        default:
 449                dprintk("%s: unsupported address family: %u\n",
 450                        __func__, da->da_addr.ss_family);
 451                goto out_free_da;
 452        }
 453
 454        if (nlen != match_netid_len || strncmp(netid, match_netid, nlen)) {
 455                dprintk("%s: ERROR: r_netid \"%s\" != \"%s\"\n",
 456                        __func__, netid, match_netid);
 457                goto out_free_da;
 458        }
 459
 460        /* save human readable address */
 461        len = strlen(startsep) + strlen(buf) + strlen(endsep) + 7;
 462        da->da_remotestr = kzalloc(len, gfp_flags);
 463
 464        /* NULL is ok, only used for dprintk */
 465        if (da->da_remotestr)
 466                snprintf(da->da_remotestr, len, "%s%s%s:%u", startsep,
 467                         buf, endsep, ntohs(port));
 468
 469        dprintk("%s: Parsed DS addr %s\n", __func__, da->da_remotestr);
 470        kfree(buf);
 471        kfree(netid);
 472        return da;
 473
 474out_free_da:
 475        kfree(da);
 476out_free_buf:
 477        dprintk("%s: Error parsing DS addr: %s\n", __func__, buf);
 478        kfree(buf);
 479out_free_netid:
 480        kfree(netid);
 481out_err:
 482        return NULL;
 483}
 484
 485/* Decode opaque device data and return the result */
 486static struct nfs4_file_layout_dsaddr*
 487decode_device(struct inode *ino, struct pnfs_device *pdev, gfp_t gfp_flags)
 488{
 489        int i;
 490        u32 cnt, num;
 491        u8 *indexp;
 492        __be32 *p;
 493        u8 *stripe_indices;
 494        u8 max_stripe_index;
 495        struct nfs4_file_layout_dsaddr *dsaddr = NULL;
 496        struct xdr_stream stream;
 497        struct xdr_buf buf;
 498        struct page *scratch;
 499        struct list_head dsaddrs;
 500        struct nfs4_pnfs_ds_addr *da;
 501
 502        /* set up xdr stream */
 503        scratch = alloc_page(gfp_flags);
 504        if (!scratch)
 505                goto out_err;
 506
 507        xdr_init_decode_pages(&stream, &buf, pdev->pages, pdev->pglen);
 508        xdr_set_scratch_buffer(&stream, page_address(scratch), PAGE_SIZE);
 509
 510        /* Get the stripe count (number of stripe index) */
 511        p = xdr_inline_decode(&stream, 4);
 512        if (unlikely(!p))
 513                goto out_err_free_scratch;
 514
 515        cnt = be32_to_cpup(p);
 516        dprintk("%s stripe count  %d\n", __func__, cnt);
 517        if (cnt > NFS4_PNFS_MAX_STRIPE_CNT) {
 518                printk(KERN_WARNING "NFS: %s: stripe count %d greater than "
 519                       "supported maximum %d\n", __func__,
 520                        cnt, NFS4_PNFS_MAX_STRIPE_CNT);
 521                goto out_err_free_scratch;
 522        }
 523
 524        /* read stripe indices */
 525        stripe_indices = kcalloc(cnt, sizeof(u8), gfp_flags);
 526        if (!stripe_indices)
 527                goto out_err_free_scratch;
 528
 529        p = xdr_inline_decode(&stream, cnt << 2);
 530        if (unlikely(!p))
 531                goto out_err_free_stripe_indices;
 532
 533        indexp = &stripe_indices[0];
 534        max_stripe_index = 0;
 535        for (i = 0; i < cnt; i++) {
 536                *indexp = be32_to_cpup(p++);
 537                max_stripe_index = max(max_stripe_index, *indexp);
 538                indexp++;
 539        }
 540
 541        /* Check the multipath list count */
 542        p = xdr_inline_decode(&stream, 4);
 543        if (unlikely(!p))
 544                goto out_err_free_stripe_indices;
 545
 546        num = be32_to_cpup(p);
 547        dprintk("%s ds_num %u\n", __func__, num);
 548        if (num > NFS4_PNFS_MAX_MULTI_CNT) {
 549                printk(KERN_WARNING "NFS: %s: multipath count %d greater than "
 550                        "supported maximum %d\n", __func__,
 551                        num, NFS4_PNFS_MAX_MULTI_CNT);
 552                goto out_err_free_stripe_indices;
 553        }
 554
 555        /* validate stripe indices are all < num */
 556        if (max_stripe_index >= num) {
 557                printk(KERN_WARNING "NFS: %s: stripe index %u >= num ds %u\n",
 558                        __func__, max_stripe_index, num);
 559                goto out_err_free_stripe_indices;
 560        }
 561
 562        dsaddr = kzalloc(sizeof(*dsaddr) +
 563                        (sizeof(struct nfs4_pnfs_ds *) * (num - 1)),
 564                        gfp_flags);
 565        if (!dsaddr)
 566                goto out_err_free_stripe_indices;
 567
 568        dsaddr->stripe_count = cnt;
 569        dsaddr->stripe_indices = stripe_indices;
 570        stripe_indices = NULL;
 571        dsaddr->ds_num = num;
 572        nfs4_init_deviceid_node(&dsaddr->id_node,
 573                                NFS_SERVER(ino)->pnfs_curr_ld,
 574                                NFS_SERVER(ino)->nfs_client,
 575                                &pdev->dev_id);
 576
 577        INIT_LIST_HEAD(&dsaddrs);
 578
 579        for (i = 0; i < dsaddr->ds_num; i++) {
 580                int j;
 581                u32 mp_count;
 582
 583                p = xdr_inline_decode(&stream, 4);
 584                if (unlikely(!p))
 585                        goto out_err_free_deviceid;
 586
 587                mp_count = be32_to_cpup(p); /* multipath count */
 588                for (j = 0; j < mp_count; j++) {
 589                        da = decode_ds_addr(NFS_SERVER(ino)->nfs_client->cl_net,
 590                                            &stream, gfp_flags);
 591                        if (da)
 592                                list_add_tail(&da->da_node, &dsaddrs);
 593                }
 594                if (list_empty(&dsaddrs)) {
 595                        dprintk("%s: no suitable DS addresses found\n",
 596                                __func__);
 597                        goto out_err_free_deviceid;
 598                }
 599
 600                dsaddr->ds_list[i] = nfs4_pnfs_ds_add(&dsaddrs, gfp_flags);
 601                if (!dsaddr->ds_list[i])
 602                        goto out_err_drain_dsaddrs;
 603
 604                /* If DS was already in cache, free ds addrs */
 605                while (!list_empty(&dsaddrs)) {
 606                        da = list_first_entry(&dsaddrs,
 607                                              struct nfs4_pnfs_ds_addr,
 608                                              da_node);
 609                        list_del_init(&da->da_node);
 610                        kfree(da->da_remotestr);
 611                        kfree(da);
 612                }
 613        }
 614
 615        __free_page(scratch);
 616        return dsaddr;
 617
 618out_err_drain_dsaddrs:
 619        while (!list_empty(&dsaddrs)) {
 620                da = list_first_entry(&dsaddrs, struct nfs4_pnfs_ds_addr,
 621                                      da_node);
 622                list_del_init(&da->da_node);
 623                kfree(da->da_remotestr);
 624                kfree(da);
 625        }
 626out_err_free_deviceid:
 627        nfs4_fl_free_deviceid(dsaddr);
 628        /* stripe_indicies was part of dsaddr */
 629        goto out_err_free_scratch;
 630out_err_free_stripe_indices:
 631        kfree(stripe_indices);
 632out_err_free_scratch:
 633        __free_page(scratch);
 634out_err:
 635        dprintk("%s ERROR: returning NULL\n", __func__);
 636        return NULL;
 637}
 638
 639/*
 640 * Decode the opaque device specified in 'dev' and add it to the cache of
 641 * available devices.
 642 */
 643static struct nfs4_file_layout_dsaddr *
 644decode_and_add_device(struct inode *inode, struct pnfs_device *dev, gfp_t gfp_flags)
 645{
 646        struct nfs4_deviceid_node *d;
 647        struct nfs4_file_layout_dsaddr *n, *new;
 648
 649        new = decode_device(inode, dev, gfp_flags);
 650        if (!new) {
 651                printk(KERN_WARNING "NFS: %s: Could not decode or add device\n",
 652                        __func__);
 653                return NULL;
 654        }
 655
 656        d = nfs4_insert_deviceid_node(&new->id_node);
 657        n = container_of(d, struct nfs4_file_layout_dsaddr, id_node);
 658        if (n != new) {
 659                nfs4_fl_free_deviceid(new);
 660                return n;
 661        }
 662
 663        return new;
 664}
 665
 666/*
 667 * Retrieve the information for dev_id, add it to the list
 668 * of available devices, and return it.
 669 */
 670struct nfs4_file_layout_dsaddr *
 671filelayout_get_device_info(struct inode *inode, struct nfs4_deviceid *dev_id, gfp_t gfp_flags)
 672{
 673        struct pnfs_device *pdev = NULL;
 674        u32 max_resp_sz;
 675        int max_pages;
 676        struct page **pages = NULL;
 677        struct nfs4_file_layout_dsaddr *dsaddr = NULL;
 678        int rc, i;
 679        struct nfs_server *server = NFS_SERVER(inode);
 680
 681        /*
 682         * Use the session max response size as the basis for setting
 683         * GETDEVICEINFO's maxcount
 684         */
 685        max_resp_sz = server->nfs_client->cl_session->fc_attrs.max_resp_sz;
 686        max_pages = nfs_page_array_len(0, max_resp_sz);
 687        dprintk("%s inode %p max_resp_sz %u max_pages %d\n",
 688                __func__, inode, max_resp_sz, max_pages);
 689
 690        pdev = kzalloc(sizeof(struct pnfs_device), gfp_flags);
 691        if (pdev == NULL)
 692                return NULL;
 693
 694        pages = kzalloc(max_pages * sizeof(struct page *), gfp_flags);
 695        if (pages == NULL) {
 696                kfree(pdev);
 697                return NULL;
 698        }
 699        for (i = 0; i < max_pages; i++) {
 700                pages[i] = alloc_page(gfp_flags);
 701                if (!pages[i])
 702                        goto out_free;
 703        }
 704
 705        memcpy(&pdev->dev_id, dev_id, sizeof(*dev_id));
 706        pdev->layout_type = LAYOUT_NFSV4_1_FILES;
 707        pdev->pages = pages;
 708        pdev->pgbase = 0;
 709        pdev->pglen = max_resp_sz;
 710        pdev->mincount = 0;
 711
 712        rc = nfs4_proc_getdeviceinfo(server, pdev);
 713        dprintk("%s getdevice info returns %d\n", __func__, rc);
 714        if (rc)
 715                goto out_free;
 716
 717        /*
 718         * Found new device, need to decode it and then add it to the
 719         * list of known devices for this mountpoint.
 720         */
 721        dsaddr = decode_and_add_device(inode, pdev, gfp_flags);
 722out_free:
 723        for (i = 0; i < max_pages; i++)
 724                __free_page(pages[i]);
 725        kfree(pages);
 726        kfree(pdev);
 727        dprintk("<-- %s dsaddr %p\n", __func__, dsaddr);
 728        return dsaddr;
 729}
 730
 731void
 732nfs4_fl_put_deviceid(struct nfs4_file_layout_dsaddr *dsaddr)
 733{
 734        nfs4_put_deviceid_node(&dsaddr->id_node);
 735}
 736
 737/*
 738 * Want res = (offset - layout->pattern_offset)/ layout->stripe_unit
 739 * Then: ((res + fsi) % dsaddr->stripe_count)
 740 */
 741u32
 742nfs4_fl_calc_j_index(struct pnfs_layout_segment *lseg, loff_t offset)
 743{
 744        struct nfs4_filelayout_segment *flseg = FILELAYOUT_LSEG(lseg);
 745        u64 tmp;
 746
 747        tmp = offset - flseg->pattern_offset;
 748        do_div(tmp, flseg->stripe_unit);
 749        tmp += flseg->first_stripe_index;
 750        return do_div(tmp, flseg->dsaddr->stripe_count);
 751}
 752
 753u32
 754nfs4_fl_calc_ds_index(struct pnfs_layout_segment *lseg, u32 j)
 755{
 756        return FILELAYOUT_LSEG(lseg)->dsaddr->stripe_indices[j];
 757}
 758
 759struct nfs_fh *
 760nfs4_fl_select_ds_fh(struct pnfs_layout_segment *lseg, u32 j)
 761{
 762        struct nfs4_filelayout_segment *flseg = FILELAYOUT_LSEG(lseg);
 763        u32 i;
 764
 765        if (flseg->stripe_type == STRIPE_SPARSE) {
 766                if (flseg->num_fh == 1)
 767                        i = 0;
 768                else if (flseg->num_fh == 0)
 769                        /* Use the MDS OPEN fh set in nfs_read_rpcsetup */
 770                        return NULL;
 771                else
 772                        i = nfs4_fl_calc_ds_index(lseg, j);
 773        } else
 774                i = j;
 775        return flseg->fh_array[i];
 776}
 777
 778struct nfs4_pnfs_ds *
 779nfs4_fl_prepare_ds(struct pnfs_layout_segment *lseg, u32 ds_idx)
 780{
 781        struct nfs4_file_layout_dsaddr *dsaddr = FILELAYOUT_LSEG(lseg)->dsaddr;
 782        struct nfs4_pnfs_ds *ds = dsaddr->ds_list[ds_idx];
 783        struct nfs4_deviceid_node *devid = FILELAYOUT_DEVID_NODE(lseg);
 784
 785        if (filelayout_test_devid_unavailable(devid))
 786                return NULL;
 787
 788        if (ds == NULL) {
 789                printk(KERN_ERR "NFS: %s: No data server for offset index %d\n",
 790                        __func__, ds_idx);
 791                filelayout_mark_devid_invalid(devid);
 792                return NULL;
 793        }
 794
 795        if (!ds->ds_clp) {
 796                struct nfs_server *s = NFS_SERVER(lseg->pls_layout->plh_inode);
 797                int err;
 798
 799                err = nfs4_ds_connect(s, ds);
 800                if (err) {
 801                        nfs4_mark_deviceid_unavailable(devid);
 802                        return NULL;
 803                }
 804        }
 805        return ds;
 806}
 807
 808module_param(dataserver_retrans, uint, 0644);
 809MODULE_PARM_DESC(dataserver_retrans, "The  number of times the NFSv4.1 client "
 810                        "retries a request before it attempts further "
 811                        " recovery  action.");
 812module_param(dataserver_timeo, uint, 0644);
 813MODULE_PARM_DESC(dataserver_timeo, "The time (in tenths of a second) the "
 814                        "NFSv4.1  client  waits for a response from a "
 815                        " data server before it retries an NFS request.");
 816
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.