148 struct exportinfo *
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);
625 * (d) (e) f m EXPORT,f1(f2) p
626 * EXPORT EXPORT | |
627 * f1 f2 | |
628 * | | |
629 * j (o) EXPORT,f2 q EXPORT f2
630 *
631 */
632 int
633 treeclimb_export(struct exportinfo *exip)
634 {
635 vnode_t *dvp, *vp;
636 fid_t fid;
637 int error;
638 int exportdir;
639 struct exportinfo *new_exi = exip;
640 struct exp_visible *visp;
641 struct exp_visible *vis_head = NULL;
642 struct vattr va;
643 treenode_t *tree_head = NULL;
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
722 /*
825
826 /*
827 * Walk up the tree and:
828 * 1. release pseudo exportinfo if it has no child
829 * 2. release visible in parent's exportinfo
830 * 3. delete non-exported leaf nodes from tree
831 *
832 * Deleting of nodes will start only if the unshared
833 * node was a leaf node.
834 * Deleting of nodes will finish when we reach a node which
835 * has children or is a real export, then we might still need
836 * to continue releasing visibles, until we reach VROOT or zone's root node.
837 */
838 void
839 treeclimb_unexport(nfs_export_t *ne, struct exportinfo *exip)
840 {
841 treenode_t *tnode, *old_nd;
842 treenode_t *connect_point = NULL;
843
844 ASSERT(RW_WRITE_HELD(&ne->exported_lock));
845 ASSERT(curzone == exip->exi_zone || curzone == global_zone);
846
847 /*
848 * exi_tree can be null for the zone root
849 * which means we're already at the "top"
850 * and there's nothing more to "climb".
851 */
852 tnode = exip->exi_tree;
853 if (tnode == NULL) {
854 /* Should only happen for... */
855 ASSERT(exip == ne->exi_root);
856 return;
857 }
858
859 /*
860 * The unshared exportinfo was unlinked in unexport().
861 * Zeroing tree_exi ensures that we will skip it.
862 */
863 tnode->tree_exi = NULL;
864
865 if (tnode->tree_vis != NULL) /* system root has tree_vis == NULL */
988 return (exi);
989 }
990
991 /*
992 * Return true if the supplied vnode has a sub-directory exported.
993 */
994 int
995 has_visible(struct exportinfo *exi, vnode_t *vp)
996 {
997 struct exp_visible *visp;
998 fid_t fid;
999 bool_t vp_is_exported;
1000
1001 vp_is_exported = VN_CMP(vp, exi->exi_vp);
1002
1003 /*
1004 * An exported root vnode has a sub-dir shared if it has a visible
1005 * list. i.e. if it does not have a visible list, then there is no
1006 * node in this filesystem leads to any other shared node.
1007 */
1008 ASSERT3P(curzone, ==, exi->exi_zone);
1009 if (vp_is_exported &&
1010 ((vp->v_flag & VROOT) || VN_IS_CURZONEROOT(vp))) {
1011 return (exi->exi_visible ? 1 : 0);
1012 }
1013
1014 /*
1015 * Only the exportinfo of a fs root node may have a visible list.
1016 * Either it is a pseudo root node, or a real exported root node.
1017 */
1018 exi = get_root_export(exi);
1019
1020 if (!exi->exi_visible)
1021 return (0);
1022
1023 /* Get the fid of the vnode */
1024 bzero(&fid, sizeof (fid));
1025 fid.fid_len = MAXFIDSZ;
1026 if (vop_fid_pseudo(vp, &fid) != 0) {
1027 return (0);
1028 }
|
148 struct exportinfo *
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 exi->exi_zoneid = ne->ne_globals->nfs_zoneid;
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
173 /*
174 * Build up the template fhandle
175 */
176 exi->exi_fh.fh_fsid = fsid;
177 ASSERT(exi->exi_fid.fid_len <= sizeof (exi->exi_fh.fh_xdata));
178 exi->exi_fh.fh_xlen = exi->exi_fid.fid_len;
179 bcopy(exi->exi_fid.fid_data, exi->exi_fh.fh_xdata,
180 exi->exi_fid.fid_len);
181 exi->exi_fh.fh_len = sizeof (exi->exi_fh.fh_data);
182
183 kex = &exi->exi_export;
184 kex->ex_flags = EX_PSEUDO;
185
186 vpathlen = strlen(vp->v_path);
187 kex->ex_pathlen = vpathlen + strlen(PSEUDOFS_SUFFIX);
188 kex->ex_path = kmem_alloc(kex->ex_pathlen + 1, KM_SLEEP);
623 * (d) (e) f m EXPORT,f1(f2) p
624 * EXPORT EXPORT | |
625 * f1 f2 | |
626 * | | |
627 * j (o) EXPORT,f2 q EXPORT f2
628 *
629 */
630 int
631 treeclimb_export(struct exportinfo *exip)
632 {
633 vnode_t *dvp, *vp;
634 fid_t fid;
635 int error;
636 int exportdir;
637 struct exportinfo *new_exi = exip;
638 struct exp_visible *visp;
639 struct exp_visible *vis_head = NULL;
640 struct vattr va;
641 treenode_t *tree_head = NULL;
642 timespec_t now;
643 nfs_export_t *ne;
644
645 ne = exip->exi_ne;
646 ASSERT3P(ne, ==, nfs_get_export()); /* curzone reality check */
647 ASSERT(RW_WRITE_HELD(&ne->exported_lock));
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 /* XXX KEBE ASKS DO WE NEED THIS?!? */
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 || vp == EXI_TO_ZONEROOTVP(exip)) {
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 vis_head = NULL;
702 }
703
704 if (VN_IS_CURZONEROOT(vp)) {
705 /* at system root */
706 /*
707 * If sharing "/", new_exi is shared exportinfo
708 * (exip). Otherwise, new_exi is exportinfo
709 * created by pseudo_exportfs() above.
710 */
711 ne->ns_root = tree_prepend_node(tree_head, NULL,
712 new_exi);
713
714 /* Update the change timestamp */
715 tree_update_change(ne, ne->ns_root, &now);
716
717 break;
718 }
719
720 /*
823
824 /*
825 * Walk up the tree and:
826 * 1. release pseudo exportinfo if it has no child
827 * 2. release visible in parent's exportinfo
828 * 3. delete non-exported leaf nodes from tree
829 *
830 * Deleting of nodes will start only if the unshared
831 * node was a leaf node.
832 * Deleting of nodes will finish when we reach a node which
833 * has children or is a real export, then we might still need
834 * to continue releasing visibles, until we reach VROOT or zone's root node.
835 */
836 void
837 treeclimb_unexport(nfs_export_t *ne, struct exportinfo *exip)
838 {
839 treenode_t *tnode, *old_nd;
840 treenode_t *connect_point = NULL;
841
842 ASSERT(RW_WRITE_HELD(&ne->exported_lock));
843 ASSERT(curzone->zone_id == exip->exi_zoneid ||
844 curzone->zone_id == global_zone->zone_id);
845
846 /*
847 * exi_tree can be null for the zone root
848 * which means we're already at the "top"
849 * and there's nothing more to "climb".
850 */
851 tnode = exip->exi_tree;
852 if (tnode == NULL) {
853 /* Should only happen for... */
854 ASSERT(exip == ne->exi_root);
855 return;
856 }
857
858 /*
859 * The unshared exportinfo was unlinked in unexport().
860 * Zeroing tree_exi ensures that we will skip it.
861 */
862 tnode->tree_exi = NULL;
863
864 if (tnode->tree_vis != NULL) /* system root has tree_vis == NULL */
987 return (exi);
988 }
989
990 /*
991 * Return true if the supplied vnode has a sub-directory exported.
992 */
993 int
994 has_visible(struct exportinfo *exi, vnode_t *vp)
995 {
996 struct exp_visible *visp;
997 fid_t fid;
998 bool_t vp_is_exported;
999
1000 vp_is_exported = VN_CMP(vp, exi->exi_vp);
1001
1002 /*
1003 * An exported root vnode has a sub-dir shared if it has a visible
1004 * list. i.e. if it does not have a visible list, then there is no
1005 * node in this filesystem leads to any other shared node.
1006 */
1007 ASSERT3P(curzone->zone_id, ==, exi->exi_zoneid);
1008 if (vp_is_exported &&
1009 ((vp->v_flag & VROOT) || VN_IS_CURZONEROOT(vp))) {
1010 return (exi->exi_visible ? 1 : 0);
1011 }
1012
1013 /*
1014 * Only the exportinfo of a fs root node may have a visible list.
1015 * Either it is a pseudo root node, or a real exported root node.
1016 */
1017 exi = get_root_export(exi);
1018
1019 if (!exi->exi_visible)
1020 return (0);
1021
1022 /* Get the fid of the vnode */
1023 bzero(&fid, sizeof (fid));
1024 fid.fid_len = MAXFIDSZ;
1025 if (vop_fid_pseudo(vp, &fid) != 0) {
1026 return (0);
1027 }
|