Home | History | Annotate | Download | only in zfs
      1    789    ahrens /*
      2    789    ahrens  * CDDL HEADER START
      3    789    ahrens  *
      4    789    ahrens  * The contents of this file are subject to the terms of the
      5   1544  eschrock  * Common Development and Distribution License (the "License").
      6   1544  eschrock  * You may not use this file except in compliance with the License.
      7    789    ahrens  *
      8    789    ahrens  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9    789    ahrens  * or http://www.opensolaris.org/os/licensing.
     10    789    ahrens  * See the License for the specific language governing permissions
     11    789    ahrens  * and limitations under the License.
     12    789    ahrens  *
     13    789    ahrens  * When distributing Covered Code, include this CDDL HEADER in each
     14    789    ahrens  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15    789    ahrens  * If applicable, add the following below this CDDL HEADER, with the
     16    789    ahrens  * fields enclosed by brackets "[]" replaced with your own identifying
     17    789    ahrens  * information: Portions Copyright [yyyy] [name of copyright owner]
     18    789    ahrens  *
     19    789    ahrens  * CDDL HEADER END
     20    789    ahrens  */
     21    789    ahrens /*
     22   8632      Bill  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
     23    789    ahrens  * Use is subject to license terms.
     24    789    ahrens  */
     25    789    ahrens 
     26    789    ahrens #include <mdb/mdb_ctf.h>
     27    789    ahrens #include <sys/zfs_context.h>
     28    789    ahrens #include <sys/mdb_modapi.h>
     29    789    ahrens #include <sys/dbuf.h>
     30    789    ahrens #include <sys/dmu_objset.h>
     31    789    ahrens #include <sys/dsl_dir.h>
     32    789    ahrens #include <sys/dsl_pool.h>
     33    789    ahrens #include <sys/metaslab_impl.h>
     34    789    ahrens #include <sys/space_map.h>
     35    789    ahrens #include <sys/list.h>
     36    789    ahrens #include <sys/spa_impl.h>
     37    789    ahrens #include <sys/vdev_impl.h>
     38  10407   Matthew #include <ctype.h>
     39    789    ahrens 
     40    789    ahrens #ifndef _KERNEL
     41    789    ahrens #include "../genunix/list.h"
     42    789    ahrens #endif
     43    789    ahrens 
     44    789    ahrens #ifdef _KERNEL
     45    789    ahrens #define	ZFS_OBJ_NAME	"zfs"
     46    789    ahrens #else
     47    789    ahrens #define	ZFS_OBJ_NAME	"libzpool.so.1"
     48    789    ahrens #endif
     49    789    ahrens 
     50    789    ahrens static int
     51    789    ahrens getmember(uintptr_t addr, const char *type, mdb_ctf_id_t *idp,
     52    789    ahrens     const char *member, int len, void *buf)
     53    789    ahrens {
     54    789    ahrens 	mdb_ctf_id_t id;
     55    789    ahrens 	ulong_t off;
     56    789    ahrens 	char name[64];
     57    789    ahrens 
     58    789    ahrens 	if (idp == NULL) {
     59    789    ahrens 		if (mdb_ctf_lookup_by_name(type, &id) == -1) {
     60    789    ahrens 			mdb_warn("couldn't find type %s", type);
     61    789    ahrens 			return (DCMD_ERR);
     62    789    ahrens 		}
     63    789    ahrens 		idp = &id;
     64    789    ahrens 	} else {
     65    789    ahrens 		type = name;
     66    789    ahrens 		mdb_ctf_type_name(*idp, name, sizeof (name));
     67    789    ahrens 	}
     68    789    ahrens 
     69    789    ahrens 	if (mdb_ctf_offsetof(*idp, member, &off) == -1) {
     70    789    ahrens 		mdb_warn("couldn't find member %s of type %s\n", member, type);
     71    789    ahrens 		return (DCMD_ERR);
     72    789    ahrens 	}
     73    789    ahrens 	if (off % 8 != 0) {
     74    789    ahrens 		mdb_warn("member %s of type %s is unsupported bitfield",
     75    789    ahrens 		    member, type);
     76    789    ahrens 		return (DCMD_ERR);
     77    789    ahrens 	}
     78    789    ahrens 	off /= 8;
     79    789    ahrens 
     80    789    ahrens 	if (mdb_vread(buf, len, addr + off) == -1) {
     81    789    ahrens 		mdb_warn("failed to read %s from %s at %p",
     82    789    ahrens 		    member, type, addr + off);
     83    789    ahrens 		return (DCMD_ERR);
     84    789    ahrens 	}
     85    789    ahrens 	/* mdb_warn("read %s from %s at %p+%llx\n", member, type, addr, off); */
     86    789    ahrens 
     87    789    ahrens 	return (0);
     88    789    ahrens }
     89    789    ahrens 
     90    789    ahrens #define	GETMEMB(addr, type, member, dest) \
     91    789    ahrens 	getmember(addr, #type, NULL, #member, sizeof (dest), &(dest))
     92    789    ahrens 
     93    789    ahrens #define	GETMEMBID(addr, ctfid, member, dest) \
     94    789    ahrens 	getmember(addr, NULL, ctfid, #member, sizeof (dest), &(dest))
     95    789    ahrens 
     96    789    ahrens static int
     97    789    ahrens getrefcount(uintptr_t addr, mdb_ctf_id_t *id,
     98    789    ahrens     const char *member, uint64_t *rc)
     99    789    ahrens {
    100    789    ahrens 	static int gotid;
    101    789    ahrens 	static mdb_ctf_id_t rc_id;
    102    789    ahrens 	ulong_t off;
    103    789    ahrens 
    104    789    ahrens 	if (!gotid) {
    105    789    ahrens 		if (mdb_ctf_lookup_by_name("struct refcount", &rc_id) == -1) {
    106    789    ahrens 			mdb_warn("couldn't find struct refcount");
    107    789    ahrens 			return (DCMD_ERR);
    108    789    ahrens 		}
    109    789    ahrens 		gotid = TRUE;
    110    789    ahrens 	}
    111    789    ahrens 
    112    789    ahrens 	if (mdb_ctf_offsetof(*id, member, &off) == -1) {
    113    789    ahrens 		char name[64];
    114    789    ahrens 		mdb_ctf_type_name(*id, name, sizeof (name));
    115    789    ahrens 		mdb_warn("couldn't find member %s of type %s\n", member, name);
    116    789    ahrens 		return (DCMD_ERR);
    117    789    ahrens 	}
    118    789    ahrens 	off /= 8;
    119    789    ahrens 
    120    789    ahrens 	return (GETMEMBID(addr + off, &rc_id, rc_count, *rc));
    121    789    ahrens }
    122    789    ahrens 
    123    789    ahrens static int verbose;
    124    789    ahrens 
    125    789    ahrens static int
    126    789    ahrens freelist_walk_init(mdb_walk_state_t *wsp)
    127    789    ahrens {
    128    789    ahrens 	if (wsp->walk_addr == NULL) {
    129    789    ahrens 		mdb_warn("must supply starting address\n");
    130    789    ahrens 		return (WALK_ERR);
    131    789    ahrens 	}
    132    789    ahrens 
    133    789    ahrens 	wsp->walk_data = 0;  /* Index into the freelist */
    134    789    ahrens 	return (WALK_NEXT);
    135    789    ahrens }
    136    789    ahrens 
    137    789    ahrens static int
    138    789    ahrens freelist_walk_step(mdb_walk_state_t *wsp)
    139    789    ahrens {
    140    789    ahrens 	uint64_t entry;
    141    789    ahrens 	uintptr_t number = (uintptr_t)wsp->walk_data;
    142   3361  ck153898 	char *ddata[] = { "ALLOC", "FREE", "CONDENSE", "INVALID",
    143   3361  ck153898 			    "INVALID", "INVALID", "INVALID", "INVALID" };
    144    789    ahrens 	int mapshift = SPA_MINBLOCKSHIFT;
    145    789    ahrens 
    146    789    ahrens 	if (mdb_vread(&entry, sizeof (entry), wsp->walk_addr) == -1) {
    147    789    ahrens 		mdb_warn("failed to read freelist entry %p", wsp->walk_addr);
    148    789    ahrens 		return (WALK_DONE);
    149    789    ahrens 	}
    150    789    ahrens 	wsp->walk_addr += sizeof (entry);
    151    789    ahrens 	wsp->walk_data = (void *)(number + 1);
    152    789    ahrens 
    153    789    ahrens 	if (SM_DEBUG_DECODE(entry)) {
    154    789    ahrens 		mdb_printf("DEBUG: %3u  %10s: txg=%llu  pass=%llu\n",
    155    789    ahrens 		    number,
    156    789    ahrens 		    ddata[SM_DEBUG_ACTION_DECODE(entry)],
    157    789    ahrens 		    SM_DEBUG_TXG_DECODE(entry),
    158    789    ahrens 		    SM_DEBUG_SYNCPASS_DECODE(entry));
    159    789    ahrens 	} else {
    160    789    ahrens 		mdb_printf("Entry: %3u  offsets=%08llx-%08llx  type=%c  "
    161    789    ahrens 		    "size=%06llx", number,
    162    789    ahrens 		    SM_OFFSET_DECODE(entry) << mapshift,
    163    789    ahrens 		    (SM_OFFSET_DECODE(entry) + SM_RUN_DECODE(entry)) <<
    164    789    ahrens 		    mapshift,
    165    789    ahrens 		    SM_TYPE_DECODE(entry) == SM_ALLOC ? 'A' : 'F',
    166    789    ahrens 		    SM_RUN_DECODE(entry) << mapshift);
    167    789    ahrens 		if (verbose)
    168    789    ahrens 			mdb_printf("      (raw=%012llx)\n", entry);
    169    789    ahrens 		mdb_printf("\n");
    170    789    ahrens 	}
    171    789    ahrens 	return (WALK_NEXT);
    172    789    ahrens }
    173    789    ahrens 
    174    789    ahrens 
    175    789    ahrens static int
    176    789    ahrens dataset_name(uintptr_t addr, char *buf)
    177    789    ahrens {
    178    789    ahrens 	static int gotid;
    179    789    ahrens 	static mdb_ctf_id_t dd_id;
    180    789    ahrens 	uintptr_t dd_parent;
    181    789    ahrens 	char dd_myname[MAXNAMELEN];
    182    789    ahrens 
    183    789    ahrens 	if (!gotid) {
    184    789    ahrens 		if (mdb_ctf_lookup_by_name("struct dsl_dir",
    185    789    ahrens 		    &dd_id) == -1) {
    186    789    ahrens 			mdb_warn("couldn't find struct dsl_dir");
    187    789    ahrens 			return (DCMD_ERR);
    188    789    ahrens 		}
    189    789    ahrens 		gotid = TRUE;
    190    789    ahrens 	}
    191    789    ahrens 	if (GETMEMBID(addr, &dd_id, dd_parent, dd_parent) ||
    192    789    ahrens 	    GETMEMBID(addr, &dd_id, dd_myname, dd_myname)) {
    193    789    ahrens 		return (DCMD_ERR);
    194    789    ahrens 	}
    195    789    ahrens 
    196    789    ahrens 	if (dd_parent) {
    197    789    ahrens 		if (dataset_name(dd_parent, buf))
    198    789    ahrens 			return (DCMD_ERR);
    199    789    ahrens 		strcat(buf, "/");
    200    789    ahrens 	}
    201    789    ahrens 
    202    789    ahrens 	if (dd_myname[0])
    203    789    ahrens 		strcat(buf, dd_myname);
    204    789    ahrens 	else
    205    789    ahrens 		strcat(buf, "???");
    206    789    ahrens 
    207    789    ahrens 	return (0);
    208    789    ahrens }
    209    789    ahrens 
    210    789    ahrens static int
    211    789    ahrens objset_name(uintptr_t addr, char *buf)
    212    789    ahrens {
    213    789    ahrens 	static int gotid;
    214  10298   Matthew 	static mdb_ctf_id_t os_id, ds_id;
    215    789    ahrens 	uintptr_t os_dsl_dataset;
    216    789    ahrens 	char ds_snapname[MAXNAMELEN];
    217    789    ahrens 	uintptr_t ds_dir;
    218    789    ahrens 
    219    789    ahrens 	buf[0] = '\0';
    220    789    ahrens 
    221    789    ahrens 	if (!gotid) {
    222  10298   Matthew 		if (mdb_ctf_lookup_by_name("struct objset",
    223  10298   Matthew 		    &os_id) == -1) {
    224  10298   Matthew 			mdb_warn("couldn't find struct objset");
    225    789    ahrens 			return (DCMD_ERR);
    226    789    ahrens 		}
    227    789    ahrens 		if (mdb_ctf_lookup_by_name("struct dsl_dataset",
    228    789    ahrens 		    &ds_id) == -1) {
    229    789    ahrens 			mdb_warn("couldn't find struct dsl_dataset");
    230    789    ahrens 			return (DCMD_ERR);
    231    789    ahrens 		}
    232    789    ahrens 
    233    789    ahrens 		gotid = TRUE;
    234    789    ahrens 	}
    235    789    ahrens 
    236  10298   Matthew 	if (GETMEMBID(addr, &os_id, os_dsl_dataset, os_dsl_dataset))
    237    789    ahrens 		return (DCMD_ERR);
    238    789    ahrens 
    239    789    ahrens 	if (os_dsl_dataset == 0) {
    240    789    ahrens 		strcat(buf, "mos");
    241    789    ahrens 		return (0);
    242    789    ahrens 	}
    243    789    ahrens 
    244    789    ahrens 	if (GETMEMBID(os_dsl_dataset, &ds_id, ds_snapname, ds_snapname) ||
    245    789    ahrens 	    GETMEMBID(os_dsl_dataset, &ds_id, ds_dir, ds_dir)) {
    246    789    ahrens 		return (DCMD_ERR);
    247    789    ahrens 	}
    248    789    ahrens 
    249    789    ahrens 	if (ds_dir && dataset_name(ds_dir, buf))
    250    789    ahrens 		return (DCMD_ERR);
    251    789    ahrens 
    252    789    ahrens 	if (ds_snapname[0]) {
    253    789    ahrens 		strcat(buf, "@");
    254    789    ahrens 		strcat(buf, ds_snapname);
    255    789    ahrens 	}
    256    789    ahrens 	return (0);
    257    789    ahrens }
    258    789    ahrens 
    259    789    ahrens static void
    260    789    ahrens enum_lookup(char *out, size_t size, mdb_ctf_id_t id, int val,
    261    789    ahrens     const char *prefix)
    262    789    ahrens {
    263    789    ahrens 	const char *cp;
    264    789    ahrens 	size_t len = strlen(prefix);
    265    789    ahrens 
    266    789    ahrens 	if ((cp = mdb_ctf_enum_name(id, val)) != NULL) {
    267    789    ahrens 		if (strncmp(cp, prefix, len) == 0)
    268    789    ahrens 			cp += len;
    269    789    ahrens 		(void) strncpy(out, cp, size);
    270    789    ahrens 	} else {
    271    789    ahrens 		mdb_snprintf(out, size, "? (%d)", val);
    272    789    ahrens 	}
    273    789    ahrens }
    274    789    ahrens 
    275    789    ahrens /* ARGSUSED */
    276    789    ahrens static int
    277   3059    ahrens zfs_params(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
    278   3059    ahrens {
    279   3059    ahrens 	/*
    280   3059    ahrens 	 * This table can be approximately generated by running:
    281   3059    ahrens 	 * egrep "^[a-z0-9_]+ [a-z0-9_]+( =.*)?;" *.c | cut -d ' ' -f 2
    282   3059    ahrens 	 */
    283   3059    ahrens 	static const char *params[] = {
    284   3059    ahrens 		"arc_reduce_dnlc_percent",
    285   3059    ahrens 		"zfs_arc_max",
    286   3059    ahrens 		"zfs_arc_min",
    287   3158    maybee 		"arc_shrink_shift",
    288   3059    ahrens 		"zfs_mdcomp_disable",
    289   3059    ahrens 		"zfs_prefetch_disable",
    290   3059    ahrens 		"zfetch_max_streams",
    291   3059    ahrens 		"zfetch_min_sec_reap",
    292   3059    ahrens 		"zfetch_block_cap",
    293   3059    ahrens 		"zfetch_array_rd_sz",
    294   3059    ahrens 		"zfs_default_bs",
    295   3059    ahrens 		"zfs_default_ibs",
    296   3059    ahrens 		"metaslab_aliquot",
    297   3059    ahrens 		"reference_tracking_enable",
    298   3059    ahrens 		"reference_history",
    299   3059    ahrens 		"spa_max_replication_override",
    300  10922      Jeff 		"spa_mode_global",
    301   3059    ahrens 		"zfs_flags",
    302   6245    maybee 		"zfs_txg_synctime",
    303   6245    maybee 		"zfs_txg_timeout",
    304   6245    maybee 		"zfs_write_limit_min",
    305   6245    maybee 		"zfs_write_limit_max",
    306   6245    maybee 		"zfs_write_limit_shift",
    307   6245    maybee 		"zfs_write_limit_override",
    308   6245    maybee 		"zfs_no_write_throttle",
    309   3059    ahrens 		"zfs_vdev_cache_max",
    310   3059    ahrens 		"zfs_vdev_cache_size",
    311   3059    ahrens 		"zfs_vdev_cache_bshift",
    312   3059    ahrens 		"vdev_mirror_shift",
    313   3059    ahrens 		"zfs_vdev_max_pending",
    314   3059    ahrens 		"zfs_vdev_min_pending",
    315   3059    ahrens 		"zfs_scrub_limit",
    316  11147    George 		"zfs_no_scrub_io",
    317  11147    George 		"zfs_no_scrub_prefetch",
    318   3059    ahrens 		"zfs_vdev_time_shift",
    319   3059    ahrens 		"zfs_vdev_ramp_rate",
    320   3059    ahrens 		"zfs_vdev_aggregation_limit",
    321   3059    ahrens 		"fzap_default_block_shift",
    322   3059    ahrens 		"zfs_immediate_write_sz",
    323   3059    ahrens 		"zfs_read_chunk_size",
    324   3059    ahrens 		"zil_disable",
    325   3059    ahrens 		"zfs_nocacheflush",
    326   6245    maybee 		"metaslab_gang_bang",
    327   9480    George 		"metaslab_df_alloc_threshold",
    328   9480    George 		"metaslab_df_free_pct",
    329   3059    ahrens 		"zio_injection_enabled",
    330   3059    ahrens 		"zvol_immediate_write_sz",
    331   3059    ahrens 	};
    332   3059    ahrens 
    333  10922      Jeff 	for (int i = 0; i < sizeof (params) / sizeof (params[0]); i++) {
    334   3059    ahrens 		int sz;
    335   3059    ahrens 		uint64_t val64;
    336   3059    ahrens 		uint32_t *val32p = (uint32_t *)&val64;
    337   3059    ahrens 
    338   3059    ahrens 		sz = mdb_readvar(&val64, params[i]);
    339   3059    ahrens 		if (sz == 4) {
    340   3059    ahrens 			mdb_printf("%s = 0x%x\n", params[i], *val32p);
    341   3059    ahrens 		} else if (sz == 8) {
    342   3059    ahrens 			mdb_printf("%s = 0x%llx\n", params[i], val64);
    343   3059    ahrens 		} else {
    344   3059    ahrens 			mdb_warn("variable %s not found", params[i]);
    345    789    ahrens 		}
    346    789    ahrens 	}
    347    789    ahrens 
    348    789    ahrens 	return (DCMD_OK);
    349    789    ahrens }
    350    789    ahrens 
    351    789    ahrens /* ARGSUSED */
    352    789    ahrens static int
    353    789    ahrens blkptr(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
    354    789    ahrens {
    355  10922      Jeff 	mdb_ctf_id_t type_enum, checksum_enum, compress_enum;
    356  10922      Jeff 	char type[80], checksum[80], compress[80];
    357  10922      Jeff 	blkptr_t blk, *bp = &blk;
    358  10922      Jeff 	char buf[BP_SPRINTF_LEN];
    359    789    ahrens 
    360  10922      Jeff 	if (mdb_vread(&blk, sizeof (blkptr_t), addr) == -1) {
    361    789    ahrens 		mdb_warn("failed to read blkptr_t");
    362    789    ahrens 		return (DCMD_ERR);
    363    789    ahrens 	}
    364    789    ahrens 
    365  10922      Jeff 	if (mdb_ctf_lookup_by_name("enum dmu_object_type", &type_enum) == -1 ||
    366  10922      Jeff 	    mdb_ctf_lookup_by_name("enum zio_checksum", &checksum_enum) == -1 ||
    367  10922      Jeff 	    mdb_ctf_lookup_by_name("enum zio_compress", &compress_enum) == -1) {
    368  10922      Jeff 		mdb_warn("Could not find blkptr enumerated types");
    369    789    ahrens 		return (DCMD_ERR);
    370    789    ahrens 	}
    371    789    ahrens 
    372  10922      Jeff 	enum_lookup(type, sizeof (type), type_enum,
    373  10922      Jeff 	    BP_GET_TYPE(bp), "DMU_OT_");
    374  10922      Jeff 	enum_lookup(checksum, sizeof (checksum), checksum_enum,
    375  10922      Jeff 	    BP_GET_CHECKSUM(bp), "ZIO_CHECKSUM_");
    376  10922      Jeff 	enum_lookup(compress, sizeof (compress), compress_enum,
    377  10922      Jeff 	    BP_GET_COMPRESS(bp), "ZIO_COMPRESS_");
    378    789    ahrens 
    379  10922      Jeff 	SPRINTF_BLKPTR(mdb_snprintf, '\n', buf, bp, type, checksum, compress);
    380    789    ahrens 
    381  10922      Jeff 	mdb_printf("%s\n", buf);
    382    789    ahrens 
    383    789    ahrens 	return (DCMD_OK);
    384    789    ahrens }
    385    789    ahrens 
    386    789    ahrens /* ARGSUSED */
    387    789    ahrens static int
    388    789    ahrens dbuf(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
    389    789    ahrens {
    390    789    ahrens 	mdb_ctf_id_t id;
    391    789    ahrens 	dmu_buf_t db;
    392    789    ahrens 	uintptr_t objset;
    393    789    ahrens 	uint8_t level;
    394    789    ahrens 	uint64_t blkid;
    395    789    ahrens 	uint64_t holds;
    396    789    ahrens 	char objectname[32];
    397    789    ahrens 	char blkidname[32];
    398    789    ahrens 	char path[MAXNAMELEN];
    399    789    ahrens 
    400    789    ahrens 	if (DCMD_HDRSPEC(flags)) {
    401    789    ahrens 		mdb_printf("        addr object lvl blkid holds os\n");
    402    789    ahrens 	}
    403    789    ahrens 
    404    789    ahrens 	if (mdb_ctf_lookup_by_name("struct dmu_buf_impl", &id) == -1) {
    405    789    ahrens 		mdb_warn("couldn't find struct dmu_buf_impl_t");
    406    789    ahrens 		return (DCMD_ERR);
    407    789    ahrens 	}
    408    789    ahrens 
    409    789    ahrens 	if (GETMEMBID(addr, &id, db_objset, objset) ||
    410    789    ahrens 	    GETMEMBID(addr, &id, db, db) ||
    411    789    ahrens 	    GETMEMBID(addr, &id, db_level, level) ||
    412    789    ahrens 	    GETMEMBID(addr, &id, db_blkid, blkid)) {
    413    789    ahrens 		return (WALK_ERR);
    414    789    ahrens 	}
    415    789    ahrens 
    416    789    ahrens 	if (getrefcount(addr, &id, "db_holds", &holds)) {
    417    789    ahrens 		return (WALK_ERR);
    418    789    ahrens 	}
    419    789    ahrens 
    420    789    ahrens 	if (db.db_object == DMU_META_DNODE_OBJECT)
    421    789    ahrens 		(void) strcpy(objectname, "mdn");
    422    789    ahrens 	else
    423    789    ahrens 		(void) mdb_snprintf(objectname, sizeof (objectname), "%llx",
    424    789    ahrens 		    (u_longlong_t)db.db_object);
    425    789    ahrens 
    426    789    ahrens 	if (blkid == DB_BONUS_BLKID)
    427    789    ahrens 		(void) strcpy(blkidname, "bonus");
    428    789    ahrens 	else
    429    789    ahrens 		(void) mdb_snprintf(blkidname, sizeof (blkidname), "%llx",
    430    789    ahrens 		    (u_longlong_t)blkid);
    431    789    ahrens 
    432    789    ahrens 	if (objset_name(objset, path)) {
    433    789    ahrens 		return (WALK_ERR);
    434    789    ahrens 	}
    435    789    ahrens 
    436    789    ahrens 	mdb_printf("%p %8s %1u %9s %2llu %s\n",
    437    789    ahrens 	    addr, objectname, level, blkidname, holds, path);
    438    789    ahrens 
    439    789    ahrens 	return (DCMD_OK);
    440    789    ahrens }
    441    789    ahrens 
    442    789    ahrens /* ARGSUSED */
    443    789    ahrens static int
    444    789    ahrens dbuf_stats(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
    445    789    ahrens {
    446    789    ahrens #define	HISTOSZ 32
    447    789    ahrens 	uintptr_t dbp;
    448    789    ahrens 	dmu_buf_impl_t db;
    449    789    ahrens 	dbuf_hash_table_t ht;
    450    789    ahrens 	uint64_t bucket, ndbufs;
    451    789    ahrens 	uint64_t histo[HISTOSZ];
    452    789    ahrens 	uint64_t histo2[HISTOSZ];
    453    789    ahrens 	int i, maxidx;
    454    789    ahrens 
    455    789    ahrens 	if (mdb_readvar(&ht, "dbuf_hash_table") == -1) {
    456    789    ahrens 		mdb_warn("failed to read 'dbuf_hash_table'");
    457    789    ahrens 		return (DCMD_ERR);
    458    789    ahrens 	}
    459    789    ahrens 
    460    789    ahrens 	for (i = 0; i < HISTOSZ; i++) {
    461    789    ahrens 		histo[i] = 0;
    462    789    ahrens 		histo2[i] = 0;
    463    789    ahrens 	}
    464    789    ahrens 
    465    789    ahrens 	ndbufs = 0;
    466    789    ahrens 	for (bucket = 0; bucket < ht.hash_table_mask+1; bucket++) {
    467    789    ahrens 		int len;
    468    789    ahrens 
    469    789    ahrens 		if (mdb_vread(&dbp, sizeof (void *),
    470    789    ahrens 		    (uintptr_t)(ht.hash_table+bucket)) == -1) {
    471    789    ahrens 			mdb_warn("failed to read hash bucket %u at %p",
    472    789    ahrens 			    bucket, ht.hash_table+bucket);
    473    789    ahrens 			return (DCMD_ERR);
    474    789    ahrens 		}
    475    789    ahrens 
    476    789    ahrens 		len = 0;
    477    789    ahrens 		while (dbp != 0) {
    478    789    ahrens 			if (mdb_vread(&db, sizeof (dmu_buf_impl_t),
    479    789    ahrens 			    dbp) == -1) {
    480    789    ahrens 				mdb_warn("failed to read dbuf at %p", dbp);
    481    789    ahrens 				return (DCMD_ERR);
    482    789    ahrens 			}
    483    789    ahrens 			dbp = (uintptr_t)db.db_hash_next;
    484    789    ahrens 			for (i = MIN(len, HISTOSZ - 1); i >= 0; i--)
    485    789    ahrens 				histo2[i]++;
    486    789    ahrens 			len++;
    487    789    ahrens 			ndbufs++;
    488    789    ahrens 		}
    489    789    ahrens 
    490    789    ahrens 		if (len >= HISTOSZ)
    491    789    ahrens 			len = HISTOSZ-1;
    492    789    ahrens 		histo[len]++;
    493    789    ahrens 	}
    494    789    ahrens 
    495    789    ahrens 	mdb_printf("hash table has %llu buckets, %llu dbufs "
    496    789    ahrens 	    "(avg %llu buckets/dbuf)\n",
    497    789    ahrens 	    ht.hash_table_mask+1, ndbufs,
    498    789    ahrens 	    (ht.hash_table_mask+1)/ndbufs);
    499    789    ahrens 
    500    789    ahrens 	mdb_printf("\n");
    501    789    ahrens 	maxidx = 0;
    502    789    ahrens 	for (i = 0; i < HISTOSZ; i++)
    503    789    ahrens 		if (histo[i] > 0)
    504    789    ahrens 			maxidx = i;
    505    789    ahrens 	mdb_printf("hash chain length	number of buckets\n");
    506    789    ahrens 	for (i = 0; i <= maxidx; i++)
    507    789    ahrens 		mdb_printf("%u			%llu\n", i, histo[i]);
    508    789    ahrens 
    509    789    ahrens 	mdb_printf("\n");
    510    789    ahrens 	maxidx = 0;
    511    789    ahrens 	for (i = 0; i < HISTOSZ; i++)
    512    789    ahrens 		if (histo2[i] > 0)
    513    789    ahrens 			maxidx = i;
    514    789    ahrens 	mdb_printf("hash chain depth	number of dbufs\n");
    515    789    ahrens 	for (i = 0; i <= maxidx; i++)
    516    789    ahrens 		mdb_printf("%u or more		%llu	%llu%%\n",
    517    789    ahrens 		    i, histo2[i], histo2[i]*100/ndbufs);
    518    789    ahrens 
    519    789    ahrens 
    520    789    ahrens 	return (DCMD_OK);
    521    789    ahrens }
    522    789    ahrens 
    523    789    ahrens typedef struct dbufs_data {
    524    789    ahrens 	mdb_ctf_id_t id;
    525    789    ahrens 	uint64_t objset;
    526    789    ahrens 	uint64_t object;
    527    789    ahrens 	uint64_t level;
    528    789    ahrens 	uint64_t blkid;
    529    789    ahrens 	char *osname;
    530    789    ahrens } dbufs_data_t;
    531    789    ahrens 
    532    789    ahrens #define	DBUFS_UNSET	(0xbaddcafedeadbeefULL)
    533    789    ahrens 
    534    789    ahrens /* ARGSUSED */
    535    789    ahrens static int
    536    789    ahrens dbufs_cb(uintptr_t addr, const void *unknown, void *arg)
    537    789    ahrens {
    538    789    ahrens 	dbufs_data_t *data = arg;
    539    789    ahrens 	uintptr_t objset;
    540    789    ahrens 	dmu_buf_t db;
    541    789    ahrens 	uint8_t level;
    542    789    ahrens 	uint64_t blkid;
    543    789    ahrens 	char osname[MAXNAMELEN];
    544    789    ahrens 
    545    789    ahrens 	if (GETMEMBID(addr, &data->id, db_objset, objset) ||
    546    789    ahrens 	    GETMEMBID(addr, &data->id, db, db) ||
    547    789    ahrens 	    GETMEMBID(addr, &data->id, db_level, level) ||
    548    789    ahrens 	    GETMEMBID(addr, &data->id, db_blkid, blkid)) {
    549    789    ahrens 		return (WALK_ERR);
    550    789    ahrens 	}
    551    789    ahrens 
    552    789    ahrens 	if ((data->objset == DBUFS_UNSET || data->objset == objset) &&
    553    789    ahrens 	    (data->osname == NULL || (objset_name(objset, osname) == 0 &&
    554   4055  eschrock 	    strcmp(data->osname, osname) == 0)) &&
    555    789    ahrens 	    (data->object == DBUFS_UNSET || data->object == db.db_object) &&
    556    789    ahrens 	    (data->level == DBUFS_UNSET || data->level == level) &&
    557    789    ahrens 	    (data->blkid == DBUFS_UNSET || data->blkid == blkid)) {
    558    789    ahrens 		mdb_printf("%#lr\n", addr);
    559    789    ahrens 	}
    560    789    ahrens 	return (WALK_NEXT);
    561    789    ahrens }
    562    789    ahrens 
    563    789    ahrens /* ARGSUSED */
    564    789    ahrens static int
    565    789    ahrens dbufs(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
    566    789    ahrens {
    567    789    ahrens 	dbufs_data_t data;
    568    789    ahrens 	char *object = NULL;
    569    789    ahrens 	char *blkid = NULL;
    570    789    ahrens 
    571    789    ahrens 	data.objset = data.object = data.level = data.blkid = DBUFS_UNSET;
    572    789    ahrens 	data.osname = NULL;
    573    789    ahrens 
    574    789    ahrens 	if (mdb_getopts(argc, argv,
    575    789    ahrens 	    'O', MDB_OPT_UINT64, &data.objset,
    576    789    ahrens 	    'n', MDB_OPT_STR, &data.osname,
    577    789    ahrens 	    'o', MDB_OPT_STR, &object,
    578    789    ahrens 	    'l', MDB_OPT_UINT64, &data.level,
    579    789    ahrens 	    'b', MDB_OPT_STR, &blkid) != argc) {
    580    789    ahrens 		return (DCMD_USAGE);
    581    789    ahrens 	}
    582    789    ahrens 
    583    789    ahrens 	if (object) {
    584    789    ahrens 		if (strcmp(object, "mdn") == 0) {
    585    789    ahrens 			data.object = DMU_META_DNODE_OBJECT;
    586    789    ahrens 		} else {
    587    789    ahrens 			data.object = mdb_strtoull(object);
    588    789    ahrens 		}
    589    789    ahrens 	}
    590    789    ahrens 
    591    789    ahrens 	if (blkid) {
    592    789    ahrens 		if (strcmp(blkid, "bonus") == 0) {
    593    789    ahrens 			data.blkid = DB_BONUS_BLKID;
    594    789    ahrens 		} else {
    595    789    ahrens 			data.blkid = mdb_strtoull(blkid);
    596    789    ahrens 		}
    597    789    ahrens 	}
    598    789    ahrens 
    599    789    ahrens 	if (mdb_ctf_lookup_by_name("struct dmu_buf_impl", &data.id) == -1) {
    600    789    ahrens 		mdb_warn("couldn't find struct dmu_buf_impl_t");
    601    789    ahrens 		return (DCMD_ERR);
    602    789    ahrens 	}
    603    789    ahrens 
    604   2459    ahrens 	if (mdb_walk("dmu_buf_impl_t", dbufs_cb, &data) != 0) {
    605    789    ahrens 		mdb_warn("can't walk dbufs");
    606    789    ahrens 		return (DCMD_ERR);
    607    789    ahrens 	}
    608    789    ahrens 
    609    789    ahrens 	return (DCMD_OK);
    610    789    ahrens }
    611    789    ahrens 
    612    789    ahrens typedef struct abuf_find_data {
    613    789    ahrens 	dva_t dva;
    614    789    ahrens 	mdb_ctf_id_t id;
    615    789    ahrens } abuf_find_data_t;
    616    789    ahrens 
    617    789    ahrens /* ARGSUSED */
    618    789    ahrens static int
    619    789    ahrens abuf_find_cb(uintptr_t addr, const void *unknown, void *arg)
    620    789    ahrens {
    621    789    ahrens 	abuf_find_data_t *data = arg;
    622    789    ahrens 	dva_t dva;
    623    789    ahrens 
    624    789    ahrens 	if (GETMEMBID(addr, &data->id, b_dva, dva)) {
    625    789    ahrens 		return (WALK_ERR);
    626    789    ahrens 	}
    627    789    ahrens 
    628    789    ahrens 	if (dva.dva_word[0] == data->dva.dva_word[0] &&
    629    789    ahrens 	    dva.dva_word[1] == data->dva.dva_word[1]) {
    630    789    ahrens 		mdb_printf("%#lr\n", addr);
    631    789    ahrens 	}
    632    789    ahrens 	return (WALK_NEXT);
    633    789    ahrens }
    634    789    ahrens 
    635    789    ahrens /* ARGSUSED */
    636    789    ahrens static int
    637    789    ahrens abuf_find(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
    638    789    ahrens {
    639    789    ahrens 	abuf_find_data_t data;
    640    789    ahrens 	GElf_Sym sym;
    641    789    ahrens 	int i;
    642    789    ahrens 	const char *syms[] = {
    643   2885    ahrens 		"ARC_mru",
    644   2885    ahrens 		"ARC_mru_ghost",
    645   2885    ahrens 		"ARC_mfu",
    646   2885    ahrens 		"ARC_mfu_ghost",
    647    789    ahrens 	};
    648    789    ahrens 
    649    789    ahrens 	if (argc != 2)
    650    789    ahrens 		return (DCMD_USAGE);
    651    789    ahrens 
    652    789    ahrens 	for (i = 0; i < 2; i ++) {
    653    789    ahrens 		switch (argv[i].a_type) {
    654    789    ahrens 		case MDB_TYPE_STRING:
    655    789    ahrens 			data.dva.dva_word[i] = mdb_strtoull(argv[i].a_un.a_str);
    656    789    ahrens 			break;
    657    789    ahrens 		case MDB_TYPE_IMMEDIATE:
    658    789    ahrens 			data.dva.dva_word[i] = argv[i].a_un.a_val;
    659    789    ahrens 			break;
    660    789    ahrens 		default:
    661    789    ahrens 			return (DCMD_USAGE);
    662    789    ahrens 		}
    663    789    ahrens 	}
    664    789    ahrens 
    665    789    ahrens 	if (mdb_ctf_lookup_by_name("struct arc_buf_hdr", &data.id) == -1) {
    666    789    ahrens 		mdb_warn("couldn't find struct arc_buf_hdr");
    667    789    ahrens 		return (DCMD_ERR);
    668    789    ahrens 	}
    669    789    ahrens 
    670    789    ahrens 	for (i = 0; i < sizeof (syms) / sizeof (syms[0]); i++) {
    671    789    ahrens 		if (mdb_lookup_by_name(syms[i], &sym)) {
    672    789    ahrens 			mdb_warn("can't find symbol %s", syms[i]);
    673    789    ahrens 			return (DCMD_ERR);
    674    789    ahrens 		}
    675    789    ahrens 
    676    789    ahrens 		if (mdb_pwalk("list", abuf_find_cb, &data, sym.st_value) != 0) {
    677    789    ahrens 			mdb_warn("can't walk %s", syms[i]);
    678    789    ahrens 			return (DCMD_ERR);
    679    789    ahrens 		}
    680    789    ahrens 	}
    681    789    ahrens 
    682    789    ahrens 	return (DCMD_OK);
    683    789    ahrens }
    684    789    ahrens 
    685   3403       bmc /*ARGSUSED*/
    686   3403       bmc static int
    687   3403       bmc arc_print(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
    688   3403       bmc {
    689   3403       bmc 	kstat_named_t *stats;
    690   3403       bmc 	GElf_Sym sym;
    691   4787    ahrens 	int nstats, i;
    692   3403       bmc 	uint_t opt_a = FALSE;
    693   4787    ahrens 	uint_t opt_b = FALSE;
    694   4787    ahrens 	uint_t shift = 0;
    695   4787    ahrens 	const char *suffix;
    696   3403       bmc 
    697   4787    ahrens 	static const char *bytestats[] = {
    698   4787    ahrens 		"p", "c", "c_min", "c_max", "size", NULL
    699   4787    ahrens 	};
    700   4787    ahrens 
    701   4787    ahrens 	static const char *extras[] = {
    702   4787    ahrens 		"arc_no_grow", "arc_tempreserve",
    703   4787    ahrens 		"arc_meta_used", "arc_meta_limit", "arc_meta_max",
    704   4787    ahrens 		NULL
    705   3403       bmc 	};
    706   3403       bmc 
    707   3403       bmc 	if (mdb_lookup_by_name("arc_stats", &sym) == -1) {
    708   3403       bmc 		mdb_warn("failed to find 'arc_stats'");
    709   3403       bmc 		return (DCMD_ERR);
    710   3403       bmc 	}
    711   3403       bmc 
    712   3403       bmc 	stats = mdb_zalloc(sym.st_size, UM_SLEEP | UM_GC);
    713   3403       bmc 
    714   3403       bmc 	if (mdb_vread(stats, sym.st_size, sym.st_value) == -1) {
    715   3403       bmc 		mdb_warn("couldn't read 'arc_stats' at %p", sym.st_value);
    716   3403       bmc 		return (DCMD_ERR);
    717   3403       bmc 	}
    718   3403       bmc 
    719   3403       bmc 	nstats = sym.st_size / sizeof (kstat_named_t);
    720   3403       bmc 
    721   4787    ahrens 	/* NB: -a / opt_a are ignored for backwards compatability */
    722   4787    ahrens 	if (mdb_getopts(argc, argv,
    723   4787    ahrens 	    'a', MDB_OPT_SETBITS, TRUE, &opt_a,
    724   4787    ahrens 	    'b', MDB_OPT_SETBITS, TRUE, &opt_b,
    725   4787    ahrens 	    'k', MDB_OPT_SETBITS, 10, &shift,
    726   4787    ahrens 	    'm', MDB_OPT_SETBITS, 20, &shift,
    727   4787    ahrens 	    'g', MDB_OPT_SETBITS, 30, &shift,
    728   4787    ahrens 	    NULL) != argc)
    729   3403       bmc 		return (DCMD_USAGE);
    730   3403       bmc 
    731   4787    ahrens 	if (!opt_b && !shift)
    732   4787    ahrens 		shift = 20;
    733   3403       bmc 
    734   4787    ahrens 	switch (shift) {
    735   4787    ahrens 	case 0:
    736   4787    ahrens 		suffix = "B";
    737   4787    ahrens 		break;
    738   4787    ahrens 	case 10:
    739   4787    ahrens 		suffix = "KB";
    740   4787    ahrens 		break;
    741   4787    ahrens 	case 20:
    742   4787    ahrens 		suffix = "MB";
    743   4787    ahrens 		break;
    744   4787    ahrens 	case 30:
    745   4787    ahrens 		suffix = "GB";
    746   4787    ahrens 		break;
    747   4787    ahrens 	default:
    748   4787    ahrens 		suffix = "XX";
    749   4787    ahrens 	}
    750   4787    ahrens 
    751   4787    ahrens 	for (i = 0; i < nstats; i++) {
    752   4787    ahrens 		int j;
    753   4787    ahrens 		boolean_t bytes = B_FALSE;
    754   4787    ahrens 
    755   4787    ahrens 		for (j = 0; bytestats[j]; j++) {
    756   4787    ahrens 			if (strcmp(stats[i].name, bytestats[j]) == 0) {
    757   4787    ahrens 				bytes = B_TRUE;
    758   4787    ahrens 				break;
    759   4787    ahrens 			}
    760   3403       bmc 		}
    761   3403       bmc 
    762   4787    ahrens 		if (bytes) {
    763   4787    ahrens 			mdb_printf("%-25s = %9llu %s\n", stats[i].name,
    764   4787    ahrens 			    stats[i].value.ui64 >> shift, suffix);
    765   4787    ahrens 		} else {
    766   4787    ahrens 			mdb_printf("%-25s = %9llu\n", stats[i].name,
    767   4787    ahrens 			    stats[i].value.ui64);
    768   3403       bmc 		}
    769   3403       bmc 	}
    770   3403       bmc 
    771   4787    ahrens 	for (i = 0; extras[i]; i++) {
    772   4787    ahrens 		uint64_t buf;
    773   3403       bmc 
    774   4787    ahrens 		if (mdb_lookup_by_name(extras[i], &sym) == -1) {
    775   4787    ahrens 			mdb_warn("failed to find '%s'", extras[i]);
    776   4787    ahrens 			return (DCMD_ERR);
    777   4787    ahrens 		}
    778   4787    ahrens 
    779   4787    ahrens 		if (sym.st_size != sizeof (uint64_t) &&
    780   4787    ahrens 		    sym.st_size != sizeof (uint32_t)) {
    781   4787    ahrens 			mdb_warn("expected scalar for variable '%s'\n",
    782   4787    ahrens 			    extras[i]);
    783   4787    ahrens 			return (DCMD_ERR);
    784   4787    ahrens 		}
    785   4787    ahrens 
    786   4787    ahrens 		if (mdb_vread(&buf, sym.st_size, sym.st_value) == -1) {
    787   4787    ahrens 			mdb_warn("couldn't read '%s'", extras[i]);
    788   4787    ahrens 			return (DCMD_ERR);
    789   4787    ahrens 		}
    790   4787    ahrens 
    791   4787    ahrens 		mdb_printf("%-25s = ", extras[i]);
    792   4787    ahrens 
    793   4787    ahrens 		/* NB: all the 64-bit extras happen to be byte counts */
    794   4787    ahrens 		if (sym.st_size == sizeof (uint64_t))
    795   4787    ahrens 			mdb_printf("%9llu %s\n", buf >> shift, suffix);
    796   4787    ahrens 
    797   4787    ahrens 		if (sym.st_size == sizeof (uint32_t))
    798   4787    ahrens 			mdb_printf("%9d\n", *((uint32_t *)&buf));
    799   4787    ahrens 	}
    800   3403       bmc 	return (DCMD_OK);
    801    789    ahrens }
    802    789    ahrens 
    803    789    ahrens /*
    804    789    ahrens  * ::spa
    805    789    ahrens  *
    806    789    ahrens  * 	-c	Print configuration information as well
    807    789    ahrens  * 	-v	Print vdev state
    808    789    ahrens  * 	-e	Print vdev error stats
    809    789    ahrens  *
    810    789    ahrens  * Print a summarized spa_t.  When given no arguments, prints out a table of all
    811    789    ahrens  * active pools on the system.
    812    789    ahrens  */
    813    789    ahrens /* ARGSUSED */
    814    789    ahrens static int
    815    789    ahrens spa_print(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
    816    789    ahrens {
    817    789    ahrens 	spa_t spa;
    818    789    ahrens 	const char *statetab[] = { "ACTIVE", "EXPORTED", "DESTROYED",
    819   7754      Jeff 		"SPARE", "L2CACHE", "UNINIT", "UNAVAIL", "POTENTIAL" };
    820    789    ahrens 	const char *state;
    821    789    ahrens 	int config = FALSE;
    822    789    ahrens 	int vdevs = FALSE;
    823    789    ahrens 	int errors = FALSE;
    824    789    ahrens 
    825    789    ahrens 	if (mdb_getopts(argc, argv,
    826    789    ahrens 	    'c', MDB_OPT_SETBITS, TRUE, &config,
    827    789    ahrens 	    'v', MDB_OPT_SETBITS, TRUE, &vdevs,
    828    789    ahrens 	    'e', MDB_OPT_SETBITS, TRUE, &errors,
    829    789    ahrens 	    NULL) != argc)
    830    789    ahrens 		return (DCMD_USAGE);
    831    789    ahrens 
    832    789    ahrens 	if (!(flags & DCMD_ADDRSPEC)) {
    833    789    ahrens 		if (mdb_walk_dcmd("spa", "spa", argc, argv) == -1) {
    834    789    ahrens 			mdb_warn("can't walk spa");
    835    789    ahrens 			return (DCMD_ERR);
    836    789    ahrens 		}
    837    789    ahrens 
    838    789    ahrens 		return (DCMD_OK);
    839    789    ahrens 	}
    840    789    ahrens 
    841    789    ahrens 	if (flags & DCMD_PIPE_OUT) {
    842    789    ahrens 		mdb_printf("%#lr\n", addr);
    843    789    ahrens 		return (DCMD_OK);
    844    789    ahrens 	}
    845    789    ahrens 
    846    789    ahrens 	if (DCMD_HDRSPEC(flags))
    847    789    ahrens 		mdb_printf("%<u>%-?s %9s %-*s%</u>\n", "ADDR", "STATE",
    848    789    ahrens 		    sizeof (uintptr_t) == 4 ? 60 : 52, "NAME");
    849    789    ahrens 
    850    789    ahrens 	if (mdb_vread(&spa, sizeof (spa), addr) == -1) {
    851    789    ahrens 		mdb_warn("failed to read spa_t at %p", addr);
    852    789    ahrens 		return (DCMD_ERR);
    853    789    ahrens 	}
    854    789    ahrens 
    855    789    ahrens 	if (spa.spa_state < 0 || spa.spa_state > POOL_STATE_UNAVAIL)
    856   1544  eschrock 		state = "UNKNOWN";
    857    789    ahrens 	else
    858    789    ahrens 		state = statetab[spa.spa_state];
    859    789    ahrens 
    860   7754      Jeff 	mdb_printf("%0?p %9s %s\n", addr, state, spa.spa_name);
    861    789    ahrens 
    862    789    ahrens 	if (config) {
    863    789    ahrens 		mdb_printf("\n");
    864    789    ahrens 		mdb_inc_indent(4);
    865    789    ahrens 		if (mdb_call_dcmd("spa_config", addr, flags, 0,
    866    789    ahrens 		    NULL) != DCMD_OK)
    867    789    ahrens 			return (DCMD_ERR);
    868    789    ahrens 		mdb_dec_indent(4);
    869    789    ahrens 	}
    870    789    ahrens 
    871    789    ahrens 	if (vdevs || errors) {
    872    789    ahrens 		mdb_arg_t v;
    873    789    ahrens 
    874    789    ahrens 		v.a_type = MDB_TYPE_STRING;
    875    789    ahrens 		v.a_un.a_str = "-e";
    876    789    ahrens 
    877    789    ahrens 		mdb_printf("\n");
    878    789    ahrens 		mdb_inc_indent(4);
    879    789    ahrens 		if (mdb_call_dcmd("spa_vdevs", addr, flags, errors ? 1 : 0,
    880    789    ahrens 		    &v) != DCMD_OK)
    881    789    ahrens 			return (DCMD_ERR);
    882    789    ahrens 		mdb_dec_indent(4);
    883    789    ahrens 	}
    884    789    ahrens 
    885    789    ahrens 	return (DCMD_OK);
    886    789    ahrens }
    887    789    ahrens 
    888    789    ahrens /*
    889    789    ahrens  * ::spa_config
    890    789    ahrens  *
    891    789    ahrens  * Given a spa_t, print the configuration information stored in spa_config.
    892    789    ahrens  * Since it's just an nvlist, format it as an indented list of name=value pairs.
    893    789    ahrens  * We simply read the value of spa_config and pass off to ::nvlist.
    894    789    ahrens  */
    895    789    ahrens /* ARGSUSED */
    896    789    ahrens static int
    897    789    ahrens spa_print_config(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
    898    789    ahrens {
    899    789    ahrens 	spa_t spa;
    900    789    ahrens 
    901    789    ahrens 	if (argc != 0 || !(flags & DCMD_ADDRSPEC))
    902    789    ahrens 		return (DCMD_USAGE);
    903    789    ahrens 
    904    789    ahrens 	if (mdb_vread(&spa, sizeof (spa), addr) == -1) {
    905    789    ahrens 		mdb_warn("failed to read spa_t at %p", addr);
    906    789    ahrens 		return (DCMD_ERR);
    907    789    ahrens 	}
    908    789    ahrens 
    909    789    ahrens 	if (spa.spa_config == NULL) {
    910    789    ahrens 		mdb_printf("(none)\n");
    911    789    ahrens 		return (DCMD_OK);
    912    789    ahrens 	}
    913    789    ahrens 
    914    789    ahrens 	return (mdb_call_dcmd("nvlist", (uintptr_t)spa.spa_config, flags,
    915    789    ahrens 	    0, NULL));
    916    789    ahrens }
    917    789    ahrens 
    918    789    ahrens /*
    919    789    ahrens  * ::vdev
    920    789    ahrens  *
    921    789    ahrens  * Print out a summarized vdev_t, in the following form:
    922    789    ahrens  *
    923    789    ahrens  * ADDR             STATE	AUX            DESC
    924    789    ahrens  * fffffffbcde23df0 HEALTHY	-              /dev/dsk/c0t0d0
    925    789    ahrens  *
    926    789    ahrens  * If '-r' is specified, recursively visit all children.
    927    789    ahrens  *
    928    789    ahrens  * With '-e', the statistics associated with the vdev are printed as well.
    929    789    ahrens  */
    930    789    ahrens static int
    931   3059    ahrens do_print_vdev(uintptr_t addr, int flags, int depth, int stats,
    932    789    ahrens     int recursive)
    933    789    ahrens {
    934    789    ahrens 	vdev_t vdev;
    935    789    ahrens 	char desc[MAXNAMELEN];
    936    789    ahrens 	int c, children;
    937    789    ahrens 	uintptr_t *child;
    938    789    ahrens 	const char *state, *aux;
    939    789    ahrens 
    940    789    ahrens 	if (mdb_vread(&vdev, sizeof (vdev), (uintptr_t)addr) == -1) {
    941    789    ahrens 		mdb_warn("failed to read vdev_t at %p\n", (uintptr_t)addr);
    942    789    ahrens 		return (DCMD_ERR);
    943    789    ahrens 	}
    944    789    ahrens 
    945    789    ahrens 	if (flags & DCMD_PIPE_OUT) {
    946    789    ahrens 		mdb_printf("%#lr", addr);
    947    789    ahrens 	} else {
    948    789    ahrens 		if (vdev.vdev_path != NULL) {
    949    789    ahrens 			if (mdb_readstr(desc, sizeof (desc),
    950    789    ahrens 			    (uintptr_t)vdev.vdev_path) == -1) {
    951    789    ahrens 				mdb_warn("failed to read vdev_path at %p\n",
    952    789    ahrens 				    vdev.vdev_path);
    953    789    ahrens 				return (DCMD_ERR);
    954    789    ahrens 			}
    955    789    ahrens 		} else if (vdev.vdev_ops != NULL) {
    956    789    ahrens 			vdev_ops_t ops;
    957    789    ahrens 			if (mdb_vread(&ops, sizeof (ops),
    958    789    ahrens 			    (uintptr_t)vdev.vdev_ops) == -1) {
    959    789    ahrens 				mdb_warn("failed to read vdev_ops at %p\n",
    960    789    ahrens 				    vdev.vdev_ops);
    961    789    ahrens 				return (DCMD_ERR);
    962    789    ahrens 			}
    963    789    ahrens 			(void) strcpy(desc, ops.vdev_op_type);
    964    789    ahrens 		} else {
    965    789    ahrens 			(void) strcpy(desc, "<unknown>");
    966    789    ahrens 		}
    967    789    ahrens 
    968    789    ahrens 		if (depth == 0 && DCMD_HDRSPEC(flags))
    969    789    ahrens 			mdb_printf("%<u>%-?s %-9s %-12s %-*s%</u>\n",
    970    789    ahrens 			    "ADDR", "STATE", "AUX",
    971    789    ahrens 			    sizeof (uintptr_t) == 4 ? 43 : 35,
    972    789    ahrens 			    "DESCRIPTION");
    973    789    ahrens 
    974    789    ahrens 		mdb_printf("%0?p ", addr);
    975    789    ahrens 
    976    789    ahrens 		switch (vdev.vdev_state) {
    977    789    ahrens 		case VDEV_STATE_CLOSED:
    978   4055  eschrock 			state = "CLOSED";
    979   4055  eschrock 			break;
    980    789    ahrens 		case VDEV_STATE_OFFLINE:
    981   4055  eschrock 			state = "OFFLINE";
    982   4055  eschrock 			break;
    983    789    ahrens 		case VDEV_STATE_CANT_OPEN:
    984   4055  eschrock 			state = "CANT_OPEN";
    985   4055  eschrock 			break;
    986    789    ahrens 		case VDEV_STATE_DEGRADED:
    987   4055  eschrock 			state = "DEGRADED";
    988   4055  eschrock 			break;
    989    789    ahrens 		case VDEV_STATE_HEALTHY:
    990   4055  eschrock 			state = "HEALTHY";
    991   4055  eschrock 			break;
    992   4451  eschrock 		case VDEV_STATE_REMOVED:
    993   4451  eschrock 			state = "REMOVED";
    994   4451  eschrock 			break;
    995   4451  eschrock 		case VDEV_STATE_FAULTED:
    996   4451  eschrock 			state = "FAULTED";
    997   4451  eschrock 			break;
    998    789    ahrens 		default:
    999   4055  eschrock 			state = "UNKNOWN";
   1000   4055  eschrock 			break;
   1001    789    ahrens 		}
   1002    789    ahrens 
   1003    789    ahrens 		switch (vdev.vdev_stat.vs_aux) {
   1004    789    ahrens 		case VDEV_AUX_NONE:
   1005    789    ahrens 			aux = "-";
   1006    789    ahrens 			break;
   1007    789    ahrens 		case VDEV_AUX_OPEN_FAILED:
   1008    789    ahrens 			aux = "OPEN_FAILED";
   1009    789    ahrens 			break;
   1010    789    ahrens 		case VDEV_AUX_CORRUPT_DATA:
   1011    789    ahrens 			aux = "CORRUPT_DATA";
   1012    789    ahrens 			break;
   1013    789    ahrens 		case VDEV_AUX_NO_REPLICAS:
   1014    789    ahrens 			aux = "NO_REPLICAS";
   1015    789    ahrens 			break;
   1016    789    ahrens 		case VDEV_AUX_BAD_GUID_SUM:
   1017    789    ahrens 			aux = "BAD_GUID_SUM";
   1018    789    ahrens 			break;
   1019    789    ahrens 		case VDEV_AUX_TOO_SMALL:
   1020    789    ahrens 			aux = "TOO_SMALL";
   1021    789    ahrens 			break;
   1022    789    ahrens 		case VDEV_AUX_BAD_LABEL:
   1023    789    ahrens 			aux = "BAD_LABEL";
   1024    789    ahrens 			break;
   1025   7294    perrin 		case VDEV_AUX_VERSION_NEWER:
   1026   7294    perrin 			aux = "VERS_NEWER";
   1027   7294    perrin 			break;
   1028   7294    perrin 		case VDEV_AUX_VERSION_OLDER:
   1029   7294    perrin 			aux = "VERS_OLDER";
   1030   7294    perrin 			break;
   1031   7294    perrin 		case VDEV_AUX_SPARED:
   1032   7294    perrin 			aux = "SPARED";
   1033   7294    perrin 			break;
   1034   7294    perrin 		case VDEV_AUX_ERR_EXCEEDED:
   1035   7294    perrin 			aux = "ERR_EXCEEDED";
   1036   7294    perrin 			break;
   1037   7294    perrin 		case VDEV_AUX_IO_FAILURE:
   1038   7294    perrin 			aux = "IO_FAILURE";
   1039   7294    perrin 			break;
   1040   7294    perrin 		case VDEV_AUX_BAD_LOG:
   1041   7294    perrin 			aux = "BAD_LOG";
   1042   7294    perrin 			break;
   1043    789    ahrens 		default:
   1044    789    ahrens 			aux = "UNKNOWN";
   1045    789    ahrens 			break;
   1046    789    ahrens 		}
   1047    789    ahrens 
   1048    789    ahrens 		mdb_printf("%-9s %-12s %*s%s\n", state, aux, depth, "", desc);
   1049    789    ahrens 
   1050    789    ahrens 		if (stats) {
   1051    789    ahrens 			vdev_stat_t *vs = &vdev.vdev_stat;
   1052    789    ahrens 			int i;
   1053    789    ahrens 
   1054    789    ahrens 			mdb_inc_indent(4);
   1055    789    ahrens 			mdb_printf("\n");
   1056    789    ahrens 			mdb_printf("%<u>       %12s %12s %12s %12s "
   1057    789    ahrens 			    "%12s%</u>\n", "READ", "WRITE", "FREE", "CLAIM",
   1058    789    ahrens 			    "IOCTL");
   1059    789    ahrens 			mdb_printf("OPS     ");
   1060    789    ahrens 			for (i = 1; i < ZIO_TYPES; i++)
   1061    789    ahrens 				mdb_printf("%11#llx%s", vs->vs_ops[i],
   1062    789    ahrens 				    i == ZIO_TYPES - 1 ? "" : "  ");
   1063    789    ahrens 			mdb_printf("\n");
   1064    789    ahrens 			mdb_printf("BYTES   ");
   1065    789    ahrens 			for (i = 1; i < ZIO_TYPES; i++)
   1066    789    ahrens 				mdb_printf("%11#llx%s", vs->vs_bytes[i],
   1067    789    ahrens 				    i == ZIO_TYPES - 1 ? "" : "  ");
   1068    789    ahrens 
   1069    789    ahrens 
   1070    789    ahrens 			mdb_printf("\n");
   1071    789    ahrens 			mdb_printf("EREAD    %10#llx\n", vs->vs_read_errors);
   1072    789    ahrens 			mdb_printf("EWRITE   %10#llx\n", vs->vs_write_errors);
   1073    789    ahrens 			mdb_printf("ECKSUM   %10#llx\n",
   1074    789    ahrens 			    vs->vs_checksum_errors);
   1075    789    ahrens 			mdb_dec_indent(4);
   1076    789    ahrens 		}
   1077    789    ahrens 
   1078   3059    ahrens 		if (stats)
   1079    789    ahrens 			mdb_printf("\n");
   1080    789    ahrens 	}
   1081    789    ahrens 
   1082    789    ahrens 	children = vdev.vdev_children;
   1083    789    ahrens 
   1084    789    ahrens 	if (children == 0 || !recursive)
   1085    789    ahrens 		return (DCMD_OK);
   1086    789    ahrens 
   1087    789    ahrens 	child = mdb_alloc(children * sizeof (void *), UM_SLEEP | UM_GC);
   1088    789    ahrens 	if (mdb_vread(child, children * sizeof (void *),
   1089    789    ahrens 	    (uintptr_t)vdev.vdev_child) == -1) {
   1090    789    ahrens 		mdb_warn("failed to read vdev children at %p", vdev.vdev_child);
   1091    789    ahrens 		return (DCMD_ERR);
   1092    789    ahrens 	}
   1093    789    ahrens 
   1094    789    ahrens 	for (c = 0; c < children; c++) {
   1095   3059    ahrens 		if (do_print_vdev(child[c], flags, depth + 2, stats,
   1096    789    ahrens 		    recursive))
   1097    789    ahrens 			return (DCMD_ERR);
   1098    789    ahrens 	}
   1099    789    ahrens 
   1100    789    ahrens 	return (DCMD_OK);
   1101    789    ahrens }
   1102    789    ahrens 
   1103    789    ahrens static int
   1104    789    ahrens vdev_print(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
   1105    789    ahrens {
   1106    789    ahrens 	int recursive = FALSE;
   1107    789    ahrens 	int stats = FALSE;
   1108   6643  eschrock 	uint64_t depth = 0;
   1109    789    ahrens 
   1110    789    ahrens 	if (mdb_getopts(argc, argv,
   1111    789    ahrens 	    'r', MDB_OPT_SETBITS, TRUE, &recursive,
   1112    789    ahrens 	    'e', MDB_OPT_SETBITS, TRUE, &stats,
   1113   6643  eschrock 	    'd', MDB_OPT_UINT64, &depth,
   1114    789    ahrens 	    NULL) != argc)
   1115    789    ahrens 		return (DCMD_USAGE);
   1116    789    ahrens 
   1117    789    ahrens 	if (!(flags & DCMD_ADDRSPEC)) {
   1118    789    ahrens 		mdb_warn("no vdev_t address given\n");
   1119    789    ahrens 		return (DCMD_ERR);
   1120    789    ahrens 	}
   1121    789    ahrens 
   1122   6643  eschrock 	return (do_print_vdev(addr, flags, (int)depth, stats, recursive));
   1123    789    ahrens }
   1124    789    ahrens 
   1125   2459    ahrens typedef struct metaslab_walk_data {
   1126   2459    ahrens 	uint64_t mw_numvdevs;
   1127   2459    ahrens 	uintptr_t *mw_vdevs;
   1128   2459    ahrens 	int mw_curvdev;
   1129   2459    ahrens 	uint64_t mw_nummss;
   1130   2459    ahrens 	uintptr_t *mw_mss;
   1131   2459    ahrens 	int mw_curms;
   1132   2459    ahrens } metaslab_walk_data_t;
   1133   2459    ahrens 
   1134   2459    ahrens static int
   1135   2459    ahrens metaslab_walk_step(mdb_walk_state_t *wsp)
   1136   2459    ahrens {
   1137   2459    ahrens 	metaslab_walk_data_t *mw = wsp->walk_data;
   1138   2459    ahrens 	metaslab_t ms;
   1139   2459    ahrens 	uintptr_t msp;
   1140   2459    ahrens 
   1141   2459    ahrens 	if (mw->mw_curvdev >= mw->mw_numvdevs)
   1142   2459    ahrens 		return (WALK_DONE);
   1143   2459    ahrens 
   1144   2459    ahrens 	if (mw->mw_mss == NULL) {
   1145   2459    ahrens 		uintptr_t mssp;
   1146   2459    ahrens 		uintptr_t vdevp;
   1147   2459    ahrens 
   1148   2459    ahrens 		ASSERT(mw->mw_curms == 0);
   1149   2459    ahrens 		ASSERT(mw->mw_nummss == 0);
   1150   2459    ahrens 
   1151   2459    ahrens 		vdevp = mw->mw_vdevs[mw->mw_curvdev];
   1152   2459    ahrens 		if (GETMEMB(vdevp, struct vdev, vdev_ms, mssp) ||
   1153   2459    ahrens 		    GETMEMB(vdevp, struct vdev, vdev_ms_count, mw->mw_nummss)) {
   1154   2459    ahrens 			return (WALK_ERR);
   1155   2459    ahrens 		}
   1156   2459    ahrens 
   1157   2459    ahrens 		mw->mw_mss = mdb_alloc(mw->mw_nummss * sizeof (void*),
   1158   2459    ahrens 		    UM_SLEEP | UM_GC);
   1159   2459    ahrens 		if (mdb_vread(mw->mw_mss, mw->mw_nummss * sizeof (void*),
   1160   2459    ahrens 		    mssp) == -1) {
   1161   2459    ahrens 			mdb_warn("failed to read vdev_ms at %p", mssp);
   1162   2459    ahrens 			return (WALK_ERR);
   1163   2459    ahrens 		}
   1164   2459    ahrens 	}
   1165   2459    ahrens 
   1166   2459    ahrens 	if (mw->mw_curms >= mw->mw_nummss) {
   1167   2459    ahrens 		mw->mw_mss = NULL;
   1168   2459    ahrens 		mw->mw_curms = 0;
   1169   2459    ahrens 		mw->mw_nummss = 0;
   1170   2459    ahrens 		mw->mw_curvdev++;
   1171   2459    ahrens 		return (WALK_NEXT);
   1172   2459    ahrens 	}
   1173   2459    ahrens 
   1174   2459    ahrens 	msp = mw->mw_mss[mw->mw_curms];
   1175   2459    ahrens 	if (mdb_vread(&ms, sizeof (metaslab_t), msp) == -1) {
   1176   2459    ahrens 		mdb_warn("failed to read metaslab_t at %p", msp);
   1177   2459    ahrens 		return (WALK_ERR);
   1178   2459    ahrens 	}
   1179   2459    ahrens 
   1180   2459    ahrens 	mw->mw_curms++;
   1181   2459    ahrens 
   1182   2459    ahrens 	return (wsp->walk_callback(msp, &ms, wsp->walk_cbdata));
   1183   2459    ahrens }
   1184   2459    ahrens 
   1185   2459    ahrens /* ARGSUSED */
   1186   2459    ahrens static int
   1187   2459    ahrens metaslab_walk_init(mdb_walk_state_t *wsp)
   1188   2459    ahrens {
   1189   2459    ahrens 	metaslab_walk_data_t *mw;
   1190   2459    ahrens 	uintptr_t root_vdevp;
   1191   2459    ahrens 	uintptr_t childp;
   1192   2459    ahrens 
   1193   2459    ahrens 	if (wsp->walk_addr == NULL) {
   1194   2459    ahrens 		mdb_warn("must supply address of spa_t\n");
   1195   2459    ahrens 		return (WALK_ERR);
   1196   2459    ahrens 	}
   1197   2459    ahrens 
   1198   2459    ahrens 	mw = mdb_zalloc(sizeof (metaslab_walk_data_t), UM_SLEEP | UM_GC);
   1199   2459    ahrens 
   1200   2459    ahrens 	if (GETMEMB(wsp->walk_addr, struct spa, spa_root_vdev, root_vdevp) ||
   1201   2459    ahrens 	    GETMEMB(root_vdevp, struct vdev, vdev_children, mw->mw_numvdevs) ||
   1202   2459    ahrens 	    GETMEMB(root_vdevp, struct vdev, vdev_child, childp)) {
   1203   2459    ahrens 		return (DCMD_ERR);
   1204   2459    ahrens 	}
   1205   2459    ahrens 
   1206   2459    ahrens 	mw->mw_vdevs = mdb_alloc(mw->mw_numvdevs * sizeof (void *),
   1207   2459    ahrens 	    UM_SLEEP | UM_GC);
   1208   2459    ahrens 	if (mdb_vread(mw->mw_vdevs, mw->mw_numvdevs * sizeof (void *),
   1209   2459    ahrens 	    childp) == -1) {
   1210   2459    ahrens 		mdb_warn("failed to read root vdev children at %p", childp);
   1211   2459    ahrens 		return (DCMD_ERR);
   1212   2459    ahrens 	}
   1213   2459    ahrens 
   1214   2459    ahrens 	wsp->walk_data = mw;
   1215   2459    ahrens 
   1216   2459    ahrens 	return (WALK_NEXT);
   1217   2459    ahrens }
   1218   2459    ahrens 
   1219    789    ahrens typedef struct mdb_spa {
   1220    789    ahrens 	uintptr_t spa_dsl_pool;
   1221    789    ahrens 	uintptr_t spa_root_vdev;
   1222    789    ahrens } mdb_spa_t;
   1223    789    ahrens 
   1224    789    ahrens typedef struct mdb_dsl_dir {
   1225    789    ahrens 	uintptr_t dd_phys;
   1226    789    ahrens 	int64_t dd_space_towrite[TXG_SIZE];
   1227    789    ahrens } mdb_dsl_dir_t;
   1228    789    ahrens 
   1229    789    ahrens typedef struct mdb_dsl_dir_phys {
   1230    789    ahrens 	uint64_t dd_used_bytes;
   1231    789    ahrens 	uint64_t dd_compressed_bytes;
   1232    789    ahrens 	uint64_t dd_uncompressed_bytes;
   1233    789    ahrens } mdb_dsl_dir_phys_t;
   1234    789    ahrens 
   1235    789    ahrens typedef struct mdb_vdev {
   1236    789    ahrens 	uintptr_t vdev_parent;
   1237    789    ahrens 	uintptr_t vdev_ms;
   1238    789    ahrens 	uint64_t vdev_ms_count;
   1239    789    ahrens 	vdev_stat_t vdev_stat;
   1240    789    ahrens } mdb_vdev_t;
   1241    789    ahrens 
   1242    789    ahrens typedef struct mdb_metaslab {
   1243    789    ahrens 	space_map_t ms_allocmap[TXG_SIZE];
   1244    789    ahrens 	space_map_t ms_freemap[TXG_SIZE];
   1245    789    ahrens 	space_map_t ms_map;
   1246   1732   bonwick 	space_map_obj_t ms_smo;
   1247   2459    ahrens 	space_map_obj_t ms_smo_syncing;
   1248    789    ahrens } mdb_metaslab_t;
   1249   2459    ahrens 
   1250   2459    ahrens typedef struct space_data {
   1251   2459    ahrens 	uint64_t ms_allocmap[TXG_SIZE];
   1252   2459    ahrens 	uint64_t ms_freemap[TXG_SIZE];
   1253   2459    ahrens 	uint64_t ms_map;
   1254   2459    ahrens 	uint64_t avail;
   1255   2459    ahrens 	uint64_t nowavail;
   1256   2459    ahrens } space_data_t;
   1257   2459    ahrens 
   1258   2459    ahrens /* ARGSUSED */
   1259   2459    ahrens static int
   1260   2459    ahrens space_cb(uintptr_t addr, const void *unknown, void *arg)
   1261   2459    ahrens {
   1262   2459    ahrens 	space_data_t *sd = arg;
   1263   2459    ahrens 	mdb_metaslab_t ms;
   1264   2459    ahrens 
   1265   2459    ahrens 	if (GETMEMB(addr, struct metaslab, ms_allocmap, ms.ms_allocmap) ||
   1266   2459    ahrens 	    GETMEMB(addr, struct metaslab, ms_freemap, ms.ms_freemap) ||
   1267   2459    ahrens 	    GETMEMB(addr, struct metaslab, ms_map, ms.ms_map) ||
   1268   2459    ahrens 	    GETMEMB(addr, struct metaslab, ms_smo, ms.ms_smo) ||
   1269   2459    ahrens 	    GETMEMB(addr, struct metaslab, ms_smo_syncing, ms.ms_smo_syncing)) {
   1270   2459    ahrens 		return (WALK_ERR);
   1271   2459    ahrens 	}
   1272   2459    ahrens 
   1273   2459    ahrens 	sd->ms_allocmap[0] += ms.ms_allocmap[0].sm_space;
   1274   2459    ahrens 	sd->ms_allocmap[1] += ms.ms_allocmap[1].sm_space;
   1275   2459    ahrens 	sd->ms_allocmap[2] += ms.ms_allocmap[2].sm_space;
   1276   2459    ahrens 	sd->ms_allocmap[3] += ms.ms_allocmap[3].sm_space;
   1277   2459    ahrens 	sd->ms_freemap[0] += ms.ms_freemap[0].sm_space;
   1278   2459    ahrens 	sd->ms_freemap[1] += ms.ms_freemap[1].sm_space;
   1279   2459    ahrens 	sd->ms_freemap[2] += ms.ms_freemap[2].sm_space;
   1280   2459    ahrens 	sd->ms_freemap[3] += ms.ms_freemap[3].sm_space;
   1281   2459    ahrens 	sd->ms_map += ms.ms_map.sm_space;
   1282   2459    ahrens 	sd->avail += ms.ms_map.sm_size - ms.ms_smo.smo_alloc;
   1283   2459    ahrens 	sd->nowavail += ms.ms_map.sm_size - ms.ms_smo_syncing.smo_alloc;
   1284   2459    ahrens 
   1285   2459    ahrens 	return (WALK_NEXT);
   1286   2459    ahrens }
   1287    789    ahrens 
   1288    789    ahrens /*
   1289    789    ahrens  * ::spa_space [-b]
   1290    789    ahrens  *
   1291    789    ahrens  * Given a spa_t, print out it's on-disk space usage and in-core
   1292    789    ahrens  * estimates of future usage.  If -b is given, print space in bytes.
   1293    789    ahrens  * Otherwise print in megabytes.
   1294    789    ahrens  */
   1295    789    ahrens /* ARGSUSED */
   1296    789    ahrens static int
   1297    789    ahrens spa_space(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
   1298    789    ahrens {
   1299    789    ahrens 	mdb_spa_t spa;
   1300    789    ahrens 	uintptr_t dp_root_dir;
   1301    789    ahrens 	mdb_dsl_dir_t dd;
   1302    789    ahrens 	mdb_dsl_dir_phys_t dsp;
   1303    789    ahrens 	uint64_t children;
   1304    789    ahrens 	uintptr_t childaddr;
   1305   2459    ahrens 	space_data_t sd;
   1306    789    ahrens 	int shift = 20;
   1307    789    ahrens 	char *suffix = "M";
   1308    789    ahrens 	int bits = FALSE;
   1309    789    ahrens 
   1310    789    ahrens 	if (mdb_getopts(argc, argv, 'b', MDB_OPT_SETBITS, TRUE, &bits, NULL) !=
   1311    789    ahrens 	    argc)
   1312    789    ahrens 		return (DCMD_USAGE);
   1313    789    ahrens 	if (!(flags & DCMD_ADDRSPEC))
   1314    789    ahrens 		return (DCMD_USAGE);
   1315    789    ahrens 
   1316    789    ahrens 	if (bits) {
   1317    789    ahrens 		shift = 0;
   1318    789    ahrens 		suffix = "";
   1319    789    ahrens 	}
   1320    789    ahrens 
   1321    789    ahrens 	if (GETMEMB(addr, struct spa, spa_dsl_pool, spa.spa_dsl_pool) ||
   1322    789    ahrens 	    GETMEMB(addr, struct spa, spa_root_vdev, spa.spa_root_vdev) ||
   1323    789    ahrens 	    GETMEMB(spa.spa_root_vdev, struct vdev, vdev_children, children) ||
   1324    789    ahrens 	    GETMEMB(spa.spa_root_vdev, struct vdev, vdev_child, childaddr) ||
   1325    789    ahrens 	    GETMEMB(spa.spa_dsl_pool, struct dsl_pool,
   1326    789    ahrens 	    dp_root_dir, dp_root_dir) ||
   1327    789    ahrens 	    GETMEMB(dp_root_dir, struct dsl_dir, dd_phys, dd.dd_phys) ||
   1328    789    ahrens 	    GETMEMB(dp_root_dir, struct dsl_dir,
   1329    789    ahrens 	    dd_space_towrite, dd.dd_space_towrite) ||
   1330    789    ahrens 	    GETMEMB(dd.dd_phys, struct dsl_dir_phys,
   1331   2459    ahrens 	    dd_used_bytes, dsp.dd_used_bytes) ||
   1332   2459    ahrens 	    GETMEMB(dd.dd_phys, struct dsl_dir_phys,
   1333    789    ahrens 	    dd_compressed_bytes, dsp.dd_compressed_bytes) ||
   1334    789    ahrens 	    GETMEMB(dd.dd_phys, struct dsl_dir_phys,
   1335    789    ahrens 	    dd_uncompressed_bytes, dsp.dd_uncompressed_bytes)) {
   1336    789    ahrens 		return (DCMD_ERR);
   1337    789    ahrens 	}
   1338    789    ahrens 
   1339    789    ahrens 	mdb_printf("dd_space_towrite = %llu%s %llu%s %llu%s %llu%s\n",
   1340    789    ahrens 	    dd.dd_space_towrite[0] >> shift, suffix,
   1341    789    ahrens 	    dd.dd_space_towrite[1] >> shift, suffix,
   1342    789    ahrens 	    dd.dd_space_towrite[2] >> shift, suffix,
   1343    789    ahrens 	    dd.dd_space_towrite[3] >> shift, suffix);
   1344    789    ahrens 
   1345    789    ahrens 	mdb_printf("dd_phys.dd_used_bytes = %llu%s\n",
   1346    789    ahrens 	    dsp.dd_used_bytes >> shift, suffix);
   1347   2459    ahrens 	mdb_printf("dd_phys.dd_compressed_bytes = %llu%s\n",
   1348   2459    ahrens 	    dsp.dd_compressed_bytes >> shift, suffix);
   1349   2459    ahrens 	mdb_printf("dd_phys.dd_uncompressed_bytes = %llu%s\n",
   1350   2459    ahrens 	    dsp.dd_uncompressed_bytes >> shift, suffix);
   1351    789    ahrens 
   1352   2459    ahrens 	bzero(&sd, sizeof (sd));
   1353   2459    ahrens 	if (mdb_pwalk("metaslab", space_cb, &sd, addr) != 0) {
   1354   2459    ahrens 		mdb_warn("can't walk metaslabs");
   1355   2459    ahrens 		return (DCMD_ERR);
   1356    789    ahrens 	}
   1357    789    ahrens 
   1358    789    ahrens 	mdb_printf("ms_allocmap = %llu%s %llu%s %llu%s %llu%s\n",
   1359   2459    ahrens 	    sd.ms_allocmap[0] >> shift, suffix,
   1360   2459    ahrens 	    sd.ms_allocmap[1] >> shift, suffix,
   1361   2459    ahrens 	    sd.ms_allocmap[2] >> shift, suffix,
   1362   2459    ahrens 	    sd.ms_allocmap[3] >> shift, suffix);
   1363    789    ahrens 	mdb_printf("ms_freemap = %llu%s %llu%s %llu%s %llu%s\n",
   1364   2459    ahrens 	    sd.ms_freemap[0] >> shift, suffix,
   1365   2459    ahrens 	    sd.ms_freemap[1] >> shift, suffix,
   1366   2459    ahrens 	    sd.ms_freemap[2] >> shift, suffix,
   1367   2459    ahrens 	    sd.ms_freemap[3] >> shift, suffix);
   1368   2459    ahrens 	mdb_printf("ms_map = %llu%s\n", sd.ms_map >> shift, suffix);
   1369   2459    ahrens 	mdb_printf("last synced avail = %llu%s\n", sd.avail >> shift, suffix);
   1370   2459    ahrens 	mdb_printf("current syncing avail = %llu%s\n",
   1371   2459    ahrens 	    sd.nowavail >> shift, suffix);
   1372    789    ahrens 
   1373    789    ahrens 	return (DCMD_OK);
   1374    789    ahrens }
   1375    789    ahrens 
   1376    789    ahrens /*
   1377    789    ahrens  * ::spa_verify
   1378    789    ahrens  *
   1379    789    ahrens  * Given a spa_t, verify that that the pool is self-consistent.
   1380    789    ahrens  * Currently, it only checks to make sure that the vdev tree exists.
   1381    789    ahrens  */
   1382    789    ahrens /* ARGSUSED */
   1383    789    ahrens static int
   1384    789    ahrens spa_verify(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
   1385    789    ahrens {
   1386    789    ahrens 	spa_t spa;
   1387    789    ahrens 
   1388    789    ahrens 	if (argc != 0 || !(flags & DCMD_ADDRSPEC))
   1389    789    ahrens 		return (DCMD_USAGE);
   1390    789    ahrens 
   1391    789    ahrens 	if (mdb_vread(&spa, sizeof (spa), addr) == -1) {
   1392    789    ahrens 		mdb_warn("failed to read spa_t at %p", addr);
   1393    789    ahrens 		return (DCMD_ERR);
   1394    789    ahrens 	}
   1395    789    ahrens 
   1396    789    ahrens 	if (spa.spa_root_vdev == NULL) {
   1397    789    ahrens 		mdb_printf("no vdev tree present\n");
   1398    789    ahrens 		return (DCMD_OK);
   1399    789    ahrens 	}
   1400    789    ahrens 
   1401    789    ahrens 	return (DCMD_OK);
   1402    789    ahrens }
   1403    789    ahrens 
   1404   8341      Eric static int
   1405   8341      Eric spa_print_aux(spa_aux_vdev_t *sav, uint_t flags, mdb_arg_t *v,
   1406   8341      Eric     const char *name)
   1407   8341      Eric {
   1408   8341      Eric 	uintptr_t *aux;
   1409   8341      Eric 	size_t len;
   1410   8341      Eric 	int ret, i;
   1411   8341      Eric 
   1412   8341      Eric 	/*
   1413   8341      Eric 	 * Iterate over aux vdevs and print those out as well.  This is a
   1414   8341      Eric 	 * little annoying because we don't have a root vdev to pass to ::vdev.
   1415   8341      Eric 	 * Instead, we print a single line and then call it for each child
   1416   8341      Eric 	 * vdev.
   1417   8341      Eric 	 */
   1418   8341      Eric 	if (sav->sav_count != 0) {
   1419   8341      Eric 		v[1].a_type = MDB_TYPE_STRING;
   1420   8341      Eric 		v[1].a_un.a_str = "-d";
   1421   8341      Eric 		v[2].a_type = MDB_TYPE_IMMEDIATE;
   1422   8341      Eric 		v[2].a_un.a_val = 2;
   1423   8341      Eric 
   1424   8341      Eric 		len = sav->sav_count * sizeof (uintptr_t);
   1425   8341      Eric 		aux = mdb_alloc(len, UM_SLEEP);
   1426   8341      Eric 		if (mdb_vread(aux, len,
   1427   8341      Eric 		    (uintptr_t)sav->sav_vdevs) == -1) {
   1428   8341      Eric 			mdb_free(aux, len);
   1429   8341      Eric 			mdb_warn("failed to read l2cache vdevs at %p",
   1430   8341      Eric 			    sav->sav_vdevs);
   1431   8341      Eric 			return (DCMD_ERR);
   1432   8341      Eric 		}
   1433   8341      Eric 
   1434   8341      Eric 		mdb_printf("%-?s %-9s %-12s %s\n", "-", "-", "-", name);
   1435   8341      Eric 
   1436   8341      Eric 		for (i = 0; i < sav->sav_count; i++) {
   1437   8341      Eric 			ret = mdb_call_dcmd("vdev", aux[i], flags, 3, v);
   1438   8341      Eric 			if (ret != DCMD_OK) {
   1439   8341      Eric 				mdb_free(aux, len);
   1440   8341      Eric 				return (ret);
   1441   8341      Eric 			}
   1442   8341      Eric 		}
   1443   8341      Eric 
   1444   8341      Eric 		mdb_free(aux, len);
   1445   8341      Eric 	}
   1446   8341      Eric 
   1447   8341      Eric 	return (0);
   1448   8341      Eric }
   1449   8341      Eric 
   1450    789    ahrens /*
   1451    789    ahrens  * ::spa_vdevs
   1452    789    ahrens  *
   1453    789    ahrens  * 	-e	Include error stats
   1454    789    ahrens  *
   1455    789    ahrens  * Print out a summarized list of vdevs for the given spa_t.
   1456   6643  eschrock  * This is accomplished by invoking "::vdev -re" on the root vdev, as well as
   1457   6643  eschrock  * iterating over the cache devices.
   1458    789    ahrens  */
   1459    789    ahrens /* ARGSUSED */
   1460    789    ahrens static int
   1461    789    ahrens spa_vdevs(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
   1462    789    ahrens {
   1463    789    ahrens 	spa_t spa;
   1464   6643  eschrock 	mdb_arg_t v[3];
   1465    789    ahrens 	int errors = FALSE;
   1466   8341      Eric 	int ret;
   1467    789    ahrens 
   1468    789    ahrens 	if (mdb_getopts(argc, argv,
   1469    789    ahrens 	    'e', MDB_OPT_SETBITS, TRUE, &errors,
   1470    789    ahrens 	    NULL) != argc)
   1471    789    ahrens 		return (DCMD_USAGE);
   1472    789    ahrens 
   1473    789    ahrens 	if (!(flags & DCMD_ADDRSPEC))
   1474    789    ahrens 		return (DCMD_USAGE);
   1475    789    ahrens 
   1476    789    ahrens 	if (mdb_vread(&spa, sizeof (spa), addr) == -1) {
   1477    789    ahrens 		mdb_warn("failed to read spa_t at %p", addr);
   1478    789    ahrens 		return (DCMD_ERR);
   1479    789    ahrens 	}
   1480    789    ahrens 
   1481    952  eschrock 	/*
   1482    952  eschrock 	 * Unitialized spa_t structures can have a NULL root vdev.
   1483    952  eschrock 	 */
   1484    952  eschrock 	if (spa.spa_root_vdev == NULL) {
   1485    952  eschrock 		mdb_printf("no associated vdevs\n");
   1486    952  eschrock 		return (DCMD_OK);
   1487    952  eschrock 	}
   1488    952  eschrock 
   1489   6643  eschrock 	v[0].a_type = MDB_TYPE_STRING;
   1490   6643  eschrock 	v[0].a_un.a_str = errors ? "-re" : "-r";
   1491    789    ahrens 
   1492   6643  eschrock 	ret = mdb_call_dcmd("vdev", (uintptr_t)spa.spa_root_vdev,
   1493   6643  eschrock 	    flags, 1, v);
   1494   6643  eschrock 	if (ret != DCMD_OK)
   1495   6643  eschrock 		return (ret);
   1496   6643  eschrock 
   1497   8341      Eric 	if (spa_print_aux(&spa.spa_l2cache, flags, v, "cache") != 0 ||
   1498   8341      Eric 	    spa_print_aux(&spa.spa_spares, flags, v, "spares") != 0)
   1499   8341      Eric 		return (DCMD_ERR);
   1500   6643  eschrock 
   1501   6643  eschrock 	return (DCMD_OK);
   1502    789    ahrens }
   1503    789    ahrens 
   1504   4055  eschrock /*
   1505   4055  eschrock  * ::zio
   1506   4055  eschrock  *
   1507   4055  eschrock  * Print a summary of zio_t and all its children.  This is intended to display a
   1508   4055  eschrock  * zio tree, and hence we only pick the most important pieces of information for
   1509   4055  eschrock  * the main summary.  More detailed information can always be found by doing a
   1510   4055  eschrock  * '::print zio' on the underlying zio_t.  The columns we display are:
   1511   4055  eschrock  *
   1512   4055  eschrock  *	ADDRESS		TYPE	STAGE		WAITER
   1513   4055  eschrock  *
   1514   4055  eschrock  * The 'address' column is indented by one space for each depth level as we
   1515   4055  eschrock  * descend down the tree.
   1516   4055  eschrock  */
   1517   4217  eschrock 
   1518   8632      Bill #define	ZIO_MAXINDENT	24
   1519   8632      Bill #define	ZIO_MAXWIDTH	(sizeof (uintptr_t) * 2 + ZIO_MAXINDENT)
   1520   8632      Bill #define	ZIO_WALK_SELF	0
   1521   8632      Bill #define	ZIO_WALK_CHILD	1
   1522   8632      Bill #define	ZIO_WALK_PARENT	2
   1523   8632      Bill 
   1524   8632      Bill typedef struct zio_print_args {
   1525   8632      Bill 	int	zpa_current_depth;
   1526   8632      Bill 	int	zpa_min_depth;
   1527   8632      Bill 	int	zpa_max_depth;
   1528   8632      Bill 	int	zpa_type;
   1529   8632      Bill 	uint_t	zpa_flags;
   1530   8632      Bill } zio_print_args_t;
   1531   8632      Bill 
   1532   8632      Bill static int zio_child_cb(uintptr_t addr, const void *unknown, void *arg);
   1533   4217  eschrock 
   1534   4055  eschrock static int
   1535   4055  eschrock zio_print_cb(uintptr_t addr, const void *data, void *priv)
   1536   4055  eschrock {
   1537   4055  eschrock 	const zio_t *zio = data;
   1538   8632      Bill 	zio_print_args_t *zpa = priv;
   1539   4055  eschrock 	mdb_ctf_id_t type_enum, stage_enum;
   1540   8632      Bill 	int indent = zpa->zpa_current_depth;
   1541   4055  eschrock 	const char *type, *stage;
   1542   8632      Bill 	uintptr_t laddr;
   1543   4055  eschrock 
   1544   8632      Bill 	if (indent > ZIO_MAXINDENT)
   1545   8632      Bill 		indent = ZIO_MAXINDENT;
   1546   4055  eschrock 
   1547   4055  eschrock 	if (mdb_ctf_lookup_by_name("enum zio_type", &type_enum) == -1 ||
   1548   4055  eschrock 	    mdb_ctf_lookup_by_name("enum zio_stage", &stage_enum) == -1) {
   1549   4055  eschrock 		mdb_warn("failed to lookup zio enums");
   1550   4055  eschrock 		return (WALK_ERR);
   1551   4055  eschrock 	}
   1552   4055  eschrock 
   1553   4055  eschrock 	if ((type = mdb_ctf_enum_name(type_enum, zio->io_type)) != NULL)
   1554   4055  eschrock 		type += sizeof ("ZIO_TYPE_") - 1;
   1555   4055  eschrock 	else
   1556   4055  eschrock 		type = "?";
   1557   4055  eschrock 
   1558   4055  eschrock 	if ((stage = mdb_ctf_enum_name(stage_enum, zio->io_stage)) != NULL)
   1559   4055  eschrock 		stage += sizeof ("ZIO_STAGE_") - 1;
   1560   4055  eschrock 	else
   1561   4055  eschrock 		stage = "?";
   1562   4055  eschrock 
   1563   8632      Bill 	if (zpa->zpa_current_depth >= zpa->zpa_min_depth) {
   1564   8632      Bill 		if (zpa->zpa_flags & DCMD_PIPE_OUT) {
   1565   8632      Bill 			mdb_printf("%?p\n", addr);
   1566   8632      Bill 		} else {
   1567   8632      Bill 			mdb_printf("%*s%-*p %-5s %-16s ", indent, "",
   1568   8632      Bill 			    ZIO_MAXWIDTH - indent, addr, type, stage);
   1569   8632      Bill 			if (zio->io_waiter)
   1570   8632      Bill 				mdb_printf("%?p\n", zio->io_waiter);
   1571   8632      Bill 			else
   1572   8632      Bill 				mdb_printf("-\n");
   1573   8632      Bill 		}
   1574   8632      Bill 	}
   1575   4055  eschrock 
   1576   8632      Bill 	if (zpa->zpa_current_depth >= zpa->zpa_max_depth)
   1577   8632      Bill 		return (WALK_NEXT);
   1578   8632      Bill 
   1579   8632      Bill 	if (zpa->zpa_type == ZIO_WALK_PARENT)
   1580   8632      Bill 		laddr = addr + OFFSETOF(zio_t, io_parent_list);
   1581   4055  eschrock 	else
   1582   8632      Bill 		laddr = addr + OFFSETOF(zio_t, io_child_list);
   1583   4055  eschrock 
   1584   8632      Bill 	zpa->zpa_current_depth++;
   1585   8632      Bill 	if (mdb_pwalk("list", zio_child_cb, zpa, laddr) != 0) {
   1586   8632      Bill 		mdb_warn("failed to walk zio_t children at %p\n", laddr);
   1587   4055  eschrock 		return (WALK_ERR);
   1588   4055  eschrock 	}
   1589   8632      Bill 	zpa->zpa_current_depth--;
   1590   4055  eschrock 
   1591   4055  eschrock 	return (WALK_NEXT);
   1592   4055  eschrock }
   1593   4055  eschrock 
   1594   8632      Bill /* ARGSUSED */
   1595   8632      Bill static int
   1596   8632      Bill zio_child_cb(uintptr_t addr, const void *unknown, void *arg)
   1597   8632      Bill {
   1598   8632      Bill 	zio_link_t zl;
   1599   8632      Bill 	zio_t zio;
   1600   8632      Bill 	uintptr_t ziop;
   1601   8632      Bill 	zio_print_args_t *zpa = arg;
   1602   8632      Bill 
   1603   8632      Bill 	if (mdb_vread(&zl, sizeof (zl), addr) == -1) {
   1604   8632      Bill 		mdb_warn("failed to read zio_link_t at %p", addr);
   1605   8632      Bill 		return (WALK_ERR);
   1606   8632      Bill 	}
   1607   8632      Bill 
   1608   8632      Bill 	if (zpa->zpa_type == ZIO_WALK_PARENT)
   1609   8632      Bill 		ziop = (uintptr_t)zl.zl_parent;
   1610   8632      Bill 	else
   1611   8632      Bill 		ziop = (uintptr_t)zl.zl_child;
   1612   8632      Bill 
   1613   8632      Bill 	if (mdb_vread(&zio, sizeof (zio_t), ziop) == -1) {
   1614   8632      Bill 		mdb_warn("failed to read zio_t at %p", ziop);
   1615   8632      Bill 		return (WALK_ERR);
   1616   8632      Bill 	}
   1617   8632      Bill 
   1618   8632      Bill 	return (zio_print_cb(ziop, &zio, arg));
   1619   8632      Bill }
   1620   8632      Bill 
   1621   8632      Bill /* ARGSUSED */
   1622   4055  eschrock static int
   1623   4055  eschrock zio_print(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
   1624   4055  eschrock {
   1625   4055  eschrock 	zio_t zio;
   1626   8632      Bill 	zio_print_args_t zpa = { 0 };
   1627   4055  eschrock 
   1628   4055  eschrock 	if (!(flags & DCMD_ADDRSPEC))
   1629   4055  eschrock 		return (DCMD_USAGE);
   1630   8632      Bill 
   1631   8632      Bill 	if (mdb_getopts(argc, argv,
   1632   8632      Bill 	    'r', MDB_OPT_SETBITS, INT_MAX, &zpa.zpa_max_depth,
   1633   8632      Bill 	    'c', MDB_OPT_SETBITS, ZIO_WALK_CHILD, &zpa.zpa_type,
   1634   8632      Bill 	    'p', MDB_OPT_SETBITS, ZIO_WALK_PARENT, &zpa.zpa_type,
   1635   8632      Bill 	    NULL) != argc)
   1636   8632      Bill 		return (DCMD_USAGE);
   1637   8632      Bill 
   1638   8632      Bill 	zpa.zpa_flags = flags;
   1639   8632      Bill 	if (zpa.zpa_max_depth != 0) {
   1640   8632      Bill 		if (zpa.zpa_type == ZIO_WALK_SELF)
   1641   8632      Bill 			zpa.zpa_type = ZIO_WALK_CHILD;
   1642   8632      Bill 	} else if (zpa.zpa_type != ZIO_WALK_SELF) {
   1643   8632      Bill 		zpa.zpa_min_depth = 1;
   1644   8632      Bill 		zpa.zpa_max_depth = 1;
   1645   8632      Bill 	}
   1646   4055  eschrock 
   1647   4055  eschrock 	if (mdb_vread(&zio, sizeof (zio_t), addr) == -1) {
   1648   4055  eschrock 		mdb_warn("failed to read zio_t at %p", addr);
   1649   4055  eschrock 		return (DCMD_ERR);
   1650   4055  eschrock 	}
   1651   4217  eschrock 
   1652   8632      Bill 	if (!(flags & DCMD_PIPE_OUT) && DCMD_HDRSPEC(flags))
   1653   8632      Bill 		mdb_printf("%<u>%-*s %-5s %-16s %-?s%</u>\n", ZIO_MAXWIDTH,
   1654   4217  eschrock 		    "ADDRESS", "TYPE", "STAGE", "WAITER");
   1655   4055  eschrock 
   1656   8632      Bill 	if (zio_print_cb(addr, &zio, &zpa) != WALK_NEXT)
   1657   4055  eschrock 		return (DCMD_ERR);
   1658   4055  eschrock 
   1659   4055  eschrock 	return (DCMD_OK);
   1660   4055  eschrock }
   1661   4055  eschrock 
   1662   4055  eschrock /*
   1663   4055  eschrock  * [addr]::zio_state
   1664   4055  eschrock  *
   1665   4055  eschrock  * Print a summary of all zio_t structures on the system, or for a particular
   1666   4055  eschrock  * pool.  This is equivalent to '::walk zio_root | ::zio'.
   1667   4055  eschrock  */
   1668   4055  eschrock /*ARGSUSED*/
   1669   4055  eschrock static int
   1670   4055  eschrock zio_state(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
   1671   4055  eschrock {
   1672   4055  eschrock 	/*
   1673   4055  eschrock 	 * MDB will remember the last address of the pipeline, so if we don't
   1674   4055  eschrock 	 * zero this we'll end up trying to walk zio structures for a
   1675   4055  eschrock 	 * non-existent spa_t.
   1676   4055  eschrock 	 */
   1677   4055  eschrock 	if (!(flags & DCMD_ADDRSPEC))
   1678   4055  eschrock 		addr = 0;
   1679   4055  eschrock 
   1680   4055  eschrock 	return (mdb_pwalk_dcmd("zio_root", "zio", argc, argv, addr));
   1681   4055  eschrock }
   1682   4055  eschrock 
   1683    789    ahrens typedef struct txg_list_walk_data {
   1684    789    ahrens 	uintptr_t lw_head[TXG_SIZE];
   1685    789    ahrens 	int	lw_txgoff;
   1686    789    ahrens 	int	lw_maxoff;
   1687    789    ahrens 	size_t	lw_offset;
   1688    789    ahrens 	void	*lw_obj;
   1689    789    ahrens } txg_list_walk_data_t;
   1690    789    ahrens 
   1691    789    ahrens static int
   1692    789    ahrens txg_list_walk_init_common(mdb_walk_state_t *wsp, int txg, int maxoff)
   1693    789    ahrens {
   1694    789    ahrens 	txg_list_walk_data_t *lwd;
   1695    789    ahrens 	txg_list_t list;
   1696    789    ahrens 	int i;
   1697    789    ahrens 
   1698    789    ahrens 	lwd = mdb_alloc(sizeof (txg_list_walk_data_t), UM_SLEEP | UM_GC);
   1699    789    ahrens 	if (mdb_vread(&list, sizeof (txg_list_t), wsp->walk_addr) == -1) {
   1700    789    ahrens 		mdb_warn("failed to read txg_list_t at %#lx", wsp->walk_addr);
   1701    789    ahrens 		return (WALK_ERR);
   1702    789    ahrens 	}
   1703    789    ahrens 
   1704    789    ahrens 	for (i = 0; i < TXG_SIZE; i++)
   1705    789    ahrens 		lwd->lw_head[i] = (uintptr_t)list.tl_head[i];
   1706    789    ahrens 	lwd->lw_offset = list.tl_offset;
   1707    789    ahrens 	lwd->lw_obj = mdb_alloc(lwd->lw_offset + sizeof (txg_node_t),
   1708    789    ahrens 	    UM_SLEEP | UM_GC);
   1709    789    ahrens 	lwd->lw_txgoff = txg;
   1710    789    ahrens 	lwd->lw_maxoff = maxoff;
   1711    789    ahrens 
   1712    789    ahrens 	wsp->walk_addr = lwd->lw_head[lwd->lw_txgoff];
   1713    789    ahrens 	wsp->walk_data = lwd;
   1714    789    ahrens 
   1715    789    ahrens 	return (WALK_NEXT);
   1716    789    ahrens }
   1717    789    ahrens 
   1718    789    ahrens static int
   1719    789    ahrens txg_list_walk_init(mdb_walk_state_t *wsp)
   1720    789    ahrens {
   1721    789    ahrens 	return (txg_list_walk_init_common(wsp, 0, TXG_SIZE-1));
   1722    789    ahrens }
   1723    789    ahrens 
   1724    789    ahrens static int
   1725    789    ahrens txg_list0_walk_init(mdb_walk_state_t *wsp)
   1726    789    ahrens {
   1727    789    ahrens 	return (txg_list_walk_init_common(wsp, 0, 0));
   1728    789    ahrens }
   1729    789    ahrens 
   1730    789    ahrens static int
   1731    789    ahrens txg_list1_walk_init(mdb_walk_state_t *wsp)
   1732    789    ahrens {
   1733    789    ahrens 	return (txg_list_walk_init_common(wsp, 1, 1));
   1734    789    ahrens }
   1735    789    ahrens 
   1736    789    ahrens static int
   1737    789    ahrens txg_list2_walk_init(mdb_walk_state_t *wsp)
   1738    789    ahrens {
   1739    789    ahrens 	return (txg_list_walk_init_common(wsp, 2, 2));
   1740    789    ahrens }
   1741    789    ahrens 
   1742    789    ahrens static int
   1743    789    ahrens txg_list3_walk_init(mdb_walk_state_t *wsp)
   1744    789    ahrens {
   1745    789    ahrens 	return (txg_list_walk_init_common(wsp, 3, 3));
   1746    789    ahrens }
   1747    789    ahrens 
   1748    789    ahrens static int
   1749    789    ahrens txg_list_walk_step(mdb_walk_state_t *wsp)
   1750    789    ahrens {
   1751    789    ahrens 	txg_list_walk_data_t *lwd = wsp->walk_data;
   1752    789    ahrens 	uintptr_t addr;
   1753    789    ahrens 	txg_node_t *node;
   1754    789    ahrens 	int status;
   1755    789    ahrens 
   1756    789    ahrens 	while (wsp->walk_addr == NULL && lwd->lw_txgoff < lwd->lw_maxoff) {
   1757    789    ahrens 		lwd->lw_txgoff++;
   1758    789    ahrens 		wsp->walk_addr = lwd->lw_head[lwd->lw_txgoff];
   1759    789    ahrens 	}
   1760    789    ahrens 
   1761    789    ahrens 	if (wsp->walk_addr == NULL)
   1762    789    ahrens 		return (WALK_DONE);
   1763    789    ahrens 
   1764    789    ahrens 	addr = wsp->walk_addr - lwd->lw_offset;
   1765    789    ahrens 
   1766    789    ahrens 	if (mdb_vread(lwd->lw_obj,
   1767    789    ahrens 	    lwd->lw_offset + sizeof (txg_node_t), addr) == -1) {
   1768    789    ahrens 		mdb_warn("failed to read list element at %#lx", addr);
   1769    789    ahrens 		return (WALK_ERR);
   1770    789    ahrens 	}
   1771    789    ahrens 
   1772    789    ahrens 	status = wsp->walk_callback(addr, lwd->lw_obj, wsp->walk_cbdata);
   1773    789    ahrens 	node = (txg_node_t *)((uintptr_t)lwd->lw_obj + lwd->lw_offset);
   1774    789    ahrens 	wsp->walk_addr = (uintptr_t)node->tn_next[lwd->lw_txgoff];
   1775    789    ahrens 
   1776    789    ahrens 	return (status);
   1777    789    ahrens }
   1778    789    ahrens 
   1779    789    ahrens /*
   1780    789    ahrens  * ::walk spa
   1781    789    ahrens  *
   1782    789    ahrens  * Walk all named spa_t structures in the namespace.  This is nothing more than
   1783    789    ahrens  * a layered avl walk.
   1784    789    ahrens  */
   1785    789    ahrens static int
   1786    789    ahrens spa_walk_init(mdb_walk_state_t *wsp)
   1787    789    ahrens {
   1788    789    ahrens 	GElf_Sym sym;
   1789    789    ahrens 
   1790    789    ahrens 	if (wsp->walk_addr != NULL) {
   1791    789    ahrens 		mdb_warn("spa walk only supports global walks\n");
   1792    789    ahrens 		return (WALK_ERR);
   1793    789    ahrens 	}
   1794    789    ahrens 
   1795    789    ahrens 	if (mdb_lookup_by_obj(ZFS_OBJ_NAME, "spa_namespace_avl", &sym) == -1) {
   1796    789    ahrens 		mdb_warn("failed to find symbol 'spa_namespace_avl'");
   1797    789    ahrens 		return (WALK_ERR);
   1798    789    ahrens 	}
   1799    789    ahrens 
   1800    789    ahrens 	wsp->walk_addr = (uintptr_t)sym.st_value;
   1801    789    ahrens 
   1802    789    ahrens 	if (mdb_layered_walk("avl", wsp) == -1) {
   1803    789    ahrens 		mdb_warn("failed to walk 'avl'\n");
   1804    789    ahrens 		return (WALK_ERR);
   1805    789    ahrens 	}
   1806    789    ahrens 
   1807    789    ahrens 	return (WALK_NEXT);
   1808    789    ahrens }
   1809    789    ahrens 
   1810    789    ahrens static int
   1811    789    ahrens spa_walk_step(mdb_walk_state_t *wsp)
   1812    789    ahrens {
   1813    789    ahrens 	spa_t	spa;
   1814    789    ahrens 
   1815    789    ahrens 	if (mdb_vread(&spa, sizeof (spa), wsp->walk_addr) == -1) {
   1816    789    ahrens 		mdb_warn("failed to read spa_t at %p", wsp->walk_addr);
   1817    789    ahrens 		return (WALK_ERR);
   1818    789    ahrens 	}
   1819    789    ahrens 
   1820    789    ahrens 	return (wsp->walk_callback(wsp->walk_addr, &spa, wsp->walk_cbdata));
   1821    789    ahrens }
   1822    789    ahrens 
   1823    789    ahrens /*
   1824   4055  eschrock  * [addr]::walk zio
   1825   4055  eschrock  *
   1826   4055  eschrock  * Walk all active zio_t structures on the system.  This is simply a layered
   1827   4055  eschrock  * walk on top of ::walk zio_cache, with the optional ability to limit the
   1828   4055  eschrock  * structures to a particular pool.
   1829   4055  eschrock  */
   1830   4055  eschrock static int
   1831   4055  eschrock zio_walk_init(mdb_walk_state_t *wsp)
   1832   4055  eschrock {
   1833   4055  eschrock 	wsp->walk_data = (void *)wsp->walk_addr;
   1834   4055  eschrock 
   1835   4055  eschrock 	if (mdb_layered_walk("zio_cache", wsp) == -1) {
   1836   4055  eschrock 		mdb_warn("failed to walk 'zio_cache'\n");
   1837   4055  eschrock 		return (WALK_ERR);
   1838   4055  eschrock 	}
   1839   4055  eschrock 
   1840   4055  eschrock 	return (WALK_NEXT);
   1841   4055  eschrock }
   1842   4055  eschrock 
   1843   4055  eschrock static int
   1844   4055  eschrock zio_walk_step(mdb_walk_state_t *wsp)
   1845   4055  eschrock {
   1846   4055  eschrock 	zio_t zio;
   1847   4055  eschrock 
   1848   4055  eschrock 	if (mdb_vread(&zio, sizeof (zio), wsp->walk_addr) == -1) {
   1849   4055  eschrock 		mdb_warn("failed to read zio_t at %p", wsp->walk_addr);
   1850   4055  eschrock 		return (WALK_ERR);
   1851   4055  eschrock 	}
   1852   4055  eschrock 
   1853   4055  eschrock 	if (wsp->walk_data != NULL && wsp->walk_data != zio.io_spa)
   1854   4055  eschrock 		return (WALK_NEXT);
   1855   4055  eschrock 
   1856   4055  eschrock 	return (wsp->walk_callback(wsp->walk_addr, &zio, wsp->walk_cbdata));
   1857   4055  eschrock }
   1858   4055  eschrock 
   1859   4055  eschrock /*
   1860   4055  eschrock  * [addr]::walk zio_root
   1861   4055  eschrock  *
   1862   4055  eschrock  * Walk only root zio_t structures, optionally for a particular spa_t.
   1863   4055  eschrock  */
   1864   4055  eschrock static int
   1865   4055  eschrock zio_walk_root_step(mdb_walk_state_t *wsp)
   1866   4055  eschrock {
   1867   4055  eschrock 	zio_t zio;
   1868   4055  eschrock 
   1869   4055  eschrock 	if (mdb_vread(&zio, sizeof (zio), wsp->walk_addr) == -1) {
   1870   4055  eschrock 		mdb_warn("failed to read zio_t at %p", wsp->walk_addr);
   1871   4055  eschrock 		return (WALK_ERR);
   1872   4055  eschrock 	}
   1873   4055  eschrock 
   1874   4055  eschrock 	if (wsp->walk_data != NULL && wsp->walk_data != zio.io_spa)
   1875   4055  eschrock 		return (WALK_NEXT);
   1876   4055  eschrock 
   1877   8632      Bill 	/* If the parent list is not empty, ignore */
   1878   8632      Bill 	if (zio.io_parent_list.list_head.list_next !=
   1879   8632      Bill 	    &((zio_t *)wsp->walk_addr)->io_parent_list.list_head)
   1880   4055  eschrock 		return (WALK_NEXT);
   1881   4055  eschrock 
   1882   4055  eschrock 	return (wsp->walk_callback(wsp->walk_addr, &zio, wsp->walk_cbdata));
   1883   4055  eschrock }
   1884   4055  eschrock 
   1885   7837   Matthew #define	NICENUM_BUFLEN 6
   1886   7837   Matthew 
   1887   7837   Matthew static int
   1888   7846   Matthew snprintfrac(char *buf, int len,
   1889   7846   Matthew     uint64_t numerator, uint64_t denom, int frac_digits)
   1890   7837   Matthew {
   1891   7846   Matthew 	int mul = 1;
   1892   7837   Matthew 	int whole, frac, i;
   1893   7837   Matthew 
   1894   7837   Matthew 	for (i = frac_digits; i; i--)
   1895   7837   Matthew 		mul *= 10;
   1896   7846   Matthew 	whole = numerator / denom;
   1897   7846   Matthew 	frac = mul * numerator / denom - mul * whole;
   1898   7837   Matthew 	return (mdb_snprintf(buf, len, "%u.%0*u", whole, frac_digits, frac));
   1899   7837   Matthew }
   1900   7837   Matthew 
   1901   7837   Matthew static void
   1902   7837   Matthew mdb_nicenum(uint64_t num, char *buf)
   1903   7837   Matthew {
   1904   7837   Matthew 	uint64_t n = num;
   1905   7837   Matthew 	int index = 0;
   1906   7837   Matthew 	char *u;
   1907   7837   Matthew 
   1908   7837   Matthew 	while (n >= 1024) {
   1909   7837   Matthew 		n = (n + (1024 / 2)) / 1024; /* Round up or down */
   1910   7837   Matthew 		index++;
   1911   7837   Matthew 	}
   1912   7837   Matthew 
   1913   7837   Matthew 	u = &" \0K\0M\0G\0T\0P\0E\0"[index*2];
   1914   7837   Matthew 
   1915   7837   Matthew 	if (index == 0) {
   1916   7837   Matthew 		(void) mdb_snprintf(buf, NICENUM_BUFLEN, "%llu",
   1917   7837   Matthew 		    (u_longlong_t)n);
   1918   7837   Matthew 	} else if (n < 10 && (num & (num - 1)) != 0) {
   1919   7846   Matthew 		(void) snprintfrac(buf, NICENUM_BUFLEN,
   1920   7846   Matthew 		    num, 1ULL << 10 * index, 2);
   1921   7837   Matthew 		strcat(buf, u);
   1922   7837   Matthew 	} else if (n < 100 && (num & (num - 1)) != 0) {
   1923   7846   Matthew 		(void) snprintfrac(buf, NICENUM_BUFLEN,
   1924   7846   Matthew 		    num, 1ULL << 10 * index, 1);
   1925   7837   Matthew 		strcat(buf, u);
   1926   7837   Matthew 	} else {
   1927   7837   Matthew 		(void) mdb_snprintf(buf, NICENUM_BUFLEN, "%llu%s",
   1928   7837   Matthew 		    (u_longlong_t)n, u);
   1929   7837   Matthew 	}
   1930   7837   Matthew }
   1931   7837   Matthew 
   1932   7837   Matthew /*
   1933   7837   Matthew  * ::zfs_blkstats
   1934   7837   Matthew  *
   1935   7837   Matthew  * 	-v	print verbose per-level information
   1936   7837   Matthew  *
   1937   7837   Matthew  */
   1938   7837   Matthew static int
   1939   7837   Matthew zfs_blkstats(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
   1940   7837   Matthew {
   1941   7837   Matthew 	boolean_t verbose = B_FALSE;
   1942   7837   Matthew 	zfs_all_blkstats_t stats;
   1943   7837   Matthew 	dmu_object_type_t t;
   1944   7837   Matthew 	zfs_blkstat_t *tzb;
   1945   7837   Matthew 	uint64_t ditto;
   1946   7837   Matthew 	dmu_object_type_info_t dmu_ot[DMU_OT_NUMTYPES + 10];
   1947   7837   Matthew 	/* +10 in case it grew */
   1948   7837   Matthew 
   1949   7837   Matthew 	if (mdb_readvar(&dmu_ot, "dmu_ot") == -1) {
   1950   7837   Matthew 		mdb_warn("failed to read 'dmu_ot'");
   1951   7837   Matthew 		return (DCMD_ERR);
   1952   7837   Matthew 	}
   1953   7837   Matthew 
   1954   7837   Matthew 	if (mdb_getopts(argc, argv,
   1955   7837   Matthew 	    'v', MDB_OPT_SETBITS, TRUE, &verbose,
   1956   7837   Matthew 	    NULL) != argc)
   1957   7837   Matthew 		return (DCMD_USAGE);
   1958   7837   Matthew 
   1959   7837   Matthew 	if (!(flags & DCMD_ADDRSPEC))
   1960   7837   Matthew 		return (DCMD_USAGE);
   1961   7837   Matthew 
   1962   7837   Matthew 	if (GETMEMB(addr, struct spa, spa_dsl_pool, addr) ||
   1963   7837   Matthew 	    GETMEMB(addr, struct dsl_pool, dp_blkstats, addr) ||
   1964   7837   Matthew 	    mdb_vread(&stats, sizeof (zfs_all_blkstats_t), addr) == -1) {
   1965   7837   Matthew 		mdb_warn("failed to read data at %p;", addr);
   1966   7837   Matthew 		mdb_printf("maybe no stats? run \"zpool scrub\" first.");
   1967   7837   Matthew 		return (DCMD_ERR);
   1968   7837   Matthew 	}
   1969   7837   Matthew 
   1970   7837   Matthew 	tzb = &stats.zab_type[DN_MAX_LEVELS][DMU_OT_NUMTYPES];
   1971   7837   Matthew 	if (tzb->zb_gangs != 0) {
   1972   7837   Matthew 		mdb_printf("Ganged blocks: %llu\n",
   1973   7837   Matthew 		    (longlong_t)tzb->zb_gangs);
   1974   7837   Matthew 	}
   1975   7837   Matthew 
   1976   7837   Matthew 	ditto = tzb->zb_ditto_2_of_2_samevdev + tzb->zb_ditto_2_of_3_samevdev +
   1977   7837   Matthew 	    tzb->zb_ditto_3_of_3_samevdev;
   1978   7837   Matthew 	if (ditto != 0) {
   1979   7837   Matthew 		mdb_printf("Dittoed blocks on same vdev: %llu\n",
   1980   7837   Matthew 		    (longlong_t)ditto);
   1981   7837   Matthew 	}
   1982   7837   Matthew 
   1983   7837   Matthew 	mdb_printf("\nBlocks\tLSIZE\tPSIZE\tASIZE"
   1984   7837   Matthew 	    "\t  avg\t comp\t%%Total\tType\n");
   1985   7837   Matthew 
   1986   7837   Matthew 	for (t = 0; t <= DMU_OT_NUMTYPES; t++) {
   1987   7837   Matthew 		char csize[NICENUM_BUFLEN], lsize[NICENUM_BUFLEN];
   1988   7837   Matthew 		char psize[NICENUM_BUFLEN], asize[NICENUM_BUFLEN];
   1989   7837   Matthew 		char avg[NICENUM_BUFLEN];
   1990   7837   Matthew 		char comp[NICENUM_BUFLEN], pct[NICENUM_BUFLEN];
   1991   7837   Matthew 		char typename[64];
   1992   7837   Matthew 		int l;
   1993   7837   Matthew 
   1994   7837   Matthew 
   1995   7837   Matthew 		if (t == DMU_OT_DEFERRED)
   1996   7837   Matthew 			strcpy(typename, "deferred free");
   1997   7837   Matthew 		else if (t == DMU_OT_TOTAL)
   1998   7837   Matthew 			strcpy(typename, "Total");
   1999   7837   Matthew 		else if (mdb_readstr(typename, sizeof (typename),
   2000   7837   Matthew 		    (uintptr_t)dmu_ot[t].ot_name) == -1) {
   2001   7837   Matthew 			mdb_warn("failed to read type name");
   2002   7837   Matthew 			return (DCMD_ERR);
   2003   7837   Matthew 		}
   2004   7837   Matthew 
   2005   7837   Matthew 		if (stats.zab_type[DN_MAX_LEVELS][t].zb_asize == 0)
   2006   7837   Matthew 			continue;
   2007   7837   Matthew 
   2008   7837   Matthew 		for (l = -1; l < DN_MAX_LEVELS; l++) {
   2009   7837   Matthew 			int level = (l == -1 ? DN_MAX_LEVELS : l);
   2010   7837   Matthew 			zfs_blkstat_t *zb = &stats.zab_type[level][t];
   2011   7837   Matthew 
   2012   7837   Matthew 			if (zb->zb_asize == 0)
   2013   7837   Matthew 				continue;
   2014   7837   Matthew 
   2015   7837   Matthew 			/*
   2016   7837   Matthew 			 * Don't print each level unless requested.
   2017   7837   Matthew 			 */
   2018   7837   Matthew 			if (!verbose && level != DN_MAX_LEVELS)
   2019   7837   Matthew 				continue;
   2020   7837   Matthew 
   2021   7837   Matthew 			/*
   2022   7837   Matthew 			 * If all the space is level 0, don't print the
   2023   7837   Matthew 			 * level 0 separately.
   2024   7837   Matthew 			 */
   2025   7837   Matthew 			if (level == 0 && zb->zb_asize ==
   2026   7837   Matthew 			    stats.zab_type[DN_MAX_LEVELS][t].zb_asize)
   2027   7837   Matthew 				continue;
   2028   7837   Matthew 
   2029   7837   Matthew 			mdb_nicenum(zb->zb_count, csize);
   2030   7837   Matthew 			mdb_nicenum(zb->zb_lsize, lsize);
   2031   7837   Matthew 			mdb_nicenum(zb->zb_psize, psize);
   2032   7837   Matthew 			mdb_nicenum(zb->zb_asize, asize);
   2033   7837   Matthew 			mdb_nicenum(zb->zb_asize / zb->zb_count, avg);
   2034   7846   Matthew 			(void) snprintfrac(comp, NICENUM_BUFLEN,
   2035   7846   Matthew 			    zb->zb_lsize, zb->zb_psize, 2);
   2036   7846   Matthew 			(void) snprintfrac(pct, NICENUM_BUFLEN,
   2037   7846   Matthew 			    100 * zb->zb_asize, tzb->zb_asize, 2);
   2038   7837   Matthew 
   2039   7837   Matthew 			mdb_printf("%6s\t%5s\t%5s\t%5s\t%5s"
   2040   7837   Matthew 			    "\t%5s\t%6s\t",
   2041   7837   Matthew 			    csize, lsize, psize, asize, avg, comp, pct);
   2042   7837   Matthew 
   2043   7837   Matthew 			if (level == DN_MAX_LEVELS)
   2044   7837   Matthew 				mdb_printf("%s\n", typename);
   2045   7837   Matthew 			else
   2046   7837   Matthew 				mdb_printf("  L%d %s\n",
   2047   7837   Matthew 				    level, typename);
   2048   7837   Matthew 		}
   2049   7837   Matthew 	}
   2050   7837   Matthew 
   2051   7837   Matthew 	return (DCMD_OK);
   2052   7837   Matthew }
   2053   7837   Matthew 
   2054  10407   Matthew /* ARGSUSED */
   2055  10407   Matthew static int
   2056  10407   Matthew reference_cb(uintptr_t addr, const void *ignored, void *arg)
   2057  10407   Matthew {
   2058  10407   Matthew 	static int gotid;
   2059  10407   Matthew 	static mdb_ctf_id_t ref_id;
   2060  10407   Matthew 	uintptr_t ref_holder;
   2061  10407   Matthew 	uintptr_t ref_removed;
   2062  10407   Matthew 	uint64_t ref_number;
   2063  10407   Matthew 	boolean_t holder_is_str;
   2064  10407   Matthew 	char holder_str[128];
   2065  10407   Matthew 	boolean_t removed = (boolean_t)arg;
   2066  10407   Matthew 
   2067  10407   Matthew 	if (!gotid) {
   2068  10407   Matthew 		if (mdb_ctf_lookup_by_name("struct reference", &ref_id) == -1) {
   2069  10407   Matthew 			mdb_warn("couldn't find struct reference");
   2070  10407   Matthew 			return (WALK_ERR);
   2071  10407   Matthew 		}
   2072  10407   Matthew 		gotid = TRUE;
   2073  10407   Matthew 	}
   2074  10407   Matthew 
   2075  10407   Matthew 	if (GETMEMBID(addr, &ref_id, ref_holder, ref_holder) ||
   2076  10407   Matthew 	    GETMEMBID(addr, &ref_id, ref_removed, ref_removed) ||
   2077  10407   Matthew 	    GETMEMBID(addr, &ref_id, ref_number, ref_number))
   2078  10407   Matthew 		return (WALK_ERR);
   2079  10407   Matthew 
   2080  10407   Matthew 	if (mdb_readstr(holder_str, sizeof (holder_str), ref_holder) != -1) {
   2081  10407   Matthew 		char *cp;
   2082  10407   Matthew 		holder_is_str = B_TRUE;
   2083  10407   Matthew 		for (cp = holder_str; *cp; cp++) {
   2084  10407   Matthew 			if (!isprint(*cp)) {
   2085  10407   Matthew 				holder_is_str = B_FALSE;
   2086  10407   Matthew 				break;
   2087  10407   Matthew 			}
   2088  10407   Matthew 		}
   2089  10407   Matthew 	} else {
   2090  10407   Matthew 		holder_is_str = B_FALSE;
   2091  10407   Matthew 	}
   2092  10407   Matthew 
   2093  10407   Matthew 	if (removed)
   2094  10407   Matthew 		mdb_printf("removed ");
   2095  10407   Matthew 	mdb_printf("reference ");
   2096  10407   Matthew 	if (ref_number != 1)
   2097  10407   Matthew 		mdb_printf("with count=%llu ", ref_number);
   2098  10407   Matthew 	mdb_printf("with tag %p", (void*)ref_holder);
   2099  10407   Matthew 	if (holder_is_str)
   2100  10407   Matthew 		mdb_printf(" \"%s\"", holder_str);
   2101  10407   Matthew 	mdb_printf(", held at:\n");
   2102  10407   Matthew 
   2103  10407   Matthew 	(void) mdb_call_dcmd("whatis", addr, DCMD_ADDRSPEC, 0, NULL);
   2104  10407   Matthew 
   2105  10407   Matthew 	if (removed) {
   2106  10407   Matthew 		mdb_printf("removed at:\n");
   2107  10407   Matthew 		(void) mdb_call_dcmd("whatis", ref_removed,
   2108  10407   Matthew 		    DCMD_ADDRSPEC, 0, NULL);
   2109  10407   Matthew 	}
   2110  10407   Matthew 
   2111  10407   Matthew 	mdb_printf("\n");
   2112  10407   Matthew 
   2113  10407   Matthew 	return (WALK_NEXT);
   2114  10407   Matthew }
   2115  10407   Matthew 
   2116  10407   Matthew /* ARGSUSED */
   2117  10407   Matthew static int
   2118  10407   Matthew refcount(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
   2119  10407   Matthew {
   2120  10407   Matthew 	uint64_t rc_count, rc_removed_count;
   2121  10407   Matthew 	uintptr_t rc_list, rc_removed;
   2122  10407   Matthew 	static int gotid;
   2123  10407   Matthew 	static mdb_ctf_id_t rc_id;
   2124  10407   Matthew 	ulong_t off;
   2125  10407   Matthew 
   2126  10407   Matthew 	if (!(flags & DCMD_ADDRSPEC))
   2127  10407   Matthew 		return (DCMD_USAGE);
   2128  10407   Matthew 
   2129  10407   Matthew 	if (!gotid) {
   2130  10407   Matthew 		if (mdb_ctf_lookup_by_name("struct refcount", &rc_id) == -1) {
   2131  10407   Matthew 			mdb_warn("couldn't find struct refcount");
   2132  10407   Matthew 			return (DCMD_ERR);
   2133  10407   Matthew 		}
   2134  10407   Matthew 		gotid = TRUE;
   2135  10407   Matthew 	}
   2136  10407   Matthew 
   2137  10407   Matthew 	if (GETMEMBID(addr, &rc_id, rc_count, rc_count) ||
   2138  10407   Matthew 	    GETMEMBID(addr, &rc_id, rc_removed_count, rc_removed_count))
   2139  10407   Matthew 		return (DCMD_ERR);
   2140  10407   Matthew 
   2141  10407   Matthew 	mdb_printf("refcount_t at %p has %llu current holds, "
   2142  10407   Matthew 	    "%llu recently released holds\n",
   2143  10407   Matthew 	    addr, (longlong_t)rc_count, (longlong_t)rc_removed_count);
   2144  10407   Matthew 
   2145  10407   Matthew 	if (rc_count > 0)
   2146  10407   Matthew 		mdb_printf("current holds:\n");
   2147  10407   Matthew 	if (mdb_ctf_offsetof(rc_id, "rc_list", &off) == -1)
   2148  10407   Matthew 		return (DCMD_ERR);
   2149  10407   Matthew 	rc_list = addr + off/NBBY;
   2150  10407   Matthew 	mdb_pwalk("list", reference_cb, (void*)B_FALSE, rc_list);
   2151  10407   Matthew 
   2152  10407   Matthew 	if (rc_removed_count > 0)
   2153  10407   Matthew 		mdb_printf("released holds:\n");
   2154  10407   Matthew 	if (mdb_ctf_offsetof(rc_id, "rc_removed", &off) == -1)
   2155  10407   Matthew 		return (DCMD_ERR);
   2156  10407   Matthew 	rc_removed = addr + off/NBBY;
   2157  10407   Matthew 	mdb_pwalk("list", reference_cb, (void*)B_TRUE, rc_removed);
   2158  10407   Matthew 
   2159  10407   Matthew 	return (DCMD_OK);
   2160  10407   Matthew }
   2161  10407   Matthew 
   2162   4055  eschrock /*
   2163    789    ahrens  * MDB module linkage information:
   2164    789    ahrens  *
   2165    789    ahrens  * We declare a list of structures describing our dcmds, and a function
   2166    789    ahrens  * named _mdb_init to return a pointer to our module information.
   2167    789    ahrens  */
   2168    789    ahrens 
   2169    789    ahrens static const mdb_dcmd_t dcmds[] = {
   2170   4787    ahrens 	{ "arc", "[-bkmg]", "print ARC variables", arc_print },
   2171    789    ahrens 	{ "blkptr", ":", "print blkptr_t", blkptr },
   2172    789    ahrens 	{ "dbuf", ":", "print dmu_buf_impl_t", dbuf },
   2173    789    ahrens 	{ "dbuf_stats", ":", "dbuf stats", dbuf_stats },
   2174    789    ahrens 	{ "dbufs",
   2175  10298   Matthew 	    "\t[-O objset_t*] [-n objset_name | \"mos\"] "
   2176   8632      Bill 	    "[-o object | \"mdn\"] \n"
   2177   8632      Bill 	    "\t[-l level] [-b blkid | \"bonus\"]",
   2178   8632      Bill 	    "find dmu_buf_impl_t's that match specified criteria", dbufs },
   2179    789    ahrens 	{ "abuf_find", "dva_word[0] dva_word[1]",
   2180   8632      Bill 	    "find arc_buf_hdr_t of a specified DVA",
   2181   8632      Bill 	    abuf_find },
   2182    789    ahrens 	{ "spa", "?[-cv]", "spa_t summary", spa_print },
   2183    789    ahrens 	{ "spa_config", ":", "print spa_t configuration", spa_print_config },
   2184    789    ahrens 	{ "spa_verify", ":", "verify spa_t consistency", spa_verify },
   2185    789    ahrens 	{ "spa_space", ":[-b]", "print spa_t on-disk space usage", spa_space },
   2186    789    ahrens 	{ "spa_vdevs", ":", "given a spa_t, print vdev summary", spa_vdevs },
   2187   4787    ahrens 	{ "vdev", ":[-re]\n"
   2188   8632      Bill 	    "\t-r display recursively\n"
   2189   8632      Bill 	    "\t-e print statistics",
   2190   8632      Bill 	    "vdev_t summary", vdev_print },
   2191   8632      Bill 	{ "zio", ":[cpr]\n"
   2192   8632      Bill 	    "\t-c display children\n"
   2193   8632      Bill 	    "\t-p display parents\n"
   2194   8632      Bill 	    "\t-r display recursively",
   2195   8632      Bill 	    "zio_t summary", zio_print },
   2196   4055  eschrock 	{ "zio_state", "?", "print out all zio_t structures on system or "
   2197   4055  eschrock 	    "for a particular pool", zio_state },
   2198   7837   Matthew 	{ "zfs_blkstats", ":[-v]",
   2199   7837   Matthew 	    "given a spa_t, print block type stats from last scrub",
   2200   7837   Matthew 	    zfs_blkstats },
   2201   3059    ahrens 	{ "zfs_params", "", "print zfs tunable parameters", zfs_params },
   2202  10407   Matthew 	{ "refcount", "", "print refcount_t holders", refcount },
   2203    789    ahrens 	{ NULL }
   2204    789    ahrens };
   2205    789    ahrens 
   2206    789    ahrens static const mdb_walker_t walkers[] = {
   2207    789    ahrens 	/*
   2208    789    ahrens 	 * In userland, there is no generic provider of list_t walkers, so we
   2209    789    ahrens 	 * need to add it.
   2210    789    ahrens 	 */
   2211    789    ahrens #ifndef _KERNEL
   2212    789    ahrens 	{ LIST_WALK_NAME, LIST_WALK_DESC,
   2213    789    ahrens 		list_walk_init, list_walk_step, list_walk_fini },
   2214    789    ahrens #endif
   2215    789    ahrens 	{ "zms_freelist", "walk ZFS metaslab freelist",
   2216   2459    ahrens 		freelist_walk_init, freelist_walk_step, NULL },
   2217    789    ahrens 	{ "txg_list", "given any txg_list_t *, walk all entries in all txgs",
   2218   2459    ahrens 		txg_list_walk_init, txg_list_walk_step, NULL },
   2219    789    ahrens 	{ "txg_list0", "given any txg_list_t *, walk all entries in txg 0",
   2220   2459    ahrens 		txg_list0_walk_init, txg_list_walk_step, NULL },
   2221    789    ahrens 	{ "txg_list1", "given any txg_list_t *, walk all entries in txg 1",
   2222   2459    ahrens 		txg_list1_walk_init, txg_list_walk_step, NULL },
   2223    789    ahrens 	{ "txg_list2", "given any txg_list_t *, walk all entries in txg 2",
   2224   2459    ahrens 		txg_list2_walk_init, txg_list_walk_step, NULL },
   2225    789    ahrens 	{ "txg_list3", "given any txg_list_t *, walk all entries in txg 3",
   2226   2459    ahrens 		txg_list3_walk_init, txg_list_walk_step, NULL },
   2227   4055  eschrock 	{ "zio", "walk all zio structures, optionally for a particular spa_t",
   2228   4055  eschrock 		zio_walk_init, zio_walk_step, NULL },
   2229   4055  eschrock 	{ "zio_root", "walk all root zio_t structures, optionally for a "
   2230   4055  eschrock 	    "particular spa_t",
   2231   4055  eschrock 		zio_walk_init, zio_walk_root_step, NULL },
   2232    789    ahrens 	{ "spa", "walk all spa_t entries in the namespace",
   2233    789    ahrens 		spa_walk_init, spa_walk_step, NULL },
   2234   2459    ahrens 	{ "metaslab", "given a spa_t *, walk all metaslab_t structures",
   2235   2459    ahrens 		metaslab_walk_init, metaslab_walk_step, NULL },
   2236    789    ahrens 	{ NULL }
   2237    789    ahrens };
   2238    789    ahrens 
   2239    789    ahrens static const mdb_modinfo_t modinfo = {
   2240    789    ahrens 	MDB_API_VERSION, dcmds, walkers
   2241    789    ahrens };
   2242    789    ahrens 
   2243    789    ahrens const mdb_modinfo_t *
   2244    789    ahrens _mdb_init(void)
   2245    789    ahrens {
   2246    789    ahrens 	return (&modinfo);
   2247    789    ahrens }
   2248