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>

@@ -18,12 +18,15 @@
  *
  * CDDL HEADER END
  */
 
 /*
- * Copyright 2014 Nexenta Systems, Inc.  All rights reserved.
  * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
+ */
+
+/*
+ * Copyright 2018 Nexenta Systems, Inc.
  * Copyright (c) 2015, Joyent, Inc.
  */
 
 #include <sys/systm.h>
 

@@ -141,20 +144,20 @@
  * struct (real or pseudo) can have a visible list as long as
  * a) its export root is VROOT
  * b) a descendant of the export root is shared
  */
 struct exportinfo *
-pseudo_exportfs(vnode_t *vp, fid_t *fid, struct exp_visible *vis_head,
+pseudo_exportfs(nfs_export_t *ne, vnode_t *vp, fid_t *fid, struct exp_visible *vis_head,
     struct exportdata *exdata)
 {
         struct exportinfo *exi;
         struct exportdata *kex;
         fsid_t fsid;
         int vpathlen;
         int i;
 
-        ASSERT(RW_WRITE_HELD(&exported_lock));
+        ASSERT(RW_WRITE_HELD(&ne->exported_lock));
 
         fsid = vp->v_vfsp->vfs_fsid;
         exi = kmem_zalloc(sizeof (*exi), KM_SLEEP);
         exi->exi_fsid = fsid;
         exi->exi_fid = *fid;

@@ -203,12 +206,22 @@
         rw_init(&exi->exi_cache_lock, NULL, RW_DEFAULT, NULL);
 
         /*
          * Insert the new entry at the front of the export list
          */
-        export_link(exi);
+        export_link(ne, exi);
 
+        /*
+         * Initialize exi_id and exi_kstats
+         */
+        mutex_enter(&nfs_exi_id_lock);
+        exi->exi_id = exi_id_get_next();
+        avl_add(&exi_id_tree, exi);
+        mutex_exit(&nfs_exi_id_lock);
+        exi->exi_kstats = exp_kstats_init(getzoneid(), exi->exi_id,
+            kex->ex_path, vpathlen, TRUE);
+
         return (exi);
 }
 
 /*
  * Free a list of visible directories

@@ -279,18 +292,18 @@
  * Removes node from the tree and frees the treenode struct.
  * Does not free structures pointed by tree_exi and tree_vis,
  * they should be already freed.
  */
 static void
-tree_remove_node(treenode_t *node)
+tree_remove_node(nfs_export_t *ne, treenode_t *node)
 {
         treenode_t *parent = node->tree_parent;
         treenode_t *s; /* s for sibling */
 
         if (parent == NULL) {
                 kmem_free(node, sizeof (*node));
-                ns_root = NULL;
+                ne->ns_root = NULL;
                 return;
         }
         /* This node is first child */
         if (parent->tree_child_first == node) {
                 parent->tree_child_first = node->tree_sibling;

@@ -435,10 +448,11 @@
 more_visible(struct exportinfo *exi, treenode_t *tree_head)
 {
         struct exp_visible *vp1, *vp2, *vis_head, *tail, *next;
         int found;
         treenode_t *child, *curr, *connect_point;
+        nfs_export_t *ne = nfs_get_export();
 
         vis_head = tree_head->tree_vis;
         connect_point = exi->exi_tree;
 
         /*

@@ -448,11 +462,11 @@
         if (exi->exi_visible == NULL) {
                 tree_add_child(connect_point, tree_head);
                 exi->exi_visible = vis_head;
 
                 /* Update the change timestamp */
-                tree_update_change(connect_point, &vis_head->vis_change);
+                tree_update_change(ne, connect_point, &vis_head->vis_change);
 
                 return;
         }
 
         /* The outer loop traverses the supplied list. */

@@ -508,11 +522,11 @@
                         connect_point = child;
                 } else { /* Branching */
                         tree_add_child(connect_point, curr);
 
                         /* Update the change timestamp */
-                        tree_update_change(connect_point,
+                        tree_update_change(ne, connect_point,
                             &curr->tree_vis->vis_change);
 
                         connect_point = NULL;
                 }
         }

@@ -625,12 +639,13 @@
         struct exp_visible *visp;
         struct exp_visible *vis_head = NULL;
         struct vattr va;
         treenode_t *tree_head = NULL;
         timespec_t now;
+        nfs_export_t *ne = nfs_get_export();
 
-        ASSERT(RW_WRITE_HELD(&exported_lock));
+        ASSERT(RW_WRITE_HELD(&ne->exported_lock));
 
         gethrestime(&now);
 
         vp = exip->exi_vp;
         VN_HOLD(vp);

@@ -675,27 +690,27 @@
                                  * Found the root directory of a filesystem
                                  * that isn't exported.  Need to export
                                  * this as a pseudo export so that an NFS v4
                                  * client can do lookups in it.
                                  */
-                                new_exi = pseudo_exportfs(vp, &fid, vis_head,
-                                    NULL);
+                                new_exi = pseudo_exportfs(ne, vp, &fid,
+                                    vis_head, NULL);
                                 vis_head = NULL;
                         }
 
-                        if (VN_CMP(vp, rootdir)) {
+                        if (VN_CMP(vp, ZONE_ROOTVP())) {
                                 /* at system root */
                                 /*
                                  * If sharing "/", new_exi is shared exportinfo
                                  * (exip). Otherwise, new_exi is exportinfo
                                  * created by pseudo_exportfs() above.
                                  */
-                                ns_root = tree_prepend_node(tree_head, NULL,
+                                ne->ns_root = tree_prepend_node(tree_head, NULL,
                                     new_exi);
 
                                 /* Update the change timestamp */
-                                tree_update_change(ns_root, &now);
+                                tree_update_change(ne, ne->ns_root, &now);
 
                                 break;
                         }
 
                         /*

@@ -786,12 +801,16 @@
                 while (tree_head) {
                         treenode_t *t2 = tree_head;
                         exportinfo_t *e  = tree_head->tree_exi;
                         /* exip will be freed in exportfs() */
                         if (e && e != exip) {
-                                export_unlink(e);
-                                exi_rele(e);
+                                exp_kstats_delete(e->exi_kstats);
+                                mutex_enter(&nfs_exi_id_lock);
+                                avl_remove(&exi_id_tree, e);
+                                mutex_exit(&nfs_exi_id_lock);
+                                export_unlink(ne, e);
+                                exi_rele(&e);
                         }
                         tree_head = tree_head->tree_child_first;
                         kmem_free(t2, sizeof (*t2));
                 }
         }

@@ -810,16 +829,16 @@
  * Deleting of nodes will finish when we reach a node which
  * has children or is a real export, then we might still need
  * to continue releasing visibles, until we reach VROOT node.
  */
 void
-treeclimb_unexport(struct exportinfo *exip)
+treeclimb_unexport(nfs_export_t *ne, struct exportinfo *exip)
 {
         treenode_t *tnode, *old_nd;
         treenode_t *connect_point = NULL;
 
-        ASSERT(RW_WRITE_HELD(&exported_lock));
+        ASSERT(RW_WRITE_HELD(&ne->exported_lock));
 
         tnode = exip->exi_tree;
         /*
          * The unshared exportinfo was unlinked in unexport().
          * Zeroing tree_exi ensures that we will skip it.

@@ -837,12 +856,16 @@
                         break;
 
                 /* Release pseudo export if it has no child */
                 if (TREE_ROOT(tnode) && !TREE_EXPORTED(tnode) &&
                     tnode->tree_child_first == NULL) {
-                        export_unlink(tnode->tree_exi);
-                        exi_rele(tnode->tree_exi);
+                        exp_kstats_delete(tnode->tree_exi->exi_kstats);
+                        mutex_enter(&nfs_exi_id_lock);
+                        avl_remove(&exi_id_tree, tnode->tree_exi);
+                        mutex_exit(&nfs_exi_id_lock);
+                        export_unlink(ne, tnode->tree_exi);
+                        exi_rele(&tnode->tree_exi);
                 }
 
                 /* Release visible in parent's exportinfo */
                 if (tnode->tree_vis != NULL)
                         less_visible(vis2exi(tnode), tnode->tree_vis);

@@ -852,18 +875,18 @@
                 tnode = tnode->tree_parent;
 
                 /* Remove itself, if this is a leaf and non-exported node */
                 if (old_nd->tree_child_first == NULL &&
                     !TREE_EXPORTED(old_nd)) {
-                        tree_remove_node(old_nd);
+                        tree_remove_node(ne, old_nd);
                         connect_point = tnode;
                 }
         }
 
         /* Update the change timestamp */
         if (connect_point != NULL)
-                tree_update_change(connect_point, NULL);
+                tree_update_change(ne, connect_point, NULL);
 }
 
 /*
  * Traverse backward across mountpoint from the
  * root vnode of a filesystem to its mounted-on

@@ -1152,27 +1175,20 @@
 
         return (0);
 }
 
 /*
- * The change attribute value of the root of nfs pseudo namespace.
- *
- * The ns_root_change is protected by exported_lock because all of the treenode
- * operations are protected by exported_lock too.
- */
-static timespec_t ns_root_change;
-
-/*
  * Get the change attribute from visible and returns TRUE.
  * If the change value is not available returns FALSE.
  */
 bool_t
 nfs_visible_change(struct exportinfo *exi, vnode_t *vp, timespec_t *change)
 {
         struct exp_visible *visp;
         fid_t fid;
         treenode_t *node;
+        nfs_export_t *ne = nfs_get_export();
 
         /*
          * First check to see if vp is export root.
          */
         if (VN_CMP(vp, exi->exi_vp))

@@ -1213,18 +1229,17 @@
         return (FALSE);
 
 exproot:
         /* The VROOT export have its visible available through treenode */
         node = exi->exi_tree;
-        if (node != ns_root) {
+        if (node != ne->ns_root) {
                 ASSERT(node->tree_vis != NULL);
                 *change = node->tree_vis->vis_change;
         } else {
                 ASSERT(node->tree_vis == NULL);
-                *change = ns_root_change;
+                *change = ne->ns_root_change;
         }
-
         return (TRUE);
 }
 
 /*
  * Update the change attribute value for a particular treenode.  The change

@@ -1232,19 +1247,19 @@
  * ns_root_change.
  *
  * If the change value is not supplied, the current time is used.
  */
 void
-tree_update_change(treenode_t *tnode, timespec_t *change)
+tree_update_change(nfs_export_t *ne, treenode_t *tnode, timespec_t *change)
 {
         timespec_t *vis_change;
 
         ASSERT(tnode != NULL);
-        ASSERT((tnode != ns_root && tnode->tree_vis != NULL) ||
-            (tnode == ns_root && tnode->tree_vis == NULL));
+        ASSERT((tnode != ne->ns_root && tnode->tree_vis != NULL) ||
+            (tnode == ne->ns_root && tnode->tree_vis == NULL));
 
-        vis_change = tnode == ns_root ? &ns_root_change
+        vis_change = tnode == ne->ns_root ? &ne->ns_root_change
             : &tnode->tree_vis->vis_change;
 
         if (change != NULL)
                 *vis_change = *change;
         else