Print this page
NEX-19996 exi_id_get_next() calls should be WRITER locked
NEX-20014 NFS v4 state lock mutex exited before entered (on error path)
Reviewed by: Sanjay Nadkarni <sanjay.nadkarni@nexenta.com>
Reviewed by: Rick McNeal <rick.mcneal@nexenta.com>
Reviewed by: Joyce McIntosh <joyce.mcintosh@nexenta.com>
NEX-15279 support NFS server in zone
NEX-15520 online NFS shares cause zoneadm halt to hang in nfs_export_zone_fini
Portions contributed by: Dan Kruchinin dan.kruchinin@nexenta.com
Portions contributed by: Stepan Zastupov stepan.zastupov@gmail.com
Reviewed by: Joyce McIntosh <joyce.mcintosh@nexenta.com>
Reviewed by: Rob Gittins <rob.gittins@nexenta.com>
Reviewed by: Gordon Ross <gordon.ross@nexenta.com>
NEX-9275 Got "bad mutex" panic when run IO to nfs share from clients
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>
Reviewed by: Sanjay Nadkarni <sanjay.nadkarni@nexenta.com>
Reviewed by: Rob Gittins <rob.gittins@nexenta.com>
NEX-6778 NFS kstats leak and cause system to hang
Revert "NEX-4261 Per-client NFS server IOPS, bandwidth, and latency kstats"
This reverts commit 586c3ab1927647487f01c337ddc011c642575a52.
Revert "NEX-5354 Aggregated IOPS, bandwidth, and latency kstats for NFS server"
This reverts commit c91d7614da8618ef48018102b077f60ecbbac8c2.
Revert "NEX-5667 nfssrv_stats_flags does not work for aggregated kstats"
This reverts commit 3dcf42618be7dd5f408c327f429c81e07ca08e74.
Revert "NEX-5750 Time values for aggregated NFS server kstats should be normalized"
This reverts commit 1f4d4f901153b0191027969fa4a8064f9d3b9ee1.
Revert "NEX-5942 Panic in rfs4_minorvers_mismatch() with NFSv4.1 client"
This reverts commit 40766417094a162f5e4cc8786c0fa0a7e5871cd9.
Revert "NEX-5752 NFS server: namespace collision in kstats"
This reverts commit ae81e668db86050da8e483264acb0cce0444a132.
Reviewed by: Rob Gittins <rob.gittins@nexenta.com>
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>
NEX-4261 Per-client NFS server IOPS, bandwidth, and latency kstats
Reviewed by: Kevin Crowe <kevin.crowe@nexenta.com>
Reviewed by: Roman Strashkin <roman.strashkin@nexenta.com>
NEX-3097 IOPS, bandwidth, and latency kstats for NFS server
Reviewed by: Josef 'Jeff' Sipek <josef.sipek@nexenta.com>
NEX-2345 nfsauth_cache_get() could spend a lot of time walking exi_cache
Reviewed by: Gordon Ross <gordon.ross@nexenta.com>

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   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 +static zone_key_t nfs_export_key;
  71   72  
  72      -struct exportinfo *exptable_path_hash[PKP_HASH_SIZE];
  73      -struct exportinfo *exptable[EXPTABLESIZE];
       73 +/*
       74 + * exi_id support
       75 + *
       76 + * exi_id_next          The next exi_id available.
       77 + * exi_id_overflow      The exi_id_next already overflowed, so we should
       78 + *                      thoroughly check for duplicates.
       79 + * exi_id_tree          AVL tree indexed by exi_id.
       80 + * nfs_exi_id_lock      Lock to protect the export ID list
       81 + *
       82 + * All exi_id_next, exi_id_overflow, and exi_id_tree are protected by
       83 + * nfs_exi_id_lock.
       84 + */
       85 +static int exi_id_next;
       86 +static bool_t exi_id_overflow;
       87 +avl_tree_t exi_id_tree;
       88 +kmutex_t nfs_exi_id_lock;
  74   89  
  75      -static int      unexport(exportinfo_t *);
       90 +static int      unexport(nfs_export_t *, exportinfo_t *);
  76   91  static void     exportfree(exportinfo_t *);
  77   92  static int      loadindex(exportdata_t *);
  78   93  
  79   94  extern void     nfsauth_cache_free(exportinfo_t *);
  80   95  extern int      sec_svc_loadrootnames(int, int, caddr_t **, model_t);
  81   96  extern void     sec_svc_freerootnames(int, int, caddr_t *);
  82   97  
  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);
       98 +static int      build_seclist_nodups(exportdata_t *, secinfo_t *, int);
       99 +static void     srv_secinfo_add(secinfo_t **, int *, secinfo_t *, int, int);
      100 +static void     srv_secinfo_remove(secinfo_t **, int *, secinfo_t *, int);
      101 +static void     srv_secinfo_treeclimb(nfs_export_t *, exportinfo_t *,
      102 +                    secinfo_t *, int, bool_t);
  87  103  
  88  104  #ifdef VOLATILE_FH_TEST
  89  105  static struct ex_vol_rename *find_volrnm_fh(exportinfo_t *, nfs_fh4 *);
  90  106  static uint32_t find_volrnm_fh_id(exportinfo_t *, nfs_fh4 *);
  91      -static void free_volrnm_list(exportinfo_t *);
      107 +static void     free_volrnm_list(exportinfo_t *);
  92  108  #endif /* VOLATILE_FH_TEST */
  93  109  
  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  110  fhandle_t nullfh2;      /* for comparing V2 filehandles */
 109  111  
 110  112  /*
 111  113   * macro for static dtrace probes to trace server namespace ref count mods.
 112  114   */
 113  115  #define SECREF_TRACE(seclist, tag, flav, aftcnt) \
 114  116          DTRACE_PROBE4(nfss__i__nmspc__secref, struct secinfo *, (seclist), \
 115  117                  char *, (tag), int, (int)(flav), int, (int)(aftcnt))
 116  118  
 117  119  
 118  120  #define exptablehash(fsid, fid) (nfs_fhhash((fsid), (fid)) & (EXPTABLESIZE - 1))
 119  121  
      122 +extern nfs_export_t *
      123 +nfs_get_export(void)
      124 +{
      125 +        return (zone_getspecific(nfs_export_key, curzone));
      126 +}
      127 +
 120  128  static uint8_t
 121  129  xor_hash(uint8_t *data, int len)
 122  130  {
 123  131          uint8_t h = 0;
 124  132  
 125  133          while (len--)
 126  134                  h ^= *data++;
 127  135  
 128  136          return (h);
 129  137  }
