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