4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 #include <mdb/mdb_ctf.h>
27 #include <sys/zfs_context.h>
28 #include <sys/mdb_modapi.h>
30 #include <sys/dmu_objset.h>
31 #include <sys/dsl_dir.h>
32 #include <sys/dsl_pool.h>
33 #include <sys/metaslab_impl.h>
34 #include <sys/space_map.h>
36 #include <sys/spa_impl.h>
37 #include <sys/vdev_impl.h>
38 #include <sys/zio_compress.h>
41 #include "../genunix/list.h"
45 #define ZFS_OBJ_NAME "zfs"
47 #define ZFS_OBJ_NAME "libzpool.so.1"
51 local_strdup(const char *s
)
53 char *s1
= mdb_alloc(strlen(s
) + 1, UM_SLEEP
);
60 getmember(uintptr_t addr
, const char *type
, mdb_ctf_id_t
*idp
,
61 const char *member
, int len
, void *buf
)
68 if (mdb_ctf_lookup_by_name(type
, &id
) == -1) {
69 mdb_warn("couldn't find type %s", type
);
75 mdb_ctf_type_name(*idp
, name
, sizeof (name
));
78 if (mdb_ctf_offsetof(*idp
, member
, &off
) == -1) {
79 mdb_warn("couldn't find member %s of type %s\n", member
, type
);
83 mdb_warn("member %s of type %s is unsupported bitfield",
89 if (mdb_vread(buf
, len
, addr
+ off
) == -1) {
90 mdb_warn("failed to read %s from %s at %p",
91 member
, type
, addr
+ off
);
94 /* mdb_warn("read %s from %s at %p+%llx\n", member, type, addr, off); */
99 #define GETMEMB(addr, type, member, dest) \
100 getmember(addr, #type, NULL, #member, sizeof (dest), &(dest))
102 #define GETMEMBID(addr, ctfid, member, dest) \
103 getmember(addr, NULL, ctfid, #member, sizeof (dest), &(dest))
106 getrefcount(uintptr_t addr
, mdb_ctf_id_t
*id
,
107 const char *member
, uint64_t *rc
)
110 static mdb_ctf_id_t rc_id
;
114 if (mdb_ctf_lookup_by_name("struct refcount", &rc_id
) == -1) {
115 mdb_warn("couldn't find struct refcount");
121 if (mdb_ctf_offsetof(*id
, member
, &off
) == -1) {
123 mdb_ctf_type_name(*id
, name
, sizeof (name
));
124 mdb_warn("couldn't find member %s of type %s\n", member
, name
);
129 return (GETMEMBID(addr
+ off
, &rc_id
, rc_count
, *rc
));
133 read_symbol(char *sym_name
, void **bufp
)
137 if (mdb_lookup_by_obj(MDB_TGT_OBJ_EVERY
, sym_name
, &sym
)) {
138 mdb_warn("can't find symbol %s", sym_name
);
142 *bufp
= mdb_alloc(sym
.st_size
, UM_SLEEP
);
144 if (mdb_vread(*bufp
, sym
.st_size
, sym
.st_value
) == -1) {
145 mdb_warn("can't read data for symbol %s", sym_name
);
146 mdb_free(*bufp
, sym
.st_size
);
156 freelist_walk_init(mdb_walk_state_t
*wsp
)
158 if (wsp
->walk_addr
== NULL
) {
159 mdb_warn("must supply starting address\n");
163 wsp
->walk_data
= 0; /* Index into the freelist */
168 freelist_walk_step(mdb_walk_state_t
*wsp
)
171 uintptr_t number
= (uintptr_t)wsp
->walk_data
;
172 char *ddata
[] = { "ALLOC", "FREE", "CONDENSE", "INVALID",
173 "INVALID", "INVALID", "INVALID", "INVALID" };
174 int mapshift
= SPA_MINBLOCKSHIFT
;
176 if (mdb_vread(&entry
, sizeof (entry
), wsp
->walk_addr
) == -1) {
177 mdb_warn("failed to read freelist entry %p", wsp
->walk_addr
);
180 wsp
->walk_addr
+= sizeof (entry
);
181 wsp
->walk_data
= (void *)(number
+ 1);
183 if (SM_DEBUG_DECODE(entry
)) {
184 mdb_printf("DEBUG: %3u %10s: txg=%llu pass=%llu\n",
186 ddata
[SM_DEBUG_ACTION_DECODE(entry
)],
187 SM_DEBUG_TXG_DECODE(entry
),
188 SM_DEBUG_SYNCPASS_DECODE(entry
));
190 mdb_printf("Entry: %3u offsets=%08llx-%08llx type=%c "
191 "size=%06llx", number
,
192 SM_OFFSET_DECODE(entry
) << mapshift
,
193 (SM_OFFSET_DECODE(entry
) + SM_RUN_DECODE(entry
)) <<
195 SM_TYPE_DECODE(entry
) == SM_ALLOC
? 'A' : 'F',
196 SM_RUN_DECODE(entry
) << mapshift
);
198 mdb_printf(" (raw=%012llx)\n", entry
);
206 dataset_name(uintptr_t addr
, char *buf
)
209 static mdb_ctf_id_t dd_id
;
211 char dd_myname
[MAXNAMELEN
];
214 if (mdb_ctf_lookup_by_name("struct dsl_dir",
216 mdb_warn("couldn't find struct dsl_dir");
221 if (GETMEMBID(addr
, &dd_id
, dd_parent
, dd_parent
) ||
222 GETMEMBID(addr
, &dd_id
, dd_myname
, dd_myname
)) {
227 if (dataset_name(dd_parent
, buf
))
233 strcat(buf
, dd_myname
);
241 objset_name(uintptr_t addr
, char *buf
)
244 static mdb_ctf_id_t osi_id
, ds_id
;
245 uintptr_t os_dsl_dataset
;
246 char ds_snapname
[MAXNAMELEN
];
252 if (mdb_ctf_lookup_by_name("struct objset_impl",
254 mdb_warn("couldn't find struct objset_impl");
257 if (mdb_ctf_lookup_by_name("struct dsl_dataset",
259 mdb_warn("couldn't find struct dsl_dataset");
266 if (GETMEMBID(addr
, &osi_id
, os_dsl_dataset
, os_dsl_dataset
))
269 if (os_dsl_dataset
== 0) {
274 if (GETMEMBID(os_dsl_dataset
, &ds_id
, ds_snapname
, ds_snapname
) ||
275 GETMEMBID(os_dsl_dataset
, &ds_id
, ds_dir
, ds_dir
)) {
279 if (ds_dir
&& dataset_name(ds_dir
, buf
))
282 if (ds_snapname
[0]) {
284 strcat(buf
, ds_snapname
);
290 enum_lookup(char *out
, size_t size
, mdb_ctf_id_t id
, int val
,
294 size_t len
= strlen(prefix
);
296 if ((cp
= mdb_ctf_enum_name(id
, val
)) != NULL
) {
297 if (strncmp(cp
, prefix
, len
) == 0)
299 (void) strncpy(out
, cp
, size
);
301 mdb_snprintf(out
, size
, "? (%d)", val
);
307 zio_pipeline(uintptr_t addr
, uint_t flags
, int argc
, const mdb_arg_t
*argv
)
309 mdb_ctf_id_t pipe_enum
;
313 if (mdb_ctf_lookup_by_name("enum zio_stage", &pipe_enum
) == -1) {
314 mdb_warn("Could not find enum zio_stage");
318 for (i
= 0; i
< 32; i
++) {
319 if (addr
& (1U << i
)) {
320 enum_lookup(stage
, sizeof (stage
), pipe_enum
, i
,
322 mdb_printf(" %s\n", stage
);
331 zfs_params(uintptr_t addr
, uint_t flags
, int argc
, const mdb_arg_t
*argv
)
334 * This table can be approximately generated by running:
335 * egrep "^[a-z0-9_]+ [a-z0-9_]+( =.*)?;" *.c | cut -d ' ' -f 2
337 static const char *params
[] = {
338 "arc_reduce_dnlc_percent",
342 "zfs_mdcomp_disable",
343 "zfs_prefetch_disable",
344 "zfetch_max_streams",
345 "zfetch_min_sec_reap",
347 "zfetch_array_rd_sz",
351 "reference_tracking_enable",
354 "spa_max_replication_override",
359 "zfs_write_limit_min",
360 "zfs_write_limit_max",
361 "zfs_write_limit_shift",
362 "zfs_write_limit_override",
363 "zfs_no_write_throttle",
364 "zfs_vdev_cache_max",
365 "zfs_vdev_cache_size",
366 "zfs_vdev_cache_bshift",
368 "zfs_vdev_max_pending",
369 "zfs_vdev_min_pending",
371 "zfs_vdev_time_shift",
372 "zfs_vdev_ramp_rate",
373 "zfs_vdev_aggregation_limit",
374 "fzap_default_block_shift",
375 "zfs_immediate_write_sz",
376 "zfs_read_chunk_size",
379 "metaslab_gang_bang",
380 "zio_injection_enabled",
381 "zvol_immediate_write_sz",
385 for (i
= 0; i
< sizeof (params
) / sizeof (params
[0]); i
++) {
388 uint32_t *val32p
= (uint32_t *)&val64
;
390 sz
= mdb_readvar(&val64
, params
[i
]);
392 mdb_printf("%s = 0x%x\n", params
[i
], *val32p
);
393 } else if (sz
== 8) {
394 mdb_printf("%s = 0x%llx\n", params
[i
], val64
);
396 mdb_warn("variable %s not found", params
[i
]);
405 blkptr(uintptr_t addr
, uint_t flags
, int argc
, const mdb_arg_t
*argv
)
408 dmu_object_type_info_t
*doti
;
409 zio_compress_info_t
*zct
;
410 zio_checksum_info_t
*zci
;
412 char buf
[MAXPATHLEN
];
414 if (mdb_vread(&bp
, sizeof (blkptr_t
), addr
) == -1) {
415 mdb_warn("failed to read blkptr_t");
419 if (read_symbol("dmu_ot", (void **)&doti
) != DCMD_OK
)
421 for (i
= 0; i
< DMU_OT_NUMTYPES
; i
++) {
422 mdb_readstr(buf
, sizeof (buf
), (uintptr_t)doti
[i
].ot_name
);
423 doti
[i
].ot_name
= local_strdup(buf
);
426 if (read_symbol("zio_checksum_table", (void **)&zci
) != DCMD_OK
)
428 for (i
= 0; i
< ZIO_CHECKSUM_FUNCTIONS
; i
++) {
429 mdb_readstr(buf
, sizeof (buf
), (uintptr_t)zci
[i
].ci_name
);
430 zci
[i
].ci_name
= local_strdup(buf
);
433 if (read_symbol("zio_compress_table", (void **)&zct
) != DCMD_OK
)
435 for (i
= 0; i
< ZIO_COMPRESS_FUNCTIONS
; i
++) {
436 mdb_readstr(buf
, sizeof (buf
), (uintptr_t)zct
[i
].ci_name
);
437 zct
[i
].ci_name
= local_strdup(buf
);
441 * Super-ick warning: This code is also duplicated in
442 * cmd/zdb.c . Yeah, I hate code replication, too.
444 for (i
= 0; i
< BP_GET_NDVAS(&bp
); i
++) {
445 dva_t
*dva
= &bp
.blk_dva
[i
];
447 mdb_printf("DVA[%d]: vdev_id %lld / %llx\n", i
,
448 DVA_GET_VDEV(dva
), DVA_GET_OFFSET(dva
));
449 mdb_printf("DVA[%d]: GANG: %-5s GRID: %04x\t"
450 "ASIZE: %llx\n", i
, DVA_GET_GANG(dva
) ? "TRUE" : "FALSE",
451 DVA_GET_GRID(dva
), DVA_GET_ASIZE(dva
));
452 mdb_printf("DVA[%d]: :%llu:%llx:%llx:%s%s%s%s\n", i
,
453 DVA_GET_VDEV(dva
), DVA_GET_OFFSET(dva
), BP_GET_PSIZE(&bp
),
454 BP_SHOULD_BYTESWAP(&bp
) ? "e" : "",
455 !DVA_GET_GANG(dva
) && BP_GET_LEVEL(&bp
) != 0 ? "i" : "",
456 DVA_GET_GANG(dva
) ? "g" : "",
457 BP_GET_COMPRESS(&bp
) != 0 ? "d" : "");
459 mdb_printf("LSIZE: %-16llx\t\tPSIZE: %llx\n",
460 BP_GET_LSIZE(&bp
), BP_GET_PSIZE(&bp
));
461 mdb_printf("ENDIAN: %6s\t\t\t\t\tTYPE: %s\n",
462 BP_GET_BYTEORDER(&bp
) ? "LITTLE" : "BIG",
463 doti
[BP_GET_TYPE(&bp
)].ot_name
);
464 mdb_printf("BIRTH: %-16llx LEVEL: %-2d\tFILL: %llx\n",
465 bp
.blk_birth
, BP_GET_LEVEL(&bp
), bp
.blk_fill
);
466 mdb_printf("CKFUNC: %-16s\t\tCOMP: %s\n",
467 zci
[BP_GET_CHECKSUM(&bp
)].ci_name
,
468 zct
[BP_GET_COMPRESS(&bp
)].ci_name
);
469 mdb_printf("CKSUM: %llx:%llx:%llx:%llx\n",
470 bp
.blk_cksum
.zc_word
[0],
471 bp
.blk_cksum
.zc_word
[1],
472 bp
.blk_cksum
.zc_word
[2],
473 bp
.blk_cksum
.zc_word
[3]);
480 dbuf(uintptr_t addr
, uint_t flags
, int argc
, const mdb_arg_t
*argv
)
490 char path
[MAXNAMELEN
];
492 if (DCMD_HDRSPEC(flags
)) {
493 mdb_printf(" addr object lvl blkid holds os\n");
496 if (mdb_ctf_lookup_by_name("struct dmu_buf_impl", &id
) == -1) {
497 mdb_warn("couldn't find struct dmu_buf_impl_t");
501 if (GETMEMBID(addr
, &id
, db_objset
, objset
) ||
502 GETMEMBID(addr
, &id
, db
, db
) ||
503 GETMEMBID(addr
, &id
, db_level
, level
) ||
504 GETMEMBID(addr
, &id
, db_blkid
, blkid
)) {
508 if (getrefcount(addr
, &id
, "db_holds", &holds
)) {
512 if (db
.db_object
== DMU_META_DNODE_OBJECT
)
513 (void) strcpy(objectname
, "mdn");
515 (void) mdb_snprintf(objectname
, sizeof (objectname
), "%llx",
516 (u_longlong_t
)db
.db_object
);
518 if (blkid
== DB_BONUS_BLKID
)
519 (void) strcpy(blkidname
, "bonus");
521 (void) mdb_snprintf(blkidname
, sizeof (blkidname
), "%llx",
522 (u_longlong_t
)blkid
);
524 if (objset_name(objset
, path
)) {
528 mdb_printf("%p %8s %1u %9s %2llu %s\n",
529 addr
, objectname
, level
, blkidname
, holds
, path
);
536 dbuf_stats(uintptr_t addr
, uint_t flags
, int argc
, const mdb_arg_t
*argv
)
541 dbuf_hash_table_t ht
;
542 uint64_t bucket
, ndbufs
;
543 uint64_t histo
[HISTOSZ
];
544 uint64_t histo2
[HISTOSZ
];
547 if (mdb_readvar(&ht
, "dbuf_hash_table") == -1) {
548 mdb_warn("failed to read 'dbuf_hash_table'");
552 for (i
= 0; i
< HISTOSZ
; i
++) {
558 for (bucket
= 0; bucket
< ht
.hash_table_mask
+1; bucket
++) {
561 if (mdb_vread(&dbp
, sizeof (void *),
562 (uintptr_t)(ht
.hash_table
+bucket
)) == -1) {
563 mdb_warn("failed to read hash bucket %u at %p",
564 bucket
, ht
.hash_table
+bucket
);
570 if (mdb_vread(&db
, sizeof (dmu_buf_impl_t
),
572 mdb_warn("failed to read dbuf at %p", dbp
);
575 dbp
= (uintptr_t)db
.db_hash_next
;
576 for (i
= MIN(len
, HISTOSZ
- 1); i
>= 0; i
--)
587 mdb_printf("hash table has %llu buckets, %llu dbufs "
588 "(avg %llu buckets/dbuf)\n",
589 ht
.hash_table_mask
+1, ndbufs
,
590 (ht
.hash_table_mask
+1)/ndbufs
);
594 for (i
= 0; i
< HISTOSZ
; i
++)
597 mdb_printf("hash chain length number of buckets\n");
598 for (i
= 0; i
<= maxidx
; i
++)
599 mdb_printf("%u %llu\n", i
, histo
[i
]);
603 for (i
= 0; i
< HISTOSZ
; i
++)
606 mdb_printf("hash chain depth number of dbufs\n");
607 for (i
= 0; i
<= maxidx
; i
++)
608 mdb_printf("%u or more %llu %llu%%\n",
609 i
, histo2
[i
], histo2
[i
]*100/ndbufs
);
615 typedef struct dbufs_data
{
624 #define DBUFS_UNSET (0xbaddcafedeadbeefULL)
628 dbufs_cb(uintptr_t addr
, const void *unknown
, void *arg
)
630 dbufs_data_t
*data
= arg
;
635 char osname
[MAXNAMELEN
];
637 if (GETMEMBID(addr
, &data
->id
, db_objset
, objset
) ||
638 GETMEMBID(addr
, &data
->id
, db
, db
) ||
639 GETMEMBID(addr
, &data
->id
, db_level
, level
) ||
640 GETMEMBID(addr
, &data
->id
, db_blkid
, blkid
)) {
644 if ((data
->objset
== DBUFS_UNSET
|| data
->objset
== objset
) &&
645 (data
->osname
== NULL
|| (objset_name(objset
, osname
) == 0 &&
646 strcmp(data
->osname
, osname
) == 0)) &&
647 (data
->object
== DBUFS_UNSET
|| data
->object
== db
.db_object
) &&
648 (data
->level
== DBUFS_UNSET
|| data
->level
== level
) &&
649 (data
->blkid
== DBUFS_UNSET
|| data
->blkid
== blkid
)) {
650 mdb_printf("%#lr\n", addr
);
657 dbufs(uintptr_t addr
, uint_t flags
, int argc
, const mdb_arg_t
*argv
)
663 data
.objset
= data
.object
= data
.level
= data
.blkid
= DBUFS_UNSET
;
666 if (mdb_getopts(argc
, argv
,
667 'O', MDB_OPT_UINT64
, &data
.objset
,
668 'n', MDB_OPT_STR
, &data
.osname
,
669 'o', MDB_OPT_STR
, &object
,
670 'l', MDB_OPT_UINT64
, &data
.level
,
671 'b', MDB_OPT_STR
, &blkid
) != argc
) {
676 if (strcmp(object
, "mdn") == 0) {
677 data
.object
= DMU_META_DNODE_OBJECT
;
679 data
.object
= mdb_strtoull(object
);
684 if (strcmp(blkid
, "bonus") == 0) {
685 data
.blkid
= DB_BONUS_BLKID
;
687 data
.blkid
= mdb_strtoull(blkid
);
691 if (mdb_ctf_lookup_by_name("struct dmu_buf_impl", &data
.id
) == -1) {
692 mdb_warn("couldn't find struct dmu_buf_impl_t");
696 if (mdb_walk("dmu_buf_impl_t", dbufs_cb
, &data
) != 0) {
697 mdb_warn("can't walk dbufs");
704 typedef struct abuf_find_data
{
711 abuf_find_cb(uintptr_t addr
, const void *unknown
, void *arg
)
713 abuf_find_data_t
*data
= arg
;
716 if (GETMEMBID(addr
, &data
->id
, b_dva
, dva
)) {
720 if (dva
.dva_word
[0] == data
->dva
.dva_word
[0] &&
721 dva
.dva_word
[1] == data
->dva
.dva_word
[1]) {
722 mdb_printf("%#lr\n", addr
);
729 abuf_find(uintptr_t addr
, uint_t flags
, int argc
, const mdb_arg_t
*argv
)
731 abuf_find_data_t data
;
734 const char *syms
[] = {
744 for (i
= 0; i
< 2; i
++) {
745 switch (argv
[i
].a_type
) {
746 case MDB_TYPE_STRING
:
747 data
.dva
.dva_word
[i
] = mdb_strtoull(argv
[i
].a_un
.a_str
);
749 case MDB_TYPE_IMMEDIATE
:
750 data
.dva
.dva_word
[i
] = argv
[i
].a_un
.a_val
;
757 if (mdb_ctf_lookup_by_name("struct arc_buf_hdr", &data
.id
) == -1) {
758 mdb_warn("couldn't find struct arc_buf_hdr");
762 for (i
= 0; i
< sizeof (syms
) / sizeof (syms
[0]); i
++) {
763 if (mdb_lookup_by_name(syms
[i
], &sym
)) {
764 mdb_warn("can't find symbol %s", syms
[i
]);
768 if (mdb_pwalk("list", abuf_find_cb
, &data
, sym
.st_value
) != 0) {
769 mdb_warn("can't walk %s", syms
[i
]);
779 arc_print(uintptr_t addr
, uint_t flags
, int argc
, const mdb_arg_t
*argv
)
781 kstat_named_t
*stats
;
784 uint_t opt_a
= FALSE
;
785 uint_t opt_b
= FALSE
;
789 static const char *bytestats
[] = {
790 "p", "c", "c_min", "c_max", "size", NULL
793 static const char *extras
[] = {
794 "arc_no_grow", "arc_tempreserve",
795 "arc_meta_used", "arc_meta_limit", "arc_meta_max",
799 if (mdb_lookup_by_name("arc_stats", &sym
) == -1) {
800 mdb_warn("failed to find 'arc_stats'");
804 stats
= mdb_zalloc(sym
.st_size
, UM_SLEEP
| UM_GC
);
806 if (mdb_vread(stats
, sym
.st_size
, sym
.st_value
) == -1) {
807 mdb_warn("couldn't read 'arc_stats' at %p", sym
.st_value
);
811 nstats
= sym
.st_size
/ sizeof (kstat_named_t
);
813 /* NB: -a / opt_a are ignored for backwards compatability */
814 if (mdb_getopts(argc
, argv
,
815 'a', MDB_OPT_SETBITS
, TRUE
, &opt_a
,
816 'b', MDB_OPT_SETBITS
, TRUE
, &opt_b
,
817 'k', MDB_OPT_SETBITS
, 10, &shift
,
818 'm', MDB_OPT_SETBITS
, 20, &shift
,
819 'g', MDB_OPT_SETBITS
, 30, &shift
,
823 if (!opt_b
&& !shift
)
843 for (i
= 0; i
< nstats
; i
++) {
845 boolean_t bytes
= B_FALSE
;
847 for (j
= 0; bytestats
[j
]; j
++) {
848 if (strcmp(stats
[i
].name
, bytestats
[j
]) == 0) {
855 mdb_printf("%-25s = %9llu %s\n", stats
[i
].name
,
856 stats
[i
].value
.ui64
>> shift
, suffix
);
858 mdb_printf("%-25s = %9llu\n", stats
[i
].name
,
859 stats
[i
].value
.ui64
);
863 for (i
= 0; extras
[i
]; i
++) {
866 if (mdb_lookup_by_name(extras
[i
], &sym
) == -1) {
867 mdb_warn("failed to find '%s'", extras
[i
]);
871 if (sym
.st_size
!= sizeof (uint64_t) &&
872 sym
.st_size
!= sizeof (uint32_t)) {
873 mdb_warn("expected scalar for variable '%s'\n",
878 if (mdb_vread(&buf
, sym
.st_size
, sym
.st_value
) == -1) {
879 mdb_warn("couldn't read '%s'", extras
[i
]);
883 mdb_printf("%-25s = ", extras
[i
]);
885 /* NB: all the 64-bit extras happen to be byte counts */
886 if (sym
.st_size
== sizeof (uint64_t))
887 mdb_printf("%9llu %s\n", buf
>> shift
, suffix
);
889 if (sym
.st_size
== sizeof (uint32_t))
890 mdb_printf("%9d\n", *((uint32_t *)&buf
));
898 * -c Print configuration information as well
899 * -v Print vdev state
900 * -e Print vdev error stats
902 * Print a summarized spa_t. When given no arguments, prints out a table of all
903 * active pools on the system.
907 spa_print(uintptr_t addr
, uint_t flags
, int argc
, const mdb_arg_t
*argv
)
910 const char *statetab
[] = { "ACTIVE", "EXPORTED", "DESTROYED",
911 "SPARE", "L2CACHE", "UNINIT", "UNAVAIL", "POTENTIAL" };
917 if (mdb_getopts(argc
, argv
,
918 'c', MDB_OPT_SETBITS
, TRUE
, &config
,
919 'v', MDB_OPT_SETBITS
, TRUE
, &vdevs
,
920 'e', MDB_OPT_SETBITS
, TRUE
, &errors
,
924 if (!(flags
& DCMD_ADDRSPEC
)) {
925 if (mdb_walk_dcmd("spa", "spa", argc
, argv
) == -1) {
926 mdb_warn("can't walk spa");
933 if (flags
& DCMD_PIPE_OUT
) {
934 mdb_printf("%#lr\n", addr
);
938 if (DCMD_HDRSPEC(flags
))
939 mdb_printf("%<u>%-?s %9s %-*s%</u>\n", "ADDR", "STATE",
940 sizeof (uintptr_t) == 4 ? 60 : 52, "NAME");
942 if (mdb_vread(&spa
, sizeof (spa
), addr
) == -1) {
943 mdb_warn("failed to read spa_t at %p", addr
);
947 if (spa
.spa_state
< 0 || spa
.spa_state
> POOL_STATE_UNAVAIL
)
950 state
= statetab
[spa
.spa_state
];
952 mdb_printf("%0?p %9s %s\n", addr
, state
, spa
.spa_name
);
957 if (mdb_call_dcmd("spa_config", addr
, flags
, 0,
963 if (vdevs
|| errors
) {
966 v
.a_type
= MDB_TYPE_STRING
;
971 if (mdb_call_dcmd("spa_vdevs", addr
, flags
, errors
? 1 : 0,
983 * Given a spa_t, print the configuration information stored in spa_config.
984 * Since it's just an nvlist, format it as an indented list of name=value pairs.
985 * We simply read the value of spa_config and pass off to ::nvlist.
989 spa_print_config(uintptr_t addr
, uint_t flags
, int argc
, const mdb_arg_t
*argv
)
993 if (argc
!= 0 || !(flags
& DCMD_ADDRSPEC
))
996 if (mdb_vread(&spa
, sizeof (spa
), addr
) == -1) {
997 mdb_warn("failed to read spa_t at %p", addr
);
1001 if (spa
.spa_config
== NULL
) {
1002 mdb_printf("(none)\n");
1006 return (mdb_call_dcmd("nvlist", (uintptr_t)spa
.spa_config
, flags
,
1013 * Print out a summarized vdev_t, in the following form:
1015 * ADDR STATE AUX DESC
1016 * fffffffbcde23df0 HEALTHY - /dev/dsk/c0t0d0
1018 * If '-r' is specified, recursively visit all children.
1020 * With '-e', the statistics associated with the vdev are printed as well.
1023 do_print_vdev(uintptr_t addr
, int flags
, int depth
, int stats
,
1027 char desc
[MAXNAMELEN
];
1030 const char *state
, *aux
;
1032 if (mdb_vread(&vdev
, sizeof (vdev
), (uintptr_t)addr
) == -1) {
1033 mdb_warn("failed to read vdev_t at %p\n", (uintptr_t)addr
);
1037 if (flags
& DCMD_PIPE_OUT
) {
1038 mdb_printf("%#lr", addr
);
1040 if (vdev
.vdev_path
!= NULL
) {
1041 if (mdb_readstr(desc
, sizeof (desc
),
1042 (uintptr_t)vdev
.vdev_path
) == -1) {
1043 mdb_warn("failed to read vdev_path at %p\n",
1047 } else if (vdev
.vdev_ops
!= NULL
) {
1049 if (mdb_vread(&ops
, sizeof (ops
),
1050 (uintptr_t)vdev
.vdev_ops
) == -1) {
1051 mdb_warn("failed to read vdev_ops at %p\n",
1055 (void) strcpy(desc
, ops
.vdev_op_type
);
1057 (void) strcpy(desc
, "<unknown>");
1060 if (depth
== 0 && DCMD_HDRSPEC(flags
))
1061 mdb_printf("%<u>%-?s %-9s %-12s %-*s%</u>\n",
1062 "ADDR", "STATE", "AUX",
1063 sizeof (uintptr_t) == 4 ? 43 : 35,
1066 mdb_printf("%0?p ", addr
);
1068 switch (vdev
.vdev_state
) {
1069 case VDEV_STATE_CLOSED
:
1072 case VDEV_STATE_OFFLINE
:
1075 case VDEV_STATE_CANT_OPEN
:
1076 state
= "CANT_OPEN";
1078 case VDEV_STATE_DEGRADED
:
1081 case VDEV_STATE_HEALTHY
:
1084 case VDEV_STATE_REMOVED
:
1087 case VDEV_STATE_FAULTED
:
1095 switch (vdev
.vdev_stat
.vs_aux
) {
1099 case VDEV_AUX_OPEN_FAILED
:
1100 aux
= "OPEN_FAILED";
1102 case VDEV_AUX_CORRUPT_DATA
:
1103 aux
= "CORRUPT_DATA";
1105 case VDEV_AUX_NO_REPLICAS
:
1106 aux
= "NO_REPLICAS";
1108 case VDEV_AUX_BAD_GUID_SUM
:
1109 aux
= "BAD_GUID_SUM";
1111 case VDEV_AUX_TOO_SMALL
:
1114 case VDEV_AUX_BAD_LABEL
:
1117 case VDEV_AUX_VERSION_NEWER
:
1120 case VDEV_AUX_VERSION_OLDER
:
1123 case VDEV_AUX_SPARED
:
1126 case VDEV_AUX_ERR_EXCEEDED
:
1127 aux
= "ERR_EXCEEDED";
1129 case VDEV_AUX_IO_FAILURE
:
1132 case VDEV_AUX_BAD_LOG
:
1140 mdb_printf("%-9s %-12s %*s%s\n", state
, aux
, depth
, "", desc
);
1143 vdev_stat_t
*vs
= &vdev
.vdev_stat
;
1148 mdb_printf("%<u> %12s %12s %12s %12s "
1149 "%12s%</u>\n", "READ", "WRITE", "FREE", "CLAIM",
1152 for (i
= 1; i
< ZIO_TYPES
; i
++)
1153 mdb_printf("%11#llx%s", vs
->vs_ops
[i
],
1154 i
== ZIO_TYPES
- 1 ? "" : " ");
1156 mdb_printf("BYTES ");
1157 for (i
= 1; i
< ZIO_TYPES
; i
++)
1158 mdb_printf("%11#llx%s", vs
->vs_bytes
[i
],
1159 i
== ZIO_TYPES
- 1 ? "" : " ");
1163 mdb_printf("EREAD %10#llx\n", vs
->vs_read_errors
);
1164 mdb_printf("EWRITE %10#llx\n", vs
->vs_write_errors
);
1165 mdb_printf("ECKSUM %10#llx\n",
1166 vs
->vs_checksum_errors
);
1174 children
= vdev
.vdev_children
;
1176 if (children
== 0 || !recursive
)
1179 child
= mdb_alloc(children
* sizeof (void *), UM_SLEEP
| UM_GC
);
1180 if (mdb_vread(child
, children
* sizeof (void *),
1181 (uintptr_t)vdev
.vdev_child
) == -1) {
1182 mdb_warn("failed to read vdev children at %p", vdev
.vdev_child
);
1186 for (c
= 0; c
< children
; c
++) {
1187 if (do_print_vdev(child
[c
], flags
, depth
+ 2, stats
,
1196 vdev_print(uintptr_t addr
, uint_t flags
, int argc
, const mdb_arg_t
*argv
)
1198 int recursive
= FALSE
;
1202 if (mdb_getopts(argc
, argv
,
1203 'r', MDB_OPT_SETBITS
, TRUE
, &recursive
,
1204 'e', MDB_OPT_SETBITS
, TRUE
, &stats
,
1205 'd', MDB_OPT_UINT64
, &depth
,
1207 return (DCMD_USAGE
);
1209 if (!(flags
& DCMD_ADDRSPEC
)) {
1210 mdb_warn("no vdev_t address given\n");
1214 return (do_print_vdev(addr
, flags
, (int)depth
, stats
, recursive
));
1217 typedef struct metaslab_walk_data
{
1218 uint64_t mw_numvdevs
;
1219 uintptr_t *mw_vdevs
;
1224 } metaslab_walk_data_t
;
1227 metaslab_walk_step(mdb_walk_state_t
*wsp
)
1229 metaslab_walk_data_t
*mw
= wsp
->walk_data
;
1233 if (mw
->mw_curvdev
>= mw
->mw_numvdevs
)
1236 if (mw
->mw_mss
== NULL
) {
1240 ASSERT(mw
->mw_curms
== 0);
1241 ASSERT(mw
->mw_nummss
== 0);
1243 vdevp
= mw
->mw_vdevs
[mw
->mw_curvdev
];
1244 if (GETMEMB(vdevp
, struct vdev
, vdev_ms
, mssp
) ||
1245 GETMEMB(vdevp
, struct vdev
, vdev_ms_count
, mw
->mw_nummss
)) {
1249 mw
->mw_mss
= mdb_alloc(mw
->mw_nummss
* sizeof (void*),
1251 if (mdb_vread(mw
->mw_mss
, mw
->mw_nummss
* sizeof (void*),
1253 mdb_warn("failed to read vdev_ms at %p", mssp
);
1258 if (mw
->mw_curms
>= mw
->mw_nummss
) {
1266 msp
= mw
->mw_mss
[mw
->mw_curms
];
1267 if (mdb_vread(&ms
, sizeof (metaslab_t
), msp
) == -1) {
1268 mdb_warn("failed to read metaslab_t at %p", msp
);
1274 return (wsp
->walk_callback(msp
, &ms
, wsp
->walk_cbdata
));
1279 metaslab_walk_init(mdb_walk_state_t
*wsp
)
1281 metaslab_walk_data_t
*mw
;
1282 uintptr_t root_vdevp
;
1285 if (wsp
->walk_addr
== NULL
) {
1286 mdb_warn("must supply address of spa_t\n");
1290 mw
= mdb_zalloc(sizeof (metaslab_walk_data_t
), UM_SLEEP
| UM_GC
);
1292 if (GETMEMB(wsp
->walk_addr
, struct spa
, spa_root_vdev
, root_vdevp
) ||
1293 GETMEMB(root_vdevp
, struct vdev
, vdev_children
, mw
->mw_numvdevs
) ||
1294 GETMEMB(root_vdevp
, struct vdev
, vdev_child
, childp
)) {
1298 mw
->mw_vdevs
= mdb_alloc(mw
->mw_numvdevs
* sizeof (void *),
1300 if (mdb_vread(mw
->mw_vdevs
, mw
->mw_numvdevs
* sizeof (void *),
1302 mdb_warn("failed to read root vdev children at %p", childp
);
1306 wsp
->walk_data
= mw
;
1311 typedef struct mdb_spa
{
1312 uintptr_t spa_dsl_pool
;
1313 uintptr_t spa_root_vdev
;
1316 typedef struct mdb_dsl_dir
{
1318 int64_t dd_space_towrite
[TXG_SIZE
];
1321 typedef struct mdb_dsl_dir_phys
{
1322 uint64_t dd_used_bytes
;
1323 uint64_t dd_compressed_bytes
;
1324 uint64_t dd_uncompressed_bytes
;
1325 } mdb_dsl_dir_phys_t
;
1327 typedef struct mdb_vdev
{
1328 uintptr_t vdev_parent
;
1330 uint64_t vdev_ms_count
;
1331 vdev_stat_t vdev_stat
;
1334 typedef struct mdb_metaslab
{
1335 space_map_t ms_allocmap
[TXG_SIZE
];
1336 space_map_t ms_freemap
[TXG_SIZE
];
1338 space_map_obj_t ms_smo
;
1339 space_map_obj_t ms_smo_syncing
;
1342 typedef struct space_data
{
1343 uint64_t ms_allocmap
[TXG_SIZE
];
1344 uint64_t ms_freemap
[TXG_SIZE
];
1352 space_cb(uintptr_t addr
, const void *unknown
, void *arg
)
1354 space_data_t
*sd
= arg
;
1357 if (GETMEMB(addr
, struct metaslab
, ms_allocmap
, ms
.ms_allocmap
) ||
1358 GETMEMB(addr
, struct metaslab
, ms_freemap
, ms
.ms_freemap
) ||
1359 GETMEMB(addr
, struct metaslab
, ms_map
, ms
.ms_map
) ||
1360 GETMEMB(addr
, struct metaslab
, ms_smo
, ms
.ms_smo
) ||
1361 GETMEMB(addr
, struct metaslab
, ms_smo_syncing
, ms
.ms_smo_syncing
)) {
1365 sd
->ms_allocmap
[0] += ms
.ms_allocmap
[0].sm_space
;
1366 sd
->ms_allocmap
[1] += ms
.ms_allocmap
[1].sm_space
;
1367 sd
->ms_allocmap
[2] += ms
.ms_allocmap
[2].sm_space
;
1368 sd
->ms_allocmap
[3] += ms
.ms_allocmap
[3].sm_space
;
1369 sd
->ms_freemap
[0] += ms
.ms_freemap
[0].sm_space
;
1370 sd
->ms_freemap
[1] += ms
.ms_freemap
[1].sm_space
;
1371 sd
->ms_freemap
[2] += ms
.ms_freemap
[2].sm_space
;
1372 sd
->ms_freemap
[3] += ms
.ms_freemap
[3].sm_space
;
1373 sd
->ms_map
+= ms
.ms_map
.sm_space
;
1374 sd
->avail
+= ms
.ms_map
.sm_size
- ms
.ms_smo
.smo_alloc
;
1375 sd
->nowavail
+= ms
.ms_map
.sm_size
- ms
.ms_smo_syncing
.smo_alloc
;
1383 * Given a spa_t, print out it's on-disk space usage and in-core
1384 * estimates of future usage. If -b is given, print space in bytes.
1385 * Otherwise print in megabytes.
1389 spa_space(uintptr_t addr
, uint_t flags
, int argc
, const mdb_arg_t
*argv
)
1392 uintptr_t dp_root_dir
;
1394 mdb_dsl_dir_phys_t dsp
;
1396 uintptr_t childaddr
;
1402 if (mdb_getopts(argc
, argv
, 'b', MDB_OPT_SETBITS
, TRUE
, &bits
, NULL
) !=
1404 return (DCMD_USAGE
);
1405 if (!(flags
& DCMD_ADDRSPEC
))
1406 return (DCMD_USAGE
);
1413 if (GETMEMB(addr
, struct spa
, spa_dsl_pool
, spa
.spa_dsl_pool
) ||
1414 GETMEMB(addr
, struct spa
, spa_root_vdev
, spa
.spa_root_vdev
) ||
1415 GETMEMB(spa
.spa_root_vdev
, struct vdev
, vdev_children
, children
) ||
1416 GETMEMB(spa
.spa_root_vdev
, struct vdev
, vdev_child
, childaddr
) ||
1417 GETMEMB(spa
.spa_dsl_pool
, struct dsl_pool
,
1418 dp_root_dir
, dp_root_dir
) ||
1419 GETMEMB(dp_root_dir
, struct dsl_dir
, dd_phys
, dd
.dd_phys
) ||
1420 GETMEMB(dp_root_dir
, struct dsl_dir
,
1421 dd_space_towrite
, dd
.dd_space_towrite
) ||
1422 GETMEMB(dd
.dd_phys
, struct dsl_dir_phys
,
1423 dd_used_bytes
, dsp
.dd_used_bytes
) ||
1424 GETMEMB(dd
.dd_phys
, struct dsl_dir_phys
,
1425 dd_compressed_bytes
, dsp
.dd_compressed_bytes
) ||
1426 GETMEMB(dd
.dd_phys
, struct dsl_dir_phys
,
1427 dd_uncompressed_bytes
, dsp
.dd_uncompressed_bytes
)) {
1431 mdb_printf("dd_space_towrite = %llu%s %llu%s %llu%s %llu%s\n",
1432 dd
.dd_space_towrite
[0] >> shift
, suffix
,
1433 dd
.dd_space_towrite
[1] >> shift
, suffix
,
1434 dd
.dd_space_towrite
[2] >> shift
, suffix
,
1435 dd
.dd_space_towrite
[3] >> shift
, suffix
);
1437 mdb_printf("dd_phys.dd_used_bytes = %llu%s\n",
1438 dsp
.dd_used_bytes
>> shift
, suffix
);
1439 mdb_printf("dd_phys.dd_compressed_bytes = %llu%s\n",
1440 dsp
.dd_compressed_bytes
>> shift
, suffix
);
1441 mdb_printf("dd_phys.dd_uncompressed_bytes = %llu%s\n",
1442 dsp
.dd_uncompressed_bytes
>> shift
, suffix
);
1444 bzero(&sd
, sizeof (sd
));
1445 if (mdb_pwalk("metaslab", space_cb
, &sd
, addr
) != 0) {
1446 mdb_warn("can't walk metaslabs");
1450 mdb_printf("ms_allocmap = %llu%s %llu%s %llu%s %llu%s\n",
1451 sd
.ms_allocmap
[0] >> shift
, suffix
,
1452 sd
.ms_allocmap
[1] >> shift
, suffix
,
1453 sd
.ms_allocmap
[2] >> shift
, suffix
,
1454 sd
.ms_allocmap
[3] >> shift
, suffix
);
1455 mdb_printf("ms_freemap = %llu%s %llu%s %llu%s %llu%s\n",
1456 sd
.ms_freemap
[0] >> shift
, suffix
,
1457 sd
.ms_freemap
[1] >> shift
, suffix
,
1458 sd
.ms_freemap
[2] >> shift
, suffix
,
1459 sd
.ms_freemap
[3] >> shift
, suffix
);
1460 mdb_printf("ms_map = %llu%s\n", sd
.ms_map
>> shift
, suffix
);
1461 mdb_printf("last synced avail = %llu%s\n", sd
.avail
>> shift
, suffix
);
1462 mdb_printf("current syncing avail = %llu%s\n",
1463 sd
.nowavail
>> shift
, suffix
);
1471 * Given a spa_t, verify that that the pool is self-consistent.
1472 * Currently, it only checks to make sure that the vdev tree exists.
1476 spa_verify(uintptr_t addr
, uint_t flags
, int argc
, const mdb_arg_t
*argv
)
1480 if (argc
!= 0 || !(flags
& DCMD_ADDRSPEC
))
1481 return (DCMD_USAGE
);
1483 if (mdb_vread(&spa
, sizeof (spa
), addr
) == -1) {
1484 mdb_warn("failed to read spa_t at %p", addr
);
1488 if (spa
.spa_root_vdev
== NULL
) {
1489 mdb_printf("no vdev tree present\n");
1499 * -e Include error stats
1501 * Print out a summarized list of vdevs for the given spa_t.
1502 * This is accomplished by invoking "::vdev -re" on the root vdev, as well as
1503 * iterating over the cache devices.
1507 spa_vdevs(uintptr_t addr
, uint_t flags
, int argc
, const mdb_arg_t
*argv
)
1516 if (mdb_getopts(argc
, argv
,
1517 'e', MDB_OPT_SETBITS
, TRUE
, &errors
,
1519 return (DCMD_USAGE
);
1521 if (!(flags
& DCMD_ADDRSPEC
))
1522 return (DCMD_USAGE
);
1524 if (mdb_vread(&spa
, sizeof (spa
), addr
) == -1) {
1525 mdb_warn("failed to read spa_t at %p", addr
);
1530 * Unitialized spa_t structures can have a NULL root vdev.
1532 if (spa
.spa_root_vdev
== NULL
) {
1533 mdb_printf("no associated vdevs\n");
1537 v
[0].a_type
= MDB_TYPE_STRING
;
1538 v
[0].a_un
.a_str
= errors
? "-re" : "-r";
1540 ret
= mdb_call_dcmd("vdev", (uintptr_t)spa
.spa_root_vdev
,
1546 * Iterate over cache devices and print those out as well. This is a
1547 * little annoying because we don't have a root vdev to pass to ::vdev.
1548 * Instead, we print a single 'cache' line and then call it for each
1551 if (spa
.spa_l2cache
.sav_count
!= 0) {
1552 v
[1].a_type
= MDB_TYPE_STRING
;
1553 v
[1].a_un
.a_str
= "-d";
1554 v
[2].a_type
= MDB_TYPE_IMMEDIATE
;
1555 v
[2].a_un
.a_val
= 2;
1557 len
= spa
.spa_l2cache
.sav_count
* sizeof (uintptr_t);
1558 aux
= mdb_alloc(len
, UM_SLEEP
);
1559 if (mdb_vread(aux
, len
,
1560 (uintptr_t)spa
.spa_l2cache
.sav_vdevs
) == -1) {
1562 mdb_warn("failed to read l2cache vdevs at %p",
1563 spa
.spa_l2cache
.sav_vdevs
);
1567 mdb_printf("%-?s %-9s %-12s cache\n", "-", "-", "-");
1569 for (i
= 0; i
< spa
.spa_l2cache
.sav_count
; i
++) {
1570 ret
= mdb_call_dcmd("vdev", aux
[i
], flags
, 3, v
);
1571 if (ret
!= DCMD_OK
) {
1586 * Print a summary of zio_t and all its children. This is intended to display a
1587 * zio tree, and hence we only pick the most important pieces of information for
1588 * the main summary. More detailed information can always be found by doing a
1589 * '::print zio' on the underlying zio_t. The columns we display are:
1591 * ADDRESS TYPE STAGE WAITER
1593 * The 'address' column is indented by one space for each depth level as we
1594 * descend down the tree.
1597 #define ZIO_MAXDEPTH 16
1600 zio_print_cb(uintptr_t addr
, const void *data
, void *priv
)
1602 const zio_t
*zio
= data
;
1603 uintptr_t depth
= (uintptr_t)priv
;
1604 mdb_ctf_id_t type_enum
, stage_enum
;
1605 const char *type
, *stage
;
1608 maxdepth
= sizeof (uintptr_t) * 2 + ZIO_MAXDEPTH
;
1609 if (depth
> ZIO_MAXDEPTH
)
1610 depth
= ZIO_MAXDEPTH
;
1612 if (mdb_ctf_lookup_by_name("enum zio_type", &type_enum
) == -1 ||
1613 mdb_ctf_lookup_by_name("enum zio_stage", &stage_enum
) == -1) {
1614 mdb_warn("failed to lookup zio enums");
1618 if ((type
= mdb_ctf_enum_name(type_enum
, zio
->io_type
)) != NULL
)
1619 type
+= sizeof ("ZIO_TYPE_") - 1;
1623 if ((stage
= mdb_ctf_enum_name(stage_enum
, zio
->io_stage
)) != NULL
)
1624 stage
+= sizeof ("ZIO_STAGE_") - 1;
1629 mdb_printf("%*s%-*p %-5s %-22s ",
1630 depth
, "", maxdepth
- depth
, addr
, type
, stage
);
1632 mdb_printf("%?p\n", zio
->io_waiter
);
1636 if (mdb_pwalk("zio_child", zio_print_cb
, (void *)(depth
+ 1),
1638 mdb_warn("failed to walk zio_t children at %p\n", addr
);
1647 zio_print(uintptr_t addr
, uint_t flags
, int argc
, const mdb_arg_t
*argv
)
1652 maxdepth
= sizeof (uintptr_t) * 2 + ZIO_MAXDEPTH
;
1654 if (!(flags
& DCMD_ADDRSPEC
))
1655 return (DCMD_USAGE
);
1657 if (mdb_vread(&zio
, sizeof (zio_t
), addr
) == -1) {
1658 mdb_warn("failed to read zio_t at %p", addr
);
1662 if (DCMD_HDRSPEC(flags
))
1663 mdb_printf("%<u>%-*s %-5s %-22s %-?s%</u>\n", maxdepth
,
1664 "ADDRESS", "TYPE", "STAGE", "WAITER");
1666 if (zio_print_cb(addr
, &zio
, NULL
) != WALK_NEXT
)
1675 * Print a summary of all zio_t structures on the system, or for a particular
1676 * pool. This is equivalent to '::walk zio_root | ::zio'.
1680 zio_state(uintptr_t addr
, uint_t flags
, int argc
, const mdb_arg_t
*argv
)
1683 * MDB will remember the last address of the pipeline, so if we don't
1684 * zero this we'll end up trying to walk zio structures for a
1685 * non-existent spa_t.
1687 if (!(flags
& DCMD_ADDRSPEC
))
1690 return (mdb_pwalk_dcmd("zio_root", "zio", argc
, argv
, addr
));
1693 typedef struct txg_list_walk_data
{
1694 uintptr_t lw_head
[TXG_SIZE
];
1699 } txg_list_walk_data_t
;
1702 txg_list_walk_init_common(mdb_walk_state_t
*wsp
, int txg
, int maxoff
)
1704 txg_list_walk_data_t
*lwd
;
1708 lwd
= mdb_alloc(sizeof (txg_list_walk_data_t
), UM_SLEEP
| UM_GC
);
1709 if (mdb_vread(&list
, sizeof (txg_list_t
), wsp
->walk_addr
) == -1) {
1710 mdb_warn("failed to read txg_list_t at %#lx", wsp
->walk_addr
);
1714 for (i
= 0; i
< TXG_SIZE
; i
++)
1715 lwd
->lw_head
[i
] = (uintptr_t)list
.tl_head
[i
];
1716 lwd
->lw_offset
= list
.tl_offset
;
1717 lwd
->lw_obj
= mdb_alloc(lwd
->lw_offset
+ sizeof (txg_node_t
),
1719 lwd
->lw_txgoff
= txg
;
1720 lwd
->lw_maxoff
= maxoff
;
1722 wsp
->walk_addr
= lwd
->lw_head
[lwd
->lw_txgoff
];
1723 wsp
->walk_data
= lwd
;
1729 txg_list_walk_init(mdb_walk_state_t
*wsp
)
1731 return (txg_list_walk_init_common(wsp
, 0, TXG_SIZE
-1));
1735 txg_list0_walk_init(mdb_walk_state_t
*wsp
)
1737 return (txg_list_walk_init_common(wsp
, 0, 0));
1741 txg_list1_walk_init(mdb_walk_state_t
*wsp
)
1743 return (txg_list_walk_init_common(wsp
, 1, 1));
1747 txg_list2_walk_init(mdb_walk_state_t
*wsp
)
1749 return (txg_list_walk_init_common(wsp
, 2, 2));
1753 txg_list3_walk_init(mdb_walk_state_t
*wsp
)
1755 return (txg_list_walk_init_common(wsp
, 3, 3));
1759 txg_list_walk_step(mdb_walk_state_t
*wsp
)
1761 txg_list_walk_data_t
*lwd
= wsp
->walk_data
;
1766 while (wsp
->walk_addr
== NULL
&& lwd
->lw_txgoff
< lwd
->lw_maxoff
) {
1768 wsp
->walk_addr
= lwd
->lw_head
[lwd
->lw_txgoff
];
1771 if (wsp
->walk_addr
== NULL
)
1774 addr
= wsp
->walk_addr
- lwd
->lw_offset
;
1776 if (mdb_vread(lwd
->lw_obj
,
1777 lwd
->lw_offset
+ sizeof (txg_node_t
), addr
) == -1) {
1778 mdb_warn("failed to read list element at %#lx", addr
);
1782 status
= wsp
->walk_callback(addr
, lwd
->lw_obj
, wsp
->walk_cbdata
);
1783 node
= (txg_node_t
*)((uintptr_t)lwd
->lw_obj
+ lwd
->lw_offset
);
1784 wsp
->walk_addr
= (uintptr_t)node
->tn_next
[lwd
->lw_txgoff
];
1792 * Walk all named spa_t structures in the namespace. This is nothing more than
1793 * a layered avl walk.
1796 spa_walk_init(mdb_walk_state_t
*wsp
)
1800 if (wsp
->walk_addr
!= NULL
) {
1801 mdb_warn("spa walk only supports global walks\n");
1805 if (mdb_lookup_by_obj(ZFS_OBJ_NAME
, "spa_namespace_avl", &sym
) == -1) {
1806 mdb_warn("failed to find symbol 'spa_namespace_avl'");
1810 wsp
->walk_addr
= (uintptr_t)sym
.st_value
;
1812 if (mdb_layered_walk("avl", wsp
) == -1) {
1813 mdb_warn("failed to walk 'avl'\n");
1821 spa_walk_step(mdb_walk_state_t
*wsp
)
1825 if (mdb_vread(&spa
, sizeof (spa
), wsp
->walk_addr
) == -1) {
1826 mdb_warn("failed to read spa_t at %p", wsp
->walk_addr
);
1830 return (wsp
->walk_callback(wsp
->walk_addr
, &spa
, wsp
->walk_cbdata
));
1836 * Walk all active zio_t structures on the system. This is simply a layered
1837 * walk on top of ::walk zio_cache, with the optional ability to limit the
1838 * structures to a particular pool.
1841 zio_walk_init(mdb_walk_state_t
*wsp
)
1843 wsp
->walk_data
= (void *)wsp
->walk_addr
;
1845 if (mdb_layered_walk("zio_cache", wsp
) == -1) {
1846 mdb_warn("failed to walk 'zio_cache'\n");
1854 zio_walk_step(mdb_walk_state_t
*wsp
)
1858 if (mdb_vread(&zio
, sizeof (zio
), wsp
->walk_addr
) == -1) {
1859 mdb_warn("failed to read zio_t at %p", wsp
->walk_addr
);
1863 if (wsp
->walk_data
!= NULL
&& wsp
->walk_data
!= zio
.io_spa
)
1866 return (wsp
->walk_callback(wsp
->walk_addr
, &zio
, wsp
->walk_cbdata
));
1872 * Walk the children of a zio_t structure.
1875 zio_child_walk_init(mdb_walk_state_t
*wsp
)
1879 if (wsp
->walk_addr
== 0) {
1880 mdb_warn("::walk zio_child doesn't support global walks\n");
1884 if (mdb_vread(&zio
, sizeof (zio
), wsp
->walk_addr
) == -1) {
1885 mdb_warn("failed to read zio_t at %p", wsp
->walk_addr
);
1889 wsp
->walk_addr
= (uintptr_t)zio
.io_child
;
1894 zio_sibling_walk_step(mdb_walk_state_t
*wsp
)
1899 if (wsp
->walk_addr
== NULL
)
1902 if (mdb_vread(&zio
, sizeof (zio
), wsp
->walk_addr
) == -1) {
1903 mdb_warn("failed to read zio_t at %p", wsp
->walk_addr
);
1907 status
= wsp
->walk_callback(wsp
->walk_addr
, &zio
, wsp
->walk_cbdata
);
1909 wsp
->walk_addr
= (uintptr_t)zio
.io_sibling_next
;
1914 * [addr]::walk zio_root
1916 * Walk only root zio_t structures, optionally for a particular spa_t.
1919 zio_walk_root_step(mdb_walk_state_t
*wsp
)
1923 if (mdb_vread(&zio
, sizeof (zio
), wsp
->walk_addr
) == -1) {
1924 mdb_warn("failed to read zio_t at %p", wsp
->walk_addr
);
1928 if (wsp
->walk_data
!= NULL
&& wsp
->walk_data
!= zio
.io_spa
)
1931 if ((uintptr_t)zio
.io_parent
!= NULL
)
1934 return (wsp
->walk_callback(wsp
->walk_addr
, &zio
, wsp
->walk_cbdata
));
1937 #define NICENUM_BUFLEN 6
1940 snprintfloat(char *buf
, int len
, float f
, int frac_digits
)
1945 for (i
= frac_digits
; i
; i
--)
1948 frac
= (int)((f
- whole
) * mul
);
1949 return (mdb_snprintf(buf
, len
, "%u.%0*u", whole
, frac_digits
, frac
));
1953 mdb_nicenum(uint64_t num
, char *buf
)
1960 n
= (n
+ (1024 / 2)) / 1024; /* Round up or down */
1964 u
= &" \0K\0M\0G\0T\0P\0E\0"[index
*2];
1967 (void) mdb_snprintf(buf
, NICENUM_BUFLEN
, "%llu",
1969 } else if (n
< 10 && (num
& (num
- 1)) != 0) {
1970 (void) snprintfloat(buf
, NICENUM_BUFLEN
,
1971 (float)num
/ (1ULL << 10 * index
), 2);
1973 } else if (n
< 100 && (num
& (num
- 1)) != 0) {
1974 (void) snprintfloat(buf
, NICENUM_BUFLEN
,
1975 (float)num
/ (1ULL << 10 * index
), 1);
1978 (void) mdb_snprintf(buf
, NICENUM_BUFLEN
, "%llu%s",
1979 (u_longlong_t
)n
, u
);
1986 * -v print verbose per-level information
1990 zfs_blkstats(uintptr_t addr
, uint_t flags
, int argc
, const mdb_arg_t
*argv
)
1992 boolean_t verbose
= B_FALSE
;
1993 zfs_all_blkstats_t stats
;
1994 dmu_object_type_t t
;
1997 dmu_object_type_info_t dmu_ot
[DMU_OT_NUMTYPES
+ 10];
1998 /* +10 in case it grew */
2000 if (mdb_readvar(&dmu_ot
, "dmu_ot") == -1) {
2001 mdb_warn("failed to read 'dmu_ot'");
2005 if (mdb_getopts(argc
, argv
,
2006 'v', MDB_OPT_SETBITS
, TRUE
, &verbose
,
2008 return (DCMD_USAGE
);
2010 if (!(flags
& DCMD_ADDRSPEC
))
2011 return (DCMD_USAGE
);
2013 if (GETMEMB(addr
, struct spa
, spa_dsl_pool
, addr
) ||
2014 GETMEMB(addr
, struct dsl_pool
, dp_blkstats
, addr
) ||
2015 mdb_vread(&stats
, sizeof (zfs_all_blkstats_t
), addr
) == -1) {
2016 mdb_warn("failed to read data at %p;", addr
);
2017 mdb_printf("maybe no stats? run \"zpool scrub\" first.");
2021 tzb
= &stats
.zab_type
[DN_MAX_LEVELS
][DMU_OT_NUMTYPES
];
2022 if (tzb
->zb_gangs
!= 0) {
2023 mdb_printf("Ganged blocks: %llu\n",
2024 (longlong_t
)tzb
->zb_gangs
);
2027 ditto
= tzb
->zb_ditto_2_of_2_samevdev
+ tzb
->zb_ditto_2_of_3_samevdev
+
2028 tzb
->zb_ditto_3_of_3_samevdev
;
2030 mdb_printf("Dittoed blocks on same vdev: %llu\n",
2034 mdb_printf("\nBlocks\tLSIZE\tPSIZE\tASIZE"
2035 "\t avg\t comp\t%%Total\tType\n");
2037 for (t
= 0; t
<= DMU_OT_NUMTYPES
; t
++) {
2038 char csize
[NICENUM_BUFLEN
], lsize
[NICENUM_BUFLEN
];
2039 char psize
[NICENUM_BUFLEN
], asize
[NICENUM_BUFLEN
];
2040 char avg
[NICENUM_BUFLEN
];
2041 char comp
[NICENUM_BUFLEN
], pct
[NICENUM_BUFLEN
];
2046 if (t
== DMU_OT_DEFERRED
)
2047 strcpy(typename
, "deferred free");
2048 else if (t
== DMU_OT_TOTAL
)
2049 strcpy(typename
, "Total");
2050 else if (mdb_readstr(typename
, sizeof (typename
),
2051 (uintptr_t)dmu_ot
[t
].ot_name
) == -1) {
2052 mdb_warn("failed to read type name");
2056 if (stats
.zab_type
[DN_MAX_LEVELS
][t
].zb_asize
== 0)
2059 for (l
= -1; l
< DN_MAX_LEVELS
; l
++) {
2060 int level
= (l
== -1 ? DN_MAX_LEVELS
: l
);
2061 zfs_blkstat_t
*zb
= &stats
.zab_type
[level
][t
];
2063 if (zb
->zb_asize
== 0)
2067 * Don't print each level unless requested.
2069 if (!verbose
&& level
!= DN_MAX_LEVELS
)
2073 * If all the space is level 0, don't print the
2074 * level 0 separately.
2076 if (level
== 0 && zb
->zb_asize
==
2077 stats
.zab_type
[DN_MAX_LEVELS
][t
].zb_asize
)
2080 mdb_nicenum(zb
->zb_count
, csize
);
2081 mdb_nicenum(zb
->zb_lsize
, lsize
);
2082 mdb_nicenum(zb
->zb_psize
, psize
);
2083 mdb_nicenum(zb
->zb_asize
, asize
);
2084 mdb_nicenum(zb
->zb_asize
/ zb
->zb_count
, avg
);
2085 (void) snprintfloat(comp
, NICENUM_BUFLEN
,
2086 (float)zb
->zb_lsize
/ zb
->zb_psize
, 2);
2087 (void) snprintfloat(pct
, NICENUM_BUFLEN
,
2088 100.0 * zb
->zb_asize
/ tzb
->zb_asize
, 2);
2090 mdb_printf("%6s\t%5s\t%5s\t%5s\t%5s"
2092 csize
, lsize
, psize
, asize
, avg
, comp
, pct
);
2094 if (level
== DN_MAX_LEVELS
)
2095 mdb_printf("%s\n", typename
);
2097 mdb_printf(" L%d %s\n",
2106 * MDB module linkage information:
2108 * We declare a list of structures describing our dcmds, and a function
2109 * named _mdb_init to return a pointer to our module information.
2112 static const mdb_dcmd_t dcmds
[] = {
2113 { "arc", "[-bkmg]", "print ARC variables", arc_print
},
2114 { "blkptr", ":", "print blkptr_t", blkptr
},
2115 { "dbuf", ":", "print dmu_buf_impl_t", dbuf
},
2116 { "dbuf_stats", ":", "dbuf stats", dbuf_stats
},
2118 "\t[-O objset_impl_t*] [-n objset_name | \"mos\"] "
2119 "[-o object | \"mdn\"] \n"
2120 "\t[-l level] [-b blkid | \"bonus\"]",
2121 "find dmu_buf_impl_t's that match specified criteria", dbufs
},
2122 { "abuf_find", "dva_word[0] dva_word[1]",
2123 "find arc_buf_hdr_t of a specified DVA",
2125 { "spa", "?[-cv]", "spa_t summary", spa_print
},
2126 { "spa_config", ":", "print spa_t configuration", spa_print_config
},
2127 { "spa_verify", ":", "verify spa_t consistency", spa_verify
},
2128 { "spa_space", ":[-b]", "print spa_t on-disk space usage", spa_space
},
2129 { "spa_vdevs", ":", "given a spa_t, print vdev summary", spa_vdevs
},
2130 { "vdev", ":[-re]\n"
2131 "\t-r display recursively\n"
2132 "\t-e print statistics\n",
2133 "vdev_t summary", vdev_print
},
2134 { "zio", ":", "zio_t summary", zio_print
},
2135 { "zio_state", "?", "print out all zio_t structures on system or "
2136 "for a particular pool", zio_state
},
2137 { "zio_pipeline", ":", "decode a zio pipeline", zio_pipeline
},
2138 { "zfs_blkstats", ":[-v]",
2139 "given a spa_t, print block type stats from last scrub",
2141 { "zfs_params", "", "print zfs tunable parameters", zfs_params
},
2145 static const mdb_walker_t walkers
[] = {
2147 * In userland, there is no generic provider of list_t walkers, so we
2151 { LIST_WALK_NAME
, LIST_WALK_DESC
,
2152 list_walk_init
, list_walk_step
, list_walk_fini
},
2154 { "zms_freelist", "walk ZFS metaslab freelist",
2155 freelist_walk_init
, freelist_walk_step
, NULL
},
2156 { "txg_list", "given any txg_list_t *, walk all entries in all txgs",
2157 txg_list_walk_init
, txg_list_walk_step
, NULL
},
2158 { "txg_list0", "given any txg_list_t *, walk all entries in txg 0",
2159 txg_list0_walk_init
, txg_list_walk_step
, NULL
},
2160 { "txg_list1", "given any txg_list_t *, walk all entries in txg 1",
2161 txg_list1_walk_init
, txg_list_walk_step
, NULL
},
2162 { "txg_list2", "given any txg_list_t *, walk all entries in txg 2",
2163 txg_list2_walk_init
, txg_list_walk_step
, NULL
},
2164 { "txg_list3", "given any txg_list_t *, walk all entries in txg 3",
2165 txg_list3_walk_init
, txg_list_walk_step
, NULL
},
2166 { "zio", "walk all zio structures, optionally for a particular spa_t",
2167 zio_walk_init
, zio_walk_step
, NULL
},
2168 { "zio_child", "walk children of a zio_t structure",
2169 zio_child_walk_init
, zio_sibling_walk_step
, NULL
},
2170 { "zio_root", "walk all root zio_t structures, optionally for a "
2172 zio_walk_init
, zio_walk_root_step
, NULL
},
2173 { "spa", "walk all spa_t entries in the namespace",
2174 spa_walk_init
, spa_walk_step
, NULL
},
2175 { "metaslab", "given a spa_t *, walk all metaslab_t structures",
2176 metaslab_walk_init
, metaslab_walk_step
, NULL
},
2180 static const mdb_modinfo_t modinfo
= {
2181 MDB_API_VERSION
, dcmds
, walkers
2184 const mdb_modinfo_t
*