↓ open down ↓ 566 lines elided ↑ open up ↑
 696  704          ASSERT(exi_ret); /* Every visible should have its home exportinfo */
 697  705          return (exi_ret);
 698  706  }
 699  707  
 700  708  /*
 701  709   * For NFS V4.
 702  710   * Add or remove the newly exported or unexported security flavors of the
 703  711   * given exportinfo from its ancestors upto the system root.
 704  712   */
 705  713  void
 706      -srv_secinfo_treeclimb(exportinfo_t *exip, secinfo_t *sec, int seccnt,
 707      -    bool_t isadd)
      714 +srv_secinfo_treeclimb(nfs_export_t *ne, exportinfo_t *exip, secinfo_t *sec,
      715 +    int seccnt, bool_t isadd)
 708  716  {
 709  717          treenode_t *tnode = exip->exi_tree;
 710  718  
 711      -        ASSERT(RW_WRITE_HELD(&exported_lock));
      719 +        ASSERT(RW_WRITE_HELD(&ne->exported_lock));
 712  720          ASSERT(tnode != NULL);
 713  721  
 714  722          if (seccnt == 0)
 715  723                  return;
 716  724  
 717  725          /*
 718  726           * If flavors are being added and the new export root isn't
 719  727           * also VROOT, its implicitly allowed flavors are inherited from
 720  728           * its pseudonode.
 721  729           * Note - for VROOT exports the implicitly allowed flavors were
↓ open down ↓ 53 lines elided ↑ open up ↑
 775  783  
 776  784  #define exp_hash_link(exi, hash_name, bucket) \
 777  785          (exi)->hash_name.bckt = (bucket); \
 778  786          (exi)->hash_name.prev = NULL; \
 779  787          (exi)->hash_name.next = *(bucket); \
 780  788          if ((exi)->hash_name.next) \
 781  789                  (exi)->hash_name.next->hash_name.prev = (exi); \
 782  790          *(bucket) = (exi);
 783  791  
 784  792  void
 785      -export_link(exportinfo_t *exi)
      793 +export_link(nfs_export_t *ne, exportinfo_t *exi)
 786  794  {
 787  795          exportinfo_t **bckt;
 788  796  
 789      -        bckt = &exptable[exptablehash(&exi->exi_fsid, &exi->exi_fid)];
      797 +        ASSERT(RW_WRITE_HELD(&ne->exported_lock));
      798 +
      799 +        bckt = &ne->exptable[exptablehash(&exi->exi_fsid, &exi->exi_fid)];
 790  800          exp_hash_link(exi, fid_hash, bckt);
 791  801  
 792      -        bckt = &exptable_path_hash[pkp_tab_hash(exi->exi_export.ex_path,
      802 +        bckt = &ne->exptable_path_hash[pkp_tab_hash(exi->exi_export.ex_path,
 793  803              strlen(exi->exi_export.ex_path))];
 794  804          exp_hash_link(exi, path_hash, bckt);
 795  805  }
 796  806  
 797  807  /*
 798      - * Initialization routine for export routines. Should only be called once.
      808 + * Helper functions for exi_id handling
 799  809   */
      810 +static int
      811 +exi_id_compar(const void *v1, const void *v2)
      812 +{
      813 +        const struct exportinfo *e1 = v1;
      814 +        const struct exportinfo *e2 = v2;
      815 +
      816 +        if (e1->exi_id < e2->exi_id)
      817 +                return (-1);
      818 +        if (e1->exi_id > e2->exi_id)
      819 +                return (1);
      820 +
      821 +        return (0);
      822 +}
      823 +
 800  824  int
 801      -nfs_exportinit(void)
      825 +exi_id_get_next()
 802  826  {
 803      -        int error;
      827 +        struct exportinfo e;
      828 +        int ret = exi_id_next;
      829 +
      830 +        ASSERT(MUTEX_HELD(&nfs_exi_id_lock));
      831 +
      832 +        do {
      833 +                exi_id_next++;
      834 +                if (exi_id_next == 0)
      835 +                        exi_id_overflow = TRUE;
      836 +
      837 +                if (!exi_id_overflow)
      838 +                        break;
      839 +
      840 +                if (exi_id_next == ret)
      841 +                        cmn_err(CE_PANIC, "exi_id exhausted");
      842 +
      843 +                e.exi_id = exi_id_next;
      844 +        } while (avl_find(&exi_id_tree, &e, NULL) != NULL);
      845 +
      846 +        return (ret);
      847 +}
      848 +
      849 +/*ARGSUSED*/
      850 +static void *
      851 +nfs_export_zone_init(zoneid_t zoneid)
      852 +{
 804  853          int i;
      854 +        nfs_export_t *ne;
 805  855  
 806      -        rw_init(&exported_lock, NULL, RW_DEFAULT, NULL);
      856 +        ne = kmem_zalloc(sizeof (*ne), KM_SLEEP);
 807  857  
      858 +        rw_init(&ne->exported_lock, NULL, RW_DEFAULT, NULL);
      859 +
 808  860          /*
 809  861           * Allocate the place holder for the public file handle, which
 810  862           * is all zeroes. It is initially set to the root filesystem.
 811  863           */
 812      -        exi_root = kmem_zalloc(sizeof (*exi_root), KM_SLEEP);
 813      -        exi_public = exi_root;
      864 +        ne->exi_root = kmem_zalloc(sizeof (*ne->exi_root), KM_SLEEP);
      865 +        ne->exi_public = ne->exi_root;
 814  866  
 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';
      867 +        ne->exi_root->exi_export.ex_flags = EX_PUBLIC;
      868 +        ne->exi_root->exi_export.ex_pathlen = 1;        /* length of "/" */
      869 +        ne->exi_root->exi_export.ex_path =
      870 +            kmem_alloc(ne->exi_root->exi_export.ex_pathlen + 1, KM_SLEEP);
      871 +        ne->exi_root->exi_export.ex_path[0] = '/';
      872 +        ne->exi_root->exi_export.ex_path[1] = '\0';
 821  873  
 822      -        exi_root->exi_count = 1;
 823      -        mutex_init(&exi_root->exi_lock, NULL, MUTEX_DEFAULT, NULL);
      874 +        ne->exi_root->exi_count = 1;
      875 +        mutex_init(&ne->exi_root->exi_lock, NULL, MUTEX_DEFAULT, NULL);
 824  876  
 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);
      877 +        ne->exi_root->exi_vp = ZONE_ROOTVP();
      878 +        ne->exi_rootfid.fid_len = MAXFIDSZ;
      879 +        if (vop_fid_pseudo(ne->exi_root->exi_vp, &ne->exi_rootfid) != 0) {
      880 +                mutex_destroy(&ne->exi_root->exi_lock);
      881 +                kmem_free(ne->exi_root->exi_export.ex_path,
      882 +                    ne->exi_root->exi_export.ex_pathlen + 1);
      883 +                kmem_free(ne->exi_root, sizeof (*ne->exi_root));
      884 +                return (NULL);
 832  885          }
 833  886  
 834      -        /*
 835      -         * Initialize auth cache and auth cache lock
 836      -         */
      887 +        /* Initialize auth cache and auth cache lock */
 837  888          for (i = 0; i < AUTH_TABLESIZE; i++) {
 838      -                exi_root->exi_cache[i] = kmem_alloc(sizeof (avl_tree_t),
      889 +                ne->exi_root->exi_cache[i] = kmem_alloc(sizeof (avl_tree_t),
 839  890                      KM_SLEEP);
 840      -                avl_create(exi_root->exi_cache[i], nfsauth_cache_clnt_compar,
 841      -                    sizeof (struct auth_cache_clnt),
      891 +                avl_create(ne->exi_root->exi_cache[i],
      892 +                    nfsauth_cache_clnt_compar, sizeof (struct auth_cache_clnt),
 842  893                      offsetof(struct auth_cache_clnt, authc_link));
 843  894          }
 844      -        rw_init(&exi_root->exi_cache_lock, NULL, RW_DEFAULT, NULL);
      895 +        rw_init(&ne->exi_root->exi_cache_lock, NULL, RW_DEFAULT, NULL);
 845  896  
 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);
      897 +        /* Setup the fhandle template */
      898 +        ne->exi_root->exi_fh.fh_fsid = rootdir->v_vfsp->vfs_fsid;
      899 +        ne->exi_root->exi_fh.fh_xlen = ne->exi_rootfid.fid_len;
      900 +        bcopy(ne->exi_rootfid.fid_data, ne->exi_root->exi_fh.fh_xdata,
      901 +            ne->exi_rootfid.fid_len);
      902 +        ne->exi_root->exi_fh.fh_len = sizeof (ne->exi_root->exi_fh.fh_data);
 852  903  
 853      -        /*
 854      -         * Publish the exportinfo in the hash table
 855      -         */
 856      -        export_link(exi_root);
      904 +        rw_enter(&ne->exported_lock, RW_WRITER);
 857  905  
 858      -        nfslog_init();
 859      -        ns_root = NULL;
      906 +        /* Publish the exportinfo in the hash table */
      907 +        export_link(ne, ne->exi_root);
 860  908  
 861      -        return (0);
      909 +        /* Initialize exi_id and exi_kstats */
      910 +        mutex_enter(&nfs_exi_id_lock);
      911 +        ne->exi_root->exi_id = exi_id_get_next();
      912 +        avl_add(&exi_id_tree, ne->exi_root);
      913 +        mutex_exit(&nfs_exi_id_lock);
      914 +        ne->exi_root->exi_kstats = exp_kstats_init(zoneid,
      915 +            ne->exi_root->exi_id, ne->exi_root->exi_export.ex_path,
      916 +            ne->exi_root->exi_export.ex_pathlen, FALSE);
      917 +
      918 +        rw_exit(&ne->exported_lock);
      919 +        ne->ns_root = NULL;
      920 +
      921 +        return (ne);
 862  922  }
 863  923  
 864      -/*
 865      - * Finalization routine for export routines. Called to cleanup previously
 866      - * initialization work when the NFS server module could not be loaded correctly.
 867      - */
 868      -void
 869      -nfs_exportfini(void)
      924 +/*ARGSUSED*/
      925 +static void
      926 +nfs_export_zone_fini(zoneid_t zoneid, void *data)
 870  927  {
 871  928          int i;
      929 +        nfs_export_t *ne = data;
      930 +        struct exportinfo *exi;
 872  931  
 873      -        /*
 874      -         * Deallocate the place holder for the public file handle.
 875      -         */
 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);
      932 +        rw_enter(&ne->exported_lock, RW_WRITER);
      933 +        mutex_enter(&nfs_exi_id_lock);
      934 +
      935 +        exp_kstats_delete(ne->exi_root->exi_kstats);
      936 +        avl_remove(&exi_id_tree, ne->exi_root);
      937 +        export_unlink(ne, ne->exi_root);
      938 +
      939 +        mutex_exit(&nfs_exi_id_lock);
      940 +        rw_exit(&ne->exported_lock);
      941 +
      942 +        /* Deallocate the place holder for the public file handle */
      943 +        srv_secinfo_list_free(ne->exi_root->exi_export.ex_secinfo,
      944 +            ne->exi_root->exi_export.ex_seccnt);
      945 +        mutex_destroy(&ne->exi_root->exi_lock);
      946 +
      947 +        rw_destroy(&ne->exi_root->exi_cache_lock);
 880  948          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));
      949 +                avl_destroy(ne->exi_root->exi_cache[i]);
      950 +                kmem_free(ne->exi_root->exi_cache[i], sizeof (avl_tree_t));
 883  951          }
 884      -        kmem_free(exi_root, sizeof (*exi_root));
 885  952  
 886      -        rw_destroy(&exported_lock);
      953 +        exp_kstats_fini(ne->exi_root->exi_kstats);
      954 +        kmem_free(ne->exi_root->exi_export.ex_path,
      955 +            ne->exi_root->exi_export.ex_pathlen + 1);
      956 +        kmem_free(ne->exi_root, sizeof (*ne->exi_root));
      957 +
      958 +        exi = avl_first(&exi_id_tree);
      959 +        while (exi != NULL) {
      960 +                struct exportinfo *nexi = AVL_NEXT(&exi_id_tree, exi);
      961 +                if (zoneid == exi->exi_zoneid)
      962 +                        (void) unexport(ne, exi);
      963 +                exi = nexi;
      964 +        }
      965 +
      966 +        rw_destroy(&ne->exported_lock);
      967 +        kmem_free(ne, sizeof (*ne));
 887  968  }
 888  969  
 889  970  /*
      971 + * Initialization routine for export routines.
      972 + * Should only be called once.
      973 + */
      974 +void
      975 +nfs_exportinit(void)
      976 +{
      977 +        mutex_init(&nfs_exi_id_lock, NULL, MUTEX_DEFAULT, NULL);
      978 +
      979 +        /* exi_id handling initialization */
      980 +        exi_id_next = 0;
      981 +        exi_id_overflow = FALSE;
      982 +        avl_create(&exi_id_tree, exi_id_compar, sizeof (struct exportinfo),
      983 +            offsetof(struct exportinfo, exi_id_link));
      984 +
      985 +        zone_key_create(&nfs_export_key, nfs_export_zone_init,
      986 +            NULL, nfs_export_zone_fini);
      987 +
      988 +        nfslog_init();
      989 +}
      990 +
      991 +/*
      992 + * Finalization routine for export routines.
      993 + */
      994 +void
      995 +nfs_exportfini(void)
      996 +{
      997 +        (void) zone_key_delete(nfs_export_key);
      998 +        avl_destroy(&exi_id_tree);
      999 +        mutex_destroy(&nfs_exi_id_lock);
     1000 +}
     1001 +
     1002 +/*
 890 1003   *  Check if 2 gss mechanism identifiers are the same.
 891 1004   *
 892 1005   *  return FALSE if not the same.
 893 1006   *  return TRUE if the same.
 894 1007   */
 895 1008  static bool_t
 896 1009  nfs_mech_equal(rpc_gss_OID mech1, rpc_gss_OID mech2)
 897 1010  {
 898 1011          if ((mech1->length == 0) && (mech2->length == 0))
 899 1012                  return (TRUE);
↓ open down ↓ 15 lines elided ↑ open up ↑
 915 1028   *  we cast them to void.
 916 1029   */
 917 1030  /*ARGSUSED*/
 918 1031  bool_t
 919 1032  rfs_gsscallback(struct svc_req *req, gss_cred_id_t deleg, void *gss_context,
 920 1033      rpc_gss_lock_t *lock, void **cookie)
 921 1034  {
 922 1035          int i, j;
 923 1036          rpc_gss_rawcred_t *raw_cred;
 924 1037          struct exportinfo *exi;
     1038 +        nfs_export_t *ne = nfs_get_export();
 925 1039  
 926 1040          /*
 927 1041           * We don't deal with delegated credentials.
 928 1042           */
 929 1043          if (deleg != GSS_C_NO_CREDENTIAL)
 930 1044                  return (FALSE);
 931 1045  
 932 1046          raw_cred = lock->raw_cred;
 933 1047          *cookie = NULL;
 934 1048  
 935      -        rw_enter(&exported_lock, RW_READER);
     1049 +        rw_enter(&ne->exported_lock, RW_READER);
     1050 +
 936 1051          for (i = 0; i < EXPTABLESIZE; i++) {
 937      -                exi = exptable[i];
     1052 +                exi = ne->exptable[i];
 938 1053                  while (exi) {
 939 1054                          if (exi->exi_export.ex_seccnt > 0) {
 940 1055                                  struct secinfo *secp;
 941 1056                                  seconfig_t *se;
 942 1057                                  int seccnt;
 943 1058  
 944 1059                                  secp = exi->exi_export.ex_secinfo;
 945 1060                                  seccnt = exi->exi_export.ex_seccnt;
 946 1061                                  for (j = 0; j < seccnt; j++) {
 947 1062                                          /*
↓ open down ↓ 19 lines elided ↑ open up ↑
 967 1082                                                  *cookie = (void *)(uintptr_t)
 968 1083                                                      se->sc_nfsnum;
 969 1084                                                  goto done;
 970 1085                                          }
 971 1086                                  }
 972 1087                          }
 973 1088                          exi = exi->fid_hash.next;
 974 1089                  }
 975 1090          }
 976 1091  done:
 977      -        rw_exit(&exported_lock);
     1092 +        rw_exit(&ne->exported_lock);
 978 1093  
 979 1094          /*
 980 1095           * If no nfs pseudo number mapping can be found in the export
 981 1096           * table, assign the nfsflavor to NFS_FLAVOR_NOMAP. In V4, we may
 982 1097           * recover the flavor mismatch from NFS layer (NFS4ERR_WRONGSEC).
 983 1098           *
 984 1099           * For example:
 985 1100           *      server first shares with krb5i;
 986 1101           *      client mounts with krb5i;
 987 1102           *      server re-shares with krb5p;
↓ open down ↓ 46 lines elided ↑ open up ↑
1034 1149          int callback;
1035 1150          int allocd_seccnt;
1036 1151          STRUCT_HANDLE(exportfs_args, uap);
1037 1152          STRUCT_DECL(exportdata, uexi);
1038 1153          struct secinfo newsec[MAX_FLAVORS];
1039 1154          int newcnt;
1040 1155          struct secinfo oldsec[MAX_FLAVORS];
1041 1156          int oldcnt;
1042 1157          int i;
1043 1158          struct pathname lookpn;
     1159 +        nfs_export_t *ne = nfs_get_export();
1044 1160  
1045 1161          STRUCT_SET_HANDLE(uap, model, args);
1046 1162  
1047 1163          /* Read in pathname from userspace */
1048 1164          if (error = pn_get(STRUCT_FGETP(uap, dname), UIO_USERSPACE, &lookpn))
1049 1165                  return (error);
1050 1166  
1051 1167          /* Walk the export list looking for that pathname */
1052      -        rw_enter(&exported_lock, RW_READER);
     1168 +        rw_enter(&ne->exported_lock, RW_READER);
1053 1169          DTRACE_PROBE(nfss__i__exported_lock1_start);
1054      -        for (ex1 = exptable_path_hash[pkp_tab_hash(lookpn.pn_path,
     1170 +        for (ex1 = ne->exptable_path_hash[pkp_tab_hash(lookpn.pn_path,
1055 1171              strlen(lookpn.pn_path))]; ex1; ex1 = ex1->path_hash.next) {
1056      -                if (ex1 != exi_root && 0 ==
     1172 +                if (ex1 != ne->exi_root && 0 ==
1057 1173                      strcmp(ex1->exi_export.ex_path, lookpn.pn_path)) {
1058 1174                          exi_hold(ex1);
1059 1175                          break;
1060 1176                  }
1061 1177          }
1062 1178          DTRACE_PROBE(nfss__i__exported_lock1_stop);
1063      -        rw_exit(&exported_lock);
     1179 +        rw_exit(&ne->exported_lock);
1064 1180  
1065 1181          /* Is this an unshare? */
1066 1182          if (STRUCT_FGETP(uap, uex) == NULL) {
1067 1183                  pn_free(&lookpn);
1068 1184                  if (ex1 == NULL)
1069 1185                          return (EINVAL);
1070      -                error = unexport(ex1);
1071      -                exi_rele(ex1);
     1186 +                error = unexport(ne, ex1);
     1187 +                exi_rele(&ex1);
1072 1188                  return (error);
1073 1189          }
1074 1190  
1075 1191          /* It is a share or a re-share */
1076 1192          error = lookupname(STRUCT_FGETP(uap, dname), UIO_USERSPACE,
1077 1193              FOLLOW, &dvp, &vp);
1078 1194          if (error == EINVAL) {
1079 1195                  /*
1080 1196                   * if fname resolves to / we get EINVAL error
1081 1197                   * since we wanted the parent vnode. Try again
↓ open down ↓ 5 lines elided ↑ open up ↑
1087 1203          }
1088 1204          if (!error && vp == NULL) {
1089 1205                  /* Last component of fname not found */
1090 1206                  if (dvp != NULL)
1091 1207                          VN_RELE(dvp);
1092 1208                  error = ENOENT;
1093 1209          }
1094 1210          if (error) {
1095 1211                  pn_free(&lookpn);
1096 1212                  if (ex1)
1097      -                        exi_rele(ex1);
     1213 +                        exi_rele(&ex1);
1098 1214                  return (error);
1099 1215          }
1100 1216  
1101 1217          /*
1102 1218           * 'vp' may be an AUTOFS node, so we perform a
1103 1219           * VOP_ACCESS() to trigger the mount of the
1104 1220           * intended filesystem, so we can share the intended
1105 1221           * filesystem instead of the AUTOFS filesystem.
1106 1222           */
1107 1223          (void) VOP_ACCESS(vp, 0, 0, cr, NULL);
↓ open down ↓ 5 lines elided ↑ open up ↑
1113 1229           * filesystem AUTOFS mounted as result of the VOP_ACCESS()
1114 1230           * call not the AUTOFS node itself.
1115 1231           */
1116 1232          if (vn_mountedvfs(vp) != NULL) {
1117 1233                  if (error = traverse(&vp)) {
1118 1234                          VN_RELE(vp);
1119 1235                          if (dvp != NULL)
1120 1236                                  VN_RELE(dvp);
1121 1237                          pn_free(&lookpn);
1122 1238                          if (ex1)
1123      -                                exi_rele(ex1);
     1239 +                                exi_rele(&ex1);
1124 1240                          return (error);
1125 1241                  }
1126 1242          }
1127 1243  
1128 1244          /* Do not allow sharing another vnode for already shared path */
1129 1245          if (ex1 && !PSEUDO(ex1) && !VN_CMP(ex1->exi_vp, vp)) {
1130 1246                  VN_RELE(vp);
1131 1247                  if (dvp != NULL)
1132 1248                          VN_RELE(dvp);
1133 1249                  pn_free(&lookpn);
1134      -                exi_rele(ex1);
     1250 +                exi_rele(&ex1);
1135 1251                  return (EEXIST);
1136 1252          }
1137 1253          if (ex1)
1138      -                exi_rele(ex1);
     1254 +                exi_rele(&ex1);
1139 1255  
1140 1256          /*
1141 1257           * Get the vfs id
1142 1258           */
1143 1259          bzero(&fid, sizeof (fid));
1144 1260          fid.fid_len = MAXFIDSZ;
1145 1261          error = VOP_FID(vp, &fid, NULL);
1146 1262          fsid = vp->v_vfsp->vfs_fsid;
1147 1263  
1148 1264          if (error) {
↓ open down ↓ 7 lines elided ↑ open up ↑
1156 1272                  if (error == ENOSPC)
1157 1273                          error = EREMOTE;
1158 1274                  pn_free(&lookpn);
1159 1275                  return (error);
1160 1276          }
1161 1277  
1162 1278          /*
1163 1279           * Do not allow re-sharing a shared vnode under a different path
1164 1280           * PSEUDO export has ex_path fabricated, e.g. "/tmp (pseudo)", skip it.
1165 1281           */
1166      -        rw_enter(&exported_lock, RW_READER);
     1282 +        rw_enter(&ne->exported_lock, RW_READER);
1167 1283          DTRACE_PROBE(nfss__i__exported_lock2_start);
1168      -        for (ex2 = exptable[exptablehash(&fsid, &fid)]; ex2;
     1284 +        for (ex2 = ne->exptable[exptablehash(&fsid, &fid)]; ex2;
1169 1285              ex2 = ex2->fid_hash.next) {
1170      -                if (ex2 != exi_root && !PSEUDO(ex2) &&
     1286 +                if (ex2 != ne->exi_root && !PSEUDO(ex2) &&
1171 1287                      VN_CMP(ex2->exi_vp, vp) &&
1172 1288                      strcmp(ex2->exi_export.ex_path, lookpn.pn_path) != 0) {
1173 1289                          DTRACE_PROBE(nfss__i__exported_lock2_stop);
1174      -                        rw_exit(&exported_lock);
     1290 +                        rw_exit(&ne->exported_lock);
1175 1291                          VN_RELE(vp);
1176 1292                          if (dvp != NULL)
1177 1293                                  VN_RELE(dvp);
1178 1294                          pn_free(&lookpn);
1179 1295                          return (EEXIST);
1180 1296                  }
1181 1297          }
1182 1298          DTRACE_PROBE(nfss__i__exported_lock2_stop);
1183      -        rw_exit(&exported_lock);
     1299 +        rw_exit(&ne->exported_lock);
1184 1300          pn_free(&lookpn);
1185 1301  
1186 1302          exi = kmem_zalloc(sizeof (*exi), KM_SLEEP);
1187 1303          exi->exi_fsid = fsid;
1188 1304          exi->exi_fid = fid;
1189 1305          exi->exi_vp = vp;
1190 1306          exi->exi_count = 1;
     1307 +        exi->exi_zoneid = crgetzoneid(cr);
1191 1308          exi->exi_volatile_dev = (vfssw[vp->v_vfsp->vfs_fstype].vsw_flag &
1192 1309              VSW_VOLATILEDEV) ? 1 : 0;
1193 1310          mutex_init(&exi->exi_lock, NULL, MUTEX_DEFAULT, NULL);
1194 1311          exi->exi_dvp = dvp;
1195 1312  
1196 1313          /*
1197 1314           * Initialize auth cache and auth cache lock
1198 1315           */
1199 1316          for (i = 0; i < AUTH_TABLESIZE; i++) {
1200 1317                  exi->exi_cache[i] = kmem_alloc(sizeof (avl_tree_t), KM_SLEEP);
↓ open down ↓ 253 lines elided ↑ open up ↑
1454 1571          }
1455 1572  
1456 1573          if (kex->ex_flags & EX_LOG) {
1457 1574                  if (error = nfslog_setup(exi))
1458 1575                          goto out6;
1459 1576          }
1460 1577  
1461 1578          /*
1462 1579           * Insert the new entry at the front of the export list
1463 1580           */
1464      -        rw_enter(&exported_lock, RW_WRITER);
     1581 +        rw_enter(&ne->exported_lock, RW_WRITER);
1465 1582          DTRACE_PROBE(nfss__i__exported_lock3_start);
1466 1583  
1467      -        export_link(exi);
     1584 +        export_link(ne, exi);
1468 1585  
1469 1586          /*
1470 1587           * Check the rest of the list for an old entry for the fs.
1471 1588           * If one is found then unlink it, wait until this is the
1472 1589           * only reference and then free it.
1473 1590           */
1474 1591          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);
     1592 +                if (ex != ne->exi_root && VN_CMP(ex->exi_vp, vp)) {
     1593 +                        mutex_enter(&nfs_exi_id_lock);
     1594 +                        avl_remove(&exi_id_tree, ex);
     1595 +                        mutex_exit(&nfs_exi_id_lock);
     1596 +                        export_unlink(ne, ex);
1477 1597                          break;
1478 1598                  }
1479 1599          }
1480 1600  
1481 1601          /*
1482 1602           * If the public filehandle is pointing at the
1483 1603           * old entry, then point it back at the root.
1484 1604           */
1485      -        if (ex != NULL && ex == exi_public)
1486      -                exi_public = exi_root;
     1605 +        if (ex != NULL && ex == ne->exi_public)
     1606 +                ne->exi_public = ne->exi_root;
1487 1607  
1488 1608          /*
1489 1609           * If the public flag is on, make the global exi_public
1490 1610           * point to this entry and turn off the public bit so that
1491 1611           * we can distinguish it from the place holder export.
1492 1612           */
1493 1613          if (kex->ex_flags & EX_PUBLIC) {
1494      -                exi_public = exi;
     1614 +                ne->exi_public = exi;
1495 1615                  kex->ex_flags &= ~EX_PUBLIC;
1496 1616          }
1497 1617  
1498 1618  #ifdef VOLATILE_FH_TEST
1499 1619          /*
1500 1620           * Set up the volatile_id value if volatile on share.
1501 1621           * The list of volatile renamed filehandles is always destroyed,
1502 1622           * if the fs was reshared.
1503 1623           */
1504 1624          if (kex->ex_flags & EX_VOLFH)
↓ open down ↓ 11 lines elided ↑ open up ↑
1516 1636          if (ex == NULL) {
1517 1637                  error = treeclimb_export(exi);
1518 1638                  if (error)
1519 1639                          goto out7;
1520 1640          } else {
1521 1641                  /* If it's a re-export update namespace tree */
1522 1642                  exi->exi_tree = ex->exi_tree;
1523 1643                  exi->exi_tree->tree_exi = exi;
1524 1644  
1525 1645                  /* Update the change timestamp */
1526      -                tree_update_change(exi->exi_tree, NULL);
     1646 +                tree_update_change(ne, exi->exi_tree, NULL);
1527 1647          }
1528 1648  
1529 1649          /*
1530 1650           * build a unique flavor list from the flavors specified
1531 1651           * in the share cmd.  unique means that each flavor only
1532 1652           * appears once in the secinfo list -- no duplicates allowed.
1533 1653           */
1534 1654          newcnt = build_seclist_nodups(&exi->exi_export, newsec, FALSE);
1535 1655  
1536      -        srv_secinfo_treeclimb(exi, newsec, newcnt, TRUE);
     1656 +        srv_secinfo_treeclimb(ne, exi, newsec, newcnt, TRUE);
1537 1657  
1538 1658          /*
1539 1659           * If re-sharing an old export entry, update the secinfo data
1540 1660           * depending on if the old entry is a pseudo node or not.
1541 1661           */
1542 1662          if (ex != NULL) {
1543 1663                  oldcnt = build_seclist_nodups(&ex->exi_export, oldsec, FALSE);
1544 1664                  if (PSEUDO(ex)) {
1545 1665                          /*
1546 1666                           * The dir being shared is a pseudo export root (which
↓ open down ↓ 4 lines elided ↑ open up ↑
1551 1671                           * pseudo exprot root to the new (real) export root.
1552 1672                           */
1553 1673                          srv_secinfo_add(&exi->exi_export.ex_secinfo,
1554 1674                              &exi->exi_export.ex_seccnt, oldsec, oldcnt, TRUE);
1555 1675                  } else {
1556 1676                          /*
1557 1677                           * First transfer implicit flavor refs to new export.
1558 1678                           * Remove old flavor refs last.
1559 1679                           */
1560 1680                          srv_secinfo_exp2exp(&exi->exi_export, oldsec, oldcnt);
1561      -                        srv_secinfo_treeclimb(ex, oldsec, oldcnt, FALSE);
     1681 +                        srv_secinfo_treeclimb(ne, ex, oldsec, oldcnt, FALSE);
1562 1682                  }
1563 1683          }
1564 1684  
1565 1685          /*
1566 1686           * If it's a re-export and the old entry has a pseudonode list,
1567 1687           * transfer it to the new export.
1568 1688           */
1569 1689          if (ex != NULL && (ex->exi_visible != NULL)) {
1570 1690                  exi->exi_visible = ex->exi_visible;
1571 1691                  ex->exi_visible = NULL;
1572 1692          }
1573 1693  
     1694 +        /*
     1695 +         * Initialize exi_id and exi_kstats
     1696 +         */
     1697 +        if (ex != NULL) {
     1698 +                exi->exi_id = ex->exi_id;
     1699 +                exi->exi_kstats = ex->exi_kstats;
     1700 +                ex->exi_kstats = NULL;
     1701 +                exp_kstats_reset(exi->exi_kstats, kex->ex_path,
     1702 +                    kex->ex_pathlen, FALSE);
     1703 +        } else {
     1704 +                mutex_enter(&nfs_exi_id_lock);
     1705 +                exi->exi_id = exi_id_get_next();
     1706 +                mutex_exit(&nfs_exi_id_lock);
     1707 +                exi->exi_kstats = exp_kstats_init(crgetzoneid(cr), exi->exi_id,
     1708 +                    kex->ex_path, kex->ex_pathlen, FALSE);
     1709 +        }
     1710 +        mutex_enter(&nfs_exi_id_lock);
     1711 +        avl_add(&exi_id_tree, exi);
     1712 +        mutex_exit(&nfs_exi_id_lock);
     1713 +
1574 1714          DTRACE_PROBE(nfss__i__exported_lock3_stop);
1575      -        rw_exit(&exported_lock);
     1715 +        rw_exit(&ne->exported_lock);
1576 1716  
1577      -        if (exi_public == exi || kex->ex_flags & EX_LOG) {
     1717 +        if (ne->exi_public == exi || kex->ex_flags & EX_LOG) {
1578 1718                  /*
1579 1719                   * Log share operation to this buffer only.
1580 1720                   */
1581 1721                  nfslog_share_record(exi, cr);
1582 1722          }
1583 1723  
1584 1724          if (ex != NULL)
1585      -                exi_rele(ex);
     1725 +                exi_rele(&ex);
1586 1726  
1587 1727          return (0);
1588 1728  
1589 1729  out7:
1590 1730          /* Unlink the new export in exptable. */
1591      -        export_unlink(exi);
     1731 +        export_unlink(ne, exi);
1592 1732          DTRACE_PROBE(nfss__i__exported_lock3_stop);
1593      -        rw_exit(&exported_lock);
     1733 +        rw_exit(&ne->exported_lock);
1594 1734  out6:
1595 1735          if (kex->ex_flags & EX_INDEX)
1596 1736                  kmem_free(kex->ex_index, strlen(kex->ex_index) + 1);
1597 1737  out5:
1598 1738          /* free partially completed allocation */
1599 1739          while (--allocd_seccnt >= 0) {
1600 1740                  exs = &kex->ex_secinfo[allocd_seccnt];
1601 1741                  srv_secinfo_entry_free(exs);
1602 1742          }
1603 1743  
↓ open down ↓ 23 lines elided ↑ open up ↑
1627 1767  
1628 1768          kmem_free(exi, sizeof (*exi));
1629 1769  
1630 1770          return (error);
1631 1771  }
1632 1772  
1633 1773  /*
1634 1774   * Remove the exportinfo from the export list
1635 1775   */
1636 1776  void
1637      -export_unlink(struct exportinfo *exi)
     1777 +export_unlink(nfs_export_t *ne, struct exportinfo *exi)
1638 1778  {
1639      -        ASSERT(RW_WRITE_HELD(&exported_lock));
     1779 +        ASSERT(RW_WRITE_HELD(&ne->exported_lock));
1640 1780  
1641 1781          exp_hash_unlink(exi, fid_hash);
1642 1782          exp_hash_unlink(exi, path_hash);
1643 1783  }
1644 1784  
1645 1785  /*
1646 1786   * Unexport an exported filesystem
1647 1787   */
1648 1788  static int
1649      -unexport(struct exportinfo *exi)
     1789 +unexport(nfs_export_t *ne, struct exportinfo *exi)
1650 1790  {
1651 1791          struct secinfo cursec[MAX_FLAVORS];
1652 1792          int curcnt;
1653 1793  
1654      -        rw_enter(&exported_lock, RW_WRITER);
     1794 +        rw_enter(&ne->exported_lock, RW_WRITER);
1655 1795  
1656 1796          /* Check if exi is still linked in the export table */
1657 1797          if (!EXP_LINKED(exi) || PSEUDO(exi)) {
1658      -                rw_exit(&exported_lock);
     1798 +                rw_exit(&ne->exported_lock);
1659 1799                  return (EINVAL);
1660 1800          }
1661 1801  
1662      -        export_unlink(exi);
     1802 +        exp_kstats_delete(exi->exi_kstats);
     1803 +        mutex_enter(&nfs_exi_id_lock);
     1804 +        avl_remove(&exi_id_tree, exi);
     1805 +        mutex_exit(&nfs_exi_id_lock);
     1806 +        export_unlink(ne, exi);
1663 1807  
1664 1808          /*
1665 1809           * Remove security flavors before treeclimb_unexport() is called
1666 1810           * because srv_secinfo_treeclimb needs the namespace tree
1667 1811           */
1668 1812          curcnt = build_seclist_nodups(&exi->exi_export, cursec, TRUE);
     1813 +        srv_secinfo_treeclimb(ne, exi, cursec, curcnt, FALSE);
1669 1814  
1670      -        srv_secinfo_treeclimb(exi, cursec, curcnt, FALSE);
1671      -
1672 1815          /*
1673 1816           * If there's a visible list, then need to leave
1674 1817           * a pseudo export here to retain the visible list
1675 1818           * for paths to exports below.
1676 1819           */
1677 1820          if (exi->exi_visible != NULL) {
1678 1821                  struct exportinfo *newexi;
1679 1822  
1680      -                newexi = pseudo_exportfs(exi->exi_vp, &exi->exi_fid,
     1823 +                newexi = pseudo_exportfs(ne, exi->exi_vp, &exi->exi_fid,
1681 1824                      exi->exi_visible, &exi->exi_export);
1682 1825                  exi->exi_visible = NULL;
1683 1826  
1684 1827                  /* interconnect the existing treenode with the new exportinfo */
1685 1828                  newexi->exi_tree = exi->exi_tree;
1686 1829                  newexi->exi_tree->tree_exi = newexi;
1687 1830  
1688 1831                  /* Update the change timestamp */
1689      -                tree_update_change(exi->exi_tree, NULL);
     1832 +                tree_update_change(ne, exi->exi_tree, NULL);
1690 1833          } else {
1691      -                treeclimb_unexport(exi);
     1834 +                treeclimb_unexport(ne, exi);
1692 1835          }
1693 1836  
1694      -        rw_exit(&exported_lock);
     1837 +        rw_exit(&ne->exported_lock);
1695 1838  
1696 1839          /*
1697 1840           * Need to call into the NFSv4 server and release all data
1698 1841           * held on this particular export.  This is important since
1699 1842           * the v4 server may be holding file locks or vnodes under
1700 1843           * this export.
1701 1844           */
1702 1845          rfs4_clean_state_exi(exi);
1703 1846  
1704 1847          /*
1705 1848           * Notify the lock manager that the filesystem is being
1706 1849           * unexported.
1707 1850           */
1708 1851          lm_unexport(exi);
1709 1852  
1710 1853          /*
1711 1854           * If this was a public export, restore
1712 1855           * the public filehandle to the root.
1713 1856           */
1714      -        if (exi == exi_public) {
1715      -                exi_public = exi_root;
     1857 +        if (exi == ne->exi_public) {
     1858 +                ne->exi_public = ne->exi_root;
1716 1859  
1717      -                nfslog_share_record(exi_public, CRED());
     1860 +                nfslog_share_record(ne->exi_public, CRED());
1718 1861          }
1719 1862  
1720      -        if (exi->exi_export.ex_flags & EX_LOG) {
     1863 +        if (exi->exi_export.ex_flags & EX_LOG)
1721 1864                  nfslog_unshare_record(exi, CRED());
1722      -        }
1723 1865  
1724      -        exi_rele(exi);
     1866 +        exi_rele(&exi);
1725 1867          return (0);
1726 1868  }
1727 1869  
1728 1870  /*
1729 1871   * Get file handle system call.
1730 1872   * Takes file name and returns a file handle for it.
1731 1873   * Credentials must be verified before calling.
1732 1874   */
1733 1875  int
1734 1876  nfs_getfh(struct nfs_getfh_args *args, model_t model, cred_t *cr)
↓ open down ↓ 135 lines elided ↑ open up ↑
1870 2012                                  i += sz;
1871 2013                                  sz = NFS_FHMAXDATA;
1872 2014                                  bcopy(fh.fh3_xdata, &logbuf[i], sz);
1873 2015                                  i += sz;
1874 2016                          }
1875 2017                  }
1876 2018                  if (!error && exi->exi_export.ex_flags & EX_LOG) {
1877 2019                          nfslog_getfh(exi, (fhandle_t *)logptr,
1878 2020                              STRUCT_FGETP(uap, fname), UIO_USERSPACE, cr);
1879 2021                  }
1880      -                exi_rele(exi);
     2022 +                exi_rele(&exi);
1881 2023                  if (!error) {
1882 2024                          if (copyout(&l, STRUCT_FGETP(uap, lenp), sizeof (int)))
1883 2025                                  error = EFAULT;
1884 2026                          if (copyout(buf, STRUCT_FGETP(uap, fhp), l))
1885 2027                                  error = EFAULT;
1886 2028                  }
1887 2029          }
1888 2030          VN_RELE(vp);
1889 2031          if (dvp != NULL) {
1890 2032                  VN_RELE(dvp);
↓ open down ↓ 548 lines elided ↑ open up ↑
2439 2581  }
2440 2582  
2441 2583  /*
2442 2584   * Find the export structure associated with the given filesystem.
2443 2585   * If found, then increment the ref count (exi_count).
2444 2586   */
2445 2587  struct exportinfo *
2446 2588  checkexport(fsid_t *fsid, fid_t *fid)
2447 2589  {
2448 2590          struct exportinfo *exi;
     2591 +        nfs_export_t *ne = nfs_get_export();
2449 2592  
2450      -        rw_enter(&exported_lock, RW_READER);
2451      -        for (exi = exptable[exptablehash(fsid, fid)];
     2593 +        rw_enter(&ne->exported_lock, RW_READER);
     2594 +        for (exi = ne->exptable[exptablehash(fsid, fid)];
2452 2595              exi != NULL;
2453 2596              exi = exi->fid_hash.next) {
2454 2597                  if (exportmatch(exi, fsid, fid)) {
2455 2598                          /*
2456 2599                           * If this is the place holder for the
2457 2600                           * public file handle, then return the
2458 2601                           * real export entry for the public file
2459 2602                           * handle.
2460 2603                           */
2461 2604                          if (exi->exi_export.ex_flags & EX_PUBLIC) {
2462      -                                exi = exi_public;
     2605 +                                exi = ne->exi_public;
2463 2606                          }
2464 2607  
2465 2608                          exi_hold(exi);
2466      -                        rw_exit(&exported_lock);
     2609 +                        rw_exit(&ne->exported_lock);
2467 2610                          return (exi);
2468 2611                  }
2469 2612          }
2470      -        rw_exit(&exported_lock);
     2613 +        rw_exit(&ne->exported_lock);
2471 2614          return (NULL);
2472 2615  }
2473 2616  
2474 2617  
2475 2618  /*
2476 2619   * "old school" version of checkexport() for NFS4.  NFS4
2477 2620   * rfs4_compound holds exported_lock for duration of compound
2478 2621   * processing.  This version doesn't manipulate exi_count
2479 2622   * since NFS4 breaks fundamental assumptions in the exi_count
2480 2623   * design.
2481 2624   */
2482 2625  struct exportinfo *
2483 2626  checkexport4(fsid_t *fsid, fid_t *fid, vnode_t *vp)
2484 2627  {
2485 2628          struct exportinfo *exi;
     2629 +        nfs_export_t *ne = nfs_get_export();
2486 2630  
2487      -        ASSERT(RW_LOCK_HELD(&exported_lock));
     2631 +        ASSERT(RW_LOCK_HELD(&ne->exported_lock));
2488 2632  
2489      -        for (exi = exptable[exptablehash(fsid, fid)];
     2633 +        for (exi = ne->exptable[exptablehash(fsid, fid)];
2490 2634              exi != NULL;
2491 2635              exi = exi->fid_hash.next) {
2492 2636                  if (exportmatch(exi, fsid, fid)) {
2493 2637                          /*
2494 2638                           * If this is the place holder for the
2495 2639                           * public file handle, then return the
2496 2640                           * real export entry for the public file
2497 2641                           * handle.
2498 2642                           */
2499 2643                          if (exi->exi_export.ex_flags & EX_PUBLIC) {
2500      -                                exi = exi_public;
     2644 +                                exi = ne->exi_public;
2501 2645                          }
2502 2646  
2503 2647                          /*
2504 2648                           * If vp is given, check if vp is the
2505 2649                           * same vnode as the exported node.
2506 2650                           *
2507 2651                           * Since VOP_FID of a lofs node returns the
2508 2652                           * fid of its real node (ufs), the exported
2509 2653                           * node for lofs and (pseudo) ufs may have
2510 2654                           * the same fsid and fid.
↓ open down ↓ 2 lines elided ↑ open up ↑
2513 2657                                  return (exi);
2514 2658                  }
2515 2659          }
2516 2660  
2517 2661          return (NULL);
2518 2662  }
2519 2663  
2520 2664  /*
2521 2665   * Free an entire export list node
2522 2666   */
2523      -void
     2667 +static void
2524 2668  exportfree(struct exportinfo *exi)
2525 2669  {
2526 2670          struct exportdata *ex;
2527 2671          struct charset_cache *cache;
2528 2672          int i;
2529 2673  
2530 2674          ex = &exi->exi_export;
2531 2675  
2532 2676          ASSERT(exi->exi_vp != NULL && !(exi->exi_export.ex_flags & EX_PUBLIC));
2533 2677          VN_RELE(exi->exi_vp);
↓ open down ↓ 42 lines elided ↑ open up ↑
2576 2720          /*
2577 2721           * All nodes in the exi_cache AVL trees were removed and freed in the
2578 2722           * nfsauth_cache_free() call above.  We will just destroy and free the
2579 2723           * empty AVL trees here.
2580 2724           */
2581 2725          for (i = 0; i < AUTH_TABLESIZE; i++) {
2582 2726                  avl_destroy(exi->exi_cache[i]);
2583 2727                  kmem_free(exi->exi_cache[i], sizeof (avl_tree_t));
2584 2728          }
2585 2729  
     2730 +        exp_kstats_fini(exi->exi_kstats);
     2731 +
2586 2732          kmem_free(exi, sizeof (*exi));
2587 2733  }
2588 2734  
2589 2735  /*
2590 2736   * load the index file from user space into kernel space.
2591 2737   */
2592 2738  static int
2593 2739  loadindex(struct exportdata *kex)
2594 2740  {
2595 2741          int error;
↓ open down ↓ 21 lines elided ↑ open up ↑
2617 2763          exi->exi_count++;
2618 2764          mutex_exit(&exi->exi_lock);
2619 2765  }
2620 2766  
2621 2767  /*
2622 2768   * When a thread completes using exi, it should call exi_rele().
2623 2769   * exi_rele() decrements exi_count. It releases exi if exi_count == 0, i.e.
2624 2770   * if this is the last user of exi and exi is not on exportinfo list anymore
2625 2771   */
2626 2772  void
2627      -exi_rele(struct exportinfo *exi)
     2773 +exi_rele(struct exportinfo **exi)
2628 2774  {
2629      -        mutex_enter(&exi->exi_lock);
2630      -        exi->exi_count--;
2631      -        if (exi->exi_count == 0) {
2632      -                mutex_exit(&exi->exi_lock);
2633      -                exportfree(exi);
     2775 +        struct exportinfo *exip = *exi;
     2776 +        mutex_enter(&exip->exi_lock);
     2777 +        exip->exi_count--;
     2778 +        if (exip->exi_count == 0) {
     2779 +                mutex_exit(&exip->exi_lock);
     2780 +                /*
     2781 +                 * The exportinfo structure needs to be cleared here
     2782 +                 * since the control point, for when we free the structure,
     2783 +                 * is in this function and is triggered by the reference
     2784 +                 * count. The caller does not necessarily know when that
     2785 +                 * will be the case.
     2786 +                 */
     2787 +                *exi = NULL;
     2788 +                exportfree(exip);
2634 2789          } else
2635      -                mutex_exit(&exi->exi_lock);
     2790 +                mutex_exit(&exip->exi_lock);
2636 2791  }
2637 2792  
2638 2793  #ifdef VOLATILE_FH_TEST
2639 2794  /*
2640 2795   * Test for volatile fh's - add file handle to list and set its volatile id
2641 2796   * to time it was renamed. If EX_VOLFH is also on and the fs is reshared,
2642 2797   * the vol_rename queue is purged.
2643 2798   *
2644 2799   * XXX This code is for unit testing purposes only... To correctly use it, it
2645 2800   * needs to tie a rename list to the export struct and (more
↓ open down ↓ 96 lines elided ↑ open up ↑
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX