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());
|