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,29 ****
*
* CDDL HEADER END
*/
/*
- * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
* Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2015, Joyent, Inc.
*/
#include <sys/systm.h>
--- 18,32 ----
*
* CDDL HEADER END
*/
/*
* 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,160 ****
* 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,
struct exportdata *exdata)
{
struct exportinfo *exi;
struct exportdata *kex;
fsid_t fsid;
int vpathlen;
int i;
! ASSERT(RW_WRITE_HELD(&exported_lock));
fsid = vp->v_vfsp->vfs_fsid;
exi = kmem_zalloc(sizeof (*exi), KM_SLEEP);
exi->exi_fsid = fsid;
exi->exi_fid = *fid;
--- 144,163 ----
* 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(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(&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,214 ****
rw_init(&exi->exi_cache_lock, NULL, RW_DEFAULT, NULL);
/*
* Insert the new entry at the front of the export list
*/
! export_link(exi);
return (exi);
}
/*
* Free a list of visible directories
--- 206,227 ----
rw_init(&exi->exi_cache_lock, NULL, RW_DEFAULT, NULL);
/*
* Insert the new entry at the front of the export list
*/
! 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,296 ****
* 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)
{
treenode_t *parent = node->tree_parent;
treenode_t *s; /* s for sibling */
if (parent == NULL) {
kmem_free(node, sizeof (*node));
! ns_root = NULL;
return;
}
/* This node is first child */
if (parent->tree_child_first == node) {
parent->tree_child_first = node->tree_sibling;
--- 292,309 ----
* 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(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));
! ne->ns_root = NULL;
return;
}
/* This node is first child */
if (parent->tree_child_first == node) {
parent->tree_child_first = node->tree_sibling;
*** 435,444 ****
--- 448,458 ----
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,458 ****
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);
return;
}
/* The outer loop traverses the supplied list. */
--- 462,472 ----
if (exi->exi_visible == NULL) {
tree_add_child(connect_point, tree_head);
exi->exi_visible = vis_head;
/* Update the change timestamp */
! tree_update_change(ne, connect_point, &vis_head->vis_change);
return;
}
/* The outer loop traverses the supplied list. */
*** 508,518 ****
connect_point = child;
} else { /* Branching */
tree_add_child(connect_point, curr);
/* Update the change timestamp */
! tree_update_change(connect_point,
&curr->tree_vis->vis_change);
connect_point = NULL;
}
}
--- 522,532 ----
connect_point = child;
} else { /* Branching */
tree_add_child(connect_point, curr);
/* Update the change timestamp */
! tree_update_change(ne, connect_point,
&curr->tree_vis->vis_change);
connect_point = NULL;
}
}
*** 625,636 ****
struct exp_visible *visp;
struct exp_visible *vis_head = NULL;
struct vattr va;
treenode_t *tree_head = NULL;
timespec_t now;
! ASSERT(RW_WRITE_HELD(&exported_lock));
gethrestime(&now);
vp = exip->exi_vp;
VN_HOLD(vp);
--- 639,651 ----
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(&ne->exported_lock));
gethrestime(&now);
vp = exip->exi_vp;
VN_HOLD(vp);
*** 675,701 ****
* 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);
vis_head = NULL;
}
! if (VN_CMP(vp, rootdir)) {
/* 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,
new_exi);
/* Update the change timestamp */
! tree_update_change(ns_root, &now);
break;
}
/*
--- 690,716 ----
* 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(ne, vp, &fid,
! vis_head, NULL);
vis_head = NULL;
}
! 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.
*/
! ne->ns_root = tree_prepend_node(tree_head, NULL,
new_exi);
/* Update the change timestamp */
! tree_update_change(ne, ne->ns_root, &now);
break;
}
/*
*** 786,797 ****
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);
}
tree_head = tree_head->tree_child_first;
kmem_free(t2, sizeof (*t2));
}
}
--- 801,816 ----
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) {
! 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,825 ****
* 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)
{
treenode_t *tnode, *old_nd;
treenode_t *connect_point = NULL;
! ASSERT(RW_WRITE_HELD(&exported_lock));
tnode = exip->exi_tree;
/*
* The unshared exportinfo was unlinked in unexport().
* Zeroing tree_exi ensures that we will skip it.
--- 829,844 ----
* 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(nfs_export_t *ne, struct exportinfo *exip)
{
treenode_t *tnode, *old_nd;
treenode_t *connect_point = NULL;
! 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,848 ****
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);
}
/* Release visible in parent's exportinfo */
if (tnode->tree_vis != NULL)
less_visible(vis2exi(tnode), tnode->tree_vis);
--- 856,871 ----
break;
/* Release pseudo export if it has no child */
if (TREE_ROOT(tnode) && !TREE_EXPORTED(tnode) &&
tnode->tree_child_first == NULL) {
! 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,869 ****
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);
connect_point = tnode;
}
}
/* Update the change timestamp */
if (connect_point != NULL)
! tree_update_change(connect_point, NULL);
}
/*
* Traverse backward across mountpoint from the
* root vnode of a filesystem to its mounted-on
--- 875,892 ----
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(ne, old_nd);
connect_point = tnode;
}
}
/* Update the change timestamp */
if (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,1178 ****
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;
/*
* First check to see if vp is export root.
*/
if (VN_CMP(vp, exi->exi_vp))
--- 1175,1194 ----
return (0);
}
/*
* 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,1230 ****
return (FALSE);
exproot:
/* The VROOT export have its visible available through treenode */
node = exi->exi_tree;
! if (node != ns_root) {
ASSERT(node->tree_vis != NULL);
*change = node->tree_vis->vis_change;
} else {
ASSERT(node->tree_vis == NULL);
! *change = ns_root_change;
}
-
return (TRUE);
}
/*
* Update the change attribute value for a particular treenode. The change
--- 1229,1245 ----
return (FALSE);
exproot:
/* The VROOT export have its visible available through treenode */
node = exi->exi_tree;
! if (node != ne->ns_root) {
ASSERT(node->tree_vis != NULL);
*change = node->tree_vis->vis_change;
} else {
ASSERT(node->tree_vis == NULL);
! *change = ne->ns_root_change;
}
return (TRUE);
}
/*
* Update the change attribute value for a particular treenode. The change
*** 1232,1250 ****
* 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)
{
timespec_t *vis_change;
ASSERT(tnode != NULL);
! ASSERT((tnode != ns_root && tnode->tree_vis != NULL) ||
! (tnode == ns_root && tnode->tree_vis == NULL));
! vis_change = tnode == ns_root ? &ns_root_change
: &tnode->tree_vis->vis_change;
if (change != NULL)
*vis_change = *change;
else
--- 1247,1265 ----
* ns_root_change.
*
* If the change value is not supplied, the current time is used.
*/
void
! tree_update_change(nfs_export_t *ne, treenode_t *tnode, timespec_t *change)
{
timespec_t *vis_change;
ASSERT(tnode != NULL);
! ASSERT((tnode != ne->ns_root && tnode->tree_vis != NULL) ||
! (tnode == ne->ns_root && tnode->tree_vis == NULL));
! vis_change = tnode == ne->ns_root ? &ne->ns_root_change
: &tnode->tree_vis->vis_change;
if (change != NULL)
*vis_change = *change;
else