linux/fs/nfsd/export.c
<<
>>
Prefs
   1#define MSNFS   /* HACK HACK */
   2/*
   3 * linux/fs/nfsd/export.c
   4 *
   5 * NFS exporting and validation.
   6 *
   7 * We maintain a list of clients, each of which has a list of
   8 * exports. To export an fs to a given client, you first have
   9 * to create the client entry with NFSCTL_ADDCLIENT, which
  10 * creates a client control block and adds it to the hash
  11 * table. Then, you call NFSCTL_EXPORT for each fs.
  12 *
  13 *
  14 * Copyright (C) 1995, 1996 Olaf Kirch, <okir@monad.swb.de>
  15 */
  16
  17#include <linux/unistd.h>
  18#include <linux/slab.h>
  19#include <linux/stat.h>
  20#include <linux/in.h>
  21#include <linux/seq_file.h>
  22#include <linux/syscalls.h>
  23#include <linux/rwsem.h>
  24#include <linux/dcache.h>
  25#include <linux/namei.h>
  26#include <linux/mount.h>
  27#include <linux/hash.h>
  28#include <linux/module.h>
  29#include <linux/exportfs.h>
  30
  31#include <linux/sunrpc/svc.h>
  32#include <linux/nfsd/nfsd.h>
  33#include <linux/nfsd/nfsfh.h>
  34#include <linux/nfsd/syscall.h>
  35#include <linux/lockd/bind.h>
  36#include <linux/sunrpc/msg_prot.h>
  37#include <linux/sunrpc/gss_api.h>
  38#include <net/ipv6.h>
  39
  40#define NFSDDBG_FACILITY        NFSDDBG_EXPORT
  41
  42typedef struct auth_domain      svc_client;
  43typedef struct svc_export       svc_export;
  44
  45static void             exp_do_unexport(svc_export *unexp);
  46static int              exp_verify_string(char *cp, int max);
  47
  48/*
  49 * We have two caches.
  50 * One maps client+vfsmnt+dentry to export options - the export map
  51 * The other maps client+filehandle-fragment to export options. - the expkey map
  52 *
  53 * The export options are actually stored in the first map, and the
  54 * second map contains a reference to the entry in the first map.
  55 */
  56
  57#define EXPKEY_HASHBITS         8
  58#define EXPKEY_HASHMAX          (1 << EXPKEY_HASHBITS)
  59#define EXPKEY_HASHMASK         (EXPKEY_HASHMAX -1)
  60static struct cache_head *expkey_table[EXPKEY_HASHMAX];
  61
  62static void expkey_put(struct kref *ref)
  63{
  64        struct svc_expkey *key = container_of(ref, struct svc_expkey, h.ref);
  65
  66        if (test_bit(CACHE_VALID, &key->h.flags) &&
  67            !test_bit(CACHE_NEGATIVE, &key->h.flags))
  68                path_put(&key->ek_path);
  69        auth_domain_put(key->ek_client);
  70        kfree(key);
  71}
  72
  73static void expkey_request(struct cache_detail *cd,
  74                           struct cache_head *h,
  75                           char **bpp, int *blen)
  76{
  77        /* client fsidtype \xfsid */
  78        struct svc_expkey *ek = container_of(h, struct svc_expkey, h);
  79        char type[5];
  80
  81        qword_add(bpp, blen, ek->ek_client->name);
  82        snprintf(type, 5, "%d", ek->ek_fsidtype);
  83        qword_add(bpp, blen, type);
  84        qword_addhex(bpp, blen, (char*)ek->ek_fsid, key_len(ek->ek_fsidtype));
  85        (*bpp)[-1] = '\n';
  86}
  87
  88static int expkey_upcall(struct cache_detail *cd, struct cache_head *h)
  89{
  90        return sunrpc_cache_pipe_upcall(cd, h, expkey_request);
  91}
  92
  93static struct svc_expkey *svc_expkey_update(struct svc_expkey *new, struct svc_expkey *old);
  94static struct svc_expkey *svc_expkey_lookup(struct svc_expkey *);
  95static struct cache_detail svc_expkey_cache;
  96
  97static int expkey_parse(struct cache_detail *cd, char *mesg, int mlen)
  98{
  99        /* client fsidtype fsid [path] */
 100        char *buf;
 101        int len;
 102        struct auth_domain *dom = NULL;
 103        int err;
 104        int fsidtype;
 105        char *ep;
 106        struct svc_expkey key;
 107        struct svc_expkey *ek = NULL;
 108
 109        if (mesg[mlen-1] != '\n')
 110                return -EINVAL;
 111        mesg[mlen-1] = 0;
 112
 113        buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
 114        err = -ENOMEM;
 115        if (!buf)
 116                goto out;
 117
 118        err = -EINVAL;
 119        if ((len=qword_get(&mesg, buf, PAGE_SIZE)) <= 0)
 120                goto out;
 121
 122        err = -ENOENT;
 123        dom = auth_domain_find(buf);
 124        if (!dom)
 125                goto out;
 126        dprintk("found domain %s\n", buf);
 127
 128        err = -EINVAL;
 129        if ((len=qword_get(&mesg, buf, PAGE_SIZE)) <= 0)
 130                goto out;
 131        fsidtype = simple_strtoul(buf, &ep, 10);
 132        if (*ep)
 133                goto out;
 134        dprintk("found fsidtype %d\n", fsidtype);
 135        if (key_len(fsidtype)==0) /* invalid type */
 136                goto out;
 137        if ((len=qword_get(&mesg, buf, PAGE_SIZE)) <= 0)
 138                goto out;
 139        dprintk("found fsid length %d\n", len);
 140        if (len != key_len(fsidtype))
 141                goto out;
 142
 143        /* OK, we seem to have a valid key */
 144        key.h.flags = 0;
 145        key.h.expiry_time = get_expiry(&mesg);
 146        if (key.h.expiry_time == 0)
 147                goto out;
 148
 149        key.ek_client = dom;    
 150        key.ek_fsidtype = fsidtype;
 151        memcpy(key.ek_fsid, buf, len);
 152
 153        ek = svc_expkey_lookup(&key);
 154        err = -ENOMEM;
 155        if (!ek)
 156                goto out;
 157
 158        /* now we want a pathname, or empty meaning NEGATIVE  */
 159        err = -EINVAL;
 160        len = qword_get(&mesg, buf, PAGE_SIZE);
 161        if (len < 0)
 162                goto out;
 163        dprintk("Path seems to be <%s>\n", buf);
 164        err = 0;
 165        if (len == 0) {
 166                set_bit(CACHE_NEGATIVE, &key.h.flags);
 167                ek = svc_expkey_update(&key, ek);
 168                if (!ek)
 169                        err = -ENOMEM;
 170        } else {
 171                err = kern_path(buf, 0, &key.ek_path);
 172                if (err)
 173                        goto out;
 174
 175                dprintk("Found the path %s\n", buf);
 176
 177                ek = svc_expkey_update(&key, ek);
 178                if (!ek)
 179                        err = -ENOMEM;
 180                path_put(&key.ek_path);
 181        }
 182        cache_flush();
 183 out:
 184        if (ek)
 185                cache_put(&ek->h, &svc_expkey_cache);
 186        if (dom)
 187                auth_domain_put(dom);
 188        kfree(buf);
 189        return err;
 190}
 191
 192static int expkey_show(struct seq_file *m,
 193                       struct cache_detail *cd,
 194                       struct cache_head *h)
 195{
 196        struct svc_expkey *ek ;
 197        int i;
 198
 199        if (h ==NULL) {
 200                seq_puts(m, "#domain fsidtype fsid [path]\n");
 201                return 0;
 202        }
 203        ek = container_of(h, struct svc_expkey, h);
 204        seq_printf(m, "%s %d 0x", ek->ek_client->name,
 205                   ek->ek_fsidtype);
 206        for (i=0; i < key_len(ek->ek_fsidtype)/4; i++)
 207                seq_printf(m, "%08x", ek->ek_fsid[i]);
 208        if (test_bit(CACHE_VALID, &h->flags) && 
 209            !test_bit(CACHE_NEGATIVE, &h->flags)) {
 210                seq_printf(m, " ");
 211                seq_path(m, &ek->ek_path, "\\ \t\n");
 212        }
 213        seq_printf(m, "\n");
 214        return 0;
 215}
 216
 217static inline int expkey_match (struct cache_head *a, struct cache_head *b)
 218{
 219        struct svc_expkey *orig = container_of(a, struct svc_expkey, h);
 220        struct svc_expkey *new = container_of(b, struct svc_expkey, h);
 221
 222        if (orig->ek_fsidtype != new->ek_fsidtype ||
 223            orig->ek_client != new->ek_client ||
 224            memcmp(orig->ek_fsid, new->ek_fsid, key_len(orig->ek_fsidtype)) != 0)
 225                return 0;
 226        return 1;
 227}
 228
 229static inline void expkey_init(struct cache_head *cnew,
 230                                   struct cache_head *citem)
 231{
 232        struct svc_expkey *new = container_of(cnew, struct svc_expkey, h);
 233        struct svc_expkey *item = container_of(citem, struct svc_expkey, h);
 234
 235        kref_get(&item->ek_client->ref);
 236        new->ek_client = item->ek_client;
 237        new->ek_fsidtype = item->ek_fsidtype;
 238
 239        memcpy(new->ek_fsid, item->ek_fsid, sizeof(new->ek_fsid));
 240}
 241
 242static inline void expkey_update(struct cache_head *cnew,
 243                                   struct cache_head *citem)
 244{
 245        struct svc_expkey *new = container_of(cnew, struct svc_expkey, h);
 246        struct svc_expkey *item = container_of(citem, struct svc_expkey, h);
 247
 248        new->ek_path = item->ek_path;
 249        path_get(&item->ek_path);
 250}
 251
 252static struct cache_head *expkey_alloc(void)
 253{
 254        struct svc_expkey *i = kmalloc(sizeof(*i), GFP_KERNEL);
 255        if (i)
 256                return &i->h;
 257        else
 258                return NULL;
 259}
 260
 261static struct cache_detail svc_expkey_cache = {
 262        .owner          = THIS_MODULE,
 263        .hash_size      = EXPKEY_HASHMAX,
 264        .hash_table     = expkey_table,
 265        .name           = "nfsd.fh",
 266        .cache_put      = expkey_put,
 267        .cache_upcall   = expkey_upcall,
 268        .cache_parse    = expkey_parse,
 269        .cache_show     = expkey_show,
 270        .match          = expkey_match,
 271        .init           = expkey_init,
 272        .update         = expkey_update,
 273        .alloc          = expkey_alloc,
 274};
 275
 276static struct svc_expkey *
 277svc_expkey_lookup(struct svc_expkey *item)
 278{
 279        struct cache_head *ch;
 280        int hash = item->ek_fsidtype;
 281        char * cp = (char*)item->ek_fsid;
 282        int len = key_len(item->ek_fsidtype);
 283
 284        hash ^= hash_mem(cp, len, EXPKEY_HASHBITS);
 285        hash ^= hash_ptr(item->ek_client, EXPKEY_HASHBITS);
 286        hash &= EXPKEY_HASHMASK;
 287
 288        ch = sunrpc_cache_lookup(&svc_expkey_cache, &item->h,
 289                                 hash);
 290        if (ch)
 291                return container_of(ch, struct svc_expkey, h);
 292        else
 293                return NULL;
 294}
 295
 296static struct svc_expkey *
 297svc_expkey_update(struct svc_expkey *new, struct svc_expkey *old)
 298{
 299        struct cache_head *ch;
 300        int hash = new->ek_fsidtype;
 301        char * cp = (char*)new->ek_fsid;
 302        int len = key_len(new->ek_fsidtype);
 303
 304        hash ^= hash_mem(cp, len, EXPKEY_HASHBITS);
 305        hash ^= hash_ptr(new->ek_client, EXPKEY_HASHBITS);
 306        hash &= EXPKEY_HASHMASK;
 307
 308        ch = sunrpc_cache_update(&svc_expkey_cache, &new->h,
 309                                 &old->h, hash);
 310        if (ch)
 311                return container_of(ch, struct svc_expkey, h);
 312        else
 313                return NULL;
 314}
 315
 316
 317#define EXPORT_HASHBITS         8
 318#define EXPORT_HASHMAX          (1<< EXPORT_HASHBITS)
 319#define EXPORT_HASHMASK         (EXPORT_HASHMAX -1)
 320
 321static struct cache_head *export_table[EXPORT_HASHMAX];
 322
 323static void nfsd4_fslocs_free(struct nfsd4_fs_locations *fsloc)
 324{
 325        int i;
 326
 327        for (i = 0; i < fsloc->locations_count; i++) {
 328                kfree(fsloc->locations[i].path);
 329                kfree(fsloc->locations[i].hosts);
 330        }
 331        kfree(fsloc->locations);
 332}
 333
 334static void svc_export_put(struct kref *ref)
 335{
 336        struct svc_export *exp = container_of(ref, struct svc_export, h.ref);
 337        path_put(&exp->ex_path);
 338        auth_domain_put(exp->ex_client);
 339        kfree(exp->ex_pathname);
 340        nfsd4_fslocs_free(&exp->ex_fslocs);
 341        kfree(exp);
 342}
 343
 344static void svc_export_request(struct cache_detail *cd,
 345                               struct cache_head *h,
 346                               char **bpp, int *blen)
 347{
 348        /*  client path */
 349        struct svc_export *exp = container_of(h, struct svc_export, h);
 350        char *pth;
 351
 352        qword_add(bpp, blen, exp->ex_client->name);
 353        pth = d_path(&exp->ex_path, *bpp, *blen);
 354        if (IS_ERR(pth)) {
 355                /* is this correct? */
 356                (*bpp)[0] = '\n';
 357                return;
 358        }
 359        qword_add(bpp, blen, pth);
 360        (*bpp)[-1] = '\n';
 361}
 362
 363static int svc_export_upcall(struct cache_detail *cd, struct cache_head *h)
 364{
 365        return sunrpc_cache_pipe_upcall(cd, h, svc_export_request);
 366}
 367
 368static struct svc_export *svc_export_update(struct svc_export *new,
 369                                            struct svc_export *old);
 370static struct svc_export *svc_export_lookup(struct svc_export *);
 371
 372static int check_export(struct inode *inode, int flags, unsigned char *uuid)
 373{
 374
 375        /* We currently export only dirs and regular files.
 376         * This is what umountd does.
 377         */
 378        if (!S_ISDIR(inode->i_mode) &&
 379            !S_ISREG(inode->i_mode))
 380                return -ENOTDIR;
 381
 382        /* There are two requirements on a filesystem to be exportable.
 383         * 1:  We must be able to identify the filesystem from a number.
 384         *       either a device number (so FS_REQUIRES_DEV needed)
 385         *       or an FSID number (so NFSEXP_FSID or ->uuid is needed).
 386         * 2:  We must be able to find an inode from a filehandle.
 387         *       This means that s_export_op must be set.
 388         */
 389        if (!(inode->i_sb->s_type->fs_flags & FS_REQUIRES_DEV) &&
 390            !(flags & NFSEXP_FSID) &&
 391            uuid == NULL) {
 392                dprintk("exp_export: export of non-dev fs without fsid\n");
 393                return -EINVAL;
 394        }
 395
 396        if (!inode->i_sb->s_export_op ||
 397            !inode->i_sb->s_export_op->fh_to_dentry) {
 398                dprintk("exp_export: export of invalid fs type.\n");
 399                return -EINVAL;
 400        }
 401
 402        return 0;
 403
 404}
 405
 406#ifdef CONFIG_NFSD_V4
 407
 408static int
 409fsloc_parse(char **mesg, char *buf, struct nfsd4_fs_locations *fsloc)
 410{
 411        int len;
 412        int migrated, i, err;
 413
 414        /* listsize */
 415        err = get_int(mesg, &fsloc->locations_count);
 416        if (err)
 417                return err;
 418        if (fsloc->locations_count > MAX_FS_LOCATIONS)
 419                return -EINVAL;
 420        if (fsloc->locations_count == 0)
 421                return 0;
 422
 423        fsloc->locations = kzalloc(fsloc->locations_count
 424                        * sizeof(struct nfsd4_fs_location), GFP_KERNEL);
 425        if (!fsloc->locations)
 426                return -ENOMEM;
 427        for (i=0; i < fsloc->locations_count; i++) {
 428                /* colon separated host list */
 429                err = -EINVAL;
 430                len = qword_get(mesg, buf, PAGE_SIZE);
 431                if (len <= 0)
 432                        goto out_free_all;
 433                err = -ENOMEM;
 434                fsloc->locations[i].hosts = kstrdup(buf, GFP_KERNEL);
 435                if (!fsloc->locations[i].hosts)
 436                        goto out_free_all;
 437                err = -EINVAL;
 438                /* slash separated path component list */
 439                len = qword_get(mesg, buf, PAGE_SIZE);
 440                if (len <= 0)
 441                        goto out_free_all;
 442                err = -ENOMEM;
 443                fsloc->locations[i].path = kstrdup(buf, GFP_KERNEL);
 444                if (!fsloc->locations[i].path)
 445                        goto out_free_all;
 446        }
 447        /* migrated */
 448        err = get_int(mesg, &migrated);
 449        if (err)
 450                goto out_free_all;
 451        err = -EINVAL;
 452        if (migrated < 0 || migrated > 1)
 453                goto out_free_all;
 454        fsloc->migrated = migrated;
 455        return 0;
 456out_free_all:
 457        nfsd4_fslocs_free(fsloc);
 458        return err;
 459}
 460
 461static int secinfo_parse(char **mesg, char *buf, struct svc_export *exp)
 462{
 463        int listsize, err;
 464        struct exp_flavor_info *f;
 465
 466        err = get_int(mesg, &listsize);
 467        if (err)
 468                return err;
 469        if (listsize < 0 || listsize > MAX_SECINFO_LIST)
 470                return -EINVAL;
 471
 472        for (f = exp->ex_flavors; f < exp->ex_flavors + listsize; f++) {
 473                err = get_int(mesg, &f->pseudoflavor);
 474                if (err)
 475                        return err;
 476                /*
 477                 * XXX: It would be nice to also check whether this
 478                 * pseudoflavor is supported, so we can discover the
 479                 * problem at export time instead of when a client fails
 480                 * to authenticate.
 481                 */
 482                err = get_int(mesg, &f->flags);
 483                if (err)
 484                        return err;
 485                /* Only some flags are allowed to differ between flavors: */
 486                if (~NFSEXP_SECINFO_FLAGS & (f->flags ^ exp->ex_flags))
 487                        return -EINVAL;
 488        }
 489        exp->ex_nflavors = listsize;
 490        return 0;
 491}
 492
 493#else /* CONFIG_NFSD_V4 */
 494static inline int
 495fsloc_parse(char **mesg, char *buf, struct nfsd4_fs_locations *fsloc){return 0;}
 496static inline int
 497secinfo_parse(char **mesg, char *buf, struct svc_export *exp) { return 0; }
 498#endif
 499
 500static int svc_export_parse(struct cache_detail *cd, char *mesg, int mlen)
 501{
 502        /* client path expiry [flags anonuid anongid fsid] */
 503        char *buf;
 504        int len;
 505        int err;
 506        struct auth_domain *dom = NULL;
 507        struct svc_export exp = {}, *expp;
 508        int an_int;
 509
 510        if (mesg[mlen-1] != '\n')
 511                return -EINVAL;
 512        mesg[mlen-1] = 0;
 513
 514        buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
 515        if (!buf)
 516                return -ENOMEM;
 517
 518        /* client */
 519        err = -EINVAL;
 520        len = qword_get(&mesg, buf, PAGE_SIZE);
 521        if (len <= 0)
 522                goto out;
 523
 524        err = -ENOENT;
 525        dom = auth_domain_find(buf);
 526        if (!dom)
 527                goto out;
 528
 529        /* path */
 530        err = -EINVAL;
 531        if ((len = qword_get(&mesg, buf, PAGE_SIZE)) <= 0)
 532                goto out1;
 533
 534        err = kern_path(buf, 0, &exp.ex_path);
 535        if (err)
 536                goto out1;
 537
 538        exp.ex_client = dom;
 539
 540        err = -ENOMEM;
 541        exp.ex_pathname = kstrdup(buf, GFP_KERNEL);
 542        if (!exp.ex_pathname)
 543                goto out2;
 544
 545        /* expiry */
 546        err = -EINVAL;
 547        exp.h.expiry_time = get_expiry(&mesg);
 548        if (exp.h.expiry_time == 0)
 549                goto out3;
 550
 551        /* flags */
 552        err = get_int(&mesg, &an_int);
 553        if (err == -ENOENT) {
 554                err = 0;
 555                set_bit(CACHE_NEGATIVE, &exp.h.flags);
 556        } else {
 557                if (err || an_int < 0)
 558                        goto out3;
 559                exp.ex_flags= an_int;
 560        
 561                /* anon uid */
 562                err = get_int(&mesg, &an_int);
 563                if (err)
 564                        goto out3;
 565                exp.ex_anon_uid= an_int;
 566
 567                /* anon gid */
 568                err = get_int(&mesg, &an_int);
 569                if (err)
 570                        goto out3;
 571                exp.ex_anon_gid= an_int;
 572
 573                /* fsid */
 574                err = get_int(&mesg, &an_int);
 575                if (err)
 576                        goto out3;
 577                exp.ex_fsid = an_int;
 578
 579                while ((len = qword_get(&mesg, buf, PAGE_SIZE)) > 0) {
 580                        if (strcmp(buf, "fsloc") == 0)
 581                                err = fsloc_parse(&mesg, buf, &exp.ex_fslocs);
 582                        else if (strcmp(buf, "uuid") == 0) {
 583                                /* expect a 16 byte uuid encoded as \xXXXX... */
 584                                len = qword_get(&mesg, buf, PAGE_SIZE);
 585                                if (len != 16)
 586                                        err  = -EINVAL;
 587                                else {
 588                                        exp.ex_uuid =
 589                                                kmemdup(buf, 16, GFP_KERNEL);
 590                                        if (exp.ex_uuid == NULL)
 591                                                err = -ENOMEM;
 592                                }
 593                        } else if (strcmp(buf, "secinfo") == 0)
 594                                err = secinfo_parse(&mesg, buf, &exp);
 595                        else
 596                                /* quietly ignore unknown words and anything
 597                                 * following. Newer user-space can try to set
 598                                 * new values, then see what the result was.
 599                                 */
 600                                break;
 601                        if (err)
 602                                goto out4;
 603                }
 604
 605                err = check_export(exp.ex_path.dentry->d_inode, exp.ex_flags,
 606                                   exp.ex_uuid);
 607                if (err)
 608                        goto out4;
 609        }
 610
 611        expp = svc_export_lookup(&exp);
 612        if (expp)
 613                expp = svc_export_update(&exp, expp);
 614        else
 615                err = -ENOMEM;
 616        cache_flush();
 617        if (expp == NULL)
 618                err = -ENOMEM;
 619        else
 620                exp_put(expp);
 621out4:
 622        nfsd4_fslocs_free(&exp.ex_fslocs);
 623        kfree(exp.ex_uuid);
 624out3:
 625        kfree(exp.ex_pathname);
 626out2:
 627        path_put(&exp.ex_path);
 628out1:
 629        auth_domain_put(dom);
 630out:
 631        kfree(buf);
 632        return err;
 633}
 634
 635static void exp_flags(struct seq_file *m, int flag, int fsid,
 636                uid_t anonu, uid_t anong, struct nfsd4_fs_locations *fslocs);
 637static void show_secinfo(struct seq_file *m, struct svc_export *exp);
 638
 639static int svc_export_show(struct seq_file *m,
 640                           struct cache_detail *cd,
 641                           struct cache_head *h)
 642{
 643        struct svc_export *exp ;
 644
 645        if (h ==NULL) {
 646                seq_puts(m, "#path domain(flags)\n");
 647                return 0;
 648        }
 649        exp = container_of(h, struct svc_export, h);
 650        seq_path(m, &exp->ex_path, " \t\n\\");
 651        seq_putc(m, '\t');
 652        seq_escape(m, exp->ex_client->name, " \t\n\\");
 653        seq_putc(m, '(');
 654        if (test_bit(CACHE_VALID, &h->flags) && 
 655            !test_bit(CACHE_NEGATIVE, &h->flags)) {
 656                exp_flags(m, exp->ex_flags, exp->ex_fsid,
 657                          exp->ex_anon_uid, exp->ex_anon_gid, &exp->ex_fslocs);
 658                if (exp->ex_uuid) {
 659                        int i;
 660                        seq_puts(m, ",uuid=");
 661                        for (i=0; i<16; i++) {
 662                                if ((i&3) == 0 && i)
 663                                        seq_putc(m, ':');
 664                                seq_printf(m, "%02x", exp->ex_uuid[i]);
 665                        }
 666                }
 667                show_secinfo(m, exp);
 668        }
 669        seq_puts(m, ")\n");
 670        return 0;
 671}
 672static int svc_export_match(struct cache_head *a, struct cache_head *b)
 673{
 674        struct svc_export *orig = container_of(a, struct svc_export, h);
 675        struct svc_export *new = container_of(b, struct svc_export, h);
 676        return orig->ex_client == new->ex_client &&
 677                orig->ex_path.dentry == new->ex_path.dentry &&
 678                orig->ex_path.mnt == new->ex_path.mnt;
 679}
 680
 681static void svc_export_init(struct cache_head *cnew, struct cache_head *citem)
 682{
 683        struct svc_export *new = container_of(cnew, struct svc_export, h);
 684        struct svc_export *item = container_of(citem, struct svc_export, h);
 685
 686        kref_get(&item->ex_client->ref);
 687        new->ex_client = item->ex_client;
 688        new->ex_path.dentry = dget(item->ex_path.dentry);
 689        new->ex_path.mnt = mntget(item->ex_path.mnt);
 690        new->ex_pathname = NULL;
 691        new->ex_fslocs.locations = NULL;
 692        new->ex_fslocs.locations_count = 0;
 693        new->ex_fslocs.migrated = 0;
 694}
 695
 696static void export_update(struct cache_head *cnew, struct cache_head *citem)
 697{
 698        struct svc_export *new = container_of(cnew, struct svc_export, h);
 699        struct svc_export *item = container_of(citem, struct svc_export, h);
 700        int i;
 701
 702        new->ex_flags = item->ex_flags;
 703        new->ex_anon_uid = item->ex_anon_uid;
 704        new->ex_anon_gid = item->ex_anon_gid;
 705        new->ex_fsid = item->ex_fsid;
 706        new->ex_uuid = item->ex_uuid;
 707        item->ex_uuid = NULL;
 708        new->ex_pathname = item->ex_pathname;
 709        item->ex_pathname = NULL;
 710        new->ex_fslocs.locations = item->ex_fslocs.locations;
 711        item->ex_fslocs.locations = NULL;
 712        new->ex_fslocs.locations_count = item->ex_fslocs.locations_count;
 713        item->ex_fslocs.locations_count = 0;
 714        new->ex_fslocs.migrated = item->ex_fslocs.migrated;
 715        item->ex_fslocs.migrated = 0;
 716        new->ex_nflavors = item->ex_nflavors;
 717        for (i = 0; i < MAX_SECINFO_LIST; i++) {
 718                new->ex_flavors[i] = item->ex_flavors[i];
 719        }
 720}
 721
 722static struct cache_head *svc_export_alloc(void)
 723{
 724        struct svc_export *i = kmalloc(sizeof(*i), GFP_KERNEL);
 725        if (i)
 726                return &i->h;
 727        else
 728                return NULL;
 729}
 730
 731struct cache_detail svc_export_cache = {
 732        .owner          = THIS_MODULE,
 733        .hash_size      = EXPORT_HASHMAX,
 734        .hash_table     = export_table,
 735        .name           = "nfsd.export",
 736        .cache_put      = svc_export_put,
 737        .cache_upcall   = svc_export_upcall,
 738        .cache_parse    = svc_export_parse,
 739        .cache_show     = svc_export_show,
 740        .match          = svc_export_match,
 741        .init           = svc_export_init,
 742        .update         = export_update,
 743        .alloc          = svc_export_alloc,
 744};
 745
 746static struct svc_export *
 747svc_export_lookup(struct svc_export *exp)
 748{
 749        struct cache_head *ch;
 750        int hash;
 751        hash = hash_ptr(exp->ex_client, EXPORT_HASHBITS);
 752        hash ^= hash_ptr(exp->ex_path.dentry, EXPORT_HASHBITS);
 753        hash ^= hash_ptr(exp->ex_path.mnt, EXPORT_HASHBITS);
 754
 755        ch = sunrpc_cache_lookup(&svc_export_cache, &exp->h,
 756                                 hash);
 757        if (ch)
 758                return container_of(ch, struct svc_export, h);
 759        else
 760                return NULL;
 761}
 762
 763static struct svc_export *
 764svc_export_update(struct svc_export *new, struct svc_export *old)
 765{
 766        struct cache_head *ch;
 767        int hash;
 768        hash = hash_ptr(old->ex_client, EXPORT_HASHBITS);
 769        hash ^= hash_ptr(old->ex_path.dentry, EXPORT_HASHBITS);
 770        hash ^= hash_ptr(old->ex_path.mnt, EXPORT_HASHBITS);
 771
 772        ch = sunrpc_cache_update(&svc_export_cache, &new->h,
 773                                 &old->h,
 774                                 hash);
 775        if (ch)
 776                return container_of(ch, struct svc_export, h);
 777        else
 778                return NULL;
 779}
 780
 781
 782static struct svc_expkey *
 783exp_find_key(svc_client *clp, int fsid_type, u32 *fsidv, struct cache_req *reqp)
 784{
 785        struct svc_expkey key, *ek;
 786        int err;
 787        
 788        if (!clp)
 789                return ERR_PTR(-ENOENT);
 790
 791        key.ek_client = clp;
 792        key.ek_fsidtype = fsid_type;
 793        memcpy(key.ek_fsid, fsidv, key_len(fsid_type));
 794
 795        ek = svc_expkey_lookup(&key);
 796        if (ek == NULL)
 797                return ERR_PTR(-ENOMEM);
 798        err = cache_check(&svc_expkey_cache, &ek->h, reqp);
 799        if (err)
 800                return ERR_PTR(err);
 801        return ek;
 802}
 803
 804static int exp_set_key(svc_client *clp, int fsid_type, u32 *fsidv,
 805                       struct svc_export *exp)
 806{
 807        struct svc_expkey key, *ek;
 808
 809        key.ek_client = clp;
 810        key.ek_fsidtype = fsid_type;
 811        memcpy(key.ek_fsid, fsidv, key_len(fsid_type));
 812        key.ek_path = exp->ex_path;
 813        key.h.expiry_time = NEVER;
 814        key.h.flags = 0;
 815
 816        ek = svc_expkey_lookup(&key);
 817        if (ek)
 818                ek = svc_expkey_update(&key,ek);
 819        if (ek) {
 820                cache_put(&ek->h, &svc_expkey_cache);
 821                return 0;
 822        }
 823        return -ENOMEM;
 824}
 825
 826/*
 827 * Find the client's export entry matching xdev/xino.
 828 */
 829static inline struct svc_expkey *
 830exp_get_key(svc_client *clp, dev_t dev, ino_t ino)
 831{
 832        u32 fsidv[3];
 833        
 834        if (old_valid_dev(dev)) {
 835                mk_fsid(FSID_DEV, fsidv, dev, ino, 0, NULL);
 836                return exp_find_key(clp, FSID_DEV, fsidv, NULL);
 837        }
 838        mk_fsid(FSID_ENCODE_DEV, fsidv, dev, ino, 0, NULL);
 839        return exp_find_key(clp, FSID_ENCODE_DEV, fsidv, NULL);
 840}
 841
 842/*
 843 * Find the client's export entry matching fsid
 844 */
 845static inline struct svc_expkey *
 846exp_get_fsid_key(svc_client *clp, int fsid)
 847{
 848        u32 fsidv[2];
 849
 850        mk_fsid(FSID_NUM, fsidv, 0, 0, fsid, NULL);
 851
 852        return exp_find_key(clp, FSID_NUM, fsidv, NULL);
 853}
 854
 855static svc_export *exp_get_by_name(svc_client *clp, const struct path *path,
 856                                     struct cache_req *reqp)
 857{
 858        struct svc_export *exp, key;
 859        int err;
 860
 861        if (!clp)
 862                return ERR_PTR(-ENOENT);
 863
 864        key.ex_client = clp;
 865        key.ex_path = *path;
 866
 867        exp = svc_export_lookup(&key);
 868        if (exp == NULL)
 869                return ERR_PTR(-ENOMEM);
 870        err = cache_check(&svc_export_cache, &exp->h, reqp);
 871        if (err)
 872                return ERR_PTR(err);
 873        return exp;
 874}
 875
 876/*
 877 * Find the export entry for a given dentry.
 878 */
 879static struct svc_export *exp_parent(svc_client *clp, struct path *path)
 880{
 881        struct dentry *saved = dget(path->dentry);
 882        svc_export *exp = exp_get_by_name(clp, path, NULL);
 883
 884        while (PTR_ERR(exp) == -ENOENT && !IS_ROOT(path->dentry)) {
 885                struct dentry *parent = dget_parent(path->dentry);
 886                dput(path->dentry);
 887                path->dentry = parent;
 888                exp = exp_get_by_name(clp, path, NULL);
 889        }
 890        dput(path->dentry);
 891        path->dentry = saved;
 892        return exp;
 893}
 894
 895/*
 896 * Hashtable locking. Write locks are placed only by user processes
 897 * wanting to modify export information.
 898 * Write locking only done in this file.  Read locking
 899 * needed externally.
 900 */
 901
 902static DECLARE_RWSEM(hash_sem);
 903
 904void
 905exp_readlock(void)
 906{
 907        down_read(&hash_sem);
 908}
 909
 910static inline void
 911exp_writelock(void)
 912{
 913        down_write(&hash_sem);
 914}
 915
 916void
 917exp_readunlock(void)
 918{
 919        up_read(&hash_sem);
 920}
 921
 922static inline void
 923exp_writeunlock(void)
 924{
 925        up_write(&hash_sem);
 926}
 927
 928static void exp_fsid_unhash(struct svc_export *exp)
 929{
 930        struct svc_expkey *ek;
 931
 932        if ((exp->ex_flags & NFSEXP_FSID) == 0)
 933                return;
 934
 935        ek = exp_get_fsid_key(exp->ex_client, exp->ex_fsid);
 936        if (!IS_ERR(ek)) {
 937                ek->h.expiry_time = get_seconds()-1;
 938                cache_put(&ek->h, &svc_expkey_cache);
 939        }
 940        svc_expkey_cache.nextcheck = get_seconds();
 941}
 942
 943static int exp_fsid_hash(svc_client *clp, struct svc_export *exp)
 944{
 945        u32 fsid[2];
 946 
 947        if ((exp->ex_flags & NFSEXP_FSID) == 0)
 948                return 0;
 949
 950        mk_fsid(FSID_NUM, fsid, 0, 0, exp->ex_fsid, NULL);
 951        return exp_set_key(clp, FSID_NUM, fsid, exp);
 952}
 953
 954static int exp_hash(struct auth_domain *clp, struct svc_export *exp)
 955{
 956        u32 fsid[2];
 957        struct inode *inode = exp->ex_path.dentry->d_inode;
 958        dev_t dev = inode->i_sb->s_dev;
 959
 960        if (old_valid_dev(dev)) {
 961                mk_fsid(FSID_DEV, fsid, dev, inode->i_ino, 0, NULL);
 962                return exp_set_key(clp, FSID_DEV, fsid, exp);
 963        }
 964        mk_fsid(FSID_ENCODE_DEV, fsid, dev, inode->i_ino, 0, NULL);
 965        return exp_set_key(clp, FSID_ENCODE_DEV, fsid, exp);
 966}
 967
 968static void exp_unhash(struct svc_export *exp)
 969{
 970        struct svc_expkey *ek;
 971        struct inode *inode = exp->ex_path.dentry->d_inode;
 972
 973        ek = exp_get_key(exp->ex_client, inode->i_sb->s_dev, inode->i_ino);
 974        if (!IS_ERR(ek)) {
 975                ek->h.expiry_time = get_seconds()-1;
 976                cache_put(&ek->h, &svc_expkey_cache);
 977        }
 978        svc_expkey_cache.nextcheck = get_seconds();
 979}
 980        
 981/*
 982 * Export a file system.
 983 */
 984int
 985exp_export(struct nfsctl_export *nxp)
 986{
 987        svc_client      *clp;
 988        struct svc_export       *exp = NULL;
 989        struct svc_export       new;
 990        struct svc_expkey       *fsid_key = NULL;
 991        struct path path;
 992        int             err;
 993
 994        /* Consistency check */
 995        err = -EINVAL;
 996        if (!exp_verify_string(nxp->ex_path, NFS_MAXPATHLEN) ||
 997            !exp_verify_string(nxp->ex_client, NFSCLNT_IDMAX))
 998                goto out;
 999
1000        dprintk("exp_export called for %s:%s (%x/%ld fl %x).\n",
1001                        nxp->ex_client, nxp->ex_path,
1002                        (unsigned)nxp->ex_dev, (long)nxp->ex_ino,
1003                        nxp->ex_flags);
1004
1005        /* Try to lock the export table for update */
1006        exp_writelock();
1007
1008        /* Look up client info */
1009        if (!(clp = auth_domain_find(nxp->ex_client)))
1010                goto out_unlock;
1011
1012
1013        /* Look up the dentry */
1014        err = kern_path(nxp->ex_path, 0, &path);
1015        if (err)
1016                goto out_put_clp;
1017        err = -EINVAL;
1018
1019        exp = exp_get_by_name(clp, &path, NULL);
1020
1021        memset(&new, 0, sizeof(new));
1022
1023        /* must make sure there won't be an ex_fsid clash */
1024        if ((nxp->ex_flags & NFSEXP_FSID) &&
1025            (!IS_ERR(fsid_key = exp_get_fsid_key(clp, nxp->ex_dev))) &&
1026            fsid_key->ek_path.mnt &&
1027            (fsid_key->ek_path.mnt != path.mnt ||
1028             fsid_key->ek_path.dentry != path.dentry))
1029                goto finish;
1030
1031        if (!IS_ERR(exp)) {
1032                /* just a flags/id/fsid update */
1033
1034                exp_fsid_unhash(exp);
1035                exp->ex_flags    = nxp->ex_flags;
1036                exp->ex_anon_uid = nxp->ex_anon_uid;
1037                exp->ex_anon_gid = nxp->ex_anon_gid;
1038                exp->ex_fsid     = nxp->ex_dev;
1039
1040                err = exp_fsid_hash(clp, exp);
1041                goto finish;
1042        }
1043
1044        err = check_export(path.dentry->d_inode, nxp->ex_flags, NULL);
1045        if (err) goto finish;
1046
1047        err = -ENOMEM;
1048
1049        dprintk("nfsd: creating export entry %p for client %p\n", exp, clp);
1050
1051        new.h.expiry_time = NEVER;
1052        new.h.flags = 0;
1053        new.ex_pathname = kstrdup(nxp->ex_path, GFP_KERNEL);
1054        if (!new.ex_pathname)
1055                goto finish;
1056        new.ex_client = clp;
1057        new.ex_path = path;
1058        new.ex_flags = nxp->ex_flags;
1059        new.ex_anon_uid = nxp->ex_anon_uid;
1060        new.ex_anon_gid = nxp->ex_anon_gid;
1061        new.ex_fsid = nxp->ex_dev;
1062
1063        exp = svc_export_lookup(&new);
1064        if (exp)
1065                exp = svc_export_update(&new, exp);
1066
1067        if (!exp)
1068                goto finish;
1069
1070        if (exp_hash(clp, exp) ||
1071            exp_fsid_hash(clp, exp)) {
1072                /* failed to create at least one index */
1073                exp_do_unexport(exp);
1074                cache_flush();
1075        } else
1076                err = 0;
1077finish:
1078        kfree(new.ex_pathname);
1079        if (exp)
1080                exp_put(exp);
1081        if (fsid_key && !IS_ERR(fsid_key))
1082                cache_put(&fsid_key->h, &svc_expkey_cache);
1083        path_put(&path);
1084out_put_clp:
1085        auth_domain_put(clp);
1086out_unlock:
1087        exp_writeunlock();
1088out:
1089        return err;
1090}
1091
1092/*
1093 * Unexport a file system. The export entry has already
1094 * been removed from the client's list of exported fs's.
1095 */
1096static void
1097exp_do_unexport(svc_export *unexp)
1098{
1099        unexp->h.expiry_time = get_seconds()-1;
1100        svc_export_cache.nextcheck = get_seconds();
1101        exp_unhash(unexp);
1102        exp_fsid_unhash(unexp);
1103}
1104
1105
1106/*
1107 * unexport syscall.
1108 */
1109int
1110exp_unexport(struct nfsctl_export *nxp)
1111{
1112        struct auth_domain *dom;
1113        svc_export *exp;
1114        struct path path;
1115        int             err;
1116
1117        /* Consistency check */
1118        if (!exp_verify_string(nxp->ex_path, NFS_MAXPATHLEN) ||
1119            !exp_verify_string(nxp->ex_client, NFSCLNT_IDMAX))
1120                return -EINVAL;
1121
1122        exp_writelock();
1123
1124        err = -EINVAL;
1125        dom = auth_domain_find(nxp->ex_client);
1126        if (!dom) {
1127                dprintk("nfsd: unexport couldn't find %s\n", nxp->ex_client);
1128                goto out_unlock;
1129        }
1130
1131        err = kern_path(nxp->ex_path, 0, &path);
1132        if (err)
1133                goto out_domain;
1134
1135        err = -EINVAL;
1136        exp = exp_get_by_name(dom, &path, NULL);
1137        path_put(&path);
1138        if (IS_ERR(exp))
1139                goto out_domain;
1140
1141        exp_do_unexport(exp);
1142        exp_put(exp);
1143        err = 0;
1144
1145out_domain:
1146        auth_domain_put(dom);
1147        cache_flush();
1148out_unlock:
1149        exp_writeunlock();
1150        return err;
1151}
1152
1153/*
1154 * Obtain the root fh on behalf of a client.
1155 * This could be done in user space, but I feel that it adds some safety
1156 * since its harder to fool a kernel module than a user space program.
1157 */
1158int
1159exp_rootfh(svc_client *clp, char *name, struct knfsd_fh *f, int maxsize)
1160{
1161        struct svc_export       *exp;
1162        struct path             path;
1163        struct inode            *inode;
1164        struct svc_fh           fh;
1165        int                     err;
1166
1167        err = -EPERM;
1168        /* NB: we probably ought to check that it's NUL-terminated */
1169        if (kern_path(name, 0, &path)) {
1170                printk("nfsd: exp_rootfh path not found %s", name);
1171                return err;
1172        }
1173        inode = path.dentry->d_inode;
1174
1175        dprintk("nfsd: exp_rootfh(%s [%p] %s:%s/%ld)\n",
1176                 name, path.dentry, clp->name,
1177                 inode->i_sb->s_id, inode->i_ino);
1178        exp = exp_parent(clp, &path);
1179        if (IS_ERR(exp)) {
1180                err = PTR_ERR(exp);
1181                goto out;
1182        }
1183
1184        /*
1185         * fh must be initialized before calling fh_compose
1186         */
1187        fh_init(&fh, maxsize);
1188        if (fh_compose(&fh, exp, path.dentry, NULL))
1189                err = -EINVAL;
1190        else
1191                err = 0;
1192        memcpy(f, &fh.fh_handle, sizeof(struct knfsd_fh));
1193        fh_put(&fh);
1194        exp_put(exp);
1195out:
1196        path_put(&path);
1197        return err;
1198}
1199
1200static struct svc_export *exp_find(struct auth_domain *clp, int fsid_type,
1201                                   u32 *fsidv, struct cache_req *reqp)
1202{
1203        struct svc_export *exp;
1204        struct svc_expkey *ek = exp_find_key(clp, fsid_type, fsidv, reqp);
1205        if (IS_ERR(ek))
1206                return ERR_CAST(ek);
1207
1208        exp = exp_get_by_name(clp, &ek->ek_path, reqp);
1209        cache_put(&ek->h, &svc_expkey_cache);
1210
1211        if (IS_ERR(exp))
1212                return ERR_CAST(exp);
1213        return exp;
1214}
1215
1216__be32 check_nfsd_access(struct svc_export *exp, struct svc_rqst *rqstp)
1217{
1218        struct exp_flavor_info *f;
1219        struct exp_flavor_info *end = exp->ex_flavors + exp->ex_nflavors;
1220
1221        /* legacy gss-only clients are always OK: */
1222        if (exp->ex_client == rqstp->rq_gssclient)
1223                return 0;
1224        /* ip-address based client; check sec= export option: */
1225        for (f = exp->ex_flavors; f < end; f++) {
1226                if (f->pseudoflavor == rqstp->rq_flavor)
1227                        return 0;
1228        }
1229        /* defaults in absence of sec= options: */
1230        if (exp->ex_nflavors == 0) {
1231                if (rqstp->rq_flavor == RPC_AUTH_NULL ||
1232                    rqstp->rq_flavor == RPC_AUTH_UNIX)
1233                        return 0;
1234        }
1235        return nfserr_wrongsec;
1236}
1237
1238/*
1239 * Uses rq_client and rq_gssclient to find an export; uses rq_client (an
1240 * auth_unix client) if it's available and has secinfo information;
1241 * otherwise, will try to use rq_gssclient.
1242 *
1243 * Called from functions that handle requests; functions that do work on
1244 * behalf of mountd are passed a single client name to use, and should
1245 * use exp_get_by_name() or exp_find().
1246 */
1247struct svc_export *
1248rqst_exp_get_by_name(struct svc_rqst *rqstp, struct path *path)
1249{
1250        struct svc_export *gssexp, *exp = ERR_PTR(-ENOENT);
1251
1252        if (rqstp->rq_client == NULL)
1253                goto gss;
1254
1255        /* First try the auth_unix client: */
1256        exp = exp_get_by_name(rqstp->rq_client, path, &rqstp->rq_chandle);
1257        if (PTR_ERR(exp) == -ENOENT)
1258                goto gss;
1259        if (IS_ERR(exp))
1260                return exp;
1261        /* If it has secinfo, assume there are no gss/... clients */
1262        if (exp->ex_nflavors > 0)
1263                return exp;
1264gss:
1265        /* Otherwise, try falling back on gss client */
1266        if (rqstp->rq_gssclient == NULL)
1267                return exp;
1268        gssexp = exp_get_by_name(rqstp->rq_gssclient, path, &rqstp->rq_chandle);
1269        if (PTR_ERR(gssexp) == -ENOENT)
1270                return exp;
1271        if (!IS_ERR(exp))
1272                exp_put(exp);
1273        return gssexp;
1274}
1275
1276struct svc_export *
1277rqst_exp_find(struct svc_rqst *rqstp, int fsid_type, u32 *fsidv)
1278{
1279        struct svc_export *gssexp, *exp = ERR_PTR(-ENOENT);
1280
1281        if (rqstp->rq_client == NULL)
1282                goto gss;
1283
1284        /* First try the auth_unix client: */
1285        exp = exp_find(rqstp->rq_client, fsid_type, fsidv, &rqstp->rq_chandle);
1286        if (PTR_ERR(exp) == -ENOENT)
1287                goto gss;
1288        if (IS_ERR(exp))
1289                return exp;
1290        /* If it has secinfo, assume there are no gss/... clients */
1291        if (exp->ex_nflavors > 0)
1292                return exp;
1293gss:
1294        /* Otherwise, try falling back on gss client */
1295        if (rqstp->rq_gssclient == NULL)
1296                return exp;
1297        gssexp = exp_find(rqstp->rq_gssclient, fsid_type, fsidv,
1298                                                &rqstp->rq_chandle);
1299        if (PTR_ERR(gssexp) == -ENOENT)
1300                return exp;
1301        if (!IS_ERR(exp))
1302                exp_put(exp);
1303        return gssexp;
1304}
1305
1306struct svc_export *
1307rqst_exp_parent(struct svc_rqst *rqstp, struct path *path)
1308{
1309        struct dentry *saved = dget(path->dentry);
1310        struct svc_export *exp = rqst_exp_get_by_name(rqstp, path);
1311
1312        while (PTR_ERR(exp) == -ENOENT && !IS_ROOT(path->dentry)) {
1313                struct dentry *parent = dget_parent(path->dentry);
1314                dput(path->dentry);
1315                path->dentry = parent;
1316                exp = rqst_exp_get_by_name(rqstp, path);
1317        }
1318        dput(path->dentry);
1319        path->dentry = saved;
1320        return exp;
1321}
1322
1323/*
1324 * Called when we need the filehandle for the root of the pseudofs,
1325 * for a given NFSv4 client.   The root is defined to be the
1326 * export point with fsid==0
1327 */
1328__be32
1329exp_pseudoroot(struct svc_rqst *rqstp, struct svc_fh *fhp)
1330{
1331        struct svc_export *exp;
1332        __be32 rv;
1333        u32 fsidv[2];
1334
1335        mk_fsid(FSID_NUM, fsidv, 0, 0, 0, NULL);
1336
1337        exp = rqst_exp_find(rqstp, FSID_NUM, fsidv);
1338        if (IS_ERR(exp))
1339                return nfserrno(PTR_ERR(exp));
1340        rv = fh_compose(fhp, exp, exp->ex_path.dentry, NULL);
1341        if (rv)
1342                goto out;
1343        rv = check_nfsd_access(exp, rqstp);
1344        if (rv)
1345                fh_put(fhp);
1346out:
1347        exp_put(exp);
1348        return rv;
1349}
1350
1351/* Iterator */
1352
1353static void *e_start(struct seq_file *m, loff_t *pos)
1354        __acquires(svc_export_cache.hash_lock)
1355{
1356        loff_t n = *pos;
1357        unsigned hash, export;
1358        struct cache_head *ch;
1359        
1360        exp_readlock();
1361        read_lock(&svc_export_cache.hash_lock);
1362        if (!n--)
1363                return SEQ_START_TOKEN;
1364        hash = n >> 32;
1365        export = n & ((1LL<<32) - 1);
1366
1367        
1368        for (ch=export_table[hash]; ch; ch=ch->next)
1369                if (!export--)
1370                        return ch;
1371        n &= ~((1LL<<32) - 1);
1372        do {
1373                hash++;
1374                n += 1LL<<32;
1375        } while(hash < EXPORT_HASHMAX && export_table[hash]==NULL);
1376        if (hash >= EXPORT_HASHMAX)
1377                return NULL;
1378        *pos = n+1;
1379        return export_table[hash];
1380}
1381
1382static void *e_next(struct seq_file *m, void *p, loff_t *pos)
1383{
1384        struct cache_head *ch = p;
1385        int hash = (*pos >> 32);
1386
1387        if (p == SEQ_START_TOKEN)
1388                hash = 0;
1389        else if (ch->next == NULL) {
1390                hash++;
1391                *pos += 1LL<<32;
1392        } else {
1393                ++*pos;
1394                return ch->next;
1395        }
1396        *pos &= ~((1LL<<32) - 1);
1397        while (hash < EXPORT_HASHMAX && export_table[hash] == NULL) {
1398                hash++;
1399                *pos += 1LL<<32;
1400        }
1401        if (hash >= EXPORT_HASHMAX)
1402                return NULL;
1403        ++*pos;
1404        return export_table[hash];
1405}
1406
1407static void e_stop(struct seq_file *m, void *p)
1408        __releases(svc_export_cache.hash_lock)
1409{
1410        read_unlock(&svc_export_cache.hash_lock);
1411        exp_readunlock();
1412}
1413
1414static struct flags {
1415        int flag;
1416        char *name[2];
1417} expflags[] = {
1418        { NFSEXP_READONLY, {"ro", "rw"}},
1419        { NFSEXP_INSECURE_PORT, {"insecure", ""}},
1420        { NFSEXP_ROOTSQUASH, {"root_squash", "no_root_squash"}},
1421        { NFSEXP_ALLSQUASH, {"all_squash", ""}},
1422        { NFSEXP_ASYNC, {"async", "sync"}},
1423        { NFSEXP_GATHERED_WRITES, {"wdelay", "no_wdelay"}},
1424        { NFSEXP_NOHIDE, {"nohide", ""}},
1425        { NFSEXP_CROSSMOUNT, {"crossmnt", ""}},
1426        { NFSEXP_NOSUBTREECHECK, {"no_subtree_check", ""}},
1427        { NFSEXP_NOAUTHNLM, {"insecure_locks", ""}},
1428#ifdef MSNFS
1429        { NFSEXP_MSNFS, {"msnfs", ""}},
1430#endif
1431        { 0, {"", ""}}
1432};
1433
1434static void show_expflags(struct seq_file *m, int flags, int mask)
1435{
1436        struct flags *flg;
1437        int state, first = 0;
1438
1439        for (flg = expflags; flg->flag; flg++) {
1440                if (flg->flag & ~mask)
1441                        continue;
1442                state = (flg->flag & flags) ? 0 : 1;
1443                if (*flg->name[state])
1444                        seq_printf(m, "%s%s", first++?",":"", flg->name[state]);
1445        }
1446}
1447
1448static void show_secinfo_flags(struct seq_file *m, int flags)
1449{
1450        seq_printf(m, ",");
1451        show_expflags(m, flags, NFSEXP_SECINFO_FLAGS);
1452}
1453
1454static void show_secinfo(struct seq_file *m, struct svc_export *exp)
1455{
1456        struct exp_flavor_info *f;
1457        struct exp_flavor_info *end = exp->ex_flavors + exp->ex_nflavors;
1458        int lastflags = 0, first = 0;
1459
1460        if (exp->ex_nflavors == 0)
1461                return;
1462        for (f = exp->ex_flavors; f < end; f++) {
1463                if (first || f->flags != lastflags) {
1464                        if (!first)
1465                                show_secinfo_flags(m, lastflags);
1466                        seq_printf(m, ",sec=%d", f->pseudoflavor);
1467                        lastflags = f->flags;
1468                } else {
1469                        seq_printf(m, ":%d", f->pseudoflavor);
1470                }
1471        }
1472        show_secinfo_flags(m, lastflags);
1473}
1474
1475static void exp_flags(struct seq_file *m, int flag, int fsid,
1476                uid_t anonu, uid_t anong, struct nfsd4_fs_locations *fsloc)
1477{
1478        show_expflags(m, flag, NFSEXP_ALLFLAGS);
1479        if (flag & NFSEXP_FSID)
1480                seq_printf(m, ",fsid=%d", fsid);
1481        if (anonu != (uid_t)-2 && anonu != (0x10000-2))
1482                seq_printf(m, ",anonuid=%u", anonu);
1483        if (anong != (gid_t)-2 && anong != (0x10000-2))
1484                seq_printf(m, ",anongid=%u", anong);
1485        if (fsloc && fsloc->locations_count > 0) {
1486                char *loctype = (fsloc->migrated) ? "refer" : "replicas";
1487                int i;
1488
1489                seq_printf(m, ",%s=", loctype);
1490                seq_escape(m, fsloc->locations[0].path, ",;@ \t\n\\");
1491                seq_putc(m, '@');
1492                seq_escape(m, fsloc->locations[0].hosts, ",;@ \t\n\\");
1493                for (i = 1; i < fsloc->locations_count; i++) {
1494                        seq_putc(m, ';');
1495                        seq_escape(m, fsloc->locations[i].path, ",;@ \t\n\\");
1496                        seq_putc(m, '@');
1497                        seq_escape(m, fsloc->locations[i].hosts, ",;@ \t\n\\");
1498                }
1499        }
1500}
1501
1502static int e_show(struct seq_file *m, void *p)
1503{
1504        struct cache_head *cp = p;
1505        struct svc_export *exp = container_of(cp, struct svc_export, h);
1506
1507        if (p == SEQ_START_TOKEN) {
1508                seq_puts(m, "# Version 1.1\n");
1509                seq_puts(m, "# Path Client(Flags) # IPs\n");
1510                return 0;
1511        }
1512
1513        cache_get(&exp->h);
1514        if (cache_check(&svc_export_cache, &exp->h, NULL))
1515                return 0;
1516        cache_put(&exp->h, &svc_export_cache);
1517        return svc_export_show(m, &svc_export_cache, cp);
1518}
1519
1520const struct seq_operations nfs_exports_op = {
1521        .start  = e_start,
1522        .next   = e_next,
1523        .stop   = e_stop,
1524        .show   = e_show,
1525};
1526
1527/*
1528 * Add or modify a client.
1529 * Change requests may involve the list of host addresses. The list of
1530 * exports and possibly existing uid maps are left untouched.
1531 */
1532int
1533exp_addclient(struct nfsctl_client *ncp)
1534{
1535        struct auth_domain      *dom;
1536        int                     i, err;
1537        struct in6_addr addr6;
1538
1539        /* First, consistency check. */
1540        err = -EINVAL;
1541        if (! exp_verify_string(ncp->cl_ident, NFSCLNT_IDMAX))
1542                goto out;
1543        if (ncp->cl_naddr > NFSCLNT_ADDRMAX)
1544                goto out;
1545
1546        /* Lock the hashtable */
1547        exp_writelock();
1548
1549        dom = unix_domain_find(ncp->cl_ident);
1550
1551        err = -ENOMEM;
1552        if (!dom)
1553                goto out_unlock;
1554
1555        /* Insert client into hashtable. */
1556        for (i = 0; i < ncp->cl_naddr; i++) {
1557                ipv6_addr_set_v4mapped(ncp->cl_addrlist[i].s_addr, &addr6);
1558                auth_unix_add_addr(&addr6, dom);
1559        }
1560        auth_unix_forget_old(dom);
1561        auth_domain_put(dom);
1562
1563        err = 0;
1564
1565out_unlock:
1566        exp_writeunlock();
1567out:
1568        return err;
1569}
1570
1571/*
1572 * Delete a client given an identifier.
1573 */
1574int
1575exp_delclient(struct nfsctl_client *ncp)
1576{
1577        int             err;
1578        struct auth_domain *dom;
1579
1580        err = -EINVAL;
1581        if (!exp_verify_string(ncp->cl_ident, NFSCLNT_IDMAX))
1582                goto out;
1583
1584        /* Lock the hashtable */
1585        exp_writelock();
1586
1587        dom = auth_domain_find(ncp->cl_ident);
1588        /* just make sure that no addresses work 
1589         * and that it will expire soon 
1590         */
1591        if (dom) {
1592                err = auth_unix_forget_old(dom);
1593                auth_domain_put(dom);
1594        }
1595
1596        exp_writeunlock();
1597out:
1598        return err;
1599}
1600
1601/*
1602 * Verify that string is non-empty and does not exceed max length.
1603 */
1604static int
1605exp_verify_string(char *cp, int max)
1606{
1607        int     i;
1608
1609        for (i = 0; i < max; i++)
1610                if (!cp[i])
1611                        return i;
1612        cp[i] = 0;
1613        printk(KERN_NOTICE "nfsd: couldn't validate string %s\n", cp);
1614        return 0;
1615}
1616
1617/*
1618 * Initialize the exports module.
1619 */
1620int
1621nfsd_export_init(void)
1622{
1623        int rv;
1624        dprintk("nfsd: initializing export module.\n");
1625
1626        rv = cache_register(&svc_export_cache);
1627        if (rv)
1628                return rv;
1629        rv = cache_register(&svc_expkey_cache);
1630        if (rv)
1631                cache_unregister(&svc_export_cache);
1632        return rv;
1633
1634}
1635
1636/*
1637 * Flush exports table - called when last nfsd thread is killed
1638 */
1639void
1640nfsd_export_flush(void)
1641{
1642        exp_writelock();
1643        cache_purge(&svc_expkey_cache);
1644        cache_purge(&svc_export_cache);
1645        exp_writeunlock();
1646}
1647
1648/*
1649 * Shutdown the exports module.
1650 */
1651void
1652nfsd_export_shutdown(void)
1653{
1654
1655        dprintk("nfsd: shutting down export module.\n");
1656
1657        exp_writelock();
1658
1659        cache_unregister(&svc_expkey_cache);
1660        cache_unregister(&svc_export_cache);
1661        svcauth_unix_purge();
1662
1663        exp_writeunlock();
1664        dprintk("nfsd: export shutdown complete.\n");
1665}
1666