Print this page
Revert exi_zone to exi_zoneid, and install exi_ne backpointer
Caution with use after exi_rele()
Ooops exi_zoneid isn't a variable again yet
Be far more judicious in the use of curzone-using macros.
(Merge and extra asserts by danmcd.)
curzone reality check and teardown changes to use the RIGHT zone
Try to remove assumption that zone's root vnode is marked VROOT

Split Close
Expand all
Collapse all
          --- old/usr/src/uts/common/fs/nfs/nfs4_srv_ns.c
          +++ new/usr/src/uts/common/fs/nfs/nfs4_srv_ns.c
↓ open down ↓ 134 lines elided ↑ open up ↑
 135  135   * mountpoint along the path, then it calls this
 136  136   * function to export it.
 137  137   *
 138  138   * This pseudo export differs from a real export in that
 139  139   * it only allows read-only access.  A "visible" list of
 140  140   * directories is added to filter lookup and readdir results
 141  141   * to only contain dirnames which lead to descendant shares.
 142  142   *
 143  143   * A visible list has a per-file-system scope.  Any exportinfo
 144  144   * struct (real or pseudo) can have a visible list as long as
 145      - * a) its export root is VROOT
      145 + * a) its export root is VROOT, or is the zone's root for in-zone NFS service
 146  146   * b) a descendant of the export root is shared
 147  147   */
 148  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)
      149 +pseudo_exportfs(nfs_export_t *ne, vnode_t *vp, fid_t *fid,
      150 +    struct exp_visible *vis_head, struct exportdata *exdata)
 151  151  {
 152  152          struct exportinfo *exi;
 153  153          struct exportdata *kex;
 154  154          fsid_t fsid;
 155  155          int vpathlen;
 156  156          int i;
 157  157  
 158  158          ASSERT(RW_WRITE_HELD(&ne->exported_lock));
 159  159  
 160  160          fsid = vp->v_vfsp->vfs_fsid;
 161  161          exi = kmem_zalloc(sizeof (*exi), KM_SLEEP);
 162  162          exi->exi_fsid = fsid;
 163  163          exi->exi_fid = *fid;
 164  164          exi->exi_vp = vp;
 165  165          VN_HOLD(exi->exi_vp);
 166  166          exi->exi_visible = vis_head;
 167  167          exi->exi_count = 1;
      168 +        exi->exi_zoneid = ne->ne_globals->nfs_zoneid;
 168  169          exi->exi_volatile_dev = (vfssw[vp->v_vfsp->vfs_fstype].vsw_flag &
 169  170              VSW_VOLATILEDEV) ? 1 : 0;
 170  171          mutex_init(&exi->exi_lock, NULL, MUTEX_DEFAULT, NULL);
 171      -        exi->exi_zoneid = ne->ne_globals->nfs_zoneid;
 172  172  
 173  173          /*
 174  174           * Build up the template fhandle
 175  175           */
 176  176          exi->exi_fh.fh_fsid = fsid;
 177  177          ASSERT(exi->exi_fid.fid_len <= sizeof (exi->exi_fh.fh_xdata));
 178  178          exi->exi_fh.fh_xlen = exi->exi_fid.fid_len;
 179  179          bcopy(exi->exi_fid.fid_data, exi->exi_fh.fh_xdata,
 180  180              exi->exi_fid.fid_len);
 181  181          exi->exi_fh.fh_len = sizeof (exi->exi_fh.fh_data);
↓ open down ↓ 451 lines elided ↑ open up ↑
 633  633          vnode_t *dvp, *vp;
 634  634          fid_t fid;
 635  635          int error;
 636  636          int exportdir;
 637  637          struct exportinfo *new_exi = exip;
 638  638          struct exp_visible *visp;
 639  639          struct exp_visible *vis_head = NULL;
 640  640          struct vattr va;
 641  641          treenode_t *tree_head = NULL;
 642  642          timespec_t now;
 643      -        nfs_export_t *ne = nfs_get_export();
      643 +        nfs_export_t *ne;
 644  644  
      645 +        ne = exip->exi_ne;
      646 +        ASSERT3P(ne, ==, nfs_get_export());     /* curzone reality check */
 645  647          ASSERT(RW_WRITE_HELD(&ne->exported_lock));
 646  648  
 647  649          gethrestime(&now);
 648  650  
 649  651          vp = exip->exi_vp;
 650  652          VN_HOLD(vp);
 651  653          exportdir = 1;
 652  654  
 653  655          for (;;) {
 654  656  
 655  657                  bzero(&fid, sizeof (fid));
 656  658                  fid.fid_len = MAXFIDSZ;
 657  659                  error = vop_fid_pseudo(vp, &fid);
 658  660                  if (error)
 659  661                          break;
 660  662  
      663 +                /* XXX KEBE ASKS DO WE NEED THIS?!? */
      664 +                ASSERT3U(exip->exi_zoneid, ==, curzone->zone_id);
 661  665                  /*
 662      -                 * The root of the file system needs special handling
      666 +                 * The root of the file system, or the zone's root for
      667 +                 * in-zone NFS service needs special handling
 663  668                   */
 664      -                if (vp->v_flag & VROOT) {
 665      -                        if (! exportdir) {
      669 +                if (vp->v_flag & VROOT || vp == EXI_TO_ZONEROOTVP(exip)) {
      670 +                        if (!exportdir) {
 666  671                                  struct exportinfo *exi;
 667  672  
 668  673                                  /*
 669  674                                   * Check if this VROOT dir is already exported.
 670  675                                   * If so, then attach the pseudonodes.  If not,
 671  676                                   * then continue .. traversal until we hit a
 672  677                                   * VROOT export (pseudo or real).
 673  678                                   */
 674  679                                  exi = checkexport4(&vp->v_vfsp->vfs_fsid, &fid,
 675  680                                      vp);
↓ open down ↓ 13 lines elided ↑ open up ↑
 689  694                                   * Found the root directory of a filesystem
 690  695                                   * that isn't exported.  Need to export
 691  696                                   * this as a pseudo export so that an NFS v4
 692  697                                   * client can do lookups in it.
 693  698                                   */
 694  699                                  new_exi = pseudo_exportfs(ne, vp, &fid,
 695  700                                      vis_head, NULL);
 696  701                                  vis_head = NULL;
 697  702                          }
 698  703  
 699      -                        if (VN_CMP(vp, ZONE_ROOTVP())) {
      704 +                        if (VN_IS_CURZONEROOT(vp)) {
 700  705                                  /* at system root */
 701  706                                  /*
 702  707                                   * If sharing "/", new_exi is shared exportinfo
 703  708                                   * (exip). Otherwise, new_exi is exportinfo
 704  709                                   * created by pseudo_exportfs() above.
 705  710                                   */
 706  711                                  ne->ns_root = tree_prepend_node(tree_head, NULL,
 707  712                                      new_exi);
 708  713  
 709  714                                  /* Update the change timestamp */
↓ open down ↓ 109 lines elided ↑ open up ↑
 819  824  /*
 820  825   * Walk up the tree and:
 821  826   * 1. release pseudo exportinfo if it has no child
 822  827   * 2. release visible in parent's exportinfo
 823  828   * 3. delete non-exported leaf nodes from tree
 824  829   *
 825  830   * Deleting of nodes will start only if the unshared
 826  831   * node was a leaf node.
 827  832   * Deleting of nodes will finish when we reach a node which
 828  833   * has children or is a real export, then we might still need
 829      - * to continue releasing visibles, until we reach VROOT node.
      834 + * to continue releasing visibles, until we reach VROOT or zone's root node.
 830  835   */
 831  836  void
 832  837  treeclimb_unexport(nfs_export_t *ne, struct exportinfo *exip)
 833  838  {
 834  839          treenode_t *tnode, *old_nd;
 835  840          treenode_t *connect_point = NULL;
 836  841  
 837  842          ASSERT(RW_WRITE_HELD(&ne->exported_lock));
      843 +        ASSERT(curzone->zone_id == exip->exi_zoneid ||
      844 +            curzone->zone_id == global_zone->zone_id);
 838  845  
 839  846          /*
 840  847           * exi_tree can be null for the zone root
 841  848           * which means we're already at the "top"
 842  849           * and there's nothing more to "climb".
 843  850           */
 844  851          tnode = exip->exi_tree;
 845  852          if (tnode == NULL) {
 846  853                  /* Should only happen for... */
 847  854                  ASSERT(exip == ne->exi_root);
↓ open down ↓ 4 lines elided ↑ open up ↑
 852  859           * The unshared exportinfo was unlinked in unexport().
 853  860           * Zeroing tree_exi ensures that we will skip it.
 854  861           */
 855  862          tnode->tree_exi = NULL;
 856  863  
 857  864          if (tnode->tree_vis != NULL) /* system root has tree_vis == NULL */
 858  865                  tnode->tree_vis->vis_exported = 0;
 859  866  
 860  867          while (tnode != NULL) {
 861  868  
 862      -                /* Stop at VROOT node which is exported or has child */
      869 +                /*
      870 +                 * Stop at VROOT (or zone root) node which is exported or has
      871 +                 * child.
      872 +                 */
 863  873                  if (TREE_ROOT(tnode) &&
 864  874                      (TREE_EXPORTED(tnode) || tnode->tree_child_first != NULL))
 865  875                          break;
 866  876  
 867  877                  /* Release pseudo export if it has no child */
 868  878                  if (TREE_ROOT(tnode) && !TREE_EXPORTED(tnode) &&
 869  879                      tnode->tree_child_first == NULL) {
 870  880                          mutex_enter(&nfs_exi_id_lock);
 871  881                          avl_remove(&exi_id_tree, tnode->tree_exi);
 872  882                          mutex_exit(&nfs_exi_id_lock);
 873  883                          export_unlink(ne, tnode->tree_exi);
 874  884                          exi_rele(tnode->tree_exi);
      885 +                        tnode->tree_exi = NULL;
 875  886                  }
 876  887  
 877  888                  /* Release visible in parent's exportinfo */
 878  889                  if (tnode->tree_vis != NULL)
 879  890                          less_visible(vis2exi(tnode), tnode->tree_vis);
 880  891  
 881  892                  /* Continue with parent */
 882  893                  old_nd = tnode;
 883  894                  tnode = tnode->tree_parent;
 884  895  
↓ open down ↓ 7 lines elided ↑ open up ↑
 892  903  
 893  904          /* Update the change timestamp */
 894  905          if (connect_point != NULL)
 895  906                  tree_update_change(ne, connect_point, NULL);
 896  907  }
 897  908  
 898  909  /*
 899  910   * Traverse backward across mountpoint from the
 900  911   * root vnode of a filesystem to its mounted-on
 901  912   * vnode.
      913 + *
      914 + * Callers to this function have confirmed the use of curzone is safe here.
 902  915   */
 903  916  vnode_t *
 904  917  untraverse(vnode_t *vp)
 905  918  {
 906  919          vnode_t *tvp, *nextvp;
 907  920  
 908  921          tvp = vp;
 909  922          for (;;) {
 910      -                if (! (tvp->v_flag & VROOT))
      923 +                if (!(tvp->v_flag & VROOT) && !VN_IS_CURZONEROOT(tvp))
 911  924                          break;
 912  925  
 913  926                  /* lock vfs to prevent unmount of this vfs */
 914  927                  vfs_lock_wait(tvp->v_vfsp);
 915  928  
 916  929                  if ((nextvp = tvp->v_vfsp->vfs_vnodecovered) == NULL) {
 917  930                          vfs_unlock(tvp->v_vfsp);
 918  931                          break;
 919  932                  }
 920  933  
↓ open down ↓ 10 lines elided ↑ open up ↑
 931  944                  vfs_unlock(tvp->v_vfsp);
 932  945                  VN_RELE(tvp);
 933  946                  tvp = nextvp;
 934  947          }
 935  948  
 936  949          return (tvp);
 937  950  }
 938  951  
 939  952  /*
 940  953   * Given an exportinfo, climb up to find the exportinfo for the VROOT
 941      - * of the filesystem.
      954 + * (or zone root) of the filesystem.
 942  955   *
 943  956   * e.g.         /
 944  957   *              |
 945  958   *              a (VROOT) pseudo-exportinfo
 946  959   *              |
 947  960   *              b
 948  961   *              |
 949  962   *              c  #share /a/b/c
 950  963   *              |
 951  964   *              d
 952  965   *
 953  966   * where c is in the same filesystem as a.
 954  967   * So, get_root_export(*exportinfo_for_c) returns exportinfo_for_a
 955  968   *
 956  969   * If d is shared, then c will be put into a's visible list.
 957  970   * Note: visible list is per filesystem and is attached to the
 958      - * VROOT exportinfo.
      971 + * VROOT exportinfo.  Returned exi does NOT have a new hold.
 959  972   */
 960  973  struct exportinfo *
 961  974  get_root_export(struct exportinfo *exip)
 962  975  {
 963  976          treenode_t *tnode = exip->exi_tree;
 964  977          exportinfo_t *exi = NULL;
 965  978  
 966  979          while (tnode) {
 967  980                  if (TREE_ROOT(tnode)) {
 968  981                          exi = tnode->tree_exi;
↓ open down ↓ 11 lines elided ↑ open up ↑
 980  993  int
 981  994  has_visible(struct exportinfo *exi, vnode_t *vp)
 982  995  {
 983  996          struct exp_visible *visp;
 984  997          fid_t fid;
 985  998          bool_t vp_is_exported;
 986  999  
 987 1000          vp_is_exported = VN_CMP(vp, exi->exi_vp);
 988 1001  
 989 1002          /*
 990      -         * An exported root vnode has a sub-dir shared if it has a visible list.
 991      -         * i.e. if it does not have a visible list, then there is no node in
 992      -         * this filesystem leads to any other shared node.
     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.
 993 1006           */
 994      -        if (vp_is_exported && (vp->v_flag & VROOT))
     1007 +        ASSERT3P(curzone->zone_id, ==, exi->exi_zoneid);
     1008 +        if (vp_is_exported &&
     1009 +            ((vp->v_flag & VROOT) || VN_IS_CURZONEROOT(vp))) {
 995 1010                  return (exi->exi_visible ? 1 : 0);
     1011 +        }
 996 1012  
 997 1013          /*
 998 1014           * Only the exportinfo of a fs root node may have a visible list.
 999 1015           * Either it is a pseudo root node, or a real exported root node.
1000 1016           */
1001 1017          exi = get_root_export(exi);
1002 1018  
1003 1019          if (!exi->exi_visible)
1004 1020                  return (0);
1005 1021  
↓ open down ↓ 52 lines elided ↑ open up ↑
1058 1074           */
1059 1075          if (VN_CMP(vp, exi->exi_vp)) {
1060 1076                  *expseudo = 0;
1061 1077                  return (1);
1062 1078          }
1063 1079  
1064 1080          /*
1065 1081           * Only a PSEUDO node has a visible list or an exported VROOT
1066 1082           * node may have a visible list.
1067 1083           */
1068      -        if (! PSEUDO(exi))
     1084 +        if (!PSEUDO(exi))
1069 1085                  exi = get_root_export(exi);
1070 1086  
1071 1087          /* Get the fid of the vnode */
1072 1088  
1073 1089          bzero(&fid, sizeof (fid));
1074 1090          fid.fid_len = MAXFIDSZ;
1075 1091          if (vop_fid_pseudo(vp, &fid) != 0) {
1076 1092                  *expseudo = 0;
1077 1093                  return (0);
1078 1094          }
↓ open down ↓ 87 lines elided ↑ open up ↑
1166 1182   * skips . and .. entries.
1167 1183   */
1168 1184  int
1169 1185  nfs_visible_inode(struct exportinfo *exi, ino64_t ino,
1170 1186      struct exp_visible **visp)
1171 1187  {
1172 1188          /*
1173 1189           * Only a PSEUDO node has a visible list or an exported VROOT
1174 1190           * node may have a visible list.
1175 1191           */
1176      -        if (! PSEUDO(exi))
     1192 +        if (!PSEUDO(exi))
1177 1193                  exi = get_root_export(exi);
1178 1194  
1179 1195          for (*visp = exi->exi_visible; *visp != NULL; *visp = (*visp)->vis_next)
1180 1196                  if ((u_longlong_t)ino == (*visp)->vis_ino) {
1181 1197                          return (1);
1182 1198                  }
1183 1199  
1184 1200          return (0);
1185 1201  }
1186 1202  
↓ open down ↓ 89 lines elided ↑ open up ↑
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX