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
↓ 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  
↓ 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;
↓ 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;
↓ 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;
↓ 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. */
↓ 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   *
↓ 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);
↓ 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);
↓ 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  
↓ 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;
↓ 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  
↓ 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          }
↓ 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.
↓ 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