xref: /illumos-gate/usr/src/cmd/mdb/common/modules/zfs/zfs.c (revision 8363e80ae72609660f6090766ca8c2c18aa53f0c)
1fa9e4066Sahrens /*
2fa9e4066Sahrens  * CDDL HEADER START
3fa9e4066Sahrens  *
4fa9e4066Sahrens  * The contents of this file are subject to the terms of the
5ea8dc4b6Seschrock  * Common Development and Distribution License (the "License").
6ea8dc4b6Seschrock  * You may not use this file except in compliance with the License.
7fa9e4066Sahrens  *
8fa9e4066Sahrens  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9fa9e4066Sahrens  * or http://www.opensolaris.org/os/licensing.
10fa9e4066Sahrens  * See the License for the specific language governing permissions
11fa9e4066Sahrens  * and limitations under the License.
12fa9e4066Sahrens  *
13fa9e4066Sahrens  * When distributing Covered Code, include this CDDL HEADER in each
14fa9e4066Sahrens  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15fa9e4066Sahrens  * If applicable, add the following below this CDDL HEADER, with the
16fa9e4066Sahrens  * fields enclosed by brackets "[]" replaced with your own identifying
17fa9e4066Sahrens  * information: Portions Copyright [yyyy] [name of copyright owner]
18fa9e4066Sahrens  *
19fa9e4066Sahrens  * CDDL HEADER END
20fa9e4066Sahrens  */
21fa9e4066Sahrens /*
2255da60b9SMark J Musante  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
23beb56283SShampavman  * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
2491e2a09fSSteve Gonczi  * Copyright (c) 2011, 2016 by Delphix. All rights reserved.
25fa9e4066Sahrens  */
26fa9e4066Sahrens 
2755da60b9SMark J Musante /* Portions Copyright 2010 Robert Milkowski */
2855da60b9SMark J Musante 
29fa9e4066Sahrens #include <mdb/mdb_ctf.h>
30fa9e4066Sahrens #include <sys/zfs_context.h>
31fa9e4066Sahrens #include <sys/mdb_modapi.h>
32fa9e4066Sahrens #include <sys/dbuf.h>
33fa9e4066Sahrens #include <sys/dmu_objset.h>
34fa9e4066Sahrens #include <sys/dsl_dir.h>
35fa9e4066Sahrens #include <sys/dsl_pool.h>
36fa9e4066Sahrens #include <sys/metaslab_impl.h>
37fa9e4066Sahrens #include <sys/space_map.h>
38fa9e4066Sahrens #include <sys/list.h>
39fa9e4066Sahrens #include <sys/vdev_impl.h>
403f1f8012SMatthew Ahrens #include <sys/zap_leaf.h>
413f1f8012SMatthew Ahrens #include <sys/zap_impl.h>
429966ca11SMatthew Ahrens #include <ctype.h>
430a586ceaSMark Shellenbaum #include <sys/zfs_acl.h>
440a586ceaSMark Shellenbaum #include <sys/sa_impl.h>
45dcbf3bd6SGeorge Wilson #include <sys/multilist.h>
46fa9e4066Sahrens 
47fa9e4066Sahrens #ifdef _KERNEL
48fa9e4066Sahrens #define	ZFS_OBJ_NAME	"zfs"
49c55e05cbSMatthew Ahrens extern int64_t mdb_gethrtime(void);
50fa9e4066Sahrens #else
51fa9e4066Sahrens #define	ZFS_OBJ_NAME	"libzpool.so.1"
52fa9e4066Sahrens #endif
53fa9e4066Sahrens 
5428e4da25SMatthew Ahrens #define	ZFS_STRUCT	"struct " ZFS_OBJ_NAME "`"
5528e4da25SMatthew Ahrens 
56feef89cfSVictor Latushkin #ifndef _KERNEL
57feef89cfSVictor Latushkin int aok;
58feef89cfSVictor Latushkin #endif
59feef89cfSVictor Latushkin 
602e4c9986SGeorge Wilson enum spa_flags {
612e4c9986SGeorge Wilson 	SPA_FLAG_CONFIG			= 1 << 0,
622e4c9986SGeorge Wilson 	SPA_FLAG_VDEVS			= 1 << 1,
632e4c9986SGeorge Wilson 	SPA_FLAG_ERRORS			= 1 << 2,
642e4c9986SGeorge Wilson 	SPA_FLAG_METASLAB_GROUPS	= 1 << 3,
652e4c9986SGeorge Wilson 	SPA_FLAG_METASLABS		= 1 << 4,
662e4c9986SGeorge Wilson 	SPA_FLAG_HISTOGRAMS		= 1 << 5
672e4c9986SGeorge Wilson };
682e4c9986SGeorge Wilson 
6991e2a09fSSteve Gonczi /*
7091e2a09fSSteve Gonczi  * If any of these flags are set, call spa_vdevs in spa_print
7191e2a09fSSteve Gonczi  */
722e4c9986SGeorge Wilson #define	SPA_FLAG_ALL_VDEV	\
732e4c9986SGeorge Wilson 	(SPA_FLAG_VDEVS | SPA_FLAG_ERRORS | SPA_FLAG_METASLAB_GROUPS | \
7491e2a09fSSteve Gonczi 	SPA_FLAG_METASLABS)
752e4c9986SGeorge Wilson 
76fa9e4066Sahrens static int
77fa9e4066Sahrens getmember(uintptr_t addr, const char *type, mdb_ctf_id_t *idp,
78fa9e4066Sahrens     const char *member, int len, void *buf)
79fa9e4066Sahrens {
80fa9e4066Sahrens 	mdb_ctf_id_t id;
81fa9e4066Sahrens 	ulong_t off;
82fa9e4066Sahrens 	char name[64];
83fa9e4066Sahrens 
84fa9e4066Sahrens 	if (idp == NULL) {
85fa9e4066Sahrens 		if (mdb_ctf_lookup_by_name(type, &id) == -1) {
86fa9e4066Sahrens 			mdb_warn("couldn't find type %s", type);
87fa9e4066Sahrens 			return (DCMD_ERR);
88fa9e4066Sahrens 		}
89fa9e4066Sahrens 		idp = &id;
90fa9e4066Sahrens 	} else {
91fa9e4066Sahrens 		type = name;
92fa9e4066Sahrens 		mdb_ctf_type_name(*idp, name, sizeof (name));
93fa9e4066Sahrens 	}
94fa9e4066Sahrens 
95fa9e4066Sahrens 	if (mdb_ctf_offsetof(*idp, member, &off) == -1) {
96fa9e4066Sahrens 		mdb_warn("couldn't find member %s of type %s\n", member, type);
97fa9e4066Sahrens 		return (DCMD_ERR);
98fa9e4066Sahrens 	}
99fa9e4066Sahrens 	if (off % 8 != 0) {
100fa9e4066Sahrens 		mdb_warn("member %s of type %s is unsupported bitfield",
101fa9e4066Sahrens 		    member, type);
102fa9e4066Sahrens 		return (DCMD_ERR);
103fa9e4066Sahrens 	}
104fa9e4066Sahrens 	off /= 8;
105fa9e4066Sahrens 
106fa9e4066Sahrens 	if (mdb_vread(buf, len, addr + off) == -1) {
107fa9e4066Sahrens 		mdb_warn("failed to read %s from %s at %p",
108fa9e4066Sahrens 		    member, type, addr + off);
109fa9e4066Sahrens 		return (DCMD_ERR);
110fa9e4066Sahrens 	}
111fa9e4066Sahrens 	/* mdb_warn("read %s from %s at %p+%llx\n", member, type, addr, off); */
112fa9e4066Sahrens 
113fa9e4066Sahrens 	return (0);
114fa9e4066Sahrens }
115fa9e4066Sahrens 
11628e4da25SMatthew Ahrens #define	GETMEMB(addr, structname, member, dest) \
11728e4da25SMatthew Ahrens 	getmember(addr, ZFS_STRUCT structname, NULL, #member, \
11828e4da25SMatthew Ahrens 	sizeof (dest), &(dest))
119fa9e4066Sahrens 
120fa9e4066Sahrens #define	GETMEMBID(addr, ctfid, member, dest) \
121fa9e4066Sahrens 	getmember(addr, NULL, ctfid, #member, sizeof (dest), &(dest))
122fa9e4066Sahrens 
1233f9d6ad7SLin Ling static boolean_t
1243f9d6ad7SLin Ling strisprint(const char *cp)
1253f9d6ad7SLin Ling {
1263f9d6ad7SLin Ling 	for (; *cp; cp++) {
1273f9d6ad7SLin Ling 		if (!isprint(*cp))
1283f9d6ad7SLin Ling 			return (B_FALSE);
1293f9d6ad7SLin Ling 	}
1303f9d6ad7SLin Ling 	return (B_TRUE);
1313f9d6ad7SLin Ling }
1323f9d6ad7SLin Ling 
1332e4c9986SGeorge Wilson #define	NICENUM_BUFLEN 6
1342e4c9986SGeorge Wilson 
1352e4c9986SGeorge Wilson static int
1362e4c9986SGeorge Wilson snprintfrac(char *buf, int len,
1372e4c9986SGeorge Wilson     uint64_t numerator, uint64_t denom, int frac_digits)
1382e4c9986SGeorge Wilson {
1392e4c9986SGeorge Wilson 	int mul = 1;
1402e4c9986SGeorge Wilson 	int whole, frac, i;
1412e4c9986SGeorge Wilson 
1422e4c9986SGeorge Wilson 	for (i = frac_digits; i; i--)
1432e4c9986SGeorge Wilson 		mul *= 10;
1442e4c9986SGeorge Wilson 	whole = numerator / denom;
1452e4c9986SGeorge Wilson 	frac = mul * numerator / denom - mul * whole;
1462e4c9986SGeorge Wilson 	return (mdb_snprintf(buf, len, "%u.%0*u", whole, frac_digits, frac));
1472e4c9986SGeorge Wilson }
1482e4c9986SGeorge Wilson 
1492e4c9986SGeorge Wilson static void
1502e4c9986SGeorge Wilson mdb_nicenum(uint64_t num, char *buf)
1512e4c9986SGeorge Wilson {
1522e4c9986SGeorge Wilson 	uint64_t n = num;
1532e4c9986SGeorge Wilson 	int index = 0;
1542e4c9986SGeorge Wilson 	char *u;
1552e4c9986SGeorge Wilson 
1562e4c9986SGeorge Wilson 	while (n >= 1024) {
1572e4c9986SGeorge Wilson 		n = (n + (1024 / 2)) / 1024; /* Round up or down */
1582e4c9986SGeorge Wilson 		index++;
1592e4c9986SGeorge Wilson 	}
1602e4c9986SGeorge Wilson 
1612e4c9986SGeorge Wilson 	u = &" \0K\0M\0G\0T\0P\0E\0"[index*2];
1622e4c9986SGeorge Wilson 
1632e4c9986SGeorge Wilson 	if (index == 0) {
1642e4c9986SGeorge Wilson 		(void) mdb_snprintf(buf, NICENUM_BUFLEN, "%llu",
1652e4c9986SGeorge Wilson 		    (u_longlong_t)n);
1662e4c9986SGeorge Wilson 	} else if (n < 10 && (num & (num - 1)) != 0) {
1672e4c9986SGeorge Wilson 		(void) snprintfrac(buf, NICENUM_BUFLEN,
1682e4c9986SGeorge Wilson 		    num, 1ULL << 10 * index, 2);
1692e4c9986SGeorge Wilson 		strcat(buf, u);
1702e4c9986SGeorge Wilson 	} else if (n < 100 && (num & (num - 1)) != 0) {
1712e4c9986SGeorge Wilson 		(void) snprintfrac(buf, NICENUM_BUFLEN,
1722e4c9986SGeorge Wilson 		    num, 1ULL << 10 * index, 1);
1732e4c9986SGeorge Wilson 		strcat(buf, u);
1742e4c9986SGeorge Wilson 	} else {
1752e4c9986SGeorge Wilson 		(void) mdb_snprintf(buf, NICENUM_BUFLEN, "%llu%s",
1762e4c9986SGeorge Wilson 		    (u_longlong_t)n, u);
1772e4c9986SGeorge Wilson 	}
1782e4c9986SGeorge Wilson }
1792e4c9986SGeorge Wilson 
180fa9e4066Sahrens static int verbose;
181fa9e4066Sahrens 
182fa9e4066Sahrens static int
183fa9e4066Sahrens freelist_walk_init(mdb_walk_state_t *wsp)
184fa9e4066Sahrens {
185fa9e4066Sahrens 	if (wsp->walk_addr == NULL) {
186fa9e4066Sahrens 		mdb_warn("must supply starting address\n");
187fa9e4066Sahrens 		return (WALK_ERR);
188fa9e4066Sahrens 	}
189fa9e4066Sahrens 
190fa9e4066Sahrens 	wsp->walk_data = 0;  /* Index into the freelist */
191fa9e4066Sahrens 	return (WALK_NEXT);
192fa9e4066Sahrens }
193fa9e4066Sahrens 
194fa9e4066Sahrens static int
195fa9e4066Sahrens freelist_walk_step(mdb_walk_state_t *wsp)
196fa9e4066Sahrens {
197fa9e4066Sahrens 	uint64_t entry;
198fa9e4066Sahrens 	uintptr_t number = (uintptr_t)wsp->walk_data;
1998053a263Sck 	char *ddata[] = { "ALLOC", "FREE", "CONDENSE", "INVALID",
2008053a263Sck 			    "INVALID", "INVALID", "INVALID", "INVALID" };
201fa9e4066Sahrens 	int mapshift = SPA_MINBLOCKSHIFT;
202fa9e4066Sahrens 
203fa9e4066Sahrens 	if (mdb_vread(&entry, sizeof (entry), wsp->walk_addr) == -1) {
204fa9e4066Sahrens 		mdb_warn("failed to read freelist entry %p", wsp->walk_addr);
205fa9e4066Sahrens 		return (WALK_DONE);
206fa9e4066Sahrens 	}
207fa9e4066Sahrens 	wsp->walk_addr += sizeof (entry);
208fa9e4066Sahrens 	wsp->walk_data = (void *)(number + 1);
209fa9e4066Sahrens 
210fa9e4066Sahrens 	if (SM_DEBUG_DECODE(entry)) {
211fa9e4066Sahrens 		mdb_printf("DEBUG: %3u  %10s: txg=%llu  pass=%llu\n",
212fa9e4066Sahrens 		    number,
213fa9e4066Sahrens 		    ddata[SM_DEBUG_ACTION_DECODE(entry)],
214fa9e4066Sahrens 		    SM_DEBUG_TXG_DECODE(entry),
215fa9e4066Sahrens 		    SM_DEBUG_SYNCPASS_DECODE(entry));
216fa9e4066Sahrens 	} else {
217fa9e4066Sahrens 		mdb_printf("Entry: %3u  offsets=%08llx-%08llx  type=%c  "
218fa9e4066Sahrens 		    "size=%06llx", number,
219fa9e4066Sahrens 		    SM_OFFSET_DECODE(entry) << mapshift,
220fa9e4066Sahrens 		    (SM_OFFSET_DECODE(entry) + SM_RUN_DECODE(entry)) <<
221fa9e4066Sahrens 		    mapshift,
222fa9e4066Sahrens 		    SM_TYPE_DECODE(entry) == SM_ALLOC ? 'A' : 'F',
223fa9e4066Sahrens 		    SM_RUN_DECODE(entry) << mapshift);
224fa9e4066Sahrens 		if (verbose)
225fa9e4066Sahrens 			mdb_printf("      (raw=%012llx)\n", entry);
226fa9e4066Sahrens 		mdb_printf("\n");
227fa9e4066Sahrens 	}
228fa9e4066Sahrens 	return (WALK_NEXT);
229fa9e4066Sahrens }
230fa9e4066Sahrens 
231fa9e4066Sahrens static int
23228e4da25SMatthew Ahrens mdb_dsl_dir_name(uintptr_t addr, char *buf)
233fa9e4066Sahrens {
234fa9e4066Sahrens 	static int gotid;
235fa9e4066Sahrens 	static mdb_ctf_id_t dd_id;
236fa9e4066Sahrens 	uintptr_t dd_parent;
2379adfa60dSMatthew Ahrens 	char dd_myname[ZFS_MAX_DATASET_NAME_LEN];
238fa9e4066Sahrens 
239fa9e4066Sahrens 	if (!gotid) {
24028e4da25SMatthew Ahrens 		if (mdb_ctf_lookup_by_name(ZFS_STRUCT "dsl_dir",
241fa9e4066Sahrens 		    &dd_id) == -1) {
242fa9e4066Sahrens 			mdb_warn("couldn't find struct dsl_dir");
243fa9e4066Sahrens 			return (DCMD_ERR);
244fa9e4066Sahrens 		}
245fa9e4066Sahrens 		gotid = TRUE;
246fa9e4066Sahrens 	}
247fa9e4066Sahrens 	if (GETMEMBID(addr, &dd_id, dd_parent, dd_parent) ||
248fa9e4066Sahrens 	    GETMEMBID(addr, &dd_id, dd_myname, dd_myname)) {
249fa9e4066Sahrens 		return (DCMD_ERR);
250fa9e4066Sahrens 	}
251fa9e4066Sahrens 
252fa9e4066Sahrens 	if (dd_parent) {
25328e4da25SMatthew Ahrens 		if (mdb_dsl_dir_name(dd_parent, buf))
254fa9e4066Sahrens 			return (DCMD_ERR);
255fa9e4066Sahrens 		strcat(buf, "/");
256fa9e4066Sahrens 	}
257fa9e4066Sahrens 
258fa9e4066Sahrens 	if (dd_myname[0])
259fa9e4066Sahrens 		strcat(buf, dd_myname);
260fa9e4066Sahrens 	else
261fa9e4066Sahrens 		strcat(buf, "???");
262fa9e4066Sahrens 
263fa9e4066Sahrens 	return (0);
264fa9e4066Sahrens }
265fa9e4066Sahrens 
266fa9e4066Sahrens static int
267fa9e4066Sahrens objset_name(uintptr_t addr, char *buf)
268fa9e4066Sahrens {
269fa9e4066Sahrens 	static int gotid;
2704223fc7cSMark Shellenbaum 	static mdb_ctf_id_t os_id, ds_id;
271fa9e4066Sahrens 	uintptr_t os_dsl_dataset;
2729adfa60dSMatthew Ahrens 	char ds_snapname[ZFS_MAX_DATASET_NAME_LEN];
273fa9e4066Sahrens 	uintptr_t ds_dir;
274fa9e4066Sahrens 
275fa9e4066Sahrens 	buf[0] = '\0';
276fa9e4066Sahrens 
277fa9e4066Sahrens 	if (!gotid) {
27828e4da25SMatthew Ahrens 		if (mdb_ctf_lookup_by_name(ZFS_STRUCT "objset",
2794223fc7cSMark Shellenbaum 		    &os_id) == -1) {
2804223fc7cSMark Shellenbaum 			mdb_warn("couldn't find struct objset");
281fa9e4066Sahrens 			return (DCMD_ERR);
282fa9e4066Sahrens 		}
28328e4da25SMatthew Ahrens 		if (mdb_ctf_lookup_by_name(ZFS_STRUCT "dsl_dataset",
284fa9e4066Sahrens 		    &ds_id) == -1) {
285fa9e4066Sahrens 			mdb_warn("couldn't find struct dsl_dataset");
286fa9e4066Sahrens 			return (DCMD_ERR);
287fa9e4066Sahrens 		}
288fa9e4066Sahrens 
289fa9e4066Sahrens 		gotid = TRUE;
290fa9e4066Sahrens 	}
291fa9e4066Sahrens 
2924223fc7cSMark Shellenbaum 	if (GETMEMBID(addr, &os_id, os_dsl_dataset, os_dsl_dataset))
293fa9e4066Sahrens 		return (DCMD_ERR);
294fa9e4066Sahrens 
295fa9e4066Sahrens 	if (os_dsl_dataset == 0) {
296fa9e4066Sahrens 		strcat(buf, "mos");
297fa9e4066Sahrens 		return (0);
298fa9e4066Sahrens 	}
299fa9e4066Sahrens 
300fa9e4066Sahrens 	if (GETMEMBID(os_dsl_dataset, &ds_id, ds_snapname, ds_snapname) ||
301fa9e4066Sahrens 	    GETMEMBID(os_dsl_dataset, &ds_id, ds_dir, ds_dir)) {
302fa9e4066Sahrens 		return (DCMD_ERR);
303fa9e4066Sahrens 	}
304fa9e4066Sahrens 
30528e4da25SMatthew Ahrens 	if (ds_dir && mdb_dsl_dir_name(ds_dir, buf))
306fa9e4066Sahrens 		return (DCMD_ERR);
307fa9e4066Sahrens 
308fa9e4066Sahrens 	if (ds_snapname[0]) {
309fa9e4066Sahrens 		strcat(buf, "@");
310fa9e4066Sahrens 		strcat(buf, ds_snapname);
311fa9e4066Sahrens 	}
312fa9e4066Sahrens 	return (0);
313fa9e4066Sahrens }
314fa9e4066Sahrens 
315*8363e80aSGeorge Wilson static int
316*8363e80aSGeorge Wilson enum_lookup(char *type, int val, const char *prefix, size_t size, char *out)
317fa9e4066Sahrens {
318fa9e4066Sahrens 	const char *cp;
319fa9e4066Sahrens 	size_t len = strlen(prefix);
320*8363e80aSGeorge Wilson 	mdb_ctf_id_t enum_type;
321*8363e80aSGeorge Wilson 
322*8363e80aSGeorge Wilson 	if (mdb_ctf_lookup_by_name(type, &enum_type) != 0) {
323*8363e80aSGeorge Wilson 		mdb_warn("Could not find enum for %s", type);
324*8363e80aSGeorge Wilson 		return (-1);
325*8363e80aSGeorge Wilson 	}
326fa9e4066Sahrens 
327*8363e80aSGeorge Wilson 	if ((cp = mdb_ctf_enum_name(enum_type, val)) != NULL) {
328fa9e4066Sahrens 		if (strncmp(cp, prefix, len) == 0)
329fa9e4066Sahrens 			cp += len;
330fa9e4066Sahrens 		(void) strncpy(out, cp, size);
331fa9e4066Sahrens 	} else {
332fa9e4066Sahrens 		mdb_snprintf(out, size, "? (%d)", val);
333fa9e4066Sahrens 	}
334*8363e80aSGeorge Wilson 	return (0);
335fa9e4066Sahrens }
336fa9e4066Sahrens 
337614409b5Sahrens /* ARGSUSED */
338614409b5Sahrens static int
339614409b5Sahrens zfs_params(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
340614409b5Sahrens {
341614409b5Sahrens 	/*
342614409b5Sahrens 	 * This table can be approximately generated by running:
343614409b5Sahrens 	 * egrep "^[a-z0-9_]+ [a-z0-9_]+( =.*)?;" *.c | cut -d ' ' -f 2
344614409b5Sahrens 	 */
345614409b5Sahrens 	static const char *params[] = {
346614409b5Sahrens 		"arc_reduce_dnlc_percent",
34769962b56SMatthew Ahrens 		"arc_lotsfree_percent",
34869962b56SMatthew Ahrens 		"zfs_dirty_data_max",
34969962b56SMatthew Ahrens 		"zfs_dirty_data_sync",
35069962b56SMatthew Ahrens 		"zfs_delay_max_ns",
35169962b56SMatthew Ahrens 		"zfs_delay_min_dirty_percent",
35269962b56SMatthew Ahrens 		"zfs_delay_scale",
35369962b56SMatthew Ahrens 		"zfs_vdev_max_active",
35469962b56SMatthew Ahrens 		"zfs_vdev_sync_read_min_active",
35569962b56SMatthew Ahrens 		"zfs_vdev_sync_read_max_active",
35669962b56SMatthew Ahrens 		"zfs_vdev_sync_write_min_active",
35769962b56SMatthew Ahrens 		"zfs_vdev_sync_write_max_active",
35869962b56SMatthew Ahrens 		"zfs_vdev_async_read_min_active",
35969962b56SMatthew Ahrens 		"zfs_vdev_async_read_max_active",
36069962b56SMatthew Ahrens 		"zfs_vdev_async_write_min_active",
36169962b56SMatthew Ahrens 		"zfs_vdev_async_write_max_active",
36269962b56SMatthew Ahrens 		"zfs_vdev_scrub_min_active",
36369962b56SMatthew Ahrens 		"zfs_vdev_scrub_max_active",
36469962b56SMatthew Ahrens 		"zfs_vdev_async_write_active_min_dirty_percent",
36569962b56SMatthew Ahrens 		"zfs_vdev_async_write_active_max_dirty_percent",
36669962b56SMatthew Ahrens 		"spa_asize_inflation",
367614409b5Sahrens 		"zfs_arc_max",
368614409b5Sahrens 		"zfs_arc_min",
36949e3519aSmaybee 		"arc_shrink_shift",
370614409b5Sahrens 		"zfs_mdcomp_disable",
371614409b5Sahrens 		"zfs_prefetch_disable",
372614409b5Sahrens 		"zfetch_max_streams",
373614409b5Sahrens 		"zfetch_min_sec_reap",
374614409b5Sahrens 		"zfetch_block_cap",
375614409b5Sahrens 		"zfetch_array_rd_sz",
376614409b5Sahrens 		"zfs_default_bs",
377614409b5Sahrens 		"zfs_default_ibs",
378614409b5Sahrens 		"metaslab_aliquot",
379614409b5Sahrens 		"reference_tracking_enable",
380614409b5Sahrens 		"reference_history",
381614409b5Sahrens 		"spa_max_replication_override",
382b24ab676SJeff Bonwick 		"spa_mode_global",
383614409b5Sahrens 		"zfs_flags",
3841ab7f2deSmaybee 		"zfs_txg_timeout",
385614409b5Sahrens 		"zfs_vdev_cache_max",
386614409b5Sahrens 		"zfs_vdev_cache_size",
387614409b5Sahrens 		"zfs_vdev_cache_bshift",
388614409b5Sahrens 		"vdev_mirror_shift",
389614409b5Sahrens 		"zfs_scrub_limit",
390b16da2e2SGeorge Wilson 		"zfs_no_scrub_io",
391b16da2e2SGeorge Wilson 		"zfs_no_scrub_prefetch",
392614409b5Sahrens 		"zfs_vdev_aggregation_limit",
393614409b5Sahrens 		"fzap_default_block_shift",
394614409b5Sahrens 		"zfs_immediate_write_sz",
395614409b5Sahrens 		"zfs_read_chunk_size",
396614409b5Sahrens 		"zfs_nocacheflush",
39755da60b9SMark J Musante 		"zil_replay_disable",
3981ab7f2deSmaybee 		"metaslab_gang_bang",
399d6e555bdSGeorge Wilson 		"metaslab_df_alloc_threshold",
400d6e555bdSGeorge Wilson 		"metaslab_df_free_pct",
401614409b5Sahrens 		"zio_injection_enabled",
402614409b5Sahrens 		"zvol_immediate_write_sz",
403614409b5Sahrens 	};
404614409b5Sahrens 
405b24ab676SJeff Bonwick 	for (int i = 0; i < sizeof (params) / sizeof (params[0]); i++) {
406614409b5Sahrens 		int sz;
407614409b5Sahrens 		uint64_t val64;
408614409b5Sahrens 		uint32_t *val32p = (uint32_t *)&val64;
409614409b5Sahrens 
410614409b5Sahrens 		sz = mdb_readvar(&val64, params[i]);
411614409b5Sahrens 		if (sz == 4) {
412614409b5Sahrens 			mdb_printf("%s = 0x%x\n", params[i], *val32p);
413614409b5Sahrens 		} else if (sz == 8) {
414614409b5Sahrens 			mdb_printf("%s = 0x%llx\n", params[i], val64);
415614409b5Sahrens 		} else {
416614409b5Sahrens 			mdb_warn("variable %s not found", params[i]);
417614409b5Sahrens 		}
418614409b5Sahrens 	}
419614409b5Sahrens 
420614409b5Sahrens 	return (DCMD_OK);
421614409b5Sahrens }
422614409b5Sahrens 
423fa9e4066Sahrens /* ARGSUSED */
424fa9e4066Sahrens static int
425fa9e4066Sahrens blkptr(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
426fa9e4066Sahrens {
427b24ab676SJeff Bonwick 	char type[80], checksum[80], compress[80];
428b24ab676SJeff Bonwick 	blkptr_t blk, *bp = &blk;
429b24ab676SJeff Bonwick 	char buf[BP_SPRINTF_LEN];
430fa9e4066Sahrens 
431b24ab676SJeff Bonwick 	if (mdb_vread(&blk, sizeof (blkptr_t), addr) == -1) {
432fa9e4066Sahrens 		mdb_warn("failed to read blkptr_t");
433fa9e4066Sahrens 		return (DCMD_ERR);
434fa9e4066Sahrens 	}
435fa9e4066Sahrens 
436*8363e80aSGeorge Wilson 	if (enum_lookup("enum dmu_object_type", BP_GET_TYPE(bp), "DMU_OT_",
437*8363e80aSGeorge Wilson 	    sizeof (type), type) == -1 ||
438*8363e80aSGeorge Wilson 	    enum_lookup("enum zio_checksum", BP_GET_CHECKSUM(bp),
439*8363e80aSGeorge Wilson 	    "ZIO_CHECKSUM_", sizeof (checksum), checksum) == -1 ||
440*8363e80aSGeorge Wilson 	    enum_lookup("enum zio_compress", BP_GET_COMPRESS(bp),
441*8363e80aSGeorge Wilson 	    "ZIO_COMPRESS_", sizeof (compress), compress) == -1) {
442b24ab676SJeff Bonwick 		mdb_warn("Could not find blkptr enumerated types");
443fa9e4066Sahrens 		return (DCMD_ERR);
444fa9e4066Sahrens 	}
445fa9e4066Sahrens 
44643466aaeSMax Grossman 	SNPRINTF_BLKPTR(mdb_snprintf, '\n', buf, sizeof (buf), bp, type,
44743466aaeSMax Grossman 	    checksum, compress);
448fa9e4066Sahrens 
449b24ab676SJeff Bonwick 	mdb_printf("%s\n", buf);
450fa9e4066Sahrens 
451fa9e4066Sahrens 	return (DCMD_OK);
452fa9e4066Sahrens }
453fa9e4066Sahrens 
45428e4da25SMatthew Ahrens typedef struct mdb_dmu_buf_impl {
45528e4da25SMatthew Ahrens 	struct {
45628e4da25SMatthew Ahrens 		uint64_t db_object;
4572515f5d4SJustin T. Gibbs 		uintptr_t db_data;
45828e4da25SMatthew Ahrens 	} db;
459d5ee8a13SMatthew Ahrens 	uintptr_t db_objset;
46028e4da25SMatthew Ahrens 	uint64_t db_level;
46128e4da25SMatthew Ahrens 	uint64_t db_blkid;
46228e4da25SMatthew Ahrens 	struct {
46328e4da25SMatthew Ahrens 		uint64_t rc_count;
46428e4da25SMatthew Ahrens 	} db_holds;
46528e4da25SMatthew Ahrens } mdb_dmu_buf_impl_t;
46628e4da25SMatthew Ahrens 
467fa9e4066Sahrens /* ARGSUSED */
468fa9e4066Sahrens static int
469fa9e4066Sahrens dbuf(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
470fa9e4066Sahrens {
47128e4da25SMatthew Ahrens 	mdb_dmu_buf_impl_t db;
472fa9e4066Sahrens 	char objectname[32];
473fa9e4066Sahrens 	char blkidname[32];
4749adfa60dSMatthew Ahrens 	char path[ZFS_MAX_DATASET_NAME_LEN];
475ba3132cfSJoe Stein 	int ptr_width = (int)(sizeof (void *)) * 2;
476fa9e4066Sahrens 
47728e4da25SMatthew Ahrens 	if (DCMD_HDRSPEC(flags))
478ba3132cfSJoe Stein 		mdb_printf("%*s %8s %3s %9s %5s %s\n",
479ba3132cfSJoe Stein 		    ptr_width, "addr", "object", "lvl", "blkid", "holds", "os");
480fa9e4066Sahrens 
48128e4da25SMatthew Ahrens 	if (mdb_ctf_vread(&db, ZFS_STRUCT "dmu_buf_impl", "mdb_dmu_buf_impl_t",
48228e4da25SMatthew Ahrens 	    addr, 0) == -1)
483fa9e4066Sahrens 		return (DCMD_ERR);
484fa9e4066Sahrens 
48528e4da25SMatthew Ahrens 	if (db.db.db_object == DMU_META_DNODE_OBJECT)
486fa9e4066Sahrens 		(void) strcpy(objectname, "mdn");
487fa9e4066Sahrens 	else
488fa9e4066Sahrens 		(void) mdb_snprintf(objectname, sizeof (objectname), "%llx",
48928e4da25SMatthew Ahrens 		    (u_longlong_t)db.db.db_object);
490fa9e4066Sahrens 
49128e4da25SMatthew Ahrens 	if (db.db_blkid == DMU_BONUS_BLKID)
492fa9e4066Sahrens 		(void) strcpy(blkidname, "bonus");
493fa9e4066Sahrens 	else
494fa9e4066Sahrens 		(void) mdb_snprintf(blkidname, sizeof (blkidname), "%llx",
49528e4da25SMatthew Ahrens 		    (u_longlong_t)db.db_blkid);
496fa9e4066Sahrens 
497d5ee8a13SMatthew Ahrens 	if (objset_name(db.db_objset, path)) {
49828e4da25SMatthew Ahrens 		return (DCMD_ERR);
499fa9e4066Sahrens 	}
500fa9e4066Sahrens 
501ba3132cfSJoe Stein 	mdb_printf("%*p %8s %3u %9s %5llu %s\n", ptr_width, addr,
50228e4da25SMatthew Ahrens 	    objectname, (int)db.db_level, blkidname,
50328e4da25SMatthew Ahrens 	    db.db_holds.rc_count, path);
504fa9e4066Sahrens 
505fa9e4066Sahrens 	return (DCMD_OK);
506fa9e4066Sahrens }
507fa9e4066Sahrens 
508fa9e4066Sahrens /* ARGSUSED */
509fa9e4066Sahrens static int
510fa9e4066Sahrens dbuf_stats(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
511fa9e4066Sahrens {
512fa9e4066Sahrens #define	HISTOSZ 32
513fa9e4066Sahrens 	uintptr_t dbp;
514fa9e4066Sahrens 	dmu_buf_impl_t db;
515fa9e4066Sahrens 	dbuf_hash_table_t ht;
516fa9e4066Sahrens 	uint64_t bucket, ndbufs;
517fa9e4066Sahrens 	uint64_t histo[HISTOSZ];
518fa9e4066Sahrens 	uint64_t histo2[HISTOSZ];
519fa9e4066Sahrens 	int i, maxidx;
520fa9e4066Sahrens 
521fa9e4066Sahrens 	if (mdb_readvar(&ht, "dbuf_hash_table") == -1) {
522fa9e4066Sahrens 		mdb_warn("failed to read 'dbuf_hash_table'");
523fa9e4066Sahrens 		return (DCMD_ERR);
524fa9e4066Sahrens 	}
525fa9e4066Sahrens 
526fa9e4066Sahrens 	for (i = 0; i < HISTOSZ; i++) {
527fa9e4066Sahrens 		histo[i] = 0;
528fa9e4066Sahrens 		histo2[i] = 0;
529fa9e4066Sahrens 	}
530fa9e4066Sahrens 
531fa9e4066Sahrens 	ndbufs = 0;
532fa9e4066Sahrens 	for (bucket = 0; bucket < ht.hash_table_mask+1; bucket++) {
533fa9e4066Sahrens 		int len;
534fa9e4066Sahrens 
535fa9e4066Sahrens 		if (mdb_vread(&dbp, sizeof (void *),
536fa9e4066Sahrens 		    (uintptr_t)(ht.hash_table+bucket)) == -1) {
537fa9e4066Sahrens 			mdb_warn("failed to read hash bucket %u at %p",
538fa9e4066Sahrens 			    bucket, ht.hash_table+bucket);
539fa9e4066Sahrens 			return (DCMD_ERR);
540fa9e4066Sahrens 		}
541fa9e4066Sahrens 
542fa9e4066Sahrens 		len = 0;
543fa9e4066Sahrens 		while (dbp != 0) {
544fa9e4066Sahrens 			if (mdb_vread(&db, sizeof (dmu_buf_impl_t),
545fa9e4066Sahrens 			    dbp) == -1) {
546fa9e4066Sahrens 				mdb_warn("failed to read dbuf at %p", dbp);
547fa9e4066Sahrens 				return (DCMD_ERR);
548fa9e4066Sahrens 			}
549fa9e4066Sahrens 			dbp = (uintptr_t)db.db_hash_next;
550fa9e4066Sahrens 			for (i = MIN(len, HISTOSZ - 1); i >= 0; i--)
551fa9e4066Sahrens 				histo2[i]++;
552fa9e4066Sahrens 			len++;
553fa9e4066Sahrens 			ndbufs++;
554fa9e4066Sahrens 		}
555fa9e4066Sahrens 
556fa9e4066Sahrens 		if (len >= HISTOSZ)
557fa9e4066Sahrens 			len = HISTOSZ-1;
558fa9e4066Sahrens 		histo[len]++;
559fa9e4066Sahrens 	}
560fa9e4066Sahrens 
561fa9e4066Sahrens 	mdb_printf("hash table has %llu buckets, %llu dbufs "
562fa9e4066Sahrens 	    "(avg %llu buckets/dbuf)\n",
563fa9e4066Sahrens 	    ht.hash_table_mask+1, ndbufs,
564fa9e4066Sahrens 	    (ht.hash_table_mask+1)/ndbufs);
565fa9e4066Sahrens 
566fa9e4066Sahrens 	mdb_printf("\n");
567fa9e4066Sahrens 	maxidx = 0;
568fa9e4066Sahrens 	for (i = 0; i < HISTOSZ; i++)
569fa9e4066Sahrens 		if (histo[i] > 0)
570fa9e4066Sahrens 			maxidx = i;
571fa9e4066Sahrens 	mdb_printf("hash chain length	number of buckets\n");
572fa9e4066Sahrens 	for (i = 0; i <= maxidx; i++)
573fa9e4066Sahrens 		mdb_printf("%u			%llu\n", i, histo[i]);
574fa9e4066Sahrens 
575fa9e4066Sahrens 	mdb_printf("\n");
576fa9e4066Sahrens 	maxidx = 0;
577fa9e4066Sahrens 	for (i = 0; i < HISTOSZ; i++)
578fa9e4066Sahrens 		if (histo2[i] > 0)
579fa9e4066Sahrens 			maxidx = i;
580fa9e4066Sahrens 	mdb_printf("hash chain depth	number of dbufs\n");
581fa9e4066Sahrens 	for (i = 0; i <= maxidx; i++)
582fa9e4066Sahrens 		mdb_printf("%u or more		%llu	%llu%%\n",
583fa9e4066Sahrens 		    i, histo2[i], histo2[i]*100/ndbufs);
584fa9e4066Sahrens 
585fa9e4066Sahrens 
586fa9e4066Sahrens 	return (DCMD_OK);
587fa9e4066Sahrens }
588fa9e4066Sahrens 
5893f1f8012SMatthew Ahrens #define	CHAIN_END 0xffff
5903f1f8012SMatthew Ahrens /*
5913f1f8012SMatthew Ahrens  * ::zap_leaf [-v]
5923f1f8012SMatthew Ahrens  *
5933f1f8012SMatthew Ahrens  * Print a zap_leaf_phys_t, assumed to be 16k
5943f1f8012SMatthew Ahrens  */
5953f1f8012SMatthew Ahrens /* ARGSUSED */
5963f1f8012SMatthew Ahrens static int
5973f1f8012SMatthew Ahrens zap_leaf(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
5983f1f8012SMatthew Ahrens {
5993f1f8012SMatthew Ahrens 	char buf[16*1024];
6003f1f8012SMatthew Ahrens 	int verbose = B_FALSE;
6013f1f8012SMatthew Ahrens 	int four = B_FALSE;
602c1379625SJustin T. Gibbs 	dmu_buf_t l_dbuf;
6033f1f8012SMatthew Ahrens 	zap_leaf_t l;
6043f1f8012SMatthew Ahrens 	zap_leaf_phys_t *zlp = (void *)buf;
6053f1f8012SMatthew Ahrens 	int i;
6063f1f8012SMatthew Ahrens 
6073f1f8012SMatthew Ahrens 	if (mdb_getopts(argc, argv,
6083f1f8012SMatthew Ahrens 	    'v', MDB_OPT_SETBITS, TRUE, &verbose,
6093f1f8012SMatthew Ahrens 	    '4', MDB_OPT_SETBITS, TRUE, &four,
6103f1f8012SMatthew Ahrens 	    NULL) != argc)
6113f1f8012SMatthew Ahrens 		return (DCMD_USAGE);
6123f1f8012SMatthew Ahrens 
613c1379625SJustin T. Gibbs 	l_dbuf.db_data = zlp;
614c1379625SJustin T. Gibbs 	l.l_dbuf = &l_dbuf;
6153f1f8012SMatthew Ahrens 	l.l_bs = 14; /* assume 16k blocks */
6163f1f8012SMatthew Ahrens 	if (four)
6173f1f8012SMatthew Ahrens 		l.l_bs = 12;
6183f1f8012SMatthew Ahrens 
6193f1f8012SMatthew Ahrens 	if (!(flags & DCMD_ADDRSPEC)) {
6203f1f8012SMatthew Ahrens 		return (DCMD_USAGE);
6213f1f8012SMatthew Ahrens 	}
6223f1f8012SMatthew Ahrens 
6233f1f8012SMatthew Ahrens 	if (mdb_vread(buf, sizeof (buf), addr) == -1) {
6243f1f8012SMatthew Ahrens 		mdb_warn("failed to read zap_leaf_phys_t at %p", addr);
6253f1f8012SMatthew Ahrens 		return (DCMD_ERR);
6263f1f8012SMatthew Ahrens 	}
6273f1f8012SMatthew Ahrens 
6283f1f8012SMatthew Ahrens 	if (zlp->l_hdr.lh_block_type != ZBT_LEAF ||
6293f1f8012SMatthew Ahrens 	    zlp->l_hdr.lh_magic != ZAP_LEAF_MAGIC) {
6303f1f8012SMatthew Ahrens 		mdb_warn("This does not appear to be a zap_leaf_phys_t");
6313f1f8012SMatthew Ahrens 		return (DCMD_ERR);
6323f1f8012SMatthew Ahrens 	}
6333f1f8012SMatthew Ahrens 
6343f1f8012SMatthew Ahrens 	mdb_printf("zap_leaf_phys_t at %p:\n", addr);
6353f1f8012SMatthew Ahrens 	mdb_printf("    lh_prefix_len = %u\n", zlp->l_hdr.lh_prefix_len);
6363f1f8012SMatthew Ahrens 	mdb_printf("    lh_prefix = %llx\n", zlp->l_hdr.lh_prefix);
6373f1f8012SMatthew Ahrens 	mdb_printf("    lh_nentries = %u\n", zlp->l_hdr.lh_nentries);
6383f1f8012SMatthew Ahrens 	mdb_printf("    lh_nfree = %u\n", zlp->l_hdr.lh_nfree,
6393f1f8012SMatthew Ahrens 	    zlp->l_hdr.lh_nfree * 100 / (ZAP_LEAF_NUMCHUNKS(&l)));
6403f1f8012SMatthew Ahrens 	mdb_printf("    lh_freelist = %u\n", zlp->l_hdr.lh_freelist);
6413f1f8012SMatthew Ahrens 	mdb_printf("    lh_flags = %x (%s)\n", zlp->l_hdr.lh_flags,
6423f1f8012SMatthew Ahrens 	    zlp->l_hdr.lh_flags & ZLF_ENTRIES_CDSORTED ?
6433f1f8012SMatthew Ahrens 	    "ENTRIES_CDSORTED" : "");
6443f1f8012SMatthew Ahrens 
6453f1f8012SMatthew Ahrens 	if (verbose) {
6463f1f8012SMatthew Ahrens 		mdb_printf(" hash table:\n");
6473f1f8012SMatthew Ahrens 		for (i = 0; i < ZAP_LEAF_HASH_NUMENTRIES(&l); i++) {
6483f1f8012SMatthew Ahrens 			if (zlp->l_hash[i] != CHAIN_END)
6493f1f8012SMatthew Ahrens 				mdb_printf("    %u: %u\n", i, zlp->l_hash[i]);
6503f1f8012SMatthew Ahrens 		}
6513f1f8012SMatthew Ahrens 	}
6523f1f8012SMatthew Ahrens 
6533f1f8012SMatthew Ahrens 	mdb_printf(" chunks:\n");
6543f1f8012SMatthew Ahrens 	for (i = 0; i < ZAP_LEAF_NUMCHUNKS(&l); i++) {
6553f1f8012SMatthew Ahrens 		/* LINTED: alignment */
6563f1f8012SMatthew Ahrens 		zap_leaf_chunk_t *zlc = &ZAP_LEAF_CHUNK(&l, i);
6573f1f8012SMatthew Ahrens 		switch (zlc->l_entry.le_type) {
6583f1f8012SMatthew Ahrens 		case ZAP_CHUNK_FREE:
6593f1f8012SMatthew Ahrens 			if (verbose) {
6603f1f8012SMatthew Ahrens 				mdb_printf("    %u: free; lf_next = %u\n",
6613f1f8012SMatthew Ahrens 				    i, zlc->l_free.lf_next);
6623f1f8012SMatthew Ahrens 			}
6633f1f8012SMatthew Ahrens 			break;
6643f1f8012SMatthew Ahrens 		case ZAP_CHUNK_ENTRY:
6653f1f8012SMatthew Ahrens 			mdb_printf("    %u: entry\n", i);
6663f1f8012SMatthew Ahrens 			if (verbose) {
6673f1f8012SMatthew Ahrens 				mdb_printf("        le_next = %u\n",
6683f1f8012SMatthew Ahrens 				    zlc->l_entry.le_next);
6693f1f8012SMatthew Ahrens 			}
6703f1f8012SMatthew Ahrens 			mdb_printf("        le_name_chunk = %u\n",
6713f1f8012SMatthew Ahrens 			    zlc->l_entry.le_name_chunk);
6723f1f8012SMatthew Ahrens 			mdb_printf("        le_name_numints = %u\n",
6733f1f8012SMatthew Ahrens 			    zlc->l_entry.le_name_numints);
6743f1f8012SMatthew Ahrens 			mdb_printf("        le_value_chunk = %u\n",
6753f1f8012SMatthew Ahrens 			    zlc->l_entry.le_value_chunk);
6763f1f8012SMatthew Ahrens 			mdb_printf("        le_value_intlen = %u\n",
6773f1f8012SMatthew Ahrens 			    zlc->l_entry.le_value_intlen);
6783f1f8012SMatthew Ahrens 			mdb_printf("        le_value_numints = %u\n",
6793f1f8012SMatthew Ahrens 			    zlc->l_entry.le_value_numints);
6803f1f8012SMatthew Ahrens 			mdb_printf("        le_cd = %u\n",
6813f1f8012SMatthew Ahrens 			    zlc->l_entry.le_cd);
6823f1f8012SMatthew Ahrens 			mdb_printf("        le_hash = %llx\n",
6833f1f8012SMatthew Ahrens 			    zlc->l_entry.le_hash);
6843f1f8012SMatthew Ahrens 			break;
6853f1f8012SMatthew Ahrens 		case ZAP_CHUNK_ARRAY:
6863f9d6ad7SLin Ling 			mdb_printf("    %u: array", i);
6873f9d6ad7SLin Ling 			if (strisprint((char *)zlc->l_array.la_array))
6883f9d6ad7SLin Ling 				mdb_printf(" \"%s\"", zlc->l_array.la_array);
6893f9d6ad7SLin Ling 			mdb_printf("\n");
6903f1f8012SMatthew Ahrens 			if (verbose) {
6913f1f8012SMatthew Ahrens 				int j;
6923f1f8012SMatthew Ahrens 				mdb_printf("        ");
6933f1f8012SMatthew Ahrens 				for (j = 0; j < ZAP_LEAF_ARRAY_BYTES; j++) {
6943f1f8012SMatthew Ahrens 					mdb_printf("%02x ",
6953f1f8012SMatthew Ahrens 					    zlc->l_array.la_array[j]);
6963f1f8012SMatthew Ahrens 				}
6973f1f8012SMatthew Ahrens 				mdb_printf("\n");
6983f1f8012SMatthew Ahrens 			}
6993f1f8012SMatthew Ahrens 			if (zlc->l_array.la_next != CHAIN_END) {
7003f1f8012SMatthew Ahrens 				mdb_printf("        lf_next = %u\n",
7013f1f8012SMatthew Ahrens 				    zlc->l_array.la_next);
7023f1f8012SMatthew Ahrens 			}
7033f1f8012SMatthew Ahrens 			break;
7043f1f8012SMatthew Ahrens 		default:
7053f1f8012SMatthew Ahrens 			mdb_printf("    %u: undefined type %u\n",
7063f1f8012SMatthew Ahrens 			    zlc->l_entry.le_type);
7073f1f8012SMatthew Ahrens 		}
7083f1f8012SMatthew Ahrens 	}
7093f1f8012SMatthew Ahrens 
7103f1f8012SMatthew Ahrens 	return (DCMD_OK);
7113f1f8012SMatthew Ahrens }
7123f1f8012SMatthew Ahrens 
713fa9e4066Sahrens typedef struct dbufs_data {
714fa9e4066Sahrens 	mdb_ctf_id_t id;
715fa9e4066Sahrens 	uint64_t objset;
716fa9e4066Sahrens 	uint64_t object;
717fa9e4066Sahrens 	uint64_t level;
718fa9e4066Sahrens 	uint64_t blkid;
719fa9e4066Sahrens 	char *osname;
720fa9e4066Sahrens } dbufs_data_t;
721fa9e4066Sahrens 
722fa9e4066Sahrens #define	DBUFS_UNSET	(0xbaddcafedeadbeefULL)
723fa9e4066Sahrens 
724fa9e4066Sahrens /* ARGSUSED */
725fa9e4066Sahrens static int
726fa9e4066Sahrens dbufs_cb(uintptr_t addr, const void *unknown, void *arg)
727fa9e4066Sahrens {
728fa9e4066Sahrens 	dbufs_data_t *data = arg;
729fa9e4066Sahrens 	uintptr_t objset;
730fa9e4066Sahrens 	dmu_buf_t db;
731fa9e4066Sahrens 	uint8_t level;
732fa9e4066Sahrens 	uint64_t blkid;
7339adfa60dSMatthew Ahrens 	char osname[ZFS_MAX_DATASET_NAME_LEN];
734fa9e4066Sahrens 
735fa9e4066Sahrens 	if (GETMEMBID(addr, &data->id, db_objset, objset) ||
736fa9e4066Sahrens 	    GETMEMBID(addr, &data->id, db, db) ||
737fa9e4066Sahrens 	    GETMEMBID(addr, &data->id, db_level, level) ||
738fa9e4066Sahrens 	    GETMEMBID(addr, &data->id, db_blkid, blkid)) {
739fa9e4066Sahrens 		return (WALK_ERR);
740fa9e4066Sahrens 	}
741fa9e4066Sahrens 
742fa9e4066Sahrens 	if ((data->objset == DBUFS_UNSET || data->objset == objset) &&
743fa9e4066Sahrens 	    (data->osname == NULL || (objset_name(objset, osname) == 0 &&
744ccae0b50Seschrock 	    strcmp(data->osname, osname) == 0)) &&
745fa9e4066Sahrens 	    (data->object == DBUFS_UNSET || data->object == db.db_object) &&
746fa9e4066Sahrens 	    (data->level == DBUFS_UNSET || data->level == level) &&
747fa9e4066Sahrens 	    (data->blkid == DBUFS_UNSET || data->blkid == blkid)) {
748fa9e4066Sahrens 		mdb_printf("%#lr\n", addr);
749fa9e4066Sahrens 	}
750fa9e4066Sahrens 	return (WALK_NEXT);
751fa9e4066Sahrens }
752fa9e4066Sahrens 
753fa9e4066Sahrens /* ARGSUSED */
754fa9e4066Sahrens static int
755fa9e4066Sahrens dbufs(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
756fa9e4066Sahrens {
757fa9e4066Sahrens 	dbufs_data_t data;
758fa9e4066Sahrens 	char *object = NULL;
759fa9e4066Sahrens 	char *blkid = NULL;
760fa9e4066Sahrens 
761fa9e4066Sahrens 	data.objset = data.object = data.level = data.blkid = DBUFS_UNSET;
762fa9e4066Sahrens 	data.osname = NULL;
763fa9e4066Sahrens 
764fa9e4066Sahrens 	if (mdb_getopts(argc, argv,
765fa9e4066Sahrens 	    'O', MDB_OPT_UINT64, &data.objset,
766fa9e4066Sahrens 	    'n', MDB_OPT_STR, &data.osname,
767fa9e4066Sahrens 	    'o', MDB_OPT_STR, &object,
768fa9e4066Sahrens 	    'l', MDB_OPT_UINT64, &data.level,
769fa9e4066Sahrens 	    'b', MDB_OPT_STR, &blkid) != argc) {
770fa9e4066Sahrens 		return (DCMD_USAGE);
771fa9e4066Sahrens 	}
772fa9e4066Sahrens 
773fa9e4066Sahrens 	if (object) {
774fa9e4066Sahrens 		if (strcmp(object, "mdn") == 0) {
775fa9e4066Sahrens 			data.object = DMU_META_DNODE_OBJECT;
776fa9e4066Sahrens 		} else {
777fa9e4066Sahrens 			data.object = mdb_strtoull(object);
778fa9e4066Sahrens 		}
779fa9e4066Sahrens 	}
780fa9e4066Sahrens 
781fa9e4066Sahrens 	if (blkid) {
782fa9e4066Sahrens 		if (strcmp(blkid, "bonus") == 0) {
7830a586ceaSMark Shellenbaum 			data.blkid = DMU_BONUS_BLKID;
784fa9e4066Sahrens 		} else {
785fa9e4066Sahrens 			data.blkid = mdb_strtoull(blkid);
786fa9e4066Sahrens 		}
787fa9e4066Sahrens 	}
788fa9e4066Sahrens 
78928e4da25SMatthew Ahrens 	if (mdb_ctf_lookup_by_name(ZFS_STRUCT "dmu_buf_impl", &data.id) == -1) {
790fa9e4066Sahrens 		mdb_warn("couldn't find struct dmu_buf_impl_t");
791fa9e4066Sahrens 		return (DCMD_ERR);
792fa9e4066Sahrens 	}
793fa9e4066Sahrens 
7945f5f7a6fSahrens 	if (mdb_walk("dmu_buf_impl_t", dbufs_cb, &data) != 0) {
795fa9e4066Sahrens 		mdb_warn("can't walk dbufs");
796fa9e4066Sahrens 		return (DCMD_ERR);
797fa9e4066Sahrens 	}
798fa9e4066Sahrens 
799fa9e4066Sahrens 	return (DCMD_OK);
800fa9e4066Sahrens }
801fa9e4066Sahrens 
802fa9e4066Sahrens typedef struct abuf_find_data {
803fa9e4066Sahrens 	dva_t dva;
804fa9e4066Sahrens 	mdb_ctf_id_t id;
805fa9e4066Sahrens } abuf_find_data_t;
806fa9e4066Sahrens 
807fa9e4066Sahrens /* ARGSUSED */
808fa9e4066Sahrens static int
809fa9e4066Sahrens abuf_find_cb(uintptr_t addr, const void *unknown, void *arg)
810fa9e4066Sahrens {
811fa9e4066Sahrens 	abuf_find_data_t *data = arg;
812fa9e4066Sahrens 	dva_t dva;
813fa9e4066Sahrens 
814fa9e4066Sahrens 	if (GETMEMBID(addr, &data->id, b_dva, dva)) {
815fa9e4066Sahrens 		return (WALK_ERR);
816fa9e4066Sahrens 	}
817fa9e4066Sahrens 
818fa9e4066Sahrens 	if (dva.dva_word[0] == data->dva.dva_word[0] &&
819fa9e4066Sahrens 	    dva.dva_word[1] == data->dva.dva_word[1]) {
820fa9e4066Sahrens 		mdb_printf("%#lr\n", addr);
821fa9e4066Sahrens 	}
822fa9e4066Sahrens 	return (WALK_NEXT);
823fa9e4066Sahrens }
824fa9e4066Sahrens 
825fa9e4066Sahrens /* ARGSUSED */
826fa9e4066Sahrens static int
827fa9e4066Sahrens abuf_find(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
828fa9e4066Sahrens {
829fa9e4066Sahrens 	abuf_find_data_t data;
830fa9e4066Sahrens 	GElf_Sym sym;
831fa9e4066Sahrens 	int i;
832fa9e4066Sahrens 	const char *syms[] = {
833a2eea2e1Sahrens 		"ARC_mru",
834a2eea2e1Sahrens 		"ARC_mru_ghost",
835a2eea2e1Sahrens 		"ARC_mfu",
836a2eea2e1Sahrens 		"ARC_mfu_ghost",
837fa9e4066Sahrens 	};
838fa9e4066Sahrens 
839fa9e4066Sahrens 	if (argc != 2)
840fa9e4066Sahrens 		return (DCMD_USAGE);
841fa9e4066Sahrens 
842fa9e4066Sahrens 	for (i = 0; i < 2; i ++) {
843fa9e4066Sahrens 		switch (argv[i].a_type) {
844fa9e4066Sahrens 		case MDB_TYPE_STRING:
845fa9e4066Sahrens 			data.dva.dva_word[i] = mdb_strtoull(argv[i].a_un.a_str);
846fa9e4066Sahrens 			break;
847fa9e4066Sahrens 		case MDB_TYPE_IMMEDIATE:
848fa9e4066Sahrens 			data.dva.dva_word[i] = argv[i].a_un.a_val;
849fa9e4066Sahrens 			break;
850fa9e4066Sahrens 		default:
851fa9e4066Sahrens 			return (DCMD_USAGE);
852fa9e4066Sahrens 		}
853fa9e4066Sahrens 	}
854fa9e4066Sahrens 
85528e4da25SMatthew Ahrens 	if (mdb_ctf_lookup_by_name(ZFS_STRUCT "arc_buf_hdr", &data.id) == -1) {
856fa9e4066Sahrens 		mdb_warn("couldn't find struct arc_buf_hdr");
857fa9e4066Sahrens 		return (DCMD_ERR);
858fa9e4066Sahrens 	}
859fa9e4066Sahrens 
860fa9e4066Sahrens 	for (i = 0; i < sizeof (syms) / sizeof (syms[0]); i++) {
86122ce0148SMatthew Ahrens 		if (mdb_lookup_by_obj(ZFS_OBJ_NAME, syms[i], &sym)) {
862fa9e4066Sahrens 			mdb_warn("can't find symbol %s", syms[i]);
863fa9e4066Sahrens 			return (DCMD_ERR);
864fa9e4066Sahrens 		}
865fa9e4066Sahrens 
866fa9e4066Sahrens 		if (mdb_pwalk("list", abuf_find_cb, &data, sym.st_value) != 0) {
867fa9e4066Sahrens 			mdb_warn("can't walk %s", syms[i]);
868fa9e4066Sahrens 			return (DCMD_ERR);
869fa9e4066Sahrens 		}
870fa9e4066Sahrens 	}
871fa9e4066Sahrens 
872fa9e4066Sahrens 	return (DCMD_OK);
873fa9e4066Sahrens }
874fa9e4066Sahrens 
87528e4da25SMatthew Ahrens 
87628e4da25SMatthew Ahrens typedef struct dbgmsg_arg {
87728e4da25SMatthew Ahrens 	boolean_t da_verbose;
87828e4da25SMatthew Ahrens 	boolean_t da_address;
87928e4da25SMatthew Ahrens } dbgmsg_arg_t;
88028e4da25SMatthew Ahrens 
8813f9d6ad7SLin Ling /* ARGSUSED */
8823f9d6ad7SLin Ling static int
8833f9d6ad7SLin Ling dbgmsg_cb(uintptr_t addr, const void *unknown, void *arg)
8843f9d6ad7SLin Ling {
8853f9d6ad7SLin Ling 	static mdb_ctf_id_t id;
8863f9d6ad7SLin Ling 	static boolean_t gotid;
8873f9d6ad7SLin Ling 	static ulong_t off;
8883f9d6ad7SLin Ling 
88928e4da25SMatthew Ahrens 	dbgmsg_arg_t *da = arg;
8903f9d6ad7SLin Ling 	time_t timestamp;
8913f9d6ad7SLin Ling 	char buf[1024];
8923f9d6ad7SLin Ling 
8933f9d6ad7SLin Ling 	if (!gotid) {
89428e4da25SMatthew Ahrens 		if (mdb_ctf_lookup_by_name(ZFS_STRUCT "zfs_dbgmsg", &id) ==
89528e4da25SMatthew Ahrens 		    -1) {
8963f9d6ad7SLin Ling 			mdb_warn("couldn't find struct zfs_dbgmsg");
8973f9d6ad7SLin Ling 			return (WALK_ERR);
8983f9d6ad7SLin Ling 		}
8993f9d6ad7SLin Ling 		gotid = TRUE;
9003f9d6ad7SLin Ling 		if (mdb_ctf_offsetof(id, "zdm_msg", &off) == -1) {
9013f9d6ad7SLin Ling 			mdb_warn("couldn't find zdm_msg");
9023f9d6ad7SLin Ling 			return (WALK_ERR);
9033f9d6ad7SLin Ling 		}
9043f9d6ad7SLin Ling 		off /= 8;
9053f9d6ad7SLin Ling 	}
9063f9d6ad7SLin Ling 
9073f9d6ad7SLin Ling 
9083f9d6ad7SLin Ling 	if (GETMEMBID(addr, &id, zdm_timestamp, timestamp)) {
9093f9d6ad7SLin Ling 		return (WALK_ERR);
9103f9d6ad7SLin Ling 	}
9113f9d6ad7SLin Ling 
9123f9d6ad7SLin Ling 	if (mdb_readstr(buf, sizeof (buf), addr + off) == -1) {
9133f9d6ad7SLin Ling 		mdb_warn("failed to read zdm_msg at %p\n", addr + off);
9143f9d6ad7SLin Ling 		return (DCMD_ERR);
9153f9d6ad7SLin Ling 	}
9163f9d6ad7SLin Ling 
91728e4da25SMatthew Ahrens 	if (da->da_address)
91828e4da25SMatthew Ahrens 		mdb_printf("%p ", addr);
91928e4da25SMatthew Ahrens 	if (da->da_verbose)
9203f9d6ad7SLin Ling 		mdb_printf("%Y ", timestamp);
9213f9d6ad7SLin Ling 
9223f9d6ad7SLin Ling 	mdb_printf("%s\n", buf);
9233f9d6ad7SLin Ling 
92428e4da25SMatthew Ahrens 	if (da->da_verbose)
9253f9d6ad7SLin Ling 		(void) mdb_call_dcmd("whatis", addr, DCMD_ADDRSPEC, 0, NULL);
9263f9d6ad7SLin Ling 
9273f9d6ad7SLin Ling 	return (WALK_NEXT);
9283f9d6ad7SLin Ling }
9293f9d6ad7SLin Ling 
9303f9d6ad7SLin Ling /* ARGSUSED */
9313f9d6ad7SLin Ling static int
9323f9d6ad7SLin Ling dbgmsg(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
9333f9d6ad7SLin Ling {
9343f9d6ad7SLin Ling 	GElf_Sym sym;
93528e4da25SMatthew Ahrens 	dbgmsg_arg_t da = { 0 };
9363f9d6ad7SLin Ling 
9373f9d6ad7SLin Ling 	if (mdb_getopts(argc, argv,
93828e4da25SMatthew Ahrens 	    'v', MDB_OPT_SETBITS, B_TRUE, &da.da_verbose,
93928e4da25SMatthew Ahrens 	    'a', MDB_OPT_SETBITS, B_TRUE, &da.da_address,
9403f9d6ad7SLin Ling 	    NULL) != argc)
9413f9d6ad7SLin Ling 		return (DCMD_USAGE);
9423f9d6ad7SLin Ling 
9433b2aab18SMatthew Ahrens 	if (mdb_lookup_by_obj(ZFS_OBJ_NAME, "zfs_dbgmsgs", &sym)) {
9443f9d6ad7SLin Ling 		mdb_warn("can't find zfs_dbgmsgs");
9453f9d6ad7SLin Ling 		return (DCMD_ERR);
9463f9d6ad7SLin Ling 	}
9473f9d6ad7SLin Ling 
94828e4da25SMatthew Ahrens 	if (mdb_pwalk("list", dbgmsg_cb, &da, sym.st_value) != 0) {
9493f9d6ad7SLin Ling 		mdb_warn("can't walk zfs_dbgmsgs");
9503f9d6ad7SLin Ling 		return (DCMD_ERR);
9513f9d6ad7SLin Ling 	}
9523f9d6ad7SLin Ling 
9533f9d6ad7SLin Ling 	return (DCMD_OK);
9543f9d6ad7SLin Ling }
9553f9d6ad7SLin Ling 
95644cb6abcSbmc /*ARGSUSED*/
95744cb6abcSbmc static int
95844cb6abcSbmc arc_print(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
95944cb6abcSbmc {
96044cb6abcSbmc 	kstat_named_t *stats;
96144cb6abcSbmc 	GElf_Sym sym;
96291ebeef5Sahrens 	int nstats, i;
96344cb6abcSbmc 	uint_t opt_a = FALSE;
96491ebeef5Sahrens 	uint_t opt_b = FALSE;
96591ebeef5Sahrens 	uint_t shift = 0;
96691ebeef5Sahrens 	const char *suffix;
96744cb6abcSbmc 
96891ebeef5Sahrens 	static const char *bytestats[] = {
9699253d63dSGeorge Wilson 		"p", "c", "c_min", "c_max", "size", "duplicate_buffers_size",
97020128a08SGeorge Wilson 		"arc_meta_used", "arc_meta_limit", "arc_meta_max",
9714076b1bfSPrakash Surya 		"arc_meta_min", "hdr_size", "data_size", "metadata_size",
9724076b1bfSPrakash Surya 		"other_size", "anon_size", "anon_evictable_data",
9734076b1bfSPrakash Surya 		"anon_evictable_metadata", "mru_size", "mru_evictable_data",
9744076b1bfSPrakash Surya 		"mru_evictable_metadata", "mru_ghost_size",
9754076b1bfSPrakash Surya 		"mru_ghost_evictable_data", "mru_ghost_evictable_metadata",
9764076b1bfSPrakash Surya 		"mfu_size", "mfu_evictable_data", "mfu_evictable_metadata",
9774076b1bfSPrakash Surya 		"mfu_ghost_size", "mfu_ghost_evictable_data",
9784076b1bfSPrakash Surya 		"mfu_ghost_evictable_metadata", "evict_l2_cached",
9794076b1bfSPrakash Surya 		"evict_l2_eligible", "evict_l2_ineligible", "l2_read_bytes",
9804076b1bfSPrakash Surya 		"l2_write_bytes", "l2_size", "l2_asize", "l2_hdr_size",
981dcbf3bd6SGeorge Wilson 		"compressed_size", "uncompressed_size", "overhead_size",
9829253d63dSGeorge Wilson 		NULL
98391ebeef5Sahrens 	};
98491ebeef5Sahrens 
98591ebeef5Sahrens 	static const char *extras[] = {
98691ebeef5Sahrens 		"arc_no_grow", "arc_tempreserve",
98791ebeef5Sahrens 		NULL
98844cb6abcSbmc 	};
98944cb6abcSbmc 
99022ce0148SMatthew Ahrens 	if (mdb_lookup_by_obj(ZFS_OBJ_NAME, "arc_stats", &sym) == -1) {
99144cb6abcSbmc 		mdb_warn("failed to find 'arc_stats'");
99244cb6abcSbmc 		return (DCMD_ERR);
99344cb6abcSbmc 	}
99444cb6abcSbmc 
99544cb6abcSbmc 	stats = mdb_zalloc(sym.st_size, UM_SLEEP | UM_GC);
99644cb6abcSbmc 
99744cb6abcSbmc 	if (mdb_vread(stats, sym.st_size, sym.st_value) == -1) {
99844cb6abcSbmc 		mdb_warn("couldn't read 'arc_stats' at %p", sym.st_value);
99944cb6abcSbmc 		return (DCMD_ERR);
100044cb6abcSbmc 	}
100144cb6abcSbmc 
100244cb6abcSbmc 	nstats = sym.st_size / sizeof (kstat_named_t);
100344cb6abcSbmc 
100491ebeef5Sahrens 	/* NB: -a / opt_a are ignored for backwards compatability */
100591ebeef5Sahrens 	if (mdb_getopts(argc, argv,
100691ebeef5Sahrens 	    'a', MDB_OPT_SETBITS, TRUE, &opt_a,
100791ebeef5Sahrens 	    'b', MDB_OPT_SETBITS, TRUE, &opt_b,
100891ebeef5Sahrens 	    'k', MDB_OPT_SETBITS, 10, &shift,
100991ebeef5Sahrens 	    'm', MDB_OPT_SETBITS, 20, &shift,
101091ebeef5Sahrens 	    'g', MDB_OPT_SETBITS, 30, &shift,
101191ebeef5Sahrens 	    NULL) != argc)
101244cb6abcSbmc 		return (DCMD_USAGE);
101344cb6abcSbmc 
101491ebeef5Sahrens 	if (!opt_b && !shift)
101591ebeef5Sahrens 		shift = 20;
101691ebeef5Sahrens 
101791ebeef5Sahrens 	switch (shift) {
101891ebeef5Sahrens 	case 0:
101991ebeef5Sahrens 		suffix = "B";
102091ebeef5Sahrens 		break;
102191ebeef5Sahrens 	case 10:
102291ebeef5Sahrens 		suffix = "KB";
102391ebeef5Sahrens 		break;
102491ebeef5Sahrens 	case 20:
102591ebeef5Sahrens 		suffix = "MB";
102691ebeef5Sahrens 		break;
102791ebeef5Sahrens 	case 30:
102891ebeef5Sahrens 		suffix = "GB";
102991ebeef5Sahrens 		break;
103091ebeef5Sahrens 	default:
103191ebeef5Sahrens 		suffix = "XX";
103291ebeef5Sahrens 	}
103391ebeef5Sahrens 
103491ebeef5Sahrens 	for (i = 0; i < nstats; i++) {
103591ebeef5Sahrens 		int j;
103691ebeef5Sahrens 		boolean_t bytes = B_FALSE;
103791ebeef5Sahrens 
103891ebeef5Sahrens 		for (j = 0; bytestats[j]; j++) {
103991ebeef5Sahrens 			if (strcmp(stats[i].name, bytestats[j]) == 0) {
104091ebeef5Sahrens 				bytes = B_TRUE;
104191ebeef5Sahrens 				break;
104291ebeef5Sahrens 			}
104391ebeef5Sahrens 		}
104444cb6abcSbmc 
104591ebeef5Sahrens 		if (bytes) {
104691ebeef5Sahrens 			mdb_printf("%-25s = %9llu %s\n", stats[i].name,
104791ebeef5Sahrens 			    stats[i].value.ui64 >> shift, suffix);
104891ebeef5Sahrens 		} else {
104991ebeef5Sahrens 			mdb_printf("%-25s = %9llu\n", stats[i].name,
105044cb6abcSbmc 			    stats[i].value.ui64);
105144cb6abcSbmc 		}
105244cb6abcSbmc 	}
105344cb6abcSbmc 
105491ebeef5Sahrens 	for (i = 0; extras[i]; i++) {
105591ebeef5Sahrens 		uint64_t buf;
105644cb6abcSbmc 
105722ce0148SMatthew Ahrens 		if (mdb_lookup_by_obj(ZFS_OBJ_NAME, extras[i], &sym) == -1) {
105891ebeef5Sahrens 			mdb_warn("failed to find '%s'", extras[i]);
105991ebeef5Sahrens 			return (DCMD_ERR);
106044cb6abcSbmc 		}
106144cb6abcSbmc 
106291ebeef5Sahrens 		if (sym.st_size != sizeof (uint64_t) &&
106391ebeef5Sahrens 		    sym.st_size != sizeof (uint32_t)) {
106491ebeef5Sahrens 			mdb_warn("expected scalar for variable '%s'\n",
106591ebeef5Sahrens 			    extras[i]);
106691ebeef5Sahrens 			return (DCMD_ERR);
106744cb6abcSbmc 		}
106844cb6abcSbmc 
106991ebeef5Sahrens 		if (mdb_vread(&buf, sym.st_size, sym.st_value) == -1) {
107091ebeef5Sahrens 			mdb_warn("couldn't read '%s'", extras[i]);
107191ebeef5Sahrens 			return (DCMD_ERR);
107244cb6abcSbmc 		}
107344cb6abcSbmc 
107491ebeef5Sahrens 		mdb_printf("%-25s = ", extras[i]);
107591ebeef5Sahrens 
107691ebeef5Sahrens 		/* NB: all the 64-bit extras happen to be byte counts */
107791ebeef5Sahrens 		if (sym.st_size == sizeof (uint64_t))
107891ebeef5Sahrens 			mdb_printf("%9llu %s\n", buf >> shift, suffix);
107944cb6abcSbmc 
108091ebeef5Sahrens 		if (sym.st_size == sizeof (uint32_t))
108191ebeef5Sahrens 			mdb_printf("%9d\n", *((uint32_t *)&buf));
108291ebeef5Sahrens 	}
108344cb6abcSbmc 	return (DCMD_OK);
108444cb6abcSbmc }
108544cb6abcSbmc 
108622ce0148SMatthew Ahrens typedef struct mdb_spa_print {
108722ce0148SMatthew Ahrens 	pool_state_t spa_state;
10889adfa60dSMatthew Ahrens 	char spa_name[ZFS_MAX_DATASET_NAME_LEN];
108991e2a09fSSteve Gonczi 	uintptr_t spa_normal_class;
109022ce0148SMatthew Ahrens } mdb_spa_print_t;
109122ce0148SMatthew Ahrens 
109291e2a09fSSteve Gonczi 
109391e2a09fSSteve Gonczi const char histo_stars[] = "****************************************";
109491e2a09fSSteve Gonczi const int histo_width = sizeof (histo_stars) - 1;
109591e2a09fSSteve Gonczi 
109691e2a09fSSteve Gonczi static void
109791e2a09fSSteve Gonczi dump_histogram(const uint64_t *histo, int size, int offset)
109891e2a09fSSteve Gonczi {
109991e2a09fSSteve Gonczi 	int i;
110091e2a09fSSteve Gonczi 	int minidx = size - 1;
110191e2a09fSSteve Gonczi 	int maxidx = 0;
110291e2a09fSSteve Gonczi 	uint64_t max = 0;
110391e2a09fSSteve Gonczi 
110491e2a09fSSteve Gonczi 	for (i = 0; i < size; i++) {
110591e2a09fSSteve Gonczi 		if (histo[i] > max)
110691e2a09fSSteve Gonczi 			max = histo[i];
110791e2a09fSSteve Gonczi 		if (histo[i] > 0 && i > maxidx)
110891e2a09fSSteve Gonczi 			maxidx = i;
110991e2a09fSSteve Gonczi 		if (histo[i] > 0 && i < minidx)
111091e2a09fSSteve Gonczi 			minidx = i;
111191e2a09fSSteve Gonczi 	}
111291e2a09fSSteve Gonczi 
111391e2a09fSSteve Gonczi 	if (max < histo_width)
111491e2a09fSSteve Gonczi 		max = histo_width;
111591e2a09fSSteve Gonczi 
111691e2a09fSSteve Gonczi 	for (i = minidx; i <= maxidx; i++) {
111791e2a09fSSteve Gonczi 		mdb_printf("%3u: %6llu %s\n",
111891e2a09fSSteve Gonczi 		    i + offset, (u_longlong_t)histo[i],
111991e2a09fSSteve Gonczi 		    &histo_stars[(max - histo[i]) * histo_width / max]);
112091e2a09fSSteve Gonczi 	}
112191e2a09fSSteve Gonczi }
112291e2a09fSSteve Gonczi 
112391e2a09fSSteve Gonczi typedef struct mdb_metaslab_class {
112491e2a09fSSteve Gonczi 	uint64_t mc_histogram[RANGE_TREE_HISTOGRAM_SIZE];
112591e2a09fSSteve Gonczi } mdb_metaslab_class_t;
112691e2a09fSSteve Gonczi 
112791e2a09fSSteve Gonczi /*
112891e2a09fSSteve Gonczi  * spa_class_histogram(uintptr_t class_addr)
112991e2a09fSSteve Gonczi  *
113091e2a09fSSteve Gonczi  * Prints free space histogram for a device class
113191e2a09fSSteve Gonczi  *
113291e2a09fSSteve Gonczi  * Returns DCMD_OK, or DCMD_ERR.
113391e2a09fSSteve Gonczi  */
113491e2a09fSSteve Gonczi static int
113591e2a09fSSteve Gonczi spa_class_histogram(uintptr_t class_addr)
113691e2a09fSSteve Gonczi {
113791e2a09fSSteve Gonczi 	mdb_metaslab_class_t mc;
113891e2a09fSSteve Gonczi 	if (mdb_ctf_vread(&mc, "metaslab_class_t",
113991e2a09fSSteve Gonczi 	    "mdb_metaslab_class_t", class_addr, 0) == -1)
114091e2a09fSSteve Gonczi 		return (DCMD_ERR);
114191e2a09fSSteve Gonczi 
114291e2a09fSSteve Gonczi 	mdb_inc_indent(4);
114391e2a09fSSteve Gonczi 	dump_histogram(mc.mc_histogram, RANGE_TREE_HISTOGRAM_SIZE, 0);
114491e2a09fSSteve Gonczi 	mdb_dec_indent(4);
114591e2a09fSSteve Gonczi 	return (DCMD_OK);
114691e2a09fSSteve Gonczi }
114791e2a09fSSteve Gonczi 
1148fa9e4066Sahrens /*
1149fa9e4066Sahrens  * ::spa
1150fa9e4066Sahrens  *
115122ce0148SMatthew Ahrens  *	-c	Print configuration information as well
115222ce0148SMatthew Ahrens  *	-v	Print vdev state
115322ce0148SMatthew Ahrens  *	-e	Print vdev error stats
11542e4c9986SGeorge Wilson  *	-m	Print vdev metaslab info
11552e4c9986SGeorge Wilson  *	-M	print vdev metaslab group info
11562e4c9986SGeorge Wilson  *	-h	Print histogram info (must be combined with -m or -M)
1157fa9e4066Sahrens  *
1158fa9e4066Sahrens  * Print a summarized spa_t.  When given no arguments, prints out a table of all
1159fa9e4066Sahrens  * active pools on the system.
1160fa9e4066Sahrens  */
1161fa9e4066Sahrens /* ARGSUSED */
1162fa9e4066Sahrens static int
1163fa9e4066Sahrens spa_print(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1164fa9e4066Sahrens {
1165fa9e4066Sahrens 	const char *statetab[] = { "ACTIVE", "EXPORTED", "DESTROYED",
1166e14bb325SJeff Bonwick 		"SPARE", "L2CACHE", "UNINIT", "UNAVAIL", "POTENTIAL" };
1167fa9e4066Sahrens 	const char *state;
11682e4c9986SGeorge Wilson 	int spa_flags = 0;
1169fa9e4066Sahrens 
1170fa9e4066Sahrens 	if (mdb_getopts(argc, argv,
11712e4c9986SGeorge Wilson 	    'c', MDB_OPT_SETBITS, SPA_FLAG_CONFIG, &spa_flags,
11722e4c9986SGeorge Wilson 	    'v', MDB_OPT_SETBITS, SPA_FLAG_VDEVS, &spa_flags,
11732e4c9986SGeorge Wilson 	    'e', MDB_OPT_SETBITS, SPA_FLAG_ERRORS, &spa_flags,
11742e4c9986SGeorge Wilson 	    'M', MDB_OPT_SETBITS, SPA_FLAG_METASLAB_GROUPS, &spa_flags,
11752e4c9986SGeorge Wilson 	    'm', MDB_OPT_SETBITS, SPA_FLAG_METASLABS, &spa_flags,
11762e4c9986SGeorge Wilson 	    'h', MDB_OPT_SETBITS, SPA_FLAG_HISTOGRAMS, &spa_flags,
1177fa9e4066Sahrens 	    NULL) != argc)
1178fa9e4066Sahrens 		return (DCMD_USAGE);
1179fa9e4066Sahrens 
1180fa9e4066Sahrens 	if (!(flags & DCMD_ADDRSPEC)) {
1181fa9e4066Sahrens 		if (mdb_walk_dcmd("spa", "spa", argc, argv) == -1) {
1182fa9e4066Sahrens 			mdb_warn("can't walk spa");
1183fa9e4066Sahrens 			return (DCMD_ERR);
1184fa9e4066Sahrens 		}
1185fa9e4066Sahrens 
1186fa9e4066Sahrens 		return (DCMD_OK);
1187fa9e4066Sahrens 	}
1188fa9e4066Sahrens 
1189fa9e4066Sahrens 	if (flags & DCMD_PIPE_OUT) {
1190fa9e4066Sahrens 		mdb_printf("%#lr\n", addr);
1191fa9e4066Sahrens 		return (DCMD_OK);
1192fa9e4066Sahrens 	}
1193fa9e4066Sahrens 
1194fa9e4066Sahrens 	if (DCMD_HDRSPEC(flags))
1195fa9e4066Sahrens 		mdb_printf("%<u>%-?s %9s %-*s%</u>\n", "ADDR", "STATE",
1196fa9e4066Sahrens 		    sizeof (uintptr_t) == 4 ? 60 : 52, "NAME");
1197fa9e4066Sahrens 
119822ce0148SMatthew Ahrens 	mdb_spa_print_t spa;
119922ce0148SMatthew Ahrens 	if (mdb_ctf_vread(&spa, "spa_t", "mdb_spa_print_t", addr, 0) == -1)
1200fa9e4066Sahrens 		return (DCMD_ERR);
1201fa9e4066Sahrens 
1202fa9e4066Sahrens 	if (spa.spa_state < 0 || spa.spa_state > POOL_STATE_UNAVAIL)
1203ea8dc4b6Seschrock 		state = "UNKNOWN";
1204fa9e4066Sahrens 	else
1205fa9e4066Sahrens 		state = statetab[spa.spa_state];
1206fa9e4066Sahrens 
1207e14bb325SJeff Bonwick 	mdb_printf("%0?p %9s %s\n", addr, state, spa.spa_name);
120891e2a09fSSteve Gonczi 	if (spa_flags & SPA_FLAG_HISTOGRAMS)
120991e2a09fSSteve Gonczi 		spa_class_histogram(spa.spa_normal_class);
1210fa9e4066Sahrens 
12112e4c9986SGeorge Wilson 	if (spa_flags & SPA_FLAG_CONFIG) {
1212fa9e4066Sahrens 		mdb_printf("\n");
1213fa9e4066Sahrens 		mdb_inc_indent(4);
1214fa9e4066Sahrens 		if (mdb_call_dcmd("spa_config", addr, flags, 0,
1215fa9e4066Sahrens 		    NULL) != DCMD_OK)
1216fa9e4066Sahrens 			return (DCMD_ERR);
1217fa9e4066Sahrens 		mdb_dec_indent(4);
1218fa9e4066Sahrens 	}
1219fa9e4066Sahrens 
12202e4c9986SGeorge Wilson 	if (spa_flags & SPA_FLAG_ALL_VDEV) {
1221fa9e4066Sahrens 		mdb_arg_t v;
12222e4c9986SGeorge Wilson 		char opts[100] = "-";
12232e4c9986SGeorge Wilson 		int args =
12242e4c9986SGeorge Wilson 		    (spa_flags | SPA_FLAG_VDEVS) == SPA_FLAG_VDEVS ? 0 : 1;
12252e4c9986SGeorge Wilson 
12262e4c9986SGeorge Wilson 		if (spa_flags & SPA_FLAG_ERRORS)
12272e4c9986SGeorge Wilson 			strcat(opts, "e");
12282e4c9986SGeorge Wilson 		if (spa_flags & SPA_FLAG_METASLABS)
12292e4c9986SGeorge Wilson 			strcat(opts, "m");
12302e4c9986SGeorge Wilson 		if (spa_flags & SPA_FLAG_METASLAB_GROUPS)
12312e4c9986SGeorge Wilson 			strcat(opts, "M");
12322e4c9986SGeorge Wilson 		if (spa_flags & SPA_FLAG_HISTOGRAMS)
12332e4c9986SGeorge Wilson 			strcat(opts, "h");
1234fa9e4066Sahrens 
1235fa9e4066Sahrens 		v.a_type = MDB_TYPE_STRING;
12362e4c9986SGeorge Wilson 		v.a_un.a_str = opts;
1237fa9e4066Sahrens 
1238fa9e4066Sahrens 		mdb_printf("\n");
1239fa9e4066Sahrens 		mdb_inc_indent(4);
12402e4c9986SGeorge Wilson 		if (mdb_call_dcmd("spa_vdevs", addr, flags, args,
1241fa9e4066Sahrens 		    &v) != DCMD_OK)
1242fa9e4066Sahrens 			return (DCMD_ERR);
1243fa9e4066Sahrens 		mdb_dec_indent(4);
1244fa9e4066Sahrens 	}
1245fa9e4066Sahrens 
1246fa9e4066Sahrens 	return (DCMD_OK);
1247fa9e4066Sahrens }
1248fa9e4066Sahrens 
124928e4da25SMatthew Ahrens typedef struct mdb_spa_config_spa {
1250d5ee8a13SMatthew Ahrens 	uintptr_t spa_config;
125128e4da25SMatthew Ahrens } mdb_spa_config_spa_t;
125228e4da25SMatthew Ahrens 
1253fa9e4066Sahrens /*
1254fa9e4066Sahrens  * ::spa_config
1255fa9e4066Sahrens  *
1256fa9e4066Sahrens  * Given a spa_t, print the configuration information stored in spa_config.
1257fa9e4066Sahrens  * Since it's just an nvlist, format it as an indented list of name=value pairs.
1258fa9e4066Sahrens  * We simply read the value of spa_config and pass off to ::nvlist.
1259fa9e4066Sahrens  */
1260fa9e4066Sahrens /* ARGSUSED */
1261fa9e4066Sahrens static int
1262fa9e4066Sahrens spa_print_config(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1263fa9e4066Sahrens {
126428e4da25SMatthew Ahrens 	mdb_spa_config_spa_t spa;
1265fa9e4066Sahrens 
1266fa9e4066Sahrens 	if (argc != 0 || !(flags & DCMD_ADDRSPEC))
1267fa9e4066Sahrens 		return (DCMD_USAGE);
1268fa9e4066Sahrens 
126928e4da25SMatthew Ahrens 	if (mdb_ctf_vread(&spa, ZFS_STRUCT "spa", "mdb_spa_config_spa_t",
127028e4da25SMatthew Ahrens 	    addr, 0) == -1)
1271fa9e4066Sahrens 		return (DCMD_ERR);
1272fa9e4066Sahrens 
1273d5ee8a13SMatthew Ahrens 	if (spa.spa_config == 0) {
1274fa9e4066Sahrens 		mdb_printf("(none)\n");
1275fa9e4066Sahrens 		return (DCMD_OK);
1276fa9e4066Sahrens 	}
1277fa9e4066Sahrens 
1278d5ee8a13SMatthew Ahrens 	return (mdb_call_dcmd("nvlist", spa.spa_config, flags,
1279fa9e4066Sahrens 	    0, NULL));
1280fa9e4066Sahrens }
1281fa9e4066Sahrens 
12822e4c9986SGeorge Wilson 
12832e4c9986SGeorge Wilson 
12842e4c9986SGeorge Wilson typedef struct mdb_range_tree {
12852e4c9986SGeorge Wilson 	uint64_t rt_space;
12862e4c9986SGeorge Wilson } mdb_range_tree_t;
12872e4c9986SGeorge Wilson 
12882e4c9986SGeorge Wilson typedef struct mdb_metaslab_group {
12892e4c9986SGeorge Wilson 	uint64_t mg_fragmentation;
12902e4c9986SGeorge Wilson 	uint64_t mg_histogram[RANGE_TREE_HISTOGRAM_SIZE];
1291*8363e80aSGeorge Wilson 	uintptr_t mg_vd;
12922e4c9986SGeorge Wilson } mdb_metaslab_group_t;
12932e4c9986SGeorge Wilson 
12942e4c9986SGeorge Wilson typedef struct mdb_metaslab {
12952e4c9986SGeorge Wilson 	uint64_t ms_id;
12962e4c9986SGeorge Wilson 	uint64_t ms_start;
12972e4c9986SGeorge Wilson 	uint64_t ms_size;
1298*8363e80aSGeorge Wilson 	int64_t ms_deferspace;
12992e4c9986SGeorge Wilson 	uint64_t ms_fragmentation;
1300*8363e80aSGeorge Wilson 	uint64_t ms_weight;
13012e4c9986SGeorge Wilson 	uintptr_t ms_alloctree[TXG_SIZE];
13022e4c9986SGeorge Wilson 	uintptr_t ms_freetree[TXG_SIZE];
13032e4c9986SGeorge Wilson 	uintptr_t ms_tree;
13042e4c9986SGeorge Wilson 	uintptr_t ms_sm;
13052e4c9986SGeorge Wilson } mdb_metaslab_t;
13062e4c9986SGeorge Wilson 
13072e4c9986SGeorge Wilson typedef struct mdb_space_map_phys_t {
13082e4c9986SGeorge Wilson 	uint64_t smp_alloc;
13092e4c9986SGeorge Wilson 	uint64_t smp_histogram[SPACE_MAP_HISTOGRAM_SIZE];
13102e4c9986SGeorge Wilson } mdb_space_map_phys_t;
13112e4c9986SGeorge Wilson 
13122e4c9986SGeorge Wilson typedef struct mdb_space_map {
13132e4c9986SGeorge Wilson 	uint64_t sm_size;
13142e4c9986SGeorge Wilson 	uint8_t sm_shift;
13152e4c9986SGeorge Wilson 	uint64_t sm_alloc;
13162e4c9986SGeorge Wilson 	uintptr_t sm_phys;
13172e4c9986SGeorge Wilson } mdb_space_map_t;
13182e4c9986SGeorge Wilson 
13192e4c9986SGeorge Wilson typedef struct mdb_vdev {
1320*8363e80aSGeorge Wilson 	uintptr_t vdev_path;
13212e4c9986SGeorge Wilson 	uintptr_t vdev_ms;
1322*8363e80aSGeorge Wilson 	uintptr_t vdev_ops;
13232e4c9986SGeorge Wilson 	uint64_t vdev_ms_count;
1324*8363e80aSGeorge Wilson 	uint64_t vdev_id;
13252e4c9986SGeorge Wilson 	vdev_stat_t vdev_stat;
13262e4c9986SGeorge Wilson } mdb_vdev_t;
13272e4c9986SGeorge Wilson 
1328*8363e80aSGeorge Wilson typedef struct mdb_vdev_ops {
1329*8363e80aSGeorge Wilson 	char vdev_op_type[16];
1330*8363e80aSGeorge Wilson } mdb_vdev_ops_t;
1331*8363e80aSGeorge Wilson 
13322e4c9986SGeorge Wilson static int
13332e4c9986SGeorge Wilson metaslab_stats(uintptr_t addr, int spa_flags)
13342e4c9986SGeorge Wilson {
13352e4c9986SGeorge Wilson 	mdb_vdev_t vdev;
13362e4c9986SGeorge Wilson 	uintptr_t *vdev_ms;
13372e4c9986SGeorge Wilson 
13382e4c9986SGeorge Wilson 	if (mdb_ctf_vread(&vdev, "vdev_t", "mdb_vdev_t",
13392e4c9986SGeorge Wilson 	    (uintptr_t)addr, 0) == -1) {
13402e4c9986SGeorge Wilson 		mdb_warn("failed to read vdev at %p\n", addr);
13412e4c9986SGeorge Wilson 		return (DCMD_ERR);
13422e4c9986SGeorge Wilson 	}
13432e4c9986SGeorge Wilson 
13442e4c9986SGeorge Wilson 	mdb_inc_indent(4);
13452e4c9986SGeorge Wilson 	mdb_printf("%<u>%-?s %6s %20s %10s %9s%</u>\n", "ADDR", "ID",
13462e4c9986SGeorge Wilson 	    "OFFSET", "FREE", "FRAGMENTATION");
13472e4c9986SGeorge Wilson 
13482e4c9986SGeorge Wilson 	vdev_ms = mdb_alloc(vdev.vdev_ms_count * sizeof (void *),
13492e4c9986SGeorge Wilson 	    UM_SLEEP | UM_GC);
13502e4c9986SGeorge Wilson 	if (mdb_vread(vdev_ms, vdev.vdev_ms_count * sizeof (void *),
13512e4c9986SGeorge Wilson 	    (uintptr_t)vdev.vdev_ms) == -1) {
13522e4c9986SGeorge Wilson 		mdb_warn("failed to read vdev_ms at %p\n", vdev.vdev_ms);
13532e4c9986SGeorge Wilson 		return (DCMD_ERR);
13542e4c9986SGeorge Wilson 	}
13552e4c9986SGeorge Wilson 
13562e4c9986SGeorge Wilson 	for (int m = 0; m < vdev.vdev_ms_count; m++) {
13572e4c9986SGeorge Wilson 		mdb_metaslab_t ms;
13582e4c9986SGeorge Wilson 		mdb_space_map_t sm = { 0 };
13592e4c9986SGeorge Wilson 		char free[NICENUM_BUFLEN];
13602e4c9986SGeorge Wilson 
13612e4c9986SGeorge Wilson 		if (mdb_ctf_vread(&ms, "metaslab_t", "mdb_metaslab_t",
13622e4c9986SGeorge Wilson 		    (uintptr_t)vdev_ms[m], 0) == -1)
13632e4c9986SGeorge Wilson 			return (DCMD_ERR);
13642e4c9986SGeorge Wilson 
13652e4c9986SGeorge Wilson 		if (ms.ms_sm != NULL &&
13662e4c9986SGeorge Wilson 		    mdb_ctf_vread(&sm, "space_map_t", "mdb_space_map_t",
13672e4c9986SGeorge Wilson 		    ms.ms_sm, 0) == -1)
13682e4c9986SGeorge Wilson 			return (DCMD_ERR);
13692e4c9986SGeorge Wilson 
13702e4c9986SGeorge Wilson 		mdb_nicenum(ms.ms_size - sm.sm_alloc, free);
13712e4c9986SGeorge Wilson 
13722e4c9986SGeorge Wilson 		mdb_printf("%0?p %6llu %20llx %10s ", vdev_ms[m], ms.ms_id,
13732e4c9986SGeorge Wilson 		    ms.ms_start, free);
13742e4c9986SGeorge Wilson 		if (ms.ms_fragmentation == ZFS_FRAG_INVALID)
13752e4c9986SGeorge Wilson 			mdb_printf("%9s\n", "-");
13762e4c9986SGeorge Wilson 		else
13772e4c9986SGeorge Wilson 			mdb_printf("%9llu%%\n", ms.ms_fragmentation);
13782e4c9986SGeorge Wilson 
13792e4c9986SGeorge Wilson 		if ((spa_flags & SPA_FLAG_HISTOGRAMS) && ms.ms_sm != NULL) {
13802e4c9986SGeorge Wilson 			mdb_space_map_phys_t smp;
13812e4c9986SGeorge Wilson 
13822e4c9986SGeorge Wilson 			if (sm.sm_phys == NULL)
13832e4c9986SGeorge Wilson 				continue;
13842e4c9986SGeorge Wilson 
13852e4c9986SGeorge Wilson 			(void) mdb_ctf_vread(&smp, "space_map_phys_t",
13862e4c9986SGeorge Wilson 			    "mdb_space_map_phys_t", sm.sm_phys, 0);
13872e4c9986SGeorge Wilson 
13882e4c9986SGeorge Wilson 			dump_histogram(smp.smp_histogram,
13892e4c9986SGeorge Wilson 			    SPACE_MAP_HISTOGRAM_SIZE, sm.sm_shift);
13902e4c9986SGeorge Wilson 		}
13912e4c9986SGeorge Wilson 	}
13922e4c9986SGeorge Wilson 	mdb_dec_indent(4);
13932e4c9986SGeorge Wilson 	return (DCMD_OK);
13942e4c9986SGeorge Wilson }
13952e4c9986SGeorge Wilson 
13962e4c9986SGeorge Wilson static int
13972e4c9986SGeorge Wilson metaslab_group_stats(uintptr_t addr, int spa_flags)
13982e4c9986SGeorge Wilson {
13992e4c9986SGeorge Wilson 	mdb_metaslab_group_t mg;
14002e4c9986SGeorge Wilson 	if (mdb_ctf_vread(&mg, "metaslab_group_t", "mdb_metaslab_group_t",
14012e4c9986SGeorge Wilson 	    (uintptr_t)addr, 0) == -1) {
14022e4c9986SGeorge Wilson 		mdb_warn("failed to read vdev_mg at %p\n", addr);
14032e4c9986SGeorge Wilson 		return (DCMD_ERR);
14042e4c9986SGeorge Wilson 	}
14052e4c9986SGeorge Wilson 
14062e4c9986SGeorge Wilson 	mdb_inc_indent(4);
14072e4c9986SGeorge Wilson 	mdb_printf("%<u>%-?s %15s%</u>\n", "ADDR", "FRAGMENTATION");
14082e4c9986SGeorge Wilson 	if (mg.mg_fragmentation == ZFS_FRAG_INVALID)
14092e4c9986SGeorge Wilson 		mdb_printf("%0?p %15s\n", addr, "-");
14102e4c9986SGeorge Wilson 	else
14112e4c9986SGeorge Wilson 		mdb_printf("%0?p %15llu%%\n", addr, mg.mg_fragmentation);
14122e4c9986SGeorge Wilson 
14132e4c9986SGeorge Wilson 	if (spa_flags & SPA_FLAG_HISTOGRAMS)
14142e4c9986SGeorge Wilson 		dump_histogram(mg.mg_histogram, RANGE_TREE_HISTOGRAM_SIZE, 0);
14152e4c9986SGeorge Wilson 	mdb_dec_indent(4);
14162e4c9986SGeorge Wilson 	return (DCMD_OK);
14172e4c9986SGeorge Wilson }
14182e4c9986SGeorge Wilson 
1419fa9e4066Sahrens /*
1420fa9e4066Sahrens  * ::vdev
1421fa9e4066Sahrens  *
1422fa9e4066Sahrens  * Print out a summarized vdev_t, in the following form:
1423fa9e4066Sahrens  *
1424fa9e4066Sahrens  * ADDR             STATE	AUX            DESC
1425fa9e4066Sahrens  * fffffffbcde23df0 HEALTHY	-              /dev/dsk/c0t0d0
1426fa9e4066Sahrens  *
1427fa9e4066Sahrens  * If '-r' is specified, recursively visit all children.
1428fa9e4066Sahrens  *
1429fa9e4066Sahrens  * With '-e', the statistics associated with the vdev are printed as well.
1430fa9e4066Sahrens  */
1431fa9e4066Sahrens static int
14322e4c9986SGeorge Wilson do_print_vdev(uintptr_t addr, int flags, int depth, boolean_t recursive,
14332e4c9986SGeorge Wilson     int spa_flags)
1434fa9e4066Sahrens {
1435fa9e4066Sahrens 	vdev_t vdev;
1436fa9e4066Sahrens 	char desc[MAXNAMELEN];
1437fa9e4066Sahrens 	int c, children;
1438fa9e4066Sahrens 	uintptr_t *child;
1439fa9e4066Sahrens 	const char *state, *aux;
1440fa9e4066Sahrens 
1441fa9e4066Sahrens 	if (mdb_vread(&vdev, sizeof (vdev), (uintptr_t)addr) == -1) {
1442fa9e4066Sahrens 		mdb_warn("failed to read vdev_t at %p\n", (uintptr_t)addr);
1443fa9e4066Sahrens 		return (DCMD_ERR);
1444fa9e4066Sahrens 	}
1445fa9e4066Sahrens 
1446fa9e4066Sahrens 	if (flags & DCMD_PIPE_OUT) {
1447b4952e17SGeorge Wilson 		mdb_printf("%#lr\n", addr);
1448fa9e4066Sahrens 	} else {
1449fa9e4066Sahrens 		if (vdev.vdev_path != NULL) {
1450fa9e4066Sahrens 			if (mdb_readstr(desc, sizeof (desc),
1451fa9e4066Sahrens 			    (uintptr_t)vdev.vdev_path) == -1) {
1452fa9e4066Sahrens 				mdb_warn("failed to read vdev_path at %p\n",
1453fa9e4066Sahrens 				    vdev.vdev_path);
1454fa9e4066Sahrens 				return (DCMD_ERR);
1455fa9e4066Sahrens 			}
1456fa9e4066Sahrens 		} else if (vdev.vdev_ops != NULL) {
1457fa9e4066Sahrens 			vdev_ops_t ops;
1458fa9e4066Sahrens 			if (mdb_vread(&ops, sizeof (ops),
1459fa9e4066Sahrens 			    (uintptr_t)vdev.vdev_ops) == -1) {
1460fa9e4066Sahrens 				mdb_warn("failed to read vdev_ops at %p\n",
1461fa9e4066Sahrens 				    vdev.vdev_ops);
1462fa9e4066Sahrens 				return (DCMD_ERR);
1463fa9e4066Sahrens 			}
1464fa9e4066Sahrens 			(void) strcpy(desc, ops.vdev_op_type);
1465fa9e4066Sahrens 		} else {
1466fa9e4066Sahrens 			(void) strcpy(desc, "<unknown>");
1467fa9e4066Sahrens 		}
1468fa9e4066Sahrens 
1469fa9e4066Sahrens 		if (depth == 0 && DCMD_HDRSPEC(flags))
1470fa9e4066Sahrens 			mdb_printf("%<u>%-?s %-9s %-12s %-*s%</u>\n",
1471fa9e4066Sahrens 			    "ADDR", "STATE", "AUX",
1472fa9e4066Sahrens 			    sizeof (uintptr_t) == 4 ? 43 : 35,
1473fa9e4066Sahrens 			    "DESCRIPTION");
1474fa9e4066Sahrens 
1475fa9e4066Sahrens 		mdb_printf("%0?p ", addr);
1476fa9e4066Sahrens 
1477fa9e4066Sahrens 		switch (vdev.vdev_state) {
1478fa9e4066Sahrens 		case VDEV_STATE_CLOSED:
1479ccae0b50Seschrock 			state = "CLOSED";
1480ccae0b50Seschrock 			break;
1481fa9e4066Sahrens 		case VDEV_STATE_OFFLINE:
1482ccae0b50Seschrock 			state = "OFFLINE";
1483ccae0b50Seschrock 			break;
1484fa9e4066Sahrens 		case VDEV_STATE_CANT_OPEN:
1485ccae0b50Seschrock 			state = "CANT_OPEN";
1486ccae0b50Seschrock 			break;
1487fa9e4066Sahrens 		case VDEV_STATE_DEGRADED:
1488ccae0b50Seschrock 			state = "DEGRADED";
1489ccae0b50Seschrock 			break;
1490fa9e4066Sahrens 		case VDEV_STATE_HEALTHY:
1491ccae0b50Seschrock 			state = "HEALTHY";
1492ccae0b50Seschrock 			break;
14933d7072f8Seschrock 		case VDEV_STATE_REMOVED:
14943d7072f8Seschrock 			state = "REMOVED";
14953d7072f8Seschrock 			break;
14963d7072f8Seschrock 		case VDEV_STATE_FAULTED:
14973d7072f8Seschrock 			state = "FAULTED";
14983d7072f8Seschrock 			break;
1499fa9e4066Sahrens 		default:
1500ccae0b50Seschrock 			state = "UNKNOWN";
1501ccae0b50Seschrock 			break;
1502fa9e4066Sahrens 		}
1503fa9e4066Sahrens 
1504fa9e4066Sahrens 		switch (vdev.vdev_stat.vs_aux) {
1505fa9e4066Sahrens 		case VDEV_AUX_NONE:
1506fa9e4066Sahrens 			aux = "-";
1507fa9e4066Sahrens 			break;
1508fa9e4066Sahrens 		case VDEV_AUX_OPEN_FAILED:
1509fa9e4066Sahrens 			aux = "OPEN_FAILED";
1510fa9e4066Sahrens 			break;
1511fa9e4066Sahrens 		case VDEV_AUX_CORRUPT_DATA:
1512fa9e4066Sahrens 			aux = "CORRUPT_DATA";
1513fa9e4066Sahrens 			break;
1514fa9e4066Sahrens 		case VDEV_AUX_NO_REPLICAS:
1515fa9e4066Sahrens 			aux = "NO_REPLICAS";
1516fa9e4066Sahrens 			break;
1517fa9e4066Sahrens 		case VDEV_AUX_BAD_GUID_SUM:
1518fa9e4066Sahrens 			aux = "BAD_GUID_SUM";
1519fa9e4066Sahrens 			break;
1520fa9e4066Sahrens 		case VDEV_AUX_TOO_SMALL:
1521fa9e4066Sahrens 			aux = "TOO_SMALL";
1522fa9e4066Sahrens 			break;
1523fa9e4066Sahrens 		case VDEV_AUX_BAD_LABEL:
1524fa9e4066Sahrens 			aux = "BAD_LABEL";
1525fa9e4066Sahrens 			break;
1526b87f3af3Sperrin 		case VDEV_AUX_VERSION_NEWER:
1527b87f3af3Sperrin 			aux = "VERS_NEWER";
1528b87f3af3Sperrin 			break;
1529b87f3af3Sperrin 		case VDEV_AUX_VERSION_OLDER:
1530b87f3af3Sperrin 			aux = "VERS_OLDER";
1531b87f3af3Sperrin 			break;
1532ad135b5dSChristopher Siden 		case VDEV_AUX_UNSUP_FEAT:
1533ad135b5dSChristopher Siden 			aux = "UNSUP_FEAT";
1534ad135b5dSChristopher Siden 			break;
1535b87f3af3Sperrin 		case VDEV_AUX_SPARED:
1536b87f3af3Sperrin 			aux = "SPARED";
1537b87f3af3Sperrin 			break;
1538b87f3af3Sperrin 		case VDEV_AUX_ERR_EXCEEDED:
1539b87f3af3Sperrin 			aux = "ERR_EXCEEDED";
1540b87f3af3Sperrin 			break;
1541b87f3af3Sperrin 		case VDEV_AUX_IO_FAILURE:
1542b87f3af3Sperrin 			aux = "IO_FAILURE";
1543b87f3af3Sperrin 			break;
1544b87f3af3Sperrin 		case VDEV_AUX_BAD_LOG:
1545b87f3af3Sperrin 			aux = "BAD_LOG";
1546b87f3af3Sperrin 			break;
15471195e687SMark J Musante 		case VDEV_AUX_EXTERNAL:
15481195e687SMark J Musante 			aux = "EXTERNAL";
15491195e687SMark J Musante 			break;
15501195e687SMark J Musante 		case VDEV_AUX_SPLIT_POOL:
15511195e687SMark J Musante 			aux = "SPLIT_POOL";
15521195e687SMark J Musante 			break;
1553fa9e4066Sahrens 		default:
1554fa9e4066Sahrens 			aux = "UNKNOWN";
1555fa9e4066Sahrens 			break;
1556fa9e4066Sahrens 		}
1557fa9e4066Sahrens 
1558fa9e4066Sahrens 		mdb_printf("%-9s %-12s %*s%s\n", state, aux, depth, "", desc);
1559fa9e4066Sahrens 
15602e4c9986SGeorge Wilson 		if (spa_flags & SPA_FLAG_ERRORS) {
1561fa9e4066Sahrens 			vdev_stat_t *vs = &vdev.vdev_stat;
1562fa9e4066Sahrens 			int i;
1563fa9e4066Sahrens 
1564fa9e4066Sahrens 			mdb_inc_indent(4);
1565fa9e4066Sahrens 			mdb_printf("\n");
1566fa9e4066Sahrens 			mdb_printf("%<u>       %12s %12s %12s %12s "
1567fa9e4066Sahrens 			    "%12s%</u>\n", "READ", "WRITE", "FREE", "CLAIM",
1568fa9e4066Sahrens 			    "IOCTL");
1569fa9e4066Sahrens 			mdb_printf("OPS     ");
1570fa9e4066Sahrens 			for (i = 1; i < ZIO_TYPES; i++)
1571fa9e4066Sahrens 				mdb_printf("%11#llx%s", vs->vs_ops[i],
1572fa9e4066Sahrens 				    i == ZIO_TYPES - 1 ? "" : "  ");
1573fa9e4066Sahrens 			mdb_printf("\n");
1574fa9e4066Sahrens 			mdb_printf("BYTES   ");
1575fa9e4066Sahrens 			for (i = 1; i < ZIO_TYPES; i++)
1576fa9e4066Sahrens 				mdb_printf("%11#llx%s", vs->vs_bytes[i],
1577fa9e4066Sahrens 				    i == ZIO_TYPES - 1 ? "" : "  ");
1578fa9e4066Sahrens 
1579fa9e4066Sahrens 
1580fa9e4066Sahrens 			mdb_printf("\n");
1581fa9e4066Sahrens 			mdb_printf("EREAD    %10#llx\n", vs->vs_read_errors);
1582fa9e4066Sahrens 			mdb_printf("EWRITE   %10#llx\n", vs->vs_write_errors);
1583fa9e4066Sahrens 			mdb_printf("ECKSUM   %10#llx\n",
1584fa9e4066Sahrens 			    vs->vs_checksum_errors);
1585fa9e4066Sahrens 			mdb_dec_indent(4);
15862e4c9986SGeorge Wilson 			mdb_printf("\n");
1587fa9e4066Sahrens 		}
1588fa9e4066Sahrens 
15892e4c9986SGeorge Wilson 		if (spa_flags & SPA_FLAG_METASLAB_GROUPS &&
15902e4c9986SGeorge Wilson 		    vdev.vdev_mg != NULL) {
15912e4c9986SGeorge Wilson 			metaslab_group_stats((uintptr_t)vdev.vdev_mg,
15922e4c9986SGeorge Wilson 			    spa_flags);
15932e4c9986SGeorge Wilson 		}
15942e4c9986SGeorge Wilson 		if (spa_flags & SPA_FLAG_METASLABS && vdev.vdev_ms != NULL) {
15952e4c9986SGeorge Wilson 			metaslab_stats((uintptr_t)addr, spa_flags);
15962e4c9986SGeorge Wilson 		}
1597fa9e4066Sahrens 	}
1598fa9e4066Sahrens 
1599fa9e4066Sahrens 	children = vdev.vdev_children;
1600fa9e4066Sahrens 
1601fa9e4066Sahrens 	if (children == 0 || !recursive)
1602fa9e4066Sahrens 		return (DCMD_OK);
1603fa9e4066Sahrens 
1604fa9e4066Sahrens 	child = mdb_alloc(children * sizeof (void *), UM_SLEEP | UM_GC);
1605fa9e4066Sahrens 	if (mdb_vread(child, children * sizeof (void *),
1606fa9e4066Sahrens 	    (uintptr_t)vdev.vdev_child) == -1) {
1607fa9e4066Sahrens 		mdb_warn("failed to read vdev children at %p", vdev.vdev_child);
1608fa9e4066Sahrens 		return (DCMD_ERR);
1609fa9e4066Sahrens 	}
1610fa9e4066Sahrens 
1611fa9e4066Sahrens 	for (c = 0; c < children; c++) {
16122e4c9986SGeorge Wilson 		if (do_print_vdev(child[c], flags, depth + 2, recursive,
16132e4c9986SGeorge Wilson 		    spa_flags)) {
1614fa9e4066Sahrens 			return (DCMD_ERR);
16152e4c9986SGeorge Wilson 		}
1616fa9e4066Sahrens 	}
1617fa9e4066Sahrens 
1618fa9e4066Sahrens 	return (DCMD_OK);
1619fa9e4066Sahrens }
1620fa9e4066Sahrens 
1621fa9e4066Sahrens static int
1622fa9e4066Sahrens vdev_print(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1623fa9e4066Sahrens {
1624c5904d13Seschrock 	uint64_t depth = 0;
16252e4c9986SGeorge Wilson 	boolean_t recursive = B_FALSE;
16262e4c9986SGeorge Wilson 	int spa_flags = 0;
1627fa9e4066Sahrens 
1628fa9e4066Sahrens 	if (mdb_getopts(argc, argv,
16292e4c9986SGeorge Wilson 	    'e', MDB_OPT_SETBITS, SPA_FLAG_ERRORS, &spa_flags,
16302e4c9986SGeorge Wilson 	    'm', MDB_OPT_SETBITS, SPA_FLAG_METASLABS, &spa_flags,
16312e4c9986SGeorge Wilson 	    'M', MDB_OPT_SETBITS, SPA_FLAG_METASLAB_GROUPS, &spa_flags,
16322e4c9986SGeorge Wilson 	    'h', MDB_OPT_SETBITS, SPA_FLAG_HISTOGRAMS, &spa_flags,
1633fa9e4066Sahrens 	    'r', MDB_OPT_SETBITS, TRUE, &recursive,
16342e4c9986SGeorge Wilson 	    'd', MDB_OPT_UINT64, &depth, NULL) != argc)
1635fa9e4066Sahrens 		return (DCMD_USAGE);
1636fa9e4066Sahrens 
1637fa9e4066Sahrens 	if (!(flags & DCMD_ADDRSPEC)) {
1638fa9e4066Sahrens 		mdb_warn("no vdev_t address given\n");
1639fa9e4066Sahrens 		return (DCMD_ERR);
1640fa9e4066Sahrens 	}
1641fa9e4066Sahrens 
16422e4c9986SGeorge Wilson 	return (do_print_vdev(addr, flags, (int)depth, recursive, spa_flags));
1643fa9e4066Sahrens }
1644fa9e4066Sahrens 
1645*8363e80aSGeorge Wilson typedef struct mdb_metaslab_alloc_trace {
1646*8363e80aSGeorge Wilson 	uintptr_t mat_mg;
1647*8363e80aSGeorge Wilson 	uintptr_t mat_msp;
1648*8363e80aSGeorge Wilson 	uint64_t mat_size;
1649*8363e80aSGeorge Wilson 	uint64_t mat_weight;
1650*8363e80aSGeorge Wilson 	uint64_t mat_offset;
1651*8363e80aSGeorge Wilson 	uint32_t mat_dva_id;
1652*8363e80aSGeorge Wilson } mdb_metaslab_alloc_trace_t;
1653*8363e80aSGeorge Wilson 
1654*8363e80aSGeorge Wilson static void
1655*8363e80aSGeorge Wilson metaslab_print_weight(uint64_t weight)
1656*8363e80aSGeorge Wilson {
1657*8363e80aSGeorge Wilson 	char buf[100];
1658*8363e80aSGeorge Wilson 
1659*8363e80aSGeorge Wilson 	if (WEIGHT_IS_SPACEBASED(weight)) {
1660*8363e80aSGeorge Wilson 		mdb_nicenum(
1661*8363e80aSGeorge Wilson 		    weight & ~(METASLAB_ACTIVE_MASK | METASLAB_WEIGHT_TYPE),
1662*8363e80aSGeorge Wilson 		    buf);
1663*8363e80aSGeorge Wilson 	} else {
1664*8363e80aSGeorge Wilson 		char size[NICENUM_BUFLEN];
1665*8363e80aSGeorge Wilson 		mdb_nicenum(1ULL << WEIGHT_GET_INDEX(weight), size);
1666*8363e80aSGeorge Wilson 		(void) mdb_snprintf(buf, sizeof (buf), "%llu x %s",
1667*8363e80aSGeorge Wilson 		    WEIGHT_GET_COUNT(weight), size);
1668*8363e80aSGeorge Wilson 	}
1669*8363e80aSGeorge Wilson 	mdb_printf("%11s ", buf);
1670*8363e80aSGeorge Wilson }
1671*8363e80aSGeorge Wilson 
1672*8363e80aSGeorge Wilson /* ARGSUSED */
1673*8363e80aSGeorge Wilson static int
1674*8363e80aSGeorge Wilson metaslab_weight(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1675*8363e80aSGeorge Wilson {
1676*8363e80aSGeorge Wilson 	uint64_t weight = 0;
1677*8363e80aSGeorge Wilson 	char active;
1678*8363e80aSGeorge Wilson 
1679*8363e80aSGeorge Wilson 	if (argc == 0 && (flags & DCMD_ADDRSPEC)) {
1680*8363e80aSGeorge Wilson 		if (mdb_vread(&weight, sizeof (uint64_t), addr) == -1) {
1681*8363e80aSGeorge Wilson 			mdb_warn("failed to read weight at %p\n", addr);
1682*8363e80aSGeorge Wilson 			return (DCMD_ERR);
1683*8363e80aSGeorge Wilson 		}
1684*8363e80aSGeorge Wilson 	} else if (argc == 1 && !(flags & DCMD_ADDRSPEC)) {
1685*8363e80aSGeorge Wilson 		weight = (argv[0].a_type == MDB_TYPE_IMMEDIATE) ?
1686*8363e80aSGeorge Wilson 		    argv[0].a_un.a_val : mdb_strtoull(argv[0].a_un.a_str);
1687*8363e80aSGeorge Wilson 	} else {
1688*8363e80aSGeorge Wilson 		return (DCMD_USAGE);
1689*8363e80aSGeorge Wilson 	}
1690*8363e80aSGeorge Wilson 
1691*8363e80aSGeorge Wilson 	if (DCMD_HDRSPEC(flags)) {
1692*8363e80aSGeorge Wilson 		mdb_printf("%<u>%-6s %9s %9s%</u>\n",
1693*8363e80aSGeorge Wilson 		    "ACTIVE", "ALGORITHM", "WEIGHT");
1694*8363e80aSGeorge Wilson 	}
1695*8363e80aSGeorge Wilson 
1696*8363e80aSGeorge Wilson 	if (weight & METASLAB_WEIGHT_PRIMARY)
1697*8363e80aSGeorge Wilson 		active = 'P';
1698*8363e80aSGeorge Wilson 	else if (weight & METASLAB_WEIGHT_SECONDARY)
1699*8363e80aSGeorge Wilson 		active = 'S';
1700*8363e80aSGeorge Wilson 	else
1701*8363e80aSGeorge Wilson 		active = '-';
1702*8363e80aSGeorge Wilson 	mdb_printf("%6c %8s ", active,
1703*8363e80aSGeorge Wilson 	    WEIGHT_IS_SPACEBASED(weight) ? "SPACE" : "SEGMENT");
1704*8363e80aSGeorge Wilson 	metaslab_print_weight(weight);
1705*8363e80aSGeorge Wilson 	mdb_printf("\n");
1706*8363e80aSGeorge Wilson 
1707*8363e80aSGeorge Wilson 	return (DCMD_OK);
1708*8363e80aSGeorge Wilson }
1709*8363e80aSGeorge Wilson 
1710*8363e80aSGeorge Wilson /* ARGSUSED */
1711*8363e80aSGeorge Wilson static int
1712*8363e80aSGeorge Wilson metaslab_trace(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1713*8363e80aSGeorge Wilson {
1714*8363e80aSGeorge Wilson 	mdb_metaslab_alloc_trace_t mat;
1715*8363e80aSGeorge Wilson 	mdb_metaslab_group_t mg = { 0 };
1716*8363e80aSGeorge Wilson 	char result_type[100];
1717*8363e80aSGeorge Wilson 
1718*8363e80aSGeorge Wilson 	if (mdb_ctf_vread(&mat, "metaslab_alloc_trace_t",
1719*8363e80aSGeorge Wilson 	    "mdb_metaslab_alloc_trace_t", addr, 0) == -1) {
1720*8363e80aSGeorge Wilson 		return (DCMD_ERR);
1721*8363e80aSGeorge Wilson 	}
1722*8363e80aSGeorge Wilson 
1723*8363e80aSGeorge Wilson 	if (!(flags & DCMD_PIPE_OUT) && DCMD_HDRSPEC(flags)) {
1724*8363e80aSGeorge Wilson 		mdb_printf("%<u>%6s %6s %8s %11s %18s %18s%</u>\n",
1725*8363e80aSGeorge Wilson 		    "MSID", "DVA", "ASIZE", "WEIGHT", "RESULT", "VDEV");
1726*8363e80aSGeorge Wilson 	}
1727*8363e80aSGeorge Wilson 
1728*8363e80aSGeorge Wilson 	if (mat.mat_msp != NULL) {
1729*8363e80aSGeorge Wilson 		mdb_metaslab_t ms;
1730*8363e80aSGeorge Wilson 
1731*8363e80aSGeorge Wilson 		if (mdb_ctf_vread(&ms, "metaslab_t", "mdb_metaslab_t",
1732*8363e80aSGeorge Wilson 		    mat.mat_msp, 0) == -1) {
1733*8363e80aSGeorge Wilson 			return (DCMD_ERR);
1734*8363e80aSGeorge Wilson 		}
1735*8363e80aSGeorge Wilson 		mdb_printf("%6llu ", ms.ms_id);
1736*8363e80aSGeorge Wilson 	} else {
1737*8363e80aSGeorge Wilson 		mdb_printf("%6s ", "-");
1738*8363e80aSGeorge Wilson 	}
1739*8363e80aSGeorge Wilson 
1740*8363e80aSGeorge Wilson 	mdb_printf("%6d %8llx ", mat.mat_dva_id, mat.mat_size);
1741*8363e80aSGeorge Wilson 
1742*8363e80aSGeorge Wilson 	metaslab_print_weight(mat.mat_weight);
1743*8363e80aSGeorge Wilson 
1744*8363e80aSGeorge Wilson 	if ((int64_t)mat.mat_offset < 0) {
1745*8363e80aSGeorge Wilson 		if (enum_lookup("enum trace_alloc_type", mat.mat_offset,
1746*8363e80aSGeorge Wilson 		    "TRACE_", sizeof (result_type), result_type) == -1) {
1747*8363e80aSGeorge Wilson 			mdb_warn("Could not find enum for trace_alloc_type");
1748*8363e80aSGeorge Wilson 			return (DCMD_ERR);
1749*8363e80aSGeorge Wilson 		}
1750*8363e80aSGeorge Wilson 		mdb_printf("%18s ", result_type);
1751*8363e80aSGeorge Wilson 	} else {
1752*8363e80aSGeorge Wilson 		mdb_printf("%<b>%18llx%</b> ", mat.mat_offset);
1753*8363e80aSGeorge Wilson 	}
1754*8363e80aSGeorge Wilson 
1755*8363e80aSGeorge Wilson 	if (mat.mat_mg != NULL &&
1756*8363e80aSGeorge Wilson 	    mdb_ctf_vread(&mg, "metaslab_group_t", "mdb_metaslab_group_t",
1757*8363e80aSGeorge Wilson 	    mat.mat_mg, 0) == -1) {
1758*8363e80aSGeorge Wilson 		return (DCMD_ERR);
1759*8363e80aSGeorge Wilson 	}
1760*8363e80aSGeorge Wilson 
1761*8363e80aSGeorge Wilson 	if (mg.mg_vd != NULL) {
1762*8363e80aSGeorge Wilson 		mdb_vdev_t vdev;
1763*8363e80aSGeorge Wilson 		char desc[MAXNAMELEN];
1764*8363e80aSGeorge Wilson 
1765*8363e80aSGeorge Wilson 		if (mdb_ctf_vread(&vdev, "vdev_t", "mdb_vdev_t",
1766*8363e80aSGeorge Wilson 		    mg.mg_vd, 0) == -1) {
1767*8363e80aSGeorge Wilson 			return (DCMD_ERR);
1768*8363e80aSGeorge Wilson 		}
1769*8363e80aSGeorge Wilson 
1770*8363e80aSGeorge Wilson 		if (vdev.vdev_path != NULL) {
1771*8363e80aSGeorge Wilson 			char path[MAXNAMELEN];
1772*8363e80aSGeorge Wilson 
1773*8363e80aSGeorge Wilson 			if (mdb_readstr(path, sizeof (path),
1774*8363e80aSGeorge Wilson 			    vdev.vdev_path) == -1) {
1775*8363e80aSGeorge Wilson 				mdb_warn("failed to read vdev_path at %p\n",
1776*8363e80aSGeorge Wilson 				    vdev.vdev_path);
1777*8363e80aSGeorge Wilson 				return (DCMD_ERR);
1778*8363e80aSGeorge Wilson 			}
1779*8363e80aSGeorge Wilson 			char *slash;
1780*8363e80aSGeorge Wilson 			if ((slash = strrchr(path, '/')) != NULL) {
1781*8363e80aSGeorge Wilson 				strcpy(desc, slash + 1);
1782*8363e80aSGeorge Wilson 			} else {
1783*8363e80aSGeorge Wilson 				strcpy(desc, path);
1784*8363e80aSGeorge Wilson 			}
1785*8363e80aSGeorge Wilson 		} else if (vdev.vdev_ops != NULL) {
1786*8363e80aSGeorge Wilson 			mdb_vdev_ops_t ops;
1787*8363e80aSGeorge Wilson 			if (mdb_ctf_vread(&ops, "vdev_ops_t", "mdb_vdev_ops_t",
1788*8363e80aSGeorge Wilson 			    vdev.vdev_ops, 0) == -1) {
1789*8363e80aSGeorge Wilson 				mdb_warn("failed to read vdev_ops at %p\n",
1790*8363e80aSGeorge Wilson 				    vdev.vdev_ops);
1791*8363e80aSGeorge Wilson 				return (DCMD_ERR);
1792*8363e80aSGeorge Wilson 			}
1793*8363e80aSGeorge Wilson 			(void) mdb_snprintf(desc, sizeof (desc),
1794*8363e80aSGeorge Wilson 			    "%s-%llu", ops.vdev_op_type, vdev.vdev_id);
1795*8363e80aSGeorge Wilson 		} else {
1796*8363e80aSGeorge Wilson 			(void) strcpy(desc, "<unknown>");
1797*8363e80aSGeorge Wilson 		}
1798*8363e80aSGeorge Wilson 		mdb_printf("%18s\n", desc);
1799*8363e80aSGeorge Wilson 	}
1800*8363e80aSGeorge Wilson 
1801*8363e80aSGeorge Wilson 	return (DCMD_OK);
1802*8363e80aSGeorge Wilson }
1803*8363e80aSGeorge Wilson 
18045f5f7a6fSahrens typedef struct metaslab_walk_data {
18055f5f7a6fSahrens 	uint64_t mw_numvdevs;
18065f5f7a6fSahrens 	uintptr_t *mw_vdevs;
18075f5f7a6fSahrens 	int mw_curvdev;
18085f5f7a6fSahrens 	uint64_t mw_nummss;
18095f5f7a6fSahrens 	uintptr_t *mw_mss;
18105f5f7a6fSahrens 	int mw_curms;
18115f5f7a6fSahrens } metaslab_walk_data_t;
18125f5f7a6fSahrens 
18135f5f7a6fSahrens static int
18145f5f7a6fSahrens metaslab_walk_step(mdb_walk_state_t *wsp)
18155f5f7a6fSahrens {
18165f5f7a6fSahrens 	metaslab_walk_data_t *mw = wsp->walk_data;
18175f5f7a6fSahrens 	metaslab_t ms;
18185f5f7a6fSahrens 	uintptr_t msp;
18195f5f7a6fSahrens 
18205f5f7a6fSahrens 	if (mw->mw_curvdev >= mw->mw_numvdevs)
18215f5f7a6fSahrens 		return (WALK_DONE);
18225f5f7a6fSahrens 
18235f5f7a6fSahrens 	if (mw->mw_mss == NULL) {
18245f5f7a6fSahrens 		uintptr_t mssp;
18255f5f7a6fSahrens 		uintptr_t vdevp;
18265f5f7a6fSahrens 
18275f5f7a6fSahrens 		ASSERT(mw->mw_curms == 0);
18285f5f7a6fSahrens 		ASSERT(mw->mw_nummss == 0);
18295f5f7a6fSahrens 
18305f5f7a6fSahrens 		vdevp = mw->mw_vdevs[mw->mw_curvdev];
183128e4da25SMatthew Ahrens 		if (GETMEMB(vdevp, "vdev", vdev_ms, mssp) ||
183228e4da25SMatthew Ahrens 		    GETMEMB(vdevp, "vdev", vdev_ms_count, mw->mw_nummss)) {
18335f5f7a6fSahrens 			return (WALK_ERR);
18345f5f7a6fSahrens 		}
18355f5f7a6fSahrens 
18365f5f7a6fSahrens 		mw->mw_mss = mdb_alloc(mw->mw_nummss * sizeof (void*),
18375f5f7a6fSahrens 		    UM_SLEEP | UM_GC);
18385f5f7a6fSahrens 		if (mdb_vread(mw->mw_mss, mw->mw_nummss * sizeof (void*),
18395f5f7a6fSahrens 		    mssp) == -1) {
18405f5f7a6fSahrens 			mdb_warn("failed to read vdev_ms at %p", mssp);
18415f5f7a6fSahrens 			return (WALK_ERR);
18425f5f7a6fSahrens 		}
18435f5f7a6fSahrens 	}
18445f5f7a6fSahrens 
18455f5f7a6fSahrens 	if (mw->mw_curms >= mw->mw_nummss) {
18465f5f7a6fSahrens 		mw->mw_mss = NULL;
18475f5f7a6fSahrens 		mw->mw_curms = 0;
18485f5f7a6fSahrens 		mw->mw_nummss = 0;
18495f5f7a6fSahrens 		mw->mw_curvdev++;
18505f5f7a6fSahrens 		return (WALK_NEXT);
18515f5f7a6fSahrens 	}
18525f5f7a6fSahrens 
18535f5f7a6fSahrens 	msp = mw->mw_mss[mw->mw_curms];
18545f5f7a6fSahrens 	if (mdb_vread(&ms, sizeof (metaslab_t), msp) == -1) {
18555f5f7a6fSahrens 		mdb_warn("failed to read metaslab_t at %p", msp);
18565f5f7a6fSahrens 		return (WALK_ERR);
18575f5f7a6fSahrens 	}
18585f5f7a6fSahrens 
18595f5f7a6fSahrens 	mw->mw_curms++;
18605f5f7a6fSahrens 
18615f5f7a6fSahrens 	return (wsp->walk_callback(msp, &ms, wsp->walk_cbdata));
18625f5f7a6fSahrens }
18635f5f7a6fSahrens 
18645f5f7a6fSahrens static int
18655f5f7a6fSahrens metaslab_walk_init(mdb_walk_state_t *wsp)
18665f5f7a6fSahrens {
18675f5f7a6fSahrens 	metaslab_walk_data_t *mw;
18685f5f7a6fSahrens 	uintptr_t root_vdevp;
18695f5f7a6fSahrens 	uintptr_t childp;
18705f5f7a6fSahrens 
18715f5f7a6fSahrens 	if (wsp->walk_addr == NULL) {
18725f5f7a6fSahrens 		mdb_warn("must supply address of spa_t\n");
18735f5f7a6fSahrens 		return (WALK_ERR);
18745f5f7a6fSahrens 	}
18755f5f7a6fSahrens 
18765f5f7a6fSahrens 	mw = mdb_zalloc(sizeof (metaslab_walk_data_t), UM_SLEEP | UM_GC);
18775f5f7a6fSahrens 
187828e4da25SMatthew Ahrens 	if (GETMEMB(wsp->walk_addr, "spa", spa_root_vdev, root_vdevp) ||
187928e4da25SMatthew Ahrens 	    GETMEMB(root_vdevp, "vdev", vdev_children, mw->mw_numvdevs) ||
188028e4da25SMatthew Ahrens 	    GETMEMB(root_vdevp, "vdev", vdev_child, childp)) {
18815f5f7a6fSahrens 		return (DCMD_ERR);
18825f5f7a6fSahrens 	}
18835f5f7a6fSahrens 
18845f5f7a6fSahrens 	mw->mw_vdevs = mdb_alloc(mw->mw_numvdevs * sizeof (void *),
18855f5f7a6fSahrens 	    UM_SLEEP | UM_GC);
18865f5f7a6fSahrens 	if (mdb_vread(mw->mw_vdevs, mw->mw_numvdevs * sizeof (void *),
18875f5f7a6fSahrens 	    childp) == -1) {
18885f5f7a6fSahrens 		mdb_warn("failed to read root vdev children at %p", childp);
18895f5f7a6fSahrens 		return (DCMD_ERR);
18905f5f7a6fSahrens 	}
18915f5f7a6fSahrens 
18925f5f7a6fSahrens 	wsp->walk_data = mw;
18935f5f7a6fSahrens 
18945f5f7a6fSahrens 	return (WALK_NEXT);
18955f5f7a6fSahrens }
18965f5f7a6fSahrens 
1897fa9e4066Sahrens typedef struct mdb_spa {
1898fa9e4066Sahrens 	uintptr_t spa_dsl_pool;
1899fa9e4066Sahrens 	uintptr_t spa_root_vdev;
1900fa9e4066Sahrens } mdb_spa_t;
1901fa9e4066Sahrens 
19022515f5d4SJustin T. Gibbs typedef struct mdb_dsl_pool {
19032515f5d4SJustin T. Gibbs 	uintptr_t dp_root_dir;
19042515f5d4SJustin T. Gibbs } mdb_dsl_pool_t;
19052515f5d4SJustin T. Gibbs 
1906fa9e4066Sahrens typedef struct mdb_dsl_dir {
19072515f5d4SJustin T. Gibbs 	uintptr_t dd_dbuf;
1908fa9e4066Sahrens 	int64_t dd_space_towrite[TXG_SIZE];
1909fa9e4066Sahrens } mdb_dsl_dir_t;
1910fa9e4066Sahrens 
1911fa9e4066Sahrens typedef struct mdb_dsl_dir_phys {
1912fa9e4066Sahrens 	uint64_t dd_used_bytes;
1913fa9e4066Sahrens 	uint64_t dd_compressed_bytes;
1914fa9e4066Sahrens 	uint64_t dd_uncompressed_bytes;
1915fa9e4066Sahrens } mdb_dsl_dir_phys_t;
1916fa9e4066Sahrens 
19175f5f7a6fSahrens typedef struct space_data {
19180713e232SGeorge Wilson 	uint64_t ms_alloctree[TXG_SIZE];
19190713e232SGeorge Wilson 	uint64_t ms_freetree[TXG_SIZE];
19200713e232SGeorge Wilson 	uint64_t ms_tree;
1921*8363e80aSGeorge Wilson 	int64_t ms_deferspace;
19225f5f7a6fSahrens 	uint64_t avail;
19235f5f7a6fSahrens 	uint64_t nowavail;
19245f5f7a6fSahrens } space_data_t;
19255f5f7a6fSahrens 
19265f5f7a6fSahrens /* ARGSUSED */
19275f5f7a6fSahrens static int
19285f5f7a6fSahrens space_cb(uintptr_t addr, const void *unknown, void *arg)
19295f5f7a6fSahrens {
19305f5f7a6fSahrens 	space_data_t *sd = arg;
19315f5f7a6fSahrens 	mdb_metaslab_t ms;
19320713e232SGeorge Wilson 	mdb_range_tree_t rt;
19332e4c9986SGeorge Wilson 	mdb_space_map_t sm = { 0 };
19340713e232SGeorge Wilson 	mdb_space_map_phys_t smp = { 0 };
19350713e232SGeorge Wilson 	int i;
19360713e232SGeorge Wilson 
19370713e232SGeorge Wilson 	if (mdb_ctf_vread(&ms, "metaslab_t", "mdb_metaslab_t",
19380713e232SGeorge Wilson 	    addr, 0) == -1)
19390713e232SGeorge Wilson 		return (WALK_ERR);
19400713e232SGeorge Wilson 
19410713e232SGeorge Wilson 	for (i = 0; i < TXG_SIZE; i++) {
19420713e232SGeorge Wilson 		if (mdb_ctf_vread(&rt, "range_tree_t",
19430713e232SGeorge Wilson 		    "mdb_range_tree_t", ms.ms_alloctree[i], 0) == -1)
19442e4c9986SGeorge Wilson 			return (WALK_ERR);
19452e4c9986SGeorge Wilson 
19460713e232SGeorge Wilson 		sd->ms_alloctree[i] += rt.rt_space;
19475f5f7a6fSahrens 
19480713e232SGeorge Wilson 		if (mdb_ctf_vread(&rt, "range_tree_t",
19490713e232SGeorge Wilson 		    "mdb_range_tree_t", ms.ms_freetree[i], 0) == -1)
19502e4c9986SGeorge Wilson 			return (WALK_ERR);
19512e4c9986SGeorge Wilson 
19520713e232SGeorge Wilson 		sd->ms_freetree[i] += rt.rt_space;
19530713e232SGeorge Wilson 	}
19540713e232SGeorge Wilson 
19550713e232SGeorge Wilson 	if (mdb_ctf_vread(&rt, "range_tree_t",
19562e4c9986SGeorge Wilson 	    "mdb_range_tree_t", ms.ms_tree, 0) == -1)
19572e4c9986SGeorge Wilson 		return (WALK_ERR);
19582e4c9986SGeorge Wilson 
19592e4c9986SGeorge Wilson 	if (ms.ms_sm != NULL &&
19600713e232SGeorge Wilson 	    mdb_ctf_vread(&sm, "space_map_t",
19610713e232SGeorge Wilson 	    "mdb_space_map_t", ms.ms_sm, 0) == -1)
19625f5f7a6fSahrens 		return (WALK_ERR);
19630713e232SGeorge Wilson 
19640713e232SGeorge Wilson 	if (sm.sm_phys != NULL) {
19650713e232SGeorge Wilson 		(void) mdb_ctf_vread(&smp, "space_map_phys_t",
19660713e232SGeorge Wilson 		    "mdb_space_map_phys_t", sm.sm_phys, 0);
19675f5f7a6fSahrens 	}
19685f5f7a6fSahrens 
1969*8363e80aSGeorge Wilson 	sd->ms_deferspace += ms.ms_deferspace;
19700713e232SGeorge Wilson 	sd->ms_tree += rt.rt_space;
19710713e232SGeorge Wilson 	sd->avail += sm.sm_size - sm.sm_alloc;
19720713e232SGeorge Wilson 	sd->nowavail += sm.sm_size - smp.smp_alloc;
19735f5f7a6fSahrens 
19745f5f7a6fSahrens 	return (WALK_NEXT);
19755f5f7a6fSahrens }
19765f5f7a6fSahrens 
1977fa9e4066Sahrens /*
1978fa9e4066Sahrens  * ::spa_space [-b]
1979fa9e4066Sahrens  *
1980fa9e4066Sahrens  * Given a spa_t, print out it's on-disk space usage and in-core
1981fa9e4066Sahrens  * estimates of future usage.  If -b is given, print space in bytes.
1982fa9e4066Sahrens  * Otherwise print in megabytes.
1983fa9e4066Sahrens  */
1984fa9e4066Sahrens /* ARGSUSED */
1985fa9e4066Sahrens static int
1986fa9e4066Sahrens spa_space(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
1987fa9e4066Sahrens {
1988fa9e4066Sahrens 	mdb_spa_t spa;
19892515f5d4SJustin T. Gibbs 	mdb_dsl_pool_t dp;
1990fa9e4066Sahrens 	mdb_dsl_dir_t dd;
19912515f5d4SJustin T. Gibbs 	mdb_dmu_buf_impl_t db;
1992fa9e4066Sahrens 	mdb_dsl_dir_phys_t dsp;
19935f5f7a6fSahrens 	space_data_t sd;
1994fa9e4066Sahrens 	int shift = 20;
1995fa9e4066Sahrens 	char *suffix = "M";
199628e4da25SMatthew Ahrens 	int bytes = B_FALSE;
1997fa9e4066Sahrens 
199828e4da25SMatthew Ahrens 	if (mdb_getopts(argc, argv, 'b', MDB_OPT_SETBITS, TRUE, &bytes, NULL) !=
1999fa9e4066Sahrens 	    argc)
2000fa9e4066Sahrens 		return (DCMD_USAGE);
2001fa9e4066Sahrens 	if (!(flags & DCMD_ADDRSPEC))
2002fa9e4066Sahrens 		return (DCMD_USAGE);
2003fa9e4066Sahrens 
200428e4da25SMatthew Ahrens 	if (bytes) {
2005fa9e4066Sahrens 		shift = 0;
2006fa9e4066Sahrens 		suffix = "";
2007fa9e4066Sahrens 	}
2008fa9e4066Sahrens 
20092515f5d4SJustin T. Gibbs 	if (mdb_ctf_vread(&spa, ZFS_STRUCT "spa", "mdb_spa_t",
20102515f5d4SJustin T. Gibbs 	    addr, 0) == -1 ||
20112515f5d4SJustin T. Gibbs 	    mdb_ctf_vread(&dp, ZFS_STRUCT "dsl_pool", "mdb_dsl_pool_t",
20122515f5d4SJustin T. Gibbs 	    spa.spa_dsl_pool, 0) == -1 ||
20132515f5d4SJustin T. Gibbs 	    mdb_ctf_vread(&dd, ZFS_STRUCT "dsl_dir", "mdb_dsl_dir_t",
20142515f5d4SJustin T. Gibbs 	    dp.dp_root_dir, 0) == -1 ||
20152515f5d4SJustin T. Gibbs 	    mdb_ctf_vread(&db, ZFS_STRUCT "dmu_buf_impl", "mdb_dmu_buf_impl_t",
20162515f5d4SJustin T. Gibbs 	    dd.dd_dbuf, 0) == -1 ||
20172515f5d4SJustin T. Gibbs 	    mdb_ctf_vread(&dsp, ZFS_STRUCT "dsl_dir_phys",
20182515f5d4SJustin T. Gibbs 	    "mdb_dsl_dir_phys_t", db.db.db_data, 0) == -1) {
2019fa9e4066Sahrens 		return (DCMD_ERR);
2020fa9e4066Sahrens 	}
2021fa9e4066Sahrens 
2022fa9e4066Sahrens 	mdb_printf("dd_space_towrite = %llu%s %llu%s %llu%s %llu%s\n",
2023fa9e4066Sahrens 	    dd.dd_space_towrite[0] >> shift, suffix,
2024fa9e4066Sahrens 	    dd.dd_space_towrite[1] >> shift, suffix,
2025fa9e4066Sahrens 	    dd.dd_space_towrite[2] >> shift, suffix,
2026fa9e4066Sahrens 	    dd.dd_space_towrite[3] >> shift, suffix);
2027fa9e4066Sahrens 
2028fa9e4066Sahrens 	mdb_printf("dd_phys.dd_used_bytes = %llu%s\n",
2029fa9e4066Sahrens 	    dsp.dd_used_bytes >> shift, suffix);
20305f5f7a6fSahrens 	mdb_printf("dd_phys.dd_compressed_bytes = %llu%s\n",
20315f5f7a6fSahrens 	    dsp.dd_compressed_bytes >> shift, suffix);
20325f5f7a6fSahrens 	mdb_printf("dd_phys.dd_uncompressed_bytes = %llu%s\n",
20335f5f7a6fSahrens 	    dsp.dd_uncompressed_bytes >> shift, suffix);
20345f5f7a6fSahrens 
20355f5f7a6fSahrens 	bzero(&sd, sizeof (sd));
20365f5f7a6fSahrens 	if (mdb_pwalk("metaslab", space_cb, &sd, addr) != 0) {
20375f5f7a6fSahrens 		mdb_warn("can't walk metaslabs");
20385f5f7a6fSahrens 		return (DCMD_ERR);
2039fa9e4066Sahrens 	}
2040fa9e4066Sahrens 
2041fa9e4066Sahrens 	mdb_printf("ms_allocmap = %llu%s %llu%s %llu%s %llu%s\n",
20420713e232SGeorge Wilson 	    sd.ms_alloctree[0] >> shift, suffix,
20430713e232SGeorge Wilson 	    sd.ms_alloctree[1] >> shift, suffix,
20440713e232SGeorge Wilson 	    sd.ms_alloctree[2] >> shift, suffix,
20450713e232SGeorge Wilson 	    sd.ms_alloctree[3] >> shift, suffix);
2046fa9e4066Sahrens 	mdb_printf("ms_freemap = %llu%s %llu%s %llu%s %llu%s\n",
20470713e232SGeorge Wilson 	    sd.ms_freetree[0] >> shift, suffix,
20480713e232SGeorge Wilson 	    sd.ms_freetree[1] >> shift, suffix,
20490713e232SGeorge Wilson 	    sd.ms_freetree[2] >> shift, suffix,
20500713e232SGeorge Wilson 	    sd.ms_freetree[3] >> shift, suffix);
20510713e232SGeorge Wilson 	mdb_printf("ms_tree = %llu%s\n", sd.ms_tree >> shift, suffix);
2052*8363e80aSGeorge Wilson 	mdb_printf("ms_deferspace = %llu%s\n",
2053*8363e80aSGeorge Wilson 	    sd.ms_deferspace >> shift, suffix);
20545f5f7a6fSahrens 	mdb_printf("last synced avail = %llu%s\n", sd.avail >> shift, suffix);
20555f5f7a6fSahrens 	mdb_printf("current syncing avail = %llu%s\n",
20565f5f7a6fSahrens 	    sd.nowavail >> shift, suffix);
2057fa9e4066Sahrens 
2058fa9e4066Sahrens 	return (DCMD_OK);
2059fa9e4066Sahrens }
2060fa9e4066Sahrens 
206122ce0148SMatthew Ahrens typedef struct mdb_spa_aux_vdev {
206222ce0148SMatthew Ahrens 	int sav_count;
206322ce0148SMatthew Ahrens 	uintptr_t sav_vdevs;
206422ce0148SMatthew Ahrens } mdb_spa_aux_vdev_t;
2065fa9e4066Sahrens 
206622ce0148SMatthew Ahrens typedef struct mdb_spa_vdevs {
206722ce0148SMatthew Ahrens 	uintptr_t spa_root_vdev;
206822ce0148SMatthew Ahrens 	mdb_spa_aux_vdev_t spa_l2cache;
206922ce0148SMatthew Ahrens 	mdb_spa_aux_vdev_t spa_spares;
207022ce0148SMatthew Ahrens } mdb_spa_vdevs_t;
2071fa9e4066Sahrens 
2072ec9f632eSEric Schrock static int
207322ce0148SMatthew Ahrens spa_print_aux(mdb_spa_aux_vdev_t *sav, uint_t flags, mdb_arg_t *v,
2074ec9f632eSEric Schrock     const char *name)
2075ec9f632eSEric Schrock {
2076ec9f632eSEric Schrock 	uintptr_t *aux;
2077ec9f632eSEric Schrock 	size_t len;
2078ec9f632eSEric Schrock 	int ret, i;
2079ec9f632eSEric Schrock 
2080ec9f632eSEric Schrock 	/*
2081ec9f632eSEric Schrock 	 * Iterate over aux vdevs and print those out as well.  This is a
2082ec9f632eSEric Schrock 	 * little annoying because we don't have a root vdev to pass to ::vdev.
2083ec9f632eSEric Schrock 	 * Instead, we print a single line and then call it for each child
2084ec9f632eSEric Schrock 	 * vdev.
2085ec9f632eSEric Schrock 	 */
2086ec9f632eSEric Schrock 	if (sav->sav_count != 0) {
2087ec9f632eSEric Schrock 		v[1].a_type = MDB_TYPE_STRING;
2088ec9f632eSEric Schrock 		v[1].a_un.a_str = "-d";
2089ec9f632eSEric Schrock 		v[2].a_type = MDB_TYPE_IMMEDIATE;
2090ec9f632eSEric Schrock 		v[2].a_un.a_val = 2;
2091ec9f632eSEric Schrock 
2092ec9f632eSEric Schrock 		len = sav->sav_count * sizeof (uintptr_t);
2093ec9f632eSEric Schrock 		aux = mdb_alloc(len, UM_SLEEP);
209422ce0148SMatthew Ahrens 		if (mdb_vread(aux, len, sav->sav_vdevs) == -1) {
2095ec9f632eSEric Schrock 			mdb_free(aux, len);
2096ec9f632eSEric Schrock 			mdb_warn("failed to read l2cache vdevs at %p",
2097ec9f632eSEric Schrock 			    sav->sav_vdevs);
2098ec9f632eSEric Schrock 			return (DCMD_ERR);
2099ec9f632eSEric Schrock 		}
2100ec9f632eSEric Schrock 
2101ec9f632eSEric Schrock 		mdb_printf("%-?s %-9s %-12s %s\n", "-", "-", "-", name);
2102ec9f632eSEric Schrock 
2103ec9f632eSEric Schrock 		for (i = 0; i < sav->sav_count; i++) {
2104ec9f632eSEric Schrock 			ret = mdb_call_dcmd("vdev", aux[i], flags, 3, v);
2105ec9f632eSEric Schrock 			if (ret != DCMD_OK) {
2106ec9f632eSEric Schrock 				mdb_free(aux, len);
2107ec9f632eSEric Schrock 				return (ret);
2108ec9f632eSEric Schrock 			}
2109ec9f632eSEric Schrock 		}
2110ec9f632eSEric Schrock 
2111ec9f632eSEric Schrock 		mdb_free(aux, len);
2112ec9f632eSEric Schrock 	}
2113ec9f632eSEric Schrock 
2114ec9f632eSEric Schrock 	return (0);
2115ec9f632eSEric Schrock }
2116ec9f632eSEric Schrock 
2117fa9e4066Sahrens /*
2118fa9e4066Sahrens  * ::spa_vdevs
2119fa9e4066Sahrens  *
21202e4c9986SGeorge Wilson  *	-e	Include error stats
21212e4c9986SGeorge Wilson  *	-m	Include metaslab information
21222e4c9986SGeorge Wilson  *	-M	Include metaslab group information
21232e4c9986SGeorge Wilson  *	-h	Include histogram information (requires -m or -M)
2124fa9e4066Sahrens  *
2125fa9e4066Sahrens  * Print out a summarized list of vdevs for the given spa_t.
2126c5904d13Seschrock  * This is accomplished by invoking "::vdev -re" on the root vdev, as well as
2127c5904d13Seschrock  * iterating over the cache devices.
2128fa9e4066Sahrens  */
2129fa9e4066Sahrens /* ARGSUSED */
2130fa9e4066Sahrens static int
2131fa9e4066Sahrens spa_vdevs(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
2132fa9e4066Sahrens {
2133c5904d13Seschrock 	mdb_arg_t v[3];
2134ec9f632eSEric Schrock 	int ret;
21352e4c9986SGeorge Wilson 	char opts[100] = "-r";
21362e4c9986SGeorge Wilson 	int spa_flags = 0;
2137fa9e4066Sahrens 
2138fa9e4066Sahrens 	if (mdb_getopts(argc, argv,
21392e4c9986SGeorge Wilson 	    'e', MDB_OPT_SETBITS, SPA_FLAG_ERRORS, &spa_flags,
21402e4c9986SGeorge Wilson 	    'm', MDB_OPT_SETBITS, SPA_FLAG_METASLABS, &spa_flags,
21412e4c9986SGeorge Wilson 	    'M', MDB_OPT_SETBITS, SPA_FLAG_METASLAB_GROUPS, &spa_flags,
21422e4c9986SGeorge Wilson 	    'h', MDB_OPT_SETBITS, SPA_FLAG_HISTOGRAMS, &spa_flags,
2143fa9e4066Sahrens 	    NULL) != argc)
2144fa9e4066Sahrens 		return (DCMD_USAGE);
2145fa9e4066Sahrens 
2146fa9e4066Sahrens 	if (!(flags & DCMD_ADDRSPEC))
2147fa9e4066Sahrens 		return (DCMD_USAGE);
2148fa9e4066Sahrens 
214922ce0148SMatthew Ahrens 	mdb_spa_vdevs_t spa;
215022ce0148SMatthew Ahrens 	if (mdb_ctf_vread(&spa, "spa_t", "mdb_spa_vdevs_t", addr, 0) == -1)
2151fa9e4066Sahrens 		return (DCMD_ERR);
2152fa9e4066Sahrens 
2153088e9d47Seschrock 	/*
2154088e9d47Seschrock 	 * Unitialized spa_t structures can have a NULL root vdev.
2155088e9d47Seschrock 	 */
2156088e9d47Seschrock 	if (spa.spa_root_vdev == NULL) {
2157088e9d47Seschrock 		mdb_printf("no associated vdevs\n");
2158088e9d47Seschrock 		return (DCMD_OK);
2159088e9d47Seschrock 	}
2160088e9d47Seschrock 
21612e4c9986SGeorge Wilson 	if (spa_flags & SPA_FLAG_ERRORS)
21622e4c9986SGeorge Wilson 		strcat(opts, "e");
21632e4c9986SGeorge Wilson 	if (spa_flags & SPA_FLAG_METASLABS)
21642e4c9986SGeorge Wilson 		strcat(opts, "m");
21652e4c9986SGeorge Wilson 	if (spa_flags & SPA_FLAG_METASLAB_GROUPS)
21662e4c9986SGeorge Wilson 		strcat(opts, "M");
21672e4c9986SGeorge Wilson 	if (spa_flags & SPA_FLAG_HISTOGRAMS)
21682e4c9986SGeorge Wilson 		strcat(opts, "h");
21692e4c9986SGeorge Wilson 
2170c5904d13Seschrock 	v[0].a_type = MDB_TYPE_STRING;
21712e4c9986SGeorge Wilson 	v[0].a_un.a_str = opts;
2172fa9e4066Sahrens 
2173c5904d13Seschrock 	ret = mdb_call_dcmd("vdev", (uintptr_t)spa.spa_root_vdev,
2174c5904d13Seschrock 	    flags, 1, v);
2175c5904d13Seschrock 	if (ret != DCMD_OK)
2176c5904d13Seschrock 		return (ret);
2177c5904d13Seschrock 
2178ec9f632eSEric Schrock 	if (spa_print_aux(&spa.spa_l2cache, flags, v, "cache") != 0 ||
2179ec9f632eSEric Schrock 	    spa_print_aux(&spa.spa_spares, flags, v, "spares") != 0)
2180ec9f632eSEric Schrock 		return (DCMD_ERR);
2181c5904d13Seschrock 
2182c5904d13Seschrock 	return (DCMD_OK);
2183fa9e4066Sahrens }
2184fa9e4066Sahrens 
2185ccae0b50Seschrock /*
2186ccae0b50Seschrock  * ::zio
2187ccae0b50Seschrock  *
2188ccae0b50Seschrock  * Print a summary of zio_t and all its children.  This is intended to display a
2189ccae0b50Seschrock  * zio tree, and hence we only pick the most important pieces of information for
2190ccae0b50Seschrock  * the main summary.  More detailed information can always be found by doing a
2191ccae0b50Seschrock  * '::print zio' on the underlying zio_t.  The columns we display are:
2192ccae0b50Seschrock  *
2193c55e05cbSMatthew Ahrens  *	ADDRESS  TYPE  STAGE  WAITER  TIME_ELAPSED
2194ccae0b50Seschrock  *
2195ccae0b50Seschrock  * The 'address' column is indented by one space for each depth level as we
2196ccae0b50Seschrock  * descend down the tree.
2197ccae0b50Seschrock  */
2198fac3008cSeschrock 
2199c55e05cbSMatthew Ahrens #define	ZIO_MAXINDENT	7
2200a3f829aeSBill Moore #define	ZIO_MAXWIDTH	(sizeof (uintptr_t) * 2 + ZIO_MAXINDENT)
2201a3f829aeSBill Moore #define	ZIO_WALK_SELF	0
2202a3f829aeSBill Moore #define	ZIO_WALK_CHILD	1
2203a3f829aeSBill Moore #define	ZIO_WALK_PARENT	2
2204a3f829aeSBill Moore 
2205a3f829aeSBill Moore typedef struct zio_print_args {
2206a3f829aeSBill Moore 	int	zpa_current_depth;
2207a3f829aeSBill Moore 	int	zpa_min_depth;
2208a3f829aeSBill Moore 	int	zpa_max_depth;
2209a3f829aeSBill Moore 	int	zpa_type;
2210a3f829aeSBill Moore 	uint_t	zpa_flags;
2211a3f829aeSBill Moore } zio_print_args_t;
2212a3f829aeSBill Moore 
221328e4da25SMatthew Ahrens typedef struct mdb_zio {
221428e4da25SMatthew Ahrens 	enum zio_type io_type;
221528e4da25SMatthew Ahrens 	enum zio_stage io_stage;
2216d5ee8a13SMatthew Ahrens 	uintptr_t io_waiter;
2217d5ee8a13SMatthew Ahrens 	uintptr_t io_spa;
221828e4da25SMatthew Ahrens 	struct {
221928e4da25SMatthew Ahrens 		struct {
2220d5ee8a13SMatthew Ahrens 			uintptr_t list_next;
222128e4da25SMatthew Ahrens 		} list_head;
222228e4da25SMatthew Ahrens 	} io_parent_list;
222328e4da25SMatthew Ahrens 	int io_error;
222428e4da25SMatthew Ahrens } mdb_zio_t;
222528e4da25SMatthew Ahrens 
2226c55e05cbSMatthew Ahrens typedef struct mdb_zio_timestamp {
2227c55e05cbSMatthew Ahrens 	hrtime_t io_timestamp;
2228c55e05cbSMatthew Ahrens } mdb_zio_timestamp_t;
2229c55e05cbSMatthew Ahrens 
2230a3f829aeSBill Moore static int zio_child_cb(uintptr_t addr, const void *unknown, void *arg);
2231fac3008cSeschrock 
2232ccae0b50Seschrock static int
2233c55e05cbSMatthew Ahrens zio_print_cb(uintptr_t addr, zio_print_args_t *zpa)
2234ccae0b50Seschrock {
2235ccae0b50Seschrock 	mdb_ctf_id_t type_enum, stage_enum;
2236a3f829aeSBill Moore 	int indent = zpa->zpa_current_depth;
2237ccae0b50Seschrock 	const char *type, *stage;
2238a3f829aeSBill Moore 	uintptr_t laddr;
2239c55e05cbSMatthew Ahrens 	mdb_zio_t zio;
2240c55e05cbSMatthew Ahrens 	mdb_zio_timestamp_t zio_timestamp = { 0 };
2241c55e05cbSMatthew Ahrens 
2242c55e05cbSMatthew Ahrens 	if (mdb_ctf_vread(&zio, ZFS_STRUCT "zio", "mdb_zio_t", addr, 0) == -1)
2243c55e05cbSMatthew Ahrens 		return (WALK_ERR);
2244c55e05cbSMatthew Ahrens 	(void) mdb_ctf_vread(&zio_timestamp, ZFS_STRUCT "zio",
2245c55e05cbSMatthew Ahrens 	    "mdb_zio_timestamp_t", addr, MDB_CTF_VREAD_QUIET);
2246ccae0b50Seschrock 
2247a3f829aeSBill Moore 	if (indent > ZIO_MAXINDENT)
2248a3f829aeSBill Moore 		indent = ZIO_MAXINDENT;
2249ccae0b50Seschrock 
2250ccae0b50Seschrock 	if (mdb_ctf_lookup_by_name("enum zio_type", &type_enum) == -1 ||
2251ccae0b50Seschrock 	    mdb_ctf_lookup_by_name("enum zio_stage", &stage_enum) == -1) {
2252ccae0b50Seschrock 		mdb_warn("failed to lookup zio enums");
2253ccae0b50Seschrock 		return (WALK_ERR);
2254ccae0b50Seschrock 	}
2255ccae0b50Seschrock 
2256c55e05cbSMatthew Ahrens 	if ((type = mdb_ctf_enum_name(type_enum, zio.io_type)) != NULL)
2257ccae0b50Seschrock 		type += sizeof ("ZIO_TYPE_") - 1;
2258ccae0b50Seschrock 	else
2259ccae0b50Seschrock 		type = "?";
2260ccae0b50Seschrock 
2261c55e05cbSMatthew Ahrens 	if (zio.io_error == 0) {
2262c55e05cbSMatthew Ahrens 		stage = mdb_ctf_enum_name(stage_enum, zio.io_stage);
226328e4da25SMatthew Ahrens 		if (stage != NULL)
226428e4da25SMatthew Ahrens 			stage += sizeof ("ZIO_STAGE_") - 1;
226528e4da25SMatthew Ahrens 		else
226628e4da25SMatthew Ahrens 			stage = "?";
226728e4da25SMatthew Ahrens 	} else {
226828e4da25SMatthew Ahrens 		stage = "FAILED";
226928e4da25SMatthew Ahrens 	}
2270ccae0b50Seschrock 
2271a3f829aeSBill Moore 	if (zpa->zpa_current_depth >= zpa->zpa_min_depth) {
2272a3f829aeSBill Moore 		if (zpa->zpa_flags & DCMD_PIPE_OUT) {
2273a3f829aeSBill Moore 			mdb_printf("%?p\n", addr);
2274a3f829aeSBill Moore 		} else {
2275a3f829aeSBill Moore 			mdb_printf("%*s%-*p %-5s %-16s ", indent, "",
2276a3f829aeSBill Moore 			    ZIO_MAXWIDTH - indent, addr, type, stage);
2277d5ee8a13SMatthew Ahrens 			if (zio.io_waiter != 0)
2278d5ee8a13SMatthew Ahrens 				mdb_printf("%-16lx ", zio.io_waiter);
2279a3f829aeSBill Moore 			else
2280c55e05cbSMatthew Ahrens 				mdb_printf("%-16s ", "-");
2281c55e05cbSMatthew Ahrens #ifdef _KERNEL
2282c55e05cbSMatthew Ahrens 			if (zio_timestamp.io_timestamp != 0) {
2283c55e05cbSMatthew Ahrens 				mdb_printf("%llums", (mdb_gethrtime() -
2284c55e05cbSMatthew Ahrens 				    zio_timestamp.io_timestamp) /
2285c55e05cbSMatthew Ahrens 				    1000000);
2286c55e05cbSMatthew Ahrens 			} else {
2287c55e05cbSMatthew Ahrens 				mdb_printf("%-12s ", "-");
2288c55e05cbSMatthew Ahrens 			}
2289c55e05cbSMatthew Ahrens #else
2290c55e05cbSMatthew Ahrens 			mdb_printf("%-12s ", "-");
2291c55e05cbSMatthew Ahrens #endif
2292c55e05cbSMatthew Ahrens 			mdb_printf("\n");
2293a3f829aeSBill Moore 		}
2294a3f829aeSBill Moore 	}
2295a3f829aeSBill Moore 
2296a3f829aeSBill Moore 	if (zpa->zpa_current_depth >= zpa->zpa_max_depth)
2297a3f829aeSBill Moore 		return (WALK_NEXT);
2298ccae0b50Seschrock 
2299a3f829aeSBill Moore 	if (zpa->zpa_type == ZIO_WALK_PARENT)
230028e4da25SMatthew Ahrens 		laddr = addr + mdb_ctf_offsetof_by_name(ZFS_STRUCT "zio",
230128e4da25SMatthew Ahrens 		    "io_parent_list");
2302ccae0b50Seschrock 	else
230328e4da25SMatthew Ahrens 		laddr = addr + mdb_ctf_offsetof_by_name(ZFS_STRUCT "zio",
230428e4da25SMatthew Ahrens 		    "io_child_list");
2305ccae0b50Seschrock 
2306a3f829aeSBill Moore 	zpa->zpa_current_depth++;
2307a3f829aeSBill Moore 	if (mdb_pwalk("list", zio_child_cb, zpa, laddr) != 0) {
2308a3f829aeSBill Moore 		mdb_warn("failed to walk zio_t children at %p\n", laddr);
2309ccae0b50Seschrock 		return (WALK_ERR);
2310ccae0b50Seschrock 	}
2311a3f829aeSBill Moore 	zpa->zpa_current_depth--;
2312ccae0b50Seschrock 
2313ccae0b50Seschrock 	return (WALK_NEXT);
2314ccae0b50Seschrock }
2315ccae0b50Seschrock 
2316a3f829aeSBill Moore /* ARGSUSED */
2317ccae0b50Seschrock static int
2318a3f829aeSBill Moore zio_child_cb(uintptr_t addr, const void *unknown, void *arg)
2319ccae0b50Seschrock {
2320a3f829aeSBill Moore 	zio_link_t zl;
2321a3f829aeSBill Moore 	uintptr_t ziop;
2322a3f829aeSBill Moore 	zio_print_args_t *zpa = arg;
2323a3f829aeSBill Moore 
2324a3f829aeSBill Moore 	if (mdb_vread(&zl, sizeof (zl), addr) == -1) {
2325a3f829aeSBill Moore 		mdb_warn("failed to read zio_link_t at %p", addr);
2326a3f829aeSBill Moore 		return (WALK_ERR);
2327a3f829aeSBill Moore 	}
2328a3f829aeSBill Moore 
2329a3f829aeSBill Moore 	if (zpa->zpa_type == ZIO_WALK_PARENT)
2330a3f829aeSBill Moore 		ziop = (uintptr_t)zl.zl_parent;
2331a3f829aeSBill Moore 	else
2332a3f829aeSBill Moore 		ziop = (uintptr_t)zl.zl_child;
2333a3f829aeSBill Moore 
233469962b56SMatthew Ahrens 	return (zio_print_cb(ziop, zpa));
2335a3f829aeSBill Moore }
2336a3f829aeSBill Moore 
2337a3f829aeSBill Moore /* ARGSUSED */
2338a3f829aeSBill Moore static int
2339a3f829aeSBill Moore zio_print(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
2340a3f829aeSBill Moore {
2341a3f829aeSBill Moore 	zio_print_args_t zpa = { 0 };
2342ccae0b50Seschrock 
2343ccae0b50Seschrock 	if (!(flags & DCMD_ADDRSPEC))
2344ccae0b50Seschrock 		return (DCMD_USAGE);
2345ccae0b50Seschrock 
2346a3f829aeSBill Moore 	if (mdb_getopts(argc, argv,
2347a3f829aeSBill Moore 	    'r', MDB_OPT_SETBITS, INT_MAX, &zpa.zpa_max_depth,
2348a3f829aeSBill Moore 	    'c', MDB_OPT_SETBITS, ZIO_WALK_CHILD, &zpa.zpa_type,
2349a3f829aeSBill Moore 	    'p', MDB_OPT_SETBITS, ZIO_WALK_PARENT, &zpa.zpa_type,
2350a3f829aeSBill Moore 	    NULL) != argc)
2351a3f829aeSBill Moore 		return (DCMD_USAGE);
2352a3f829aeSBill Moore 
2353a3f829aeSBill Moore 	zpa.zpa_flags = flags;
2354a3f829aeSBill Moore 	if (zpa.zpa_max_depth != 0) {
2355a3f829aeSBill Moore 		if (zpa.zpa_type == ZIO_WALK_SELF)
2356a3f829aeSBill Moore 			zpa.zpa_type = ZIO_WALK_CHILD;
2357a3f829aeSBill Moore 	} else if (zpa.zpa_type != ZIO_WALK_SELF) {
2358a3f829aeSBill Moore 		zpa.zpa_min_depth = 1;
2359a3f829aeSBill Moore 		zpa.zpa_max_depth = 1;
2360a3f829aeSBill Moore 	}
2361a3f829aeSBill Moore 
2362c55e05cbSMatthew Ahrens 	if (!(flags & DCMD_PIPE_OUT) && DCMD_HDRSPEC(flags)) {
2363c55e05cbSMatthew Ahrens 		mdb_printf("%<u>%-*s %-5s %-16s %-16s %-12s%</u>\n",
2364c55e05cbSMatthew Ahrens 		    ZIO_MAXWIDTH, "ADDRESS", "TYPE", "STAGE", "WAITER",
2365c55e05cbSMatthew Ahrens 		    "TIME_ELAPSED");
2366c55e05cbSMatthew Ahrens 	}
2367fac3008cSeschrock 
2368c55e05cbSMatthew Ahrens 	if (zio_print_cb(addr, &zpa) != WALK_NEXT)
2369ccae0b50Seschrock 		return (DCMD_ERR);
2370ccae0b50Seschrock 
2371ccae0b50Seschrock 	return (DCMD_OK);
2372ccae0b50Seschrock }
2373ccae0b50Seschrock 
2374ccae0b50Seschrock /*
2375ccae0b50Seschrock  * [addr]::zio_state
2376ccae0b50Seschrock  *
2377ccae0b50Seschrock  * Print a summary of all zio_t structures on the system, or for a particular
2378ccae0b50Seschrock  * pool.  This is equivalent to '::walk zio_root | ::zio'.
2379ccae0b50Seschrock  */
2380ccae0b50Seschrock /*ARGSUSED*/
2381ccae0b50Seschrock static int
2382ccae0b50Seschrock zio_state(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
2383ccae0b50Seschrock {
2384ccae0b50Seschrock 	/*
2385ccae0b50Seschrock 	 * MDB will remember the last address of the pipeline, so if we don't
2386ccae0b50Seschrock 	 * zero this we'll end up trying to walk zio structures for a
2387ccae0b50Seschrock 	 * non-existent spa_t.
2388ccae0b50Seschrock 	 */
2389ccae0b50Seschrock 	if (!(flags & DCMD_ADDRSPEC))
2390ccae0b50Seschrock 		addr = 0;
2391ccae0b50Seschrock 
2392ccae0b50Seschrock 	return (mdb_pwalk_dcmd("zio_root", "zio", argc, argv, addr));
2393ccae0b50Seschrock }
2394ccae0b50Seschrock 
2395dcbf3bd6SGeorge Wilson typedef struct mdb_multilist {
2396dcbf3bd6SGeorge Wilson 	uint64_t ml_num_sublists;
2397dcbf3bd6SGeorge Wilson 	uintptr_t ml_sublists;
2398dcbf3bd6SGeorge Wilson } mdb_multilist_t;
2399dcbf3bd6SGeorge Wilson 
2400dcbf3bd6SGeorge Wilson typedef struct multilist_walk_data {
2401dcbf3bd6SGeorge Wilson 	uint64_t mwd_idx;
2402dcbf3bd6SGeorge Wilson 	mdb_multilist_t mwd_ml;
2403dcbf3bd6SGeorge Wilson } multilist_walk_data_t;
2404dcbf3bd6SGeorge Wilson 
2405dcbf3bd6SGeorge Wilson /* ARGSUSED */
2406dcbf3bd6SGeorge Wilson static int
2407dcbf3bd6SGeorge Wilson multilist_print_cb(uintptr_t addr, const void *unknown, void *arg)
2408dcbf3bd6SGeorge Wilson {
2409dcbf3bd6SGeorge Wilson 	mdb_printf("%#lr\n", addr);
2410dcbf3bd6SGeorge Wilson 	return (WALK_NEXT);
2411dcbf3bd6SGeorge Wilson }
2412dcbf3bd6SGeorge Wilson 
2413dcbf3bd6SGeorge Wilson static int
2414dcbf3bd6SGeorge Wilson multilist_walk_step(mdb_walk_state_t *wsp)
2415dcbf3bd6SGeorge Wilson {
2416dcbf3bd6SGeorge Wilson 	multilist_walk_data_t *mwd = wsp->walk_data;
2417dcbf3bd6SGeorge Wilson 
2418dcbf3bd6SGeorge Wilson 	if (mwd->mwd_idx >= mwd->mwd_ml.ml_num_sublists)
2419dcbf3bd6SGeorge Wilson 		return (WALK_DONE);
2420dcbf3bd6SGeorge Wilson 
2421dcbf3bd6SGeorge Wilson 	wsp->walk_addr = mwd->mwd_ml.ml_sublists +
2422dcbf3bd6SGeorge Wilson 	    mdb_ctf_sizeof_by_name("multilist_sublist_t") * mwd->mwd_idx +
2423dcbf3bd6SGeorge Wilson 	    mdb_ctf_offsetof_by_name("multilist_sublist_t", "mls_list");
2424dcbf3bd6SGeorge Wilson 
2425dcbf3bd6SGeorge Wilson 	mdb_pwalk("list", multilist_print_cb, (void*)NULL, wsp->walk_addr);
2426dcbf3bd6SGeorge Wilson 	mwd->mwd_idx++;
2427dcbf3bd6SGeorge Wilson 
2428dcbf3bd6SGeorge Wilson 	return (WALK_NEXT);
2429dcbf3bd6SGeorge Wilson }
2430dcbf3bd6SGeorge Wilson 
2431dcbf3bd6SGeorge Wilson static int
2432dcbf3bd6SGeorge Wilson multilist_walk_init(mdb_walk_state_t *wsp)
2433dcbf3bd6SGeorge Wilson {
2434dcbf3bd6SGeorge Wilson 	multilist_walk_data_t *mwd;
2435dcbf3bd6SGeorge Wilson 
2436dcbf3bd6SGeorge Wilson 	if (wsp->walk_addr == NULL) {
2437dcbf3bd6SGeorge Wilson 		mdb_warn("must supply address of multilist_t\n");
2438dcbf3bd6SGeorge Wilson 		return (WALK_ERR);
2439dcbf3bd6SGeorge Wilson 	}
2440dcbf3bd6SGeorge Wilson 
2441dcbf3bd6SGeorge Wilson 	mwd = mdb_zalloc(sizeof (multilist_walk_data_t), UM_SLEEP | UM_GC);
2442dcbf3bd6SGeorge Wilson 	if (mdb_ctf_vread(&mwd->mwd_ml, "multilist_t", "mdb_multilist_t",
2443dcbf3bd6SGeorge Wilson 	    wsp->walk_addr, 0) == -1) {
2444dcbf3bd6SGeorge Wilson 		return (WALK_ERR);
2445dcbf3bd6SGeorge Wilson 	}
2446dcbf3bd6SGeorge Wilson 
2447dcbf3bd6SGeorge Wilson 	if (mwd->mwd_ml.ml_num_sublists == 0 ||
2448dcbf3bd6SGeorge Wilson 	    mwd->mwd_ml.ml_sublists == NULL) {
2449dcbf3bd6SGeorge Wilson 		mdb_warn("invalid or uninitialized multilist at %#lx\n",
2450dcbf3bd6SGeorge Wilson 		    wsp->walk_addr);
2451dcbf3bd6SGeorge Wilson 		return (WALK_ERR);
2452dcbf3bd6SGeorge Wilson 	}
2453dcbf3bd6SGeorge Wilson 
2454dcbf3bd6SGeorge Wilson 	wsp->walk_data = mwd;
2455dcbf3bd6SGeorge Wilson 	return (WALK_NEXT);
2456dcbf3bd6SGeorge Wilson }
2457dcbf3bd6SGeorge Wilson 
2458fa9e4066Sahrens typedef struct txg_list_walk_data {
2459fa9e4066Sahrens 	uintptr_t lw_head[TXG_SIZE];
2460fa9e4066Sahrens 	int	lw_txgoff;
2461fa9e4066Sahrens 	int	lw_maxoff;
2462fa9e4066Sahrens 	size_t	lw_offset;
2463fa9e4066Sahrens 	void	*lw_obj;
2464fa9e4066Sahrens } txg_list_walk_data_t;
2465fa9e4066Sahrens 
2466fa9e4066Sahrens static int
2467fa9e4066Sahrens txg_list_walk_init_common(mdb_walk_state_t *wsp, int txg, int maxoff)
2468fa9e4066Sahrens {
2469fa9e4066Sahrens 	txg_list_walk_data_t *lwd;
2470fa9e4066Sahrens 	txg_list_t list;
2471fa9e4066Sahrens 	int i;
2472fa9e4066Sahrens 
2473fa9e4066Sahrens 	lwd = mdb_alloc(sizeof (txg_list_walk_data_t), UM_SLEEP | UM_GC);
2474fa9e4066Sahrens 	if (mdb_vread(&list, sizeof (txg_list_t), wsp->walk_addr) == -1) {
2475fa9e4066Sahrens 		mdb_warn("failed to read txg_list_t at %#lx", wsp->walk_addr);
2476fa9e4066Sahrens 		return (WALK_ERR);
2477fa9e4066Sahrens 	}
2478fa9e4066Sahrens 
2479fa9e4066Sahrens 	for (i = 0; i < TXG_SIZE; i++)
2480fa9e4066Sahrens 		lwd->lw_head[i] = (uintptr_t)list.tl_head[i];
2481fa9e4066Sahrens 	lwd->lw_offset = list.tl_offset;
2482fa9e4066Sahrens 	lwd->lw_obj = mdb_alloc(lwd->lw_offset + sizeof (txg_node_t),
2483fa9e4066Sahrens 	    UM_SLEEP | UM_GC);
2484fa9e4066Sahrens 	lwd->lw_txgoff = txg;
2485fa9e4066Sahrens 	lwd->lw_maxoff = maxoff;
2486fa9e4066Sahrens 
2487fa9e4066Sahrens 	wsp->walk_addr = lwd->lw_head[lwd->lw_txgoff];
2488fa9e4066Sahrens 	wsp->walk_data = lwd;
2489fa9e4066Sahrens 
2490fa9e4066Sahrens 	return (WALK_NEXT);
2491fa9e4066Sahrens }
2492fa9e4066Sahrens 
2493fa9e4066Sahrens static int
2494fa9e4066Sahrens txg_list_walk_init(mdb_walk_state_t *wsp)
2495fa9e4066Sahrens {
2496fa9e4066Sahrens 	return (txg_list_walk_init_common(wsp, 0, TXG_SIZE-1));
2497fa9e4066Sahrens }
2498fa9e4066Sahrens 
2499fa9e4066Sahrens static int
2500fa9e4066Sahrens txg_list0_walk_init(mdb_walk_state_t *wsp)
2501fa9e4066Sahrens {
2502fa9e4066Sahrens 	return (txg_list_walk_init_common(wsp, 0, 0));
2503fa9e4066Sahrens }
2504fa9e4066Sahrens 
2505fa9e4066Sahrens static int
2506fa9e4066Sahrens txg_list1_walk_init(mdb_walk_state_t *wsp)
2507fa9e4066Sahrens {
2508fa9e4066Sahrens 	return (txg_list_walk_init_common(wsp, 1, 1));
2509fa9e4066Sahrens }
2510fa9e4066Sahrens 
2511fa9e4066Sahrens static int
2512fa9e4066Sahrens txg_list2_walk_init(mdb_walk_state_t *wsp)
2513fa9e4066Sahrens {
2514fa9e4066Sahrens 	return (txg_list_walk_init_common(wsp, 2, 2));
2515fa9e4066Sahrens }
2516fa9e4066Sahrens 
2517fa9e4066Sahrens static int
2518fa9e4066Sahrens txg_list3_walk_init(mdb_walk_state_t *wsp)
2519fa9e4066Sahrens {
2520fa9e4066Sahrens 	return (txg_list_walk_init_common(wsp, 3, 3));
2521fa9e4066Sahrens }
2522fa9e4066Sahrens 
2523fa9e4066Sahrens static int
2524fa9e4066Sahrens txg_list_walk_step(mdb_walk_state_t *wsp)
2525fa9e4066Sahrens {
2526fa9e4066Sahrens 	txg_list_walk_data_t *lwd = wsp->walk_data;
2527fa9e4066Sahrens 	uintptr_t addr;
2528fa9e4066Sahrens 	txg_node_t *node;
2529fa9e4066Sahrens 	int status;
2530fa9e4066Sahrens 
2531fa9e4066Sahrens 	while (wsp->walk_addr == NULL && lwd->lw_txgoff < lwd->lw_maxoff) {
2532fa9e4066Sahrens 		lwd->lw_txgoff++;
2533fa9e4066Sahrens 		wsp->walk_addr = lwd->lw_head[lwd->lw_txgoff];
2534fa9e4066Sahrens 	}
2535fa9e4066Sahrens 
2536fa9e4066Sahrens 	if (wsp->walk_addr == NULL)
2537fa9e4066Sahrens 		return (WALK_DONE);
2538fa9e4066Sahrens 
2539fa9e4066Sahrens 	addr = wsp->walk_addr - lwd->lw_offset;
2540fa9e4066Sahrens 
2541fa9e4066Sahrens 	if (mdb_vread(lwd->lw_obj,
2542fa9e4066Sahrens 	    lwd->lw_offset + sizeof (txg_node_t), addr) == -1) {
2543fa9e4066Sahrens 		mdb_warn("failed to read list element at %#lx", addr);
2544fa9e4066Sahrens 		return (WALK_ERR);
2545fa9e4066Sahrens 	}
2546fa9e4066Sahrens 
2547fa9e4066Sahrens 	status = wsp->walk_callback(addr, lwd->lw_obj, wsp->walk_cbdata);
2548fa9e4066Sahrens 	node = (txg_node_t *)((uintptr_t)lwd->lw_obj + lwd->lw_offset);
2549fa9e4066Sahrens 	wsp->walk_addr = (uintptr_t)node->tn_next[lwd->lw_txgoff];
2550fa9e4066Sahrens 
2551fa9e4066Sahrens 	return (status);
2552fa9e4066Sahrens }
2553fa9e4066Sahrens 
2554fa9e4066Sahrens /*
2555fa9e4066Sahrens  * ::walk spa
2556fa9e4066Sahrens  *
2557fa9e4066Sahrens  * Walk all named spa_t structures in the namespace.  This is nothing more than
2558fa9e4066Sahrens  * a layered avl walk.
2559fa9e4066Sahrens  */
2560fa9e4066Sahrens static int
2561fa9e4066Sahrens spa_walk_init(mdb_walk_state_t *wsp)
2562fa9e4066Sahrens {
2563fa9e4066Sahrens 	GElf_Sym sym;
2564fa9e4066Sahrens 
2565fa9e4066Sahrens 	if (wsp->walk_addr != NULL) {
2566fa9e4066Sahrens 		mdb_warn("spa walk only supports global walks\n");
2567fa9e4066Sahrens 		return (WALK_ERR);
2568fa9e4066Sahrens 	}
2569fa9e4066Sahrens 
2570fa9e4066Sahrens 	if (mdb_lookup_by_obj(ZFS_OBJ_NAME, "spa_namespace_avl", &sym) == -1) {
2571fa9e4066Sahrens 		mdb_warn("failed to find symbol 'spa_namespace_avl'");
2572fa9e4066Sahrens 		return (WALK_ERR);
2573fa9e4066Sahrens 	}
2574fa9e4066Sahrens 
2575fa9e4066Sahrens 	wsp->walk_addr = (uintptr_t)sym.st_value;
2576fa9e4066Sahrens 
2577fa9e4066Sahrens 	if (mdb_layered_walk("avl", wsp) == -1) {
2578fa9e4066Sahrens 		mdb_warn("failed to walk 'avl'\n");
2579fa9e4066Sahrens 		return (WALK_ERR);
2580fa9e4066Sahrens 	}
2581fa9e4066Sahrens 
2582fa9e4066Sahrens 	return (WALK_NEXT);
2583fa9e4066Sahrens }
2584fa9e4066Sahrens 
2585fa9e4066Sahrens static int
2586fa9e4066Sahrens spa_walk_step(mdb_walk_state_t *wsp)
2587fa9e4066Sahrens {
258822ce0148SMatthew Ahrens 	return (wsp->walk_callback(wsp->walk_addr, NULL, wsp->walk_cbdata));
2589fa9e4066Sahrens }
2590fa9e4066Sahrens 
2591ccae0b50Seschrock /*
2592ccae0b50Seschrock  * [addr]::walk zio
2593ccae0b50Seschrock  *
2594ccae0b50Seschrock  * Walk all active zio_t structures on the system.  This is simply a layered
2595ccae0b50Seschrock  * walk on top of ::walk zio_cache, with the optional ability to limit the
2596ccae0b50Seschrock  * structures to a particular pool.
2597ccae0b50Seschrock  */
2598ccae0b50Seschrock static int
2599ccae0b50Seschrock zio_walk_init(mdb_walk_state_t *wsp)
2600ccae0b50Seschrock {
2601dee140dfSMatthew Ahrens 	wsp->walk_data = (void *)wsp->walk_addr;
2602ccae0b50Seschrock 
2603ccae0b50Seschrock 	if (mdb_layered_walk("zio_cache", wsp) == -1) {
2604ccae0b50Seschrock 		mdb_warn("failed to walk 'zio_cache'\n");
2605ccae0b50Seschrock 		return (WALK_ERR);
2606ccae0b50Seschrock 	}
2607ccae0b50Seschrock 
2608ccae0b50Seschrock 	return (WALK_NEXT);
2609ccae0b50Seschrock }
2610ccae0b50Seschrock 
2611ccae0b50Seschrock static int
2612ccae0b50Seschrock zio_walk_step(mdb_walk_state_t *wsp)
2613ccae0b50Seschrock {
261428e4da25SMatthew Ahrens 	mdb_zio_t zio;
2615dee140dfSMatthew Ahrens 	uintptr_t spa = (uintptr_t)wsp->walk_data;
2616ccae0b50Seschrock 
261728e4da25SMatthew Ahrens 	if (mdb_ctf_vread(&zio, ZFS_STRUCT "zio", "mdb_zio_t",
261828e4da25SMatthew Ahrens 	    wsp->walk_addr, 0) == -1)
2619ccae0b50Seschrock 		return (WALK_ERR);
2620ccae0b50Seschrock 
2621dee140dfSMatthew Ahrens 	if (spa != 0 && spa != zio.io_spa)
2622ccae0b50Seschrock 		return (WALK_NEXT);
2623ccae0b50Seschrock 
2624ccae0b50Seschrock 	return (wsp->walk_callback(wsp->walk_addr, &zio, wsp->walk_cbdata));
2625ccae0b50Seschrock }
2626ccae0b50Seschrock 
2627ccae0b50Seschrock /*
2628ccae0b50Seschrock  * [addr]::walk zio_root
2629ccae0b50Seschrock  *
2630ccae0b50Seschrock  * Walk only root zio_t structures, optionally for a particular spa_t.
2631ccae0b50Seschrock  */
2632ccae0b50Seschrock static int
2633ccae0b50Seschrock zio_walk_root_step(mdb_walk_state_t *wsp)
2634ccae0b50Seschrock {
263528e4da25SMatthew Ahrens 	mdb_zio_t zio;
2636dee140dfSMatthew Ahrens 	uintptr_t spa = (uintptr_t)wsp->walk_data;
2637ccae0b50Seschrock 
263828e4da25SMatthew Ahrens 	if (mdb_ctf_vread(&zio, ZFS_STRUCT "zio", "mdb_zio_t",
263928e4da25SMatthew Ahrens 	    wsp->walk_addr, 0) == -1)
2640ccae0b50Seschrock 		return (WALK_ERR);
2641ccae0b50Seschrock 
2642dee140dfSMatthew Ahrens 	if (spa != 0 && spa != zio.io_spa)
2643ccae0b50Seschrock 		return (WALK_NEXT);
2644ccae0b50Seschrock 
2645a3f829aeSBill Moore 	/* If the parent list is not empty, ignore */
2646d5ee8a13SMatthew Ahrens 	if (zio.io_parent_list.list_head.list_next !=
264728e4da25SMatthew Ahrens 	    wsp->walk_addr +
264828e4da25SMatthew Ahrens 	    mdb_ctf_offsetof_by_name(ZFS_STRUCT "zio", "io_parent_list") +
264928e4da25SMatthew Ahrens 	    mdb_ctf_offsetof_by_name("struct list", "list_head"))
2650ccae0b50Seschrock 		return (WALK_NEXT);
2651ccae0b50Seschrock 
2652ccae0b50Seschrock 	return (wsp->walk_callback(wsp->walk_addr, &zio, wsp->walk_cbdata));
2653ccae0b50Seschrock }
2654ccae0b50Seschrock 
265588b7b0f2SMatthew Ahrens /*
265688b7b0f2SMatthew Ahrens  * ::zfs_blkstats
265788b7b0f2SMatthew Ahrens  *
26582e4c9986SGeorge Wilson  *	-v	print verbose per-level information
265988b7b0f2SMatthew Ahrens  *
266088b7b0f2SMatthew Ahrens  */
266188b7b0f2SMatthew Ahrens static int
266288b7b0f2SMatthew Ahrens zfs_blkstats(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
266388b7b0f2SMatthew Ahrens {
266488b7b0f2SMatthew Ahrens 	boolean_t verbose = B_FALSE;
266588b7b0f2SMatthew Ahrens 	zfs_all_blkstats_t stats;
266688b7b0f2SMatthew Ahrens 	dmu_object_type_t t;
266788b7b0f2SMatthew Ahrens 	zfs_blkstat_t *tzb;
266888b7b0f2SMatthew Ahrens 	uint64_t ditto;
266988b7b0f2SMatthew Ahrens 	dmu_object_type_info_t dmu_ot[DMU_OT_NUMTYPES + 10];
267088b7b0f2SMatthew Ahrens 	/* +10 in case it grew */
267188b7b0f2SMatthew Ahrens 
267288b7b0f2SMatthew Ahrens 	if (mdb_readvar(&dmu_ot, "dmu_ot") == -1) {
267388b7b0f2SMatthew Ahrens 		mdb_warn("failed to read 'dmu_ot'");
267488b7b0f2SMatthew Ahrens 		return (DCMD_ERR);
267588b7b0f2SMatthew Ahrens 	}
267688b7b0f2SMatthew Ahrens 
267788b7b0f2SMatthew Ahrens 	if (mdb_getopts(argc, argv,
267888b7b0f2SMatthew Ahrens 	    'v', MDB_OPT_SETBITS, TRUE, &verbose,
267988b7b0f2SMatthew Ahrens 	    NULL) != argc)
268088b7b0f2SMatthew Ahrens 		return (DCMD_USAGE);
268188b7b0f2SMatthew Ahrens 
268288b7b0f2SMatthew Ahrens 	if (!(flags & DCMD_ADDRSPEC))
268388b7b0f2SMatthew Ahrens 		return (DCMD_USAGE);
268488b7b0f2SMatthew Ahrens 
268528e4da25SMatthew Ahrens 	if (GETMEMB(addr, "spa", spa_dsl_pool, addr) ||
268628e4da25SMatthew Ahrens 	    GETMEMB(addr, "dsl_pool", dp_blkstats, addr) ||
268788b7b0f2SMatthew Ahrens 	    mdb_vread(&stats, sizeof (zfs_all_blkstats_t), addr) == -1) {
268888b7b0f2SMatthew Ahrens 		mdb_warn("failed to read data at %p;", addr);
268988b7b0f2SMatthew Ahrens 		mdb_printf("maybe no stats? run \"zpool scrub\" first.");
269088b7b0f2SMatthew Ahrens 		return (DCMD_ERR);
269188b7b0f2SMatthew Ahrens 	}
269288b7b0f2SMatthew Ahrens 
2693ad135b5dSChristopher Siden 	tzb = &stats.zab_type[DN_MAX_LEVELS][DMU_OT_TOTAL];
269488b7b0f2SMatthew Ahrens 	if (tzb->zb_gangs != 0) {
269588b7b0f2SMatthew Ahrens 		mdb_printf("Ganged blocks: %llu\n",
269688b7b0f2SMatthew Ahrens 		    (longlong_t)tzb->zb_gangs);
269788b7b0f2SMatthew Ahrens 	}
269888b7b0f2SMatthew Ahrens 
269988b7b0f2SMatthew Ahrens 	ditto = tzb->zb_ditto_2_of_2_samevdev + tzb->zb_ditto_2_of_3_samevdev +
270088b7b0f2SMatthew Ahrens 	    tzb->zb_ditto_3_of_3_samevdev;
270188b7b0f2SMatthew Ahrens 	if (ditto != 0) {
270288b7b0f2SMatthew Ahrens 		mdb_printf("Dittoed blocks on same vdev: %llu\n",
270388b7b0f2SMatthew Ahrens 		    (longlong_t)ditto);
270488b7b0f2SMatthew Ahrens 	}
270588b7b0f2SMatthew Ahrens 
270688b7b0f2SMatthew Ahrens 	mdb_printf("\nBlocks\tLSIZE\tPSIZE\tASIZE"
270788b7b0f2SMatthew Ahrens 	    "\t  avg\t comp\t%%Total\tType\n");
270888b7b0f2SMatthew Ahrens 
2709ad135b5dSChristopher Siden 	for (t = 0; t <= DMU_OT_TOTAL; t++) {
271088b7b0f2SMatthew Ahrens 		char csize[NICENUM_BUFLEN], lsize[NICENUM_BUFLEN];
271188b7b0f2SMatthew Ahrens 		char psize[NICENUM_BUFLEN], asize[NICENUM_BUFLEN];
271288b7b0f2SMatthew Ahrens 		char avg[NICENUM_BUFLEN];
271388b7b0f2SMatthew Ahrens 		char comp[NICENUM_BUFLEN], pct[NICENUM_BUFLEN];
271488b7b0f2SMatthew Ahrens 		char typename[64];
271588b7b0f2SMatthew Ahrens 		int l;
271688b7b0f2SMatthew Ahrens 
271788b7b0f2SMatthew Ahrens 
271888b7b0f2SMatthew Ahrens 		if (t == DMU_OT_DEFERRED)
271988b7b0f2SMatthew Ahrens 			strcpy(typename, "deferred free");
2720ad135b5dSChristopher Siden 		else if (t == DMU_OT_OTHER)
2721ad135b5dSChristopher Siden 			strcpy(typename, "other");
272288b7b0f2SMatthew Ahrens 		else if (t == DMU_OT_TOTAL)
272388b7b0f2SMatthew Ahrens 			strcpy(typename, "Total");
272488b7b0f2SMatthew Ahrens 		else if (mdb_readstr(typename, sizeof (typename),
272588b7b0f2SMatthew Ahrens 		    (uintptr_t)dmu_ot[t].ot_name) == -1) {
272688b7b0f2SMatthew Ahrens 			mdb_warn("failed to read type name");
272788b7b0f2SMatthew Ahrens 			return (DCMD_ERR);
272888b7b0f2SMatthew Ahrens 		}
272988b7b0f2SMatthew Ahrens 
273088b7b0f2SMatthew Ahrens 		if (stats.zab_type[DN_MAX_LEVELS][t].zb_asize == 0)
273188b7b0f2SMatthew Ahrens 			continue;
273288b7b0f2SMatthew Ahrens 
273388b7b0f2SMatthew Ahrens 		for (l = -1; l < DN_MAX_LEVELS; l++) {
273488b7b0f2SMatthew Ahrens 			int level = (l == -1 ? DN_MAX_LEVELS : l);
273588b7b0f2SMatthew Ahrens 			zfs_blkstat_t *zb = &stats.zab_type[level][t];
273688b7b0f2SMatthew Ahrens 
273788b7b0f2SMatthew Ahrens 			if (zb->zb_asize == 0)
273888b7b0f2SMatthew Ahrens 				continue;
273988b7b0f2SMatthew Ahrens 
274088b7b0f2SMatthew Ahrens 			/*
274188b7b0f2SMatthew Ahrens 			 * Don't print each level unless requested.
274288b7b0f2SMatthew Ahrens 			 */
274388b7b0f2SMatthew Ahrens 			if (!verbose && level != DN_MAX_LEVELS)
274488b7b0f2SMatthew Ahrens 				continue;
274588b7b0f2SMatthew Ahrens 
274688b7b0f2SMatthew Ahrens 			/*
274788b7b0f2SMatthew Ahrens 			 * If all the space is level 0, don't print the
274888b7b0f2SMatthew Ahrens 			 * level 0 separately.
274988b7b0f2SMatthew Ahrens 			 */
275088b7b0f2SMatthew Ahrens 			if (level == 0 && zb->zb_asize ==
275188b7b0f2SMatthew Ahrens 			    stats.zab_type[DN_MAX_LEVELS][t].zb_asize)
275288b7b0f2SMatthew Ahrens 				continue;
275388b7b0f2SMatthew Ahrens 
275488b7b0f2SMatthew Ahrens 			mdb_nicenum(zb->zb_count, csize);
275588b7b0f2SMatthew Ahrens 			mdb_nicenum(zb->zb_lsize, lsize);
275688b7b0f2SMatthew Ahrens 			mdb_nicenum(zb->zb_psize, psize);
275788b7b0f2SMatthew Ahrens 			mdb_nicenum(zb->zb_asize, asize);
275888b7b0f2SMatthew Ahrens 			mdb_nicenum(zb->zb_asize / zb->zb_count, avg);
2759ff64c0f7SMatthew Ahrens 			(void) snprintfrac(comp, NICENUM_BUFLEN,
2760ff64c0f7SMatthew Ahrens 			    zb->zb_lsize, zb->zb_psize, 2);
2761ff64c0f7SMatthew Ahrens 			(void) snprintfrac(pct, NICENUM_BUFLEN,
2762ff64c0f7SMatthew Ahrens 			    100 * zb->zb_asize, tzb->zb_asize, 2);
276388b7b0f2SMatthew Ahrens 
276488b7b0f2SMatthew Ahrens 			mdb_printf("%6s\t%5s\t%5s\t%5s\t%5s"
276588b7b0f2SMatthew Ahrens 			    "\t%5s\t%6s\t",
276688b7b0f2SMatthew Ahrens 			    csize, lsize, psize, asize, avg, comp, pct);
276788b7b0f2SMatthew Ahrens 
276888b7b0f2SMatthew Ahrens 			if (level == DN_MAX_LEVELS)
276988b7b0f2SMatthew Ahrens 				mdb_printf("%s\n", typename);
277088b7b0f2SMatthew Ahrens 			else
277188b7b0f2SMatthew Ahrens 				mdb_printf("  L%d %s\n",
277288b7b0f2SMatthew Ahrens 				    level, typename);
277388b7b0f2SMatthew Ahrens 		}
277488b7b0f2SMatthew Ahrens 	}
277588b7b0f2SMatthew Ahrens 
277688b7b0f2SMatthew Ahrens 	return (DCMD_OK);
277788b7b0f2SMatthew Ahrens }
277888b7b0f2SMatthew Ahrens 
2779d5ee8a13SMatthew Ahrens typedef struct mdb_reference {
2780d5ee8a13SMatthew Ahrens 	uintptr_t ref_holder;
2781d5ee8a13SMatthew Ahrens 	uintptr_t ref_removed;
2782d5ee8a13SMatthew Ahrens 	uint64_t ref_number;
2783d5ee8a13SMatthew Ahrens } mdb_reference_t;
2784d5ee8a13SMatthew Ahrens 
27859966ca11SMatthew Ahrens /* ARGSUSED */
27869966ca11SMatthew Ahrens static int
27879966ca11SMatthew Ahrens reference_cb(uintptr_t addr, const void *ignored, void *arg)
27889966ca11SMatthew Ahrens {
2789d5ee8a13SMatthew Ahrens 	mdb_reference_t ref;
27903f9d6ad7SLin Ling 	boolean_t holder_is_str = B_FALSE;
27919966ca11SMatthew Ahrens 	char holder_str[128];
27929966ca11SMatthew Ahrens 	boolean_t removed = (boolean_t)arg;
27939966ca11SMatthew Ahrens 
2794d5ee8a13SMatthew Ahrens 	if (mdb_ctf_vread(&ref, "reference_t", "mdb_reference_t", addr,
2795d5ee8a13SMatthew Ahrens 	    0) == -1)
2796d5ee8a13SMatthew Ahrens 		return (DCMD_ERR);
27979966ca11SMatthew Ahrens 
2798d5ee8a13SMatthew Ahrens 	if (mdb_readstr(holder_str, sizeof (holder_str),
2799d5ee8a13SMatthew Ahrens 	    ref.ref_holder) != -1)
28003f9d6ad7SLin Ling 		holder_is_str = strisprint(holder_str);
28019966ca11SMatthew Ahrens 
28029966ca11SMatthew Ahrens 	if (removed)
28039966ca11SMatthew Ahrens 		mdb_printf("removed ");
28049966ca11SMatthew Ahrens 	mdb_printf("reference ");
2805d5ee8a13SMatthew Ahrens 	if (ref.ref_number != 1)
2806d5ee8a13SMatthew Ahrens 		mdb_printf("with count=%llu ", ref.ref_number);
2807d5ee8a13SMatthew Ahrens 	mdb_printf("with tag %lx", ref.ref_holder);
28089966ca11SMatthew Ahrens 	if (holder_is_str)
28099966ca11SMatthew Ahrens 		mdb_printf(" \"%s\"", holder_str);
28109966ca11SMatthew Ahrens 	mdb_printf(", held at:\n");
28119966ca11SMatthew Ahrens 
28129966ca11SMatthew Ahrens 	(void) mdb_call_dcmd("whatis", addr, DCMD_ADDRSPEC, 0, NULL);
28139966ca11SMatthew Ahrens 
28149966ca11SMatthew Ahrens 	if (removed) {
28159966ca11SMatthew Ahrens 		mdb_printf("removed at:\n");
2816d5ee8a13SMatthew Ahrens 		(void) mdb_call_dcmd("whatis", ref.ref_removed,
28179966ca11SMatthew Ahrens 		    DCMD_ADDRSPEC, 0, NULL);
28189966ca11SMatthew Ahrens 	}
28199966ca11SMatthew Ahrens 
28209966ca11SMatthew Ahrens 	mdb_printf("\n");
28219966ca11SMatthew Ahrens 
28229966ca11SMatthew Ahrens 	return (WALK_NEXT);
28239966ca11SMatthew Ahrens }
28249966ca11SMatthew Ahrens 
2825d5ee8a13SMatthew Ahrens typedef struct mdb_refcount {
2826d5ee8a13SMatthew Ahrens 	uint64_t rc_count;
2827d5ee8a13SMatthew Ahrens } mdb_refcount_t;
2828d5ee8a13SMatthew Ahrens 
2829d5ee8a13SMatthew Ahrens typedef struct mdb_refcount_removed {
2830d5ee8a13SMatthew Ahrens 	uint64_t rc_removed_count;
2831d5ee8a13SMatthew Ahrens } mdb_refcount_removed_t;
2832d5ee8a13SMatthew Ahrens 
2833d5ee8a13SMatthew Ahrens typedef struct mdb_refcount_tracked {
2834d5ee8a13SMatthew Ahrens 	boolean_t rc_tracked;
2835d5ee8a13SMatthew Ahrens } mdb_refcount_tracked_t;
2836d5ee8a13SMatthew Ahrens 
28379966ca11SMatthew Ahrens /* ARGSUSED */
28389966ca11SMatthew Ahrens static int
28399966ca11SMatthew Ahrens refcount(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
28409966ca11SMatthew Ahrens {
2841d5ee8a13SMatthew Ahrens 	mdb_refcount_t rc;
2842d5ee8a13SMatthew Ahrens 	mdb_refcount_removed_t rcr;
2843d5ee8a13SMatthew Ahrens 	mdb_refcount_tracked_t rct;
2844d5ee8a13SMatthew Ahrens 	int off;
284528e4da25SMatthew Ahrens 	boolean_t released = B_FALSE;
28469966ca11SMatthew Ahrens 
28479966ca11SMatthew Ahrens 	if (!(flags & DCMD_ADDRSPEC))
28489966ca11SMatthew Ahrens 		return (DCMD_USAGE);
28499966ca11SMatthew Ahrens 
285028e4da25SMatthew Ahrens 	if (mdb_getopts(argc, argv,
285128e4da25SMatthew Ahrens 	    'r', MDB_OPT_SETBITS, B_TRUE, &released,
285228e4da25SMatthew Ahrens 	    NULL) != argc)
285328e4da25SMatthew Ahrens 		return (DCMD_USAGE);
285428e4da25SMatthew Ahrens 
2855d5ee8a13SMatthew Ahrens 	if (mdb_ctf_vread(&rc, "refcount_t", "mdb_refcount_t", addr,
2856d5ee8a13SMatthew Ahrens 	    0) == -1)
28579966ca11SMatthew Ahrens 		return (DCMD_ERR);
28589966ca11SMatthew Ahrens 
2859d5ee8a13SMatthew Ahrens 	if (mdb_ctf_vread(&rcr, "refcount_t", "mdb_refcount_removed_t", addr,
2860d5ee8a13SMatthew Ahrens 	    MDB_CTF_VREAD_QUIET) == -1) {
2861d5ee8a13SMatthew Ahrens 		mdb_printf("refcount_t at %p has %llu holds (untracked)\n",
2862d5ee8a13SMatthew Ahrens 		    addr, (longlong_t)rc.rc_count);
286328e4da25SMatthew Ahrens 		return (DCMD_OK);
286428e4da25SMatthew Ahrens 	}
286528e4da25SMatthew Ahrens 
2866d5ee8a13SMatthew Ahrens 	if (mdb_ctf_vread(&rct, "refcount_t", "mdb_refcount_tracked_t", addr,
2867d5ee8a13SMatthew Ahrens 	    MDB_CTF_VREAD_QUIET) == -1) {
2868d5ee8a13SMatthew Ahrens 		/* If this is an old target, it might be tracked. */
2869d5ee8a13SMatthew Ahrens 		rct.rc_tracked = B_TRUE;
2870d5ee8a13SMatthew Ahrens 	}
2871d5ee8a13SMatthew Ahrens 
28729966ca11SMatthew Ahrens 	mdb_printf("refcount_t at %p has %llu current holds, "
28739966ca11SMatthew Ahrens 	    "%llu recently released holds\n",
2874d5ee8a13SMatthew Ahrens 	    addr, (longlong_t)rc.rc_count, (longlong_t)rcr.rc_removed_count);
28759966ca11SMatthew Ahrens 
2876d5ee8a13SMatthew Ahrens 	if (rct.rc_tracked && rc.rc_count > 0)
28779966ca11SMatthew Ahrens 		mdb_printf("current holds:\n");
2878d5ee8a13SMatthew Ahrens 	off = mdb_ctf_offsetof_by_name("refcount_t", "rc_list");
2879d5ee8a13SMatthew Ahrens 	if (off == -1)
28809966ca11SMatthew Ahrens 		return (DCMD_ERR);
2881d5ee8a13SMatthew Ahrens 	mdb_pwalk("list", reference_cb, (void*)B_FALSE, addr + off);
2882d5ee8a13SMatthew Ahrens 
2883d5ee8a13SMatthew Ahrens 	if (released && rcr.rc_removed_count > 0) {
2884d5ee8a13SMatthew Ahrens 		mdb_printf("released holds:\n");
28859966ca11SMatthew Ahrens 
2886d5ee8a13SMatthew Ahrens 		off = mdb_ctf_offsetof_by_name("refcount_t", "rc_removed");
2887d5ee8a13SMatthew Ahrens 		if (off == -1)
288828e4da25SMatthew Ahrens 			return (DCMD_ERR);
2889421ff020SPrakash Surya 		mdb_pwalk("list", reference_cb, (void*)B_TRUE, addr + off);
289028e4da25SMatthew Ahrens 	}
28919966ca11SMatthew Ahrens 
28929966ca11SMatthew Ahrens 	return (DCMD_OK);
28939966ca11SMatthew Ahrens }
28949966ca11SMatthew Ahrens 
28950a586ceaSMark Shellenbaum /* ARGSUSED */
28960a586ceaSMark Shellenbaum static int
28970a586ceaSMark Shellenbaum sa_attr_table(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
28980a586ceaSMark Shellenbaum {
28990a586ceaSMark Shellenbaum 	sa_attr_table_t *table;
29000a586ceaSMark Shellenbaum 	sa_os_t sa_os;
29010a586ceaSMark Shellenbaum 	char *name;
29020a586ceaSMark Shellenbaum 	int i;
29030a586ceaSMark Shellenbaum 
29040a586ceaSMark Shellenbaum 	if (mdb_vread(&sa_os, sizeof (sa_os_t), addr) == -1) {
29050a586ceaSMark Shellenbaum 		mdb_warn("failed to read sa_os at %p", addr);
29060a586ceaSMark Shellenbaum 		return (DCMD_ERR);
29070a586ceaSMark Shellenbaum 	}
29080a586ceaSMark Shellenbaum 
29090a586ceaSMark Shellenbaum 	table = mdb_alloc(sizeof (sa_attr_table_t) * sa_os.sa_num_attrs,
29100a586ceaSMark Shellenbaum 	    UM_SLEEP | UM_GC);
29110a586ceaSMark Shellenbaum 	name = mdb_alloc(MAXPATHLEN, UM_SLEEP | UM_GC);
29120a586ceaSMark Shellenbaum 
29130a586ceaSMark Shellenbaum 	if (mdb_vread(table, sizeof (sa_attr_table_t) * sa_os.sa_num_attrs,
29140a586ceaSMark Shellenbaum 	    (uintptr_t)sa_os.sa_attr_table) == -1) {
29150a586ceaSMark Shellenbaum 		mdb_warn("failed to read sa_os at %p", addr);
29160a586ceaSMark Shellenbaum 		return (DCMD_ERR);
29170a586ceaSMark Shellenbaum 	}
29180a586ceaSMark Shellenbaum 
29190a586ceaSMark Shellenbaum 	mdb_printf("%<u>%-10s %-10s %-10s %-10s %s%</u>\n",
29200a586ceaSMark Shellenbaum 	    "ATTR ID", "REGISTERED", "LENGTH", "BSWAP", "NAME");
29210a586ceaSMark Shellenbaum 	for (i = 0; i != sa_os.sa_num_attrs; i++) {
29220a586ceaSMark Shellenbaum 		mdb_readstr(name, MAXPATHLEN, (uintptr_t)table[i].sa_name);
29230a586ceaSMark Shellenbaum 		mdb_printf("%5x   %8x %8x %8x          %-s\n",
29240a586ceaSMark Shellenbaum 		    (int)table[i].sa_attr, (int)table[i].sa_registered,
29250a586ceaSMark Shellenbaum 		    (int)table[i].sa_length, table[i].sa_byteswap, name);
29260a586ceaSMark Shellenbaum 	}
29270a586ceaSMark Shellenbaum 
29280a586ceaSMark Shellenbaum 	return (DCMD_OK);
29290a586ceaSMark Shellenbaum }
29300a586ceaSMark Shellenbaum 
29310a586ceaSMark Shellenbaum static int
29320a586ceaSMark Shellenbaum sa_get_off_table(uintptr_t addr, uint32_t **off_tab, int attr_count)
29330a586ceaSMark Shellenbaum {
29340a586ceaSMark Shellenbaum 	uintptr_t idx_table;
29350a586ceaSMark Shellenbaum 
293628e4da25SMatthew Ahrens 	if (GETMEMB(addr, "sa_idx_tab", sa_idx_tab, idx_table)) {
29370a586ceaSMark Shellenbaum 		mdb_printf("can't find offset table in sa_idx_tab\n");
29380a586ceaSMark Shellenbaum 		return (-1);
29390a586ceaSMark Shellenbaum 	}
29400a586ceaSMark Shellenbaum 
29410a586ceaSMark Shellenbaum 	*off_tab = mdb_alloc(attr_count * sizeof (uint32_t),
29420a586ceaSMark Shellenbaum 	    UM_SLEEP | UM_GC);
29430a586ceaSMark Shellenbaum 
29440a586ceaSMark Shellenbaum 	if (mdb_vread(*off_tab,
29450a586ceaSMark Shellenbaum 	    attr_count * sizeof (uint32_t), idx_table) == -1) {
29460a586ceaSMark Shellenbaum 		mdb_warn("failed to attribute offset table %p", idx_table);
29470a586ceaSMark Shellenbaum 		return (-1);
29480a586ceaSMark Shellenbaum 	}
29490a586ceaSMark Shellenbaum 
29500a586ceaSMark Shellenbaum 	return (DCMD_OK);
29510a586ceaSMark Shellenbaum }
29520a586ceaSMark Shellenbaum 
29530a586ceaSMark Shellenbaum /*ARGSUSED*/
29540a586ceaSMark Shellenbaum static int
29550a586ceaSMark Shellenbaum sa_attr_print(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
29560a586ceaSMark Shellenbaum {
29570a586ceaSMark Shellenbaum 	uint32_t *offset_tab;
29580a586ceaSMark Shellenbaum 	int attr_count;
29590a586ceaSMark Shellenbaum 	uint64_t attr_id;
29600a586ceaSMark Shellenbaum 	uintptr_t attr_addr;
29610a586ceaSMark Shellenbaum 	uintptr_t bonus_tab, spill_tab;
29620a586ceaSMark Shellenbaum 	uintptr_t db_bonus, db_spill;
29630a586ceaSMark Shellenbaum 	uintptr_t os, os_sa;
29640a586ceaSMark Shellenbaum 	uintptr_t db_data;
29650a586ceaSMark Shellenbaum 
29660a586ceaSMark Shellenbaum 	if (argc != 1)
29670a586ceaSMark Shellenbaum 		return (DCMD_USAGE);
29680a586ceaSMark Shellenbaum 
29690a586ceaSMark Shellenbaum 	if (argv[0].a_type == MDB_TYPE_STRING)
29700a586ceaSMark Shellenbaum 		attr_id = mdb_strtoull(argv[0].a_un.a_str);
29710a586ceaSMark Shellenbaum 	else
29720a586ceaSMark Shellenbaum 		return (DCMD_USAGE);
29730a586ceaSMark Shellenbaum 
297428e4da25SMatthew Ahrens 	if (GETMEMB(addr, "sa_handle", sa_bonus_tab, bonus_tab) ||
297528e4da25SMatthew Ahrens 	    GETMEMB(addr, "sa_handle", sa_spill_tab, spill_tab) ||
297628e4da25SMatthew Ahrens 	    GETMEMB(addr, "sa_handle", sa_os, os) ||
297728e4da25SMatthew Ahrens 	    GETMEMB(addr, "sa_handle", sa_bonus, db_bonus) ||
297828e4da25SMatthew Ahrens 	    GETMEMB(addr, "sa_handle", sa_spill, db_spill)) {
29790a586ceaSMark Shellenbaum 		mdb_printf("Can't find necessary information in sa_handle "
29800a586ceaSMark Shellenbaum 		    "in sa_handle\n");
29810a586ceaSMark Shellenbaum 		return (DCMD_ERR);
29820a586ceaSMark Shellenbaum 	}
29830a586ceaSMark Shellenbaum 
298428e4da25SMatthew Ahrens 	if (GETMEMB(os, "objset", os_sa, os_sa)) {
29850a586ceaSMark Shellenbaum 		mdb_printf("Can't find os_sa in objset\n");
29860a586ceaSMark Shellenbaum 		return (DCMD_ERR);
29870a586ceaSMark Shellenbaum 	}
29880a586ceaSMark Shellenbaum 
298928e4da25SMatthew Ahrens 	if (GETMEMB(os_sa, "sa_os", sa_num_attrs, attr_count)) {
29900a586ceaSMark Shellenbaum 		mdb_printf("Can't find sa_num_attrs\n");
29910a586ceaSMark Shellenbaum 		return (DCMD_ERR);
29920a586ceaSMark Shellenbaum 	}
29930a586ceaSMark Shellenbaum 
29940a586ceaSMark Shellenbaum 	if (attr_id > attr_count) {
29950a586ceaSMark Shellenbaum 		mdb_printf("attribute id number is out of range\n");
29960a586ceaSMark Shellenbaum 		return (DCMD_ERR);
29970a586ceaSMark Shellenbaum 	}
29980a586ceaSMark Shellenbaum 
29990a586ceaSMark Shellenbaum 	if (bonus_tab) {
30000a586ceaSMark Shellenbaum 		if (sa_get_off_table(bonus_tab, &offset_tab,
30010a586ceaSMark Shellenbaum 		    attr_count) == -1) {
30020a586ceaSMark Shellenbaum 			return (DCMD_ERR);
30030a586ceaSMark Shellenbaum 		}
30040a586ceaSMark Shellenbaum 
300528e4da25SMatthew Ahrens 		if (GETMEMB(db_bonus, "dmu_buf", db_data, db_data)) {
30060a586ceaSMark Shellenbaum 			mdb_printf("can't find db_data in bonus dbuf\n");
30070a586ceaSMark Shellenbaum 			return (DCMD_ERR);
30080a586ceaSMark Shellenbaum 		}
30090a586ceaSMark Shellenbaum 	}
30100a586ceaSMark Shellenbaum 
30110a586ceaSMark Shellenbaum 	if (bonus_tab && !TOC_ATTR_PRESENT(offset_tab[attr_id]) &&
30120a586ceaSMark Shellenbaum 	    spill_tab == NULL) {
30130a586ceaSMark Shellenbaum 		mdb_printf("Attribute does not exist\n");
30140a586ceaSMark Shellenbaum 		return (DCMD_ERR);
30150a586ceaSMark Shellenbaum 	} else if (!TOC_ATTR_PRESENT(offset_tab[attr_id]) && spill_tab) {
30160a586ceaSMark Shellenbaum 		if (sa_get_off_table(spill_tab, &offset_tab,
30170a586ceaSMark Shellenbaum 		    attr_count) == -1) {
30180a586ceaSMark Shellenbaum 			return (DCMD_ERR);
30190a586ceaSMark Shellenbaum 		}
302028e4da25SMatthew Ahrens 		if (GETMEMB(db_spill, "dmu_buf", db_data, db_data)) {
30210a586ceaSMark Shellenbaum 			mdb_printf("can't find db_data in spill dbuf\n");
30220a586ceaSMark Shellenbaum 			return (DCMD_ERR);
30230a586ceaSMark Shellenbaum 		}
30240a586ceaSMark Shellenbaum 		if (!TOC_ATTR_PRESENT(offset_tab[attr_id])) {
30250a586ceaSMark Shellenbaum 			mdb_printf("Attribute does not exist\n");
30260a586ceaSMark Shellenbaum 			return (DCMD_ERR);
30270a586ceaSMark Shellenbaum 		}
30280a586ceaSMark Shellenbaum 	}
30290a586ceaSMark Shellenbaum 	attr_addr = db_data + TOC_OFF(offset_tab[attr_id]);
30300a586ceaSMark Shellenbaum 	mdb_printf("%p\n", attr_addr);
30310a586ceaSMark Shellenbaum 	return (DCMD_OK);
30320a586ceaSMark Shellenbaum }
30330a586ceaSMark Shellenbaum 
30340a586ceaSMark Shellenbaum /* ARGSUSED */
30350a586ceaSMark Shellenbaum static int
30360a586ceaSMark Shellenbaum zfs_ace_print_common(uintptr_t addr, uint_t flags,
30370a586ceaSMark Shellenbaum     uint64_t id, uint32_t access_mask, uint16_t ace_flags,
30380a586ceaSMark Shellenbaum     uint16_t ace_type, int verbose)
30390a586ceaSMark Shellenbaum {
30400a586ceaSMark Shellenbaum 	if (DCMD_HDRSPEC(flags) && !verbose)
30410a586ceaSMark Shellenbaum 		mdb_printf("%<u>%-?s %-8s %-8s %-8s %s%</u>\n",
30420a586ceaSMark Shellenbaum 		    "ADDR", "FLAGS", "MASK", "TYPE", "ID");
30430a586ceaSMark Shellenbaum 
30440a586ceaSMark Shellenbaum 	if (!verbose) {
30450a586ceaSMark Shellenbaum 		mdb_printf("%0?p %-8x %-8x %-8x %-llx\n", addr,
30460a586ceaSMark Shellenbaum 		    ace_flags, access_mask, ace_type, id);
30470a586ceaSMark Shellenbaum 		return (DCMD_OK);
30480a586ceaSMark Shellenbaum 	}
30490a586ceaSMark Shellenbaum 
30500a586ceaSMark Shellenbaum 	switch (ace_flags & ACE_TYPE_FLAGS) {
30510a586ceaSMark Shellenbaum 	case ACE_OWNER:
30520a586ceaSMark Shellenbaum 		mdb_printf("owner@:");
30530a586ceaSMark Shellenbaum 		break;
30540a586ceaSMark Shellenbaum 	case (ACE_IDENTIFIER_GROUP | ACE_GROUP):
30550a586ceaSMark Shellenbaum 		mdb_printf("group@:");
30560a586ceaSMark Shellenbaum 		break;
30570a586ceaSMark Shellenbaum 	case ACE_EVERYONE:
30580a586ceaSMark Shellenbaum 		mdb_printf("everyone@:");
30590a586ceaSMark Shellenbaum 		break;
30600a586ceaSMark Shellenbaum 	case ACE_IDENTIFIER_GROUP:
30610a586ceaSMark Shellenbaum 		mdb_printf("group:%llx:", (u_longlong_t)id);
30620a586ceaSMark Shellenbaum 		break;
30630a586ceaSMark Shellenbaum 	case 0: /* User entry */
30640a586ceaSMark Shellenbaum 		mdb_printf("user:%llx:", (u_longlong_t)id);
30650a586ceaSMark Shellenbaum 		break;
30660a586ceaSMark Shellenbaum 	}
30670a586ceaSMark Shellenbaum 
30680a586ceaSMark Shellenbaum 	/* print out permission mask */
30690a586ceaSMark Shellenbaum 	if (access_mask & ACE_READ_DATA)
30700a586ceaSMark Shellenbaum 		mdb_printf("r");
30710a586ceaSMark Shellenbaum 	else
30720a586ceaSMark Shellenbaum 		mdb_printf("-");
30730a586ceaSMark Shellenbaum 	if (access_mask & ACE_WRITE_DATA)
30740a586ceaSMark Shellenbaum 		mdb_printf("w");
30750a586ceaSMark Shellenbaum 	else
30760a586ceaSMark Shellenbaum 		mdb_printf("-");
30770a586ceaSMark Shellenbaum 	if (access_mask & ACE_EXECUTE)
30780a586ceaSMark Shellenbaum 		mdb_printf("x");
30790a586ceaSMark Shellenbaum 	else
30800a586ceaSMark Shellenbaum 		mdb_printf("-");
30810a586ceaSMark Shellenbaum 	if (access_mask & ACE_APPEND_DATA)
30820a586ceaSMark Shellenbaum 		mdb_printf("p");
30830a586ceaSMark Shellenbaum 	else
30840a586ceaSMark Shellenbaum 		mdb_printf("-");
30850a586ceaSMark Shellenbaum 	if (access_mask & ACE_DELETE)
30860a586ceaSMark Shellenbaum 		mdb_printf("d");
30870a586ceaSMark Shellenbaum 	else
30880a586ceaSMark Shellenbaum 		mdb_printf("-");
30890a586ceaSMark Shellenbaum 	if (access_mask & ACE_DELETE_CHILD)
30900a586ceaSMark Shellenbaum 		mdb_printf("D");
30910a586ceaSMark Shellenbaum 	else
30920a586ceaSMark Shellenbaum 		mdb_printf("-");
30930a586ceaSMark Shellenbaum 	if (access_mask & ACE_READ_ATTRIBUTES)
30940a586ceaSMark Shellenbaum 		mdb_printf("a");
30950a586ceaSMark Shellenbaum 	else
30960a586ceaSMark Shellenbaum 		mdb_printf("-");
30970a586ceaSMark Shellenbaum 	if (access_mask & ACE_WRITE_ATTRIBUTES)
30980a586ceaSMark Shellenbaum 		mdb_printf("A");
30990a586ceaSMark Shellenbaum 	else
31000a586ceaSMark Shellenbaum 		mdb_printf("-");
31010a586ceaSMark Shellenbaum 	if (access_mask & ACE_READ_NAMED_ATTRS)
31020a586ceaSMark Shellenbaum 		mdb_printf("R");
31030a586ceaSMark Shellenbaum 	else
31040a586ceaSMark Shellenbaum 		mdb_printf("-");
31050a586ceaSMark Shellenbaum 	if (access_mask & ACE_WRITE_NAMED_ATTRS)
31060a586ceaSMark Shellenbaum 		mdb_printf("W");
31070a586ceaSMark Shellenbaum 	else
31080a586ceaSMark Shellenbaum 		mdb_printf("-");
31090a586ceaSMark Shellenbaum 	if (access_mask & ACE_READ_ACL)
31100a586ceaSMark Shellenbaum 		mdb_printf("c");
31110a586ceaSMark Shellenbaum 	else
31120a586ceaSMark Shellenbaum 		mdb_printf("-");
31130a586ceaSMark Shellenbaum 	if (access_mask & ACE_WRITE_ACL)
31140a586ceaSMark Shellenbaum 		mdb_printf("C");
31150a586ceaSMark Shellenbaum 	else
31160a586ceaSMark Shellenbaum 		mdb_printf("-");
31170a586ceaSMark Shellenbaum 	if (access_mask & ACE_WRITE_OWNER)
31180a586ceaSMark Shellenbaum 		mdb_printf("o");
31190a586ceaSMark Shellenbaum 	else
31200a586ceaSMark Shellenbaum 		mdb_printf("-");
31210a586ceaSMark Shellenbaum 	if (access_mask & ACE_SYNCHRONIZE)
31220a586ceaSMark Shellenbaum 		mdb_printf("s");
31230a586ceaSMark Shellenbaum 	else
31240a586ceaSMark Shellenbaum 		mdb_printf("-");
31250a586ceaSMark Shellenbaum 
31260a586ceaSMark Shellenbaum 	mdb_printf(":");
31270a586ceaSMark Shellenbaum 
31280a586ceaSMark Shellenbaum 	/* Print out inheritance flags */
31290a586ceaSMark Shellenbaum 	if (ace_flags & ACE_FILE_INHERIT_ACE)
31300a586ceaSMark Shellenbaum 		mdb_printf("f");
31310a586ceaSMark Shellenbaum 	else
31320a586ceaSMark Shellenbaum 		mdb_printf("-");
31330a586ceaSMark Shellenbaum 	if (ace_flags & ACE_DIRECTORY_INHERIT_ACE)
31340a586ceaSMark Shellenbaum 		mdb_printf("d");
31350a586ceaSMark Shellenbaum 	else
31360a586ceaSMark Shellenbaum 		mdb_printf("-");
31370a586ceaSMark Shellenbaum 	if (ace_flags & ACE_INHERIT_ONLY_ACE)
31380a586ceaSMark Shellenbaum 		mdb_printf("i");
31390a586ceaSMark Shellenbaum 	else
31400a586ceaSMark Shellenbaum 		mdb_printf("-");
31410a586ceaSMark Shellenbaum 	if (ace_flags & ACE_NO_PROPAGATE_INHERIT_ACE)
31420a586ceaSMark Shellenbaum 		mdb_printf("n");
31430a586ceaSMark Shellenbaum 	else
31440a586ceaSMark Shellenbaum 		mdb_printf("-");
31450a586ceaSMark Shellenbaum 	if (ace_flags & ACE_SUCCESSFUL_ACCESS_ACE_FLAG)
31460a586ceaSMark Shellenbaum 		mdb_printf("S");
31470a586ceaSMark Shellenbaum 	else
31480a586ceaSMark Shellenbaum 		mdb_printf("-");
31490a586ceaSMark Shellenbaum 	if (ace_flags & ACE_FAILED_ACCESS_ACE_FLAG)
31500a586ceaSMark Shellenbaum 		mdb_printf("F");
31510a586ceaSMark Shellenbaum 	else
31520a586ceaSMark Shellenbaum 		mdb_printf("-");
31530a586ceaSMark Shellenbaum 	if (ace_flags & ACE_INHERITED_ACE)
31540a586ceaSMark Shellenbaum 		mdb_printf("I");
31550a586ceaSMark Shellenbaum 	else
31560a586ceaSMark Shellenbaum 		mdb_printf("-");
31570a586ceaSMark Shellenbaum 
31580a586ceaSMark Shellenbaum 	switch (ace_type) {
31590a586ceaSMark Shellenbaum 	case ACE_ACCESS_ALLOWED_ACE_TYPE:
31600a586ceaSMark Shellenbaum 		mdb_printf(":allow\n");
31610a586ceaSMark Shellenbaum 		break;
31620a586ceaSMark Shellenbaum 	case ACE_ACCESS_DENIED_ACE_TYPE:
31630a586ceaSMark Shellenbaum 		mdb_printf(":deny\n");
31640a586ceaSMark Shellenbaum 		break;
31650a586ceaSMark Shellenbaum 	case ACE_SYSTEM_AUDIT_ACE_TYPE:
31660a586ceaSMark Shellenbaum 		mdb_printf(":audit\n");
31670a586ceaSMark Shellenbaum 		break;
31680a586ceaSMark Shellenbaum 	case ACE_SYSTEM_ALARM_ACE_TYPE:
31690a586ceaSMark Shellenbaum 		mdb_printf(":alarm\n");
31700a586ceaSMark Shellenbaum 		break;
31710a586ceaSMark Shellenbaum 	default:
31720a586ceaSMark Shellenbaum 		mdb_printf(":?\n");
31730a586ceaSMark Shellenbaum 	}
31740a586ceaSMark Shellenbaum 	return (DCMD_OK);
31750a586ceaSMark Shellenbaum }
31760a586ceaSMark Shellenbaum 
31770a586ceaSMark Shellenbaum /* ARGSUSED */
31780a586ceaSMark Shellenbaum static int
31790a586ceaSMark Shellenbaum zfs_ace_print(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
31800a586ceaSMark Shellenbaum {
31810a586ceaSMark Shellenbaum 	zfs_ace_t zace;
31820a586ceaSMark Shellenbaum 	int verbose = FALSE;
31830a586ceaSMark Shellenbaum 	uint64_t id;
31840a586ceaSMark Shellenbaum 
31850a586ceaSMark Shellenbaum 	if (!(flags & DCMD_ADDRSPEC))
31860a586ceaSMark Shellenbaum 		return (DCMD_USAGE);
31870a586ceaSMark Shellenbaum 
31880a586ceaSMark Shellenbaum 	if (mdb_getopts(argc, argv,
31890a586ceaSMark Shellenbaum 	    'v', MDB_OPT_SETBITS, TRUE, &verbose, TRUE, NULL) != argc)
31900a586ceaSMark Shellenbaum 		return (DCMD_USAGE);
31910a586ceaSMark Shellenbaum 
31920a586ceaSMark Shellenbaum 	if (mdb_vread(&zace, sizeof (zfs_ace_t), addr) == -1) {
31930a586ceaSMark Shellenbaum 		mdb_warn("failed to read zfs_ace_t");
31940a586ceaSMark Shellenbaum 		return (DCMD_ERR);
31950a586ceaSMark Shellenbaum 	}
31960a586ceaSMark Shellenbaum 
31970a586ceaSMark Shellenbaum 	if ((zace.z_hdr.z_flags & ACE_TYPE_FLAGS) == 0 ||
31980a586ceaSMark Shellenbaum 	    (zace.z_hdr.z_flags & ACE_TYPE_FLAGS) == ACE_IDENTIFIER_GROUP)
31990a586ceaSMark Shellenbaum 		id = zace.z_fuid;
32000a586ceaSMark Shellenbaum 	else
32010a586ceaSMark Shellenbaum 		id = -1;
32020a586ceaSMark Shellenbaum 
32030a586ceaSMark Shellenbaum 	return (zfs_ace_print_common(addr, flags, id, zace.z_hdr.z_access_mask,
32040a586ceaSMark Shellenbaum 	    zace.z_hdr.z_flags, zace.z_hdr.z_type, verbose));
32050a586ceaSMark Shellenbaum }
32060a586ceaSMark Shellenbaum 
32070a586ceaSMark Shellenbaum /* ARGSUSED */
32080a586ceaSMark Shellenbaum static int
32090a586ceaSMark Shellenbaum zfs_ace0_print(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
32100a586ceaSMark Shellenbaum {
32110a586ceaSMark Shellenbaum 	ace_t ace;
32120a586ceaSMark Shellenbaum 	uint64_t id;
32130a586ceaSMark Shellenbaum 	int verbose = FALSE;
32140a586ceaSMark Shellenbaum 
32150a586ceaSMark Shellenbaum 	if (!(flags & DCMD_ADDRSPEC))
32160a586ceaSMark Shellenbaum 		return (DCMD_USAGE);
32170a586ceaSMark Shellenbaum 
32180a586ceaSMark Shellenbaum 	if (mdb_getopts(argc, argv,
32190a586ceaSMark Shellenbaum 	    'v', MDB_OPT_SETBITS, TRUE, &verbose, TRUE, NULL) != argc)
32200a586ceaSMark Shellenbaum 		return (DCMD_USAGE);
32210a586ceaSMark Shellenbaum 
32220a586ceaSMark Shellenbaum 	if (mdb_vread(&ace, sizeof (ace_t), addr) == -1) {
32230a586ceaSMark Shellenbaum 		mdb_warn("failed to read ace_t");
32240a586ceaSMark Shellenbaum 		return (DCMD_ERR);
32250a586ceaSMark Shellenbaum 	}
32260a586ceaSMark Shellenbaum 
32270a586ceaSMark Shellenbaum 	if ((ace.a_flags & ACE_TYPE_FLAGS) == 0 ||
32280a586ceaSMark Shellenbaum 	    (ace.a_flags & ACE_TYPE_FLAGS) == ACE_IDENTIFIER_GROUP)
32290a586ceaSMark Shellenbaum 		id = ace.a_who;
32300a586ceaSMark Shellenbaum 	else
32310a586ceaSMark Shellenbaum 		id = -1;
32320a586ceaSMark Shellenbaum 
32330a586ceaSMark Shellenbaum 	return (zfs_ace_print_common(addr, flags, id, ace.a_access_mask,
32340a586ceaSMark Shellenbaum 	    ace.a_flags, ace.a_type, verbose));
32350a586ceaSMark Shellenbaum }
32360a586ceaSMark Shellenbaum 
32370a586ceaSMark Shellenbaum typedef struct acl_dump_args {
32380a586ceaSMark Shellenbaum 	int a_argc;
32390a586ceaSMark Shellenbaum 	const mdb_arg_t *a_argv;
32400a586ceaSMark Shellenbaum 	uint16_t a_version;
32410a586ceaSMark Shellenbaum 	int a_flags;
32420a586ceaSMark Shellenbaum } acl_dump_args_t;
32430a586ceaSMark Shellenbaum 
32440a586ceaSMark Shellenbaum /* ARGSUSED */
32450a586ceaSMark Shellenbaum static int
32460a586ceaSMark Shellenbaum acl_aces_cb(uintptr_t addr, const void *unknown, void *arg)
32470a586ceaSMark Shellenbaum {
32480a586ceaSMark Shellenbaum 	acl_dump_args_t *acl_args = (acl_dump_args_t *)arg;
32490a586ceaSMark Shellenbaum 
32500a586ceaSMark Shellenbaum 	if (acl_args->a_version == 1) {
32510a586ceaSMark Shellenbaum 		if (mdb_call_dcmd("zfs_ace", addr,
32520a586ceaSMark Shellenbaum 		    DCMD_ADDRSPEC|acl_args->a_flags, acl_args->a_argc,
32530a586ceaSMark Shellenbaum 		    acl_args->a_argv) != DCMD_OK) {
32540a586ceaSMark Shellenbaum 			return (WALK_ERR);
32550a586ceaSMark Shellenbaum 		}
32560a586ceaSMark Shellenbaum 	} else {
32570a586ceaSMark Shellenbaum 		if (mdb_call_dcmd("zfs_ace0", addr,
32580a586ceaSMark Shellenbaum 		    DCMD_ADDRSPEC|acl_args->a_flags, acl_args->a_argc,
32590a586ceaSMark Shellenbaum 		    acl_args->a_argv) != DCMD_OK) {
32600a586ceaSMark Shellenbaum 			return (WALK_ERR);
32610a586ceaSMark Shellenbaum 		}
32620a586ceaSMark Shellenbaum 	}
32630a586ceaSMark Shellenbaum 	acl_args->a_flags = DCMD_LOOP;
32640a586ceaSMark Shellenbaum 	return (WALK_NEXT);
32650a586ceaSMark Shellenbaum }
32660a586ceaSMark Shellenbaum 
32670a586ceaSMark Shellenbaum /* ARGSUSED */
32680a586ceaSMark Shellenbaum static int
32690a586ceaSMark Shellenbaum acl_cb(uintptr_t addr, const void *unknown, void *arg)
32700a586ceaSMark Shellenbaum {
32710a586ceaSMark Shellenbaum 	acl_dump_args_t *acl_args = (acl_dump_args_t *)arg;
32720a586ceaSMark Shellenbaum 
32730a586ceaSMark Shellenbaum 	if (acl_args->a_version == 1) {
32740a586ceaSMark Shellenbaum 		if (mdb_pwalk("zfs_acl_node_aces", acl_aces_cb,
32750a586ceaSMark Shellenbaum 		    arg, addr) != 0) {
32760a586ceaSMark Shellenbaum 			mdb_warn("can't walk ACEs");
32770a586ceaSMark Shellenbaum 			return (DCMD_ERR);
32780a586ceaSMark Shellenbaum 		}
32790a586ceaSMark Shellenbaum 	} else {
32800a586ceaSMark Shellenbaum 		if (mdb_pwalk("zfs_acl_node_aces0", acl_aces_cb,
32810a586ceaSMark Shellenbaum 		    arg, addr) != 0) {
32820a586ceaSMark Shellenbaum 			mdb_warn("can't walk ACEs");
32830a586ceaSMark Shellenbaum 			return (DCMD_ERR);
32840a586ceaSMark Shellenbaum 		}
32850a586ceaSMark Shellenbaum 	}
32860a586ceaSMark Shellenbaum 	return (WALK_NEXT);
32870a586ceaSMark Shellenbaum }
32880a586ceaSMark Shellenbaum 
32890a586ceaSMark Shellenbaum /* ARGSUSED */
32900a586ceaSMark Shellenbaum static int
32910a586ceaSMark Shellenbaum zfs_acl_dump(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
32920a586ceaSMark Shellenbaum {
32930a586ceaSMark Shellenbaum 	zfs_acl_t zacl;
32940a586ceaSMark Shellenbaum 	int verbose = FALSE;
32950a586ceaSMark Shellenbaum 	acl_dump_args_t acl_args;
32960a586ceaSMark Shellenbaum 
32970a586ceaSMark Shellenbaum 	if (!(flags & DCMD_ADDRSPEC))
32980a586ceaSMark Shellenbaum 		return (DCMD_USAGE);
32990a586ceaSMark Shellenbaum 
33000a586ceaSMark Shellenbaum 	if (mdb_getopts(argc, argv,
33010a586ceaSMark Shellenbaum 	    'v', MDB_OPT_SETBITS, TRUE, &verbose, TRUE, NULL) != argc)
33020a586ceaSMark Shellenbaum 		return (DCMD_USAGE);
33030a586ceaSMark Shellenbaum 
33040a586ceaSMark Shellenbaum 	if (mdb_vread(&zacl, sizeof (zfs_acl_t), addr) == -1) {
33050a586ceaSMark Shellenbaum 		mdb_warn("failed to read zfs_acl_t");
33060a586ceaSMark Shellenbaum 		return (DCMD_ERR);
33070a586ceaSMark Shellenbaum 	}
33080a586ceaSMark Shellenbaum 
33090a586ceaSMark Shellenbaum 	acl_args.a_argc = argc;
33100a586ceaSMark Shellenbaum 	acl_args.a_argv = argv;
33110a586ceaSMark Shellenbaum 	acl_args.a_version = zacl.z_version;
33120a586ceaSMark Shellenbaum 	acl_args.a_flags = DCMD_LOOPFIRST;
33130a586ceaSMark Shellenbaum 
33140a586ceaSMark Shellenbaum 	if (mdb_pwalk("zfs_acl_node", acl_cb, &acl_args, addr) != 0) {
33150a586ceaSMark Shellenbaum 		mdb_warn("can't walk ACL");
33160a586ceaSMark Shellenbaum 		return (DCMD_ERR);
33170a586ceaSMark Shellenbaum 	}
33180a586ceaSMark Shellenbaum 
33190a586ceaSMark Shellenbaum 	return (DCMD_OK);
33200a586ceaSMark Shellenbaum }
33210a586ceaSMark Shellenbaum 
33220a586ceaSMark Shellenbaum /* ARGSUSED */
33230a586ceaSMark Shellenbaum static int
33240a586ceaSMark Shellenbaum zfs_acl_node_walk_init(mdb_walk_state_t *wsp)
33250a586ceaSMark Shellenbaum {
33260a586ceaSMark Shellenbaum 	if (wsp->walk_addr == NULL) {
33270a586ceaSMark Shellenbaum 		mdb_warn("must supply address of zfs_acl_node_t\n");
33280a586ceaSMark Shellenbaum 		return (WALK_ERR);
33290a586ceaSMark Shellenbaum 	}
33300a586ceaSMark Shellenbaum 
333128e4da25SMatthew Ahrens 	wsp->walk_addr +=
333228e4da25SMatthew Ahrens 	    mdb_ctf_offsetof_by_name(ZFS_STRUCT "zfs_acl", "z_acl");
33330a586ceaSMark Shellenbaum 
33340a586ceaSMark Shellenbaum 	if (mdb_layered_walk("list", wsp) == -1) {
33350a586ceaSMark Shellenbaum 		mdb_warn("failed to walk 'list'\n");
33360a586ceaSMark Shellenbaum 		return (WALK_ERR);
33370a586ceaSMark Shellenbaum 	}
33380a586ceaSMark Shellenbaum 
33390a586ceaSMark Shellenbaum 	return (WALK_NEXT);
33400a586ceaSMark Shellenbaum }
33410a586ceaSMark Shellenbaum 
33420a586ceaSMark Shellenbaum static int
33430a586ceaSMark Shellenbaum zfs_acl_node_walk_step(mdb_walk_state_t *wsp)
33440a586ceaSMark Shellenbaum {
33450a586ceaSMark Shellenbaum 	zfs_acl_node_t	aclnode;
33460a586ceaSMark Shellenbaum 
33470a586ceaSMark Shellenbaum 	if (mdb_vread(&aclnode, sizeof (zfs_acl_node_t),
33480a586ceaSMark Shellenbaum 	    wsp->walk_addr) == -1) {
33490a586ceaSMark Shellenbaum 		mdb_warn("failed to read zfs_acl_node at %p", wsp->walk_addr);
33500a586ceaSMark Shellenbaum 		return (WALK_ERR);
33510a586ceaSMark Shellenbaum 	}
33520a586ceaSMark Shellenbaum 
33530a586ceaSMark Shellenbaum 	return (wsp->walk_callback(wsp->walk_addr, &aclnode, wsp->walk_cbdata));
33540a586ceaSMark Shellenbaum }
33550a586ceaSMark Shellenbaum 
33560a586ceaSMark Shellenbaum typedef struct ace_walk_data {
33570a586ceaSMark Shellenbaum 	int		ace_count;
33580a586ceaSMark Shellenbaum 	int		ace_version;
33590a586ceaSMark Shellenbaum } ace_walk_data_t;
33600a586ceaSMark Shellenbaum 
33610a586ceaSMark Shellenbaum static int
33620a586ceaSMark Shellenbaum zfs_aces_walk_init_common(mdb_walk_state_t *wsp, int version,
33630a586ceaSMark Shellenbaum     int ace_count, uintptr_t ace_data)
33640a586ceaSMark Shellenbaum {
33650a586ceaSMark Shellenbaum 	ace_walk_data_t *ace_walk_data;
33660a586ceaSMark Shellenbaum 
33670a586ceaSMark Shellenbaum 	if (wsp->walk_addr == NULL) {
33680a586ceaSMark Shellenbaum 		mdb_warn("must supply address of zfs_acl_node_t\n");
33690a586ceaSMark Shellenbaum 		return (WALK_ERR);
33700a586ceaSMark Shellenbaum 	}
33710a586ceaSMark Shellenbaum 
33720a586ceaSMark Shellenbaum 	ace_walk_data = mdb_alloc(sizeof (ace_walk_data_t), UM_SLEEP | UM_GC);
33730a586ceaSMark Shellenbaum 
33740a586ceaSMark Shellenbaum 	ace_walk_data->ace_count = ace_count;
33750a586ceaSMark Shellenbaum 	ace_walk_data->ace_version = version;
33760a586ceaSMark Shellenbaum 
33770a586ceaSMark Shellenbaum 	wsp->walk_addr = ace_data;
33780a586ceaSMark Shellenbaum 	wsp->walk_data = ace_walk_data;
33790a586ceaSMark Shellenbaum 
33800a586ceaSMark Shellenbaum 	return (WALK_NEXT);
33810a586ceaSMark Shellenbaum }
33820a586ceaSMark Shellenbaum 
33830a586ceaSMark Shellenbaum static int
33840a586ceaSMark Shellenbaum zfs_acl_node_aces_walk_init_common(mdb_walk_state_t *wsp, int version)
33850a586ceaSMark Shellenbaum {
33860a586ceaSMark Shellenbaum 	static int gotid;
33870a586ceaSMark Shellenbaum 	static mdb_ctf_id_t acl_id;
33880a586ceaSMark Shellenbaum 	int z_ace_count;
33890a586ceaSMark Shellenbaum 	uintptr_t z_acldata;
33900a586ceaSMark Shellenbaum 
33910a586ceaSMark Shellenbaum 	if (!gotid) {
33920a586ceaSMark Shellenbaum 		if (mdb_ctf_lookup_by_name("struct zfs_acl_node",
33930a586ceaSMark Shellenbaum 		    &acl_id) == -1) {
33940a586ceaSMark Shellenbaum 			mdb_warn("couldn't find struct zfs_acl_node");
33950a586ceaSMark Shellenbaum 			return (DCMD_ERR);
33960a586ceaSMark Shellenbaum 		}
33970a586ceaSMark Shellenbaum 		gotid = TRUE;
33980a586ceaSMark Shellenbaum 	}
33990a586ceaSMark Shellenbaum 
34000a586ceaSMark Shellenbaum 	if (GETMEMBID(wsp->walk_addr, &acl_id, z_ace_count, z_ace_count)) {
34010a586ceaSMark Shellenbaum 		return (DCMD_ERR);
34020a586ceaSMark Shellenbaum 	}
34030a586ceaSMark Shellenbaum 	if (GETMEMBID(wsp->walk_addr, &acl_id, z_acldata, z_acldata)) {
34040a586ceaSMark Shellenbaum 		return (DCMD_ERR);
34050a586ceaSMark Shellenbaum 	}
34060a586ceaSMark Shellenbaum 
34070a586ceaSMark Shellenbaum 	return (zfs_aces_walk_init_common(wsp, version,
34080a586ceaSMark Shellenbaum 	    z_ace_count, z_acldata));
34090a586ceaSMark Shellenbaum }
34100a586ceaSMark Shellenbaum 
34110a586ceaSMark Shellenbaum /* ARGSUSED */
34120a586ceaSMark Shellenbaum static int
34130a586ceaSMark Shellenbaum zfs_acl_node_aces_walk_init(mdb_walk_state_t *wsp)
34140a586ceaSMark Shellenbaum {
34150a586ceaSMark Shellenbaum 	return (zfs_acl_node_aces_walk_init_common(wsp, 1));
34160a586ceaSMark Shellenbaum }
34170a586ceaSMark Shellenbaum 
34180a586ceaSMark Shellenbaum /* ARGSUSED */
34190a586ceaSMark Shellenbaum static int
34200a586ceaSMark Shellenbaum zfs_acl_node_aces0_walk_init(mdb_walk_state_t *wsp)
34210a586ceaSMark Shellenbaum {
34220a586ceaSMark Shellenbaum 	return (zfs_acl_node_aces_walk_init_common(wsp, 0));
34230a586ceaSMark Shellenbaum }
34240a586ceaSMark Shellenbaum 
34250a586ceaSMark Shellenbaum static int
34260a586ceaSMark Shellenbaum zfs_aces_walk_step(mdb_walk_state_t *wsp)
34270a586ceaSMark Shellenbaum {
34280a586ceaSMark Shellenbaum 	ace_walk_data_t *ace_data = wsp->walk_data;
34290a586ceaSMark Shellenbaum 	zfs_ace_t zace;
34300a586ceaSMark Shellenbaum 	ace_t *acep;
34310a586ceaSMark Shellenbaum 	int status;
34320a586ceaSMark Shellenbaum 	int entry_type;
34330a586ceaSMark Shellenbaum 	int allow_type;
34340a586ceaSMark Shellenbaum 	uintptr_t ptr;
34350a586ceaSMark Shellenbaum 
34360a586ceaSMark Shellenbaum 	if (ace_data->ace_count == 0)
34370a586ceaSMark Shellenbaum 		return (WALK_DONE);
34380a586ceaSMark Shellenbaum 
34390a586ceaSMark Shellenbaum 	if (mdb_vread(&zace, sizeof (zfs_ace_t), wsp->walk_addr) == -1) {
34400a586ceaSMark Shellenbaum 		mdb_warn("failed to read zfs_ace_t at %#lx",
34410a586ceaSMark Shellenbaum 		    wsp->walk_addr);
34420a586ceaSMark Shellenbaum 		return (WALK_ERR);
34430a586ceaSMark Shellenbaum 	}
34440a586ceaSMark Shellenbaum 
34450a586ceaSMark Shellenbaum 	switch (ace_data->ace_version) {
34460a586ceaSMark Shellenbaum 	case 0:
34470a586ceaSMark Shellenbaum 		acep = (ace_t *)&zace;
34480a586ceaSMark Shellenbaum 		entry_type = acep->a_flags & ACE_TYPE_FLAGS;
34490a586ceaSMark Shellenbaum 		allow_type = acep->a_type;
34500a586ceaSMark Shellenbaum 		break;
34510a586ceaSMark Shellenbaum 	case 1:
34520a586ceaSMark Shellenbaum 		entry_type = zace.z_hdr.z_flags & ACE_TYPE_FLAGS;
34530a586ceaSMark Shellenbaum 		allow_type = zace.z_hdr.z_type;
34540a586ceaSMark Shellenbaum 		break;
34550a586ceaSMark Shellenbaum 	default:
34560a586ceaSMark Shellenbaum 		return (WALK_ERR);
34570a586ceaSMark Shellenbaum 	}
34580a586ceaSMark Shellenbaum 
34590a586ceaSMark Shellenbaum 	ptr = (uintptr_t)wsp->walk_addr;
34600a586ceaSMark Shellenbaum 	switch (entry_type) {
34610a586ceaSMark Shellenbaum 	case ACE_OWNER:
34620a586ceaSMark Shellenbaum 	case ACE_EVERYONE:
34630a586ceaSMark Shellenbaum 	case (ACE_IDENTIFIER_GROUP | ACE_GROUP):
34640a586ceaSMark Shellenbaum 		ptr += ace_data->ace_version == 0 ?
34650a586ceaSMark Shellenbaum 		    sizeof (ace_t) : sizeof (zfs_ace_hdr_t);
34660a586ceaSMark Shellenbaum 		break;
34670a586ceaSMark Shellenbaum 	case ACE_IDENTIFIER_GROUP:
34680a586ceaSMark Shellenbaum 	default:
34690a586ceaSMark Shellenbaum 		switch (allow_type) {
34700a586ceaSMark Shellenbaum 		case ACE_ACCESS_ALLOWED_OBJECT_ACE_TYPE:
34710a586ceaSMark Shellenbaum 		case ACE_ACCESS_DENIED_OBJECT_ACE_TYPE:
34720a586ceaSMark Shellenbaum 		case ACE_SYSTEM_AUDIT_OBJECT_ACE_TYPE:
34730a586ceaSMark Shellenbaum 		case ACE_SYSTEM_ALARM_OBJECT_ACE_TYPE:
34740a586ceaSMark Shellenbaum 			ptr += ace_data->ace_version == 0 ?
34750a586ceaSMark Shellenbaum 			    sizeof (ace_t) : sizeof (zfs_object_ace_t);
34760a586ceaSMark Shellenbaum 			break;
34770a586ceaSMark Shellenbaum 		default:
34780a586ceaSMark Shellenbaum 			ptr += ace_data->ace_version == 0 ?
34790a586ceaSMark Shellenbaum 			    sizeof (ace_t) : sizeof (zfs_ace_t);
34800a586ceaSMark Shellenbaum 			break;
34810a586ceaSMark Shellenbaum 		}
34820a586ceaSMark Shellenbaum 	}
34830a586ceaSMark Shellenbaum 
34840a586ceaSMark Shellenbaum 	ace_data->ace_count--;
34850a586ceaSMark Shellenbaum 	status = wsp->walk_callback(wsp->walk_addr,
34860a586ceaSMark Shellenbaum 	    (void *)(uintptr_t)&zace, wsp->walk_cbdata);
34870a586ceaSMark Shellenbaum 
34880a586ceaSMark Shellenbaum 	wsp->walk_addr = ptr;
34890a586ceaSMark Shellenbaum 	return (status);
34900a586ceaSMark Shellenbaum }
34910a586ceaSMark Shellenbaum 
349228e4da25SMatthew Ahrens typedef struct mdb_zfs_rrwlock {
3493d5ee8a13SMatthew Ahrens 	uintptr_t	rr_writer;
349428e4da25SMatthew Ahrens 	boolean_t	rr_writer_wanted;
349528e4da25SMatthew Ahrens } mdb_zfs_rrwlock_t;
349628e4da25SMatthew Ahrens 
349728e4da25SMatthew Ahrens static uint_t rrw_key;
349828e4da25SMatthew Ahrens 
349928e4da25SMatthew Ahrens /* ARGSUSED */
350028e4da25SMatthew Ahrens static int
350128e4da25SMatthew Ahrens rrwlock(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
350228e4da25SMatthew Ahrens {
350328e4da25SMatthew Ahrens 	mdb_zfs_rrwlock_t rrw;
350428e4da25SMatthew Ahrens 
350528e4da25SMatthew Ahrens 	if (rrw_key == 0) {
350628e4da25SMatthew Ahrens 		if (mdb_ctf_readsym(&rrw_key, "uint_t", "rrw_tsd_key", 0) == -1)
350728e4da25SMatthew Ahrens 			return (DCMD_ERR);
350828e4da25SMatthew Ahrens 	}
350928e4da25SMatthew Ahrens 
351028e4da25SMatthew Ahrens 	if (mdb_ctf_vread(&rrw, "rrwlock_t", "mdb_zfs_rrwlock_t", addr,
351128e4da25SMatthew Ahrens 	    0) == -1)
351228e4da25SMatthew Ahrens 		return (DCMD_ERR);
351328e4da25SMatthew Ahrens 
3514d5ee8a13SMatthew Ahrens 	if (rrw.rr_writer != 0) {
3515d5ee8a13SMatthew Ahrens 		mdb_printf("write lock held by thread %lx\n", rrw.rr_writer);
351628e4da25SMatthew Ahrens 		return (DCMD_OK);
351728e4da25SMatthew Ahrens 	}
351828e4da25SMatthew Ahrens 
351928e4da25SMatthew Ahrens 	if (rrw.rr_writer_wanted) {
352028e4da25SMatthew Ahrens 		mdb_printf("writer wanted\n");
352128e4da25SMatthew Ahrens 	}
352228e4da25SMatthew Ahrens 
352328e4da25SMatthew Ahrens 	mdb_printf("anonymous references:\n");
352428e4da25SMatthew Ahrens 	(void) mdb_call_dcmd("refcount", addr +
352528e4da25SMatthew Ahrens 	    mdb_ctf_offsetof_by_name(ZFS_STRUCT "rrwlock", "rr_anon_rcount"),
352628e4da25SMatthew Ahrens 	    DCMD_ADDRSPEC, 0, NULL);
352728e4da25SMatthew Ahrens 
352828e4da25SMatthew Ahrens 	mdb_printf("linked references:\n");
352928e4da25SMatthew Ahrens 	(void) mdb_call_dcmd("refcount", addr +
353028e4da25SMatthew Ahrens 	    mdb_ctf_offsetof_by_name(ZFS_STRUCT "rrwlock", "rr_linked_rcount"),
353128e4da25SMatthew Ahrens 	    DCMD_ADDRSPEC, 0, NULL);
353228e4da25SMatthew Ahrens 
353328e4da25SMatthew Ahrens 	/*
353428e4da25SMatthew Ahrens 	 * XXX This should find references from
353528e4da25SMatthew Ahrens 	 * "::walk thread | ::tsd -v <rrw_key>", but there is no support
353628e4da25SMatthew Ahrens 	 * for programmatic consumption of dcmds, so this would be
353728e4da25SMatthew Ahrens 	 * difficult, potentially requiring reimplementing ::tsd (both
353828e4da25SMatthew Ahrens 	 * user and kernel versions) in this MDB module.
353928e4da25SMatthew Ahrens 	 */
354028e4da25SMatthew Ahrens 
354128e4da25SMatthew Ahrens 	return (DCMD_OK);
354228e4da25SMatthew Ahrens }
354328e4da25SMatthew Ahrens 
3544dcbf3bd6SGeorge Wilson typedef struct mdb_arc_buf_hdr_t {
3545dcbf3bd6SGeorge Wilson 	uint16_t b_psize;
3546dcbf3bd6SGeorge Wilson 	uint16_t b_lsize;
3547dcbf3bd6SGeorge Wilson 	struct {
3548dcbf3bd6SGeorge Wilson 		uint32_t	b_bufcnt;
3549dcbf3bd6SGeorge Wilson 		uintptr_t	b_state;
3550dcbf3bd6SGeorge Wilson 		uintptr_t	b_pdata;
3551dcbf3bd6SGeorge Wilson 	} b_l1hdr;
3552dcbf3bd6SGeorge Wilson } mdb_arc_buf_hdr_t;
3553dcbf3bd6SGeorge Wilson 
3554dcbf3bd6SGeorge Wilson enum arc_cflags {
3555dcbf3bd6SGeorge Wilson 	ARC_CFLAG_VERBOSE		= 1 << 0,
3556dcbf3bd6SGeorge Wilson 	ARC_CFLAG_ANON			= 1 << 1,
3557dcbf3bd6SGeorge Wilson 	ARC_CFLAG_MRU			= 1 << 2,
3558dcbf3bd6SGeorge Wilson 	ARC_CFLAG_MFU			= 1 << 3,
3559dcbf3bd6SGeorge Wilson 	ARC_CFLAG_BUFS			= 1 << 4,
3560dcbf3bd6SGeorge Wilson };
3561dcbf3bd6SGeorge Wilson 
3562dcbf3bd6SGeorge Wilson typedef struct arc_compression_stats_data {
3563dcbf3bd6SGeorge Wilson 	GElf_Sym anon_sym;	/* ARC_anon symbol */
3564dcbf3bd6SGeorge Wilson 	GElf_Sym mru_sym;	/* ARC_mru symbol */
3565dcbf3bd6SGeorge Wilson 	GElf_Sym mrug_sym;	/* ARC_mru_ghost symbol */
3566dcbf3bd6SGeorge Wilson 	GElf_Sym mfu_sym;	/* ARC_mfu symbol */
3567dcbf3bd6SGeorge Wilson 	GElf_Sym mfug_sym;	/* ARC_mfu_ghost symbol */
3568dcbf3bd6SGeorge Wilson 	GElf_Sym l2c_sym;	/* ARC_l2c_only symbol */
3569dcbf3bd6SGeorge Wilson 	uint64_t *anon_c_hist;	/* histogram of compressed sizes in anon */
3570dcbf3bd6SGeorge Wilson 	uint64_t *anon_u_hist;	/* histogram of uncompressed sizes in anon */
3571dcbf3bd6SGeorge Wilson 	uint64_t *anon_bufs;	/* histogram of buffer counts in anon state */
3572dcbf3bd6SGeorge Wilson 	uint64_t *mru_c_hist;	/* histogram of compressed sizes in mru */
3573dcbf3bd6SGeorge Wilson 	uint64_t *mru_u_hist;	/* histogram of uncompressed sizes in mru */
3574dcbf3bd6SGeorge Wilson 	uint64_t *mru_bufs;	/* histogram of buffer counts in mru */
3575dcbf3bd6SGeorge Wilson 	uint64_t *mfu_c_hist;	/* histogram of compressed sizes in mfu */
3576dcbf3bd6SGeorge Wilson 	uint64_t *mfu_u_hist;	/* histogram of uncompressed sizes in mfu */
3577dcbf3bd6SGeorge Wilson 	uint64_t *mfu_bufs;	/* histogram of buffer counts in mfu */
3578dcbf3bd6SGeorge Wilson 	uint64_t *all_c_hist;	/* histogram of compressed anon + mru + mfu */
3579dcbf3bd6SGeorge Wilson 	uint64_t *all_u_hist;	/* histogram of uncompressed anon + mru + mfu */
3580dcbf3bd6SGeorge Wilson 	uint64_t *all_bufs;	/* histogram of buffer counts in all states  */
3581dcbf3bd6SGeorge Wilson 	int arc_cflags;		/* arc compression flags, specified by user */
3582dcbf3bd6SGeorge Wilson 	int hist_nbuckets;	/* number of buckets in each histogram */
3583dcbf3bd6SGeorge Wilson } arc_compression_stats_data_t;
3584dcbf3bd6SGeorge Wilson 
3585dcbf3bd6SGeorge Wilson int
3586dcbf3bd6SGeorge Wilson highbit64(uint64_t i)
3587dcbf3bd6SGeorge Wilson {
3588dcbf3bd6SGeorge Wilson 	int h = 1;
3589dcbf3bd6SGeorge Wilson 
3590dcbf3bd6SGeorge Wilson 	if (i == 0)
3591dcbf3bd6SGeorge Wilson 		return (0);
3592dcbf3bd6SGeorge Wilson 	if (i & 0xffffffff00000000ULL) {
3593dcbf3bd6SGeorge Wilson 		h += 32; i >>= 32;
3594dcbf3bd6SGeorge Wilson 	}
3595dcbf3bd6SGeorge Wilson 	if (i & 0xffff0000) {
3596dcbf3bd6SGeorge Wilson 		h += 16; i >>= 16;
3597dcbf3bd6SGeorge Wilson 	}
3598dcbf3bd6SGeorge Wilson 	if (i & 0xff00) {
3599dcbf3bd6SGeorge Wilson 		h += 8; i >>= 8;
3600dcbf3bd6SGeorge Wilson 	}
3601dcbf3bd6SGeorge Wilson 	if (i & 0xf0) {
3602dcbf3bd6SGeorge Wilson 		h += 4; i >>= 4;
3603dcbf3bd6SGeorge Wilson 	}
3604dcbf3bd6SGeorge Wilson 	if (i & 0xc) {
3605dcbf3bd6SGeorge Wilson 		h += 2; i >>= 2;
3606dcbf3bd6SGeorge Wilson 	}
3607dcbf3bd6SGeorge Wilson 	if (i & 0x2) {
3608dcbf3bd6SGeorge Wilson 		h += 1;
3609dcbf3bd6SGeorge Wilson 	}
3610dcbf3bd6SGeorge Wilson 	return (h);
3611dcbf3bd6SGeorge Wilson }
3612dcbf3bd6SGeorge Wilson 
3613dcbf3bd6SGeorge Wilson /* ARGSUSED */
3614dcbf3bd6SGeorge Wilson static int
3615dcbf3bd6SGeorge Wilson arc_compression_stats_cb(uintptr_t addr, const void *unknown, void *arg)
3616dcbf3bd6SGeorge Wilson {
3617dcbf3bd6SGeorge Wilson 	arc_compression_stats_data_t *data = arg;
3618dcbf3bd6SGeorge Wilson 	mdb_arc_buf_hdr_t hdr;
3619dcbf3bd6SGeorge Wilson 	int cbucket, ubucket, bufcnt;
3620dcbf3bd6SGeorge Wilson 
3621dcbf3bd6SGeorge Wilson 	if (mdb_ctf_vread(&hdr, "arc_buf_hdr_t", "mdb_arc_buf_hdr_t",
3622dcbf3bd6SGeorge Wilson 	    addr, 0) == -1) {
3623dcbf3bd6SGeorge Wilson 		return (WALK_ERR);
3624dcbf3bd6SGeorge Wilson 	}
3625dcbf3bd6SGeorge Wilson 
3626dcbf3bd6SGeorge Wilson 	/*
3627dcbf3bd6SGeorge Wilson 	 * Headers in the ghost states, or the l2c_only state don't have
3628dcbf3bd6SGeorge Wilson 	 * arc buffers linked off of them. Thus, their compressed size
3629dcbf3bd6SGeorge Wilson 	 * is meaningless, so we skip these from the stats.
3630dcbf3bd6SGeorge Wilson 	 */
3631dcbf3bd6SGeorge Wilson 	if (hdr.b_l1hdr.b_state == data->mrug_sym.st_value ||
3632dcbf3bd6SGeorge Wilson 	    hdr.b_l1hdr.b_state == data->mfug_sym.st_value ||
3633dcbf3bd6SGeorge Wilson 	    hdr.b_l1hdr.b_state == data->l2c_sym.st_value) {
3634dcbf3bd6SGeorge Wilson 		return (WALK_NEXT);
3635dcbf3bd6SGeorge Wilson 	}
3636dcbf3bd6SGeorge Wilson 
3637dcbf3bd6SGeorge Wilson 	/*
3638dcbf3bd6SGeorge Wilson 	 * The physical size (compressed) and logical size
3639dcbf3bd6SGeorge Wilson 	 * (uncompressed) are in units of SPA_MINBLOCKSIZE. By default,
3640dcbf3bd6SGeorge Wilson 	 * we use the log2 of this value (rounded down to the nearest
3641dcbf3bd6SGeorge Wilson 	 * integer) to determine the bucket to assign this header to.
3642dcbf3bd6SGeorge Wilson 	 * Thus, the histogram is logarithmic with respect to the size
3643dcbf3bd6SGeorge Wilson 	 * of the header. For example, the following is a mapping of the
3644dcbf3bd6SGeorge Wilson 	 * bucket numbers and the range of header sizes they correspond to:
3645dcbf3bd6SGeorge Wilson 	 *
3646dcbf3bd6SGeorge Wilson 	 *	0: 0 byte headers
3647dcbf3bd6SGeorge Wilson 	 *	1: 512 byte headers
3648dcbf3bd6SGeorge Wilson 	 *	2: [1024 - 2048) byte headers
3649dcbf3bd6SGeorge Wilson 	 *	3: [2048 - 4096) byte headers
3650dcbf3bd6SGeorge Wilson 	 *	4: [4096 - 8192) byte headers
3651dcbf3bd6SGeorge Wilson 	 *	5: [8192 - 16394) byte headers
3652dcbf3bd6SGeorge Wilson 	 *	6: [16384 - 32768) byte headers
3653dcbf3bd6SGeorge Wilson 	 *	7: [32768 - 65536) byte headers
3654dcbf3bd6SGeorge Wilson 	 *	8: [65536 - 131072) byte headers
3655dcbf3bd6SGeorge Wilson 	 *	9: 131072 byte headers
3656dcbf3bd6SGeorge Wilson 	 *
3657dcbf3bd6SGeorge Wilson 	 * If the ARC_CFLAG_VERBOSE flag was specified, we use the
3658dcbf3bd6SGeorge Wilson 	 * physical and logical sizes directly. Thus, the histogram will
3659dcbf3bd6SGeorge Wilson 	 * no longer be logarithmic; instead it will be linear with
3660dcbf3bd6SGeorge Wilson 	 * respect to the size of the header. The following is a mapping
3661dcbf3bd6SGeorge Wilson 	 * of the first many bucket numbers and the header size they
3662dcbf3bd6SGeorge Wilson 	 * correspond to:
3663dcbf3bd6SGeorge Wilson 	 *
3664dcbf3bd6SGeorge Wilson 	 *	0: 0 byte headers
3665dcbf3bd6SGeorge Wilson 	 *	1: 512 byte headers
3666dcbf3bd6SGeorge Wilson 	 *	2: 1024 byte headers
3667dcbf3bd6SGeorge Wilson 	 *	3: 1536 byte headers
3668dcbf3bd6SGeorge Wilson 	 *	4: 2048 byte headers
3669dcbf3bd6SGeorge Wilson 	 *	5: 2560 byte headers
3670dcbf3bd6SGeorge Wilson 	 *	6: 3072 byte headers
3671dcbf3bd6SGeorge Wilson 	 *
3672dcbf3bd6SGeorge Wilson 	 * And so on. Keep in mind that a range of sizes isn't used in
3673dcbf3bd6SGeorge Wilson 	 * the case of linear scale because the headers can only
3674dcbf3bd6SGeorge Wilson 	 * increment or decrement in sizes of 512 bytes. So, it's not
3675dcbf3bd6SGeorge Wilson 	 * possible for a header to be sized in between whats listed
3676dcbf3bd6SGeorge Wilson 	 * above.
3677dcbf3bd6SGeorge Wilson 	 *
3678dcbf3bd6SGeorge Wilson 	 * Also, the above mapping values were calculated assuming a
3679dcbf3bd6SGeorge Wilson 	 * SPA_MINBLOCKSHIFT of 512 bytes and a SPA_MAXBLOCKSIZE of 128K.
3680dcbf3bd6SGeorge Wilson 	 */
3681dcbf3bd6SGeorge Wilson 
3682dcbf3bd6SGeorge Wilson 	if (data->arc_cflags & ARC_CFLAG_VERBOSE) {
3683dcbf3bd6SGeorge Wilson 		cbucket = hdr.b_psize;
3684dcbf3bd6SGeorge Wilson 		ubucket = hdr.b_lsize;
3685dcbf3bd6SGeorge Wilson 	} else {
3686dcbf3bd6SGeorge Wilson 		cbucket = highbit64(hdr.b_psize);
3687dcbf3bd6SGeorge Wilson 		ubucket = highbit64(hdr.b_lsize);
3688dcbf3bd6SGeorge Wilson 	}
3689dcbf3bd6SGeorge Wilson 
3690dcbf3bd6SGeorge Wilson 	bufcnt = hdr.b_l1hdr.b_bufcnt;
3691dcbf3bd6SGeorge Wilson 	if (bufcnt >= data->hist_nbuckets)
3692dcbf3bd6SGeorge Wilson 		bufcnt = data->hist_nbuckets - 1;
3693dcbf3bd6SGeorge Wilson 
3694dcbf3bd6SGeorge Wilson 	/* Ensure we stay within the bounds of the histogram array */
3695dcbf3bd6SGeorge Wilson 	ASSERT3U(cbucket, <, data->hist_nbuckets);
3696dcbf3bd6SGeorge Wilson 	ASSERT3U(ubucket, <, data->hist_nbuckets);
3697dcbf3bd6SGeorge Wilson 
3698dcbf3bd6SGeorge Wilson 	if (hdr.b_l1hdr.b_state == data->anon_sym.st_value) {
3699dcbf3bd6SGeorge Wilson 		data->anon_c_hist[cbucket]++;
3700dcbf3bd6SGeorge Wilson 		data->anon_u_hist[ubucket]++;
3701dcbf3bd6SGeorge Wilson 		data->anon_bufs[bufcnt]++;
3702dcbf3bd6SGeorge Wilson 	} else if (hdr.b_l1hdr.b_state == data->mru_sym.st_value) {
3703dcbf3bd6SGeorge Wilson 		data->mru_c_hist[cbucket]++;
3704dcbf3bd6SGeorge Wilson 		data->mru_u_hist[ubucket]++;
3705dcbf3bd6SGeorge Wilson 		data->mru_bufs[bufcnt]++;
3706dcbf3bd6SGeorge Wilson 	} else if (hdr.b_l1hdr.b_state == data->mfu_sym.st_value) {
3707dcbf3bd6SGeorge Wilson 		data->mfu_c_hist[cbucket]++;
3708dcbf3bd6SGeorge Wilson 		data->mfu_u_hist[ubucket]++;
3709dcbf3bd6SGeorge Wilson 		data->mfu_bufs[bufcnt]++;
3710dcbf3bd6SGeorge Wilson 	}
3711dcbf3bd6SGeorge Wilson 
3712dcbf3bd6SGeorge Wilson 	data->all_c_hist[cbucket]++;
3713dcbf3bd6SGeorge Wilson 	data->all_u_hist[ubucket]++;
3714dcbf3bd6SGeorge Wilson 	data->all_bufs[bufcnt]++;
3715dcbf3bd6SGeorge Wilson 
3716dcbf3bd6SGeorge Wilson 	return (WALK_NEXT);
3717dcbf3bd6SGeorge Wilson }
3718dcbf3bd6SGeorge Wilson 
3719dcbf3bd6SGeorge Wilson /* ARGSUSED */
3720dcbf3bd6SGeorge Wilson static int
3721dcbf3bd6SGeorge Wilson arc_compression_stats(uintptr_t addr, uint_t flags, int argc,
3722dcbf3bd6SGeorge Wilson     const mdb_arg_t *argv)
3723dcbf3bd6SGeorge Wilson {
3724dcbf3bd6SGeorge Wilson 	arc_compression_stats_data_t data = { 0 };
3725dcbf3bd6SGeorge Wilson 	unsigned int max_shifted = SPA_MAXBLOCKSIZE >> SPA_MINBLOCKSHIFT;
3726dcbf3bd6SGeorge Wilson 	unsigned int hist_size;
3727dcbf3bd6SGeorge Wilson 	char range[32];
3728dcbf3bd6SGeorge Wilson 	int rc = DCMD_OK;
3729dcbf3bd6SGeorge Wilson 
3730dcbf3bd6SGeorge Wilson 	if (mdb_getopts(argc, argv,
3731dcbf3bd6SGeorge Wilson 	    'v', MDB_OPT_SETBITS, ARC_CFLAG_VERBOSE, &data.arc_cflags,
3732dcbf3bd6SGeorge Wilson 	    'a', MDB_OPT_SETBITS, ARC_CFLAG_ANON, &data.arc_cflags,
3733dcbf3bd6SGeorge Wilson 	    'b', MDB_OPT_SETBITS, ARC_CFLAG_BUFS, &data.arc_cflags,
3734dcbf3bd6SGeorge Wilson 	    'r', MDB_OPT_SETBITS, ARC_CFLAG_MRU, &data.arc_cflags,
3735dcbf3bd6SGeorge Wilson 	    'f', MDB_OPT_SETBITS, ARC_CFLAG_MFU, &data.arc_cflags) != argc)
3736dcbf3bd6SGeorge Wilson 		return (DCMD_USAGE);
3737dcbf3bd6SGeorge Wilson 
3738dcbf3bd6SGeorge Wilson 	if (mdb_lookup_by_obj(ZFS_OBJ_NAME, "ARC_anon", &data.anon_sym) ||
3739dcbf3bd6SGeorge Wilson 	    mdb_lookup_by_obj(ZFS_OBJ_NAME, "ARC_mru", &data.mru_sym) ||
3740dcbf3bd6SGeorge Wilson 	    mdb_lookup_by_obj(ZFS_OBJ_NAME, "ARC_mru_ghost", &data.mrug_sym) ||
3741dcbf3bd6SGeorge Wilson 	    mdb_lookup_by_obj(ZFS_OBJ_NAME, "ARC_mfu", &data.mfu_sym) ||
3742dcbf3bd6SGeorge Wilson 	    mdb_lookup_by_obj(ZFS_OBJ_NAME, "ARC_mfu_ghost", &data.mfug_sym) ||
3743dcbf3bd6SGeorge Wilson 	    mdb_lookup_by_obj(ZFS_OBJ_NAME, "ARC_l2c_only", &data.l2c_sym)) {
3744dcbf3bd6SGeorge Wilson 		mdb_warn("can't find arc state symbol");
3745dcbf3bd6SGeorge Wilson 		return (DCMD_ERR);
3746dcbf3bd6SGeorge Wilson 	}
3747dcbf3bd6SGeorge Wilson 
3748dcbf3bd6SGeorge Wilson 	/*
3749dcbf3bd6SGeorge Wilson 	 * Determine the maximum expected size for any header, and use
3750dcbf3bd6SGeorge Wilson 	 * this to determine the number of buckets needed for each
3751dcbf3bd6SGeorge Wilson 	 * histogram. If ARC_CFLAG_VERBOSE is specified, this value is
3752dcbf3bd6SGeorge Wilson 	 * used directly; otherwise the log2 of the maximum size is
3753dcbf3bd6SGeorge Wilson 	 * used. Thus, if using a log2 scale there's a maximum of 10
3754dcbf3bd6SGeorge Wilson 	 * possible buckets, while the linear scale (when using
3755dcbf3bd6SGeorge Wilson 	 * ARC_CFLAG_VERBOSE) has a maximum of 257 buckets.
3756dcbf3bd6SGeorge Wilson 	 */
3757dcbf3bd6SGeorge Wilson 	if (data.arc_cflags & ARC_CFLAG_VERBOSE)
3758dcbf3bd6SGeorge Wilson 		data.hist_nbuckets = max_shifted + 1;
3759dcbf3bd6SGeorge Wilson 	else
3760dcbf3bd6SGeorge Wilson 		data.hist_nbuckets = highbit64(max_shifted) + 1;
3761dcbf3bd6SGeorge Wilson 
3762dcbf3bd6SGeorge Wilson 	hist_size = sizeof (uint64_t) * data.hist_nbuckets;
3763dcbf3bd6SGeorge Wilson 
3764dcbf3bd6SGeorge Wilson 	data.anon_c_hist = mdb_zalloc(hist_size, UM_SLEEP);
3765dcbf3bd6SGeorge Wilson 	data.anon_u_hist = mdb_zalloc(hist_size, UM_SLEEP);
3766dcbf3bd6SGeorge Wilson 	data.anon_bufs = mdb_zalloc(hist_size, UM_SLEEP);
3767dcbf3bd6SGeorge Wilson 
3768dcbf3bd6SGeorge Wilson 	data.mru_c_hist = mdb_zalloc(hist_size, UM_SLEEP);
3769dcbf3bd6SGeorge Wilson 	data.mru_u_hist = mdb_zalloc(hist_size, UM_SLEEP);
3770dcbf3bd6SGeorge Wilson 	data.mru_bufs = mdb_zalloc(hist_size, UM_SLEEP);
3771dcbf3bd6SGeorge Wilson 
3772dcbf3bd6SGeorge Wilson 	data.mfu_c_hist = mdb_zalloc(hist_size, UM_SLEEP);
3773dcbf3bd6SGeorge Wilson 	data.mfu_u_hist = mdb_zalloc(hist_size, UM_SLEEP);
3774dcbf3bd6SGeorge Wilson 	data.mfu_bufs = mdb_zalloc(hist_size, UM_SLEEP);
3775dcbf3bd6SGeorge Wilson 
3776dcbf3bd6SGeorge Wilson 	data.all_c_hist = mdb_zalloc(hist_size, UM_SLEEP);
3777dcbf3bd6SGeorge Wilson 	data.all_u_hist = mdb_zalloc(hist_size, UM_SLEEP);
3778dcbf3bd6SGeorge Wilson 	data.all_bufs = mdb_zalloc(hist_size, UM_SLEEP);
3779dcbf3bd6SGeorge Wilson 
3780dcbf3bd6SGeorge Wilson 	if (mdb_walk("arc_buf_hdr_t_full", arc_compression_stats_cb,
3781dcbf3bd6SGeorge Wilson 	    &data) != 0) {
3782dcbf3bd6SGeorge Wilson 		mdb_warn("can't walk arc_buf_hdr's");
3783dcbf3bd6SGeorge Wilson 		rc = DCMD_ERR;
3784dcbf3bd6SGeorge Wilson 		goto out;
3785dcbf3bd6SGeorge Wilson 	}
3786dcbf3bd6SGeorge Wilson 
3787dcbf3bd6SGeorge Wilson 	if (data.arc_cflags & ARC_CFLAG_VERBOSE) {
3788dcbf3bd6SGeorge Wilson 		rc = mdb_snprintf(range, sizeof (range),
3789dcbf3bd6SGeorge Wilson 		    "[n*%llu, (n+1)*%llu)", SPA_MINBLOCKSIZE,
3790dcbf3bd6SGeorge Wilson 		    SPA_MINBLOCKSIZE);
3791dcbf3bd6SGeorge Wilson 	} else {
3792dcbf3bd6SGeorge Wilson 		rc = mdb_snprintf(range, sizeof (range),
3793dcbf3bd6SGeorge Wilson 		    "[2^(n-1)*%llu, 2^n*%llu)", SPA_MINBLOCKSIZE,
3794dcbf3bd6SGeorge Wilson 		    SPA_MINBLOCKSIZE);
3795dcbf3bd6SGeorge Wilson 	}
3796dcbf3bd6SGeorge Wilson 
3797dcbf3bd6SGeorge Wilson 	if (rc < 0) {
3798dcbf3bd6SGeorge Wilson 		/* snprintf failed, abort the dcmd */
3799dcbf3bd6SGeorge Wilson 		rc = DCMD_ERR;
3800dcbf3bd6SGeorge Wilson 		goto out;
3801dcbf3bd6SGeorge Wilson 	} else {
3802dcbf3bd6SGeorge Wilson 		/* snprintf succeeded above, reset return code */
3803dcbf3bd6SGeorge Wilson 		rc = DCMD_OK;
3804dcbf3bd6SGeorge Wilson 	}
3805dcbf3bd6SGeorge Wilson 
3806dcbf3bd6SGeorge Wilson 	if (data.arc_cflags & ARC_CFLAG_ANON) {
3807dcbf3bd6SGeorge Wilson 		if (data.arc_cflags & ARC_CFLAG_BUFS) {
3808dcbf3bd6SGeorge Wilson 			mdb_printf("Histogram of the number of anon buffers "
3809dcbf3bd6SGeorge Wilson 			    "that are associated with an arc hdr.\n");
3810dcbf3bd6SGeorge Wilson 			dump_histogram(data.anon_bufs, data.hist_nbuckets, 0);
3811dcbf3bd6SGeorge Wilson 			mdb_printf("\n");
3812dcbf3bd6SGeorge Wilson 		}
3813dcbf3bd6SGeorge Wilson 		mdb_printf("Histogram of compressed anon buffers.\n"
3814dcbf3bd6SGeorge Wilson 		    "Each bucket represents buffers of size: %s.\n", range);
3815dcbf3bd6SGeorge Wilson 		dump_histogram(data.anon_c_hist, data.hist_nbuckets, 0);
3816dcbf3bd6SGeorge Wilson 		mdb_printf("\n");
3817dcbf3bd6SGeorge Wilson 
3818dcbf3bd6SGeorge Wilson 		mdb_printf("Histogram of uncompressed anon buffers.\n"
3819dcbf3bd6SGeorge Wilson 		    "Each bucket represents buffers of size: %s.\n", range);
3820dcbf3bd6SGeorge Wilson 		dump_histogram(data.anon_u_hist, data.hist_nbuckets, 0);
3821dcbf3bd6SGeorge Wilson 		mdb_printf("\n");
3822dcbf3bd6SGeorge Wilson 	}
3823dcbf3bd6SGeorge Wilson 
3824dcbf3bd6SGeorge Wilson 	if (data.arc_cflags & ARC_CFLAG_MRU) {
3825dcbf3bd6SGeorge Wilson 		if (data.arc_cflags & ARC_CFLAG_BUFS) {
3826dcbf3bd6SGeorge Wilson 			mdb_printf("Histogram of the number of mru buffers "
3827dcbf3bd6SGeorge Wilson 			    "that are associated with an arc hdr.\n");
3828dcbf3bd6SGeorge Wilson 			dump_histogram(data.mru_bufs, data.hist_nbuckets, 0);
3829dcbf3bd6SGeorge Wilson 			mdb_printf("\n");
3830dcbf3bd6SGeorge Wilson 		}
3831dcbf3bd6SGeorge Wilson 		mdb_printf("Histogram of compressed mru buffers.\n"
3832dcbf3bd6SGeorge Wilson 		    "Each bucket represents buffers of size: %s.\n", range);
3833dcbf3bd6SGeorge Wilson 		dump_histogram(data.mru_c_hist, data.hist_nbuckets, 0);
3834dcbf3bd6SGeorge Wilson 		mdb_printf("\n");
3835dcbf3bd6SGeorge Wilson 
3836dcbf3bd6SGeorge Wilson 		mdb_printf("Histogram of uncompressed mru buffers.\n"
3837dcbf3bd6SGeorge Wilson 		    "Each bucket represents buffers of size: %s.\n", range);
3838dcbf3bd6SGeorge Wilson 		dump_histogram(data.mru_u_hist, data.hist_nbuckets, 0);
3839dcbf3bd6SGeorge Wilson 		mdb_printf("\n");
3840dcbf3bd6SGeorge Wilson 	}
3841dcbf3bd6SGeorge Wilson 
3842dcbf3bd6SGeorge Wilson 	if (data.arc_cflags & ARC_CFLAG_MFU) {
3843dcbf3bd6SGeorge Wilson 		if (data.arc_cflags & ARC_CFLAG_BUFS) {
3844dcbf3bd6SGeorge Wilson 			mdb_printf("Histogram of the number of mfu buffers "
3845dcbf3bd6SGeorge Wilson 			    "that are associated with an arc hdr.\n");
3846dcbf3bd6SGeorge Wilson 			dump_histogram(data.mfu_bufs, data.hist_nbuckets, 0);
3847dcbf3bd6SGeorge Wilson 			mdb_printf("\n");
3848dcbf3bd6SGeorge Wilson 		}
3849dcbf3bd6SGeorge Wilson 
3850dcbf3bd6SGeorge Wilson 		mdb_printf("Histogram of compressed mfu buffers.\n"
3851dcbf3bd6SGeorge Wilson 		    "Each bucket represents buffers of size: %s.\n", range);
3852dcbf3bd6SGeorge Wilson 		dump_histogram(data.mfu_c_hist, data.hist_nbuckets, 0);
3853dcbf3bd6SGeorge Wilson 		mdb_printf("\n");
3854dcbf3bd6SGeorge Wilson 
3855dcbf3bd6SGeorge Wilson 		mdb_printf("Histogram of uncompressed mfu buffers.\n"
3856dcbf3bd6SGeorge Wilson 		    "Each bucket represents buffers of size: %s.\n", range);
3857dcbf3bd6SGeorge Wilson 		dump_histogram(data.mfu_u_hist, data.hist_nbuckets, 0);
3858dcbf3bd6SGeorge Wilson 		mdb_printf("\n");
3859dcbf3bd6SGeorge Wilson 	}
3860dcbf3bd6SGeorge Wilson 
3861dcbf3bd6SGeorge Wilson 	if (data.arc_cflags & ARC_CFLAG_BUFS) {
3862dcbf3bd6SGeorge Wilson 		mdb_printf("Histogram of all buffers that "
3863dcbf3bd6SGeorge Wilson 		    "are associated with an arc hdr.\n");
3864dcbf3bd6SGeorge Wilson 		dump_histogram(data.all_bufs, data.hist_nbuckets, 0);
3865dcbf3bd6SGeorge Wilson 		mdb_printf("\n");
3866dcbf3bd6SGeorge Wilson 	}
3867dcbf3bd6SGeorge Wilson 
3868dcbf3bd6SGeorge Wilson 	mdb_printf("Histogram of all compressed buffers.\n"
3869dcbf3bd6SGeorge Wilson 	    "Each bucket represents buffers of size: %s.\n", range);
3870dcbf3bd6SGeorge Wilson 	dump_histogram(data.all_c_hist, data.hist_nbuckets, 0);
3871dcbf3bd6SGeorge Wilson 	mdb_printf("\n");
3872dcbf3bd6SGeorge Wilson 
3873dcbf3bd6SGeorge Wilson 	mdb_printf("Histogram of all uncompressed buffers.\n"
3874dcbf3bd6SGeorge Wilson 	    "Each bucket represents buffers of size: %s.\n", range);
3875dcbf3bd6SGeorge Wilson 	dump_histogram(data.all_u_hist, data.hist_nbuckets, 0);
3876dcbf3bd6SGeorge Wilson 
3877dcbf3bd6SGeorge Wilson out:
3878dcbf3bd6SGeorge Wilson 	mdb_free(data.anon_c_hist, hist_size);
3879dcbf3bd6SGeorge Wilson 	mdb_free(data.anon_u_hist, hist_size);
3880dcbf3bd6SGeorge Wilson 	mdb_free(data.anon_bufs, hist_size);
3881dcbf3bd6SGeorge Wilson 
3882dcbf3bd6SGeorge Wilson 	mdb_free(data.mru_c_hist, hist_size);
3883dcbf3bd6SGeorge Wilson 	mdb_free(data.mru_u_hist, hist_size);
3884dcbf3bd6SGeorge Wilson 	mdb_free(data.mru_bufs, hist_size);
3885dcbf3bd6SGeorge Wilson 
3886dcbf3bd6SGeorge Wilson 	mdb_free(data.mfu_c_hist, hist_size);
3887dcbf3bd6SGeorge Wilson 	mdb_free(data.mfu_u_hist, hist_size);
3888dcbf3bd6SGeorge Wilson 	mdb_free(data.mfu_bufs, hist_size);
3889dcbf3bd6SGeorge Wilson 
3890dcbf3bd6SGeorge Wilson 	mdb_free(data.all_c_hist, hist_size);
3891dcbf3bd6SGeorge Wilson 	mdb_free(data.all_u_hist, hist_size);
3892dcbf3bd6SGeorge Wilson 	mdb_free(data.all_bufs, hist_size);
3893dcbf3bd6SGeorge Wilson 
3894dcbf3bd6SGeorge Wilson 	return (rc);
3895dcbf3bd6SGeorge Wilson }
3896dcbf3bd6SGeorge Wilson 
3897fa9e4066Sahrens /*
3898fa9e4066Sahrens  * MDB module linkage information:
3899fa9e4066Sahrens  *
3900fa9e4066Sahrens  * We declare a list of structures describing our dcmds, and a function
3901fa9e4066Sahrens  * named _mdb_init to return a pointer to our module information.
3902fa9e4066Sahrens  */
3903fa9e4066Sahrens 
3904fa9e4066Sahrens static const mdb_dcmd_t dcmds[] = {
390591ebeef5Sahrens 	{ "arc", "[-bkmg]", "print ARC variables", arc_print },
3906fa9e4066Sahrens 	{ "blkptr", ":", "print blkptr_t", blkptr },
3907fa9e4066Sahrens 	{ "dbuf", ":", "print dmu_buf_impl_t", dbuf },
3908fa9e4066Sahrens 	{ "dbuf_stats", ":", "dbuf stats", dbuf_stats },
3909fa9e4066Sahrens 	{ "dbufs",
39104223fc7cSMark Shellenbaum 	    "\t[-O objset_t*] [-n objset_name | \"mos\"] "
3911a3f829aeSBill Moore 	    "[-o object | \"mdn\"] \n"
3912a3f829aeSBill Moore 	    "\t[-l level] [-b blkid | \"bonus\"]",
3913a3f829aeSBill Moore 	    "find dmu_buf_impl_t's that match specified criteria", dbufs },
3914fa9e4066Sahrens 	{ "abuf_find", "dva_word[0] dva_word[1]",
3915a3f829aeSBill Moore 	    "find arc_buf_hdr_t of a specified DVA",
3916a3f829aeSBill Moore 	    abuf_find },
39172e4c9986SGeorge Wilson 	{ "spa", "?[-cevmMh]\n"
39182e4c9986SGeorge Wilson 	    "\t-c display spa config\n"
39192e4c9986SGeorge Wilson 	    "\t-e display vdev statistics\n"
39202e4c9986SGeorge Wilson 	    "\t-v display vdev information\n"
39212e4c9986SGeorge Wilson 	    "\t-m display metaslab statistics\n"
39222e4c9986SGeorge Wilson 	    "\t-M display metaslab group statistics\n"
39232e4c9986SGeorge Wilson 	    "\t-h display histogram (requires -m or -M)\n",
39242e4c9986SGeorge Wilson 	    "spa_t summary", spa_print },
3925fa9e4066Sahrens 	{ "spa_config", ":", "print spa_t configuration", spa_print_config },
3926fa9e4066Sahrens 	{ "spa_space", ":[-b]", "print spa_t on-disk space usage", spa_space },
39272e4c9986SGeorge Wilson 	{ "spa_vdevs", ":[-emMh]\n"
39282e4c9986SGeorge Wilson 	    "\t-e display vdev statistics\n"
39292e4c9986SGeorge Wilson 	    "\t-m dispaly metaslab statistics\n"
39302e4c9986SGeorge Wilson 	    "\t-M display metaslab group statistic\n"
39312e4c9986SGeorge Wilson 	    "\t-h display histogram (requires -m or -M)\n",
39322e4c9986SGeorge Wilson 	    "given a spa_t, print vdev summary", spa_vdevs },
393391e2a09fSSteve Gonczi 	{ "vdev", ":[-remMh]\n"
3934a3f829aeSBill Moore 	    "\t-r display recursively\n"
39352e4c9986SGeorge Wilson 	    "\t-e display statistics\n"
393691e2a09fSSteve Gonczi 	    "\t-m display metaslab statistics (top level vdev only)\n"
393791e2a09fSSteve Gonczi 	    "\t-M display metaslab group statistics (top level vdev only)\n"
39382e4c9986SGeorge Wilson 	    "\t-h display histogram (requires -m or -M)\n",
3939a3f829aeSBill Moore 	    "vdev_t summary", vdev_print },
39402e4c9986SGeorge Wilson 	{ "zio", ":[-cpr]\n"
3941a3f829aeSBill Moore 	    "\t-c display children\n"
3942a3f829aeSBill Moore 	    "\t-p display parents\n"
3943a3f829aeSBill Moore 	    "\t-r display recursively",
3944a3f829aeSBill Moore 	    "zio_t summary", zio_print },
3945ccae0b50Seschrock 	{ "zio_state", "?", "print out all zio_t structures on system or "
3946ccae0b50Seschrock 	    "for a particular pool", zio_state },
394788b7b0f2SMatthew Ahrens 	{ "zfs_blkstats", ":[-v]",
394888b7b0f2SMatthew Ahrens 	    "given a spa_t, print block type stats from last scrub",
394988b7b0f2SMatthew Ahrens 	    zfs_blkstats },
3950614409b5Sahrens 	{ "zfs_params", "", "print zfs tunable parameters", zfs_params },
395128e4da25SMatthew Ahrens 	{ "refcount", ":[-r]\n"
395228e4da25SMatthew Ahrens 	    "\t-r display recently removed references",
395328e4da25SMatthew Ahrens 	    "print refcount_t holders", refcount },
39543f1f8012SMatthew Ahrens 	{ "zap_leaf", "", "print zap_leaf_phys_t", zap_leaf },
39550a586ceaSMark Shellenbaum 	{ "zfs_aces", ":[-v]", "print all ACEs from a zfs_acl_t",
39560a586ceaSMark Shellenbaum 	    zfs_acl_dump },
39570a586ceaSMark Shellenbaum 	{ "zfs_ace", ":[-v]", "print zfs_ace", zfs_ace_print },
39580a586ceaSMark Shellenbaum 	{ "zfs_ace0", ":[-v]", "print zfs_ace0", zfs_ace0_print },
39590a586ceaSMark Shellenbaum 	{ "sa_attr_table", ":", "print SA attribute table from sa_os_t",
39600a586ceaSMark Shellenbaum 	    sa_attr_table},
39610a586ceaSMark Shellenbaum 	{ "sa_attr", ": attr_id",
39620a586ceaSMark Shellenbaum 	    "print SA attribute address when given sa_handle_t", sa_attr_print},
396328e4da25SMatthew Ahrens 	{ "zfs_dbgmsg", ":[-va]",
39643f9d6ad7SLin Ling 	    "print zfs debug log", dbgmsg},
396528e4da25SMatthew Ahrens 	{ "rrwlock", ":",
396628e4da25SMatthew Ahrens 	    "print rrwlock_t, including readers", rrwlock},
3967*8363e80aSGeorge Wilson 	{ "metaslab_weight", "weight",
3968*8363e80aSGeorge Wilson 	    "print metaslab weight", metaslab_weight},
3969*8363e80aSGeorge Wilson 	{ "metaslab_trace", ":",
3970*8363e80aSGeorge Wilson 	    "print metaslab allocation trace records", metaslab_trace},
3971dcbf3bd6SGeorge Wilson 	{ "arc_compression_stats", ":[-vabrf]\n"
3972dcbf3bd6SGeorge Wilson 	    "\t-v verbose, display a linearly scaled histogram\n"
3973dcbf3bd6SGeorge Wilson 	    "\t-a display ARC_anon state statistics individually\n"
3974dcbf3bd6SGeorge Wilson 	    "\t-r display ARC_mru state statistics individually\n"
3975dcbf3bd6SGeorge Wilson 	    "\t-f display ARC_mfu state statistics individually\n"
3976dcbf3bd6SGeorge Wilson 	    "\t-b display histogram of buffer counts\n",
3977dcbf3bd6SGeorge Wilson 	    "print a histogram of compressed arc buffer sizes",
3978dcbf3bd6SGeorge Wilson 	    arc_compression_stats},
3979fa9e4066Sahrens 	{ NULL }
3980fa9e4066Sahrens };
3981fa9e4066Sahrens 
3982fa9e4066Sahrens static const mdb_walker_t walkers[] = {
3983fa9e4066Sahrens 	{ "zms_freelist", "walk ZFS metaslab freelist",
398428e4da25SMatthew Ahrens 	    freelist_walk_init, freelist_walk_step, NULL },
3985fa9e4066Sahrens 	{ "txg_list", "given any txg_list_t *, walk all entries in all txgs",
398628e4da25SMatthew Ahrens 	    txg_list_walk_init, txg_list_walk_step, NULL },
3987fa9e4066Sahrens 	{ "txg_list0", "given any txg_list_t *, walk all entries in txg 0",
398828e4da25SMatthew Ahrens 	    txg_list0_walk_init, txg_list_walk_step, NULL },
3989fa9e4066Sahrens 	{ "txg_list1", "given any txg_list_t *, walk all entries in txg 1",
399028e4da25SMatthew Ahrens 	    txg_list1_walk_init, txg_list_walk_step, NULL },
3991fa9e4066Sahrens 	{ "txg_list2", "given any txg_list_t *, walk all entries in txg 2",
399228e4da25SMatthew Ahrens 	    txg_list2_walk_init, txg_list_walk_step, NULL },
3993fa9e4066Sahrens 	{ "txg_list3", "given any txg_list_t *, walk all entries in txg 3",
399428e4da25SMatthew Ahrens 	    txg_list3_walk_init, txg_list_walk_step, NULL },
3995ccae0b50Seschrock 	{ "zio", "walk all zio structures, optionally for a particular spa_t",
399628e4da25SMatthew Ahrens 	    zio_walk_init, zio_walk_step, NULL },
399728e4da25SMatthew Ahrens 	{ "zio_root",
399828e4da25SMatthew Ahrens 	    "walk all root zio_t structures, optionally for a particular spa_t",
399928e4da25SMatthew Ahrens 	    zio_walk_init, zio_walk_root_step, NULL },
4000fa9e4066Sahrens 	{ "spa", "walk all spa_t entries in the namespace",
400128e4da25SMatthew Ahrens 	    spa_walk_init, spa_walk_step, NULL },
40025f5f7a6fSahrens 	{ "metaslab", "given a spa_t *, walk all metaslab_t structures",
400328e4da25SMatthew Ahrens 	    metaslab_walk_init, metaslab_walk_step, NULL },
4004dcbf3bd6SGeorge Wilson 	{ "multilist", "given a multilist_t *, walk all list_t structures",
4005dcbf3bd6SGeorge Wilson 	    multilist_walk_init, multilist_walk_step, NULL },
40060a586ceaSMark Shellenbaum 	{ "zfs_acl_node", "given a zfs_acl_t, walk all zfs_acl_nodes",
40070a586ceaSMark Shellenbaum 	    zfs_acl_node_walk_init, zfs_acl_node_walk_step, NULL },
40080a586ceaSMark Shellenbaum 	{ "zfs_acl_node_aces", "given a zfs_acl_node_t, walk all ACEs",
40090a586ceaSMark Shellenbaum 	    zfs_acl_node_aces_walk_init, zfs_aces_walk_step, NULL },
40100a586ceaSMark Shellenbaum 	{ "zfs_acl_node_aces0",
40110a586ceaSMark Shellenbaum 	    "given a zfs_acl_node_t, walk all ACEs as ace_t",
40120a586ceaSMark Shellenbaum 	    zfs_acl_node_aces0_walk_init, zfs_aces_walk_step, NULL },
4013fa9e4066Sahrens 	{ NULL }
4014fa9e4066Sahrens };
4015fa9e4066Sahrens 
4016fa9e4066Sahrens static const mdb_modinfo_t modinfo = {
4017fa9e4066Sahrens 	MDB_API_VERSION, dcmds, walkers
4018fa9e4066Sahrens };
4019fa9e4066Sahrens 
4020fa9e4066Sahrens const mdb_modinfo_t *
4021fa9e4066Sahrens _mdb_init(void)
4022fa9e4066Sahrens {
4023fa9e4066Sahrens 	return (&modinfo);
4024fa9e4066Sahrens }
4025