diff options
author | ahrens <none@none> | 2005-10-31 11:33:35 -0800 |
---|---|---|
committer | ahrens <none@none> | 2005-10-31 11:33:35 -0800 |
commit | fa9e4066f08beec538e775443c5be79dd423fcab (patch) | |
tree | 576d99665e57bb7cb70584431adb08c14d47e3ce /usr/src/cmd/mdb/common/modules/genunix/avl.c | |
parent | f1b64740276f67fc6914c1d855f2af601efe99ac (diff) | |
download | illumos-gate-fa9e4066f08beec538e775443c5be79dd423fcab.tar.gz |
PSARC 2002/240 ZFS
6338653 Integrate ZFS
PSARC 2004/652 - DKIOCFLUSH
5096886 Write caching disks need mechanism to flush cache to physical media
Diffstat (limited to 'usr/src/cmd/mdb/common/modules/genunix/avl.c')
-rw-r--r-- | usr/src/cmd/mdb/common/modules/genunix/avl.c | 217 |
1 files changed, 217 insertions, 0 deletions
diff --git a/usr/src/cmd/mdb/common/modules/genunix/avl.c b/usr/src/cmd/mdb/common/modules/genunix/avl.c new file mode 100644 index 0000000000..b10856cfc3 --- /dev/null +++ b/usr/src/cmd/mdb/common/modules/genunix/avl.c @@ -0,0 +1,217 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/avl.h> + +#include <mdb/mdb_modapi.h> + +struct aw_info { + void *aw_buff; /* buffer to hold the tree's data structure */ + avl_tree_t aw_tree; /* copy of avl_tree_t being walked */ +}; + +/* + * common code used to find the addr of the the leftmost child below + * an AVL node + */ +static uintptr_t +avl_leftmostchild(uintptr_t addr, void * buff, size_t offset, size_t size) +{ + avl_node_t *node = (avl_node_t *)((uintptr_t)buff + offset); + + for (;;) { + addr -= offset; + if (mdb_vread(buff, size, addr) == -1) { + mdb_warn("read of avl_node_t failed: %p", addr); + return ((uintptr_t)-1L); + } + if (node->avl_child[0] == NULL) + break; + addr = (uintptr_t)node->avl_child[0]; + } + return (addr); +} + +/* + * initialize a forward walk thru an avl tree. + */ +int +avl_walk_init(mdb_walk_state_t *wsp) +{ + struct aw_info *aw; + avl_tree_t *tree; + uintptr_t addr; + + /* + * allocate the AVL walk data + */ + wsp->walk_data = aw = mdb_zalloc(sizeof (struct aw_info), UM_SLEEP); + + /* + * get an mdb copy of the avl_tree_t being walked + */ + tree = &aw->aw_tree; + if (mdb_vread(tree, sizeof (avl_tree_t), wsp->walk_addr) == -1) { + mdb_warn("read of avl_tree_t failed: %p", wsp->walk_addr); + goto error; + } + if (tree->avl_size < tree->avl_offset + sizeof (avl_node_t)) { + mdb_warn("invalid avl_tree_t at %p, avl_size:%d, avl_offset:%d", + wsp->walk_addr, tree->avl_size, tree->avl_offset); + goto error; + } + + /* + * allocate a buffer to hold the mdb copy of tree's structs + * "node" always points at the avl_node_t field inside the struct + */ + aw->aw_buff = mdb_zalloc(tree->avl_size, UM_SLEEP); + + /* + * get the first avl_node_t address, use same algorithm + * as avl_start() -- leftmost child in tree from root + */ + addr = (uintptr_t)tree->avl_root; + if (addr == NULL) { + wsp->walk_addr = NULL; + return (WALK_NEXT); + } + addr = avl_leftmostchild(addr, aw->aw_buff, tree->avl_offset, + tree->avl_size); + if (addr == (uintptr_t)-1L) + goto error; + + wsp->walk_addr = addr; + return (WALK_NEXT); + +error: + if (aw->aw_buff != NULL) + mdb_free(aw->aw_buff, sizeof (tree->avl_size)); + mdb_free(aw, sizeof (struct aw_info)); + return (WALK_ERR); +} + +/* + * At each step, visit (callback) the current node, then move to the next + * in the AVL tree. Uses the same algorithm as avl_walk(). + */ +int +avl_walk_step(mdb_walk_state_t *wsp) +{ + struct aw_info *aw; + size_t offset; + size_t size; + uintptr_t addr; + avl_node_t *node; + int status; + int was_child; + + /* + * don't walk past the end of the tree! + */ + addr = wsp->walk_addr; + if (addr == NULL) + return (WALK_DONE); + + aw = (struct aw_info *)wsp->walk_data; + size = aw->aw_tree.avl_size; + offset = aw->aw_tree.avl_offset; + node = (avl_node_t *)((uintptr_t)aw->aw_buff + offset); + + /* + * must read the current node for the call back to use + */ + if (mdb_vread(aw->aw_buff, size, addr) == -1) { + mdb_warn("read of avl_node_t failed: %p", addr); + return (WALK_ERR); + } + + /* + * do the call back + */ + status = wsp->walk_callback(addr, aw->aw_buff, wsp->walk_cbdata); + if (status != WALK_NEXT) + return (status); + + /* + * move to the next node.... + * note we read in new nodes, so the pointer to the buffer is fixed + */ + + /* + * if the node has a right child then go to it and then all the way + * thru as many left children as possible + */ + addr = (uintptr_t)node->avl_child[1]; + if (addr != NULL) { + addr = avl_leftmostchild(addr, aw->aw_buff, offset, size); + if (addr == (uintptr_t)-1L) + return (WALK_ERR); + + /* + * othewise return to parent nodes, stopping if we ever return from + * a left child + */ + } else { + for (;;) { + was_child = AVL_XCHILD(node); + addr = (uintptr_t)AVL_XPARENT(node); + if (addr == NULL) + break; + addr -= offset; + if (was_child == 0) /* stop on return from left child */ + break; + if (mdb_vread(aw->aw_buff, size, addr) == -1) { + mdb_warn("read of avl_node_t failed: %p", addr); + return (WALK_ERR); + } + } + } + + wsp->walk_addr = addr; + return (WALK_NEXT); +} + +/* + * Release the memory allocated for the walk + */ +void +avl_walk_fini(mdb_walk_state_t *wsp) +{ + struct aw_info *aw; + + aw = (struct aw_info *)wsp->walk_data; + + if (aw == NULL) + return; + + if (aw->aw_buff != NULL) + mdb_free(aw->aw_buff, aw->aw_tree.avl_size); + + mdb_free(aw, sizeof (struct aw_info)); +} |