Print this page
NEX-19996 exi_id_get_next() calls should be WRITER locked
NEX-20014 NFS v4 state lock mutex exited before entered (on error path)
Reviewed by: Sanjay Nadkarni <sanjay.nadkarni@nexenta.com>
Reviewed by: Rick McNeal <rick.mcneal@nexenta.com>
Reviewed by: Joyce McIntosh <joyce.mcintosh@nexenta.com>
NEX-15279 support NFS server in zone
NEX-15520 online NFS shares cause zoneadm halt to hang in nfs_export_zone_fini
Portions contributed by: Dan Kruchinin dan.kruchinin@nexenta.com
Portions contributed by: Stepan Zastupov stepan.zastupov@gmail.com
Reviewed by: Joyce McIntosh <joyce.mcintosh@nexenta.com>
Reviewed by: Rob Gittins <rob.gittins@nexenta.com>
Reviewed by: Gordon Ross <gordon.ross@nexenta.com>
NEX-9275 Got "bad mutex" panic when run IO to nfs share from clients
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>
Reviewed by: Sanjay Nadkarni <sanjay.nadkarni@nexenta.com>
Reviewed by: Rob Gittins <rob.gittins@nexenta.com>
NEX-6778 NFS kstats leak and cause system to hang
Revert "NEX-4261 Per-client NFS server IOPS, bandwidth, and latency kstats"
This reverts commit 586c3ab1927647487f01c337ddc011c642575a52.
Revert "NEX-5354 Aggregated IOPS, bandwidth, and latency kstats for NFS server"
This reverts commit c91d7614da8618ef48018102b077f60ecbbac8c2.
Revert "NEX-5667 nfssrv_stats_flags does not work for aggregated kstats"
This reverts commit 3dcf42618be7dd5f408c327f429c81e07ca08e74.
Revert "NEX-5750 Time values for aggregated NFS server kstats should be normalized"
This reverts commit 1f4d4f901153b0191027969fa4a8064f9d3b9ee1.
Revert "NEX-5942 Panic in rfs4_minorvers_mismatch() with NFSv4.1 client"
This reverts commit 40766417094a162f5e4cc8786c0fa0a7e5871cd9.
Revert "NEX-5752 NFS server: namespace collision in kstats"
This reverts commit ae81e668db86050da8e483264acb0cce0444a132.
Reviewed by: Rob Gittins <rob.gittins@nexenta.com>
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com>
NEX-4261 Per-client NFS server IOPS, bandwidth, and latency kstats
Reviewed by: Kevin Crowe <kevin.crowe@nexenta.com>
Reviewed by: Roman Strashkin <roman.strashkin@nexenta.com>
NEX-3097 IOPS, bandwidth, and latency kstats for NFS server
Reviewed by: Josef 'Jeff' Sipek <josef.sipek@nexenta.com>
NEX-2345 nfsauth_cache_get() could spend a lot of time walking exi_cache
Reviewed by: Gordon Ross <gordon.ross@nexenta.com>

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 ↓ 101 lines elided ↑ open up ↑
 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  145   * a) its export root is VROOT
 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,
      149 +pseudo_exportfs(nfs_export_t *ne, vnode_t *vp, fid_t *fid, struct exp_visible *vis_head,
 147  150      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;
 165  168          exi->exi_volatile_dev = (vfssw[vp->v_vfsp->vfs_fstype].vsw_flag &
↓ open down ↓ 32 lines elided ↑ open up ↑
 198  201                  exi->exi_cache[i] = kmem_alloc(sizeof (avl_tree_t), KM_SLEEP);
 199  202                  avl_create(exi->exi_cache[i], nfsauth_cache_clnt_compar,
 200  203                      sizeof (struct auth_cache_clnt),
 201  204                      offsetof(struct auth_cache_clnt, authc_link));
 202  205          }
 203  206          rw_init(&exi->exi_cache_lock, NULL, RW_DEFAULT, NULL);
 204  207  
 205  208          /*
 206  209           * Insert the new entry at the front of the export list
 207  210           */
 208      -        export_link(exi);
      211 +        export_link(ne, exi);
 209  212  
      213 +        /*
      214 +         * Initialize exi_id and exi_kstats
      215 +         */
      216 +        mutex_enter(&nfs_exi_id_lock);
      217 +        exi->exi_id = exi_id_get_next();
      218 +        avl_add(&exi_id_tree, exi);
      219 +        mutex_exit(&nfs_exi_id_lock);
      220 +        exi->exi_kstats = exp_kstats_init(getzoneid(), exi->exi_id,
      221 +            kex->ex_path, vpathlen, TRUE);
      222 +
 210  223          return (exi);
 211  224  }
 212  225  
 213  226  /*
 214  227   * Free a list of visible directories
 215  228   */
 216  229  void
 217  230  free_visible(struct exp_visible *head)
 218  231  {
 219  232          struct exp_visible *visp, *next;
↓ open down ↓ 54 lines elided ↑ open up ↑
 274  287          }
 275  288          return (tnode);
 276  289  }
 277  290  
 278  291  /*
 279  292   * Removes node from the tree and frees the treenode struct.
 280  293   * Does not free structures pointed by tree_exi and tree_vis,
 281  294   * they should be already freed.
 282  295   */
 283  296  static void
 284      -tree_remove_node(treenode_t *node)
      297 +tree_remove_node(nfs_export_t *ne, treenode_t *node)
 285  298  {
 286  299          treenode_t *parent = node->tree_parent;
 287  300          treenode_t *s; /* s for sibling */
 288  301  
 289  302          if (parent == NULL) {
 290  303                  kmem_free(node, sizeof (*node));
 291      -                ns_root = NULL;
      304 +                ne->ns_root = NULL;
 292  305                  return;
 293  306          }
 294  307          /* This node is first child */
 295  308          if (parent->tree_child_first == node) {
 296  309                  parent->tree_child_first = node->tree_sibling;
 297  310          /* This node is not first child */
 298  311          } else {
 299  312                  s = parent->tree_child_first;
 300  313                  while (s->tree_sibling != node)
 301  314                          s = s->tree_sibling;
↓ open down ↓ 128 lines elided ↑ open up ↑
 430  443   *     Even that N3 and T3 have same tree_vis, they are NOT merged, but will
 431  444   *     become duplicates.
 432  445   * N4: not processed separately
 433  446   */
 434  447  static void
 435  448  more_visible(struct exportinfo *exi, treenode_t *tree_head)
 436  449  {
 437  450          struct exp_visible *vp1, *vp2, *vis_head, *tail, *next;
 438  451          int found;
 439  452          treenode_t *child, *curr, *connect_point;
      453 +        nfs_export_t *ne = nfs_get_export();
 440  454  
 441  455          vis_head = tree_head->tree_vis;
 442  456          connect_point = exi->exi_tree;
 443  457  
 444  458          /*
 445  459           * If exportinfo doesn't already have a visible
 446  460           * list just assign the entire supplied list.
 447  461           */
 448  462          if (exi->exi_visible == NULL) {
 449  463                  tree_add_child(connect_point, tree_head);
 450  464                  exi->exi_visible = vis_head;
 451  465  
 452  466                  /* Update the change timestamp */
 453      -                tree_update_change(connect_point, &vis_head->vis_change);
      467 +                tree_update_change(ne, connect_point, &vis_head->vis_change);
 454  468  
 455  469                  return;
 456  470          }
 457  471  
 458  472          /* The outer loop traverses the supplied list. */
 459  473          for (vp1 = vis_head; vp1; vp1 = next) {
 460  474                  found = 0;
 461  475                  next = vp1->vis_next;
 462  476  
 463  477                  /* The inner loop searches the exportinfo visible list. */
↓ open down ↓ 39 lines elided ↑ open up ↑
 503  517                          if (curr->tree_exi) { /* Transfer the exportinfo */
 504  518                                  child->tree_exi = curr->tree_exi;
 505  519                                  child->tree_exi->exi_tree = child;
 506  520                          }
 507  521                          kmem_free(curr, sizeof (treenode_t));
 508  522                          connect_point = child;
 509  523                  } else { /* Branching */
 510  524                          tree_add_child(connect_point, curr);
 511  525  
 512  526                          /* Update the change timestamp */
 513      -                        tree_update_change(connect_point,
      527 +                        tree_update_change(ne, connect_point,
 514  528                              &curr->tree_vis->vis_change);
 515  529  
 516  530                          connect_point = NULL;
 517  531                  }
 518  532          }
 519  533  }
 520  534  
 521  535  /*
 522  536   * Remove one visible entry from the pseudo exportfs.
 523  537   *
↓ open down ↓ 96 lines elided ↑ open up ↑
 620  634          vnode_t *dvp, *vp;
 621  635          fid_t fid;
 622  636          int error;
 623  637          int exportdir;
 624  638          struct exportinfo *new_exi = exip;
 625  639          struct exp_visible *visp;
 626  640          struct exp_visible *vis_head = NULL;
 627  641          struct vattr va;
 628  642          treenode_t *tree_head = NULL;
 629  643          timespec_t now;
      644 +        nfs_export_t *ne = nfs_get_export();
 630  645  
 631      -        ASSERT(RW_WRITE_HELD(&exported_lock));
      646 +        ASSERT(RW_WRITE_HELD(&ne->exported_lock));
 632  647  
 633  648          gethrestime(&now);
 634  649  
 635  650          vp = exip->exi_vp;
 636  651          VN_HOLD(vp);
 637  652          exportdir = 1;
 638  653  
 639  654          for (;;) {
 640  655  
 641  656                  bzero(&fid, sizeof (fid));
↓ open down ↓ 28 lines elided ↑ open up ↑
 670  685                                          more_visible(exi, tree_head);
 671  686                                          break;  /* and climb no further */
 672  687                                  }
 673  688  
 674  689                                  /*
 675  690                                   * Found the root directory of a filesystem
 676  691                                   * that isn't exported.  Need to export
 677  692                                   * this as a pseudo export so that an NFS v4
 678  693                                   * client can do lookups in it.
 679  694                                   */
 680      -                                new_exi = pseudo_exportfs(vp, &fid, vis_head,
 681      -                                    NULL);
      695 +                                new_exi = pseudo_exportfs(ne, vp, &fid,
      696 +                                    vis_head, NULL);
 682  697                                  vis_head = NULL;
 683  698                          }
 684  699  
 685      -                        if (VN_CMP(vp, rootdir)) {
      700 +                        if (VN_CMP(vp, ZONE_ROOTVP())) {
 686  701                                  /* at system root */
 687  702                                  /*
 688  703                                   * If sharing "/", new_exi is shared exportinfo
 689  704                                   * (exip). Otherwise, new_exi is exportinfo
 690  705                                   * created by pseudo_exportfs() above.
 691  706                                   */
 692      -                                ns_root = tree_prepend_node(tree_head, NULL,
      707 +                                ne->ns_root = tree_prepend_node(tree_head, NULL,
 693  708                                      new_exi);
 694  709  
 695  710                                  /* Update the change timestamp */
 696      -                                tree_update_change(ns_root, &now);
      711 +                                tree_update_change(ne, ne->ns_root, &now);
 697  712  
 698  713                                  break;
 699  714                          }
 700  715  
 701  716                          /*
 702  717                           * Traverse across the mountpoint and continue the
 703  718                           * climb on the mounted-on filesystem.
 704  719                           */
 705  720                          vp = untraverse(vp);
 706  721                          exportdir = 0;
↓ open down ↓ 74 lines elided ↑ open up ↑
 781  796  
 782  797                  /* Connect unconnected exportinfo, if there is any. */
 783  798                  if (new_exi && new_exi != exip)
 784  799                          tree_head = tree_prepend_node(tree_head, NULL, new_exi);
 785  800  
 786  801                  while (tree_head) {
 787  802                          treenode_t *t2 = tree_head;
 788  803                          exportinfo_t *e  = tree_head->tree_exi;
 789  804                          /* exip will be freed in exportfs() */
 790  805                          if (e && e != exip) {
 791      -                                export_unlink(e);
 792      -                                exi_rele(e);
      806 +                                exp_kstats_delete(e->exi_kstats);
      807 +                                mutex_enter(&nfs_exi_id_lock);
      808 +                                avl_remove(&exi_id_tree, e);
      809 +                                mutex_exit(&nfs_exi_id_lock);
      810 +                                export_unlink(ne, e);
      811 +                                exi_rele(&e);
 793  812                          }
 794  813                          tree_head = tree_head->tree_child_first;
 795  814                          kmem_free(t2, sizeof (*t2));
 796  815                  }
 797  816          }
 798  817  
 799  818          return (error);
 800  819  }
 801  820  
 802  821  /*
↓ open down ↓ 2 lines elided ↑ open up ↑
 805  824   * 2. release visible in parent's exportinfo
 806  825   * 3. delete non-exported leaf nodes from tree
 807  826   *
 808  827   * Deleting of nodes will start only if the unshared
 809  828   * node was a leaf node.
 810  829   * Deleting of nodes will finish when we reach a node which
 811  830   * has children or is a real export, then we might still need
 812  831   * to continue releasing visibles, until we reach VROOT node.
 813  832   */
 814  833  void
 815      -treeclimb_unexport(struct exportinfo *exip)
      834 +treeclimb_unexport(nfs_export_t *ne, struct exportinfo *exip)
 816  835  {
 817  836          treenode_t *tnode, *old_nd;
 818  837          treenode_t *connect_point = NULL;
 819  838  
 820      -        ASSERT(RW_WRITE_HELD(&exported_lock));
      839 +        ASSERT(RW_WRITE_HELD(&ne->exported_lock));
 821  840  
 822  841          tnode = exip->exi_tree;
 823  842          /*
 824  843           * The unshared exportinfo was unlinked in unexport().
 825  844           * Zeroing tree_exi ensures that we will skip it.
 826  845           */
 827  846          tnode->tree_exi = NULL;
 828  847  
 829  848          if (tnode->tree_vis != NULL) /* system root has tree_vis == NULL */
 830  849                  tnode->tree_vis->vis_exported = 0;
↓ open down ↓ 1 lines elided ↑ open up ↑
 832  851          while (tnode != NULL) {
 833  852  
 834  853                  /* Stop at VROOT node which is exported or has child */
 835  854                  if (TREE_ROOT(tnode) &&
 836  855                      (TREE_EXPORTED(tnode) || tnode->tree_child_first != NULL))
 837  856                          break;
 838  857  
 839  858                  /* Release pseudo export if it has no child */
 840  859                  if (TREE_ROOT(tnode) && !TREE_EXPORTED(tnode) &&
 841  860                      tnode->tree_child_first == NULL) {
 842      -                        export_unlink(tnode->tree_exi);
 843      -                        exi_rele(tnode->tree_exi);
      861 +                        exp_kstats_delete(tnode->tree_exi->exi_kstats);
      862 +                        mutex_enter(&nfs_exi_id_lock);
      863 +                        avl_remove(&exi_id_tree, tnode->tree_exi);
      864 +                        mutex_exit(&nfs_exi_id_lock);
      865 +                        export_unlink(ne, tnode->tree_exi);
      866 +                        exi_rele(&tnode->tree_exi);
 844  867                  }
 845  868  
 846  869                  /* Release visible in parent's exportinfo */
 847  870                  if (tnode->tree_vis != NULL)
 848  871                          less_visible(vis2exi(tnode), tnode->tree_vis);
 849  872  
 850  873                  /* Continue with parent */
 851  874                  old_nd = tnode;
 852  875                  tnode = tnode->tree_parent;
 853  876  
 854  877                  /* Remove itself, if this is a leaf and non-exported node */
 855  878                  if (old_nd->tree_child_first == NULL &&
 856  879                      !TREE_EXPORTED(old_nd)) {
 857      -                        tree_remove_node(old_nd);
      880 +                        tree_remove_node(ne, old_nd);
 858  881                          connect_point = tnode;
 859  882                  }
 860  883          }
 861  884  
 862  885          /* Update the change timestamp */
 863  886          if (connect_point != NULL)
 864      -                tree_update_change(connect_point, NULL);
      887 +                tree_update_change(ne, connect_point, NULL);
 865  888  }
 866  889  
 867  890  /*
 868  891   * Traverse backward across mountpoint from the
 869  892   * root vnode of a filesystem to its mounted-on
 870  893   * vnode.
 871  894   */
 872  895  vnode_t *
 873  896  untraverse(vnode_t *vp)
 874  897  {
↓ open down ↓ 272 lines elided ↑ open up ↑
1147 1170  
1148 1171          for (*visp = exi->exi_visible; *visp != NULL; *visp = (*visp)->vis_next)
1149 1172                  if ((u_longlong_t)ino == (*visp)->vis_ino) {
1150 1173                          return (1);
1151 1174                  }
1152 1175  
1153 1176          return (0);
1154 1177  }
1155 1178  
1156 1179  /*
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 1180   * Get the change attribute from visible and returns TRUE.
1166 1181   * If the change value is not available returns FALSE.
1167 1182   */
1168 1183  bool_t
1169 1184  nfs_visible_change(struct exportinfo *exi, vnode_t *vp, timespec_t *change)
1170 1185  {
1171 1186          struct exp_visible *visp;
1172 1187          fid_t fid;
1173 1188          treenode_t *node;
     1189 +        nfs_export_t *ne = nfs_get_export();
1174 1190  
1175 1191          /*
1176 1192           * First check to see if vp is export root.
1177 1193           */
1178 1194          if (VN_CMP(vp, exi->exi_vp))
1179 1195                  goto exproot;
1180 1196  
1181 1197          /*
1182 1198           * Only a PSEUDO node has a visible list or an exported VROOT
1183 1199           * node may have a visible list.
↓ open down ↓ 24 lines elided ↑ open up ↑
1208 1224                          *change = visp->vis_change;
1209 1225                          return (TRUE);
1210 1226                  }
1211 1227          }
1212 1228  
1213 1229          return (FALSE);
1214 1230  
1215 1231  exproot:
1216 1232          /* The VROOT export have its visible available through treenode */
1217 1233          node = exi->exi_tree;
1218      -        if (node != ns_root) {
     1234 +        if (node != ne->ns_root) {
1219 1235                  ASSERT(node->tree_vis != NULL);
1220 1236                  *change = node->tree_vis->vis_change;
1221 1237          } else {
1222 1238                  ASSERT(node->tree_vis == NULL);
1223      -                *change = ns_root_change;
     1239 +                *change = ne->ns_root_change;
1224 1240          }
1225      -
1226 1241          return (TRUE);
1227 1242  }
1228 1243  
1229 1244  /*
1230 1245   * Update the change attribute value for a particular treenode.  The change
1231 1246   * attribute value is stored in the visible attached to the treenode, or in the
1232 1247   * ns_root_change.
1233 1248   *
1234 1249   * If the change value is not supplied, the current time is used.
1235 1250   */
1236 1251  void
1237      -tree_update_change(treenode_t *tnode, timespec_t *change)
     1252 +tree_update_change(nfs_export_t *ne, treenode_t *tnode, timespec_t *change)
1238 1253  {
1239 1254          timespec_t *vis_change;
1240 1255  
1241 1256          ASSERT(tnode != NULL);
1242      -        ASSERT((tnode != ns_root && tnode->tree_vis != NULL) ||
1243      -            (tnode == ns_root && tnode->tree_vis == NULL));
     1257 +        ASSERT((tnode != ne->ns_root && tnode->tree_vis != NULL) ||
     1258 +            (tnode == ne->ns_root && tnode->tree_vis == NULL));
1244 1259  
1245      -        vis_change = tnode == ns_root ? &ns_root_change
     1260 +        vis_change = tnode == ne->ns_root ? &ne->ns_root_change
1246 1261              : &tnode->tree_vis->vis_change;
1247 1262  
1248 1263          if (change != NULL)
1249 1264                  *vis_change = *change;
1250 1265          else
1251 1266                  gethrestime(vis_change);
1252 1267  }
    
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX