702 #ifdef DEBUG
703 if (zone == NULL && tnode->tree_exi != NULL)
704 zone = tnode->tree_exi->exi_zone;
705 #endif
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.
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);
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
1903 /*
1904 * Remove security flavors before treeclimb_unexport() is called
1905 * because srv_secinfo_treeclimb needs the namespace tree
1906 */
1907 curcnt = build_seclist_nodups(&exi->exi_export, cursec, TRUE);
1908 srv_secinfo_treeclimb(ne, exi, cursec, curcnt, FALSE);
1909
1910 /*
1911 * If there's a visible list, then need to leave
1912 * a pseudo export here to retain the visible list
1913 * for paths to exports below.
1914 */
1915 if (exi->exi_visible != NULL) {
1916 struct exportinfo *newexi;
1917
1918 newexi = pseudo_exportfs(ne, exi->exi_vp, &exi->exi_fid,
1919 exi->exi_visible, &exi->exi_export);
1920 exi->exi_visible = NULL;
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 /*
2172 break;
2173 }
2174
2175 if (v4srv)
2176 exi = checkexport4(&vp->v_vfsp->vfs_fsid, &fid, vp);
2177 else
2178 exi = checkexport(&vp->v_vfsp->vfs_fsid, &fid);
2179
2180 if (exi != NULL) {
2181 /*
2182 * Found the export info
2183 */
2184 break;
2185 }
2186
2187 /*
2188 * We have just failed finding a matching export.
2189 * If we're at the root of this filesystem, then
2190 * it's time to stop (with failure).
2191 */
2192 if ((vp->v_flag & VROOT) || VN_IS_CURZONEROOT(vp)) {
2193 error = EINVAL;
2194 break;
2195 }
2196
2197 if (walk != NULL)
2198 (*walk)++;
2199
2200 /*
2201 * Now, do a ".." up vp. If dvp is supplied, use it,
2202 * otherwise, look it up.
2203 */
2204 if (dvp == NULL) {
2205 error = VOP_LOOKUP(vp, "..", &dvp, NULL, 0, NULL, cr,
2206 NULL, NULL, NULL);
2207 if (error)
2208 break;
2209 }
2210 VN_RELE(vp);
2211 vp = dvp;
|
702 #ifdef DEBUG
703 if (zone == NULL && tnode->tree_exi != NULL)
704 zone = tnode->tree_exi->exi_zone;
705 #endif
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 static 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 ASSERT3U(exip->exi_zoneid, ==, curzone->zone_id);
730
731 /*
732 * exi_tree can be null for the zone root
733 * which means we're already at the "top"
734 * and there's nothing more to "climb".
735 */
736 tnode = exip->exi_tree;
737 if (tnode == NULL) {
738 /* Should only happen for... */
739 ASSERT(exip == ne->exi_root);
740 return;
741 }
742
743 if (seccnt == 0)
744 return;
745
746 /*
747 * If flavors are being added and the new export root isn't
748 * also VROOT, its implicitly allowed flavors are inherited from
749 * its pseudonode.
800 if ((exi)->hash_name.prev) \
801 (exi)->hash_name.prev->hash_name.next = (exi)->hash_name.next; \
802 if ((exi)->hash_name.next) \
803 (exi)->hash_name.next->hash_name.prev = (exi)->hash_name.prev; \
804 (exi)->hash_name.bckt = NULL;
805
806 #define exp_hash_link(exi, hash_name, bucket) \
807 (exi)->hash_name.bckt = (bucket); \
808 (exi)->hash_name.prev = NULL; \
809 (exi)->hash_name.next = *(bucket); \
810 if ((exi)->hash_name.next) \
811 (exi)->hash_name.next->hash_name.prev = (exi); \
812 *(bucket) = (exi);
813
814 void
815 export_link(nfs_export_t *ne, exportinfo_t *exi)
816 {
817 exportinfo_t **bckt;
818
819 ASSERT(RW_WRITE_HELD(&ne->exported_lock));
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);
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 zone_t *zone;
904
905 ne = kmem_zalloc(sizeof (*ne), KM_SLEEP);
906
907 rw_init(&ne->exported_lock, NULL, RW_DEFAULT, NULL);
908
909 ne->ne_globals = ng; /* "up" pointer */
910
911 /*
912 * Allocate the place holder for the public file handle, which
913 * is all zeroes. It is initially set to the root filesystem.
914 */
915 ne->exi_root = kmem_zalloc(sizeof (*ne->exi_root), KM_SLEEP);
916 ne->exi_public = ne->exi_root;
917
918 ne->exi_root->exi_export.ex_flags = EX_PUBLIC;
919 ne->exi_root->exi_export.ex_pathlen = 1; /* length of "/" */
920 ne->exi_root->exi_export.ex_path =
921 kmem_alloc(ne->exi_root->exi_export.ex_pathlen + 1, KM_SLEEP);
922 ne->exi_root->exi_export.ex_path[0] = '/';
923 ne->exi_root->exi_export.ex_path[1] = '\0';
924
925 ne->exi_root->exi_count = 1;
926 mutex_init(&ne->exi_root->exi_lock, NULL, MUTEX_DEFAULT, NULL);
927
928 /*
929 * Because we cannot:
930 * ASSERT(curzone->zone_id == ng->nfs_zoneid);
931 * We grab the zone pointer explicitly (like netstacks do) and
932 * set the rootvp here.
933 */
934 zone = zone_find_by_id_nolock(ng->nfs_zoneid);
935 ne->exi_root->exi_vp = zone->zone_rootvp;
936 ne->exi_root->exi_zone = zone; /* XXX KEBE SAYS lose me, and... */
937 /* ne->exi_root->exi_zoneid = ng->nfs_zoneid; */ /* use me instead! */
938
939 /*
940 * Fill in ne->exi_rootfid later, in nfs_export_get_rootfid
941 * because we can't correctly return errors here.
942 */
943
944 /* Initialize auth cache and auth cache lock */
945 for (i = 0; i < AUTH_TABLESIZE; i++) {
946 ne->exi_root->exi_cache[i] = kmem_alloc(sizeof (avl_tree_t),
947 KM_SLEEP);
948 avl_create(ne->exi_root->exi_cache[i],
949 nfsauth_cache_clnt_compar, sizeof (struct auth_cache_clnt),
950 offsetof(struct auth_cache_clnt, authc_link));
951 }
952 rw_init(&ne->exi_root->exi_cache_lock, NULL, RW_DEFAULT, NULL);
953
954 /* setup exi_fh later, in nfs_export_get_rootfid */
955
956 rw_enter(&ne->exported_lock, RW_WRITER);
957
1911 /*
1912 * Remove security flavors before treeclimb_unexport() is called
1913 * because srv_secinfo_treeclimb needs the namespace tree
1914 */
1915 curcnt = build_seclist_nodups(&exi->exi_export, cursec, TRUE);
1916 srv_secinfo_treeclimb(ne, exi, cursec, curcnt, FALSE);
1917
1918 /*
1919 * If there's a visible list, then need to leave
1920 * a pseudo export here to retain the visible list
1921 * for paths to exports below.
1922 */
1923 if (exi->exi_visible != NULL) {
1924 struct exportinfo *newexi;
1925
1926 newexi = pseudo_exportfs(ne, exi->exi_vp, &exi->exi_fid,
1927 exi->exi_visible, &exi->exi_export);
1928 exi->exi_visible = NULL;
1929
1930 /* interconnect the existing treenode with the new exportinfo */
1931 newexi->exi_zone = exi->exi_zone; /* XXX KEBE SAYS LOSE ME */
1932 newexi->exi_tree = exi->exi_tree;
1933 newexi->exi_tree->tree_exi = newexi;
1934
1935 /* Update the change timestamp */
1936 tree_update_change(ne, exi->exi_tree, NULL);
1937 } else {
1938 treeclimb_unexport(ne, exi);
1939 }
1940
1941 rw_exit(&ne->exported_lock);
1942
1943 /*
1944 * Need to call into the NFSv4 server and release all data
1945 * held on this particular export. This is important since
1946 * the v4 server may be holding file locks or vnodes under
1947 * this export.
1948 */
1949 rfs4_clean_state_exi(ne, exi);
1950
1951 /*
2180 break;
2181 }
2182
2183 if (v4srv)
2184 exi = checkexport4(&vp->v_vfsp->vfs_fsid, &fid, vp);
2185 else
2186 exi = checkexport(&vp->v_vfsp->vfs_fsid, &fid);
2187
2188 if (exi != NULL) {
2189 /*
2190 * Found the export info
2191 */
2192 break;
2193 }
2194
2195 /*
2196 * We have just failed finding a matching export.
2197 * If we're at the root of this filesystem, then
2198 * it's time to stop (with failure).
2199 */
2200 ASSERT3P(vp->v_vfsp->vfs_zone, ==, curzone);
2201 if ((vp->v_flag & VROOT) || VN_IS_CURZONEROOT(vp)) {
2202 error = EINVAL;
2203 break;
2204 }
2205
2206 if (walk != NULL)
2207 (*walk)++;
2208
2209 /*
2210 * Now, do a ".." up vp. If dvp is supplied, use it,
2211 * otherwise, look it up.
2212 */
2213 if (dvp == NULL) {
2214 error = VOP_LOOKUP(vp, "..", &dvp, NULL, 0, NULL, cr,
2215 NULL, NULL, NULL);
2216 if (error)
2217 break;
2218 }
2219 VN_RELE(vp);
2220 vp = dvp;
|