Print this page
curzone reality check and teardown changes to use the RIGHT zone


 129  * This is an export entry that's created as the
 130  * side-effect of a "real" export.  As a part of
 131  * a real export, the pathname to the export is
 132  * checked to see if all the directory components
 133  * are accessible via an NFSv4 client, i.e. are
 134  * exported.  If treeclimb_export() finds an unexported
 135  * mountpoint along the path, then it calls this
 136  * function to export it.
 137  *
 138  * This pseudo export differs from a real export in that
 139  * it only allows read-only access.  A "visible" list of
 140  * directories is added to filter lookup and readdir results
 141  * to only contain dirnames which lead to descendant shares.
 142  *
 143  * A visible list has a per-file-system scope.  Any exportinfo
 144  * struct (real or pseudo) can have a visible list as long as
 145  * a) its export root is VROOT, or is the zone's root for in-zone NFS service
 146  * b) a descendant of the export root is shared
 147  */
 148 struct exportinfo *
 149 pseudo_exportfs(nfs_export_t *ne, vnode_t *vp, fid_t *fid, struct exp_visible *vis_head,
 150     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_volatile_dev = (vfssw[vp->v_vfsp->vfs_fstype].vsw_flag &
 169             VSW_VOLATILEDEV) ? 1 : 0;
 170         mutex_init(&exi->exi_lock, NULL, MUTEX_DEFAULT, NULL);
 171 
 172         /*
 173          * Build up the template fhandle
 174          */
 175         exi->exi_fh.fh_fsid = fsid;
 176         ASSERT(exi->exi_fid.fid_len <= sizeof (exi->exi_fh.fh_xdata));
 177         exi->exi_fh.fh_xlen = exi->exi_fid.fid_len;
 178         bcopy(exi->exi_fid.fid_data, exi->exi_fh.fh_xdata,
 179             exi->exi_fid.fid_len);
 180         exi->exi_fh.fh_len = sizeof (exi->exi_fh.fh_data);
 181 
 182         kex = &exi->exi_export;
 183         kex->ex_flags = EX_PSEUDO;
 184 
 185         vpathlen = strlen(vp->v_path);
 186         kex->ex_pathlen = vpathlen + strlen(PSEUDOFS_SUFFIX);
 187         kex->ex_path = kmem_alloc(kex->ex_pathlen + 1, KM_SLEEP);


 625  *           |                  |                  |
 626  *           j                 (o) EXPORT,f2       q EXPORT f2
 627  *
 628  */
 629 int
 630 treeclimb_export(struct exportinfo *exip)
 631 {
 632         vnode_t *dvp, *vp;
 633         fid_t fid;
 634         int error;
 635         int exportdir;
 636         struct exportinfo *new_exi = exip;
 637         struct exp_visible *visp;
 638         struct exp_visible *vis_head = NULL;
 639         struct vattr va;
 640         treenode_t *tree_head = NULL;
 641         timespec_t now;
 642         nfs_export_t *ne = nfs_get_export();
 643 
 644         ASSERT(RW_WRITE_HELD(&ne->exported_lock));

 645 
 646         gethrestime(&now);
 647 
 648         vp = exip->exi_vp;
 649         VN_HOLD(vp);
 650         exportdir = 1;
 651 
 652         for (;;) {
 653 
 654                 bzero(&fid, sizeof (fid));
 655                 fid.fid_len = MAXFIDSZ;
 656                 error = vop_fid_pseudo(vp, &fid);
 657                 if (error)
 658                         break;
 659 
 660                 /*
 661                  * The root of the file system, or the zone's root for
 662                  * in-zone NFS service needs special handling
 663                  */
 664                 if (vp->v_flag & VROOT || VN_IS_CURZONEROOT(vp)) {


 676                                 if (exi != NULL) {
 677                                         /*
 678                                          * Found an export info
 679                                          *
 680                                          * Extend the list of visible
 681                                          * directories whether it's a pseudo
 682                                          * or a real export.
 683                                          */
 684                                         more_visible(exi, tree_head);
 685                                         break;  /* and climb no further */
 686                                 }
 687 
 688                                 /*
 689                                  * Found the root directory of a filesystem
 690                                  * that isn't exported.  Need to export
 691                                  * this as a pseudo export so that an NFS v4
 692                                  * client can do lookups in it.
 693                                  */
 694                                 new_exi = pseudo_exportfs(ne, vp, &fid,
 695                                     vis_head, NULL);

 696                                 vis_head = NULL;
 697                         }
 698 
 699                         if (VN_IS_CURZONEROOT(vp)) {
 700                                 /* at system root */
 701                                 /*
 702                                  * If sharing "/", new_exi is shared exportinfo
 703                                  * (exip). Otherwise, new_exi is exportinfo
 704                                  * created by pseudo_exportfs() above.
 705                                  */
 706                                 ne->ns_root = tree_prepend_node(tree_head, NULL,
 707                                     new_exi);
 708 
 709                                 /* Update the change timestamp */
 710                                 tree_update_change(ne, ne->ns_root, &now);
 711 
 712                                 break;
 713                         }
 714 
 715                         /*


 818 
 819 /*
 820  * Walk up the tree and:
 821  * 1. release pseudo exportinfo if it has no child
 822  * 2. release visible in parent's exportinfo
 823  * 3. delete non-exported leaf nodes from tree
 824  *
 825  * Deleting of nodes will start only if the unshared
 826  * node was a leaf node.
 827  * Deleting of nodes will finish when we reach a node which
 828  * has children or is a real export, then we might still need
 829  * to continue releasing visibles, until we reach VROOT or zone's root node.
 830  */
 831 void
 832 treeclimb_unexport(nfs_export_t *ne, struct exportinfo *exip)
 833 {
 834         treenode_t *tnode, *old_nd;
 835         treenode_t *connect_point = NULL;
 836 
 837         ASSERT(RW_WRITE_HELD(&ne->exported_lock));

 838 
 839         tnode = exip->exi_tree;
 840         /*
 841          * The unshared exportinfo was unlinked in unexport().
 842          * Zeroing tree_exi ensures that we will skip it.
 843          */
 844         tnode->tree_exi = NULL;
 845 
 846         if (tnode->tree_vis != NULL) /* system root has tree_vis == NULL */
 847                 tnode->tree_vis->vis_exported = 0;
 848 
 849         while (tnode != NULL) {
 850 
 851                 /*
 852                  * Stop at VROOT (or zone root) node which is exported or has
 853                  * child.
 854                  */
 855                 if (TREE_ROOT(tnode) &&
 856                     (TREE_EXPORTED(tnode) || tnode->tree_child_first != NULL))
 857                         break;


 966         return (exi);
 967 }
 968 
 969 /*
 970  * Return true if the supplied vnode has a sub-directory exported.
 971  */
 972 int
 973 has_visible(struct exportinfo *exi, vnode_t *vp)
 974 {
 975         struct exp_visible *visp;
 976         fid_t fid;
 977         bool_t vp_is_exported;
 978 
 979         vp_is_exported = VN_CMP(vp, exi->exi_vp);
 980 
 981         /*
 982          * An exported root vnode has a sub-dir shared if it has a visible
 983          * list.  i.e. if it does not have a visible list, then there is no
 984          * node in this filesystem leads to any other shared node.
 985          */

 986         if (vp_is_exported &&
 987             ((vp->v_flag & VROOT) || VN_IS_CURZONEROOT(vp))) {
 988                 return (exi->exi_visible ? 1 : 0);
 989         }
 990 
 991         /*
 992          * Only the exportinfo of a fs root node may have a visible list.
 993          * Either it is a pseudo root node, or a real exported root node.
 994          */
 995         exi = get_root_export(exi);
 996 
 997         if (!exi->exi_visible)
 998                 return (0);
 999 
1000         /* Get the fid of the vnode */
1001         bzero(&fid, sizeof (fid));
1002         fid.fid_len = MAXFIDSZ;
1003         if (vop_fid_pseudo(vp, &fid) != 0) {
1004                 return (0);
1005         }




 129  * This is an export entry that's created as the
 130  * side-effect of a "real" export.  As a part of
 131  * a real export, the pathname to the export is
 132  * checked to see if all the directory components
 133  * are accessible via an NFSv4 client, i.e. are
 134  * exported.  If treeclimb_export() finds an unexported
 135  * mountpoint along the path, then it calls this
 136  * function to export it.
 137  *
 138  * This pseudo export differs from a real export in that
 139  * it only allows read-only access.  A "visible" list of
 140  * directories is added to filter lookup and readdir results
 141  * to only contain dirnames which lead to descendant shares.
 142  *
 143  * A visible list has a per-file-system scope.  Any exportinfo
 144  * struct (real or pseudo) can have a visible list as long as
 145  * a) its export root is VROOT, or is the zone's root for in-zone NFS service
 146  * b) a descendant of the export root is shared
 147  */
 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         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);


 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 = nfs_get_export();
 644 
 645         ASSERT(RW_WRITE_HELD(&ne->exported_lock));
 646         ASSERT3P(curzone, ==, exip->exi_zone);
 647 
 648         gethrestime(&now);
 649 
 650         vp = exip->exi_vp;
 651         VN_HOLD(vp);
 652         exportdir = 1;
 653 
 654         for (;;) {
 655 
 656                 bzero(&fid, sizeof (fid));
 657                 fid.fid_len = MAXFIDSZ;
 658                 error = vop_fid_pseudo(vp, &fid);
 659                 if (error)
 660                         break;
 661 
 662                 /*
 663                  * The root of the file system, or the zone's root for
 664                  * in-zone NFS service needs special handling
 665                  */
 666                 if (vp->v_flag & VROOT || VN_IS_CURZONEROOT(vp)) {


 678                                 if (exi != NULL) {
 679                                         /*
 680                                          * Found an export info
 681                                          *
 682                                          * Extend the list of visible
 683                                          * directories whether it's a pseudo
 684                                          * or a real export.
 685                                          */
 686                                         more_visible(exi, tree_head);
 687                                         break;  /* and climb no further */
 688                                 }
 689 
 690                                 /*
 691                                  * Found the root directory of a filesystem
 692                                  * that isn't exported.  Need to export
 693                                  * this as a pseudo export so that an NFS v4
 694                                  * client can do lookups in it.
 695                                  */
 696                                 new_exi = pseudo_exportfs(ne, vp, &fid,
 697                                     vis_head, NULL);
 698                                 new_exi->exi_zone = exip->exi_zone;
 699                                 vis_head = NULL;
 700                         }
 701 
 702                         if (VN_IS_CURZONEROOT(vp)) {
 703                                 /* at system root */
 704                                 /*
 705                                  * If sharing "/", new_exi is shared exportinfo
 706                                  * (exip). Otherwise, new_exi is exportinfo
 707                                  * created by pseudo_exportfs() above.
 708                                  */
 709                                 ne->ns_root = tree_prepend_node(tree_head, NULL,
 710                                     new_exi);
 711 
 712                                 /* Update the change timestamp */
 713                                 tree_update_change(ne, ne->ns_root, &now);
 714 
 715                                 break;
 716                         }
 717 
 718                         /*


 821 
 822 /*
 823  * Walk up the tree and:
 824  * 1. release pseudo exportinfo if it has no child
 825  * 2. release visible in parent's exportinfo
 826  * 3. delete non-exported leaf nodes from tree
 827  *
 828  * Deleting of nodes will start only if the unshared
 829  * node was a leaf node.
 830  * Deleting of nodes will finish when we reach a node which
 831  * has children or is a real export, then we might still need
 832  * to continue releasing visibles, until we reach VROOT or zone's root node.
 833  */
 834 void
 835 treeclimb_unexport(nfs_export_t *ne, struct exportinfo *exip)
 836 {
 837         treenode_t *tnode, *old_nd;
 838         treenode_t *connect_point = NULL;
 839 
 840         ASSERT(RW_WRITE_HELD(&ne->exported_lock));
 841         ASSERT(curzone == exip->exi_zone || curzone == global_zone);
 842 
 843         tnode = exip->exi_tree;
 844         /*
 845          * The unshared exportinfo was unlinked in unexport().
 846          * Zeroing tree_exi ensures that we will skip it.
 847          */
 848         tnode->tree_exi = NULL;
 849 
 850         if (tnode->tree_vis != NULL) /* system root has tree_vis == NULL */
 851                 tnode->tree_vis->vis_exported = 0;
 852 
 853         while (tnode != NULL) {
 854 
 855                 /*
 856                  * Stop at VROOT (or zone root) node which is exported or has
 857                  * child.
 858                  */
 859                 if (TREE_ROOT(tnode) &&
 860                     (TREE_EXPORTED(tnode) || tnode->tree_child_first != NULL))
 861                         break;


 970         return (exi);
 971 }
 972 
 973 /*
 974  * Return true if the supplied vnode has a sub-directory exported.
 975  */
 976 int
 977 has_visible(struct exportinfo *exi, vnode_t *vp)
 978 {
 979         struct exp_visible *visp;
 980         fid_t fid;
 981         bool_t vp_is_exported;
 982 
 983         vp_is_exported = VN_CMP(vp, exi->exi_vp);
 984 
 985         /*
 986          * An exported root vnode has a sub-dir shared if it has a visible
 987          * list.  i.e. if it does not have a visible list, then there is no
 988          * node in this filesystem leads to any other shared node.
 989          */
 990         ASSERT3P(curzone, ==, exi->exi_zone);
 991         if (vp_is_exported &&
 992             ((vp->v_flag & VROOT) || VN_IS_CURZONEROOT(vp))) {
 993                 return (exi->exi_visible ? 1 : 0);
 994         }
 995 
 996         /*
 997          * Only the exportinfo of a fs root node may have a visible list.
 998          * Either it is a pseudo root node, or a real exported root node.
 999          */
1000         exi = get_root_export(exi);
1001 
1002         if (!exi->exi_visible)
1003                 return (0);
1004 
1005         /* Get the fid of the vnode */
1006         bzero(&fid, sizeof (fid));
1007         fid.fid_len = MAXFIDSZ;
1008         if (vop_fid_pseudo(vp, &fid) != 0) {
1009                 return (0);
1010         }