51 #include <sys/cmn_err.h>
  52 #include <sys/acl.h>
  53 #include <sys/utsname.h>
  54 #include <sys/sdt.h>
  55 #include <netinet/in.h>
  56 #include <sys/avl.h>
  57 
  58 #include <rpc/types.h>
  59 #include <rpc/auth.h>
  60 #include <rpc/svc.h>
  61 
  62 #include <nfs/nfs.h>
  63 #include <nfs/export.h>
  64 #include <nfs/nfssys.h>
  65 #include <nfs/nfs_clnt.h>
  66 #include <nfs/nfs_acl.h>
  67 #include <nfs/nfs_log.h>
  68 #include <nfs/lm.h>
  69 #include <sys/sunddi.h>
  70 
  71 static zone_key_t nfs_export_key;
  72 
  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;
  89 
  90 static int      unexport(nfs_export_t *, exportinfo_t *);
  91 static void     exportfree(exportinfo_t *);
  92 static int      loadindex(exportdata_t *);
 
 
 105 static struct ex_vol_rename *find_volrnm_fh(exportinfo_t *, nfs_fh4 *);
 106 static uint32_t find_volrnm_fh_id(exportinfo_t *, nfs_fh4 *);
 107 static void     free_volrnm_list(exportinfo_t *);
 108 #endif /* VOLATILE_FH_TEST */
 109 
 110 fhandle_t nullfh2;      /* for comparing V2 filehandles */
 111 
 112 /*
 113  * macro for static dtrace probes to trace server namespace ref count mods.
 114  */
 115 #define SECREF_TRACE(seclist, tag, flav, aftcnt) \
 116         DTRACE_PROBE4(nfss__i__nmspc__secref, struct secinfo *, (seclist), \
 117                 char *, (tag), int, (int)(flav), int, (int)(aftcnt))
 118 
 119 
 120 #define exptablehash(fsid, fid) (nfs_fhhash((fsid), (fid)) & (EXPTABLESIZE - 1))
 121 
 122 extern nfs_export_t *
 123 nfs_get_export(void)
 124 {
 125         return (zone_getspecific(nfs_export_key, curzone));
 126 }
 127 
 128 static uint8_t
 129 xor_hash(uint8_t *data, int len)
 130 {
 131         uint8_t h = 0;
 132 
 133         while (len--)
 134                 h ^= *data++;
 135 
 136         return (h);
 137 }
 138 
 139 /*
 140  * File handle hash function, XOR over all bytes in fsid and fid.
 141  */
 142 static unsigned
 143 nfs_fhhash(fsid_t *fsid, fid_t *fid)
 144 {
 145         int len;
 
 705                 if (TREE_ROOT(tnode)) {
 706                         ASSERT3P(zone, ==, tnode->tree_exi->exi_zone);
 707                         exi_ret = tnode->tree_exi;
 708                         break;
 709                 }
 710         }
 711 
 712         ASSERT(exi_ret); /* Every visible should have its home exportinfo */
 713         return (exi_ret);
 714 }
 715 
 716 /*
 717  * For NFS V4.
 718  * Add or remove the newly exported or unexported security flavors of the
 719  * given exportinfo from its ancestors upto the system root.
 720  */
 721 void
 722 srv_secinfo_treeclimb(nfs_export_t *ne, exportinfo_t *exip, secinfo_t *sec,
 723     int seccnt, bool_t isadd)
 724 {
 725         treenode_t *tnode = exip->exi_tree;
 726 
 727         ASSERT(RW_WRITE_HELD(&ne->exported_lock));
 728         ASSERT(tnode != NULL);
 729 
 730         if (seccnt == 0)
 731                 return;
 732 
 733         /*
 734          * If flavors are being added and the new export root isn't
 735          * also VROOT, its implicitly allowed flavors are inherited from
 736          * its pseudonode.
 737          * Note - for VROOT exports the implicitly allowed flavors were
 738          * transferred from the PSEUDO export in exportfs()
 739          */
 740         if (isadd && !(exip->exi_vp->v_flag & VROOT) &&
 741             !VN_IS_CURZONEROOT(exip->exi_vp) &&
 742             tnode->tree_vis->vis_seccnt > 0) {
 743                 srv_secinfo_add(&exip->exi_export.ex_secinfo,
 744                     &exip->exi_export.ex_seccnt, tnode->tree_vis->vis_secinfo,
 745                     tnode->tree_vis->vis_seccnt, FALSE);
 746         }
 747 
 748         /*
 749          * Move to parent node and propagate sec flavor
 
 787         if ((exi)->hash_name.prev) \
 788                 (exi)->hash_name.prev->hash_name.next = (exi)->hash_name.next; \
 789         if ((exi)->hash_name.next) \
 790                 (exi)->hash_name.next->hash_name.prev = (exi)->hash_name.prev; \
 791         (exi)->hash_name.bckt = NULL;
 792 
 793 #define exp_hash_link(exi, hash_name, bucket) \
 794         (exi)->hash_name.bckt = (bucket); \
 795         (exi)->hash_name.prev = NULL; \
 796         (exi)->hash_name.next = *(bucket); \
 797         if ((exi)->hash_name.next) \
 798                 (exi)->hash_name.next->hash_name.prev = (exi); \
 799         *(bucket) = (exi);
 800 
 801 void
 802 export_link(nfs_export_t *ne, exportinfo_t *exi)
 803 {
 804         exportinfo_t **bckt;
 805 
 806         ASSERT(RW_WRITE_HELD(&ne->exported_lock));
 807 
 808         bckt = &ne->exptable[exptablehash(&exi->exi_fsid, &exi->exi_fid)];
 809         exp_hash_link(exi, fid_hash, bckt);
 810 
 811         bckt = &ne->exptable_path_hash[pkp_tab_hash(exi->exi_export.ex_path,
 812             strlen(exi->exi_export.ex_path))];
 813         exp_hash_link(exi, path_hash, bckt);
 814 }
 815 
 816 /*
 817  * Helper functions for exi_id handling
 818  */
 819 static int
 820 exi_id_compar(const void *v1, const void *v2)
 821 {
 822         const struct exportinfo *e1 = v1;
 823         const struct exportinfo *e2 = v2;
 824 
 825         if (e1->exi_id < e2->exi_id)
 826                 return (-1);
 
 838 
 839         ASSERT(MUTEX_HELD(&nfs_exi_id_lock));
 840 
 841         do {
 842                 exi_id_next++;
 843                 if (exi_id_next == 0)
 844                         exi_id_overflow = TRUE;
 845 
 846                 if (!exi_id_overflow)
 847                         break;
 848 
 849                 if (exi_id_next == ret)
 850                         cmn_err(CE_PANIC, "exi_id exhausted");
 851 
 852                 e.exi_id = exi_id_next;
 853         } while (avl_find(&exi_id_tree, &e, NULL) != NULL);
 854 
 855         return (ret);
 856 }
 857 
 858 /*ARGSUSED*/
 859 static void *
 860 nfs_export_zone_init(zoneid_t zoneid)
 861 {
 862         int i;
 863         nfs_export_t *ne;
 864 
 865         ne = kmem_zalloc(sizeof (*ne), KM_SLEEP);
 866 
 867         rw_init(&ne->exported_lock, NULL, RW_DEFAULT, NULL);
 868 
 869         /*
 870          * Allocate the place holder for the public file handle, which
 871          * is all zeroes. It is initially set to the root filesystem.
 872          */
 873         ne->exi_root = kmem_zalloc(sizeof (*ne->exi_root), KM_SLEEP);
 874         ne->exi_public = ne->exi_root;
 875 
 876         ne->exi_root->exi_export.ex_flags = EX_PUBLIC;
 877         ne->exi_root->exi_export.ex_pathlen = 1;  /* length of "/" */
 878         ne->exi_root->exi_export.ex_path =
 879             kmem_alloc(ne->exi_root->exi_export.ex_pathlen + 1, KM_SLEEP);
 880         ne->exi_root->exi_export.ex_path[0] = '/';
 881         ne->exi_root->exi_export.ex_path[1] = '\0';
 882 
 883         ne->exi_root->exi_count = 1;
 884         mutex_init(&ne->exi_root->exi_lock, NULL, MUTEX_DEFAULT, NULL);
 885 
 886         ne->exi_root->exi_zone = zone_find_by_id_nolock(zoneid);
 887         ne->exi_root->exi_vp = ne->exi_root->exi_zone->zone_rootvp;
 888         ne->exi_rootfid.fid_len = MAXFIDSZ;
 889         if (vop_fid_pseudo(ne->exi_root->exi_vp, &ne->exi_rootfid) != 0) {
 890                 mutex_destroy(&ne->exi_root->exi_lock);
 891                 kmem_free(ne->exi_root->exi_export.ex_path,
 892                     ne->exi_root->exi_export.ex_pathlen + 1);
 893                 kmem_free(ne->exi_root, sizeof (*ne->exi_root));
 894                 return (NULL);
 895         }
 896 
 897         /* Initialize auth cache and auth cache lock */
 898         for (i = 0; i < AUTH_TABLESIZE; i++) {
 899                 ne->exi_root->exi_cache[i] = kmem_alloc(sizeof (avl_tree_t),
 900                     KM_SLEEP);
 901                 avl_create(ne->exi_root->exi_cache[i],
 902                     nfsauth_cache_clnt_compar, sizeof (struct auth_cache_clnt),
 903                     offsetof(struct auth_cache_clnt, authc_link));
 904         }
 905         rw_init(&ne->exi_root->exi_cache_lock, NULL, RW_DEFAULT, NULL);
 906 
 907         /* Setup the fhandle template */
 908         ne->exi_root->exi_fh.fh_fsid = rootdir->v_vfsp->vfs_fsid;
 909         ne->exi_root->exi_fh.fh_xlen = ne->exi_rootfid.fid_len;
 910         bcopy(ne->exi_rootfid.fid_data, ne->exi_root->exi_fh.fh_xdata,
 911             ne->exi_rootfid.fid_len);
 912         ne->exi_root->exi_fh.fh_len = sizeof (ne->exi_root->exi_fh.fh_data);
 913 
 914         rw_enter(&ne->exported_lock, RW_WRITER);
 915 
 916         /* Publish the exportinfo in the hash table */
 917         export_link(ne, ne->exi_root);
 918 
 919         /* Initialize exi_id and exi_kstats */
 920         mutex_enter(&nfs_exi_id_lock);
 921         ne->exi_root->exi_id = exi_id_get_next();
 922         avl_add(&exi_id_tree, ne->exi_root);
 923         mutex_exit(&nfs_exi_id_lock);
 924 
 925         rw_exit(&ne->exported_lock);
 926         ne->ns_root = NULL;
 927 
 928         return (ne);
 929 }
 930 
 931 /*ARGSUSED*/
 932 static void
 933 nfs_export_zone_fini(zoneid_t zoneid, void *data)
 934 {
 935         int i;
 936         nfs_export_t *ne = data;
 937         struct exportinfo *exi;
 938 
 939         rw_enter(&ne->exported_lock, RW_WRITER);
 940         mutex_enter(&nfs_exi_id_lock);
 941 
 942         avl_remove(&exi_id_tree, ne->exi_root);
 943         export_unlink(ne, ne->exi_root);
 944 
 945         mutex_exit(&nfs_exi_id_lock);
 946         rw_exit(&ne->exported_lock);
 947 
 948         /* Deallocate the place holder for the public file handle */
 949         srv_secinfo_list_free(ne->exi_root->exi_export.ex_secinfo,
 950             ne->exi_root->exi_export.ex_seccnt);
 951         mutex_destroy(&ne->exi_root->exi_lock);
 952 
 953         rw_destroy(&ne->exi_root->exi_cache_lock);
 954         for (i = 0; i < AUTH_TABLESIZE; i++) {
 955                 avl_destroy(ne->exi_root->exi_cache[i]);
 956                 kmem_free(ne->exi_root->exi_cache[i], sizeof (avl_tree_t));
 957         }
 958 
 959         kmem_free(ne->exi_root->exi_export.ex_path,
 960             ne->exi_root->exi_export.ex_pathlen + 1);
 961         kmem_free(ne->exi_root, sizeof (*ne->exi_root));
 962 
 963         exi = avl_first(&exi_id_tree);
 964         while (exi != NULL) {
 965                 struct exportinfo *nexi = AVL_NEXT(&exi_id_tree, exi);
 966                 if (zoneid == exi->exi_zoneid)
 967                         (void) unexport(ne, exi);
 968                 exi = nexi;
 969         }
 970 
 971         rw_destroy(&ne->exported_lock);
 972         kmem_free(ne, sizeof (*ne));
 973 }
 974 
 975 /*
 976  * Initialization routine for export routines.
 977  * Should only be called once.
 978  */
 979 void
 980 nfs_exportinit(void)
 981 {
 982         mutex_init(&nfs_exi_id_lock, NULL, MUTEX_DEFAULT, NULL);
 983 
 984         /* exi_id handling initialization */
 985         exi_id_next = 0;
 986         exi_id_overflow = FALSE;
 987         avl_create(&exi_id_tree, exi_id_compar, sizeof (struct exportinfo),
 988             offsetof(struct exportinfo, exi_id_link));
 989 
 990         zone_key_create(&nfs_export_key, nfs_export_zone_init,
 991             NULL, nfs_export_zone_fini);
 992 
 993         nfslog_init();
 994 }
 995 
 996 /*
 997  * Finalization routine for export routines.
 998  */
 999 void
1000 nfs_exportfini(void)
1001 {
1002         (void) zone_key_delete(nfs_export_key);
1003         avl_destroy(&exi_id_tree);
1004         mutex_destroy(&nfs_exi_id_lock);
1005 }
1006 
1007 /*
1008  *  Check if 2 gss mechanism identifiers are the same.
1009  *
1010  *  return FALSE if not the same.
1011  *  return TRUE if the same.
1012  */
1013 static bool_t
1014 nfs_mech_equal(rpc_gss_OID mech1, rpc_gss_OID mech2)
1015 {
1016         if ((mech1->length == 0) && (mech2->length == 0))
1017                 return (TRUE);
1018 
1019         if (mech1->length != mech2->length)
1020                 return (FALSE);
1021 
1022         return (bcmp(mech1->elements, mech2->elements, mech1->length) == 0);
 
1826 
1827                 /* interconnect the existing treenode with the new exportinfo */
1828                 newexi->exi_zone = exi->exi_zone;
1829                 newexi->exi_tree = exi->exi_tree;
1830                 newexi->exi_tree->tree_exi = newexi;
1831 
1832                 /* Update the change timestamp */
1833                 tree_update_change(ne, exi->exi_tree, NULL);
1834         } else {
1835                 treeclimb_unexport(ne, exi);
1836         }
1837 
1838         rw_exit(&ne->exported_lock);
1839 
1840         /*
1841          * Need to call into the NFSv4 server and release all data
1842          * held on this particular export.  This is important since
1843          * the v4 server may be holding file locks or vnodes under
1844          * this export.
1845          */
1846         rfs4_clean_state_exi(exi);
1847 
1848         /*
1849          * Notify the lock manager that the filesystem is being
1850          * unexported.
1851          */
1852         lm_unexport(exi);
1853 
1854         /*
1855          * If this was a public export, restore
1856          * the public filehandle to the root.
1857          */
1858 
1859         /*
1860          * XXX KEBE ASKS --> Should CRED() instead be
1861          * exi->exi_zone->zone_kcred?
1862          */
1863         if (exi == ne->exi_public) {
1864                 ne->exi_public = ne->exi_root;
1865 
1866                 nfslog_share_record(ne->exi_public, CRED());
 
 | 
 
 
  51 #include <sys/cmn_err.h>
  52 #include <sys/acl.h>
  53 #include <sys/utsname.h>
  54 #include <sys/sdt.h>
  55 #include <netinet/in.h>
  56 #include <sys/avl.h>
  57 
  58 #include <rpc/types.h>
  59 #include <rpc/auth.h>
  60 #include <rpc/svc.h>
  61 
  62 #include <nfs/nfs.h>
  63 #include <nfs/export.h>
  64 #include <nfs/nfssys.h>
  65 #include <nfs/nfs_clnt.h>
  66 #include <nfs/nfs_acl.h>
  67 #include <nfs/nfs_log.h>
  68 #include <nfs/lm.h>
  69 #include <sys/sunddi.h>
  70 
  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;
  87 
  88 static int      unexport(nfs_export_t *, exportinfo_t *);
  89 static void     exportfree(exportinfo_t *);
  90 static int      loadindex(exportdata_t *);
 
 
 103 static struct ex_vol_rename *find_volrnm_fh(exportinfo_t *, nfs_fh4 *);
 104 static uint32_t find_volrnm_fh_id(exportinfo_t *, nfs_fh4 *);
 105 static void     free_volrnm_list(exportinfo_t *);
 106 #endif /* VOLATILE_FH_TEST */
 107 
 108 fhandle_t nullfh2;      /* for comparing V2 filehandles */
 109 
 110 /*
 111  * macro for static dtrace probes to trace server namespace ref count mods.
 112  */
 113 #define SECREF_TRACE(seclist, tag, flav, aftcnt) \
 114         DTRACE_PROBE4(nfss__i__nmspc__secref, struct secinfo *, (seclist), \
 115                 char *, (tag), int, (int)(flav), int, (int)(aftcnt))
 116 
 117 
 118 #define exptablehash(fsid, fid) (nfs_fhhash((fsid), (fid)) & (EXPTABLESIZE - 1))
 119 
 120 extern nfs_export_t *
 121 nfs_get_export(void)
 122 {
 123         nfs_globals_t *ng = zone_getspecific(nfssrv_zone_key, curzone);
 124         nfs_export_t *ne = ng->nfs_export;
 125         ASSERT(ne != NULL);
 126         return (ne);
 127 }
 128 
 129 static uint8_t
 130 xor_hash(uint8_t *data, int len)
 131 {
 132         uint8_t h = 0;
 133 
 134         while (len--)
 135                 h ^= *data++;
 136 
 137         return (h);
 138 }
 139 
 140 /*
 141  * File handle hash function, XOR over all bytes in fsid and fid.
 142  */
 143 static unsigned
 144 nfs_fhhash(fsid_t *fsid, fid_t *fid)
 145 {
 146         int len;
 
 706                 if (TREE_ROOT(tnode)) {
 707                         ASSERT3P(zone, ==, tnode->tree_exi->exi_zone);
 708                         exi_ret = tnode->tree_exi;
 709                         break;
 710                 }
 711         }
 712 
 713         ASSERT(exi_ret); /* Every visible should have its home exportinfo */
 714         return (exi_ret);
 715 }
 716 
 717 /*
 718  * For NFS V4.
 719  * Add or remove the newly exported or unexported security flavors of the
 720  * given exportinfo from its ancestors upto the system root.
 721  */
 722 void
 723 srv_secinfo_treeclimb(nfs_export_t *ne, exportinfo_t *exip, secinfo_t *sec,
 724     int seccnt, bool_t isadd)
 725 {
 726         treenode_t *tnode;
 727 
 728         ASSERT(RW_WRITE_HELD(&ne->exported_lock));
 729 
 730         /*
 731          * exi_tree can be null for the zone root
 732          * which means we're already at the "top"
 733          * and there's nothing more to "climb".
 734          */
 735         tnode = exip->exi_tree;
 736         if (tnode == NULL) {
 737                 /* Should only happen for... */
 738                 ASSERT(exip == ne->exi_root);
 739                 return;
 740         }
 741 
 742         if (seccnt == 0)
 743                 return;
 744 
 745         /*
 746          * If flavors are being added and the new export root isn't
 747          * also VROOT, its implicitly allowed flavors are inherited from
 748          * its pseudonode.
 749          * Note - for VROOT exports the implicitly allowed flavors were
 750          * transferred from the PSEUDO export in exportfs()
 751          */
 752         if (isadd && !(exip->exi_vp->v_flag & VROOT) &&
 753             !VN_IS_CURZONEROOT(exip->exi_vp) &&
 754             tnode->tree_vis->vis_seccnt > 0) {
 755                 srv_secinfo_add(&exip->exi_export.ex_secinfo,
 756                     &exip->exi_export.ex_seccnt, tnode->tree_vis->vis_secinfo,
 757                     tnode->tree_vis->vis_seccnt, FALSE);
 758         }
 759 
 760         /*
 761          * Move to parent node and propagate sec flavor
 
 799         if ((exi)->hash_name.prev) \
 800                 (exi)->hash_name.prev->hash_name.next = (exi)->hash_name.next; \
 801         if ((exi)->hash_name.next) \
 802                 (exi)->hash_name.next->hash_name.prev = (exi)->hash_name.prev; \
 803         (exi)->hash_name.bckt = NULL;
 804 
 805 #define exp_hash_link(exi, hash_name, bucket) \
 806         (exi)->hash_name.bckt = (bucket); \
 807         (exi)->hash_name.prev = NULL; \
 808         (exi)->hash_name.next = *(bucket); \
 809         if ((exi)->hash_name.next) \
 810                 (exi)->hash_name.next->hash_name.prev = (exi); \
 811         *(bucket) = (exi);
 812 
 813 void
 814 export_link(nfs_export_t *ne, exportinfo_t *exi)
 815 {
 816         exportinfo_t **bckt;
 817 
 818         ASSERT(RW_WRITE_HELD(&ne->exported_lock));
 819         ASSERT(exi->exi_zoneid == ne->ne_globals->nfs_zoneid);
 820 
 821         bckt = &ne->exptable[exptablehash(&exi->exi_fsid, &exi->exi_fid)];
 822         exp_hash_link(exi, fid_hash, bckt);
 823 
 824         bckt = &ne->exptable_path_hash[pkp_tab_hash(exi->exi_export.ex_path,
 825             strlen(exi->exi_export.ex_path))];
 826         exp_hash_link(exi, path_hash, bckt);
 827 }
 828 
 829 /*
 830  * Helper functions for exi_id handling
 831  */
 832 static int
 833 exi_id_compar(const void *v1, const void *v2)
 834 {
 835         const struct exportinfo *e1 = v1;
 836         const struct exportinfo *e2 = v2;
 837 
 838         if (e1->exi_id < e2->exi_id)
 839                 return (-1);
 
 851 
 852         ASSERT(MUTEX_HELD(&nfs_exi_id_lock));
 853 
 854         do {
 855                 exi_id_next++;
 856                 if (exi_id_next == 0)
 857                         exi_id_overflow = TRUE;
 858 
 859                 if (!exi_id_overflow)
 860                         break;
 861 
 862                 if (exi_id_next == ret)
 863                         cmn_err(CE_PANIC, "exi_id exhausted");
 864 
 865                 e.exi_id = exi_id_next;
 866         } while (avl_find(&exi_id_tree, &e, NULL) != NULL);
 867 
 868         return (ret);
 869 }
 870 
 871 /*
 872  * Get the root file handle for this zone.
 873  * Called when nfs_svc() starts
 874  */
 875 int
 876 nfs_export_get_rootfh(nfs_globals_t *g)
 877 {
 878         nfs_export_t *ne = g->nfs_export;
 879         int err;
 880 
 881         ne->exi_rootfid.fid_len = MAXFIDSZ;
 882         err = vop_fid_pseudo(ne->exi_root->exi_vp, &ne->exi_rootfid);
 883         if (err != 0) {
 884                 ne->exi_rootfid.fid_len = 0;
 885                 return (err);
 886         }
 887 
 888         /* Setup the fhandle template exi_fh */
 889         ne->exi_root->exi_fh.fh_fsid = rootdir->v_vfsp->vfs_fsid;
 890         ne->exi_root->exi_fh.fh_xlen = ne->exi_rootfid.fid_len;
 891         bcopy(ne->exi_rootfid.fid_data, ne->exi_root->exi_fh.fh_xdata,
 892             ne->exi_rootfid.fid_len);
 893         ne->exi_root->exi_fh.fh_len = sizeof (ne->exi_root->exi_fh.fh_data);
 894 
 895         return (0);
 896 }
 897 
 898 void
 899 nfs_export_zone_init(nfs_globals_t *ng)
 900 {
 901         int i;
 902         nfs_export_t *ne;
 903 
 904         ne = kmem_zalloc(sizeof (*ne), KM_SLEEP);
 905 
 906         rw_init(&ne->exported_lock, NULL, RW_DEFAULT, NULL);
 907 
 908         ne->ne_globals = ng; /* "up" pointer */
 909 
 910         /*
 911          * Allocate the place holder for the public file handle, which
 912          * is all zeroes. It is initially set to the root filesystem.
 913          */
 914         ne->exi_root = kmem_zalloc(sizeof (*ne->exi_root), KM_SLEEP);
 915         ne->exi_public = ne->exi_root;
 916 
 917         ne->exi_root->exi_export.ex_flags = EX_PUBLIC;
 918         ne->exi_root->exi_export.ex_pathlen = 1;  /* length of "/" */
 919         ne->exi_root->exi_export.ex_path =
 920             kmem_alloc(ne->exi_root->exi_export.ex_pathlen + 1, KM_SLEEP);
 921         ne->exi_root->exi_export.ex_path[0] = '/';
 922         ne->exi_root->exi_export.ex_path[1] = '\0';
 923 
 924         ne->exi_root->exi_count = 1;
 925         mutex_init(&ne->exi_root->exi_lock, NULL, MUTEX_DEFAULT, NULL);
 926 
 927         ASSERT(curzone->zone_id == ng->nfs_zoneid);
 928         ne->exi_root->exi_vp = ZONE_ROOTVP();
 929         ne->exi_root->exi_zoneid = ng->nfs_zoneid;
 930 
 931         /*
 932          * Fill in ne->exi_rootfid later, in nfs_export_get_rootfid
 933          * because we can't correctly return errors here.
 934          */
 935 
 936         /* Initialize auth cache and auth cache lock */
 937         for (i = 0; i < AUTH_TABLESIZE; i++) {
 938                 ne->exi_root->exi_cache[i] = kmem_alloc(sizeof (avl_tree_t),
 939                     KM_SLEEP);
 940                 avl_create(ne->exi_root->exi_cache[i],
 941                     nfsauth_cache_clnt_compar, sizeof (struct auth_cache_clnt),
 942                     offsetof(struct auth_cache_clnt, authc_link));
 943         }
 944         rw_init(&ne->exi_root->exi_cache_lock, NULL, RW_DEFAULT, NULL);
 945 
 946         /* setup exi_fh later, in nfs_export_get_rootfid */
 947 
 948         rw_enter(&ne->exported_lock, RW_WRITER);
 949 
 950         /* Publish the exportinfo in the hash table */
 951         export_link(ne, ne->exi_root);
 952 
 953         /* Initialize exi_id and exi_kstats */
 954         mutex_enter(&nfs_exi_id_lock);
 955         ne->exi_root->exi_id = exi_id_get_next();
 956         avl_add(&exi_id_tree, ne->exi_root);
 957         mutex_exit(&nfs_exi_id_lock);
 958 
 959         rw_exit(&ne->exported_lock);
 960         ne->ns_root = NULL;
 961 
 962         ng->nfs_export = ne;
 963 }
 964 
 965 /*
 966  * During zone shutdown, remove exports
 967  */
 968 void
 969 nfs_export_zone_shutdown(nfs_globals_t *ng)
 970 {
 971         nfs_export_t *ne = ng->nfs_export;
 972         struct exportinfo *exi, *nexi;
 973         int i, errors;
 974 
 975         rw_enter(&ne->exported_lock, RW_READER);
 976 
 977         errors = 0;
 978         for (i = 0; i < EXPTABLESIZE; i++) {
 979 
 980                 exi = ne->exptable[i];
 981                 if (exi != NULL)
 982                         exi_hold(exi);
 983 
 984                 while (exi != NULL) {
 985 
 986                         /*
 987                          * Get and hold next export before
 988                          * dropping the rwlock and unexport
 989                          */
 990                         nexi = exi->fid_hash.next;
 991                         if (nexi != NULL)
 992                                 exi_hold(nexi);
 993 
 994                         rw_exit(&ne->exported_lock);
 995 
 996                         /*
 997                          * Skip ne->exi_root which gets special
 998                          * create/destroy handling.
 999                          */
1000                         if (exi != ne->exi_root &&
1001                             unexport(ne, exi) != 0)
1002                                 errors++;
1003                         exi_rele(exi);
1004 
1005                         rw_enter(&ne->exported_lock, RW_READER);
1006                         exi = nexi;
1007                 }
1008         }
1009         if (errors > 0) {
1010                 cmn_err(CE_NOTE,
1011                     "NFS: failed un-exports in zone %d",
1012                     (int) ng->nfs_zoneid);
1013         }
1014 
1015         rw_exit(&ne->exported_lock);
1016 }
1017 
1018 void
1019 nfs_export_zone_fini(nfs_globals_t *ng)
1020 {
1021         int i;
1022         nfs_export_t *ne = ng->nfs_export;
1023         struct exportinfo *exi;
1024 
1025         ng->nfs_export = NULL;
1026 
1027         rw_enter(&ne->exported_lock, RW_WRITER);
1028 
1029         mutex_enter(&nfs_exi_id_lock);
1030         avl_remove(&exi_id_tree, ne->exi_root);
1031         mutex_exit(&nfs_exi_id_lock);
1032 
1033         export_unlink(ne, ne->exi_root);
1034 
1035         rw_exit(&ne->exported_lock);
1036 
1037         /* Deallocate the place holder for the public file handle */
1038         srv_secinfo_list_free(ne->exi_root->exi_export.ex_secinfo,
1039             ne->exi_root->exi_export.ex_seccnt);
1040         mutex_destroy(&ne->exi_root->exi_lock);
1041 
1042         rw_destroy(&ne->exi_root->exi_cache_lock);
1043         for (i = 0; i < AUTH_TABLESIZE; i++) {
1044                 avl_destroy(ne->exi_root->exi_cache[i]);
1045                 kmem_free(ne->exi_root->exi_cache[i], sizeof (avl_tree_t));
1046         }
1047 
1048         kmem_free(ne->exi_root->exi_export.ex_path,
1049             ne->exi_root->exi_export.ex_pathlen + 1);
1050         kmem_free(ne->exi_root, sizeof (*ne->exi_root));
1051 
1052         /*
1053          * The shutdown hook should have left the exi_id_tree
1054          * with nothing belonging to this zone.
1055          */
1056         mutex_enter(&nfs_exi_id_lock);
1057         i = 0;
1058         exi = avl_first(&exi_id_tree);
1059         while (exi != NULL) {
1060                 if (exi->exi_zoneid == ng->nfs_zoneid)
1061                         i++;
1062                 exi = AVL_NEXT(&exi_id_tree, exi);
1063         }
1064         mutex_exit(&nfs_exi_id_lock);
1065         if (i > 0) {
1066                 cmn_err(CE_NOTE,
1067                     "NFS: zone %d has %d export IDs left after shutdown",
1068                     (int) ng->nfs_zoneid, i);
1069         }
1070         rw_destroy(&ne->exported_lock);
1071         kmem_free(ne, sizeof (*ne));
1072 }
1073 
1074 /*
1075  * Initialization routine for export routines.
1076  * Should only be called once.
1077  */
1078 void
1079 nfs_exportinit(void)
1080 {
1081         mutex_init(&nfs_exi_id_lock, NULL, MUTEX_DEFAULT, NULL);
1082 
1083         /* exi_id handling initialization */
1084         exi_id_next = 0;
1085         exi_id_overflow = FALSE;
1086         avl_create(&exi_id_tree, exi_id_compar, sizeof (struct exportinfo),
1087             offsetof(struct exportinfo, exi_id_link));
1088 
1089         nfslog_init();
1090 }
1091 
1092 /*
1093  * Finalization routine for export routines.
1094  */
1095 void
1096 nfs_exportfini(void)
1097 {
1098         avl_destroy(&exi_id_tree);
1099         mutex_destroy(&nfs_exi_id_lock);
1100 }
1101 
1102 /*
1103  *  Check if 2 gss mechanism identifiers are the same.
1104  *
1105  *  return FALSE if not the same.
1106  *  return TRUE if the same.
1107  */
1108 static bool_t
1109 nfs_mech_equal(rpc_gss_OID mech1, rpc_gss_OID mech2)
1110 {
1111         if ((mech1->length == 0) && (mech2->length == 0))
1112                 return (TRUE);
1113 
1114         if (mech1->length != mech2->length)
1115                 return (FALSE);
1116 
1117         return (bcmp(mech1->elements, mech2->elements, mech1->length) == 0);
 
1921 
1922                 /* interconnect the existing treenode with the new exportinfo */
1923                 newexi->exi_zone = exi->exi_zone;
1924                 newexi->exi_tree = exi->exi_tree;
1925                 newexi->exi_tree->tree_exi = newexi;
1926 
1927                 /* Update the change timestamp */
1928                 tree_update_change(ne, exi->exi_tree, NULL);
1929         } else {
1930                 treeclimb_unexport(ne, exi);
1931         }
1932 
1933         rw_exit(&ne->exported_lock);
1934 
1935         /*
1936          * Need to call into the NFSv4 server and release all data
1937          * held on this particular export.  This is important since
1938          * the v4 server may be holding file locks or vnodes under
1939          * this export.
1940          */
1941         rfs4_clean_state_exi(ne, exi);
1942 
1943         /*
1944          * Notify the lock manager that the filesystem is being
1945          * unexported.
1946          */
1947         lm_unexport(exi);
1948 
1949         /*
1950          * If this was a public export, restore
1951          * the public filehandle to the root.
1952          */
1953 
1954         /*
1955          * XXX KEBE ASKS --> Should CRED() instead be
1956          * exi->exi_zone->zone_kcred?
1957          */
1958         if (exi == ne->exi_public) {
1959                 ne->exi_public = ne->exi_root;
1960 
1961                 nfslog_share_record(ne->exi_public, CRED());
 
 |