Print this page
11083 support NFS server in zone
Portions contributed by: Dan Kruchinin <dan.kruchinin@nexenta.com>
Portions contributed by: Stepan Zastupov <stepan.zastupov@gmail.com>
Portions contributed by: Joyce McIntosh <joyce.mcintosh@nexenta.com>
Portions contributed by: Mike Zeller <mike@mikezeller.net>
Portions contributed by: Dan McDonald <danmcd@joyent.com>
Portions contributed by: Gordon Ross <gordon.w.ross@gmail.com>
Portions contributed by: Vitaliy Gusev <gusev.vitaliy@gmail.com>
Reviewed by: Rick McNeal <rick.mcneal@nexenta.com>
Reviewed by: Rob Gittins <rob.gittins@nexenta.com>
Reviewed by: Sanjay Nadkarni <sanjay.nadkarni@nexenta.com>
Reviewed by: Jason King <jbk@joyent.com>
Reviewed by: C Fraire <cfraire@me.com>
Change-Id: I22f289d357503f9b48a0bc2482cc4328a6d43d16

Split Close
Expand all
Collapse all
          --- old/usr/src/uts/common/fs/nfs/nfs_export.c
          +++ new/usr/src/uts/common/fs/nfs/nfs_export.c
↓ open down ↓ 12 lines elided ↑ open up ↑
  13   13   * When distributing Covered Code, include this CDDL HEADER in each
  14   14   * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15   15   * If applicable, add the following below this CDDL HEADER, with the
  16   16   * fields enclosed by brackets "[]" replaced with your own identifying
  17   17   * information: Portions Copyright [yyyy] [name of copyright owner]
  18   18   *
  19   19   * CDDL HEADER END
  20   20   */
  21   21  
  22   22  /*
  23      - * Copyright 2015 Nexenta Systems, Inc.  All rights reserved.
  24   23   * Copyright (c) 1990, 2010, Oracle and/or its affiliates. All rights reserved.
  25   24   */
  26   25  
  27   26  /*
  28      - *      Copyright 1983, 1984, 1985, 1986, 1987, 1988, 1989  AT&T.
       27 + *      Copyright 1983, 1984, 1985, 1986, 1987, 1988, 1989  AT&T.
  29   28   *              All rights reserved.
  30   29   */
  31   30  
       31 +/*
       32 + * Copyright 2018 Nexenta Systems, Inc.
       33 + */
  32   34  
  33   35  #include <sys/types.h>
  34   36  #include <sys/param.h>
  35   37  #include <sys/time.h>
  36   38  #include <sys/vfs.h>
  37   39  #include <sys/vnode.h>
  38   40  #include <sys/socket.h>
  39   41  #include <sys/errno.h>
  40   42  #include <sys/uio.h>
  41   43  #include <sys/proc.h>
↓ open down ↓ 16 lines elided ↑ open up ↑
  58   60  #include <rpc/svc.h>
  59   61  
  60   62  #include <nfs/nfs.h>
  61   63  #include <nfs/export.h>
  62   64  #include <nfs/nfssys.h>
  63   65  #include <nfs/nfs_clnt.h>
  64   66  #include <nfs/nfs_acl.h>
  65   67  #include <nfs/nfs_log.h>
  66   68  #include <nfs/lm.h>
  67   69  #include <sys/sunddi.h>
  68      -#include <sys/pkp_hash.h>
  69   70  
  70      -treenode_t *ns_root;
       71 +/*
       72 + * exi_id support
       73 + *
       74 + * exi_id_next          The next exi_id available.
       75 + * exi_id_overflow      The exi_id_next already overflowed, so we should
       76 + *                      thoroughly check for duplicates.
       77 + * exi_id_tree          AVL tree indexed by exi_id.
       78 + * nfs_exi_id_lock      Lock to protect the export ID list
       79 + *
       80 + * All exi_id_next, exi_id_overflow, and exi_id_tree are protected by
       81 + * nfs_exi_id_lock.
       82 + */
       83 +static int exi_id_next;
       84 +static bool_t exi_id_overflow;
       85 +avl_tree_t exi_id_tree;
       86 +kmutex_t nfs_exi_id_lock;
  71   87  
  72      -struct exportinfo *exptable_path_hash[PKP_HASH_SIZE];
  73      -struct exportinfo *exptable[EXPTABLESIZE];
  74      -
  75      -static int      unexport(exportinfo_t *);
       88 +static int      unexport(nfs_export_t *, exportinfo_t *);
  76   89  static void     exportfree(exportinfo_t *);
  77   90  static int      loadindex(exportdata_t *);
  78   91  
  79   92  extern void     nfsauth_cache_free(exportinfo_t *);
  80   93  extern int      sec_svc_loadrootnames(int, int, caddr_t **, model_t);
  81   94  extern void     sec_svc_freerootnames(int, int, caddr_t *);
  82   95  
  83      -static int build_seclist_nodups(exportdata_t *, secinfo_t *, int);
  84      -static void srv_secinfo_add(secinfo_t **, int *, secinfo_t *, int, int);
  85      -static void srv_secinfo_remove(secinfo_t **, int *, secinfo_t *, int);
  86      -static void srv_secinfo_treeclimb(exportinfo_t *, secinfo_t *, int, bool_t);
       96 +static int      build_seclist_nodups(exportdata_t *, secinfo_t *, int);
       97 +static void     srv_secinfo_add(secinfo_t **, int *, secinfo_t *, int, int);
       98 +static void     srv_secinfo_remove(secinfo_t **, int *, secinfo_t *, int);
       99 +static void     srv_secinfo_treeclimb(nfs_export_t *, exportinfo_t *,
      100 +                    secinfo_t *, int, bool_t);
  87  101  
  88  102  #ifdef VOLATILE_FH_TEST
  89  103  static struct ex_vol_rename *find_volrnm_fh(exportinfo_t *, nfs_fh4 *);
  90  104  static uint32_t find_volrnm_fh_id(exportinfo_t *, nfs_fh4 *);
  91      -static void free_volrnm_list(exportinfo_t *);
      105 +static void     free_volrnm_list(exportinfo_t *);
  92  106  #endif /* VOLATILE_FH_TEST */
  93  107  
  94      -/*
  95      - * exported_lock        Read/Write lock that protects the exportinfo list.
  96      - *                      This lock must be held when searching or modifiying
  97      - *                      the exportinfo list.
  98      - */
  99      -krwlock_t exported_lock;
 100      -
 101      -/*
 102      - * "public" and default (root) location for public filehandle
 103      - */
 104      -struct exportinfo *exi_public, *exi_root;
 105      -
 106      -fid_t exi_rootfid;      /* for checking the default public file handle */
 107      -
 108  108  fhandle_t nullfh2;      /* for comparing V2 filehandles */
 109  109  
 110  110  /*
 111  111   * macro for static dtrace probes to trace server namespace ref count mods.
 112  112   */
 113  113  #define SECREF_TRACE(seclist, tag, flav, aftcnt) \
 114  114          DTRACE_PROBE4(nfss__i__nmspc__secref, struct secinfo *, (seclist), \
 115  115                  char *, (tag), int, (int)(flav), int, (int)(aftcnt))
 116  116  
 117  117  
 118  118  #define exptablehash(fsid, fid) (nfs_fhhash((fsid), (fid)) & (EXPTABLESIZE - 1))
 119  119  
      120 +extern nfs_export_t *
      121 +nfs_get_export(void)
      122 +{
      123 +        nfs_globals_t *ng = nfs_srv_getzg();
      124 +        nfs_export_t *ne = ng->nfs_export;
      125 +        ASSERT(ne != NULL);
      126 +        return (ne);
      127 +}
      128 +
 120  129  static uint8_t
 121  130  xor_hash(uint8_t *data, int len)
 122  131  {
 123  132          uint8_t h = 0;
 124  133  
 125  134          while (len--)
 126  135                  h ^= *data++;
 127  136  
 128  137          return (h);
 129  138  }
↓ open down ↓ 556 lines elided ↑ open up ↑
 686  695          exportinfo_t *exi_ret = NULL;
 687  696  
 688  697          for (;;) {
 689  698                  tnode = tnode->tree_parent;
 690  699                  if (TREE_ROOT(tnode)) {
 691  700                          exi_ret = tnode->tree_exi;
 692  701                          break;
 693  702                  }
 694  703          }
 695  704  
 696      -        ASSERT(exi_ret); /* Every visible should have its home exportinfo */
      705 +        /* Every visible should have its home exportinfo */
      706 +        ASSERT(exi_ret != NULL);
 697  707          return (exi_ret);
 698  708  }
 699  709  
 700  710  /*
 701  711   * For NFS V4.
 702  712   * Add or remove the newly exported or unexported security flavors of the
 703  713   * given exportinfo from its ancestors upto the system root.
 704  714   */
 705      -void
 706      -srv_secinfo_treeclimb(exportinfo_t *exip, secinfo_t *sec, int seccnt,
 707      -    bool_t isadd)
      715 +static void
      716 +srv_secinfo_treeclimb(nfs_export_t *ne, exportinfo_t *exip, secinfo_t *sec,
      717 +    int seccnt, bool_t isadd)
 708  718  {
 709      -        treenode_t *tnode = exip->exi_tree;
      719 +        treenode_t *tnode;
 710  720  
 711      -        ASSERT(RW_WRITE_HELD(&exported_lock));
 712      -        ASSERT(tnode != NULL);
      721 +        ASSERT(RW_WRITE_HELD(&ne->exported_lock));
 713  722  
      723 +        /*
      724 +         * exi_tree can be null for the zone root
      725 +         * which means we're already at the "top"
      726 +         * and there's nothing more to "climb".
      727 +         */
      728 +        tnode = exip->exi_tree;
      729 +        if (tnode == NULL) {
      730 +                /* Should only happen for... */
      731 +                ASSERT(exip == ne->exi_root);
      732 +                return;
      733 +        }
      734 +
 714  735          if (seccnt == 0)
 715  736                  return;
 716  737  
 717  738          /*
 718  739           * If flavors are being added and the new export root isn't
 719  740           * also VROOT, its implicitly allowed flavors are inherited from
 720  741           * its pseudonode.
 721  742           * Note - for VROOT exports the implicitly allowed flavors were
 722  743           * transferred from the PSEUDO export in exportfs()
 723  744           */
 724  745          if (isadd && !(exip->exi_vp->v_flag & VROOT) &&
      746 +            !VN_CMP(exip->exi_vp, EXI_TO_ZONEROOTVP(exip)) &&
 725  747              tnode->tree_vis->vis_seccnt > 0) {
 726  748                  srv_secinfo_add(&exip->exi_export.ex_secinfo,
 727  749                      &exip->exi_export.ex_seccnt, tnode->tree_vis->vis_secinfo,
 728  750                      tnode->tree_vis->vis_seccnt, FALSE);
 729  751          }
 730  752  
 731  753          /*
 732  754           * Move to parent node and propagate sec flavor
 733  755           * to exportinfo and to visible structures.
 734  756           */
↓ open down ↓ 40 lines elided ↑ open up ↑
 775  797  
 776  798  #define exp_hash_link(exi, hash_name, bucket) \
 777  799          (exi)->hash_name.bckt = (bucket); \
 778  800          (exi)->hash_name.prev = NULL; \
 779  801          (exi)->hash_name.next = *(bucket); \
 780  802          if ((exi)->hash_name.next) \
 781  803                  (exi)->hash_name.next->hash_name.prev = (exi); \
 782  804          *(bucket) = (exi);
 783  805  
 784  806  void
 785      -export_link(exportinfo_t *exi)
      807 +export_link(nfs_export_t *ne, exportinfo_t *exi)
 786  808  {
 787  809          exportinfo_t **bckt;
 788  810  
 789      -        bckt = &exptable[exptablehash(&exi->exi_fsid, &exi->exi_fid)];
      811 +        ASSERT(RW_WRITE_HELD(&ne->exported_lock));
      812 +
      813 +        bckt = &ne->exptable[exptablehash(&exi->exi_fsid, &exi->exi_fid)];
 790  814          exp_hash_link(exi, fid_hash, bckt);
 791  815  
 792      -        bckt = &exptable_path_hash[pkp_tab_hash(exi->exi_export.ex_path,
      816 +        bckt = &ne->exptable_path_hash[pkp_tab_hash(exi->exi_export.ex_path,
 793  817              strlen(exi->exi_export.ex_path))];
 794  818          exp_hash_link(exi, path_hash, bckt);
      819 +        exi->exi_ne = ne;
 795  820  }
 796  821  
 797  822  /*
 798      - * Initialization routine for export routines. Should only be called once.
      823 + * Helper functions for exi_id handling
 799  824   */
      825 +static int
      826 +exi_id_compar(const void *v1, const void *v2)
      827 +{
      828 +        const struct exportinfo *e1 = v1;
      829 +        const struct exportinfo *e2 = v2;
      830 +
      831 +        if (e1->exi_id < e2->exi_id)
      832 +                return (-1);
      833 +        if (e1->exi_id > e2->exi_id)
      834 +                return (1);
      835 +
      836 +        return (0);
      837 +}
      838 +
 800  839  int
 801      -nfs_exportinit(void)
      840 +exi_id_get_next()
 802  841  {
 803      -        int error;
      842 +        struct exportinfo e;
      843 +        int ret = exi_id_next;
      844 +
      845 +        ASSERT(MUTEX_HELD(&nfs_exi_id_lock));
      846 +
      847 +        do {
      848 +                exi_id_next++;
      849 +                if (exi_id_next == 0)
      850 +                        exi_id_overflow = TRUE;
      851 +
      852 +                if (!exi_id_overflow)
      853 +                        break;
      854 +
      855 +                if (exi_id_next == ret)
      856 +                        cmn_err(CE_PANIC, "exi_id exhausted");
      857 +
      858 +                e.exi_id = exi_id_next;
      859 +        } while (avl_find(&exi_id_tree, &e, NULL) != NULL);
      860 +
      861 +        return (ret);
      862 +}
      863 +
      864 +/*
      865 + * Get the root file handle for this zone.
      866 + * Called when nfs_svc() starts
      867 + */
      868 +int
      869 +nfs_export_get_rootfh(nfs_globals_t *g)
      870 +{
      871 +        nfs_export_t *ne = g->nfs_export;
      872 +        int err;
      873 +
      874 +        ne->exi_rootfid.fid_len = MAXFIDSZ;
      875 +        err = vop_fid_pseudo(ne->exi_root->exi_vp, &ne->exi_rootfid);
      876 +        if (err != 0) {
      877 +                ne->exi_rootfid.fid_len = 0;
      878 +                return (err);
      879 +        }
      880 +
      881 +        /* Setup the fhandle template exi_fh */
      882 +        ne->exi_root->exi_fh.fh_fsid = rootdir->v_vfsp->vfs_fsid;
      883 +        ne->exi_root->exi_fh.fh_xlen = ne->exi_rootfid.fid_len;
      884 +        bcopy(ne->exi_rootfid.fid_data, ne->exi_root->exi_fh.fh_xdata,
      885 +            ne->exi_rootfid.fid_len);
      886 +        ne->exi_root->exi_fh.fh_len = sizeof (ne->exi_root->exi_fh.fh_data);
      887 +
      888 +        return (0);
      889 +}
      890 +
      891 +void
      892 +nfs_export_zone_init(nfs_globals_t *ng)
      893 +{
 804  894          int i;
      895 +        nfs_export_t *ne;
      896 +        zone_t *zone;
 805  897  
 806      -        rw_init(&exported_lock, NULL, RW_DEFAULT, NULL);
      898 +        ne = kmem_zalloc(sizeof (*ne), KM_SLEEP);
 807  899  
      900 +        rw_init(&ne->exported_lock, NULL, RW_DEFAULT, NULL);
      901 +
      902 +        ne->ne_globals = ng; /* "up" pointer */
      903 +
 808  904          /*
 809  905           * Allocate the place holder for the public file handle, which
 810  906           * is all zeroes. It is initially set to the root filesystem.
 811  907           */
 812      -        exi_root = kmem_zalloc(sizeof (*exi_root), KM_SLEEP);
 813      -        exi_public = exi_root;
      908 +        ne->exi_root = kmem_zalloc(sizeof (*ne->exi_root), KM_SLEEP);
      909 +        ne->exi_public = ne->exi_root;
 814  910  
 815      -        exi_root->exi_export.ex_flags = EX_PUBLIC;
 816      -        exi_root->exi_export.ex_pathlen = 1;    /* length of "/" */
 817      -        exi_root->exi_export.ex_path =
 818      -            kmem_alloc(exi_root->exi_export.ex_pathlen + 1, KM_SLEEP);
 819      -        exi_root->exi_export.ex_path[0] = '/';
 820      -        exi_root->exi_export.ex_path[1] = '\0';
      911 +        ne->exi_root->exi_export.ex_flags = EX_PUBLIC;
      912 +        ne->exi_root->exi_export.ex_pathlen = 1;        /* length of "/" */
      913 +        ne->exi_root->exi_export.ex_path =
      914 +            kmem_alloc(ne->exi_root->exi_export.ex_pathlen + 1, KM_SLEEP);
      915 +        ne->exi_root->exi_export.ex_path[0] = '/';
      916 +        ne->exi_root->exi_export.ex_path[1] = '\0';
 821  917  
 822      -        exi_root->exi_count = 1;
 823      -        mutex_init(&exi_root->exi_lock, NULL, MUTEX_DEFAULT, NULL);
      918 +        ne->exi_root->exi_count = 1;
      919 +        mutex_init(&ne->exi_root->exi_lock, NULL, MUTEX_DEFAULT, NULL);
 824  920  
 825      -        exi_root->exi_vp = rootdir;
 826      -        exi_rootfid.fid_len = MAXFIDSZ;
 827      -        error = vop_fid_pseudo(exi_root->exi_vp, &exi_rootfid);
 828      -        if (error) {
 829      -                mutex_destroy(&exi_root->exi_lock);
 830      -                kmem_free(exi_root, sizeof (*exi_root));
 831      -                return (error);
 832      -        }
      921 +        /*
      922 +         * Because we cannot:
      923 +         *      ASSERT(curzone->zone_id == ng->nfs_zoneid);
      924 +         * We grab the zone pointer explicitly (like netstacks do) and
      925 +         * set the rootvp here.
      926 +         *
      927 +         * Subsequent exportinfo_t's that get export_link()ed to "ne" also
      928 +         * will backpoint to "ne" such that exi->exi_ne->exi_root->exi_vp
      929 +         * will get the zone's rootvp for a given exportinfo_t.
      930 +         */
      931 +        zone = zone_find_by_id_nolock(ng->nfs_zoneid);
      932 +        ne->exi_root->exi_vp = zone->zone_rootvp;
      933 +        ne->exi_root->exi_zoneid = ng->nfs_zoneid;
 833  934  
 834  935          /*
 835      -         * Initialize auth cache and auth cache lock
      936 +         * Fill in ne->exi_rootfid later, in nfs_export_get_rootfid
      937 +         * because we can't correctly return errors here.
 836  938           */
      939 +
      940 +        /* Initialize auth cache and auth cache lock */
 837  941          for (i = 0; i < AUTH_TABLESIZE; i++) {
 838      -                exi_root->exi_cache[i] = kmem_alloc(sizeof (avl_tree_t),
      942 +                ne->exi_root->exi_cache[i] = kmem_alloc(sizeof (avl_tree_t),
 839  943                      KM_SLEEP);
 840      -                avl_create(exi_root->exi_cache[i], nfsauth_cache_clnt_compar,
 841      -                    sizeof (struct auth_cache_clnt),
      944 +                avl_create(ne->exi_root->exi_cache[i],
      945 +                    nfsauth_cache_clnt_compar, sizeof (struct auth_cache_clnt),
 842  946                      offsetof(struct auth_cache_clnt, authc_link));
 843  947          }
 844      -        rw_init(&exi_root->exi_cache_lock, NULL, RW_DEFAULT, NULL);
      948 +        rw_init(&ne->exi_root->exi_cache_lock, NULL, RW_DEFAULT, NULL);
 845  949  
 846      -        /* setup the fhandle template */
 847      -        exi_root->exi_fh.fh_fsid = rootdir->v_vfsp->vfs_fsid;
 848      -        exi_root->exi_fh.fh_xlen = exi_rootfid.fid_len;
 849      -        bcopy(exi_rootfid.fid_data, exi_root->exi_fh.fh_xdata,
 850      -            exi_rootfid.fid_len);
 851      -        exi_root->exi_fh.fh_len = sizeof (exi_root->exi_fh.fh_data);
      950 +        /* setup exi_fh later, in nfs_export_get_rootfid */
 852  951  
 853      -        /*
 854      -         * Publish the exportinfo in the hash table
 855      -         */
 856      -        export_link(exi_root);
      952 +        rw_enter(&ne->exported_lock, RW_WRITER);
 857  953  
 858      -        nfslog_init();
 859      -        ns_root = NULL;
      954 +        /* Publish the exportinfo in the hash table */
      955 +        export_link(ne, ne->exi_root);
 860  956  
 861      -        return (0);
      957 +        /* Initialize exi_id and exi_kstats */
      958 +        mutex_enter(&nfs_exi_id_lock);
      959 +        ne->exi_root->exi_id = exi_id_get_next();
      960 +        avl_add(&exi_id_tree, ne->exi_root);
      961 +        mutex_exit(&nfs_exi_id_lock);
      962 +
      963 +        rw_exit(&ne->exported_lock);
      964 +        ne->ns_root = NULL;
      965 +
      966 +        ng->nfs_export = ne;
 862  967  }
 863  968  
 864  969  /*
 865      - * Finalization routine for export routines. Called to cleanup previously
 866      - * initialization work when the NFS server module could not be loaded correctly.
      970 + * During zone shutdown, remove exports
 867  971   */
 868  972  void
 869      -nfs_exportfini(void)
      973 +nfs_export_zone_shutdown(nfs_globals_t *ng)
 870  974  {
      975 +        nfs_export_t *ne = ng->nfs_export;
      976 +        struct exportinfo *exi, *nexi;
      977 +        int i, errors;
      978 +
      979 +        rw_enter(&ne->exported_lock, RW_READER);
      980 +
      981 +        errors = 0;
      982 +        for (i = 0; i < EXPTABLESIZE; i++) {
      983 +
      984 +                exi = ne->exptable[i];
      985 +                if (exi != NULL)
      986 +                        exi_hold(exi);
      987 +
      988 +                while (exi != NULL) {
      989 +
      990 +                        /*
      991 +                         * Get and hold next export before
      992 +                         * dropping the rwlock and unexport
      993 +                         */
      994 +                        nexi = exi->fid_hash.next;
      995 +                        if (nexi != NULL)
      996 +                                exi_hold(nexi);
      997 +
      998 +                        rw_exit(&ne->exported_lock);
      999 +
     1000 +                        /*
     1001 +                         * Skip ne->exi_root which gets special
     1002 +                         * create/destroy handling.
     1003 +                         */
     1004 +                        if (exi != ne->exi_root &&
     1005 +                            unexport(ne, exi) != 0)
     1006 +                                errors++;
     1007 +                        exi_rele(exi);
     1008 +
     1009 +                        rw_enter(&ne->exported_lock, RW_READER);
     1010 +                        exi = nexi;
     1011 +                }
     1012 +        }
     1013 +        if (errors > 0) {
     1014 +                cmn_err(CE_NOTE, "NFS: failed un-exports in zone %d",
     1015 +                    (int)ng->nfs_zoneid);
     1016 +        }
     1017 +
     1018 +        rw_exit(&ne->exported_lock);
     1019 +}
     1020 +
     1021 +void
     1022 +nfs_export_zone_fini(nfs_globals_t *ng)
     1023 +{
 871 1024          int i;
     1025 +        nfs_export_t *ne = ng->nfs_export;
     1026 +        struct exportinfo *exi;
 872 1027  
     1028 +        ng->nfs_export = NULL;
     1029 +
     1030 +        rw_enter(&ne->exported_lock, RW_WRITER);
     1031 +
     1032 +        mutex_enter(&nfs_exi_id_lock);
     1033 +        avl_remove(&exi_id_tree, ne->exi_root);
     1034 +        mutex_exit(&nfs_exi_id_lock);
     1035 +
     1036 +        export_unlink(ne, ne->exi_root);
     1037 +
     1038 +        rw_exit(&ne->exported_lock);
     1039 +
     1040 +        /* Deallocate the place holder for the public file handle */
     1041 +        srv_secinfo_list_free(ne->exi_root->exi_export.ex_secinfo,
     1042 +            ne->exi_root->exi_export.ex_seccnt);
     1043 +        mutex_destroy(&ne->exi_root->exi_lock);
     1044 +
     1045 +        rw_destroy(&ne->exi_root->exi_cache_lock);
     1046 +        for (i = 0; i < AUTH_TABLESIZE; i++) {
     1047 +                avl_destroy(ne->exi_root->exi_cache[i]);
     1048 +                kmem_free(ne->exi_root->exi_cache[i], sizeof (avl_tree_t));
     1049 +        }
     1050 +
     1051 +        kmem_free(ne->exi_root->exi_export.ex_path,
     1052 +            ne->exi_root->exi_export.ex_pathlen + 1);
     1053 +        kmem_free(ne->exi_root, sizeof (*ne->exi_root));
     1054 +
 873 1055          /*
 874      -         * Deallocate the place holder for the public file handle.
     1056 +         * The shutdown hook should have left the exi_id_tree
     1057 +         * with nothing belonging to this zone.
 875 1058           */
 876      -        srv_secinfo_list_free(exi_root->exi_export.ex_secinfo,
 877      -            exi_root->exi_export.ex_seccnt);
 878      -        mutex_destroy(&exi_root->exi_lock);
 879      -        rw_destroy(&exi_root->exi_cache_lock);
 880      -        for (i = 0; i < AUTH_TABLESIZE; i++) {
 881      -                avl_destroy(exi_root->exi_cache[i]);
 882      -                kmem_free(exi_root->exi_cache[i], sizeof (avl_tree_t));
     1059 +        mutex_enter(&nfs_exi_id_lock);
     1060 +        i = 0;
     1061 +        exi = avl_first(&exi_id_tree);
     1062 +        while (exi != NULL) {
     1063 +                if (exi->exi_zoneid == ng->nfs_zoneid)
     1064 +                        i++;
     1065 +                exi = AVL_NEXT(&exi_id_tree, exi);
 883 1066          }
 884      -        kmem_free(exi_root, sizeof (*exi_root));
     1067 +        mutex_exit(&nfs_exi_id_lock);
     1068 +        if (i > 0) {
     1069 +                cmn_err(CE_NOTE,
     1070 +                    "NFS: zone %d has %d export IDs left after shutdown",
     1071 +                    (int)ng->nfs_zoneid, i);
     1072 +        }
     1073 +        rw_destroy(&ne->exported_lock);
     1074 +        kmem_free(ne, sizeof (*ne));
     1075 +}
 885 1076  
 886      -        rw_destroy(&exported_lock);
     1077 +/*
     1078 + * Initialization routine for export routines.
     1079 + * Should only be called once.
     1080 + */
     1081 +void
     1082 +nfs_exportinit(void)
     1083 +{
     1084 +        mutex_init(&nfs_exi_id_lock, NULL, MUTEX_DEFAULT, NULL);
     1085 +
     1086 +        /* exi_id handling initialization */
     1087 +        exi_id_next = 0;
     1088 +        exi_id_overflow = FALSE;
     1089 +        avl_create(&exi_id_tree, exi_id_compar, sizeof (struct exportinfo),
     1090 +            offsetof(struct exportinfo, exi_id_link));
     1091 +
     1092 +        nfslog_init();
 887 1093  }
 888 1094  
 889 1095  /*
     1096 + * Finalization routine for export routines.
     1097 + */
     1098 +void
     1099 +nfs_exportfini(void)
     1100 +{
     1101 +        avl_destroy(&exi_id_tree);
     1102 +        mutex_destroy(&nfs_exi_id_lock);
     1103 +}
     1104 +
     1105 +/*
 890 1106   *  Check if 2 gss mechanism identifiers are the same.
 891 1107   *
 892 1108   *  return FALSE if not the same.
 893 1109   *  return TRUE if the same.
 894 1110   */
 895 1111  static bool_t
 896 1112  nfs_mech_equal(rpc_gss_OID mech1, rpc_gss_OID mech2)
 897 1113  {
 898 1114          if ((mech1->length == 0) && (mech2->length == 0))
 899 1115                  return (TRUE);
↓ open down ↓ 15 lines elided ↑ open up ↑
 915 1131   *  we cast them to void.
 916 1132   */
 917 1133  /*ARGSUSED*/
 918 1134  bool_t
 919 1135  rfs_gsscallback(struct svc_req *req, gss_cred_id_t deleg, void *gss_context,
 920 1136      rpc_gss_lock_t *lock, void **cookie)
 921 1137  {
 922 1138          int i, j;
 923 1139          rpc_gss_rawcred_t *raw_cred;
 924 1140          struct exportinfo *exi;
     1141 +        nfs_export_t *ne = nfs_get_export();
 925 1142  
 926 1143          /*
 927 1144           * We don't deal with delegated credentials.
 928 1145           */
 929 1146          if (deleg != GSS_C_NO_CREDENTIAL)
 930 1147                  return (FALSE);
 931 1148  
 932 1149          raw_cred = lock->raw_cred;
 933 1150          *cookie = NULL;
 934 1151  
 935      -        rw_enter(&exported_lock, RW_READER);
     1152 +        rw_enter(&ne->exported_lock, RW_READER);
     1153 +
 936 1154          for (i = 0; i < EXPTABLESIZE; i++) {
 937      -                exi = exptable[i];
     1155 +                exi = ne->exptable[i];
 938 1156                  while (exi) {
 939 1157                          if (exi->exi_export.ex_seccnt > 0) {
 940 1158                                  struct secinfo *secp;
 941 1159                                  seconfig_t *se;
 942 1160                                  int seccnt;
 943 1161  
 944 1162                                  secp = exi->exi_export.ex_secinfo;
 945 1163                                  seccnt = exi->exi_export.ex_seccnt;
 946 1164                                  for (j = 0; j < seccnt; j++) {
 947 1165                                          /*
↓ open down ↓ 19 lines elided ↑ open up ↑
 967 1185                                                  *cookie = (void *)(uintptr_t)
 968 1186                                                      se->sc_nfsnum;
 969 1187                                                  goto done;
 970 1188                                          }
 971 1189                                  }
 972 1190                          }
 973 1191                          exi = exi->fid_hash.next;
 974 1192                  }
 975 1193          }
 976 1194  done:
 977      -        rw_exit(&exported_lock);
     1195 +        rw_exit(&ne->exported_lock);
 978 1196  
 979 1197          /*
 980 1198           * If no nfs pseudo number mapping can be found in the export
 981 1199           * table, assign the nfsflavor to NFS_FLAVOR_NOMAP. In V4, we may
 982 1200           * recover the flavor mismatch from NFS layer (NFS4ERR_WRONGSEC).
 983 1201           *
 984 1202           * For example:
 985 1203           *      server first shares with krb5i;
 986 1204           *      client mounts with krb5i;
 987 1205           *      server re-shares with krb5p;
↓ open down ↓ 46 lines elided ↑ open up ↑
1034 1252          int callback;
1035 1253          int allocd_seccnt;
1036 1254          STRUCT_HANDLE(exportfs_args, uap);
1037 1255          STRUCT_DECL(exportdata, uexi);
1038 1256          struct secinfo newsec[MAX_FLAVORS];
1039 1257          int newcnt;
1040 1258          struct secinfo oldsec[MAX_FLAVORS];
1041 1259          int oldcnt;
1042 1260          int i;
1043 1261          struct pathname lookpn;
     1262 +        nfs_export_t *ne = nfs_get_export();
1044 1263  
1045 1264          STRUCT_SET_HANDLE(uap, model, args);
1046 1265  
1047 1266          /* Read in pathname from userspace */
1048 1267          if (error = pn_get(STRUCT_FGETP(uap, dname), UIO_USERSPACE, &lookpn))
1049 1268                  return (error);
1050 1269  
1051 1270          /* Walk the export list looking for that pathname */
1052      -        rw_enter(&exported_lock, RW_READER);
     1271 +        rw_enter(&ne->exported_lock, RW_READER);
1053 1272          DTRACE_PROBE(nfss__i__exported_lock1_start);
1054      -        for (ex1 = exptable_path_hash[pkp_tab_hash(lookpn.pn_path,
     1273 +        for (ex1 = ne->exptable_path_hash[pkp_tab_hash(lookpn.pn_path,
1055 1274              strlen(lookpn.pn_path))]; ex1; ex1 = ex1->path_hash.next) {
1056      -                if (ex1 != exi_root && 0 ==
     1275 +                if (ex1 != ne->exi_root && 0 ==
1057 1276                      strcmp(ex1->exi_export.ex_path, lookpn.pn_path)) {
1058 1277                          exi_hold(ex1);
1059 1278                          break;
1060 1279                  }
1061 1280          }
1062 1281          DTRACE_PROBE(nfss__i__exported_lock1_stop);
1063      -        rw_exit(&exported_lock);
     1282 +        rw_exit(&ne->exported_lock);
1064 1283  
1065 1284          /* Is this an unshare? */
1066 1285          if (STRUCT_FGETP(uap, uex) == NULL) {
1067 1286                  pn_free(&lookpn);
1068 1287                  if (ex1 == NULL)
1069 1288                          return (EINVAL);
1070      -                error = unexport(ex1);
     1289 +                error = unexport(ne, ex1);
1071 1290                  exi_rele(ex1);
1072 1291                  return (error);
1073 1292          }
1074 1293  
1075 1294          /* It is a share or a re-share */
1076 1295          error = lookupname(STRUCT_FGETP(uap, dname), UIO_USERSPACE,
1077 1296              FOLLOW, &dvp, &vp);
1078 1297          if (error == EINVAL) {
1079 1298                  /*
1080 1299                   * if fname resolves to / we get EINVAL error
↓ open down ↓ 75 lines elided ↑ open up ↑
1156 1375                  if (error == ENOSPC)
1157 1376                          error = EREMOTE;
1158 1377                  pn_free(&lookpn);
1159 1378                  return (error);
1160 1379          }
1161 1380  
1162 1381          /*
1163 1382           * Do not allow re-sharing a shared vnode under a different path
1164 1383           * PSEUDO export has ex_path fabricated, e.g. "/tmp (pseudo)", skip it.
1165 1384           */
1166      -        rw_enter(&exported_lock, RW_READER);
     1385 +        rw_enter(&ne->exported_lock, RW_READER);
1167 1386          DTRACE_PROBE(nfss__i__exported_lock2_start);
1168      -        for (ex2 = exptable[exptablehash(&fsid, &fid)]; ex2;
     1387 +        for (ex2 = ne->exptable[exptablehash(&fsid, &fid)]; ex2;
1169 1388              ex2 = ex2->fid_hash.next) {
1170      -                if (ex2 != exi_root && !PSEUDO(ex2) &&
     1389 +                if (ex2 != ne->exi_root && !PSEUDO(ex2) &&
1171 1390                      VN_CMP(ex2->exi_vp, vp) &&
1172 1391                      strcmp(ex2->exi_export.ex_path, lookpn.pn_path) != 0) {
1173 1392                          DTRACE_PROBE(nfss__i__exported_lock2_stop);
1174      -                        rw_exit(&exported_lock);
     1393 +                        rw_exit(&ne->exported_lock);
1175 1394                          VN_RELE(vp);
1176 1395                          if (dvp != NULL)
1177 1396                                  VN_RELE(dvp);
1178 1397                          pn_free(&lookpn);
1179 1398                          return (EEXIST);
1180 1399                  }
1181 1400          }
1182 1401          DTRACE_PROBE(nfss__i__exported_lock2_stop);
1183      -        rw_exit(&exported_lock);
     1402 +        rw_exit(&ne->exported_lock);
1184 1403          pn_free(&lookpn);
1185 1404  
1186 1405          exi = kmem_zalloc(sizeof (*exi), KM_SLEEP);
1187 1406          exi->exi_fsid = fsid;
1188 1407          exi->exi_fid = fid;
1189 1408          exi->exi_vp = vp;
1190 1409          exi->exi_count = 1;
     1410 +        exi->exi_zoneid = crgetzoneid(cr);
     1411 +        ASSERT3U(exi->exi_zoneid, ==, curzone->zone_id);
1191 1412          exi->exi_volatile_dev = (vfssw[vp->v_vfsp->vfs_fstype].vsw_flag &
1192 1413              VSW_VOLATILEDEV) ? 1 : 0;
1193 1414          mutex_init(&exi->exi_lock, NULL, MUTEX_DEFAULT, NULL);
1194 1415          exi->exi_dvp = dvp;
1195 1416  
1196 1417          /*
1197 1418           * Initialize auth cache and auth cache lock
1198 1419           */
1199 1420          for (i = 0; i < AUTH_TABLESIZE; i++) {
1200 1421                  exi->exi_cache[i] = kmem_alloc(sizeof (avl_tree_t), KM_SLEEP);
↓ open down ↓ 253 lines elided ↑ open up ↑
1454 1675          }
1455 1676  
1456 1677          if (kex->ex_flags & EX_LOG) {
1457 1678                  if (error = nfslog_setup(exi))
1458 1679                          goto out6;
1459 1680          }
1460 1681  
1461 1682          /*
1462 1683           * Insert the new entry at the front of the export list
1463 1684           */
1464      -        rw_enter(&exported_lock, RW_WRITER);
     1685 +        rw_enter(&ne->exported_lock, RW_WRITER);
1465 1686          DTRACE_PROBE(nfss__i__exported_lock3_start);
1466 1687  
1467      -        export_link(exi);
     1688 +        export_link(ne, exi);
1468 1689  
1469 1690          /*
1470 1691           * Check the rest of the list for an old entry for the fs.
1471 1692           * If one is found then unlink it, wait until this is the
1472 1693           * only reference and then free it.
1473 1694           */
1474 1695          for (ex = exi->fid_hash.next; ex != NULL; ex = ex->fid_hash.next) {
1475      -                if (ex != exi_root && VN_CMP(ex->exi_vp, vp)) {
1476      -                        export_unlink(ex);
     1696 +                if (ex != ne->exi_root && VN_CMP(ex->exi_vp, vp)) {
     1697 +                        mutex_enter(&nfs_exi_id_lock);
     1698 +                        avl_remove(&exi_id_tree, ex);
     1699 +                        mutex_exit(&nfs_exi_id_lock);
     1700 +                        export_unlink(ne, ex);
1477 1701                          break;
1478 1702                  }
1479 1703          }
1480 1704  
1481 1705          /*
1482 1706           * If the public filehandle is pointing at the
1483 1707           * old entry, then point it back at the root.
1484 1708           */
1485      -        if (ex != NULL && ex == exi_public)
1486      -                exi_public = exi_root;
     1709 +        if (ex != NULL && ex == ne->exi_public)
     1710 +                ne->exi_public = ne->exi_root;
1487 1711  
1488 1712          /*
1489 1713           * If the public flag is on, make the global exi_public
1490 1714           * point to this entry and turn off the public bit so that
1491 1715           * we can distinguish it from the place holder export.
1492 1716           */
1493 1717          if (kex->ex_flags & EX_PUBLIC) {
1494      -                exi_public = exi;
     1718 +                ne->exi_public = exi;
1495 1719                  kex->ex_flags &= ~EX_PUBLIC;
1496 1720          }
1497 1721  
1498 1722  #ifdef VOLATILE_FH_TEST
1499 1723          /*
1500 1724           * Set up the volatile_id value if volatile on share.
1501 1725           * The list of volatile renamed filehandles is always destroyed,
1502 1726           * if the fs was reshared.
1503 1727           */
1504 1728          if (kex->ex_flags & EX_VOLFH)
↓ open down ↓ 11 lines elided ↑ open up ↑
1516 1740          if (ex == NULL) {
1517 1741                  error = treeclimb_export(exi);
1518 1742                  if (error)
1519 1743                          goto out7;
1520 1744          } else {
1521 1745                  /* If it's a re-export update namespace tree */
1522 1746                  exi->exi_tree = ex->exi_tree;
1523 1747                  exi->exi_tree->tree_exi = exi;
1524 1748  
1525 1749                  /* Update the change timestamp */
1526      -                tree_update_change(exi->exi_tree, NULL);
     1750 +                tree_update_change(ne, exi->exi_tree, NULL);
1527 1751          }
1528 1752  
1529 1753          /*
1530 1754           * build a unique flavor list from the flavors specified
1531 1755           * in the share cmd.  unique means that each flavor only
1532 1756           * appears once in the secinfo list -- no duplicates allowed.
1533 1757           */
1534 1758          newcnt = build_seclist_nodups(&exi->exi_export, newsec, FALSE);
1535 1759  
1536      -        srv_secinfo_treeclimb(exi, newsec, newcnt, TRUE);
     1760 +        srv_secinfo_treeclimb(ne, exi, newsec, newcnt, TRUE);
1537 1761  
1538 1762          /*
1539 1763           * If re-sharing an old export entry, update the secinfo data
1540 1764           * depending on if the old entry is a pseudo node or not.
1541 1765           */
1542 1766          if (ex != NULL) {
1543 1767                  oldcnt = build_seclist_nodups(&ex->exi_export, oldsec, FALSE);
1544 1768                  if (PSEUDO(ex)) {
1545 1769                          /*
1546 1770                           * The dir being shared is a pseudo export root (which
↓ open down ↓ 4 lines elided ↑ open up ↑
1551 1775                           * pseudo exprot root to the new (real) export root.
1552 1776                           */
1553 1777                          srv_secinfo_add(&exi->exi_export.ex_secinfo,
1554 1778                              &exi->exi_export.ex_seccnt, oldsec, oldcnt, TRUE);
1555 1779                  } else {
1556 1780                          /*
1557 1781                           * First transfer implicit flavor refs to new export.
1558 1782                           * Remove old flavor refs last.
1559 1783                           */
1560 1784                          srv_secinfo_exp2exp(&exi->exi_export, oldsec, oldcnt);
1561      -                        srv_secinfo_treeclimb(ex, oldsec, oldcnt, FALSE);
     1785 +                        srv_secinfo_treeclimb(ne, ex, oldsec, oldcnt, FALSE);
1562 1786                  }
1563 1787          }
1564 1788  
1565 1789          /*
1566 1790           * If it's a re-export and the old entry has a pseudonode list,
1567 1791           * transfer it to the new export.
1568 1792           */
1569 1793          if (ex != NULL && (ex->exi_visible != NULL)) {
1570 1794                  exi->exi_visible = ex->exi_visible;
1571 1795                  ex->exi_visible = NULL;
1572 1796          }
1573 1797  
     1798 +        /*
     1799 +         * Initialize exi_id and exi_kstats
     1800 +         */
     1801 +        if (ex != NULL) {
     1802 +                exi->exi_id = ex->exi_id;
     1803 +        } else {
     1804 +                mutex_enter(&nfs_exi_id_lock);
     1805 +                exi->exi_id = exi_id_get_next();
     1806 +                mutex_exit(&nfs_exi_id_lock);
     1807 +        }
     1808 +        mutex_enter(&nfs_exi_id_lock);
     1809 +        avl_add(&exi_id_tree, exi);
     1810 +        mutex_exit(&nfs_exi_id_lock);
     1811 +
1574 1812          DTRACE_PROBE(nfss__i__exported_lock3_stop);
1575      -        rw_exit(&exported_lock);
     1813 +        rw_exit(&ne->exported_lock);
1576 1814  
1577      -        if (exi_public == exi || kex->ex_flags & EX_LOG) {
     1815 +        if (ne->exi_public == exi || kex->ex_flags & EX_LOG) {
1578 1816                  /*
1579 1817                   * Log share operation to this buffer only.
1580 1818                   */
1581 1819                  nfslog_share_record(exi, cr);
1582 1820          }
1583 1821  
1584 1822          if (ex != NULL)
1585 1823                  exi_rele(ex);
1586 1824  
1587 1825          return (0);
1588 1826  
1589 1827  out7:
1590 1828          /* Unlink the new export in exptable. */
1591      -        export_unlink(exi);
     1829 +        export_unlink(ne, exi);
1592 1830          DTRACE_PROBE(nfss__i__exported_lock3_stop);
1593      -        rw_exit(&exported_lock);
     1831 +        rw_exit(&ne->exported_lock);
1594 1832  out6:
1595 1833          if (kex->ex_flags & EX_INDEX)
1596 1834                  kmem_free(kex->ex_index, strlen(kex->ex_index) + 1);
1597 1835  out5:
1598 1836          /* free partially completed allocation */
1599 1837          while (--allocd_seccnt >= 0) {
1600 1838                  exs = &kex->ex_secinfo[allocd_seccnt];
1601 1839                  srv_secinfo_entry_free(exs);
1602 1840          }
1603 1841  
↓ open down ↓ 23 lines elided ↑ open up ↑
1627 1865  
1628 1866          kmem_free(exi, sizeof (*exi));
1629 1867  
1630 1868          return (error);
1631 1869  }
1632 1870  
1633 1871  /*
1634 1872   * Remove the exportinfo from the export list
1635 1873   */
1636 1874  void
1637      -export_unlink(struct exportinfo *exi)
     1875 +export_unlink(nfs_export_t *ne, struct exportinfo *exi)
1638 1876  {
1639      -        ASSERT(RW_WRITE_HELD(&exported_lock));
     1877 +        ASSERT(RW_WRITE_HELD(&ne->exported_lock));
1640 1878  
1641 1879          exp_hash_unlink(exi, fid_hash);
1642 1880          exp_hash_unlink(exi, path_hash);
     1881 +        ASSERT3P(exi->exi_ne, ==, ne);
     1882 +        exi->exi_ne = NULL;
1643 1883  }
1644 1884  
1645 1885  /*
1646 1886   * Unexport an exported filesystem
1647 1887   */
1648 1888  static int
1649      -unexport(struct exportinfo *exi)
     1889 +unexport(nfs_export_t *ne, struct exportinfo *exi)
1650 1890  {
1651 1891          struct secinfo cursec[MAX_FLAVORS];
1652 1892          int curcnt;
1653 1893  
1654      -        rw_enter(&exported_lock, RW_WRITER);
     1894 +        rw_enter(&ne->exported_lock, RW_WRITER);
1655 1895  
1656 1896          /* Check if exi is still linked in the export table */
1657 1897          if (!EXP_LINKED(exi) || PSEUDO(exi)) {
1658      -                rw_exit(&exported_lock);
     1898 +                rw_exit(&ne->exported_lock);
1659 1899                  return (EINVAL);
1660 1900          }
1661 1901  
1662      -        export_unlink(exi);
     1902 +        mutex_enter(&nfs_exi_id_lock);
     1903 +        avl_remove(&exi_id_tree, exi);
     1904 +        mutex_exit(&nfs_exi_id_lock);
     1905 +        export_unlink(ne, exi);
1663 1906  
1664 1907          /*
1665 1908           * Remove security flavors before treeclimb_unexport() is called
1666 1909           * because srv_secinfo_treeclimb needs the namespace tree
1667 1910           */
1668 1911          curcnt = build_seclist_nodups(&exi->exi_export, cursec, TRUE);
     1912 +        srv_secinfo_treeclimb(ne, exi, cursec, curcnt, FALSE);
1669 1913  
1670      -        srv_secinfo_treeclimb(exi, cursec, curcnt, FALSE);
1671      -
1672 1914          /*
1673 1915           * If there's a visible list, then need to leave
1674 1916           * a pseudo export here to retain the visible list
1675 1917           * for paths to exports below.
1676 1918           */
1677 1919          if (exi->exi_visible != NULL) {
1678 1920                  struct exportinfo *newexi;
1679 1921  
1680      -                newexi = pseudo_exportfs(exi->exi_vp, &exi->exi_fid,
     1922 +                newexi = pseudo_exportfs(ne, exi->exi_vp, &exi->exi_fid,
1681 1923                      exi->exi_visible, &exi->exi_export);
1682 1924                  exi->exi_visible = NULL;
1683 1925  
1684 1926                  /* interconnect the existing treenode with the new exportinfo */
1685 1927                  newexi->exi_tree = exi->exi_tree;
1686 1928                  newexi->exi_tree->tree_exi = newexi;
1687 1929  
1688 1930                  /* Update the change timestamp */
1689      -                tree_update_change(exi->exi_tree, NULL);
     1931 +                tree_update_change(ne, exi->exi_tree, NULL);
1690 1932          } else {
1691      -                treeclimb_unexport(exi);
     1933 +                treeclimb_unexport(ne, exi);
1692 1934          }
1693 1935  
1694      -        rw_exit(&exported_lock);
     1936 +        rw_exit(&ne->exported_lock);
1695 1937  
1696 1938          /*
1697 1939           * Need to call into the NFSv4 server and release all data
1698 1940           * held on this particular export.  This is important since
1699 1941           * the v4 server may be holding file locks or vnodes under
1700 1942           * this export.
1701 1943           */
1702      -        rfs4_clean_state_exi(exi);
     1944 +        rfs4_clean_state_exi(ne, exi);
1703 1945  
1704 1946          /*
1705 1947           * Notify the lock manager that the filesystem is being
1706 1948           * unexported.
1707 1949           */
1708 1950          lm_unexport(exi);
1709 1951  
1710 1952          /*
1711 1953           * If this was a public export, restore
1712 1954           * the public filehandle to the root.
1713 1955           */
1714      -        if (exi == exi_public) {
1715      -                exi_public = exi_root;
1716 1956  
1717      -                nfslog_share_record(exi_public, CRED());
     1957 +        /*
     1958 +         * XXX KEBE ASKS --> Should CRED() instead be
     1959 +         * exi->exi_zone->zone_kcred?
     1960 +         */
     1961 +        if (exi == ne->exi_public) {
     1962 +                ne->exi_public = ne->exi_root;
     1963 +
     1964 +                nfslog_share_record(ne->exi_public, CRED());
1718 1965          }
1719 1966  
1720      -        if (exi->exi_export.ex_flags & EX_LOG) {
     1967 +        if (exi->exi_export.ex_flags & EX_LOG)
1721 1968                  nfslog_unshare_record(exi, CRED());
1722      -        }
1723 1969  
1724 1970          exi_rele(exi);
1725 1971          return (0);
1726 1972  }
1727 1973  
1728 1974  /*
1729 1975   * Get file handle system call.
1730 1976   * Takes file name and returns a file handle for it.
1731 1977   * Credentials must be verified before calling.
1732 1978   */
↓ open down ↓ 206 lines elided ↑ open up ↑
1939 2185                           * Found the export info
1940 2186                           */
1941 2187                          break;
1942 2188                  }
1943 2189  
1944 2190                  /*
1945 2191                   * We have just failed finding a matching export.
1946 2192                   * If we're at the root of this filesystem, then
1947 2193                   * it's time to stop (with failure).
1948 2194                   */
1949      -                if (vp->v_flag & VROOT) {
     2195 +                ASSERT3P(vp->v_vfsp->vfs_zone, ==, curzone);
     2196 +                if ((vp->v_flag & VROOT) || VN_IS_CURZONEROOT(vp)) {
1950 2197                          error = EINVAL;
1951 2198                          break;
1952 2199                  }
1953 2200  
1954 2201                  if (walk != NULL)
1955 2202                          (*walk)++;
1956 2203  
1957 2204                  /*
1958 2205                   * Now, do a ".." up vp. If dvp is supplied, use it,
1959 2206                   * otherwise, look it up.
↓ open down ↓ 479 lines elided ↑ open up ↑
2439 2686  }
2440 2687  
2441 2688  /*
2442 2689   * Find the export structure associated with the given filesystem.
2443 2690   * If found, then increment the ref count (exi_count).
2444 2691   */
2445 2692  struct exportinfo *
2446 2693  checkexport(fsid_t *fsid, fid_t *fid)
2447 2694  {
2448 2695          struct exportinfo *exi;
     2696 +        nfs_export_t *ne = nfs_get_export();
2449 2697  
2450      -        rw_enter(&exported_lock, RW_READER);
2451      -        for (exi = exptable[exptablehash(fsid, fid)];
     2698 +        rw_enter(&ne->exported_lock, RW_READER);
     2699 +        for (exi = ne->exptable[exptablehash(fsid, fid)];
2452 2700              exi != NULL;
2453 2701              exi = exi->fid_hash.next) {
2454 2702                  if (exportmatch(exi, fsid, fid)) {
2455 2703                          /*
2456 2704                           * If this is the place holder for the
2457 2705                           * public file handle, then return the
2458 2706                           * real export entry for the public file
2459 2707                           * handle.
2460 2708                           */
2461 2709                          if (exi->exi_export.ex_flags & EX_PUBLIC) {
2462      -                                exi = exi_public;
     2710 +                                exi = ne->exi_public;
2463 2711                          }
2464 2712  
2465 2713                          exi_hold(exi);
2466      -                        rw_exit(&exported_lock);
     2714 +                        rw_exit(&ne->exported_lock);
2467 2715                          return (exi);
2468 2716                  }
2469 2717          }
2470      -        rw_exit(&exported_lock);
     2718 +        rw_exit(&ne->exported_lock);
2471 2719          return (NULL);
2472 2720  }
2473 2721  
2474 2722  
2475 2723  /*
2476 2724   * "old school" version of checkexport() for NFS4.  NFS4
2477 2725   * rfs4_compound holds exported_lock for duration of compound
2478 2726   * processing.  This version doesn't manipulate exi_count
2479 2727   * since NFS4 breaks fundamental assumptions in the exi_count
2480 2728   * design.
2481 2729   */
2482 2730  struct exportinfo *
2483 2731  checkexport4(fsid_t *fsid, fid_t *fid, vnode_t *vp)
2484 2732  {
2485 2733          struct exportinfo *exi;
     2734 +        nfs_export_t *ne = nfs_get_export();
2486 2735  
2487      -        ASSERT(RW_LOCK_HELD(&exported_lock));
     2736 +        ASSERT(RW_LOCK_HELD(&ne->exported_lock));
2488 2737  
2489      -        for (exi = exptable[exptablehash(fsid, fid)];
     2738 +        for (exi = ne->exptable[exptablehash(fsid, fid)];
2490 2739              exi != NULL;
2491 2740              exi = exi->fid_hash.next) {
2492 2741                  if (exportmatch(exi, fsid, fid)) {
2493 2742                          /*
2494 2743                           * If this is the place holder for the
2495 2744                           * public file handle, then return the
2496 2745                           * real export entry for the public file
2497 2746                           * handle.
2498 2747                           */
2499 2748                          if (exi->exi_export.ex_flags & EX_PUBLIC) {
2500      -                                exi = exi_public;
     2749 +                                exi = ne->exi_public;
2501 2750                          }
2502 2751  
2503 2752                          /*
2504 2753                           * If vp is given, check if vp is the
2505 2754                           * same vnode as the exported node.
2506 2755                           *
2507 2756                           * Since VOP_FID of a lofs node returns the
2508 2757                           * fid of its real node (ufs), the exported
2509 2758                           * node for lofs and (pseudo) ufs may have
2510 2759                           * the same fsid and fid.
↓ open down ↓ 231 lines elided ↑ open up ↑
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX