Print this page
    
11083 support NFS server in zone
Portions contributed by: Dan Kruchinin <dan.kruchinin@nexenta.com>
Portions contributed by: Stepan Zastupov <stepan.zastupov@gmail.com>
Portions contributed by: Joyce McIntosh <joyce.mcintosh@nexenta.com>
Portions contributed by: Mike Zeller <mike@mikezeller.net>
Portions contributed by: Dan McDonald <danmcd@joyent.com>
Portions contributed by: Gordon Ross <gordon.w.ross@gmail.com>
Portions contributed by: Vitaliy Gusev <gusev.vitaliy@gmail.com>
Reviewed by: Rick McNeal <rick.mcneal@nexenta.com>
Reviewed by: Rob Gittins <rob.gittins@nexenta.com>
Reviewed by: Sanjay Nadkarni <sanjay.nadkarni@nexenta.com>
Reviewed by: Jason King <jbk@joyent.com>
Reviewed by: C Fraire <cfraire@me.com>
Change-Id: I22f289d357503f9b48a0bc2482cc4328a6d43d16
    
      
        | 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
   1    1  /*
   2    2   * CDDL HEADER START
   3    3   *
   4    4   * The contents of this file are subject to the terms of the
   5    5   * Common Development and Distribution License (the "License").
   6    6   * You may not use this file except in compliance with the License.
   7    7   *
   8    8   * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9    9   * or http://www.opensolaris.org/os/licensing.
  10   10   * See the License for the specific language governing permissions
  11   11   * and limitations under the License.
  12   12   *
  
    | 
      ↓ open down ↓ | 
    12 lines elided | 
    
      ↑ open up ↑ | 
  
  13   13   * When distributing Covered Code, include this CDDL HEADER in each
  14   14   * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15   15   * If applicable, add the following below this CDDL HEADER, with the
  16   16   * fields enclosed by brackets "[]" replaced with your own identifying
  17   17   * information: Portions Copyright [yyyy] [name of copyright owner]
  18   18   *
  19   19   * CDDL HEADER END
  20   20   */
  21   21  
  22   22  /*
  23      - * Copyright 2014 Nexenta Systems, Inc.  All rights reserved.
  24   23   * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
       24 + */
       25 +
       26 +/*
       27 + * Copyright 2018 Nexenta Systems, Inc.
  25   28   * Copyright (c) 2015, Joyent, Inc.
  26   29   */
  27   30  
  28   31  #include <sys/systm.h>
  29   32  
  30   33  #include <nfs/nfs.h>
  31   34  #include <nfs/export.h>
  32   35  #include <sys/cmn_err.h>
  33   36  #include <sys/avl.h>
  34   37  
  35   38  #define PSEUDOFS_SUFFIX         " (pseudo)"
  36   39  
  37   40  /*
  38   41   * A version of VOP_FID that deals with a remote VOP_FID for nfs.
  39   42   * If vp is an nfs node, nfs4_fid() returns EREMOTE, nfs3_fid() and nfs_fid()
  40   43   * returns the filehandle of vp as its fid. When nfs uses fid to set the
  41   44   * exportinfo filehandle template, a remote nfs filehandle would be too big for
  42   45   * the fid of the exported directory. This routine remaps the value of the
  43   46   * attribute va_nodeid of vp to be the fid of vp, so that the fid can fit.
  44   47   *
  45   48   * We need this fid mainly for setting up NFSv4 server namespace where an
  46   49   * nfs filesystem is also part of it. Thus, need to be able to setup a pseudo
  47   50   * exportinfo for an nfs node.
  48   51   *
  49   52   * e.g. mount a filesystem on top of a nfs dir, and then share the new mount
  50   53   *      (like exporting a local disk from a "diskless" client)
  51   54   */
  52   55  int
  53   56  vop_fid_pseudo(vnode_t *vp, fid_t *fidp)
  54   57  {
  55   58          struct vattr va;
  56   59          int error;
  57   60  
  58   61          error = VOP_FID(vp, fidp, NULL);
  59   62  
  60   63          /*
  61   64           * XXX nfs4_fid() does nothing and returns EREMOTE.
  62   65           * XXX nfs3_fid()/nfs_fid() returns nfs filehandle as its fid
  63   66           * which has a bigger length than local fid.
  64   67           * NFS_FH4MAXDATA is the size of
  65   68           * fhandle4_t.fh_xdata[NFS_FH4MAXDATA].
  66   69           *
  67   70           * Note: nfs[2,3,4]_fid() only gets called for diskless clients.
  68   71           */
  69   72          if (error == EREMOTE ||
  70   73              (error == 0 && fidp->fid_len > NFS_FH4MAXDATA)) {
  71   74  
  72   75                  va.va_mask = AT_NODEID;
  73   76                  error = VOP_GETATTR(vp, &va, 0, CRED(), NULL);
  74   77                  if (error)
  75   78                          return (error);
  76   79  
  77   80                  fidp->fid_len = sizeof (va.va_nodeid);
  78   81                  bcopy(&va.va_nodeid, fidp->fid_data, fidp->fid_len);
  79   82                  return (0);
  80   83          }
  81   84  
  82   85          return (error);
  83   86  }
  84   87  
  85   88  /*
  86   89   * Get an nfsv4 vnode of the given fid from the visible list of an
  87   90   * nfs filesystem or get the exi_vp if it is the root node.
  88   91   */
  89   92  int
  90   93  nfs4_vget_pseudo(struct exportinfo *exi, vnode_t **vpp, fid_t *fidp)
  91   94  {
  92   95          fid_t exp_fid;
  93   96          struct exp_visible *visp;
  94   97          int error;
  95   98  
  96   99          /* check if the given fid is in the visible list */
  97  100  
  98  101          for (visp = exi->exi_visible; visp; visp = visp->vis_next) {
  99  102                  if (EQFID(fidp, &visp->vis_fid)) {
 100  103                          VN_HOLD(visp->vis_vp);
 101  104                          *vpp = visp->vis_vp;
 102  105                          return (0);
 103  106                  }
 104  107          }
 105  108  
 106  109          /* check if the given fid is the same as the exported node */
 107  110  
 108  111          bzero(&exp_fid, sizeof (exp_fid));
 109  112          exp_fid.fid_len = MAXFIDSZ;
 110  113          error = vop_fid_pseudo(exi->exi_vp, &exp_fid);
 111  114          if (error)
 112  115                  return (error);
 113  116  
 114  117          if (EQFID(fidp, &exp_fid)) {
 115  118                  VN_HOLD(exi->exi_vp);
 116  119                  *vpp = exi->exi_vp;
 117  120                  return (0);
 118  121          }
 119  122  
 120  123          return (ENOENT);
 121  124  }
 122  125  
 123  126  /*
 124  127   * Create a pseudo export entry
 125  128   *
 126  129   * This is an export entry that's created as the
 127  130   * side-effect of a "real" export.  As a part of
 128  131   * a real export, the pathname to the export is
 129  132   * checked to see if all the directory components
 130  133   * are accessible via an NFSv4 client, i.e. are
 131  134   * exported.  If treeclimb_export() finds an unexported
  
    | 
      ↓ open down ↓ | 
    97 lines elided | 
    
      ↑ open up ↑ | 
  
 132  135   * mountpoint along the path, then it calls this
 133  136   * function to export it.
 134  137   *
 135  138   * This pseudo export differs from a real export in that
 136  139   * it only allows read-only access.  A "visible" list of
 137  140   * directories is added to filter lookup and readdir results
 138  141   * to only contain dirnames which lead to descendant shares.
 139  142   *
 140  143   * A visible list has a per-file-system scope.  Any exportinfo
 141  144   * struct (real or pseudo) can have a visible list as long as
 142      - * a) its export root is VROOT
      145 + * a) its export root is VROOT, or is the zone's root for in-zone NFS service
 143  146   * b) a descendant of the export root is shared
 144  147   */
 145  148  struct exportinfo *
 146      -pseudo_exportfs(vnode_t *vp, fid_t *fid, struct exp_visible *vis_head,
 147      -    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)
 148  151  {
 149  152          struct exportinfo *exi;
 150  153          struct exportdata *kex;
 151  154          fsid_t fsid;
 152  155          int vpathlen;
 153  156          int i;
 154  157  
 155      -        ASSERT(RW_WRITE_HELD(&exported_lock));
      158 +        ASSERT(RW_WRITE_HELD(&ne->exported_lock));
 156  159  
 157  160          fsid = vp->v_vfsp->vfs_fsid;
 158  161          exi = kmem_zalloc(sizeof (*exi), KM_SLEEP);
 159  162          exi->exi_fsid = fsid;
 160  163          exi->exi_fid = *fid;
 161  164          exi->exi_vp = vp;
 162  165          VN_HOLD(exi->exi_vp);
 163  166          exi->exi_visible = vis_head;
 164  167          exi->exi_count = 1;
      168 +        exi->exi_zoneid = ne->ne_globals->nfs_zoneid;
 165  169          exi->exi_volatile_dev = (vfssw[vp->v_vfsp->vfs_fstype].vsw_flag &
 166  170              VSW_VOLATILEDEV) ? 1 : 0;
 167  171          mutex_init(&exi->exi_lock, NULL, MUTEX_DEFAULT, NULL);
 168  172  
 169  173          /*
 170  174           * Build up the template fhandle
 171  175           */
 172  176          exi->exi_fh.fh_fsid = fsid;
 173  177          ASSERT(exi->exi_fid.fid_len <= sizeof (exi->exi_fh.fh_xdata));
 174  178          exi->exi_fh.fh_xlen = exi->exi_fid.fid_len;
 175  179          bcopy(exi->exi_fid.fid_data, exi->exi_fh.fh_xdata,
 176  180              exi->exi_fid.fid_len);
 177  181          exi->exi_fh.fh_len = sizeof (exi->exi_fh.fh_data);
 178  182  
 179  183          kex = &exi->exi_export;
 180  184          kex->ex_flags = EX_PSEUDO;
 181  185  
 182  186          vpathlen = strlen(vp->v_path);
 183  187          kex->ex_pathlen = vpathlen + strlen(PSEUDOFS_SUFFIX);
 184  188          kex->ex_path = kmem_alloc(kex->ex_pathlen + 1, KM_SLEEP);
 185  189  
 186  190          if (vpathlen)
 187  191                  (void) strncpy(kex->ex_path, vp->v_path, vpathlen);
 188  192          (void) strcpy(kex->ex_path + vpathlen, PSEUDOFS_SUFFIX);
 189  193  
 190  194          /* Transfer the secinfo data from exdata to this new pseudo node */
 191  195          if (exdata)
 192  196                  srv_secinfo_exp2pseu(&exi->exi_export, exdata);
 193  197  
 194  198          /*
 195  199           * Initialize auth cache and auth cache lock
 196  200           */
 197  201          for (i = 0; i < AUTH_TABLESIZE; i++) {
  
    | 
      ↓ open down ↓ | 
    23 lines elided | 
    
      ↑ open up ↑ | 
  
 198  202                  exi->exi_cache[i] = kmem_alloc(sizeof (avl_tree_t), KM_SLEEP);
 199  203                  avl_create(exi->exi_cache[i], nfsauth_cache_clnt_compar,
 200  204                      sizeof (struct auth_cache_clnt),
 201  205                      offsetof(struct auth_cache_clnt, authc_link));
 202  206          }
 203  207          rw_init(&exi->exi_cache_lock, NULL, RW_DEFAULT, NULL);
 204  208  
 205  209          /*
 206  210           * Insert the new entry at the front of the export list
 207  211           */
 208      -        export_link(exi);
      212 +        export_link(ne, exi);
 209  213  
      214 +        /*
      215 +         * Initialize exi_id and exi_kstats
      216 +         */
      217 +        mutex_enter(&nfs_exi_id_lock);
      218 +        exi->exi_id = exi_id_get_next();
      219 +        avl_add(&exi_id_tree, exi);
      220 +        mutex_exit(&nfs_exi_id_lock);
      221 +
 210  222          return (exi);
 211  223  }
 212  224  
 213  225  /*
 214  226   * Free a list of visible directories
 215  227   */
 216  228  void
 217  229  free_visible(struct exp_visible *head)
 218  230  {
 219  231          struct exp_visible *visp, *next;
 220  232  
 221  233          for (visp = head; visp; visp = next) {
 222  234                  if (visp->vis_vp != NULL)
 223  235                          VN_RELE(visp->vis_vp);
 224  236  
 225  237                  next = visp->vis_next;
 226  238                  srv_secinfo_list_free(visp->vis_secinfo, visp->vis_seccnt);
 227  239                  kmem_free(visp, sizeof (*visp));
 228  240          }
 229  241  }
 230  242  
 231  243  /*
 232  244   * Connects newchild (or subtree with newchild in head)
 233  245   * to the parent node. We always add it to the beginning
 234  246   * of sibling list.
 235  247   */
 236  248  static void
 237  249  tree_add_child(treenode_t *parent, treenode_t *newchild)
 238  250  {
 239  251          newchild->tree_parent = parent;
 240  252          newchild->tree_sibling = parent->tree_child_first;
 241  253          parent->tree_child_first = newchild;
 242  254  }
 243  255  
 244  256  /* Look up among direct children a node with the exact tree_vis pointer */
 245  257  static treenode_t *
 246  258  tree_find_child_by_vis(treenode_t *t, exp_visible_t *vis)
 247  259  {
 248  260          for (t = t->tree_child_first; t; t = t->tree_sibling)
 249  261                  if (t->tree_vis == vis)
 250  262                          return (t);
 251  263          return (NULL);
 252  264  }
 253  265  
 254  266  /*
 255  267   * Add new node to the head of subtree pointed by 'n'. n can be NULL.
 256  268   * Interconnects the new treenode with exp_visible and exportinfo
 257  269   * if needed.
 258  270   */
 259  271  static treenode_t *
 260  272  tree_prepend_node(treenode_t *n, exp_visible_t *v, exportinfo_t *e)
 261  273  {
 262  274          treenode_t *tnode = kmem_zalloc(sizeof (*tnode), KM_SLEEP);
 263  275  
 264  276          if (n) {
 265  277                  tnode->tree_child_first = n;
 266  278                  n->tree_parent = tnode;
 267  279          }
 268  280          if (v) {
 269  281                  tnode->tree_vis = v;
 270  282          }
 271  283          if (e) {
 272  284                  tnode->tree_exi = e;
 273  285                  e->exi_tree = tnode;
  
    | 
      ↓ open down ↓ | 
    54 lines elided | 
    
      ↑ open up ↑ | 
  
 274  286          }
 275  287          return (tnode);
 276  288  }
 277  289  
 278  290  /*
 279  291   * Removes node from the tree and frees the treenode struct.
 280  292   * Does not free structures pointed by tree_exi and tree_vis,
 281  293   * they should be already freed.
 282  294   */
 283  295  static void
 284      -tree_remove_node(treenode_t *node)
      296 +tree_remove_node(nfs_export_t *ne, treenode_t *node)
 285  297  {
 286  298          treenode_t *parent = node->tree_parent;
 287  299          treenode_t *s; /* s for sibling */
 288  300  
 289  301          if (parent == NULL) {
 290  302                  kmem_free(node, sizeof (*node));
 291      -                ns_root = NULL;
      303 +                ne->ns_root = NULL;
 292  304                  return;
 293  305          }
 294  306          /* This node is first child */
 295  307          if (parent->tree_child_first == node) {
 296  308                  parent->tree_child_first = node->tree_sibling;
 297  309          /* This node is not first child */
 298  310          } else {
 299  311                  s = parent->tree_child_first;
 300  312                  while (s->tree_sibling != node)
 301  313                          s = s->tree_sibling;
 302  314                  s->tree_sibling = s->tree_sibling->tree_sibling;
 303  315          }
 304  316          kmem_free(node, sizeof (*node));
 305  317  }
 306  318  
 307  319  /*
 308  320   * When we export a new directory we need to add a new
 309  321   * path segment through the pseudofs to reach the new
 310  322   * directory. This new path is reflected in a list of
 311  323   * directories added to the "visible" list.
 312  324   *
 313  325   * Here there are two lists of visible fids: one hanging off the
 314  326   * pseudo exportinfo, and the one we want to add.  It's possible
 315  327   * that the two lists share a common path segment
 316  328   * and have some common directories.  We need to combine
 317  329   * the lists so there's no duplicate entries. Where a common
 318  330   * path component is found, the vis_count field is bumped.
 319  331   *
 320  332   * This example shows that the treenode chain (tree_head) and
 321  333   * exp_visible chain (vis_head) can differ in length. The latter
 322  334   * can be shorter. The outer loop must loop over the vis_head chain.
 323  335   *
 324  336   * share /x/a
 325  337   * mount -F ufs /dev/dsk/... /x/y
 326  338   * mkdir -p /x/y/a/b
 327  339   * share  /x/y/a/b
 328  340   *
 329  341   * When more_visible() is called during the second share,
 330  342   * the existing namespace is following:
 331  343   *                                   exp_visible_t
 332  344   *   treenode_t       exportinfo_t      v0     v1
 333  345   * ns_root+---+        +------------+  +---+  +---+
 334  346   *      t0| / |........| E0 pseudo  |->| x |->| a |
 335  347   *        +---+        +------------+  +---+  +---+
 336  348   *          |                           /    /
 337  349   *        +---+                        /    /
 338  350   *      t1| x |------------------------    /
 339  351   *        +---+                           /
 340  352   *          |                            /
 341  353   *        +---+                         /
 342  354   *      t2| a |-------------------------
 343  355   *        +---+........+------------+
 344  356   *                     | E1 real    |
 345  357   *                     +------------+
 346  358   *
 347  359   * This is being added:
 348  360   *
 349  361   *    tree_head  vis_head
 350  362   *        +---+  +---+
 351  363   *      t3| x |->| x |v2
 352  364   *        +---+  +---+
 353  365   *          |      |
 354  366   *        +---+  +---+                     v4     v5
 355  367   *      t4| y |->| y |v3  +------------+  +---+  +---+
 356  368   *        +---+\ +---+    | E2 pseudo  |->| a |->| b |
 357  369   *          |   \....... >+------------+  +---+  +---+
 358  370   *        +---+                           /      /
 359  371   *      t5| a |---------------------------      /
 360  372   *        +---+                                /
 361  373   *          |                                 /
 362  374   *        +---+-------------------------------
 363  375   *      t6| b |           +------------+
 364  376   *        +---+..........>| E3 real    |
 365  377   *                        +------------+
 366  378   *
 367  379   * more_visible() will:
 368  380   * - kmem_free() t3 and v2
 369  381   * - add t4, t5, t6 as a child of t1 (t4 will become sibling of t2)
 370  382   * - add v3 to the end of E0->exi_visible
 371  383   *
 372  384   * Note that v4 and v5 were already processed in pseudo_exportfs() and
 373  385   * added to E2. The outer loop of more_visible() will loop only over v2
 374  386   * and v3. The inner loop of more_visible() always loops over v0 and v1.
 375  387   *
 376  388   * Illustration for this scenario:
 377  389   *
 378  390   * mkdir -p /v/a/b/c
 379  391   * share /v/a/b/c
 380  392   * mkdir /v/a/b/c1
 381  393   * mkdir -p /v/a1
 382  394   * mv /v/a/b /v/a1
 383  395   * share /v/a1/b/c1
 384  396   *
 385  397   *           EXISTING
 386  398   *           treenode
 387  399   *           namespace:    +-----------+   visibles
 388  400   *                         |exportinfo |-->v->a->b->c
 389  401   * connect_point->+---+--->+-----------+
 390  402   *                | / |T0
 391  403   *                +---+
 392  404   *                  |                            NEW treenode chain:
 393  405   *         child->+---+
 394  406   *                | v |T1                          +---+<-curr
 395  407   *                +---+                          N1| v |
 396  408   *                  |                              +---+
 397  409   *                +---+                              |
 398  410   *                | a |T2                          +---+<-tree_head
 399  411   *                +---+                          N2| a1|
 400  412   *                  |                              +---+
 401  413   *                +---+                              |
 402  414   *                | b |T3                          +---+
 403  415   *                +---+                          N3| b |
 404  416   *                  |                              +---+
 405  417   *                +---+                              |
 406  418   *                | c |T4                          +---+
 407  419   *                +---+                          N4| c1|
 408  420   *                                                 +---+
 409  421   *
 410  422   * The picture above illustrates the position of following pointers after line
 411  423   * 'child = tree_find_child_by_vis(connect_point, curr->tree_vis);'
 412  424   * was executed for the first time in the outer 'for' loop:
 413  425   *
 414  426   * connect_point..parent treenode in the EXISTING namespace to which the 'curr'
 415  427   *                should be connected. If 'connect_point' already has a child
 416  428   *                with the same value of tree_vis as the curr->tree_vis is,
 417  429   *                the 'curr' will not be added, but kmem_free()d.
 418  430   * child..........the result of tree_find_child_by_vis()
 419  431   * curr...........currently processed treenode from the NEW treenode chain
 420  432   * tree_head......current head of the NEW treenode chain, in this case it was
 421  433   *                already moved down to its child - preparation for another loop
 422  434   *
 423  435   * What will happen to NEW treenodes N1, N2, N3, N4 in more_visible() later:
 424  436   *
 425  437   * N1: is merged - i.e. N1 is kmem_free()d. T0 has a child T1 with the same
 426  438   *     tree_vis as N1
 427  439   * N2: is added as a new child of T1
 428  440   *     Note: not just N2, but the whole chain N2->N3->N4 is added
 429  441   * N3: not processed separately (it was added together with N2)
  
    | 
      ↓ open down ↓ | 
    128 lines elided | 
    
      ↑ open up ↑ | 
  
 430  442   *     Even that N3 and T3 have same tree_vis, they are NOT merged, but will
 431  443   *     become duplicates.
 432  444   * N4: not processed separately
 433  445   */
 434  446  static void
 435  447  more_visible(struct exportinfo *exi, treenode_t *tree_head)
 436  448  {
 437  449          struct exp_visible *vp1, *vp2, *vis_head, *tail, *next;
 438  450          int found;
 439  451          treenode_t *child, *curr, *connect_point;
      452 +        nfs_export_t *ne = nfs_get_export();
 440  453  
 441  454          vis_head = tree_head->tree_vis;
 442  455          connect_point = exi->exi_tree;
 443  456  
 444  457          /*
 445  458           * If exportinfo doesn't already have a visible
 446  459           * list just assign the entire supplied list.
 447  460           */
 448  461          if (exi->exi_visible == NULL) {
 449  462                  tree_add_child(connect_point, tree_head);
 450  463                  exi->exi_visible = vis_head;
 451  464  
 452  465                  /* Update the change timestamp */
 453      -                tree_update_change(connect_point, &vis_head->vis_change);
      466 +                tree_update_change(ne, connect_point, &vis_head->vis_change);
 454  467  
 455  468                  return;
 456  469          }
 457  470  
 458  471          /* The outer loop traverses the supplied list. */
 459  472          for (vp1 = vis_head; vp1; vp1 = next) {
 460  473                  found = 0;
 461  474                  next = vp1->vis_next;
 462  475  
 463  476                  /* The inner loop searches the exportinfo visible list. */
 464  477                  for (vp2 = exi->exi_visible; vp2; vp2 = vp2->vis_next) {
 465  478                          tail = vp2;
 466  479                          if (EQFID(&vp1->vis_fid, &vp2->vis_fid)) {
 467  480                                  found = 1;
 468  481                                  vp2->vis_count++;
 469  482                                  VN_RELE(vp1->vis_vp);
 470  483                                  /* Transfer vis_exported from vp1 to vp2. */
 471  484                                  if (vp1->vis_exported && !vp2->vis_exported)
 472  485                                          vp2->vis_exported = 1;
 473  486                                  kmem_free(vp1, sizeof (*vp1));
 474  487                                  tree_head->tree_vis = vp2;
 475  488                                  break;
 476  489                          }
 477  490                  }
 478  491  
 479  492                  /* If not found - add to the end of the list */
 480  493                  if (! found) {
 481  494                          tail->vis_next = vp1;
 482  495                          vp1->vis_next = NULL;
 483  496                  }
 484  497  
 485  498                  curr = tree_head;
 486  499                  tree_head = tree_head->tree_child_first;
 487  500  
 488  501                  if (! connect_point) /* No longer merging */
 489  502                          continue;
 490  503                  /*
 491  504                   * The inner loop could set curr->tree_vis to the EXISTING
 492  505                   * exp_visible vp2, so we can search among the children of
 493  506                   * connect_point for the curr->tree_vis. No need for EQFID.
 494  507                   */
 495  508                  child = tree_find_child_by_vis(connect_point, curr->tree_vis);
 496  509  
 497  510                  /*
 498  511                   * Merging cannot be done if a valid child->tree_exi would
 499  512                   * be overwritten by a new curr->tree_exi.
 500  513                   */
 501  514                  if (child &&
 502  515                      (child->tree_exi == NULL || curr->tree_exi == NULL)) {
  
    | 
      ↓ open down ↓ | 
    39 lines elided | 
    
      ↑ open up ↑ | 
  
 503  516                          if (curr->tree_exi) { /* Transfer the exportinfo */
 504  517                                  child->tree_exi = curr->tree_exi;
 505  518                                  child->tree_exi->exi_tree = child;
 506  519                          }
 507  520                          kmem_free(curr, sizeof (treenode_t));
 508  521                          connect_point = child;
 509  522                  } else { /* Branching */
 510  523                          tree_add_child(connect_point, curr);
 511  524  
 512  525                          /* Update the change timestamp */
 513      -                        tree_update_change(connect_point,
      526 +                        tree_update_change(ne, connect_point,
 514  527                              &curr->tree_vis->vis_change);
 515  528  
 516  529                          connect_point = NULL;
 517  530                  }
 518  531          }
 519  532  }
 520  533  
 521  534  /*
 522  535   * Remove one visible entry from the pseudo exportfs.
 523  536   *
 524  537   * When we unexport a directory, we have to remove path
 525  538   * components from the visible list in the pseudo exportfs
 526  539   * entry. The supplied visible contains one fid of one path
 527  540   * component. The visible list of the export
 528  541   * is checked against provided visible, matching fid has its
 529  542   * reference count decremented.  If a reference count drops to
 530  543   * zero, then it means no paths now use this directory, so its
 531  544   * fid can be removed from the visible list.
 532  545   *
 533  546   * When the last path is removed, the visible list will be null.
 534  547   */
 535  548  static void
 536  549  less_visible(struct exportinfo *exi, struct exp_visible *vp1)
 537  550  {
 538  551          struct exp_visible *vp2;
 539  552          struct exp_visible *prev, *next;
 540  553  
 541  554          for (vp2 = exi->exi_visible, prev = NULL; vp2; vp2 = next) {
 542  555  
 543  556                  next = vp2->vis_next;
 544  557  
 545  558                  if (vp1 == vp2) {
 546  559                          /*
 547  560                           * Decrement the ref count.
 548  561                           * Remove the entry if it's zero.
 549  562                           */
 550  563                          if (--vp2->vis_count <= 0) {
 551  564                                  if (prev == NULL)
 552  565                                          exi->exi_visible = next;
 553  566                                  else
 554  567                                          prev->vis_next = next;
 555  568                                  VN_RELE(vp2->vis_vp);
 556  569                                  srv_secinfo_list_free(vp2->vis_secinfo,
 557  570                                      vp2->vis_seccnt);
 558  571                                  kmem_free(vp2, sizeof (*vp1));
 559  572                          }
 560  573                          break;
 561  574                  }
 562  575                  prev = vp2;
 563  576          }
 564  577  }
 565  578  
 566  579  /*
 567  580   * This function checks the path to a new export to
 568  581   * check whether all the pathname components are
 569  582   * exported. It works by climbing the file tree one
 570  583   * component at a time via "..", crossing mountpoints
 571  584   * if necessary until an export entry is found, or the
 572  585   * system root is reached.
 573  586   *
 574  587   * If an unexported mountpoint is found, then
 575  588   * a new pseudo export is added and the pathname from
 576  589   * the mountpoint down to the export is added to the
 577  590   * visible list for the new pseudo export.  If an existing
 578  591   * pseudo export is found, then the pathname is added
 579  592   * to its visible list.
 580  593   *
 581  594   * Note that there's some tests for exportdir.
 582  595   * The exportinfo entry that's passed as a parameter
 583  596   * is that of the real export and exportdir is set
 584  597   * for this case.
 585  598   *
 586  599   * Here is an example of a possible setup:
 587  600   *
 588  601   * () - a new fs; fs mount point
 589  602   * EXPORT - a real exported node
 590  603   * PSEUDO - a pseudo node
 591  604   * vis - visible list
 592  605   * f# - security flavor#
 593  606   * (f#) - security flavor# propagated from its descendents
 594  607   * "" - covered vnode
 595  608   *
 596  609   *
 597  610   *                 /
 598  611   *                 |
 599  612   *                 (a) PSEUDO (f1,f2)
 600  613   *                 |   vis: b,b,"c","n"
 601  614   *                 |
 602  615   *                 b
 603  616   *        ---------|------------------
 604  617   *        |                          |
 605  618   *        (c) EXPORT,f1(f2)          (n) PSEUDO (f1,f2)
 606  619   *        |   vis: "e","d"           |   vis: m,m,,p,q,"o"
 607  620   *        |                          |
 608  621   *  ------------------          -------------------
 609  622   *  |        |        |         |                  |
 610  623   *  (d)      (e)      f         m EXPORT,f1(f2)    p
 611  624   *  EXPORT   EXPORT             |                  |
 612  625   *  f1       f2                 |                  |
 613  626   *           |                  |                  |
 614  627   *           j                 (o) EXPORT,f2       q EXPORT f2
 615  628   *
 616  629   */
 617  630  int
 618  631  treeclimb_export(struct exportinfo *exip)
 619  632  {
  
    | 
      ↓ open down ↓ | 
    96 lines elided | 
    
      ↑ open up ↑ | 
  
 620  633          vnode_t *dvp, *vp;
 621  634          fid_t fid;
 622  635          int error;
 623  636          int exportdir;
 624  637          struct exportinfo *new_exi = exip;
 625  638          struct exp_visible *visp;
 626  639          struct exp_visible *vis_head = NULL;
 627  640          struct vattr va;
 628  641          treenode_t *tree_head = NULL;
 629  642          timespec_t now;
      643 +        nfs_export_t *ne;
 630  644  
 631      -        ASSERT(RW_WRITE_HELD(&exported_lock));
      645 +        ne = exip->exi_ne;
      646 +        ASSERT3P(ne, ==, nfs_get_export());     /* curzone reality check */
      647 +        ASSERT(RW_WRITE_HELD(&ne->exported_lock));
 632  648  
 633  649          gethrestime(&now);
 634  650  
 635  651          vp = exip->exi_vp;
 636  652          VN_HOLD(vp);
 637  653          exportdir = 1;
 638  654  
 639  655          for (;;) {
 640  656  
 641  657                  bzero(&fid, sizeof (fid));
 642  658                  fid.fid_len = MAXFIDSZ;
 643  659                  error = vop_fid_pseudo(vp, &fid);
 644  660                  if (error)
 645  661                          break;
 646  662  
      663 +                /* XXX KEBE ASKS DO WE NEED THIS?!? */
      664 +                ASSERT3U(exip->exi_zoneid, ==, curzone->zone_id);
 647  665                  /*
 648      -                 * 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
 649  668                   */
 650      -                if (vp->v_flag & VROOT) {
 651      -                        if (! exportdir) {
      669 +                if (vp->v_flag & VROOT || vp == EXI_TO_ZONEROOTVP(exip)) {
      670 +                        if (!exportdir) {
 652  671                                  struct exportinfo *exi;
 653  672  
 654  673                                  /*
 655  674                                   * Check if this VROOT dir is already exported.
 656  675                                   * If so, then attach the pseudonodes.  If not,
 657  676                                   * then continue .. traversal until we hit a
 658  677                                   * VROOT export (pseudo or real).
 659  678                                   */
 660  679                                  exi = checkexport4(&vp->v_vfsp->vfs_fsid, &fid,
 661  680                                      vp);
 662  681                                  if (exi != NULL) {
 663  682                                          /*
 664  683                                           * Found an export info
 665  684                                           *
 666  685                                           * Extend the list of visible
 667  686                                           * directories whether it's a pseudo
 668  687                                           * or a real export.
 669  688                                           */
  
    | 
      ↓ open down ↓ | 
    8 lines elided | 
    
      ↑ open up ↑ | 
  
 670  689                                          more_visible(exi, tree_head);
 671  690                                          break;  /* and climb no further */
 672  691                                  }
 673  692  
 674  693                                  /*
 675  694                                   * Found the root directory of a filesystem
 676  695                                   * that isn't exported.  Need to export
 677  696                                   * this as a pseudo export so that an NFS v4
 678  697                                   * client can do lookups in it.
 679  698                                   */
 680      -                                new_exi = pseudo_exportfs(vp, &fid, vis_head,
 681      -                                    NULL);
      699 +                                new_exi = pseudo_exportfs(ne, vp, &fid,
      700 +                                    vis_head, NULL);
 682  701                                  vis_head = NULL;
 683  702                          }
 684  703  
 685      -                        if (VN_CMP(vp, rootdir)) {
      704 +                        if (VN_IS_CURZONEROOT(vp)) {
 686  705                                  /* at system root */
 687  706                                  /*
 688  707                                   * If sharing "/", new_exi is shared exportinfo
 689  708                                   * (exip). Otherwise, new_exi is exportinfo
 690  709                                   * created by pseudo_exportfs() above.
 691  710                                   */
 692      -                                ns_root = tree_prepend_node(tree_head, NULL,
      711 +                                ne->ns_root = tree_prepend_node(tree_head, NULL,
 693  712                                      new_exi);
 694  713  
 695  714                                  /* Update the change timestamp */
 696      -                                tree_update_change(ns_root, &now);
      715 +                                tree_update_change(ne, ne->ns_root, &now);
 697  716  
 698  717                                  break;
 699  718                          }
 700  719  
 701  720                          /*
 702  721                           * Traverse across the mountpoint and continue the
 703  722                           * climb on the mounted-on filesystem.
 704  723                           */
 705      -                        vp = untraverse(vp);
      724 +                        vp = untraverse(vp, ne->exi_root->exi_vp);
 706  725                          exportdir = 0;
 707  726                          continue;
 708  727                  }
 709  728  
 710  729                  /*
 711  730                   * Do a getattr to obtain the nodeid (inode num)
 712  731                   * for this vnode.
 713  732                   */
 714  733                  va.va_mask = AT_NODEID;
 715  734                  error = VOP_GETATTR(vp, &va, 0, CRED(), NULL);
 716  735                  if (error)
 717  736                          break;
 718  737  
 719  738                  /*
 720  739                   *  Add this directory fid to visible list
 721  740                   */
 722  741                  visp = kmem_alloc(sizeof (*visp), KM_SLEEP);
 723  742                  VN_HOLD(vp);
 724  743                  visp->vis_vp = vp;
 725  744                  visp->vis_fid = fid;            /* structure copy */
 726  745                  visp->vis_ino = va.va_nodeid;
 727  746                  visp->vis_count = 1;
 728  747                  visp->vis_exported = exportdir;
 729  748                  visp->vis_secinfo = NULL;
 730  749                  visp->vis_seccnt = 0;
 731  750                  visp->vis_change = now;         /* structure copy */
 732  751                  visp->vis_next = vis_head;
 733  752                  vis_head = visp;
 734  753  
 735  754                  /*
 736  755                   * Will set treenode's pointer to exportinfo to
 737  756                   * 1. shared exportinfo (exip) - if first visit here
 738  757                   * 2. freshly allocated pseudo export (if any)
 739  758                   * 3. null otherwise
 740  759                   */
 741  760                  tree_head = tree_prepend_node(tree_head, visp, new_exi);
 742  761                  new_exi = NULL;
 743  762  
 744  763                  /*
 745  764                   * Now, do a ".." to find parent dir of vp.
 746  765                   */
 747  766                  error = VOP_LOOKUP(vp, "..", &dvp, NULL, 0, NULL, CRED(),
 748  767                      NULL, NULL, NULL);
 749  768  
 750  769                  if (error == ENOTDIR && exportdir) {
 751  770                          dvp = exip->exi_dvp;
 752  771                          ASSERT(dvp != NULL);
 753  772                          VN_HOLD(dvp);
 754  773                          error = 0;
 755  774                  }
 756  775  
 757  776                  if (error)
 758  777                          break;
 759  778  
 760  779                  exportdir = 0;
 761  780                  VN_RELE(vp);
 762  781                  vp = dvp;
 763  782          }
 764  783  
 765  784          VN_RELE(vp);
 766  785  
 767  786          /*
 768  787           * We can have set error due to error in:
 769  788           * 1. vop_fid_pseudo()
 770  789           * 2. VOP_GETATTR()
 771  790           * 3. VOP_LOOKUP()
 772  791           * We must free pseudo exportinfos, visibles and treenodes.
 773  792           * Visibles are referenced from treenode_t::tree_vis and
 774  793           * exportinfo_t::exi_visible. To avoid double freeing, only
 775  794           * exi_visible pointer is used, via exi_rele(), for the clean-up.
 776  795           */
 777  796          if (error) {
 778  797                  /* Free unconnected visibles, if there are any. */
 779  798                  if (vis_head)
 780  799                          free_visible(vis_head);
  
    | 
      ↓ open down ↓ | 
    65 lines elided | 
    
      ↑ open up ↑ | 
  
 781  800  
 782  801                  /* Connect unconnected exportinfo, if there is any. */
 783  802                  if (new_exi && new_exi != exip)
 784  803                          tree_head = tree_prepend_node(tree_head, NULL, new_exi);
 785  804  
 786  805                  while (tree_head) {
 787  806                          treenode_t *t2 = tree_head;
 788  807                          exportinfo_t *e  = tree_head->tree_exi;
 789  808                          /* exip will be freed in exportfs() */
 790  809                          if (e && e != exip) {
 791      -                                export_unlink(e);
      810 +                                mutex_enter(&nfs_exi_id_lock);
      811 +                                avl_remove(&exi_id_tree, e);
      812 +                                mutex_exit(&nfs_exi_id_lock);
      813 +                                export_unlink(ne, e);
 792  814                                  exi_rele(e);
 793  815                          }
 794  816                          tree_head = tree_head->tree_child_first;
 795  817                          kmem_free(t2, sizeof (*t2));
 796  818                  }
 797  819          }
 798  820  
 799  821          return (error);
 800  822  }
 801  823  
 802  824  /*
 803  825   * Walk up the tree and:
 804  826   * 1. release pseudo exportinfo if it has no child
 805  827   * 2. release visible in parent's exportinfo
 806  828   * 3. delete non-exported leaf nodes from tree
 807  829   *
 808  830   * Deleting of nodes will start only if the unshared
 809  831   * node was a leaf node.
 810  832   * Deleting of nodes will finish when we reach a node which
 811  833   * has children or is a real export, then we might still need
 812      - * to continue releasing visibles, until we reach VROOT node.
      834 + * to continue releasing visibles, until we reach VROOT or zone's root node.
 813  835   */
 814  836  void
 815      -treeclimb_unexport(struct exportinfo *exip)
      837 +treeclimb_unexport(nfs_export_t *ne, struct exportinfo *exip)
 816  838  {
 817  839          treenode_t *tnode, *old_nd;
 818  840          treenode_t *connect_point = NULL;
 819  841  
 820      -        ASSERT(RW_WRITE_HELD(&exported_lock));
      842 +        ASSERT(RW_WRITE_HELD(&ne->exported_lock));
      843 +        ASSERT(curzone->zone_id == exip->exi_zoneid ||
      844 +            curzone->zone_id == global_zone->zone_id);
 821  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 +         */
 822  851          tnode = exip->exi_tree;
      852 +        if (tnode == NULL) {
      853 +                /* Should only happen for... */
      854 +                ASSERT(exip == ne->exi_root);
      855 +                return;
      856 +        }
      857 +
 823  858          /*
 824  859           * The unshared exportinfo was unlinked in unexport().
 825  860           * Zeroing tree_exi ensures that we will skip it.
 826  861           */
 827  862          tnode->tree_exi = NULL;
 828  863  
 829  864          if (tnode->tree_vis != NULL) /* system root has tree_vis == NULL */
 830  865                  tnode->tree_vis->vis_exported = 0;
 831  866  
 832  867          while (tnode != NULL) {
 833  868  
 834      -                /* 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 +                 */
 835  873                  if (TREE_ROOT(tnode) &&
 836  874                      (TREE_EXPORTED(tnode) || tnode->tree_child_first != NULL))
 837  875                          break;
 838  876  
 839  877                  /* Release pseudo export if it has no child */
 840  878                  if (TREE_ROOT(tnode) && !TREE_EXPORTED(tnode) &&
 841  879                      tnode->tree_child_first == NULL) {
 842      -                        export_unlink(tnode->tree_exi);
      880 +                        mutex_enter(&nfs_exi_id_lock);
      881 +                        avl_remove(&exi_id_tree, tnode->tree_exi);
      882 +                        mutex_exit(&nfs_exi_id_lock);
      883 +                        export_unlink(ne, tnode->tree_exi);
 843  884                          exi_rele(tnode->tree_exi);
      885 +                        tnode->tree_exi = NULL;
 844  886                  }
 845  887  
 846  888                  /* Release visible in parent's exportinfo */
 847  889                  if (tnode->tree_vis != NULL)
 848  890                          less_visible(vis2exi(tnode), tnode->tree_vis);
 849  891  
 850  892                  /* Continue with parent */
 851  893                  old_nd = tnode;
 852  894                  tnode = tnode->tree_parent;
 853  895  
 854  896                  /* Remove itself, if this is a leaf and non-exported node */
 855  897                  if (old_nd->tree_child_first == NULL &&
 856  898                      !TREE_EXPORTED(old_nd)) {
 857      -                        tree_remove_node(old_nd);
      899 +                        tree_remove_node(ne, old_nd);
 858  900                          connect_point = tnode;
 859  901                  }
 860  902          }
 861  903  
 862  904          /* Update the change timestamp */
 863  905          if (connect_point != NULL)
 864      -                tree_update_change(connect_point, NULL);
      906 +                tree_update_change(ne, connect_point, NULL);
 865  907  }
 866  908  
 867  909  /*
 868  910   * Traverse backward across mountpoint from the
 869  911   * root vnode of a filesystem to its mounted-on
 870  912   * vnode.
 871  913   */
 872  914  vnode_t *
 873      -untraverse(vnode_t *vp)
      915 +untraverse(vnode_t *vp, vnode_t *zone_rootvp)
 874  916  {
 875  917          vnode_t *tvp, *nextvp;
 876  918  
 877  919          tvp = vp;
 878  920          for (;;) {
 879      -                if (! (tvp->v_flag & VROOT))
      921 +                if (!(tvp->v_flag & VROOT) && !VN_CMP(tvp, zone_rootvp))
 880  922                          break;
 881  923  
 882  924                  /* lock vfs to prevent unmount of this vfs */
 883  925                  vfs_lock_wait(tvp->v_vfsp);
 884  926  
 885  927                  if ((nextvp = tvp->v_vfsp->vfs_vnodecovered) == NULL) {
 886  928                          vfs_unlock(tvp->v_vfsp);
 887  929                          break;
 888  930                  }
 889  931  
 890  932                  /*
 891  933                   * Hold nextvp to prevent unmount.  After unlock vfs and
 892  934                   * rele tvp, any number of overlays could be unmounted.
 893  935                   * Putting a hold on vfs_vnodecovered will only allow
 894  936                   * tvp's vfs to be unmounted. Of course if caller placed
 895  937                   * extra hold on vp before calling untraverse, the following
 896  938                   * hold would not be needed.  Since prev actions of caller
 897  939                   * are unknown, we need to hold here just to be safe.
 898  940                   */
 899  941                  VN_HOLD(nextvp);
  
    | 
      ↓ open down ↓ | 
    10 lines elided | 
    
      ↑ open up ↑ | 
  
 900  942                  vfs_unlock(tvp->v_vfsp);
 901  943                  VN_RELE(tvp);
 902  944                  tvp = nextvp;
 903  945          }
 904  946  
 905  947          return (tvp);
 906  948  }
 907  949  
 908  950  /*
 909  951   * Given an exportinfo, climb up to find the exportinfo for the VROOT
 910      - * of the filesystem.
      952 + * (or zone root) of the filesystem.
 911  953   *
 912  954   * e.g.         /
 913  955   *              |
 914  956   *              a (VROOT) pseudo-exportinfo
 915  957   *              |
 916  958   *              b
 917  959   *              |
 918  960   *              c  #share /a/b/c
 919  961   *              |
 920  962   *              d
 921  963   *
 922  964   * where c is in the same filesystem as a.
 923  965   * So, get_root_export(*exportinfo_for_c) returns exportinfo_for_a
 924  966   *
 925  967   * If d is shared, then c will be put into a's visible list.
 926  968   * Note: visible list is per filesystem and is attached to the
 927      - * VROOT exportinfo.
      969 + * VROOT exportinfo.  Returned exi does NOT have a new hold.
 928  970   */
 929  971  struct exportinfo *
 930  972  get_root_export(struct exportinfo *exip)
 931  973  {
 932  974          treenode_t *tnode = exip->exi_tree;
 933  975          exportinfo_t *exi = NULL;
 934  976  
 935  977          while (tnode) {
 936  978                  if (TREE_ROOT(tnode)) {
 937  979                          exi = tnode->tree_exi;
 938  980                          break;
 939  981                  }
 940  982                  tnode = tnode->tree_parent;
 941  983          }
 942  984          ASSERT(exi);
 943  985          return (exi);
 944  986  }
 945  987  
 946  988  /*
 947  989   * Return true if the supplied vnode has a sub-directory exported.
 948  990   */
  
    | 
      ↓ open down ↓ | 
    11 lines elided | 
    
      ↑ open up ↑ | 
  
 949  991  int
 950  992  has_visible(struct exportinfo *exi, vnode_t *vp)
 951  993  {
 952  994          struct exp_visible *visp;
 953  995          fid_t fid;
 954  996          bool_t vp_is_exported;
 955  997  
 956  998          vp_is_exported = VN_CMP(vp, exi->exi_vp);
 957  999  
 958 1000          /*
 959      -         * An exported root vnode has a sub-dir shared if it has a visible list.
 960      -         * i.e. if it does not have a visible list, then there is no node in
 961      -         * this filesystem leads to any other shared node.
     1001 +         * An exported root vnode has a sub-dir shared if it has a visible
     1002 +         * list.  i.e. if it does not have a visible list, then there is no
     1003 +         * node in this filesystem leads to any other shared node.
 962 1004           */
 963      -        if (vp_is_exported && (vp->v_flag & VROOT))
     1005 +        ASSERT3P(curzone->zone_id, ==, exi->exi_zoneid);
     1006 +        if (vp_is_exported &&
     1007 +            ((vp->v_flag & VROOT) || VN_IS_CURZONEROOT(vp))) {
 964 1008                  return (exi->exi_visible ? 1 : 0);
     1009 +        }
 965 1010  
 966 1011          /*
 967 1012           * Only the exportinfo of a fs root node may have a visible list.
 968 1013           * Either it is a pseudo root node, or a real exported root node.
 969 1014           */
 970 1015          exi = get_root_export(exi);
 971 1016  
 972 1017          if (!exi->exi_visible)
 973 1018                  return (0);
 974 1019  
 975 1020          /* Get the fid of the vnode */
 976 1021          bzero(&fid, sizeof (fid));
 977 1022          fid.fid_len = MAXFIDSZ;
 978 1023          if (vop_fid_pseudo(vp, &fid) != 0) {
 979 1024                  return (0);
 980 1025          }
 981 1026  
 982 1027          /*
 983 1028           * See if vp is in the visible list of the root node exportinfo.
 984 1029           */
 985 1030          for (visp = exi->exi_visible; visp; visp = visp->vis_next) {
 986 1031                  if (EQFID(&fid, &visp->vis_fid)) {
 987 1032                          /*
 988 1033                           * If vp is an exported non-root node with only 1 path
 989 1034                           * count (for itself), it indicates no sub-dir shared
 990 1035                           * using this vp as a path.
 991 1036                           */
 992 1037                          if (vp_is_exported && visp->vis_count < 2)
 993 1038                                  break;
 994 1039  
 995 1040                          return (1);
 996 1041                  }
 997 1042          }
 998 1043  
 999 1044          return (0);
1000 1045  }
1001 1046  
1002 1047  /*
1003 1048   * Returns true if the supplied vnode is visible
1004 1049   * in this export.  If vnode is visible, return
1005 1050   * vis_exported in expseudo.
1006 1051   */
1007 1052  int
1008 1053  nfs_visible(struct exportinfo *exi, vnode_t *vp, int *expseudo)
1009 1054  {
1010 1055          struct exp_visible *visp;
1011 1056          fid_t fid;
1012 1057  
1013 1058          /*
1014 1059           * First check to see if vp is export root.
1015 1060           *
1016 1061           * A pseudo export root can never be exported
1017 1062           * (it would be a real export then); however,
1018 1063           * it is always visible.  If a pseudo root object
1019 1064           * was exported by server admin, then the entire
1020 1065           * pseudo exportinfo (and all visible entries) would
1021 1066           * be destroyed.  A pseudo exportinfo only exists
1022 1067           * to provide access to real (descendant) export(s).
1023 1068           *
1024 1069           * Previously, rootdir was special cased here; however,
1025 1070           * the export root special case handles the rootdir
1026 1071           * case also.
  
    | 
      ↓ open down ↓ | 
    52 lines elided | 
    
      ↑ open up ↑ | 
  
1027 1072           */
1028 1073          if (VN_CMP(vp, exi->exi_vp)) {
1029 1074                  *expseudo = 0;
1030 1075                  return (1);
1031 1076          }
1032 1077  
1033 1078          /*
1034 1079           * Only a PSEUDO node has a visible list or an exported VROOT
1035 1080           * node may have a visible list.
1036 1081           */
1037      -        if (! PSEUDO(exi))
     1082 +        if (!PSEUDO(exi))
1038 1083                  exi = get_root_export(exi);
1039 1084  
1040 1085          /* Get the fid of the vnode */
1041 1086  
1042 1087          bzero(&fid, sizeof (fid));
1043 1088          fid.fid_len = MAXFIDSZ;
1044 1089          if (vop_fid_pseudo(vp, &fid) != 0) {
1045 1090                  *expseudo = 0;
1046 1091                  return (0);
1047 1092          }
1048 1093  
1049 1094          /*
1050 1095           * We can't trust VN_CMP() above because of LOFS.
1051 1096           * Even though VOP_CMP will do the right thing for LOFS
1052 1097           * objects, VN_CMP will short circuit out early when the
1053 1098           * vnode ops ptrs are different.  Just in case we're dealing
1054 1099           * with LOFS, compare exi_fid/fsid here.
1055 1100           *
1056 1101           * expseudo is not set because this is not an export
1057 1102           */
1058 1103          if (EQFID(&exi->exi_fid, &fid) &&
1059 1104              EQFSID(&exi->exi_fsid, &vp->v_vfsp->vfs_fsid)) {
1060 1105                  *expseudo = 0;
1061 1106                  return (1);
1062 1107          }
1063 1108  
1064 1109  
1065 1110          /* See if it matches any fid in the visible list */
1066 1111  
1067 1112          for (visp = exi->exi_visible; visp; visp = visp->vis_next) {
1068 1113                  if (EQFID(&fid, &visp->vis_fid)) {
1069 1114                          *expseudo = visp->vis_exported;
1070 1115                          return (1);
1071 1116                  }
1072 1117          }
1073 1118  
1074 1119          *expseudo = 0;
1075 1120  
1076 1121          return (0);
1077 1122  }
1078 1123  
1079 1124  /*
1080 1125   * Returns true if the supplied vnode is the
1081 1126   * directory of an export point.
1082 1127   */
1083 1128  int
1084 1129  nfs_exported(struct exportinfo *exi, vnode_t *vp)
1085 1130  {
1086 1131          struct exp_visible *visp;
1087 1132          fid_t fid;
1088 1133  
1089 1134          /*
1090 1135           * First check to see if vp is the export root
1091 1136           * This check required for the case of lookup ..
1092 1137           * where .. is a V_ROOT vnode and a pseudo exportroot.
1093 1138           * Pseudo export root objects do not have an entry
1094 1139           * in the visible list even though every V_ROOT
1095 1140           * pseudonode is visible.  It is safe to compare
1096 1141           * vp here because pseudo_exportfs put a hold on
1097 1142           * it when exi_vp was initialized.
1098 1143           *
1099 1144           * Note: VN_CMP() won't match for LOFS shares, but they're
1100 1145           * handled below w/EQFID/EQFSID.
1101 1146           */
1102 1147          if (VN_CMP(vp, exi->exi_vp))
1103 1148                  return (1);
1104 1149  
1105 1150          /* Get the fid of the vnode */
1106 1151  
1107 1152          bzero(&fid, sizeof (fid));
1108 1153          fid.fid_len = MAXFIDSZ;
1109 1154          if (vop_fid_pseudo(vp, &fid) != 0)
1110 1155                  return (0);
1111 1156  
1112 1157          if (EQFID(&fid, &exi->exi_fid) &&
1113 1158              EQFSID(&vp->v_vfsp->vfs_fsid, &exi->exi_fsid)) {
1114 1159                  return (1);
1115 1160          }
1116 1161  
1117 1162          /* See if it matches any fid in the visible list */
1118 1163  
1119 1164          for (visp = exi->exi_visible; visp; visp = visp->vis_next) {
1120 1165                  if (EQFID(&fid, &visp->vis_fid))
1121 1166                          return (visp->vis_exported);
1122 1167          }
1123 1168  
1124 1169          return (0);
1125 1170  }
1126 1171  
1127 1172  /*
1128 1173   * Returns true if the supplied inode is visible
1129 1174   * in this export.  This function is used by
1130 1175   * readdir which uses inode numbers from the
1131 1176   * directory.
1132 1177   *
1133 1178   * NOTE: this code does not match inode number for ".",
1134 1179   * but it isn't required because NFS4 server rddir
  
    | 
      ↓ open down ↓ | 
    87 lines elided | 
    
      ↑ open up ↑ | 
  
1135 1180   * skips . and .. entries.
1136 1181   */
1137 1182  int
1138 1183  nfs_visible_inode(struct exportinfo *exi, ino64_t ino,
1139 1184      struct exp_visible **visp)
1140 1185  {
1141 1186          /*
1142 1187           * Only a PSEUDO node has a visible list or an exported VROOT
1143 1188           * node may have a visible list.
1144 1189           */
1145      -        if (! PSEUDO(exi))
     1190 +        if (!PSEUDO(exi))
1146 1191                  exi = get_root_export(exi);
1147 1192  
1148 1193          for (*visp = exi->exi_visible; *visp != NULL; *visp = (*visp)->vis_next)
1149 1194                  if ((u_longlong_t)ino == (*visp)->vis_ino) {
1150 1195                          return (1);
1151 1196                  }
1152 1197  
1153 1198          return (0);
1154 1199  }
1155 1200  
1156 1201  /*
1157      - * The change attribute value of the root of nfs pseudo namespace.
1158      - *
1159      - * The ns_root_change is protected by exported_lock because all of the treenode
1160      - * operations are protected by exported_lock too.
1161      - */
1162      -static timespec_t ns_root_change;
1163      -
1164      -/*
1165 1202   * Get the change attribute from visible and returns TRUE.
1166 1203   * If the change value is not available returns FALSE.
1167 1204   */
1168 1205  bool_t
1169 1206  nfs_visible_change(struct exportinfo *exi, vnode_t *vp, timespec_t *change)
1170 1207  {
1171 1208          struct exp_visible *visp;
1172 1209          fid_t fid;
1173 1210          treenode_t *node;
     1211 +        nfs_export_t *ne = nfs_get_export();
1174 1212  
1175 1213          /*
1176 1214           * First check to see if vp is export root.
1177 1215           */
1178 1216          if (VN_CMP(vp, exi->exi_vp))
1179 1217                  goto exproot;
1180 1218  
1181 1219          /*
1182 1220           * Only a PSEUDO node has a visible list or an exported VROOT
1183 1221           * node may have a visible list.
1184 1222           */
1185 1223          if (!PSEUDO(exi))
1186 1224                  exi = get_root_export(exi);
1187 1225  
1188 1226          /* Get the fid of the vnode */
1189 1227          bzero(&fid, sizeof (fid));
1190 1228          fid.fid_len = MAXFIDSZ;
1191 1229          if (vop_fid_pseudo(vp, &fid) != 0)
1192 1230                  return (FALSE);
1193 1231  
1194 1232          /*
1195 1233           * We can't trust VN_CMP() above because of LOFS.
1196 1234           * Even though VOP_CMP will do the right thing for LOFS
1197 1235           * objects, VN_CMP will short circuit out early when the
1198 1236           * vnode ops ptrs are different.  Just in case we're dealing
1199 1237           * with LOFS, compare exi_fid/fsid here.
1200 1238           */
1201 1239          if (EQFID(&exi->exi_fid, &fid) &&
1202 1240              EQFSID(&exi->exi_fsid, &vp->v_vfsp->vfs_fsid))
1203 1241                  goto exproot;
1204 1242  
1205 1243          /* See if it matches any fid in the visible list */
1206 1244          for (visp = exi->exi_visible; visp; visp = visp->vis_next) {
1207 1245                  if (EQFID(&fid, &visp->vis_fid)) {
  
    | 
      ↓ open down ↓ | 
    24 lines elided | 
    
      ↑ open up ↑ | 
  
1208 1246                          *change = visp->vis_change;
1209 1247                          return (TRUE);
1210 1248                  }
1211 1249          }
1212 1250  
1213 1251          return (FALSE);
1214 1252  
1215 1253  exproot:
1216 1254          /* The VROOT export have its visible available through treenode */
1217 1255          node = exi->exi_tree;
1218      -        if (node != ns_root) {
     1256 +        if (node != ne->ns_root) {
1219 1257                  ASSERT(node->tree_vis != NULL);
1220 1258                  *change = node->tree_vis->vis_change;
1221 1259          } else {
1222 1260                  ASSERT(node->tree_vis == NULL);
1223      -                *change = ns_root_change;
     1261 +                *change = ne->ns_root_change;
1224 1262          }
1225      -
1226 1263          return (TRUE);
1227 1264  }
1228 1265  
1229 1266  /*
1230 1267   * Update the change attribute value for a particular treenode.  The change
1231 1268   * attribute value is stored in the visible attached to the treenode, or in the
1232 1269   * ns_root_change.
1233 1270   *
1234 1271   * If the change value is not supplied, the current time is used.
1235 1272   */
1236 1273  void
1237      -tree_update_change(treenode_t *tnode, timespec_t *change)
     1274 +tree_update_change(nfs_export_t *ne, treenode_t *tnode, timespec_t *change)
1238 1275  {
1239 1276          timespec_t *vis_change;
1240 1277  
1241 1278          ASSERT(tnode != NULL);
1242      -        ASSERT((tnode != ns_root && tnode->tree_vis != NULL) ||
1243      -            (tnode == ns_root && tnode->tree_vis == NULL));
     1279 +        ASSERT((tnode != ne->ns_root && tnode->tree_vis != NULL) ||
     1280 +            (tnode == ne->ns_root && tnode->tree_vis == NULL));
1244 1281  
1245      -        vis_change = tnode == ns_root ? &ns_root_change
     1282 +        vis_change = tnode == ne->ns_root ? &ne->ns_root_change
1246 1283              : &tnode->tree_vis->vis_change;
1247 1284  
1248 1285          if (change != NULL)
1249 1286                  *vis_change = *change;
1250 1287          else
1251 1288                  gethrestime(vis_change);
1252 1289  }
    
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX