149 pseudo_exportfs(nfs_export_t *ne, vnode_t *vp, fid_t *fid,
150 struct exp_visible *vis_head, struct exportdata *exdata)
151 {
152 struct exportinfo *exi;
153 struct exportdata *kex;
154 fsid_t fsid;
155 int vpathlen;
156 int i;
157
158 ASSERT(RW_WRITE_HELD(&ne->exported_lock));
159
160 fsid = vp->v_vfsp->vfs_fsid;
161 exi = kmem_zalloc(sizeof (*exi), KM_SLEEP);
162 exi->exi_fsid = fsid;
163 exi->exi_fid = *fid;
164 exi->exi_vp = vp;
165 VN_HOLD(exi->exi_vp);
166 exi->exi_visible = vis_head;
167 exi->exi_count = 1;
168 /* Caller will set exi_zone... */
169 exi->exi_volatile_dev = (vfssw[vp->v_vfsp->vfs_fstype].vsw_flag &
170 VSW_VOLATILEDEV) ? 1 : 0;
171 mutex_init(&exi->exi_lock, NULL, MUTEX_DEFAULT, NULL);
172 exi->exi_zoneid = ne->ne_globals->nfs_zoneid;
173
174 /*
175 * Build up the template fhandle
176 */
177 exi->exi_fh.fh_fsid = fsid;
178 ASSERT(exi->exi_fid.fid_len <= sizeof (exi->exi_fh.fh_xdata));
179 exi->exi_fh.fh_xlen = exi->exi_fid.fid_len;
180 bcopy(exi->exi_fid.fid_data, exi->exi_fh.fh_xdata,
181 exi->exi_fid.fid_len);
182 exi->exi_fh.fh_len = sizeof (exi->exi_fh.fh_data);
183
184 kex = &exi->exi_export;
185 kex->ex_flags = EX_PSEUDO;
186
187 vpathlen = strlen(vp->v_path);
188 kex->ex_pathlen = vpathlen + strlen(PSEUDOFS_SUFFIX);
189 kex->ex_path = kmem_alloc(kex->ex_pathlen + 1, KM_SLEEP);
190
191 if (vpathlen)
192 (void) strncpy(kex->ex_path, vp->v_path, vpathlen);
643 timespec_t now;
644 nfs_export_t *ne = nfs_get_export();
645
646 ASSERT(RW_WRITE_HELD(&ne->exported_lock));
647 ASSERT3P(curzone, ==, exip->exi_zone);
648
649 gethrestime(&now);
650
651 vp = exip->exi_vp;
652 VN_HOLD(vp);
653 exportdir = 1;
654
655 for (;;) {
656
657 bzero(&fid, sizeof (fid));
658 fid.fid_len = MAXFIDSZ;
659 error = vop_fid_pseudo(vp, &fid);
660 if (error)
661 break;
662
663 /*
664 * The root of the file system, or the zone's root for
665 * in-zone NFS service needs special handling
666 */
667 if (vp->v_flag & VROOT || VN_IS_CURZONEROOT(vp)) {
668 if (!exportdir) {
669 struct exportinfo *exi;
670
671 /*
672 * Check if this VROOT dir is already exported.
673 * If so, then attach the pseudonodes. If not,
674 * then continue .. traversal until we hit a
675 * VROOT export (pseudo or real).
676 */
677 exi = checkexport4(&vp->v_vfsp->vfs_fsid, &fid,
678 vp);
679 if (exi != NULL) {
680 /*
681 * Found an export info
682 *
683 * Extend the list of visible
684 * directories whether it's a pseudo
685 * or a real export.
686 */
687 more_visible(exi, tree_head);
688 break; /* and climb no further */
689 }
690
691 /*
692 * Found the root directory of a filesystem
693 * that isn't exported. Need to export
694 * this as a pseudo export so that an NFS v4
695 * client can do lookups in it.
696 */
697 new_exi = pseudo_exportfs(ne, vp, &fid,
698 vis_head, NULL);
699 new_exi->exi_zone = exip->exi_zone;
700 vis_head = NULL;
701 }
702
703 if (VN_IS_CURZONEROOT(vp)) {
704 /* at system root */
705 /*
706 * If sharing "/", new_exi is shared exportinfo
707 * (exip). Otherwise, new_exi is exportinfo
708 * created by pseudo_exportfs() above.
709 */
710 ne->ns_root = tree_prepend_node(tree_head, NULL,
711 new_exi);
712
713 /* Update the change timestamp */
714 tree_update_change(ne, ne->ns_root, &now);
715
716 break;
717 }
718
863 tnode->tree_vis->vis_exported = 0;
864
865 while (tnode != NULL) {
866
867 /*
868 * Stop at VROOT (or zone root) node which is exported or has
869 * child.
870 */
871 if (TREE_ROOT(tnode) &&
872 (TREE_EXPORTED(tnode) || tnode->tree_child_first != NULL))
873 break;
874
875 /* Release pseudo export if it has no child */
876 if (TREE_ROOT(tnode) && !TREE_EXPORTED(tnode) &&
877 tnode->tree_child_first == NULL) {
878 mutex_enter(&nfs_exi_id_lock);
879 avl_remove(&exi_id_tree, tnode->tree_exi);
880 mutex_exit(&nfs_exi_id_lock);
881 export_unlink(ne, tnode->tree_exi);
882 exi_rele(tnode->tree_exi);
883 }
884
885 /* Release visible in parent's exportinfo */
886 if (tnode->tree_vis != NULL)
887 less_visible(vis2exi(tnode), tnode->tree_vis);
888
889 /* Continue with parent */
890 old_nd = tnode;
891 tnode = tnode->tree_parent;
892
893 /* Remove itself, if this is a leaf and non-exported node */
894 if (old_nd->tree_child_first == NULL &&
895 !TREE_EXPORTED(old_nd)) {
896 tree_remove_node(ne, old_nd);
897 connect_point = tnode;
898 }
899 }
900
901 /* Update the change timestamp */
902 if (connect_point != NULL)
903 tree_update_change(ne, connect_point, NULL);
904 }
905
906 /*
907 * Traverse backward across mountpoint from the
908 * root vnode of a filesystem to its mounted-on
909 * vnode.
910 */
911 vnode_t *
912 untraverse(vnode_t *vp)
913 {
914 vnode_t *tvp, *nextvp;
915
916 tvp = vp;
917 for (;;) {
918 if (!(tvp->v_flag & VROOT) && !VN_IS_CURZONEROOT(tvp))
919 break;
920
921 /* lock vfs to prevent unmount of this vfs */
922 vfs_lock_wait(tvp->v_vfsp);
923
924 if ((nextvp = tvp->v_vfsp->vfs_vnodecovered) == NULL) {
925 vfs_unlock(tvp->v_vfsp);
926 break;
927 }
928
929 /*
946
947 /*
948 * Given an exportinfo, climb up to find the exportinfo for the VROOT
949 * (or zone root) of the filesystem.
950 *
951 * e.g. /
952 * |
953 * a (VROOT) pseudo-exportinfo
954 * |
955 * b
956 * |
957 * c #share /a/b/c
958 * |
959 * d
960 *
961 * where c is in the same filesystem as a.
962 * So, get_root_export(*exportinfo_for_c) returns exportinfo_for_a
963 *
964 * If d is shared, then c will be put into a's visible list.
965 * Note: visible list is per filesystem and is attached to the
966 * VROOT exportinfo.
967 */
968 struct exportinfo *
969 get_root_export(struct exportinfo *exip)
970 {
971 treenode_t *tnode = exip->exi_tree;
972 exportinfo_t *exi = NULL;
973
974 while (tnode) {
975 if (TREE_ROOT(tnode)) {
976 exi = tnode->tree_exi;
977 break;
978 }
979 tnode = tnode->tree_parent;
980 }
981 ASSERT(exi);
982 return (exi);
983 }
984
985 /*
986 * Return true if the supplied vnode has a sub-directory exported.
|
149 pseudo_exportfs(nfs_export_t *ne, vnode_t *vp, fid_t *fid,
150 struct exp_visible *vis_head, struct exportdata *exdata)
151 {
152 struct exportinfo *exi;
153 struct exportdata *kex;
154 fsid_t fsid;
155 int vpathlen;
156 int i;
157
158 ASSERT(RW_WRITE_HELD(&ne->exported_lock));
159
160 fsid = vp->v_vfsp->vfs_fsid;
161 exi = kmem_zalloc(sizeof (*exi), KM_SLEEP);
162 exi->exi_fsid = fsid;
163 exi->exi_fid = *fid;
164 exi->exi_vp = vp;
165 VN_HOLD(exi->exi_vp);
166 exi->exi_visible = vis_head;
167 exi->exi_count = 1;
168 /* Caller will set exi_zone... */
169 /* XXX KEBE SAYS Uncomment me or fix in the caller */
170 /* exi->exi_zoneid = ne->ne_globals->nfs_zoneid; */
171 exi->exi_volatile_dev = (vfssw[vp->v_vfsp->vfs_fstype].vsw_flag &
172 VSW_VOLATILEDEV) ? 1 : 0;
173 mutex_init(&exi->exi_lock, NULL, MUTEX_DEFAULT, NULL);
174
175 /*
176 * Build up the template fhandle
177 */
178 exi->exi_fh.fh_fsid = fsid;
179 ASSERT(exi->exi_fid.fid_len <= sizeof (exi->exi_fh.fh_xdata));
180 exi->exi_fh.fh_xlen = exi->exi_fid.fid_len;
181 bcopy(exi->exi_fid.fid_data, exi->exi_fh.fh_xdata,
182 exi->exi_fid.fid_len);
183 exi->exi_fh.fh_len = sizeof (exi->exi_fh.fh_data);
184
185 kex = &exi->exi_export;
186 kex->ex_flags = EX_PSEUDO;
187
188 vpathlen = strlen(vp->v_path);
189 kex->ex_pathlen = vpathlen + strlen(PSEUDOFS_SUFFIX);
190 kex->ex_path = kmem_alloc(kex->ex_pathlen + 1, KM_SLEEP);
191
192 if (vpathlen)
193 (void) strncpy(kex->ex_path, vp->v_path, vpathlen);
644 timespec_t now;
645 nfs_export_t *ne = nfs_get_export();
646
647 ASSERT(RW_WRITE_HELD(&ne->exported_lock));
648 ASSERT3P(curzone, ==, exip->exi_zone);
649
650 gethrestime(&now);
651
652 vp = exip->exi_vp;
653 VN_HOLD(vp);
654 exportdir = 1;
655
656 for (;;) {
657
658 bzero(&fid, sizeof (fid));
659 fid.fid_len = MAXFIDSZ;
660 error = vop_fid_pseudo(vp, &fid);
661 if (error)
662 break;
663
664 ASSERT3U(exip->exi_zoneid, ==, curzone->zone_id);
665 /*
666 * The root of the file system, or the zone's root for
667 * in-zone NFS service needs special handling
668 */
669 if (vp->v_flag & VROOT || VN_IS_CURZONEROOT(vp)) {
670 if (!exportdir) {
671 struct exportinfo *exi;
672
673 /*
674 * Check if this VROOT dir is already exported.
675 * If so, then attach the pseudonodes. If not,
676 * then continue .. traversal until we hit a
677 * VROOT export (pseudo or real).
678 */
679 exi = checkexport4(&vp->v_vfsp->vfs_fsid, &fid,
680 vp);
681 if (exi != NULL) {
682 /*
683 * Found an export info
684 *
685 * Extend the list of visible
686 * directories whether it's a pseudo
687 * or a real export.
688 */
689 more_visible(exi, tree_head);
690 break; /* and climb no further */
691 }
692
693 /*
694 * Found the root directory of a filesystem
695 * that isn't exported. Need to export
696 * this as a pseudo export so that an NFS v4
697 * client can do lookups in it.
698 */
699 new_exi = pseudo_exportfs(ne, vp, &fid,
700 vis_head, NULL);
701 /* XXX KEBE SAYS NUKE ME */
702 new_exi->exi_zone = exip->exi_zone;
703 vis_head = NULL;
704 }
705
706 if (VN_IS_CURZONEROOT(vp)) {
707 /* at system root */
708 /*
709 * If sharing "/", new_exi is shared exportinfo
710 * (exip). Otherwise, new_exi is exportinfo
711 * created by pseudo_exportfs() above.
712 */
713 ne->ns_root = tree_prepend_node(tree_head, NULL,
714 new_exi);
715
716 /* Update the change timestamp */
717 tree_update_change(ne, ne->ns_root, &now);
718
719 break;
720 }
721
866 tnode->tree_vis->vis_exported = 0;
867
868 while (tnode != NULL) {
869
870 /*
871 * Stop at VROOT (or zone root) node which is exported or has
872 * child.
873 */
874 if (TREE_ROOT(tnode) &&
875 (TREE_EXPORTED(tnode) || tnode->tree_child_first != NULL))
876 break;
877
878 /* Release pseudo export if it has no child */
879 if (TREE_ROOT(tnode) && !TREE_EXPORTED(tnode) &&
880 tnode->tree_child_first == NULL) {
881 mutex_enter(&nfs_exi_id_lock);
882 avl_remove(&exi_id_tree, tnode->tree_exi);
883 mutex_exit(&nfs_exi_id_lock);
884 export_unlink(ne, tnode->tree_exi);
885 exi_rele(tnode->tree_exi);
886 tnode->tree_exi = NULL;
887 }
888
889 /* Release visible in parent's exportinfo */
890 if (tnode->tree_vis != NULL)
891 less_visible(vis2exi(tnode), tnode->tree_vis);
892
893 /* Continue with parent */
894 old_nd = tnode;
895 tnode = tnode->tree_parent;
896
897 /* Remove itself, if this is a leaf and non-exported node */
898 if (old_nd->tree_child_first == NULL &&
899 !TREE_EXPORTED(old_nd)) {
900 tree_remove_node(ne, old_nd);
901 connect_point = tnode;
902 }
903 }
904
905 /* Update the change timestamp */
906 if (connect_point != NULL)
907 tree_update_change(ne, connect_point, NULL);
908 }
909
910 /*
911 * Traverse backward across mountpoint from the
912 * root vnode of a filesystem to its mounted-on
913 * vnode.
914 *
915 * Callers to this function have confirmed the use of curzone is safe here.
916 */
917 vnode_t *
918 untraverse(vnode_t *vp)
919 {
920 vnode_t *tvp, *nextvp;
921
922 tvp = vp;
923 for (;;) {
924 if (!(tvp->v_flag & VROOT) && !VN_IS_CURZONEROOT(tvp))
925 break;
926
927 /* lock vfs to prevent unmount of this vfs */
928 vfs_lock_wait(tvp->v_vfsp);
929
930 if ((nextvp = tvp->v_vfsp->vfs_vnodecovered) == NULL) {
931 vfs_unlock(tvp->v_vfsp);
932 break;
933 }
934
935 /*
952
953 /*
954 * Given an exportinfo, climb up to find the exportinfo for the VROOT
955 * (or zone root) of the filesystem.
956 *
957 * e.g. /
958 * |
959 * a (VROOT) pseudo-exportinfo
960 * |
961 * b
962 * |
963 * c #share /a/b/c
964 * |
965 * d
966 *
967 * where c is in the same filesystem as a.
968 * So, get_root_export(*exportinfo_for_c) returns exportinfo_for_a
969 *
970 * If d is shared, then c will be put into a's visible list.
971 * Note: visible list is per filesystem and is attached to the
972 * VROOT exportinfo. Returned exi does NOT have a new hold.
973 */
974 struct exportinfo *
975 get_root_export(struct exportinfo *exip)
976 {
977 treenode_t *tnode = exip->exi_tree;
978 exportinfo_t *exi = NULL;
979
980 while (tnode) {
981 if (TREE_ROOT(tnode)) {
982 exi = tnode->tree_exi;
983 break;
984 }
985 tnode = tnode->tree_parent;
986 }
987 ASSERT(exi);
988 return (exi);
989 }
990
991 /*
992 * Return true if the supplied vnode has a sub-directory exported.
|