summaryrefslogtreecommitdiff
path: root/usr
diff options
context:
space:
mode:
authorPavel Filipensky <Pavel.Filipensky@Sun.COM>2010-02-28 14:10:13 +0000
committerPavel Filipensky <Pavel.Filipensky@Sun.COM>2010-02-28 14:10:13 +0000
commit3f2383012abdf005e860f5afa06cb2e0044a424f (patch)
tree71c69c62fec067b9c94c91dce252deb378fbb44d /usr
parentea1b934f6e05788b68ee3d5f5d2c6c35683854db (diff)
downloadillumos-gate-3f2383012abdf005e860f5afa06cb2e0044a424f.tar.gz
6901748 mvfs and nfs pseudo namespace tree do not work together
6926015 dead code in exportfs()
Diffstat (limited to 'usr')
-rw-r--r--usr/src/uts/common/fs/nfs/nfs4_srv_ns.c142
-rw-r--r--usr/src/uts/common/fs/nfs/nfs_export.c16
-rw-r--r--usr/src/uts/common/nfs/export.h23
3 files changed, 91 insertions, 90 deletions
diff --git a/usr/src/uts/common/fs/nfs/nfs4_srv_ns.c b/usr/src/uts/common/fs/nfs/nfs4_srv_ns.c
index 40ef94e16b..922c24a260 100644
--- a/usr/src/uts/common/fs/nfs/nfs4_srv_ns.c
+++ b/usr/src/uts/common/fs/nfs/nfs4_srv_ns.c
@@ -18,7 +18,7 @@
*
* CDDL HEADER END
*
- * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -270,7 +270,6 @@ tree_prepend_node(treenode_t *n, exp_visible_t *v, exportinfo_t *e)
}
if (v) {
tnode->tree_vis = v;
- v->vis_tree = tnode;
}
if (e) {
tnode->tree_exi = e;
@@ -309,8 +308,6 @@ tree_remove_node(treenode_t *node)
}
/*
- * Add a list of visible directories to a pseudo exportfs.
- *
* When we export a new directory we need to add a new
* path segment through the pseudofs to reach the new
* directory. This new path is reflected in a list of
@@ -323,19 +320,70 @@ tree_remove_node(treenode_t *node)
* the lists so there's no duplicate entries. Where a common
* path component is found, the vis_count field is bumped.
*
- * When the addition is complete, the supplied list is freed.
+ * This example shows that the treenode chain (tree_head) and
+ * exp_visible chain (vis_head) can differ in length. The latter
+ * can be shorter. The outer loop must loop over the vis_head chain.
+ *
+ * share /x/a
+ * mount -F ufs /dev/dsk/... /x/y
+ * mkdir -p /x/y/a/b
+ * share /x/y/a/b
+ *
+ * When more_visible() is called during the second share,
+ * the existing namespace is folowing:
+ * exp_visible_t
+ * treenode_t exportinfo_t v0 v1
+ * ns_root+---+ +------------+ +---+ +---+
+ * t0| / |........| E0 pseudo |->| x |->| a |
+ * +---+ +------------+ +---+ +---+
+ * | / /
+ * +---+ / /
+ * t1| x |------------------------ /
+ * +---+ /
+ * | /
+ * +---+ /
+ * t2| a |-------------------------
+ * +---+........+------------+
+ * | E1 real |
+ * +------------+
+ *
+ * This is being added:
+ *
+ * tree_head vis_head
+ * +---+ +---+
+ * t3| x |->| x |v2
+ * +---+ +---+
+ * | |
+ * +---+ +---+ v4 v5
+ * t4| y |->| y |v3 +------------+ +---+ +---+
+ * +---+\ +---+ | E2 pseudo |->| a |->| b |
+ * | \....... >+------------+ +---+ +---+
+ * +---+ / /
+ * t5| a |--------------------------- /
+ * +---+ /
+ * | /
+ * +---+-------------------------------
+ * t6| b | +------------+
+ * +---+..........>| E3 real |
+ * +------------+
+ *
+ * more_visible() will:
+ * - add t3 (with t4,t5,t6) as a child of t0 (t3 will become sibling of t1)
+ * - t3->tree_vis = v0 (plus bump vis_count for v0) and free v2
+ * - add v3 to the end of E0->exi_visible
+ *
+ * Note that v4 and v5 were already proccesed in pseudo_exportfs() and
+ * added to E2. The outer loop of more_visible() will loop only over v2
+ * and v3. The inner loop of more_visible() always loops over v0 and v1.
*/
-
static void
-more_visible(struct exportinfo *exi, struct exp_visible *vis_head)
+more_visible(struct exportinfo *exi, treenode_t *tree_head)
{
- struct exp_visible *vp1, *vp2;
- struct exp_visible *tail, *new;
- treenode_t *subtree_head, *dupl, *dest;
+ struct exp_visible *vp1, *vp2, *vis_head, *tail, *next;
int found;
- dest = exi->exi_tree;
- subtree_head = vis_head->vis_tree;
+ vis_head = tree_head->tree_vis;
+ tree_add_child(exi->exi_tree, tree_head);
/*
* If exportinfo doesn't already have a visible
@@ -343,39 +391,23 @@ more_visible(struct exportinfo *exi, struct exp_visible *vis_head)
*/
if (exi->exi_visible == NULL) {
exi->exi_visible = vis_head;
- tree_add_child(dest, subtree_head);
return;
}
- /*
- * The outer loop traverses the supplied list.
- */
- for (vp1 = vis_head; vp1; vp1 = vp1->vis_next) {
-
- /*
- * Given an element from the list to be added,
- * search the exportinfo visible list looking for a match.
- * If a match is found, increment the reference count.
- */
+ /* The outer loop traverses the supplied list. */
+ for (vp1 = vis_head; vp1; vp1 = next) {
found = 0;
+ next = vp1->vis_next;
+ /* The inner loop searches the exportinfo visible list. */
for (vp2 = exi->exi_visible; vp2; vp2 = vp2->vis_next) {
-
tail = vp2;
-
if (EQFID(&vp1->vis_fid, &vp2->vis_fid)) {
found = 1;
vp2->vis_count++;
VN_RELE(vp1->vis_vp);
- vp1->vis_vp = NULL;
-
/*
- * If the visible struct we want to add
- * (vp1) has vis_exported set to 1, then
- * the matching visible struct we just found
- * must also have it's vis_exported field
- * set to 1.
- *
+ * Transfer vis_exported from vp1 to vp2.
* For example, if /export/home was shared
* (and a mountpoint), then "export" and
* "home" would each have visible structs in
@@ -386,51 +418,23 @@ more_visible(struct exportinfo *exi, struct exp_visible *vis_head)
* existing visible struct for export, and
* see that vis_exported was 0. The code
* below will set it to 1.
- *
- * vp1 is from vis list passed in (vis_head)
- * vp2 is from vis list on pseudo exportinfo
*/
if (vp1->vis_exported && !vp2->vis_exported)
vp2->vis_exported = 1;
- /*
- * Assuming that visibles in vis_head are sorted
- * in same order as they appear in the shared
- * path. If /a/b/c/d is being shared we will
- * see 'a' before 'b' etc.
- */
- dupl = vp1->vis_tree;
- dest = vp2->vis_tree;
- /* If node is shared, transfer exportinfo ptr */
- if (dupl->tree_exi) {
- dest->tree_exi = dupl->tree_exi;
- dest->tree_exi->exi_tree = dest;
- }
- subtree_head = dupl->tree_child_first;
- kmem_free(dupl, sizeof (*dupl));
+
+ kmem_free(vp1, sizeof (*vp1));
+ tree_head->tree_vis = vp2;
break;
}
}
/* If not found - add to the end of the list */
if (! found) {
- new = kmem_zalloc(sizeof (*new), KM_SLEEP);
- *new = *vp1;
- tail->vis_next = new;
- new->vis_next = NULL;
- vp1->vis_vp = NULL;
- /* Tell treenode that new visible is kmem_zalloc-ated */
- new->vis_tree->tree_vis = new;
+ tail->vis_next = vp1;
+ vp1->vis_next = NULL;
}
+ tree_head = tree_head->tree_child_first;
}
-
- /*
- * Throw away the path list. vis_vp pointers in vis_head list
- * are either VN_RELEed or reassigned, and are set to NULL.
- * There is no need to VN_RELE in free_visible for this vis_head.
- */
- free_visible(vis_head);
- if (subtree_head)
- tree_add_child(dest, subtree_head);
}
/*
@@ -595,7 +599,7 @@ treeclimb_export(struct exportinfo *exip)
* directories whether it's a pseudo
* or a real export.
*/
- more_visible(exi, vis_head);
+ more_visible(exi, tree_head);
break; /* and climb no further */
}
}
@@ -778,7 +782,7 @@ treeclimb_unexport(struct exportinfo *exip)
/* Release visible in parent's exportinfo */
if (tnode->tree_vis) {
- exi = vis2exi(tnode->tree_vis);
+ exi = vis2exi(tnode);
less_visible(exi, tnode->tree_vis);
}
diff --git a/usr/src/uts/common/fs/nfs/nfs_export.c b/usr/src/uts/common/fs/nfs/nfs_export.c
index 6bd69dc5c3..53f9f97294 100644
--- a/usr/src/uts/common/fs/nfs/nfs_export.c
+++ b/usr/src/uts/common/fs/nfs/nfs_export.c
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -695,18 +695,17 @@ srv_secinfo_exp2pseu(exportdata_t *curdata, exportdata_t *olddata)
}
/*
- * Find for given exp_visible the exportinfo which has it
- * linked on its exi_visible list.
+ * Find for given treenode the exportinfo which has its
+ * exp_visible linked on its exi_visible list.
*
* Note: We could add new pointer either to treenode or
* to exp_visible, which will point there directly.
* This would buy some speed for some memory.
*/
exportinfo_t *
-vis2exi(struct exp_visible *vis)
+vis2exi(treenode_t *tnode)
{
exportinfo_t *exi_ret = NULL;
- treenode_t *tnode = vis->vis_tree;
for (;;) {
tnode = tnode->tree_parent;
@@ -1570,13 +1569,8 @@ exi_scan_end:
return (0);
out7:
- /*
- * Unlink and re-link the new and old export in exptable.
- */
+ /* Unlink the new export in exptable. */
(void) export_unlink(&exi->exi_fsid, &exi->exi_fid, exi->exi_vp, NULL);
- if (ex != NULL)
- export_link(ex);
-
rw_exit(&exported_lock);
out6:
if (kex->ex_flags & EX_INDEX)
diff --git a/usr/src/uts/common/nfs/export.h b/usr/src/uts/common/nfs/export.h
index 79c605a21e..9bc35d0a6a 100644
--- a/usr/src/uts/common/nfs/export.h
+++ b/usr/src/uts/common/nfs/export.h
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -301,11 +301,15 @@ struct svc_req;
/*
* Treenodes are used to build tree representing every node which is part
- * of nfs server pseudo namespace.
- * This tree is interconnected with both exportinfo and exp_visible struct.
- * When there is a need to walk the namespace (either starting in
- * exportinfo or in exp_visible) we first make a step aside (to the left),
- * walk up or down as needed, and then we step back (to the right).
+ * of nfs server pseudo namespace. They are connected with both exportinfo
+ * and exp_visible struct. They were introduced to avoid lookup of ".."
+ * in the underlying file system during unshare, which was failing if the
+ * file system was forcibly unmounted or if the directory was removed.
+ * One exp_visible_t can be shared via several treenode_t, i.e.
+ * different tree_vis can point to the same exp_visible_t.
+ * This will happen if some directory is on two different shared paths:
+ * E.g. after share /tmp/a/b1 and share /tmp/a/b2 there will be two treenodes
+ * corresponding to /tmp/a and both will have same value in tree_vis.
*
*
*
@@ -349,9 +353,9 @@ struct svc_req;
*
*
* Bi-directional interconnect:
- *
* treenode_t::tree_exi --------- exportinfo_t::exi_tree
- * treenode_t::tree_vis ......... exp_visible_t::vis_tree
+ * One-way direction connection:
+ * treenode_t::tree_vis .........> exp_visible_t
*/
/* Access to treenode_t is under protection of exported_lock RW_LOCK */
typedef struct treenode {
@@ -457,7 +461,6 @@ struct exp_visible {
int vis_count;
int vis_exported;
struct exp_visible *vis_next;
- struct treenode *vis_tree;
struct secinfo *vis_secinfo;
int vis_seccnt;
};
@@ -523,7 +526,7 @@ extern char *build_symlink(vnode_t *, cred_t *, size_t *);
/*
* Functions that handle the NFSv4 server namespace
*/
-extern exportinfo_t *vis2exi(struct exp_visible *);
+extern exportinfo_t *vis2exi(treenode_t *);
extern int treeclimb_export(struct exportinfo *);
extern void treeclimb_unexport(struct exportinfo *);
extern int nfs_visible(struct exportinfo *, vnode_t *, int *);