/* * Walk up the tree and: * 1. release pseudo exportinfo if it has no child * 2. release visible in parent's exportinfo * 3. delete non-exported leaf nodes from tree * * Deleting of nodes will start only if the unshared * node was a leaf node. * 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. */ tnode->tree_exi = NULL; if (tnode->tree_vis != NULL) /* system root has tree_vis == NULL */ tnode->tree_vis->vis_exported = 0; while (tnode != NULL) { /* Stop at VROOT node which is exported or has child */ if (TREE_ROOT(tnode) && (TREE_EXPORTED(tnode) || tnode->tree_child_first != NULL)) 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); /* Continue with parent */ old_nd = tnode; 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); }
/* * Given an exportinfo, climb up to find the exportinfo for the VROOT * of the filesystem. * * e.g. / * | * a (VROOT) pseudo-exportinfo * | * b * | * c #share /a/b/c * | * d * * where c is in the same filesystem as a. * So, get_root_export(*exportinfo_for_c) returns exportinfo_for_a * * If d is shared, then c will be put into a's visible list. * Note: visible list is per filesystem and is attached to the * VROOT exportinfo. */ struct exportinfo * get_root_export(struct exportinfo *exip) { treenode_t *tnode = exip->exi_tree; exportinfo_t *exi = NULL; while (tnode) { if (TREE_ROOT(tnode)) { exi = tnode->tree_exi; break; } tnode = tnode->tree_parent; } ASSERT(exi); return (exi); }