1789Sahrens /* 2789Sahrens * CDDL HEADER START 3789Sahrens * 4789Sahrens * The contents of this file are subject to the terms of the 51544Seschrock * Common Development and Distribution License (the "License"). 61544Seschrock * You may not use this file except in compliance with the License. 7789Sahrens * 8789Sahrens * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9789Sahrens * or http://www.opensolaris.org/os/licensing. 10789Sahrens * See the License for the specific language governing permissions 11789Sahrens * and limitations under the License. 12789Sahrens * 13789Sahrens * When distributing Covered Code, include this CDDL HEADER in each 14789Sahrens * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15789Sahrens * If applicable, add the following below this CDDL HEADER, with the 16789Sahrens * fields enclosed by brackets "[]" replaced with your own identifying 17789Sahrens * information: Portions Copyright [yyyy] [name of copyright owner] 18789Sahrens * 19789Sahrens * CDDL HEADER END 20789Sahrens */ 21789Sahrens /* 221544Seschrock * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 23789Sahrens * Use is subject to license terms. 24789Sahrens */ 25789Sahrens 26789Sahrens #pragma ident "%Z%%M% %I% %E% SMI" 27789Sahrens 28789Sahrens #include <mdb/mdb_ctf.h> 29789Sahrens #include <sys/zfs_context.h> 30789Sahrens #include <sys/mdb_modapi.h> 31789Sahrens #include <sys/dbuf.h> 32789Sahrens #include <sys/dmu_objset.h> 33789Sahrens #include <sys/dsl_dir.h> 34789Sahrens #include <sys/dsl_pool.h> 35789Sahrens #include <sys/metaslab_impl.h> 36789Sahrens #include <sys/space_map.h> 37789Sahrens #include <sys/list.h> 38789Sahrens #include <sys/spa_impl.h> 39789Sahrens #include <sys/vdev_impl.h> 40789Sahrens #include <sys/zio_compress.h> 41789Sahrens 42789Sahrens #ifndef _KERNEL 43789Sahrens #include "../genunix/list.h" 44789Sahrens #endif 45789Sahrens 46789Sahrens #ifdef _KERNEL 47789Sahrens #define ZFS_OBJ_NAME "zfs" 48789Sahrens #else 49789Sahrens #define ZFS_OBJ_NAME "libzpool.so.1" 50789Sahrens #endif 51789Sahrens 52789Sahrens static char * 53789Sahrens local_strdup(const char *s) 54789Sahrens { 55789Sahrens char *s1 = mdb_alloc(strlen(s) + 1, UM_SLEEP); 56789Sahrens 57789Sahrens (void) strcpy(s1, s); 58789Sahrens return (s1); 59789Sahrens } 60789Sahrens 61789Sahrens static int 62789Sahrens getmember(uintptr_t addr, const char *type, mdb_ctf_id_t *idp, 63789Sahrens const char *member, int len, void *buf) 64789Sahrens { 65789Sahrens mdb_ctf_id_t id; 66789Sahrens ulong_t off; 67789Sahrens char name[64]; 68789Sahrens 69789Sahrens if (idp == NULL) { 70789Sahrens if (mdb_ctf_lookup_by_name(type, &id) == -1) { 71789Sahrens mdb_warn("couldn't find type %s", type); 72789Sahrens return (DCMD_ERR); 73789Sahrens } 74789Sahrens idp = &id; 75789Sahrens } else { 76789Sahrens type = name; 77789Sahrens mdb_ctf_type_name(*idp, name, sizeof (name)); 78789Sahrens } 79789Sahrens 80789Sahrens if (mdb_ctf_offsetof(*idp, member, &off) == -1) { 81789Sahrens mdb_warn("couldn't find member %s of type %s\n", member, type); 82789Sahrens return (DCMD_ERR); 83789Sahrens } 84789Sahrens if (off % 8 != 0) { 85789Sahrens mdb_warn("member %s of type %s is unsupported bitfield", 86789Sahrens member, type); 87789Sahrens return (DCMD_ERR); 88789Sahrens } 89789Sahrens off /= 8; 90789Sahrens 91789Sahrens if (mdb_vread(buf, len, addr + off) == -1) { 92789Sahrens mdb_warn("failed to read %s from %s at %p", 93789Sahrens member, type, addr + off); 94789Sahrens return (DCMD_ERR); 95789Sahrens } 96789Sahrens /* mdb_warn("read %s from %s at %p+%llx\n", member, type, addr, off); */ 97789Sahrens 98789Sahrens return (0); 99789Sahrens } 100789Sahrens 101789Sahrens #define GETMEMB(addr, type, member, dest) \ 102789Sahrens getmember(addr, #type, NULL, #member, sizeof (dest), &(dest)) 103789Sahrens 104789Sahrens #define GETMEMBID(addr, ctfid, member, dest) \ 105789Sahrens getmember(addr, NULL, ctfid, #member, sizeof (dest), &(dest)) 106789Sahrens 107789Sahrens static int 108789Sahrens getrefcount(uintptr_t addr, mdb_ctf_id_t *id, 109789Sahrens const char *member, uint64_t *rc) 110789Sahrens { 111789Sahrens static int gotid; 112789Sahrens static mdb_ctf_id_t rc_id; 113789Sahrens ulong_t off; 114789Sahrens 115789Sahrens if (!gotid) { 116789Sahrens if (mdb_ctf_lookup_by_name("struct refcount", &rc_id) == -1) { 117789Sahrens mdb_warn("couldn't find struct refcount"); 118789Sahrens return (DCMD_ERR); 119789Sahrens } 120789Sahrens gotid = TRUE; 121789Sahrens } 122789Sahrens 123789Sahrens if (mdb_ctf_offsetof(*id, member, &off) == -1) { 124789Sahrens char name[64]; 125789Sahrens mdb_ctf_type_name(*id, name, sizeof (name)); 126789Sahrens mdb_warn("couldn't find member %s of type %s\n", member, name); 127789Sahrens return (DCMD_ERR); 128789Sahrens } 129789Sahrens off /= 8; 130789Sahrens 131789Sahrens return (GETMEMBID(addr + off, &rc_id, rc_count, *rc)); 132789Sahrens } 133789Sahrens 134789Sahrens static int 135789Sahrens read_symbol(char *sym_name, void **bufp) 136789Sahrens { 137789Sahrens GElf_Sym sym; 138789Sahrens 139789Sahrens if (mdb_lookup_by_obj(MDB_TGT_OBJ_EVERY, sym_name, &sym)) { 140789Sahrens mdb_warn("can't find symbol %s", sym_name); 141789Sahrens return (DCMD_ERR); 142789Sahrens } 143789Sahrens 144789Sahrens *bufp = mdb_alloc(sym.st_size, UM_SLEEP); 145789Sahrens 146789Sahrens if (mdb_vread(*bufp, sym.st_size, sym.st_value) == -1) { 147789Sahrens mdb_warn("can't read data for symbol %s", sym_name); 148789Sahrens mdb_free(*bufp, sym.st_size); 149789Sahrens return (DCMD_ERR); 150789Sahrens } 151789Sahrens 152789Sahrens return (DCMD_OK); 153789Sahrens } 154789Sahrens 155789Sahrens static int verbose; 156789Sahrens 157789Sahrens static int 158789Sahrens freelist_walk_init(mdb_walk_state_t *wsp) 159789Sahrens { 160789Sahrens if (wsp->walk_addr == NULL) { 161789Sahrens mdb_warn("must supply starting address\n"); 162789Sahrens return (WALK_ERR); 163789Sahrens } 164789Sahrens 165789Sahrens wsp->walk_data = 0; /* Index into the freelist */ 166789Sahrens return (WALK_NEXT); 167789Sahrens } 168789Sahrens 169789Sahrens static int 170789Sahrens freelist_walk_step(mdb_walk_state_t *wsp) 171789Sahrens { 172789Sahrens uint64_t entry; 173789Sahrens uintptr_t number = (uintptr_t)wsp->walk_data; 174789Sahrens char *ddata[] = { "ALLOC", "FREE", "CONDENSE", "INVALID" }; 175789Sahrens int mapshift = SPA_MINBLOCKSHIFT; 176789Sahrens 177789Sahrens if (mdb_vread(&entry, sizeof (entry), wsp->walk_addr) == -1) { 178789Sahrens mdb_warn("failed to read freelist entry %p", wsp->walk_addr); 179789Sahrens return (WALK_DONE); 180789Sahrens } 181789Sahrens wsp->walk_addr += sizeof (entry); 182789Sahrens wsp->walk_data = (void *)(number + 1); 183789Sahrens 184789Sahrens if (SM_DEBUG_DECODE(entry)) { 185789Sahrens mdb_printf("DEBUG: %3u %10s: txg=%llu pass=%llu\n", 186789Sahrens number, 187789Sahrens ddata[SM_DEBUG_ACTION_DECODE(entry)], 188789Sahrens SM_DEBUG_TXG_DECODE(entry), 189789Sahrens SM_DEBUG_SYNCPASS_DECODE(entry)); 190789Sahrens } else { 191789Sahrens mdb_printf("Entry: %3u offsets=%08llx-%08llx type=%c " 192789Sahrens "size=%06llx", number, 193789Sahrens SM_OFFSET_DECODE(entry) << mapshift, 194789Sahrens (SM_OFFSET_DECODE(entry) + SM_RUN_DECODE(entry)) << 195789Sahrens mapshift, 196789Sahrens SM_TYPE_DECODE(entry) == SM_ALLOC ? 'A' : 'F', 197789Sahrens SM_RUN_DECODE(entry) << mapshift); 198789Sahrens if (verbose) 199789Sahrens mdb_printf(" (raw=%012llx)\n", entry); 200789Sahrens mdb_printf("\n"); 201789Sahrens } 202789Sahrens return (WALK_NEXT); 203789Sahrens } 204789Sahrens 205789Sahrens 206789Sahrens static int 207789Sahrens dataset_name(uintptr_t addr, char *buf) 208789Sahrens { 209789Sahrens static int gotid; 210789Sahrens static mdb_ctf_id_t dd_id; 211789Sahrens uintptr_t dd_parent; 212789Sahrens char dd_myname[MAXNAMELEN]; 213789Sahrens 214789Sahrens if (!gotid) { 215789Sahrens if (mdb_ctf_lookup_by_name("struct dsl_dir", 216789Sahrens &dd_id) == -1) { 217789Sahrens mdb_warn("couldn't find struct dsl_dir"); 218789Sahrens return (DCMD_ERR); 219789Sahrens } 220789Sahrens gotid = TRUE; 221789Sahrens } 222789Sahrens if (GETMEMBID(addr, &dd_id, dd_parent, dd_parent) || 223789Sahrens GETMEMBID(addr, &dd_id, dd_myname, dd_myname)) { 224789Sahrens return (DCMD_ERR); 225789Sahrens } 226789Sahrens 227789Sahrens if (dd_parent) { 228789Sahrens if (dataset_name(dd_parent, buf)) 229789Sahrens return (DCMD_ERR); 230789Sahrens strcat(buf, "/"); 231789Sahrens } 232789Sahrens 233789Sahrens if (dd_myname[0]) 234789Sahrens strcat(buf, dd_myname); 235789Sahrens else 236789Sahrens strcat(buf, "???"); 237789Sahrens 238789Sahrens return (0); 239789Sahrens } 240789Sahrens 241789Sahrens static int 242789Sahrens objset_name(uintptr_t addr, char *buf) 243789Sahrens { 244789Sahrens static int gotid; 245789Sahrens static mdb_ctf_id_t osi_id, ds_id; 246789Sahrens uintptr_t os_dsl_dataset; 247789Sahrens char ds_snapname[MAXNAMELEN]; 248789Sahrens uintptr_t ds_dir; 249789Sahrens 250789Sahrens buf[0] = '\0'; 251789Sahrens 252789Sahrens if (!gotid) { 253789Sahrens if (mdb_ctf_lookup_by_name("struct objset_impl", 254789Sahrens &osi_id) == -1) { 255789Sahrens mdb_warn("couldn't find struct objset_impl"); 256789Sahrens return (DCMD_ERR); 257789Sahrens } 258789Sahrens if (mdb_ctf_lookup_by_name("struct dsl_dataset", 259789Sahrens &ds_id) == -1) { 260789Sahrens mdb_warn("couldn't find struct dsl_dataset"); 261789Sahrens return (DCMD_ERR); 262789Sahrens } 263789Sahrens 264789Sahrens gotid = TRUE; 265789Sahrens } 266789Sahrens 267789Sahrens if (GETMEMBID(addr, &osi_id, os_dsl_dataset, os_dsl_dataset)) 268789Sahrens return (DCMD_ERR); 269789Sahrens 270789Sahrens if (os_dsl_dataset == 0) { 271789Sahrens strcat(buf, "mos"); 272789Sahrens return (0); 273789Sahrens } 274789Sahrens 275789Sahrens if (GETMEMBID(os_dsl_dataset, &ds_id, ds_snapname, ds_snapname) || 276789Sahrens GETMEMBID(os_dsl_dataset, &ds_id, ds_dir, ds_dir)) { 277789Sahrens return (DCMD_ERR); 278789Sahrens } 279789Sahrens 280789Sahrens if (ds_dir && dataset_name(ds_dir, buf)) 281789Sahrens return (DCMD_ERR); 282789Sahrens 283789Sahrens if (ds_snapname[0]) { 284789Sahrens strcat(buf, "@"); 285789Sahrens strcat(buf, ds_snapname); 286789Sahrens } 287789Sahrens return (0); 288789Sahrens } 289789Sahrens 290789Sahrens static void 291789Sahrens enum_lookup(char *out, size_t size, mdb_ctf_id_t id, int val, 292789Sahrens const char *prefix) 293789Sahrens { 294789Sahrens const char *cp; 295789Sahrens size_t len = strlen(prefix); 296789Sahrens 297789Sahrens if ((cp = mdb_ctf_enum_name(id, val)) != NULL) { 298789Sahrens if (strncmp(cp, prefix, len) == 0) 299789Sahrens cp += len; 300789Sahrens (void) strncpy(out, cp, size); 301789Sahrens } else { 302789Sahrens mdb_snprintf(out, size, "? (%d)", val); 303789Sahrens } 304789Sahrens } 305789Sahrens 306789Sahrens /* ARGSUSED */ 307789Sahrens static int 308789Sahrens zio_pipeline(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 309789Sahrens { 310789Sahrens mdb_ctf_id_t pipe_enum; 311789Sahrens int i; 312789Sahrens char stage[1024]; 313789Sahrens 314789Sahrens if (mdb_ctf_lookup_by_name("enum zio_stage", &pipe_enum) == -1) { 315789Sahrens mdb_warn("Could not find enum zio_stage"); 316789Sahrens return (DCMD_ERR); 317789Sahrens } 318789Sahrens 319789Sahrens for (i = 0; i < 32; i++) { 320789Sahrens if (addr & (1U << i)) { 321789Sahrens enum_lookup(stage, sizeof (stage), pipe_enum, i, 322789Sahrens "ZIO_STAGE_"); 323789Sahrens mdb_printf(" %s\n", stage); 324789Sahrens } 325789Sahrens } 326789Sahrens 327789Sahrens return (DCMD_OK); 328789Sahrens } 329789Sahrens 330789Sahrens /* ARGSUSED */ 331789Sahrens static int 332789Sahrens blkptr(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 333789Sahrens { 334789Sahrens blkptr_t bp; 335789Sahrens dmu_object_type_info_t *doti; 336789Sahrens zio_compress_info_t *zct; 337789Sahrens zio_checksum_info_t *zci; 338789Sahrens int i; 339789Sahrens char buf[MAXPATHLEN]; 340789Sahrens 341789Sahrens if (mdb_vread(&bp, sizeof (blkptr_t), addr) == -1) { 342789Sahrens mdb_warn("failed to read blkptr_t"); 343789Sahrens return (DCMD_ERR); 344789Sahrens } 345789Sahrens 346789Sahrens if (read_symbol("dmu_ot", (void **)&doti) != DCMD_OK) 347789Sahrens return (DCMD_ERR); 348789Sahrens for (i = 0; i < DMU_OT_NUMTYPES; i++) { 349789Sahrens mdb_readstr(buf, sizeof (buf), (uintptr_t)doti[i].ot_name); 350789Sahrens doti[i].ot_name = local_strdup(buf); 351789Sahrens } 352789Sahrens 353789Sahrens if (read_symbol("zio_checksum_table", (void **)&zci) != DCMD_OK) 354789Sahrens return (DCMD_ERR); 355789Sahrens for (i = 0; i < ZIO_CHECKSUM_FUNCTIONS; i++) { 356789Sahrens mdb_readstr(buf, sizeof (buf), (uintptr_t)zci[i].ci_name); 357789Sahrens zci[i].ci_name = local_strdup(buf); 358789Sahrens } 359789Sahrens 360789Sahrens if (read_symbol("zio_compress_table", (void **)&zct) != DCMD_OK) 361789Sahrens return (DCMD_ERR); 362789Sahrens for (i = 0; i < ZIO_COMPRESS_FUNCTIONS; i++) { 363789Sahrens mdb_readstr(buf, sizeof (buf), (uintptr_t)zct[i].ci_name); 364789Sahrens zct[i].ci_name = local_strdup(buf); 365789Sahrens } 366789Sahrens 3671775Sbillm /* 3681775Sbillm * Super-ick warning: This code is also duplicated in 3691775Sbillm * cmd/zdb.c . Yeah, I hate code replication, too. 3701775Sbillm */ 3711775Sbillm for (i = 0; i < BP_GET_NDVAS(&bp); i++) { 3721732Sbonwick dva_t *dva = &bp.blk_dva[i]; 3731775Sbillm 3741775Sbillm mdb_printf("DVA[%d]: vdev_id %lld / %llx\n", i, 3751775Sbillm DVA_GET_VDEV(dva), DVA_GET_OFFSET(dva)); 3761775Sbillm mdb_printf("DVA[%d]: GANG: %-5s GRID: %04x\t" 3771775Sbillm "ASIZE: %llx\n", i, DVA_GET_GANG(dva) ? "TRUE" : "FALSE", 3781775Sbillm DVA_GET_GRID(dva), DVA_GET_ASIZE(dva)); 3791775Sbillm mdb_printf("DVA[%d]: :%llu:%llx:%llx:%s%s%s%s\n", i, 3801775Sbillm DVA_GET_VDEV(dva), DVA_GET_OFFSET(dva), BP_GET_PSIZE(&bp), 3811775Sbillm BP_SHOULD_BYTESWAP(&bp) ? "e" : "", 3821775Sbillm !DVA_GET_GANG(dva) && BP_GET_LEVEL(&bp) != 0 ? "i" : "", 3831775Sbillm DVA_GET_GANG(dva) ? "g" : "", 3841775Sbillm BP_GET_COMPRESS(&bp) != 0 ? "d" : ""); 385789Sahrens } 386789Sahrens mdb_printf("LSIZE: %-16llx\t\tPSIZE: %llx\n", 387789Sahrens BP_GET_LSIZE(&bp), BP_GET_PSIZE(&bp)); 3881775Sbillm mdb_printf("ENDIAN: %6s\t\t\t\t\tTYPE: %s\n", 389789Sahrens BP_GET_BYTEORDER(&bp) ? "LITTLE" : "BIG", 390789Sahrens doti[BP_GET_TYPE(&bp)].ot_name); 391789Sahrens mdb_printf("BIRTH: %-16llx LEVEL: %-2d\tFILL: %llx\n", 392789Sahrens bp.blk_birth, BP_GET_LEVEL(&bp), bp.blk_fill); 393789Sahrens mdb_printf("CKFUNC: %-16s\t\tCOMP: %s\n", 394789Sahrens zci[BP_GET_CHECKSUM(&bp)].ci_name, 395789Sahrens zct[BP_GET_COMPRESS(&bp)].ci_name); 396789Sahrens mdb_printf("CKSUM: %llx:%llx:%llx:%llx\n", 397789Sahrens bp.blk_cksum.zc_word[0], 398789Sahrens bp.blk_cksum.zc_word[1], 399789Sahrens bp.blk_cksum.zc_word[2], 400789Sahrens bp.blk_cksum.zc_word[3]); 401789Sahrens 402789Sahrens return (DCMD_OK); 403789Sahrens } 404789Sahrens 405789Sahrens /* ARGSUSED */ 406789Sahrens static int 407789Sahrens dbuf(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 408789Sahrens { 409789Sahrens mdb_ctf_id_t id; 410789Sahrens dmu_buf_t db; 411789Sahrens uintptr_t objset; 412789Sahrens uint8_t level; 413789Sahrens uint64_t blkid; 414789Sahrens uint64_t holds; 415789Sahrens char objectname[32]; 416789Sahrens char blkidname[32]; 417789Sahrens char path[MAXNAMELEN]; 418789Sahrens 419789Sahrens if (DCMD_HDRSPEC(flags)) { 420789Sahrens mdb_printf(" addr object lvl blkid holds os\n"); 421789Sahrens } 422789Sahrens 423789Sahrens if (mdb_ctf_lookup_by_name("struct dmu_buf_impl", &id) == -1) { 424789Sahrens mdb_warn("couldn't find struct dmu_buf_impl_t"); 425789Sahrens return (DCMD_ERR); 426789Sahrens } 427789Sahrens 428789Sahrens if (GETMEMBID(addr, &id, db_objset, objset) || 429789Sahrens GETMEMBID(addr, &id, db, db) || 430789Sahrens GETMEMBID(addr, &id, db_level, level) || 431789Sahrens GETMEMBID(addr, &id, db_blkid, blkid)) { 432789Sahrens return (WALK_ERR); 433789Sahrens } 434789Sahrens 435789Sahrens if (getrefcount(addr, &id, "db_holds", &holds)) { 436789Sahrens return (WALK_ERR); 437789Sahrens } 438789Sahrens 439789Sahrens if (db.db_object == DMU_META_DNODE_OBJECT) 440789Sahrens (void) strcpy(objectname, "mdn"); 441789Sahrens else 442789Sahrens (void) mdb_snprintf(objectname, sizeof (objectname), "%llx", 443789Sahrens (u_longlong_t)db.db_object); 444789Sahrens 445789Sahrens if (blkid == DB_BONUS_BLKID) 446789Sahrens (void) strcpy(blkidname, "bonus"); 447789Sahrens else 448789Sahrens (void) mdb_snprintf(blkidname, sizeof (blkidname), "%llx", 449789Sahrens (u_longlong_t)blkid); 450789Sahrens 451789Sahrens if (objset_name(objset, path)) { 452789Sahrens return (WALK_ERR); 453789Sahrens } 454789Sahrens 455789Sahrens mdb_printf("%p %8s %1u %9s %2llu %s\n", 456789Sahrens addr, objectname, level, blkidname, holds, path); 457789Sahrens 458789Sahrens return (DCMD_OK); 459789Sahrens } 460789Sahrens 461789Sahrens /* ARGSUSED */ 462789Sahrens static int 463789Sahrens dbuf_stats(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 464789Sahrens { 465789Sahrens #define HISTOSZ 32 466789Sahrens uintptr_t dbp; 467789Sahrens dmu_buf_impl_t db; 468789Sahrens dbuf_hash_table_t ht; 469789Sahrens uint64_t bucket, ndbufs; 470789Sahrens uint64_t histo[HISTOSZ]; 471789Sahrens uint64_t histo2[HISTOSZ]; 472789Sahrens int i, maxidx; 473789Sahrens 474789Sahrens if (mdb_readvar(&ht, "dbuf_hash_table") == -1) { 475789Sahrens mdb_warn("failed to read 'dbuf_hash_table'"); 476789Sahrens return (DCMD_ERR); 477789Sahrens } 478789Sahrens 479789Sahrens for (i = 0; i < HISTOSZ; i++) { 480789Sahrens histo[i] = 0; 481789Sahrens histo2[i] = 0; 482789Sahrens } 483789Sahrens 484789Sahrens ndbufs = 0; 485789Sahrens for (bucket = 0; bucket < ht.hash_table_mask+1; bucket++) { 486789Sahrens int len; 487789Sahrens 488789Sahrens if (mdb_vread(&dbp, sizeof (void *), 489789Sahrens (uintptr_t)(ht.hash_table+bucket)) == -1) { 490789Sahrens mdb_warn("failed to read hash bucket %u at %p", 491789Sahrens bucket, ht.hash_table+bucket); 492789Sahrens return (DCMD_ERR); 493789Sahrens } 494789Sahrens 495789Sahrens len = 0; 496789Sahrens while (dbp != 0) { 497789Sahrens if (mdb_vread(&db, sizeof (dmu_buf_impl_t), 498789Sahrens dbp) == -1) { 499789Sahrens mdb_warn("failed to read dbuf at %p", dbp); 500789Sahrens return (DCMD_ERR); 501789Sahrens } 502789Sahrens dbp = (uintptr_t)db.db_hash_next; 503789Sahrens for (i = MIN(len, HISTOSZ - 1); i >= 0; i--) 504789Sahrens histo2[i]++; 505789Sahrens len++; 506789Sahrens ndbufs++; 507789Sahrens } 508789Sahrens 509789Sahrens if (len >= HISTOSZ) 510789Sahrens len = HISTOSZ-1; 511789Sahrens histo[len]++; 512789Sahrens } 513789Sahrens 514789Sahrens mdb_printf("hash table has %llu buckets, %llu dbufs " 515789Sahrens "(avg %llu buckets/dbuf)\n", 516789Sahrens ht.hash_table_mask+1, ndbufs, 517789Sahrens (ht.hash_table_mask+1)/ndbufs); 518789Sahrens 519789Sahrens mdb_printf("\n"); 520789Sahrens maxidx = 0; 521789Sahrens for (i = 0; i < HISTOSZ; i++) 522789Sahrens if (histo[i] > 0) 523789Sahrens maxidx = i; 524789Sahrens mdb_printf("hash chain length number of buckets\n"); 525789Sahrens for (i = 0; i <= maxidx; i++) 526789Sahrens mdb_printf("%u %llu\n", i, histo[i]); 527789Sahrens 528789Sahrens mdb_printf("\n"); 529789Sahrens maxidx = 0; 530789Sahrens for (i = 0; i < HISTOSZ; i++) 531789Sahrens if (histo2[i] > 0) 532789Sahrens maxidx = i; 533789Sahrens mdb_printf("hash chain depth number of dbufs\n"); 534789Sahrens for (i = 0; i <= maxidx; i++) 535789Sahrens mdb_printf("%u or more %llu %llu%%\n", 536789Sahrens i, histo2[i], histo2[i]*100/ndbufs); 537789Sahrens 538789Sahrens 539789Sahrens return (DCMD_OK); 540789Sahrens } 541789Sahrens 542789Sahrens typedef struct dbufs_data { 543789Sahrens mdb_ctf_id_t id; 544789Sahrens uint64_t objset; 545789Sahrens uint64_t object; 546789Sahrens uint64_t level; 547789Sahrens uint64_t blkid; 548789Sahrens char *osname; 549789Sahrens } dbufs_data_t; 550789Sahrens 551789Sahrens #define DBUFS_UNSET (0xbaddcafedeadbeefULL) 552789Sahrens 553789Sahrens /* ARGSUSED */ 554789Sahrens static int 555789Sahrens dbufs_cb(uintptr_t addr, const void *unknown, void *arg) 556789Sahrens { 557789Sahrens dbufs_data_t *data = arg; 558789Sahrens uintptr_t objset; 559789Sahrens dmu_buf_t db; 560789Sahrens uint8_t level; 561789Sahrens uint64_t blkid; 562789Sahrens char osname[MAXNAMELEN]; 563789Sahrens 564789Sahrens if (GETMEMBID(addr, &data->id, db_objset, objset) || 565789Sahrens GETMEMBID(addr, &data->id, db, db) || 566789Sahrens GETMEMBID(addr, &data->id, db_level, level) || 567789Sahrens GETMEMBID(addr, &data->id, db_blkid, blkid)) { 568789Sahrens return (WALK_ERR); 569789Sahrens } 570789Sahrens 571789Sahrens if ((data->objset == DBUFS_UNSET || data->objset == objset) && 572789Sahrens (data->osname == NULL || (objset_name(objset, osname) == 0 && 573789Sahrens strcmp(data->osname, osname) == 0)) && 574789Sahrens (data->object == DBUFS_UNSET || data->object == db.db_object) && 575789Sahrens (data->level == DBUFS_UNSET || data->level == level) && 576789Sahrens (data->blkid == DBUFS_UNSET || data->blkid == blkid)) { 577789Sahrens mdb_printf("%#lr\n", addr); 578789Sahrens } 579789Sahrens return (WALK_NEXT); 580789Sahrens } 581789Sahrens 582789Sahrens /* ARGSUSED */ 583789Sahrens static int 584789Sahrens dbufs(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 585789Sahrens { 586789Sahrens dbufs_data_t data; 587789Sahrens char *object = NULL; 588789Sahrens char *blkid = NULL; 589789Sahrens 590789Sahrens data.objset = data.object = data.level = data.blkid = DBUFS_UNSET; 591789Sahrens data.osname = NULL; 592789Sahrens 593789Sahrens if (mdb_getopts(argc, argv, 594789Sahrens 'O', MDB_OPT_UINT64, &data.objset, 595789Sahrens 'n', MDB_OPT_STR, &data.osname, 596789Sahrens 'o', MDB_OPT_STR, &object, 597789Sahrens 'l', MDB_OPT_UINT64, &data.level, 598789Sahrens 'b', MDB_OPT_STR, &blkid) != argc) { 599789Sahrens return (DCMD_USAGE); 600789Sahrens } 601789Sahrens 602789Sahrens if (object) { 603789Sahrens if (strcmp(object, "mdn") == 0) { 604789Sahrens data.object = DMU_META_DNODE_OBJECT; 605789Sahrens } else { 606789Sahrens data.object = mdb_strtoull(object); 607789Sahrens } 608789Sahrens } 609789Sahrens 610789Sahrens if (blkid) { 611789Sahrens if (strcmp(blkid, "bonus") == 0) { 612789Sahrens data.blkid = DB_BONUS_BLKID; 613789Sahrens } else { 614789Sahrens data.blkid = mdb_strtoull(blkid); 615789Sahrens } 616789Sahrens } 617789Sahrens 618789Sahrens if (mdb_ctf_lookup_by_name("struct dmu_buf_impl", &data.id) == -1) { 619789Sahrens mdb_warn("couldn't find struct dmu_buf_impl_t"); 620789Sahrens return (DCMD_ERR); 621789Sahrens } 622789Sahrens 623*2459Sahrens if (mdb_walk("dmu_buf_impl_t", dbufs_cb, &data) != 0) { 624789Sahrens mdb_warn("can't walk dbufs"); 625789Sahrens return (DCMD_ERR); 626789Sahrens } 627789Sahrens 628789Sahrens return (DCMD_OK); 629789Sahrens } 630789Sahrens 631789Sahrens typedef struct abuf_find_data { 632789Sahrens dva_t dva; 633789Sahrens mdb_ctf_id_t id; 634789Sahrens } abuf_find_data_t; 635789Sahrens 636789Sahrens /* ARGSUSED */ 637789Sahrens static int 638789Sahrens abuf_find_cb(uintptr_t addr, const void *unknown, void *arg) 639789Sahrens { 640789Sahrens abuf_find_data_t *data = arg; 641789Sahrens dva_t dva; 642789Sahrens 643789Sahrens if (GETMEMBID(addr, &data->id, b_dva, dva)) { 644789Sahrens return (WALK_ERR); 645789Sahrens } 646789Sahrens 647789Sahrens if (dva.dva_word[0] == data->dva.dva_word[0] && 648789Sahrens dva.dva_word[1] == data->dva.dva_word[1]) { 649789Sahrens mdb_printf("%#lr\n", addr); 650789Sahrens } 651789Sahrens return (WALK_NEXT); 652789Sahrens } 653789Sahrens 654789Sahrens /* ARGSUSED */ 655789Sahrens static int 656789Sahrens abuf_find(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 657789Sahrens { 658789Sahrens abuf_find_data_t data; 659789Sahrens GElf_Sym sym; 660789Sahrens int i; 661789Sahrens const char *syms[] = { 662789Sahrens "ARC_mru_top", 663789Sahrens "ARC_mru_bot", 664789Sahrens "ARC_mfu_top", 665789Sahrens "ARC_mfu_bot", 666789Sahrens }; 667789Sahrens 668789Sahrens if (argc != 2) 669789Sahrens return (DCMD_USAGE); 670789Sahrens 671789Sahrens for (i = 0; i < 2; i ++) { 672789Sahrens switch (argv[i].a_type) { 673789Sahrens case MDB_TYPE_STRING: 674789Sahrens data.dva.dva_word[i] = mdb_strtoull(argv[i].a_un.a_str); 675789Sahrens break; 676789Sahrens case MDB_TYPE_IMMEDIATE: 677789Sahrens data.dva.dva_word[i] = argv[i].a_un.a_val; 678789Sahrens break; 679789Sahrens default: 680789Sahrens return (DCMD_USAGE); 681789Sahrens } 682789Sahrens } 683789Sahrens 684789Sahrens if (mdb_ctf_lookup_by_name("struct arc_buf_hdr", &data.id) == -1) { 685789Sahrens mdb_warn("couldn't find struct arc_buf_hdr"); 686789Sahrens return (DCMD_ERR); 687789Sahrens } 688789Sahrens 689789Sahrens for (i = 0; i < sizeof (syms) / sizeof (syms[0]); i++) { 690789Sahrens if (mdb_lookup_by_name(syms[i], &sym)) { 691789Sahrens mdb_warn("can't find symbol %s", syms[i]); 692789Sahrens return (DCMD_ERR); 693789Sahrens } 694789Sahrens 695789Sahrens if (mdb_pwalk("list", abuf_find_cb, &data, sym.st_value) != 0) { 696789Sahrens mdb_warn("can't walk %s", syms[i]); 697789Sahrens return (DCMD_ERR); 698789Sahrens } 699789Sahrens } 700789Sahrens 701789Sahrens return (DCMD_OK); 702789Sahrens } 703789Sahrens 704789Sahrens void 705789Sahrens abuf_help(void) 706789Sahrens { 707789Sahrens mdb_printf("::abuf_find dva_word[0] dva_word[1]\n"); 708789Sahrens } 709789Sahrens 710789Sahrens /* 711789Sahrens * ::spa 712789Sahrens * 713789Sahrens * -c Print configuration information as well 714789Sahrens * -v Print vdev state 715789Sahrens * -e Print vdev error stats 716789Sahrens * 717789Sahrens * Print a summarized spa_t. When given no arguments, prints out a table of all 718789Sahrens * active pools on the system. 719789Sahrens */ 720789Sahrens /* ARGSUSED */ 721789Sahrens static int 722789Sahrens spa_print(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 723789Sahrens { 724789Sahrens spa_t spa; 725789Sahrens char poolname[MAXNAMELEN]; 726789Sahrens const char *statetab[] = { "ACTIVE", "EXPORTED", "DESTROYED", 727789Sahrens "UNINIT", "UNAVAIL" }; 728789Sahrens const char *state; 729789Sahrens int config = FALSE; 730789Sahrens int vdevs = FALSE; 731789Sahrens int errors = FALSE; 732789Sahrens 733789Sahrens if (mdb_getopts(argc, argv, 734789Sahrens 'c', MDB_OPT_SETBITS, TRUE, &config, 735789Sahrens 'v', MDB_OPT_SETBITS, TRUE, &vdevs, 736789Sahrens 'e', MDB_OPT_SETBITS, TRUE, &errors, 737789Sahrens NULL) != argc) 738789Sahrens return (DCMD_USAGE); 739789Sahrens 740789Sahrens if (!(flags & DCMD_ADDRSPEC)) { 741789Sahrens if (mdb_walk_dcmd("spa", "spa", argc, argv) == -1) { 742789Sahrens mdb_warn("can't walk spa"); 743789Sahrens return (DCMD_ERR); 744789Sahrens } 745789Sahrens 746789Sahrens return (DCMD_OK); 747789Sahrens } 748789Sahrens 749789Sahrens if (flags & DCMD_PIPE_OUT) { 750789Sahrens mdb_printf("%#lr\n", addr); 751789Sahrens return (DCMD_OK); 752789Sahrens } 753789Sahrens 754789Sahrens if (DCMD_HDRSPEC(flags)) 755789Sahrens mdb_printf("%<u>%-?s %9s %-*s%</u>\n", "ADDR", "STATE", 756789Sahrens sizeof (uintptr_t) == 4 ? 60 : 52, "NAME"); 757789Sahrens 758789Sahrens if (mdb_vread(&spa, sizeof (spa), addr) == -1) { 759789Sahrens mdb_warn("failed to read spa_t at %p", addr); 760789Sahrens return (DCMD_ERR); 761789Sahrens } 762789Sahrens 763789Sahrens if (mdb_readstr(poolname, sizeof (poolname), (uintptr_t)spa.spa_name) 764789Sahrens == -1) { 765789Sahrens mdb_warn("failed to read pool name at %p", spa.spa_name); 766789Sahrens return (DCMD_ERR); 767789Sahrens } 768789Sahrens 769789Sahrens if (spa.spa_state < 0 || spa.spa_state > POOL_STATE_UNAVAIL) 7701544Seschrock state = "UNKNOWN"; 771789Sahrens else 772789Sahrens state = statetab[spa.spa_state]; 773789Sahrens 774789Sahrens mdb_printf("%0?p %9s %s\n", addr, state, poolname); 775789Sahrens 776789Sahrens if (config) { 777789Sahrens mdb_printf("\n"); 778789Sahrens mdb_inc_indent(4); 779789Sahrens if (mdb_call_dcmd("spa_config", addr, flags, 0, 780789Sahrens NULL) != DCMD_OK) 781789Sahrens return (DCMD_ERR); 782789Sahrens mdb_dec_indent(4); 783789Sahrens } 784789Sahrens 785789Sahrens if (vdevs || errors) { 786789Sahrens mdb_arg_t v; 787789Sahrens 788789Sahrens v.a_type = MDB_TYPE_STRING; 789789Sahrens v.a_un.a_str = "-e"; 790789Sahrens 791789Sahrens mdb_printf("\n"); 792789Sahrens mdb_inc_indent(4); 793789Sahrens if (mdb_call_dcmd("spa_vdevs", addr, flags, errors ? 1 : 0, 794789Sahrens &v) != DCMD_OK) 795789Sahrens return (DCMD_ERR); 796789Sahrens mdb_dec_indent(4); 797789Sahrens } 798789Sahrens 799789Sahrens return (DCMD_OK); 800789Sahrens } 801789Sahrens 802789Sahrens /* 803789Sahrens * ::spa_config 804789Sahrens * 805789Sahrens * Given a spa_t, print the configuration information stored in spa_config. 806789Sahrens * Since it's just an nvlist, format it as an indented list of name=value pairs. 807789Sahrens * We simply read the value of spa_config and pass off to ::nvlist. 808789Sahrens */ 809789Sahrens /* ARGSUSED */ 810789Sahrens static int 811789Sahrens spa_print_config(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 812789Sahrens { 813789Sahrens spa_t spa; 814789Sahrens 815789Sahrens if (argc != 0 || !(flags & DCMD_ADDRSPEC)) 816789Sahrens return (DCMD_USAGE); 817789Sahrens 818789Sahrens if (mdb_vread(&spa, sizeof (spa), addr) == -1) { 819789Sahrens mdb_warn("failed to read spa_t at %p", addr); 820789Sahrens return (DCMD_ERR); 821789Sahrens } 822789Sahrens 823789Sahrens if (spa.spa_config == NULL) { 824789Sahrens mdb_printf("(none)\n"); 825789Sahrens return (DCMD_OK); 826789Sahrens } 827789Sahrens 828789Sahrens return (mdb_call_dcmd("nvlist", (uintptr_t)spa.spa_config, flags, 829789Sahrens 0, NULL)); 830789Sahrens } 831789Sahrens 832789Sahrens void 833789Sahrens vdev_help(void) 834789Sahrens { 835789Sahrens mdb_printf("[vdev_t*]::vdev [-qr]\n" 836789Sahrens "\t-> -q display vdev_queue parameters\n" 837789Sahrens "\t-> -r recursive (visit all children)\n"); 838789Sahrens } 839789Sahrens 840789Sahrens /* 841789Sahrens * ::vdev 842789Sahrens * 843789Sahrens * Print out a summarized vdev_t, in the following form: 844789Sahrens * 845789Sahrens * ADDR STATE AUX DESC 846789Sahrens * fffffffbcde23df0 HEALTHY - /dev/dsk/c0t0d0 847789Sahrens * 848789Sahrens * or with "-q" to print out a vdev_t's vdev_queue parameters: 849789Sahrens * 850789Sahrens * vdev_t: c26ae4c0 851789Sahrens * c26ae73c min pending 0x2 852789Sahrens * c26ae744 max pending 0x23 853789Sahrens * c26ae74c agg limit 0x20000 854789Sahrens * c26ae754 time shift 0x4 855789Sahrens * c26ae75c ramp rate 0x2 856789Sahrens * 857789Sahrens * If '-r' is specified, recursively visit all children. 858789Sahrens * 859789Sahrens * With '-e', the statistics associated with the vdev are printed as well. 860789Sahrens */ 861789Sahrens static int 862789Sahrens do_print_vdev(uintptr_t addr, int flags, int depth, int queue, int stats, 863789Sahrens int recursive) 864789Sahrens { 865789Sahrens vdev_t vdev; 866789Sahrens char desc[MAXNAMELEN]; 867789Sahrens int c, children; 868789Sahrens uintptr_t *child; 869789Sahrens const char *state, *aux; 870789Sahrens 871789Sahrens if (mdb_vread(&vdev, sizeof (vdev), (uintptr_t)addr) == -1) { 872789Sahrens mdb_warn("failed to read vdev_t at %p\n", (uintptr_t)addr); 873789Sahrens return (DCMD_ERR); 874789Sahrens } 875789Sahrens 876789Sahrens if (flags & DCMD_PIPE_OUT) { 877789Sahrens mdb_printf("%#lr", addr); 878789Sahrens } else { 879789Sahrens if (vdev.vdev_path != NULL) { 880789Sahrens if (mdb_readstr(desc, sizeof (desc), 881789Sahrens (uintptr_t)vdev.vdev_path) == -1) { 882789Sahrens mdb_warn("failed to read vdev_path at %p\n", 883789Sahrens vdev.vdev_path); 884789Sahrens return (DCMD_ERR); 885789Sahrens } 886789Sahrens } else if (vdev.vdev_ops != NULL) { 887789Sahrens vdev_ops_t ops; 888789Sahrens if (mdb_vread(&ops, sizeof (ops), 889789Sahrens (uintptr_t)vdev.vdev_ops) == -1) { 890789Sahrens mdb_warn("failed to read vdev_ops at %p\n", 891789Sahrens vdev.vdev_ops); 892789Sahrens return (DCMD_ERR); 893789Sahrens } 894789Sahrens (void) strcpy(desc, ops.vdev_op_type); 895789Sahrens } else { 896789Sahrens (void) strcpy(desc, "<unknown>"); 897789Sahrens } 898789Sahrens 899789Sahrens if (depth == 0 && DCMD_HDRSPEC(flags)) 900789Sahrens mdb_printf("%<u>%-?s %-9s %-12s %-*s%</u>\n", 901789Sahrens "ADDR", "STATE", "AUX", 902789Sahrens sizeof (uintptr_t) == 4 ? 43 : 35, 903789Sahrens "DESCRIPTION"); 904789Sahrens 905789Sahrens mdb_printf("%0?p ", addr); 906789Sahrens 907789Sahrens switch (vdev.vdev_state) { 908789Sahrens case VDEV_STATE_CLOSED: 909789Sahrens state = "CLOSED"; 910789Sahrens break; 911789Sahrens case VDEV_STATE_OFFLINE: 912789Sahrens state = "OFFLINE"; 913789Sahrens break; 914789Sahrens case VDEV_STATE_CANT_OPEN: 915789Sahrens state = "CANT_OPEN"; 916789Sahrens break; 917789Sahrens case VDEV_STATE_DEGRADED: 918789Sahrens state = "DEGRADED"; 919789Sahrens break; 920789Sahrens case VDEV_STATE_HEALTHY: 921789Sahrens state = "HEALTHY"; 922789Sahrens break; 923789Sahrens default: 924789Sahrens state = "UNKNOWN"; 925789Sahrens break; 926789Sahrens } 927789Sahrens 928789Sahrens switch (vdev.vdev_stat.vs_aux) { 929789Sahrens case VDEV_AUX_NONE: 930789Sahrens aux = "-"; 931789Sahrens break; 932789Sahrens case VDEV_AUX_OPEN_FAILED: 933789Sahrens aux = "OPEN_FAILED"; 934789Sahrens break; 935789Sahrens case VDEV_AUX_CORRUPT_DATA: 936789Sahrens aux = "CORRUPT_DATA"; 937789Sahrens break; 938789Sahrens case VDEV_AUX_NO_REPLICAS: 939789Sahrens aux = "NO_REPLICAS"; 940789Sahrens break; 941789Sahrens case VDEV_AUX_BAD_GUID_SUM: 942789Sahrens aux = "BAD_GUID_SUM"; 943789Sahrens break; 944789Sahrens case VDEV_AUX_TOO_SMALL: 945789Sahrens aux = "TOO_SMALL"; 946789Sahrens break; 947789Sahrens case VDEV_AUX_BAD_LABEL: 948789Sahrens aux = "BAD_LABEL"; 949789Sahrens break; 950789Sahrens default: 951789Sahrens aux = "UNKNOWN"; 952789Sahrens break; 953789Sahrens } 954789Sahrens 955789Sahrens mdb_printf("%-9s %-12s %*s%s\n", state, aux, depth, "", desc); 956789Sahrens 957789Sahrens if (queue) { 958789Sahrens mdb_inc_indent(4); 959789Sahrens mdb_printf("\n"); 960789Sahrens mdb_printf("%p min pending 0x%llx\n", 961789Sahrens (uintptr_t)(addr + offsetof(vdev_t, 962789Sahrens vdev_queue.vq_min_pending)), 963789Sahrens vdev.vdev_queue.vq_min_pending); 964789Sahrens mdb_printf("%p max pending 0x%llx\n", 965789Sahrens (uintptr_t)(addr + offsetof(vdev_t, 966789Sahrens vdev_queue.vq_max_pending)), 967789Sahrens vdev.vdev_queue.vq_max_pending); 968789Sahrens mdb_printf("%p agg limit 0x%llx\n", 969789Sahrens (uintptr_t)(addr + offsetof(vdev_t, 970789Sahrens vdev_queue.vq_agg_limit)), 971789Sahrens vdev.vdev_queue.vq_agg_limit); 972789Sahrens mdb_printf("%p time shift 0x%llx\n", 973789Sahrens (uintptr_t)(addr + offsetof(vdev_t, 974789Sahrens vdev_queue.vq_time_shift)), 975789Sahrens vdev.vdev_queue.vq_time_shift); 976789Sahrens mdb_printf("%p ramp rate 0x%llx\n", 977789Sahrens (uintptr_t)(addr + offsetof(vdev_t, 978789Sahrens vdev_queue.vq_ramp_rate)), 979789Sahrens vdev.vdev_queue.vq_ramp_rate); 980789Sahrens mdb_dec_indent(4); 981789Sahrens } 982789Sahrens 983789Sahrens if (stats) { 984789Sahrens vdev_stat_t *vs = &vdev.vdev_stat; 985789Sahrens int i; 986789Sahrens 987789Sahrens mdb_inc_indent(4); 988789Sahrens mdb_printf("\n"); 989789Sahrens mdb_printf("%<u> %12s %12s %12s %12s " 990789Sahrens "%12s%</u>\n", "READ", "WRITE", "FREE", "CLAIM", 991789Sahrens "IOCTL"); 992789Sahrens mdb_printf("OPS "); 993789Sahrens for (i = 1; i < ZIO_TYPES; i++) 994789Sahrens mdb_printf("%11#llx%s", vs->vs_ops[i], 995789Sahrens i == ZIO_TYPES - 1 ? "" : " "); 996789Sahrens mdb_printf("\n"); 997789Sahrens mdb_printf("BYTES "); 998789Sahrens for (i = 1; i < ZIO_TYPES; i++) 999789Sahrens mdb_printf("%11#llx%s", vs->vs_bytes[i], 1000789Sahrens i == ZIO_TYPES - 1 ? "" : " "); 1001789Sahrens 1002789Sahrens 1003789Sahrens mdb_printf("\n"); 1004789Sahrens mdb_printf("EREAD %10#llx\n", vs->vs_read_errors); 1005789Sahrens mdb_printf("EWRITE %10#llx\n", vs->vs_write_errors); 1006789Sahrens mdb_printf("ECKSUM %10#llx\n", 1007789Sahrens vs->vs_checksum_errors); 1008789Sahrens mdb_dec_indent(4); 1009789Sahrens } 1010789Sahrens 1011789Sahrens if (queue || stats) 1012789Sahrens mdb_printf("\n"); 1013789Sahrens } 1014789Sahrens 1015789Sahrens children = vdev.vdev_children; 1016789Sahrens 1017789Sahrens if (children == 0 || !recursive) 1018789Sahrens return (DCMD_OK); 1019789Sahrens 1020789Sahrens child = mdb_alloc(children * sizeof (void *), UM_SLEEP | UM_GC); 1021789Sahrens if (mdb_vread(child, children * sizeof (void *), 1022789Sahrens (uintptr_t)vdev.vdev_child) == -1) { 1023789Sahrens mdb_warn("failed to read vdev children at %p", vdev.vdev_child); 1024789Sahrens return (DCMD_ERR); 1025789Sahrens } 1026789Sahrens 1027789Sahrens for (c = 0; c < children; c++) { 1028789Sahrens if (do_print_vdev(child[c], flags, depth + 2, queue, stats, 1029789Sahrens recursive)) 1030789Sahrens return (DCMD_ERR); 1031789Sahrens } 1032789Sahrens 1033789Sahrens return (DCMD_OK); 1034789Sahrens } 1035789Sahrens 1036789Sahrens static int 1037789Sahrens vdev_print(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 1038789Sahrens { 1039789Sahrens int print_queue = FALSE; 1040789Sahrens int recursive = FALSE; 1041789Sahrens int stats = FALSE; 1042789Sahrens 1043789Sahrens if (mdb_getopts(argc, argv, 1044789Sahrens 'q', MDB_OPT_SETBITS, TRUE, &print_queue, 1045789Sahrens 'r', MDB_OPT_SETBITS, TRUE, &recursive, 1046789Sahrens 'e', MDB_OPT_SETBITS, TRUE, &stats, 1047789Sahrens NULL) != argc) 1048789Sahrens return (DCMD_USAGE); 1049789Sahrens 1050789Sahrens if (!(flags & DCMD_ADDRSPEC)) { 1051789Sahrens mdb_warn("no vdev_t address given\n"); 1052789Sahrens return (DCMD_ERR); 1053789Sahrens } 1054789Sahrens 1055789Sahrens return (do_print_vdev(addr, flags, 0, print_queue, stats, recursive)); 1056789Sahrens } 1057789Sahrens 1058*2459Sahrens typedef struct metaslab_walk_data { 1059*2459Sahrens uint64_t mw_numvdevs; 1060*2459Sahrens uintptr_t *mw_vdevs; 1061*2459Sahrens int mw_curvdev; 1062*2459Sahrens uint64_t mw_nummss; 1063*2459Sahrens uintptr_t *mw_mss; 1064*2459Sahrens int mw_curms; 1065*2459Sahrens } metaslab_walk_data_t; 1066*2459Sahrens 1067*2459Sahrens static int 1068*2459Sahrens metaslab_walk_step(mdb_walk_state_t *wsp) 1069*2459Sahrens { 1070*2459Sahrens metaslab_walk_data_t *mw = wsp->walk_data; 1071*2459Sahrens metaslab_t ms; 1072*2459Sahrens uintptr_t msp; 1073*2459Sahrens 1074*2459Sahrens if (mw->mw_curvdev >= mw->mw_numvdevs) 1075*2459Sahrens return (WALK_DONE); 1076*2459Sahrens 1077*2459Sahrens if (mw->mw_mss == NULL) { 1078*2459Sahrens uintptr_t mssp; 1079*2459Sahrens uintptr_t vdevp; 1080*2459Sahrens 1081*2459Sahrens ASSERT(mw->mw_curms == 0); 1082*2459Sahrens ASSERT(mw->mw_nummss == 0); 1083*2459Sahrens 1084*2459Sahrens vdevp = mw->mw_vdevs[mw->mw_curvdev]; 1085*2459Sahrens if (GETMEMB(vdevp, struct vdev, vdev_ms, mssp) || 1086*2459Sahrens GETMEMB(vdevp, struct vdev, vdev_ms_count, mw->mw_nummss)) { 1087*2459Sahrens return (WALK_ERR); 1088*2459Sahrens } 1089*2459Sahrens 1090*2459Sahrens mw->mw_mss = mdb_alloc(mw->mw_nummss * sizeof (void*), 1091*2459Sahrens UM_SLEEP | UM_GC); 1092*2459Sahrens if (mdb_vread(mw->mw_mss, mw->mw_nummss * sizeof (void*), 1093*2459Sahrens mssp) == -1) { 1094*2459Sahrens mdb_warn("failed to read vdev_ms at %p", mssp); 1095*2459Sahrens return (WALK_ERR); 1096*2459Sahrens } 1097*2459Sahrens } 1098*2459Sahrens 1099*2459Sahrens if (mw->mw_curms >= mw->mw_nummss) { 1100*2459Sahrens mw->mw_mss = NULL; 1101*2459Sahrens mw->mw_curms = 0; 1102*2459Sahrens mw->mw_nummss = 0; 1103*2459Sahrens mw->mw_curvdev++; 1104*2459Sahrens return (WALK_NEXT); 1105*2459Sahrens } 1106*2459Sahrens 1107*2459Sahrens msp = mw->mw_mss[mw->mw_curms]; 1108*2459Sahrens if (mdb_vread(&ms, sizeof (metaslab_t), msp) == -1) { 1109*2459Sahrens mdb_warn("failed to read metaslab_t at %p", msp); 1110*2459Sahrens return (WALK_ERR); 1111*2459Sahrens } 1112*2459Sahrens 1113*2459Sahrens mw->mw_curms++; 1114*2459Sahrens 1115*2459Sahrens return (wsp->walk_callback(msp, &ms, wsp->walk_cbdata)); 1116*2459Sahrens } 1117*2459Sahrens 1118*2459Sahrens /* ARGSUSED */ 1119*2459Sahrens static int 1120*2459Sahrens metaslab_walk_init(mdb_walk_state_t *wsp) 1121*2459Sahrens { 1122*2459Sahrens metaslab_walk_data_t *mw; 1123*2459Sahrens uintptr_t root_vdevp; 1124*2459Sahrens uintptr_t childp; 1125*2459Sahrens 1126*2459Sahrens if (wsp->walk_addr == NULL) { 1127*2459Sahrens mdb_warn("must supply address of spa_t\n"); 1128*2459Sahrens return (WALK_ERR); 1129*2459Sahrens } 1130*2459Sahrens 1131*2459Sahrens mw = mdb_zalloc(sizeof (metaslab_walk_data_t), UM_SLEEP | UM_GC); 1132*2459Sahrens 1133*2459Sahrens if (GETMEMB(wsp->walk_addr, struct spa, spa_root_vdev, root_vdevp) || 1134*2459Sahrens GETMEMB(root_vdevp, struct vdev, vdev_children, mw->mw_numvdevs) || 1135*2459Sahrens GETMEMB(root_vdevp, struct vdev, vdev_child, childp)) { 1136*2459Sahrens return (DCMD_ERR); 1137*2459Sahrens } 1138*2459Sahrens 1139*2459Sahrens mw->mw_vdevs = mdb_alloc(mw->mw_numvdevs * sizeof (void *), 1140*2459Sahrens UM_SLEEP | UM_GC); 1141*2459Sahrens if (mdb_vread(mw->mw_vdevs, mw->mw_numvdevs * sizeof (void *), 1142*2459Sahrens childp) == -1) { 1143*2459Sahrens mdb_warn("failed to read root vdev children at %p", childp); 1144*2459Sahrens return (DCMD_ERR); 1145*2459Sahrens } 1146*2459Sahrens 1147*2459Sahrens wsp->walk_data = mw; 1148*2459Sahrens 1149*2459Sahrens return (WALK_NEXT); 1150*2459Sahrens } 1151*2459Sahrens 1152789Sahrens typedef struct mdb_spa { 1153789Sahrens uintptr_t spa_dsl_pool; 1154789Sahrens uintptr_t spa_root_vdev; 1155789Sahrens } mdb_spa_t; 1156789Sahrens 1157789Sahrens typedef struct mdb_dsl_dir { 1158789Sahrens uintptr_t dd_phys; 1159789Sahrens uint64_t dd_used_bytes; 1160789Sahrens int64_t dd_space_towrite[TXG_SIZE]; 1161789Sahrens } mdb_dsl_dir_t; 1162789Sahrens 1163789Sahrens typedef struct mdb_dsl_dir_phys { 1164789Sahrens uint64_t dd_used_bytes; 1165789Sahrens uint64_t dd_compressed_bytes; 1166789Sahrens uint64_t dd_uncompressed_bytes; 1167789Sahrens } mdb_dsl_dir_phys_t; 1168789Sahrens 1169789Sahrens typedef struct mdb_vdev { 1170789Sahrens uintptr_t vdev_parent; 1171789Sahrens uintptr_t vdev_ms; 1172789Sahrens uint64_t vdev_ms_count; 1173789Sahrens vdev_stat_t vdev_stat; 1174789Sahrens } mdb_vdev_t; 1175789Sahrens 1176789Sahrens typedef struct mdb_metaslab { 1177789Sahrens space_map_t ms_allocmap[TXG_SIZE]; 1178789Sahrens space_map_t ms_freemap[TXG_SIZE]; 1179789Sahrens space_map_t ms_map; 11801732Sbonwick space_map_obj_t ms_smo; 1181*2459Sahrens space_map_obj_t ms_smo_syncing; 1182789Sahrens } mdb_metaslab_t; 1183789Sahrens 1184*2459Sahrens typedef struct space_data { 1185*2459Sahrens uint64_t ms_allocmap[TXG_SIZE]; 1186*2459Sahrens uint64_t ms_freemap[TXG_SIZE]; 1187*2459Sahrens uint64_t ms_map; 1188*2459Sahrens uint64_t avail; 1189*2459Sahrens uint64_t nowavail; 1190*2459Sahrens } space_data_t; 1191*2459Sahrens 1192*2459Sahrens /* ARGSUSED */ 1193*2459Sahrens static int 1194*2459Sahrens space_cb(uintptr_t addr, const void *unknown, void *arg) 1195*2459Sahrens { 1196*2459Sahrens space_data_t *sd = arg; 1197*2459Sahrens mdb_metaslab_t ms; 1198*2459Sahrens 1199*2459Sahrens if (GETMEMB(addr, struct metaslab, ms_allocmap, ms.ms_allocmap) || 1200*2459Sahrens GETMEMB(addr, struct metaslab, ms_freemap, ms.ms_freemap) || 1201*2459Sahrens GETMEMB(addr, struct metaslab, ms_map, ms.ms_map) || 1202*2459Sahrens GETMEMB(addr, struct metaslab, ms_smo, ms.ms_smo) || 1203*2459Sahrens GETMEMB(addr, struct metaslab, ms_smo_syncing, ms.ms_smo_syncing)) { 1204*2459Sahrens return (WALK_ERR); 1205*2459Sahrens } 1206*2459Sahrens 1207*2459Sahrens sd->ms_allocmap[0] += ms.ms_allocmap[0].sm_space; 1208*2459Sahrens sd->ms_allocmap[1] += ms.ms_allocmap[1].sm_space; 1209*2459Sahrens sd->ms_allocmap[2] += ms.ms_allocmap[2].sm_space; 1210*2459Sahrens sd->ms_allocmap[3] += ms.ms_allocmap[3].sm_space; 1211*2459Sahrens sd->ms_freemap[0] += ms.ms_freemap[0].sm_space; 1212*2459Sahrens sd->ms_freemap[1] += ms.ms_freemap[1].sm_space; 1213*2459Sahrens sd->ms_freemap[2] += ms.ms_freemap[2].sm_space; 1214*2459Sahrens sd->ms_freemap[3] += ms.ms_freemap[3].sm_space; 1215*2459Sahrens sd->ms_map += ms.ms_map.sm_space; 1216*2459Sahrens sd->avail += ms.ms_map.sm_size - ms.ms_smo.smo_alloc; 1217*2459Sahrens sd->nowavail += ms.ms_map.sm_size - ms.ms_smo_syncing.smo_alloc; 1218*2459Sahrens 1219*2459Sahrens return (WALK_NEXT); 1220*2459Sahrens } 1221*2459Sahrens 1222789Sahrens /* 1223789Sahrens * ::spa_space [-b] 1224789Sahrens * 1225789Sahrens * Given a spa_t, print out it's on-disk space usage and in-core 1226789Sahrens * estimates of future usage. If -b is given, print space in bytes. 1227789Sahrens * Otherwise print in megabytes. 1228789Sahrens */ 1229789Sahrens /* ARGSUSED */ 1230789Sahrens static int 1231789Sahrens spa_space(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 1232789Sahrens { 1233789Sahrens mdb_spa_t spa; 1234789Sahrens uintptr_t dp_root_dir; 1235789Sahrens mdb_dsl_dir_t dd; 1236789Sahrens mdb_dsl_dir_phys_t dsp; 1237789Sahrens uint64_t children; 1238789Sahrens uintptr_t childaddr; 1239*2459Sahrens space_data_t sd; 1240789Sahrens int shift = 20; 1241789Sahrens char *suffix = "M"; 1242789Sahrens int bits = FALSE; 1243789Sahrens 1244789Sahrens if (mdb_getopts(argc, argv, 'b', MDB_OPT_SETBITS, TRUE, &bits, NULL) != 1245789Sahrens argc) 1246789Sahrens return (DCMD_USAGE); 1247789Sahrens if (!(flags & DCMD_ADDRSPEC)) 1248789Sahrens return (DCMD_USAGE); 1249789Sahrens 1250789Sahrens if (bits) { 1251789Sahrens shift = 0; 1252789Sahrens suffix = ""; 1253789Sahrens } 1254789Sahrens 1255789Sahrens if (GETMEMB(addr, struct spa, spa_dsl_pool, spa.spa_dsl_pool) || 1256789Sahrens GETMEMB(addr, struct spa, spa_root_vdev, spa.spa_root_vdev) || 1257789Sahrens GETMEMB(spa.spa_root_vdev, struct vdev, vdev_children, children) || 1258789Sahrens GETMEMB(spa.spa_root_vdev, struct vdev, vdev_child, childaddr) || 1259789Sahrens GETMEMB(spa.spa_dsl_pool, struct dsl_pool, 1260789Sahrens dp_root_dir, dp_root_dir) || 1261789Sahrens GETMEMB(dp_root_dir, struct dsl_dir, dd_phys, dd.dd_phys) || 1262789Sahrens GETMEMB(dp_root_dir, struct dsl_dir, 1263789Sahrens dd_used_bytes, dd.dd_used_bytes) || 1264789Sahrens GETMEMB(dp_root_dir, struct dsl_dir, 1265789Sahrens dd_space_towrite, dd.dd_space_towrite) || 1266789Sahrens GETMEMB(dd.dd_phys, struct dsl_dir_phys, 1267*2459Sahrens dd_used_bytes, dsp.dd_used_bytes) || 1268*2459Sahrens GETMEMB(dd.dd_phys, struct dsl_dir_phys, 1269789Sahrens dd_compressed_bytes, dsp.dd_compressed_bytes) || 1270789Sahrens GETMEMB(dd.dd_phys, struct dsl_dir_phys, 1271789Sahrens dd_uncompressed_bytes, dsp.dd_uncompressed_bytes)) { 1272789Sahrens return (DCMD_ERR); 1273789Sahrens } 1274789Sahrens 1275789Sahrens mdb_printf("dd_space_towrite = %llu%s %llu%s %llu%s %llu%s\n", 1276789Sahrens dd.dd_space_towrite[0] >> shift, suffix, 1277789Sahrens dd.dd_space_towrite[1] >> shift, suffix, 1278789Sahrens dd.dd_space_towrite[2] >> shift, suffix, 1279789Sahrens dd.dd_space_towrite[3] >> shift, suffix); 1280789Sahrens mdb_printf("dd_used_bytes = %llu%s\n", 1281789Sahrens dd.dd_used_bytes >> shift, suffix); 1282789Sahrens 1283789Sahrens mdb_printf("dd_phys.dd_used_bytes = %llu%s\n", 1284789Sahrens dsp.dd_used_bytes >> shift, suffix); 1285*2459Sahrens mdb_printf("dd_phys.dd_compressed_bytes = %llu%s\n", 1286*2459Sahrens dsp.dd_compressed_bytes >> shift, suffix); 1287*2459Sahrens mdb_printf("dd_phys.dd_uncompressed_bytes = %llu%s\n", 1288*2459Sahrens dsp.dd_uncompressed_bytes >> shift, suffix); 1289789Sahrens 1290*2459Sahrens bzero(&sd, sizeof (sd)); 1291*2459Sahrens if (mdb_pwalk("metaslab", space_cb, &sd, addr) != 0) { 1292*2459Sahrens mdb_warn("can't walk metaslabs"); 1293*2459Sahrens return (DCMD_ERR); 1294789Sahrens } 1295789Sahrens 1296789Sahrens mdb_printf("ms_allocmap = %llu%s %llu%s %llu%s %llu%s\n", 1297*2459Sahrens sd.ms_allocmap[0] >> shift, suffix, 1298*2459Sahrens sd.ms_allocmap[1] >> shift, suffix, 1299*2459Sahrens sd.ms_allocmap[2] >> shift, suffix, 1300*2459Sahrens sd.ms_allocmap[3] >> shift, suffix); 1301789Sahrens mdb_printf("ms_freemap = %llu%s %llu%s %llu%s %llu%s\n", 1302*2459Sahrens sd.ms_freemap[0] >> shift, suffix, 1303*2459Sahrens sd.ms_freemap[1] >> shift, suffix, 1304*2459Sahrens sd.ms_freemap[2] >> shift, suffix, 1305*2459Sahrens sd.ms_freemap[3] >> shift, suffix); 1306*2459Sahrens mdb_printf("ms_map = %llu%s\n", sd.ms_map >> shift, suffix); 1307*2459Sahrens mdb_printf("last synced avail = %llu%s\n", sd.avail >> shift, suffix); 1308*2459Sahrens mdb_printf("current syncing avail = %llu%s\n", 1309*2459Sahrens sd.nowavail >> shift, suffix); 1310789Sahrens 1311789Sahrens return (DCMD_OK); 1312789Sahrens } 1313789Sahrens 1314789Sahrens /* 1315789Sahrens * ::spa_verify 1316789Sahrens * 1317789Sahrens * Given a spa_t, verify that that the pool is self-consistent. 1318789Sahrens * Currently, it only checks to make sure that the vdev tree exists. 1319789Sahrens */ 1320789Sahrens /* ARGSUSED */ 1321789Sahrens static int 1322789Sahrens spa_verify(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 1323789Sahrens { 1324789Sahrens spa_t spa; 1325789Sahrens 1326789Sahrens if (argc != 0 || !(flags & DCMD_ADDRSPEC)) 1327789Sahrens return (DCMD_USAGE); 1328789Sahrens 1329789Sahrens if (mdb_vread(&spa, sizeof (spa), addr) == -1) { 1330789Sahrens mdb_warn("failed to read spa_t at %p", addr); 1331789Sahrens return (DCMD_ERR); 1332789Sahrens } 1333789Sahrens 1334789Sahrens if (spa.spa_root_vdev == NULL) { 1335789Sahrens mdb_printf("no vdev tree present\n"); 1336789Sahrens return (DCMD_OK); 1337789Sahrens } 1338789Sahrens 1339789Sahrens return (DCMD_OK); 1340789Sahrens } 1341789Sahrens 1342789Sahrens /* 1343789Sahrens * ::spa_vdevs 1344789Sahrens * 1345789Sahrens * -e Include error stats 1346789Sahrens * 1347789Sahrens * Print out a summarized list of vdevs for the given spa_t. 1348789Sahrens * This is accomplished by invoking "::vdev -re" on the root vdev. 1349789Sahrens */ 1350789Sahrens /* ARGSUSED */ 1351789Sahrens static int 1352789Sahrens spa_vdevs(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 1353789Sahrens { 1354789Sahrens spa_t spa; 1355789Sahrens mdb_arg_t v; 1356789Sahrens int errors = FALSE; 1357789Sahrens 1358789Sahrens if (mdb_getopts(argc, argv, 1359789Sahrens 'e', MDB_OPT_SETBITS, TRUE, &errors, 1360789Sahrens NULL) != argc) 1361789Sahrens return (DCMD_USAGE); 1362789Sahrens 1363789Sahrens if (!(flags & DCMD_ADDRSPEC)) 1364789Sahrens return (DCMD_USAGE); 1365789Sahrens 1366789Sahrens if (mdb_vread(&spa, sizeof (spa), addr) == -1) { 1367789Sahrens mdb_warn("failed to read spa_t at %p", addr); 1368789Sahrens return (DCMD_ERR); 1369789Sahrens } 1370789Sahrens 1371952Seschrock /* 1372952Seschrock * Unitialized spa_t structures can have a NULL root vdev. 1373952Seschrock */ 1374952Seschrock if (spa.spa_root_vdev == NULL) { 1375952Seschrock mdb_printf("no associated vdevs\n"); 1376952Seschrock return (DCMD_OK); 1377952Seschrock } 1378952Seschrock 1379789Sahrens v.a_type = MDB_TYPE_STRING; 1380789Sahrens v.a_un.a_str = errors ? "-re" : "-r"; 1381789Sahrens 1382789Sahrens return (mdb_call_dcmd("vdev", (uintptr_t)spa.spa_root_vdev, 1383789Sahrens flags, 1, &v)); 1384789Sahrens } 1385789Sahrens 1386789Sahrens typedef struct txg_list_walk_data { 1387789Sahrens uintptr_t lw_head[TXG_SIZE]; 1388789Sahrens int lw_txgoff; 1389789Sahrens int lw_maxoff; 1390789Sahrens size_t lw_offset; 1391789Sahrens void *lw_obj; 1392789Sahrens } txg_list_walk_data_t; 1393789Sahrens 1394789Sahrens static int 1395789Sahrens txg_list_walk_init_common(mdb_walk_state_t *wsp, int txg, int maxoff) 1396789Sahrens { 1397789Sahrens txg_list_walk_data_t *lwd; 1398789Sahrens txg_list_t list; 1399789Sahrens int i; 1400789Sahrens 1401789Sahrens lwd = mdb_alloc(sizeof (txg_list_walk_data_t), UM_SLEEP | UM_GC); 1402789Sahrens if (mdb_vread(&list, sizeof (txg_list_t), wsp->walk_addr) == -1) { 1403789Sahrens mdb_warn("failed to read txg_list_t at %#lx", wsp->walk_addr); 1404789Sahrens return (WALK_ERR); 1405789Sahrens } 1406789Sahrens 1407789Sahrens for (i = 0; i < TXG_SIZE; i++) 1408789Sahrens lwd->lw_head[i] = (uintptr_t)list.tl_head[i]; 1409789Sahrens lwd->lw_offset = list.tl_offset; 1410789Sahrens lwd->lw_obj = mdb_alloc(lwd->lw_offset + sizeof (txg_node_t), 1411789Sahrens UM_SLEEP | UM_GC); 1412789Sahrens lwd->lw_txgoff = txg; 1413789Sahrens lwd->lw_maxoff = maxoff; 1414789Sahrens 1415789Sahrens wsp->walk_addr = lwd->lw_head[lwd->lw_txgoff]; 1416789Sahrens wsp->walk_data = lwd; 1417789Sahrens 1418789Sahrens return (WALK_NEXT); 1419789Sahrens } 1420789Sahrens 1421789Sahrens static int 1422789Sahrens txg_list_walk_init(mdb_walk_state_t *wsp) 1423789Sahrens { 1424789Sahrens return (txg_list_walk_init_common(wsp, 0, TXG_SIZE-1)); 1425789Sahrens } 1426789Sahrens 1427789Sahrens static int 1428789Sahrens txg_list0_walk_init(mdb_walk_state_t *wsp) 1429789Sahrens { 1430789Sahrens return (txg_list_walk_init_common(wsp, 0, 0)); 1431789Sahrens } 1432789Sahrens 1433789Sahrens static int 1434789Sahrens txg_list1_walk_init(mdb_walk_state_t *wsp) 1435789Sahrens { 1436789Sahrens return (txg_list_walk_init_common(wsp, 1, 1)); 1437789Sahrens } 1438789Sahrens 1439789Sahrens static int 1440789Sahrens txg_list2_walk_init(mdb_walk_state_t *wsp) 1441789Sahrens { 1442789Sahrens return (txg_list_walk_init_common(wsp, 2, 2)); 1443789Sahrens } 1444789Sahrens 1445789Sahrens static int 1446789Sahrens txg_list3_walk_init(mdb_walk_state_t *wsp) 1447789Sahrens { 1448789Sahrens return (txg_list_walk_init_common(wsp, 3, 3)); 1449789Sahrens } 1450789Sahrens 1451789Sahrens static int 1452789Sahrens txg_list_walk_step(mdb_walk_state_t *wsp) 1453789Sahrens { 1454789Sahrens txg_list_walk_data_t *lwd = wsp->walk_data; 1455789Sahrens uintptr_t addr; 1456789Sahrens txg_node_t *node; 1457789Sahrens int status; 1458789Sahrens 1459789Sahrens while (wsp->walk_addr == NULL && lwd->lw_txgoff < lwd->lw_maxoff) { 1460789Sahrens lwd->lw_txgoff++; 1461789Sahrens wsp->walk_addr = lwd->lw_head[lwd->lw_txgoff]; 1462789Sahrens } 1463789Sahrens 1464789Sahrens if (wsp->walk_addr == NULL) 1465789Sahrens return (WALK_DONE); 1466789Sahrens 1467789Sahrens addr = wsp->walk_addr - lwd->lw_offset; 1468789Sahrens 1469789Sahrens if (mdb_vread(lwd->lw_obj, 1470789Sahrens lwd->lw_offset + sizeof (txg_node_t), addr) == -1) { 1471789Sahrens mdb_warn("failed to read list element at %#lx", addr); 1472789Sahrens return (WALK_ERR); 1473789Sahrens } 1474789Sahrens 1475789Sahrens status = wsp->walk_callback(addr, lwd->lw_obj, wsp->walk_cbdata); 1476789Sahrens node = (txg_node_t *)((uintptr_t)lwd->lw_obj + lwd->lw_offset); 1477789Sahrens wsp->walk_addr = (uintptr_t)node->tn_next[lwd->lw_txgoff]; 1478789Sahrens 1479789Sahrens return (status); 1480789Sahrens } 1481789Sahrens 1482789Sahrens /* 1483789Sahrens * ::walk spa 1484789Sahrens * 1485789Sahrens * Walk all named spa_t structures in the namespace. This is nothing more than 1486789Sahrens * a layered avl walk. 1487789Sahrens */ 1488789Sahrens static int 1489789Sahrens spa_walk_init(mdb_walk_state_t *wsp) 1490789Sahrens { 1491789Sahrens GElf_Sym sym; 1492789Sahrens 1493789Sahrens if (wsp->walk_addr != NULL) { 1494789Sahrens mdb_warn("spa walk only supports global walks\n"); 1495789Sahrens return (WALK_ERR); 1496789Sahrens } 1497789Sahrens 1498789Sahrens if (mdb_lookup_by_obj(ZFS_OBJ_NAME, "spa_namespace_avl", &sym) == -1) { 1499789Sahrens mdb_warn("failed to find symbol 'spa_namespace_avl'"); 1500789Sahrens return (WALK_ERR); 1501789Sahrens } 1502789Sahrens 1503789Sahrens wsp->walk_addr = (uintptr_t)sym.st_value; 1504789Sahrens 1505789Sahrens if (mdb_layered_walk("avl", wsp) == -1) { 1506789Sahrens mdb_warn("failed to walk 'avl'\n"); 1507789Sahrens return (WALK_ERR); 1508789Sahrens } 1509789Sahrens 1510789Sahrens return (WALK_NEXT); 1511789Sahrens } 1512789Sahrens 1513789Sahrens static int 1514789Sahrens spa_walk_step(mdb_walk_state_t *wsp) 1515789Sahrens { 1516789Sahrens spa_t spa; 1517789Sahrens 1518789Sahrens if (mdb_vread(&spa, sizeof (spa), wsp->walk_addr) == -1) { 1519789Sahrens mdb_warn("failed to read spa_t at %p", wsp->walk_addr); 1520789Sahrens return (WALK_ERR); 1521789Sahrens } 1522789Sahrens 1523789Sahrens return (wsp->walk_callback(wsp->walk_addr, &spa, wsp->walk_cbdata)); 1524789Sahrens } 1525789Sahrens 1526789Sahrens /* 1527789Sahrens * MDB module linkage information: 1528789Sahrens * 1529789Sahrens * We declare a list of structures describing our dcmds, and a function 1530789Sahrens * named _mdb_init to return a pointer to our module information. 1531789Sahrens */ 1532789Sahrens 1533789Sahrens static const mdb_dcmd_t dcmds[] = { 1534789Sahrens { "blkptr", ":", "print blkptr_t", blkptr }, 1535789Sahrens { "dbuf", ":", "print dmu_buf_impl_t", dbuf }, 1536789Sahrens { "dbuf_stats", ":", "dbuf stats", dbuf_stats }, 1537789Sahrens { "dbufs", 1538789Sahrens "\t[-O objset_t*] [-n objset_name | \"mos\"] [-o object | \"mdn\"] \n" 1539789Sahrens "\t[-l level] [-b blkid | \"bonus\"]", 1540789Sahrens "find dmu_buf_impl_t's that meet criterion", dbufs }, 1541789Sahrens { "abuf_find", "dva_word[0] dva_word[1]", 1542789Sahrens "find arc_buf_hdr_t of a specified DVA", 1543789Sahrens abuf_find }, 1544789Sahrens { "spa", "?[-cv]", "spa_t summary", spa_print }, 1545789Sahrens { "spa_config", ":", "print spa_t configuration", spa_print_config }, 1546789Sahrens { "spa_verify", ":", "verify spa_t consistency", spa_verify }, 1547789Sahrens { "spa_space", ":[-b]", "print spa_t on-disk space usage", spa_space }, 1548789Sahrens { "spa_vdevs", ":", "given a spa_t, print vdev summary", spa_vdevs }, 1549789Sahrens { "vdev", ":[-qre]", "vdev_t summary", vdev_print }, 1550789Sahrens { "zio_pipeline", ":", "decode a zio pipeline", zio_pipeline }, 1551789Sahrens { NULL } 1552789Sahrens }; 1553789Sahrens 1554789Sahrens static const mdb_walker_t walkers[] = { 1555789Sahrens /* 1556789Sahrens * In userland, there is no generic provider of list_t walkers, so we 1557789Sahrens * need to add it. 1558789Sahrens */ 1559789Sahrens #ifndef _KERNEL 1560789Sahrens { LIST_WALK_NAME, LIST_WALK_DESC, 1561789Sahrens list_walk_init, list_walk_step, list_walk_fini }, 1562789Sahrens #endif 1563789Sahrens { "zms_freelist", "walk ZFS metaslab freelist", 1564*2459Sahrens freelist_walk_init, freelist_walk_step, NULL }, 1565789Sahrens { "txg_list", "given any txg_list_t *, walk all entries in all txgs", 1566*2459Sahrens txg_list_walk_init, txg_list_walk_step, NULL }, 1567789Sahrens { "txg_list0", "given any txg_list_t *, walk all entries in txg 0", 1568*2459Sahrens txg_list0_walk_init, txg_list_walk_step, NULL }, 1569789Sahrens { "txg_list1", "given any txg_list_t *, walk all entries in txg 1", 1570*2459Sahrens txg_list1_walk_init, txg_list_walk_step, NULL }, 1571789Sahrens { "txg_list2", "given any txg_list_t *, walk all entries in txg 2", 1572*2459Sahrens txg_list2_walk_init, txg_list_walk_step, NULL }, 1573789Sahrens { "txg_list3", "given any txg_list_t *, walk all entries in txg 3", 1574*2459Sahrens txg_list3_walk_init, txg_list_walk_step, NULL }, 1575789Sahrens { "spa", "walk all spa_t entries in the namespace", 1576789Sahrens spa_walk_init, spa_walk_step, NULL }, 1577*2459Sahrens { "metaslab", "given a spa_t *, walk all metaslab_t structures", 1578*2459Sahrens metaslab_walk_init, metaslab_walk_step, NULL }, 1579789Sahrens { NULL } 1580789Sahrens }; 1581789Sahrens 1582789Sahrens static const mdb_modinfo_t modinfo = { 1583789Sahrens MDB_API_VERSION, dcmds, walkers 1584789Sahrens }; 1585789Sahrens 1586789Sahrens const mdb_modinfo_t * 1587789Sahrens _mdb_init(void) 1588789Sahrens { 1589789Sahrens return (&modinfo); 1590789Sahrens } 1591