1789Sahrens /* 2789Sahrens * CDDL HEADER START 3789Sahrens * 4789Sahrens * The contents of this file are subject to the terms of the 5*1544Seschrock * Common Development and Distribution License (the "License"). 6*1544Seschrock * 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 /* 22*1544Seschrock * 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 /* ARGSUSED */ 206789Sahrens static void 207789Sahrens freelist_walk_fini(mdb_walk_state_t *wsp) 208789Sahrens { 209789Sahrens } 210789Sahrens 211789Sahrens typedef struct dbuf_walk_data { 212789Sahrens dbuf_hash_table_t ht; 213789Sahrens int64_t bucket; 214789Sahrens uintptr_t dbp; 215789Sahrens dmu_buf_impl_t db; 216789Sahrens } dbuf_walk_data_t; 217789Sahrens 218789Sahrens static int 219789Sahrens dbuf_walk_init(mdb_walk_state_t *wsp) 220789Sahrens { 221789Sahrens dbuf_walk_data_t *dwd; 222789Sahrens 223789Sahrens if (wsp->walk_addr != NULL) { 224789Sahrens mdb_warn("must supply starting address\n"); 225789Sahrens return (WALK_ERR); 226789Sahrens } 227789Sahrens 228789Sahrens dwd = mdb_alloc(sizeof (dbuf_walk_data_t), UM_SLEEP); 229789Sahrens 230789Sahrens if (mdb_readvar(&dwd->ht, "dbuf_hash_table") == -1) { 231789Sahrens mdb_warn("failed to read 'dbuf_hash_table'"); 232789Sahrens mdb_free(dwd, sizeof (dbuf_walk_data_t)); 233789Sahrens return (WALK_ERR); 234789Sahrens } 235789Sahrens dwd->bucket = -1; 236789Sahrens dwd->dbp = 0; 237789Sahrens wsp->walk_data = dwd; 238789Sahrens return (WALK_NEXT); 239789Sahrens } 240789Sahrens 241789Sahrens static int 242789Sahrens dbuf_walk_step(mdb_walk_state_t *wsp) 243789Sahrens { 244789Sahrens int status; 245789Sahrens dbuf_walk_data_t *dwd = wsp->walk_data; 246789Sahrens 247789Sahrens while (dwd->dbp == 0) { 248789Sahrens dwd->bucket++; 249789Sahrens if (dwd->bucket == dwd->ht.hash_table_mask+1) 250789Sahrens return (WALK_DONE); 251789Sahrens 252789Sahrens if (mdb_vread(&dwd->dbp, sizeof (void *), 253789Sahrens (uintptr_t)(dwd->ht.hash_table+dwd->bucket)) == -1) { 254789Sahrens mdb_warn("failed to read hash bucket %u at %p", 255789Sahrens dwd->bucket, dwd->ht.hash_table+dwd->bucket); 256789Sahrens return (WALK_DONE); 257789Sahrens } 258789Sahrens } 259789Sahrens 260789Sahrens wsp->walk_addr = dwd->dbp; 261789Sahrens if (mdb_vread(&dwd->db, sizeof (dmu_buf_impl_t), 262789Sahrens wsp->walk_addr) == -1) { 263789Sahrens mdb_warn("failed to read dbuf at %p", wsp->walk_addr); 264789Sahrens return (WALK_DONE); 265789Sahrens } 266789Sahrens status = wsp->walk_callback(wsp->walk_addr, &dwd->db, wsp->walk_cbdata); 267789Sahrens 268789Sahrens dwd->dbp = (uintptr_t)dwd->db.db_hash_next; 269789Sahrens return (status); 270789Sahrens } 271789Sahrens 272789Sahrens static void 273789Sahrens dbuf_walk_fini(mdb_walk_state_t *wsp) 274789Sahrens { 275789Sahrens dbuf_walk_data_t *dwd = wsp->walk_data; 276789Sahrens mdb_free(dwd, sizeof (dbuf_walk_data_t)); 277789Sahrens } 278789Sahrens 279789Sahrens static int 280789Sahrens dataset_name(uintptr_t addr, char *buf) 281789Sahrens { 282789Sahrens static int gotid; 283789Sahrens static mdb_ctf_id_t dd_id; 284789Sahrens uintptr_t dd_parent; 285789Sahrens char dd_myname[MAXNAMELEN]; 286789Sahrens 287789Sahrens if (!gotid) { 288789Sahrens if (mdb_ctf_lookup_by_name("struct dsl_dir", 289789Sahrens &dd_id) == -1) { 290789Sahrens mdb_warn("couldn't find struct dsl_dir"); 291789Sahrens return (DCMD_ERR); 292789Sahrens } 293789Sahrens gotid = TRUE; 294789Sahrens } 295789Sahrens if (GETMEMBID(addr, &dd_id, dd_parent, dd_parent) || 296789Sahrens GETMEMBID(addr, &dd_id, dd_myname, dd_myname)) { 297789Sahrens return (DCMD_ERR); 298789Sahrens } 299789Sahrens 300789Sahrens if (dd_parent) { 301789Sahrens if (dataset_name(dd_parent, buf)) 302789Sahrens return (DCMD_ERR); 303789Sahrens strcat(buf, "/"); 304789Sahrens } 305789Sahrens 306789Sahrens if (dd_myname[0]) 307789Sahrens strcat(buf, dd_myname); 308789Sahrens else 309789Sahrens strcat(buf, "???"); 310789Sahrens 311789Sahrens return (0); 312789Sahrens } 313789Sahrens 314789Sahrens static int 315789Sahrens objset_name(uintptr_t addr, char *buf) 316789Sahrens { 317789Sahrens static int gotid; 318789Sahrens static mdb_ctf_id_t osi_id, ds_id; 319789Sahrens uintptr_t os_dsl_dataset; 320789Sahrens char ds_snapname[MAXNAMELEN]; 321789Sahrens uintptr_t ds_dir; 322789Sahrens 323789Sahrens buf[0] = '\0'; 324789Sahrens 325789Sahrens if (!gotid) { 326789Sahrens if (mdb_ctf_lookup_by_name("struct objset_impl", 327789Sahrens &osi_id) == -1) { 328789Sahrens mdb_warn("couldn't find struct objset_impl"); 329789Sahrens return (DCMD_ERR); 330789Sahrens } 331789Sahrens if (mdb_ctf_lookup_by_name("struct dsl_dataset", 332789Sahrens &ds_id) == -1) { 333789Sahrens mdb_warn("couldn't find struct dsl_dataset"); 334789Sahrens return (DCMD_ERR); 335789Sahrens } 336789Sahrens 337789Sahrens gotid = TRUE; 338789Sahrens } 339789Sahrens 340789Sahrens if (GETMEMBID(addr, &osi_id, os_dsl_dataset, os_dsl_dataset)) 341789Sahrens return (DCMD_ERR); 342789Sahrens 343789Sahrens if (os_dsl_dataset == 0) { 344789Sahrens strcat(buf, "mos"); 345789Sahrens return (0); 346789Sahrens } 347789Sahrens 348789Sahrens if (GETMEMBID(os_dsl_dataset, &ds_id, ds_snapname, ds_snapname) || 349789Sahrens GETMEMBID(os_dsl_dataset, &ds_id, ds_dir, ds_dir)) { 350789Sahrens return (DCMD_ERR); 351789Sahrens } 352789Sahrens 353789Sahrens if (ds_dir && dataset_name(ds_dir, buf)) 354789Sahrens return (DCMD_ERR); 355789Sahrens 356789Sahrens if (ds_snapname[0]) { 357789Sahrens strcat(buf, "@"); 358789Sahrens strcat(buf, ds_snapname); 359789Sahrens } 360789Sahrens return (0); 361789Sahrens } 362789Sahrens 363789Sahrens static void 364789Sahrens enum_lookup(char *out, size_t size, mdb_ctf_id_t id, int val, 365789Sahrens const char *prefix) 366789Sahrens { 367789Sahrens const char *cp; 368789Sahrens size_t len = strlen(prefix); 369789Sahrens 370789Sahrens if ((cp = mdb_ctf_enum_name(id, val)) != NULL) { 371789Sahrens if (strncmp(cp, prefix, len) == 0) 372789Sahrens cp += len; 373789Sahrens (void) strncpy(out, cp, size); 374789Sahrens } else { 375789Sahrens mdb_snprintf(out, size, "? (%d)", val); 376789Sahrens } 377789Sahrens } 378789Sahrens 379789Sahrens /* ARGSUSED */ 380789Sahrens static int 381789Sahrens zio_pipeline(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 382789Sahrens { 383789Sahrens mdb_ctf_id_t pipe_enum; 384789Sahrens int i; 385789Sahrens char stage[1024]; 386789Sahrens 387789Sahrens if (mdb_ctf_lookup_by_name("enum zio_stage", &pipe_enum) == -1) { 388789Sahrens mdb_warn("Could not find enum zio_stage"); 389789Sahrens return (DCMD_ERR); 390789Sahrens } 391789Sahrens 392789Sahrens for (i = 0; i < 32; i++) { 393789Sahrens if (addr & (1U << i)) { 394789Sahrens enum_lookup(stage, sizeof (stage), pipe_enum, i, 395789Sahrens "ZIO_STAGE_"); 396789Sahrens mdb_printf(" %s\n", stage); 397789Sahrens } 398789Sahrens } 399789Sahrens 400789Sahrens return (DCMD_OK); 401789Sahrens } 402789Sahrens 403789Sahrens /* ARGSUSED */ 404789Sahrens static int 405789Sahrens blkptr(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 406789Sahrens { 407789Sahrens blkptr_t bp; 408789Sahrens dva_t *dva; 409789Sahrens dmu_object_type_info_t *doti; 410789Sahrens zio_compress_info_t *zct; 411789Sahrens zio_checksum_info_t *zci; 412789Sahrens int i; 413789Sahrens char buf[MAXPATHLEN]; 414789Sahrens 415789Sahrens if (mdb_vread(&bp, sizeof (blkptr_t), addr) == -1) { 416789Sahrens mdb_warn("failed to read blkptr_t"); 417789Sahrens return (DCMD_ERR); 418789Sahrens } 419789Sahrens 420789Sahrens if (read_symbol("dmu_ot", (void **)&doti) != DCMD_OK) 421789Sahrens return (DCMD_ERR); 422789Sahrens for (i = 0; i < DMU_OT_NUMTYPES; i++) { 423789Sahrens mdb_readstr(buf, sizeof (buf), (uintptr_t)doti[i].ot_name); 424789Sahrens doti[i].ot_name = local_strdup(buf); 425789Sahrens } 426789Sahrens 427789Sahrens if (read_symbol("zio_checksum_table", (void **)&zci) != DCMD_OK) 428789Sahrens return (DCMD_ERR); 429789Sahrens for (i = 0; i < ZIO_CHECKSUM_FUNCTIONS; i++) { 430789Sahrens mdb_readstr(buf, sizeof (buf), (uintptr_t)zci[i].ci_name); 431789Sahrens zci[i].ci_name = local_strdup(buf); 432789Sahrens } 433789Sahrens 434789Sahrens if (read_symbol("zio_compress_table", (void **)&zct) != DCMD_OK) 435789Sahrens return (DCMD_ERR); 436789Sahrens for (i = 0; i < ZIO_COMPRESS_FUNCTIONS; i++) { 437789Sahrens mdb_readstr(buf, sizeof (buf), (uintptr_t)zct[i].ci_name); 438789Sahrens zct[i].ci_name = local_strdup(buf); 439789Sahrens } 440789Sahrens 441789Sahrens for (i = 0; i < SPA_DVAS_PER_BP; i++) { 442789Sahrens dva = &bp.blk_dva[i]; 443789Sahrens mdb_printf("DVA[%d]: vdev_id %lld / %llx\n", i, 444789Sahrens DVA_GET_VDEV(dva), DVA_GET_OFFSET(dva)); 445789Sahrens mdb_printf("DVA[%d]: GRID: %04x\t" 446789Sahrens "ASIZE: %llx\n", i, DVA_GET_GRID(dva), DVA_GET_ASIZE(dva)); 447789Sahrens } 448789Sahrens mdb_printf("LSIZE: %-16llx\t\tPSIZE: %llx\n", 449789Sahrens BP_GET_LSIZE(&bp), BP_GET_PSIZE(&bp)); 450789Sahrens mdb_printf("ENDIAN: %6s GANG: %-5s\tTYPE: %s\n", 451789Sahrens BP_GET_BYTEORDER(&bp) ? "LITTLE" : "BIG", 452789Sahrens DVA_GET_GANG(dva) ? "TRUE" : "FALSE", 453789Sahrens doti[BP_GET_TYPE(&bp)].ot_name); 454789Sahrens mdb_printf("BIRTH: %-16llx LEVEL: %-2d\tFILL: %llx\n", 455789Sahrens bp.blk_birth, BP_GET_LEVEL(&bp), bp.blk_fill); 456789Sahrens mdb_printf("CKFUNC: %-16s\t\tCOMP: %s\n", 457789Sahrens zci[BP_GET_CHECKSUM(&bp)].ci_name, 458789Sahrens zct[BP_GET_COMPRESS(&bp)].ci_name); 459789Sahrens mdb_printf("CKSUM: %llx:%llx:%llx:%llx\n", 460789Sahrens bp.blk_cksum.zc_word[0], 461789Sahrens bp.blk_cksum.zc_word[1], 462789Sahrens bp.blk_cksum.zc_word[2], 463789Sahrens bp.blk_cksum.zc_word[3]); 464789Sahrens 465789Sahrens return (DCMD_OK); 466789Sahrens } 467789Sahrens 468789Sahrens /* ARGSUSED */ 469789Sahrens static int 470789Sahrens dbuf(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 471789Sahrens { 472789Sahrens mdb_ctf_id_t id; 473789Sahrens dmu_buf_t db; 474789Sahrens uintptr_t objset; 475789Sahrens uint8_t level; 476789Sahrens uint64_t blkid; 477789Sahrens uint64_t holds; 478789Sahrens char objectname[32]; 479789Sahrens char blkidname[32]; 480789Sahrens char path[MAXNAMELEN]; 481789Sahrens 482789Sahrens if (DCMD_HDRSPEC(flags)) { 483789Sahrens mdb_printf(" addr object lvl blkid holds os\n"); 484789Sahrens } 485789Sahrens 486789Sahrens if (mdb_ctf_lookup_by_name("struct dmu_buf_impl", &id) == -1) { 487789Sahrens mdb_warn("couldn't find struct dmu_buf_impl_t"); 488789Sahrens return (DCMD_ERR); 489789Sahrens } 490789Sahrens 491789Sahrens if (GETMEMBID(addr, &id, db_objset, objset) || 492789Sahrens GETMEMBID(addr, &id, db, db) || 493789Sahrens GETMEMBID(addr, &id, db_level, level) || 494789Sahrens GETMEMBID(addr, &id, db_blkid, blkid)) { 495789Sahrens return (WALK_ERR); 496789Sahrens } 497789Sahrens 498789Sahrens if (getrefcount(addr, &id, "db_holds", &holds)) { 499789Sahrens return (WALK_ERR); 500789Sahrens } 501789Sahrens 502789Sahrens if (db.db_object == DMU_META_DNODE_OBJECT) 503789Sahrens (void) strcpy(objectname, "mdn"); 504789Sahrens else 505789Sahrens (void) mdb_snprintf(objectname, sizeof (objectname), "%llx", 506789Sahrens (u_longlong_t)db.db_object); 507789Sahrens 508789Sahrens if (blkid == DB_BONUS_BLKID) 509789Sahrens (void) strcpy(blkidname, "bonus"); 510789Sahrens else 511789Sahrens (void) mdb_snprintf(blkidname, sizeof (blkidname), "%llx", 512789Sahrens (u_longlong_t)blkid); 513789Sahrens 514789Sahrens if (objset_name(objset, path)) { 515789Sahrens return (WALK_ERR); 516789Sahrens } 517789Sahrens 518789Sahrens mdb_printf("%p %8s %1u %9s %2llu %s\n", 519789Sahrens addr, objectname, level, blkidname, holds, path); 520789Sahrens 521789Sahrens return (DCMD_OK); 522789Sahrens } 523789Sahrens 524789Sahrens /* ARGSUSED */ 525789Sahrens static int 526789Sahrens dbuf_stats(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 527789Sahrens { 528789Sahrens #define HISTOSZ 32 529789Sahrens uintptr_t dbp; 530789Sahrens dmu_buf_impl_t db; 531789Sahrens dbuf_hash_table_t ht; 532789Sahrens uint64_t bucket, ndbufs; 533789Sahrens uint64_t histo[HISTOSZ]; 534789Sahrens uint64_t histo2[HISTOSZ]; 535789Sahrens int i, maxidx; 536789Sahrens 537789Sahrens if (mdb_readvar(&ht, "dbuf_hash_table") == -1) { 538789Sahrens mdb_warn("failed to read 'dbuf_hash_table'"); 539789Sahrens return (DCMD_ERR); 540789Sahrens } 541789Sahrens 542789Sahrens for (i = 0; i < HISTOSZ; i++) { 543789Sahrens histo[i] = 0; 544789Sahrens histo2[i] = 0; 545789Sahrens } 546789Sahrens 547789Sahrens ndbufs = 0; 548789Sahrens for (bucket = 0; bucket < ht.hash_table_mask+1; bucket++) { 549789Sahrens int len; 550789Sahrens 551789Sahrens if (mdb_vread(&dbp, sizeof (void *), 552789Sahrens (uintptr_t)(ht.hash_table+bucket)) == -1) { 553789Sahrens mdb_warn("failed to read hash bucket %u at %p", 554789Sahrens bucket, ht.hash_table+bucket); 555789Sahrens return (DCMD_ERR); 556789Sahrens } 557789Sahrens 558789Sahrens len = 0; 559789Sahrens while (dbp != 0) { 560789Sahrens if (mdb_vread(&db, sizeof (dmu_buf_impl_t), 561789Sahrens dbp) == -1) { 562789Sahrens mdb_warn("failed to read dbuf at %p", dbp); 563789Sahrens return (DCMD_ERR); 564789Sahrens } 565789Sahrens dbp = (uintptr_t)db.db_hash_next; 566789Sahrens for (i = MIN(len, HISTOSZ - 1); i >= 0; i--) 567789Sahrens histo2[i]++; 568789Sahrens len++; 569789Sahrens ndbufs++; 570789Sahrens } 571789Sahrens 572789Sahrens if (len >= HISTOSZ) 573789Sahrens len = HISTOSZ-1; 574789Sahrens histo[len]++; 575789Sahrens } 576789Sahrens 577789Sahrens mdb_printf("hash table has %llu buckets, %llu dbufs " 578789Sahrens "(avg %llu buckets/dbuf)\n", 579789Sahrens ht.hash_table_mask+1, ndbufs, 580789Sahrens (ht.hash_table_mask+1)/ndbufs); 581789Sahrens 582789Sahrens mdb_printf("\n"); 583789Sahrens maxidx = 0; 584789Sahrens for (i = 0; i < HISTOSZ; i++) 585789Sahrens if (histo[i] > 0) 586789Sahrens maxidx = i; 587789Sahrens mdb_printf("hash chain length number of buckets\n"); 588789Sahrens for (i = 0; i <= maxidx; i++) 589789Sahrens mdb_printf("%u %llu\n", i, histo[i]); 590789Sahrens 591789Sahrens mdb_printf("\n"); 592789Sahrens maxidx = 0; 593789Sahrens for (i = 0; i < HISTOSZ; i++) 594789Sahrens if (histo2[i] > 0) 595789Sahrens maxidx = i; 596789Sahrens mdb_printf("hash chain depth number of dbufs\n"); 597789Sahrens for (i = 0; i <= maxidx; i++) 598789Sahrens mdb_printf("%u or more %llu %llu%%\n", 599789Sahrens i, histo2[i], histo2[i]*100/ndbufs); 600789Sahrens 601789Sahrens 602789Sahrens return (DCMD_OK); 603789Sahrens } 604789Sahrens 605789Sahrens typedef struct dbufs_data { 606789Sahrens mdb_ctf_id_t id; 607789Sahrens uint64_t objset; 608789Sahrens uint64_t object; 609789Sahrens uint64_t level; 610789Sahrens uint64_t blkid; 611789Sahrens char *osname; 612789Sahrens } dbufs_data_t; 613789Sahrens 614789Sahrens #define DBUFS_UNSET (0xbaddcafedeadbeefULL) 615789Sahrens 616789Sahrens /* ARGSUSED */ 617789Sahrens static int 618789Sahrens dbufs_cb(uintptr_t addr, const void *unknown, void *arg) 619789Sahrens { 620789Sahrens dbufs_data_t *data = arg; 621789Sahrens uintptr_t objset; 622789Sahrens dmu_buf_t db; 623789Sahrens uint8_t level; 624789Sahrens uint64_t blkid; 625789Sahrens char osname[MAXNAMELEN]; 626789Sahrens 627789Sahrens if (GETMEMBID(addr, &data->id, db_objset, objset) || 628789Sahrens GETMEMBID(addr, &data->id, db, db) || 629789Sahrens GETMEMBID(addr, &data->id, db_level, level) || 630789Sahrens GETMEMBID(addr, &data->id, db_blkid, blkid)) { 631789Sahrens return (WALK_ERR); 632789Sahrens } 633789Sahrens 634789Sahrens if ((data->objset == DBUFS_UNSET || data->objset == objset) && 635789Sahrens (data->osname == NULL || (objset_name(objset, osname) == 0 && 636789Sahrens strcmp(data->osname, osname) == 0)) && 637789Sahrens (data->object == DBUFS_UNSET || data->object == db.db_object) && 638789Sahrens (data->level == DBUFS_UNSET || data->level == level) && 639789Sahrens (data->blkid == DBUFS_UNSET || data->blkid == blkid)) { 640789Sahrens mdb_printf("%#lr\n", addr); 641789Sahrens } 642789Sahrens return (WALK_NEXT); 643789Sahrens } 644789Sahrens 645789Sahrens /* ARGSUSED */ 646789Sahrens static int 647789Sahrens dbufs(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 648789Sahrens { 649789Sahrens dbufs_data_t data; 650789Sahrens char *object = NULL; 651789Sahrens char *blkid = NULL; 652789Sahrens 653789Sahrens data.objset = data.object = data.level = data.blkid = DBUFS_UNSET; 654789Sahrens data.osname = NULL; 655789Sahrens 656789Sahrens if (mdb_getopts(argc, argv, 657789Sahrens 'O', MDB_OPT_UINT64, &data.objset, 658789Sahrens 'n', MDB_OPT_STR, &data.osname, 659789Sahrens 'o', MDB_OPT_STR, &object, 660789Sahrens 'l', MDB_OPT_UINT64, &data.level, 661789Sahrens 'b', MDB_OPT_STR, &blkid) != argc) { 662789Sahrens return (DCMD_USAGE); 663789Sahrens } 664789Sahrens 665789Sahrens if (object) { 666789Sahrens if (strcmp(object, "mdn") == 0) { 667789Sahrens data.object = DMU_META_DNODE_OBJECT; 668789Sahrens } else { 669789Sahrens data.object = mdb_strtoull(object); 670789Sahrens } 671789Sahrens } 672789Sahrens 673789Sahrens if (blkid) { 674789Sahrens if (strcmp(blkid, "bonus") == 0) { 675789Sahrens data.blkid = DB_BONUS_BLKID; 676789Sahrens } else { 677789Sahrens data.blkid = mdb_strtoull(blkid); 678789Sahrens } 679789Sahrens } 680789Sahrens 681789Sahrens if (mdb_ctf_lookup_by_name("struct dmu_buf_impl", &data.id) == -1) { 682789Sahrens mdb_warn("couldn't find struct dmu_buf_impl_t"); 683789Sahrens return (DCMD_ERR); 684789Sahrens } 685789Sahrens 686789Sahrens if (mdb_pwalk("dbufs", dbufs_cb, &data, 0) != 0) { 687789Sahrens mdb_warn("can't walk dbufs"); 688789Sahrens return (DCMD_ERR); 689789Sahrens } 690789Sahrens 691789Sahrens return (DCMD_OK); 692789Sahrens } 693789Sahrens 694789Sahrens typedef struct abuf_find_data { 695789Sahrens dva_t dva; 696789Sahrens mdb_ctf_id_t id; 697789Sahrens } abuf_find_data_t; 698789Sahrens 699789Sahrens /* ARGSUSED */ 700789Sahrens static int 701789Sahrens abuf_find_cb(uintptr_t addr, const void *unknown, void *arg) 702789Sahrens { 703789Sahrens abuf_find_data_t *data = arg; 704789Sahrens dva_t dva; 705789Sahrens 706789Sahrens if (GETMEMBID(addr, &data->id, b_dva, dva)) { 707789Sahrens return (WALK_ERR); 708789Sahrens } 709789Sahrens 710789Sahrens if (dva.dva_word[0] == data->dva.dva_word[0] && 711789Sahrens dva.dva_word[1] == data->dva.dva_word[1]) { 712789Sahrens mdb_printf("%#lr\n", addr); 713789Sahrens } 714789Sahrens return (WALK_NEXT); 715789Sahrens } 716789Sahrens 717789Sahrens /* ARGSUSED */ 718789Sahrens static int 719789Sahrens abuf_find(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 720789Sahrens { 721789Sahrens abuf_find_data_t data; 722789Sahrens GElf_Sym sym; 723789Sahrens int i; 724789Sahrens const char *syms[] = { 725789Sahrens "ARC_mru_top", 726789Sahrens "ARC_mru_bot", 727789Sahrens "ARC_mfu_top", 728789Sahrens "ARC_mfu_bot", 729789Sahrens }; 730789Sahrens 731789Sahrens if (argc != 2) 732789Sahrens return (DCMD_USAGE); 733789Sahrens 734789Sahrens for (i = 0; i < 2; i ++) { 735789Sahrens switch (argv[i].a_type) { 736789Sahrens case MDB_TYPE_STRING: 737789Sahrens data.dva.dva_word[i] = mdb_strtoull(argv[i].a_un.a_str); 738789Sahrens break; 739789Sahrens case MDB_TYPE_IMMEDIATE: 740789Sahrens data.dva.dva_word[i] = argv[i].a_un.a_val; 741789Sahrens break; 742789Sahrens default: 743789Sahrens return (DCMD_USAGE); 744789Sahrens } 745789Sahrens } 746789Sahrens 747789Sahrens if (mdb_ctf_lookup_by_name("struct arc_buf_hdr", &data.id) == -1) { 748789Sahrens mdb_warn("couldn't find struct arc_buf_hdr"); 749789Sahrens return (DCMD_ERR); 750789Sahrens } 751789Sahrens 752789Sahrens for (i = 0; i < sizeof (syms) / sizeof (syms[0]); i++) { 753789Sahrens if (mdb_lookup_by_name(syms[i], &sym)) { 754789Sahrens mdb_warn("can't find symbol %s", syms[i]); 755789Sahrens return (DCMD_ERR); 756789Sahrens } 757789Sahrens 758789Sahrens if (mdb_pwalk("list", abuf_find_cb, &data, sym.st_value) != 0) { 759789Sahrens mdb_warn("can't walk %s", syms[i]); 760789Sahrens return (DCMD_ERR); 761789Sahrens } 762789Sahrens } 763789Sahrens 764789Sahrens return (DCMD_OK); 765789Sahrens } 766789Sahrens 767789Sahrens void 768789Sahrens abuf_help(void) 769789Sahrens { 770789Sahrens mdb_printf("::abuf_find dva_word[0] dva_word[1]\n"); 771789Sahrens } 772789Sahrens 773789Sahrens /* 774789Sahrens * ::spa 775789Sahrens * 776789Sahrens * -c Print configuration information as well 777789Sahrens * -v Print vdev state 778789Sahrens * -e Print vdev error stats 779789Sahrens * 780789Sahrens * Print a summarized spa_t. When given no arguments, prints out a table of all 781789Sahrens * active pools on the system. 782789Sahrens */ 783789Sahrens /* ARGSUSED */ 784789Sahrens static int 785789Sahrens spa_print(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 786789Sahrens { 787789Sahrens spa_t spa; 788789Sahrens char poolname[MAXNAMELEN]; 789789Sahrens const char *statetab[] = { "ACTIVE", "EXPORTED", "DESTROYED", 790789Sahrens "UNINIT", "UNAVAIL" }; 791789Sahrens const char *state; 792789Sahrens int config = FALSE; 793789Sahrens int vdevs = FALSE; 794789Sahrens int errors = FALSE; 795789Sahrens 796789Sahrens if (mdb_getopts(argc, argv, 797789Sahrens 'c', MDB_OPT_SETBITS, TRUE, &config, 798789Sahrens 'v', MDB_OPT_SETBITS, TRUE, &vdevs, 799789Sahrens 'e', MDB_OPT_SETBITS, TRUE, &errors, 800789Sahrens NULL) != argc) 801789Sahrens return (DCMD_USAGE); 802789Sahrens 803789Sahrens if (!(flags & DCMD_ADDRSPEC)) { 804789Sahrens if (mdb_walk_dcmd("spa", "spa", argc, argv) == -1) { 805789Sahrens mdb_warn("can't walk spa"); 806789Sahrens return (DCMD_ERR); 807789Sahrens } 808789Sahrens 809789Sahrens return (DCMD_OK); 810789Sahrens } 811789Sahrens 812789Sahrens if (flags & DCMD_PIPE_OUT) { 813789Sahrens mdb_printf("%#lr\n", addr); 814789Sahrens return (DCMD_OK); 815789Sahrens } 816789Sahrens 817789Sahrens if (DCMD_HDRSPEC(flags)) 818789Sahrens mdb_printf("%<u>%-?s %9s %-*s%</u>\n", "ADDR", "STATE", 819789Sahrens sizeof (uintptr_t) == 4 ? 60 : 52, "NAME"); 820789Sahrens 821789Sahrens if (mdb_vread(&spa, sizeof (spa), addr) == -1) { 822789Sahrens mdb_warn("failed to read spa_t at %p", addr); 823789Sahrens return (DCMD_ERR); 824789Sahrens } 825789Sahrens 826789Sahrens if (mdb_readstr(poolname, sizeof (poolname), (uintptr_t)spa.spa_name) 827789Sahrens == -1) { 828789Sahrens mdb_warn("failed to read pool name at %p", spa.spa_name); 829789Sahrens return (DCMD_ERR); 830789Sahrens } 831789Sahrens 832789Sahrens if (spa.spa_state < 0 || spa.spa_state > POOL_STATE_UNAVAIL) 833*1544Seschrock state = "UNKNOWN"; 834789Sahrens else 835789Sahrens state = statetab[spa.spa_state]; 836789Sahrens 837789Sahrens mdb_printf("%0?p %9s %s\n", addr, state, poolname); 838789Sahrens 839789Sahrens if (config) { 840789Sahrens mdb_printf("\n"); 841789Sahrens mdb_inc_indent(4); 842789Sahrens if (mdb_call_dcmd("spa_config", addr, flags, 0, 843789Sahrens NULL) != DCMD_OK) 844789Sahrens return (DCMD_ERR); 845789Sahrens mdb_dec_indent(4); 846789Sahrens } 847789Sahrens 848789Sahrens if (vdevs || errors) { 849789Sahrens mdb_arg_t v; 850789Sahrens 851789Sahrens v.a_type = MDB_TYPE_STRING; 852789Sahrens v.a_un.a_str = "-e"; 853789Sahrens 854789Sahrens mdb_printf("\n"); 855789Sahrens mdb_inc_indent(4); 856789Sahrens if (mdb_call_dcmd("spa_vdevs", addr, flags, errors ? 1 : 0, 857789Sahrens &v) != DCMD_OK) 858789Sahrens return (DCMD_ERR); 859789Sahrens mdb_dec_indent(4); 860789Sahrens } 861789Sahrens 862789Sahrens return (DCMD_OK); 863789Sahrens } 864789Sahrens 865789Sahrens /* 866789Sahrens * ::spa_config 867789Sahrens * 868789Sahrens * Given a spa_t, print the configuration information stored in spa_config. 869789Sahrens * Since it's just an nvlist, format it as an indented list of name=value pairs. 870789Sahrens * We simply read the value of spa_config and pass off to ::nvlist. 871789Sahrens */ 872789Sahrens /* ARGSUSED */ 873789Sahrens static int 874789Sahrens spa_print_config(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 875789Sahrens { 876789Sahrens spa_t spa; 877789Sahrens 878789Sahrens if (argc != 0 || !(flags & DCMD_ADDRSPEC)) 879789Sahrens return (DCMD_USAGE); 880789Sahrens 881789Sahrens if (mdb_vread(&spa, sizeof (spa), addr) == -1) { 882789Sahrens mdb_warn("failed to read spa_t at %p", addr); 883789Sahrens return (DCMD_ERR); 884789Sahrens } 885789Sahrens 886789Sahrens if (spa.spa_config == NULL) { 887789Sahrens mdb_printf("(none)\n"); 888789Sahrens return (DCMD_OK); 889789Sahrens } 890789Sahrens 891789Sahrens return (mdb_call_dcmd("nvlist", (uintptr_t)spa.spa_config, flags, 892789Sahrens 0, NULL)); 893789Sahrens } 894789Sahrens 895789Sahrens void 896789Sahrens vdev_help(void) 897789Sahrens { 898789Sahrens mdb_printf("[vdev_t*]::vdev [-qr]\n" 899789Sahrens "\t-> -q display vdev_queue parameters\n" 900789Sahrens "\t-> -r recursive (visit all children)\n"); 901789Sahrens } 902789Sahrens 903789Sahrens /* 904789Sahrens * ::vdev 905789Sahrens * 906789Sahrens * Print out a summarized vdev_t, in the following form: 907789Sahrens * 908789Sahrens * ADDR STATE AUX DESC 909789Sahrens * fffffffbcde23df0 HEALTHY - /dev/dsk/c0t0d0 910789Sahrens * 911789Sahrens * or with "-q" to print out a vdev_t's vdev_queue parameters: 912789Sahrens * 913789Sahrens * vdev_t: c26ae4c0 914789Sahrens * c26ae73c min pending 0x2 915789Sahrens * c26ae744 max pending 0x23 916789Sahrens * c26ae74c agg limit 0x20000 917789Sahrens * c26ae754 time shift 0x4 918789Sahrens * c26ae75c ramp rate 0x2 919789Sahrens * 920789Sahrens * If '-r' is specified, recursively visit all children. 921789Sahrens * 922789Sahrens * With '-e', the statistics associated with the vdev are printed as well. 923789Sahrens */ 924789Sahrens static int 925789Sahrens do_print_vdev(uintptr_t addr, int flags, int depth, int queue, int stats, 926789Sahrens int recursive) 927789Sahrens { 928789Sahrens vdev_t vdev; 929789Sahrens char desc[MAXNAMELEN]; 930789Sahrens int c, children; 931789Sahrens uintptr_t *child; 932789Sahrens const char *state, *aux; 933789Sahrens 934789Sahrens if (mdb_vread(&vdev, sizeof (vdev), (uintptr_t)addr) == -1) { 935789Sahrens mdb_warn("failed to read vdev_t at %p\n", (uintptr_t)addr); 936789Sahrens return (DCMD_ERR); 937789Sahrens } 938789Sahrens 939789Sahrens if (flags & DCMD_PIPE_OUT) { 940789Sahrens mdb_printf("%#lr", addr); 941789Sahrens } else { 942789Sahrens if (vdev.vdev_path != NULL) { 943789Sahrens if (mdb_readstr(desc, sizeof (desc), 944789Sahrens (uintptr_t)vdev.vdev_path) == -1) { 945789Sahrens mdb_warn("failed to read vdev_path at %p\n", 946789Sahrens vdev.vdev_path); 947789Sahrens return (DCMD_ERR); 948789Sahrens } 949789Sahrens } else if (vdev.vdev_ops != NULL) { 950789Sahrens vdev_ops_t ops; 951789Sahrens if (mdb_vread(&ops, sizeof (ops), 952789Sahrens (uintptr_t)vdev.vdev_ops) == -1) { 953789Sahrens mdb_warn("failed to read vdev_ops at %p\n", 954789Sahrens vdev.vdev_ops); 955789Sahrens return (DCMD_ERR); 956789Sahrens } 957789Sahrens (void) strcpy(desc, ops.vdev_op_type); 958789Sahrens } else { 959789Sahrens (void) strcpy(desc, "<unknown>"); 960789Sahrens } 961789Sahrens 962789Sahrens if (depth == 0 && DCMD_HDRSPEC(flags)) 963789Sahrens mdb_printf("%<u>%-?s %-9s %-12s %-*s%</u>\n", 964789Sahrens "ADDR", "STATE", "AUX", 965789Sahrens sizeof (uintptr_t) == 4 ? 43 : 35, 966789Sahrens "DESCRIPTION"); 967789Sahrens 968789Sahrens mdb_printf("%0?p ", addr); 969789Sahrens 970789Sahrens switch (vdev.vdev_state) { 971789Sahrens case VDEV_STATE_CLOSED: 972789Sahrens state = "CLOSED"; 973789Sahrens break; 974789Sahrens case VDEV_STATE_OFFLINE: 975789Sahrens state = "OFFLINE"; 976789Sahrens break; 977789Sahrens case VDEV_STATE_CANT_OPEN: 978789Sahrens state = "CANT_OPEN"; 979789Sahrens break; 980789Sahrens case VDEV_STATE_DEGRADED: 981789Sahrens state = "DEGRADED"; 982789Sahrens break; 983789Sahrens case VDEV_STATE_HEALTHY: 984789Sahrens state = "HEALTHY"; 985789Sahrens break; 986789Sahrens default: 987789Sahrens state = "UNKNOWN"; 988789Sahrens break; 989789Sahrens } 990789Sahrens 991789Sahrens switch (vdev.vdev_stat.vs_aux) { 992789Sahrens case VDEV_AUX_NONE: 993789Sahrens aux = "-"; 994789Sahrens break; 995789Sahrens case VDEV_AUX_OPEN_FAILED: 996789Sahrens aux = "OPEN_FAILED"; 997789Sahrens break; 998789Sahrens case VDEV_AUX_CORRUPT_DATA: 999789Sahrens aux = "CORRUPT_DATA"; 1000789Sahrens break; 1001789Sahrens case VDEV_AUX_NO_REPLICAS: 1002789Sahrens aux = "NO_REPLICAS"; 1003789Sahrens break; 1004789Sahrens case VDEV_AUX_BAD_GUID_SUM: 1005789Sahrens aux = "BAD_GUID_SUM"; 1006789Sahrens break; 1007789Sahrens case VDEV_AUX_TOO_SMALL: 1008789Sahrens aux = "TOO_SMALL"; 1009789Sahrens break; 1010789Sahrens case VDEV_AUX_BAD_LABEL: 1011789Sahrens aux = "BAD_LABEL"; 1012789Sahrens break; 1013789Sahrens default: 1014789Sahrens aux = "UNKNOWN"; 1015789Sahrens break; 1016789Sahrens } 1017789Sahrens 1018789Sahrens mdb_printf("%-9s %-12s %*s%s\n", state, aux, depth, "", desc); 1019789Sahrens 1020789Sahrens if (queue) { 1021789Sahrens mdb_inc_indent(4); 1022789Sahrens mdb_printf("\n"); 1023789Sahrens mdb_printf("%p min pending 0x%llx\n", 1024789Sahrens (uintptr_t)(addr + offsetof(vdev_t, 1025789Sahrens vdev_queue.vq_min_pending)), 1026789Sahrens vdev.vdev_queue.vq_min_pending); 1027789Sahrens mdb_printf("%p max pending 0x%llx\n", 1028789Sahrens (uintptr_t)(addr + offsetof(vdev_t, 1029789Sahrens vdev_queue.vq_max_pending)), 1030789Sahrens vdev.vdev_queue.vq_max_pending); 1031789Sahrens mdb_printf("%p agg limit 0x%llx\n", 1032789Sahrens (uintptr_t)(addr + offsetof(vdev_t, 1033789Sahrens vdev_queue.vq_agg_limit)), 1034789Sahrens vdev.vdev_queue.vq_agg_limit); 1035789Sahrens mdb_printf("%p time shift 0x%llx\n", 1036789Sahrens (uintptr_t)(addr + offsetof(vdev_t, 1037789Sahrens vdev_queue.vq_time_shift)), 1038789Sahrens vdev.vdev_queue.vq_time_shift); 1039789Sahrens mdb_printf("%p ramp rate 0x%llx\n", 1040789Sahrens (uintptr_t)(addr + offsetof(vdev_t, 1041789Sahrens vdev_queue.vq_ramp_rate)), 1042789Sahrens vdev.vdev_queue.vq_ramp_rate); 1043789Sahrens mdb_dec_indent(4); 1044789Sahrens } 1045789Sahrens 1046789Sahrens if (stats) { 1047789Sahrens vdev_stat_t *vs = &vdev.vdev_stat; 1048789Sahrens int i; 1049789Sahrens 1050789Sahrens mdb_inc_indent(4); 1051789Sahrens mdb_printf("\n"); 1052789Sahrens mdb_printf("%<u> %12s %12s %12s %12s " 1053789Sahrens "%12s%</u>\n", "READ", "WRITE", "FREE", "CLAIM", 1054789Sahrens "IOCTL"); 1055789Sahrens mdb_printf("OPS "); 1056789Sahrens for (i = 1; i < ZIO_TYPES; i++) 1057789Sahrens mdb_printf("%11#llx%s", vs->vs_ops[i], 1058789Sahrens i == ZIO_TYPES - 1 ? "" : " "); 1059789Sahrens mdb_printf("\n"); 1060789Sahrens mdb_printf("BYTES "); 1061789Sahrens for (i = 1; i < ZIO_TYPES; i++) 1062789Sahrens mdb_printf("%11#llx%s", vs->vs_bytes[i], 1063789Sahrens i == ZIO_TYPES - 1 ? "" : " "); 1064789Sahrens 1065789Sahrens 1066789Sahrens mdb_printf("\n"); 1067789Sahrens mdb_printf("EREAD %10#llx\n", vs->vs_read_errors); 1068789Sahrens mdb_printf("EWRITE %10#llx\n", vs->vs_write_errors); 1069789Sahrens mdb_printf("ECKSUM %10#llx\n", 1070789Sahrens vs->vs_checksum_errors); 1071789Sahrens mdb_dec_indent(4); 1072789Sahrens } 1073789Sahrens 1074789Sahrens if (queue || stats) 1075789Sahrens mdb_printf("\n"); 1076789Sahrens } 1077789Sahrens 1078789Sahrens children = vdev.vdev_children; 1079789Sahrens 1080789Sahrens if (children == 0 || !recursive) 1081789Sahrens return (DCMD_OK); 1082789Sahrens 1083789Sahrens child = mdb_alloc(children * sizeof (void *), UM_SLEEP | UM_GC); 1084789Sahrens if (mdb_vread(child, children * sizeof (void *), 1085789Sahrens (uintptr_t)vdev.vdev_child) == -1) { 1086789Sahrens mdb_warn("failed to read vdev children at %p", vdev.vdev_child); 1087789Sahrens return (DCMD_ERR); 1088789Sahrens } 1089789Sahrens 1090789Sahrens for (c = 0; c < children; c++) { 1091789Sahrens if (do_print_vdev(child[c], flags, depth + 2, queue, stats, 1092789Sahrens recursive)) 1093789Sahrens return (DCMD_ERR); 1094789Sahrens } 1095789Sahrens 1096789Sahrens return (DCMD_OK); 1097789Sahrens } 1098789Sahrens 1099789Sahrens static int 1100789Sahrens vdev_print(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 1101789Sahrens { 1102789Sahrens int print_queue = FALSE; 1103789Sahrens int recursive = FALSE; 1104789Sahrens int stats = FALSE; 1105789Sahrens 1106789Sahrens if (mdb_getopts(argc, argv, 1107789Sahrens 'q', MDB_OPT_SETBITS, TRUE, &print_queue, 1108789Sahrens 'r', MDB_OPT_SETBITS, TRUE, &recursive, 1109789Sahrens 'e', MDB_OPT_SETBITS, TRUE, &stats, 1110789Sahrens NULL) != argc) 1111789Sahrens return (DCMD_USAGE); 1112789Sahrens 1113789Sahrens if (!(flags & DCMD_ADDRSPEC)) { 1114789Sahrens mdb_warn("no vdev_t address given\n"); 1115789Sahrens return (DCMD_ERR); 1116789Sahrens } 1117789Sahrens 1118789Sahrens return (do_print_vdev(addr, flags, 0, print_queue, stats, recursive)); 1119789Sahrens } 1120789Sahrens 1121789Sahrens typedef struct mdb_spa { 1122789Sahrens uintptr_t spa_dsl_pool; 1123789Sahrens uintptr_t spa_root_vdev; 1124789Sahrens } mdb_spa_t; 1125789Sahrens 1126789Sahrens typedef struct mdb_dsl_dir { 1127789Sahrens uintptr_t dd_phys; 1128789Sahrens uint64_t dd_used_bytes; 1129789Sahrens int64_t dd_space_towrite[TXG_SIZE]; 1130789Sahrens } mdb_dsl_dir_t; 1131789Sahrens 1132789Sahrens typedef struct mdb_dsl_dir_phys { 1133789Sahrens uint64_t dd_used_bytes; 1134789Sahrens uint64_t dd_compressed_bytes; 1135789Sahrens uint64_t dd_uncompressed_bytes; 1136789Sahrens } mdb_dsl_dir_phys_t; 1137789Sahrens 1138789Sahrens typedef struct mdb_vdev { 1139789Sahrens uintptr_t vdev_parent; 1140789Sahrens uintptr_t vdev_ms; 1141789Sahrens uint64_t vdev_ms_count; 1142789Sahrens vdev_stat_t vdev_stat; 1143789Sahrens } mdb_vdev_t; 1144789Sahrens 1145789Sahrens typedef struct mdb_metaslab { 1146789Sahrens space_map_t ms_allocmap[TXG_SIZE]; 1147789Sahrens space_map_t ms_freemap[TXG_SIZE]; 1148789Sahrens space_map_t ms_map; 1149789Sahrens uint64_t ms_usable_space; 1150789Sahrens } mdb_metaslab_t; 1151789Sahrens 1152789Sahrens /* 1153789Sahrens * ::spa_space [-b] 1154789Sahrens * 1155789Sahrens * Given a spa_t, print out it's on-disk space usage and in-core 1156789Sahrens * estimates of future usage. If -b is given, print space in bytes. 1157789Sahrens * Otherwise print in megabytes. 1158789Sahrens */ 1159789Sahrens /* ARGSUSED */ 1160789Sahrens static int 1161789Sahrens spa_space(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 1162789Sahrens { 1163789Sahrens mdb_spa_t spa; 1164789Sahrens uintptr_t dp_root_dir; 1165789Sahrens mdb_dsl_dir_t dd; 1166789Sahrens mdb_dsl_dir_phys_t dsp; 1167789Sahrens uint64_t children; 1168789Sahrens uintptr_t childaddr; 1169789Sahrens uintptr_t *child; 1170789Sahrens uint64_t ms_allocmap[TXG_SIZE] = {0, 0, 0, 0}; 1171789Sahrens uint64_t ms_freemap[TXG_SIZE] = {0, 0, 0, 0}; 1172789Sahrens uint64_t ms_map = 0; 1173789Sahrens uint64_t ms_usable_space = 0; 1174789Sahrens int i, j; 1175789Sahrens int havecompressed = TRUE; 1176789Sahrens int shift = 20; 1177789Sahrens char *suffix = "M"; 1178789Sahrens int bits = FALSE; 1179789Sahrens 1180789Sahrens if (mdb_getopts(argc, argv, 'b', MDB_OPT_SETBITS, TRUE, &bits, NULL) != 1181789Sahrens argc) 1182789Sahrens return (DCMD_USAGE); 1183789Sahrens if (!(flags & DCMD_ADDRSPEC)) 1184789Sahrens return (DCMD_USAGE); 1185789Sahrens 1186789Sahrens if (bits) { 1187789Sahrens shift = 0; 1188789Sahrens suffix = ""; 1189789Sahrens } 1190789Sahrens 1191789Sahrens if (GETMEMB(addr, struct spa, spa_dsl_pool, spa.spa_dsl_pool) || 1192789Sahrens GETMEMB(addr, struct spa, spa_root_vdev, spa.spa_root_vdev) || 1193789Sahrens GETMEMB(spa.spa_root_vdev, struct vdev, vdev_children, children) || 1194789Sahrens GETMEMB(spa.spa_root_vdev, struct vdev, vdev_child, childaddr) || 1195789Sahrens GETMEMB(spa.spa_dsl_pool, struct dsl_pool, 1196789Sahrens dp_root_dir, dp_root_dir) || 1197789Sahrens GETMEMB(dp_root_dir, struct dsl_dir, dd_phys, dd.dd_phys) || 1198789Sahrens GETMEMB(dp_root_dir, struct dsl_dir, 1199789Sahrens dd_used_bytes, dd.dd_used_bytes) || 1200789Sahrens GETMEMB(dp_root_dir, struct dsl_dir, 1201789Sahrens dd_space_towrite, dd.dd_space_towrite) || 1202789Sahrens GETMEMB(dd.dd_phys, struct dsl_dir_phys, 1203789Sahrens dd_used_bytes, dsp.dd_used_bytes)) { 1204789Sahrens return (DCMD_ERR); 1205789Sahrens } 1206789Sahrens 1207789Sahrens if (GETMEMB(dd.dd_phys, struct dsl_dir_phys, 1208789Sahrens dd_compressed_bytes, dsp.dd_compressed_bytes) || 1209789Sahrens GETMEMB(dd.dd_phys, struct dsl_dir_phys, 1210789Sahrens dd_uncompressed_bytes, dsp.dd_uncompressed_bytes)) { 1211789Sahrens havecompressed = FALSE; 1212789Sahrens } 1213789Sahrens 1214789Sahrens child = mdb_alloc(children * sizeof (void *), UM_SLEEP | UM_GC); 1215789Sahrens if (mdb_vread(child, children * sizeof (void *), childaddr) == -1) { 1216789Sahrens mdb_warn("failed to read root vdev children at %p", childaddr); 1217789Sahrens return (DCMD_ERR); 1218789Sahrens } 1219789Sahrens 1220789Sahrens mdb_printf("dd_space_towrite = %llu%s %llu%s %llu%s %llu%s\n", 1221789Sahrens dd.dd_space_towrite[0] >> shift, suffix, 1222789Sahrens dd.dd_space_towrite[1] >> shift, suffix, 1223789Sahrens dd.dd_space_towrite[2] >> shift, suffix, 1224789Sahrens dd.dd_space_towrite[3] >> shift, suffix); 1225789Sahrens mdb_printf("dd_used_bytes = %llu%s\n", 1226789Sahrens dd.dd_used_bytes >> shift, suffix); 1227789Sahrens 1228789Sahrens mdb_printf("dd_phys.dd_used_bytes = %llu%s\n", 1229789Sahrens dsp.dd_used_bytes >> shift, suffix); 1230789Sahrens if (havecompressed) { 1231789Sahrens mdb_printf("dd_phys.dd_compressed_bytes = %llu%s\n", 1232789Sahrens dsp.dd_compressed_bytes >> shift, suffix); 1233789Sahrens mdb_printf("dd_phys.dd_uncompressed_bytes = %llu%s\n", 1234789Sahrens dsp.dd_uncompressed_bytes >> shift, suffix); 1235789Sahrens } 1236789Sahrens 1237789Sahrens for (i = 0; i < children; i++) { 1238789Sahrens mdb_vdev_t vd; 1239789Sahrens uintptr_t *vdev_ms; 1240789Sahrens 1241789Sahrens if (GETMEMB(child[i], struct vdev, 1242789Sahrens vdev_parent, vd.vdev_parent) || 1243789Sahrens GETMEMB(child[i], struct vdev, 1244789Sahrens vdev_stat, vd.vdev_stat) || 1245789Sahrens GETMEMB(child[i], struct vdev, vdev_ms, vd.vdev_ms) || 1246789Sahrens GETMEMB(child[i], struct vdev, 1247789Sahrens vdev_ms_count, vd.vdev_ms_count)) { 1248789Sahrens return (DCMD_ERR); 1249789Sahrens } 1250789Sahrens 1251789Sahrens /* 1252789Sahrens * If this is the root vdev, its stats are the pool-wide stats. 1253789Sahrens */ 1254789Sahrens if (vd.vdev_parent == NULL) { 1255789Sahrens mdb_printf("pool_alloc = %llu%s\n", 1256789Sahrens vd.vdev_stat.vs_alloc >> shift, suffix); 1257789Sahrens mdb_printf("pool_space = %llu%s\n", 1258789Sahrens vd.vdev_stat.vs_space >> shift, suffix); 1259789Sahrens } 1260789Sahrens 1261789Sahrens /* 1262789Sahrens * If this is not a top-level vdev, it doesn't have space. 1263789Sahrens */ 1264789Sahrens if (vd.vdev_parent != spa.spa_root_vdev) 1265789Sahrens continue; 1266789Sahrens 1267789Sahrens vdev_ms = mdb_alloc(vd.vdev_ms_count * sizeof (void*), 1268789Sahrens UM_SLEEP | UM_GC); 1269789Sahrens if (mdb_vread(vdev_ms, vd.vdev_ms_count * sizeof (void*), 1270789Sahrens (uintptr_t)vd.vdev_ms) == -1) { 1271789Sahrens mdb_warn("failed to read vdev_ms at %p", vd.vdev_ms); 1272789Sahrens return (DCMD_ERR); 1273789Sahrens } 1274789Sahrens 1275789Sahrens for (j = 0; j < vd.vdev_ms_count; j++) { 1276789Sahrens mdb_metaslab_t ms; 1277789Sahrens 1278789Sahrens if (GETMEMB(vdev_ms[j], struct metaslab, 1279789Sahrens ms_allocmap, ms.ms_allocmap) || 1280789Sahrens GETMEMB(vdev_ms[j], struct metaslab, 1281789Sahrens ms_freemap, ms.ms_freemap) || 1282789Sahrens GETMEMB(vdev_ms[j], struct metaslab, 1283789Sahrens ms_map, ms.ms_map) || 1284789Sahrens GETMEMB(vdev_ms[j], struct metaslab, 1285789Sahrens ms_usable_space, ms.ms_usable_space)) { 1286789Sahrens return (DCMD_ERR); 1287789Sahrens } 1288789Sahrens 1289789Sahrens ms_allocmap[0] += ms.ms_allocmap[0].sm_space; 1290789Sahrens ms_allocmap[1] += ms.ms_allocmap[1].sm_space; 1291789Sahrens ms_allocmap[2] += ms.ms_allocmap[2].sm_space; 1292789Sahrens ms_allocmap[3] += ms.ms_allocmap[3].sm_space; 1293789Sahrens ms_freemap[0] += ms.ms_freemap[0].sm_space; 1294789Sahrens ms_freemap[1] += ms.ms_freemap[1].sm_space; 1295789Sahrens ms_freemap[2] += ms.ms_freemap[2].sm_space; 1296789Sahrens ms_freemap[3] += ms.ms_freemap[3].sm_space; 1297789Sahrens ms_map += ms.ms_map.sm_space; 1298789Sahrens ms_usable_space += ms.ms_usable_space; 1299789Sahrens } 1300789Sahrens } 1301789Sahrens 1302789Sahrens mdb_printf("ms_allocmap = %llu%s %llu%s %llu%s %llu%s\n", 1303789Sahrens ms_allocmap[0] >> shift, suffix, 1304789Sahrens ms_allocmap[1] >> shift, suffix, 1305789Sahrens ms_allocmap[2] >> shift, suffix, 1306789Sahrens ms_allocmap[3] >> shift, suffix); 1307789Sahrens mdb_printf("ms_freemap = %llu%s %llu%s %llu%s %llu%s\n", 1308789Sahrens ms_freemap[0] >> shift, suffix, 1309789Sahrens ms_freemap[1] >> shift, suffix, 1310789Sahrens ms_freemap[2] >> shift, suffix, 1311789Sahrens ms_freemap[3] >> shift, suffix); 1312789Sahrens mdb_printf("ms_map = %llu%s\n", ms_map >> shift, suffix); 1313789Sahrens mdb_printf("ms_usable_space = %llu%s\n", 1314789Sahrens ms_usable_space >> shift, suffix); 1315789Sahrens 1316789Sahrens return (DCMD_OK); 1317789Sahrens } 1318789Sahrens 1319789Sahrens /* 1320789Sahrens * ::spa_verify 1321789Sahrens * 1322789Sahrens * Given a spa_t, verify that that the pool is self-consistent. 1323789Sahrens * Currently, it only checks to make sure that the vdev tree exists. 1324789Sahrens */ 1325789Sahrens /* ARGSUSED */ 1326789Sahrens static int 1327789Sahrens spa_verify(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 1328789Sahrens { 1329789Sahrens spa_t spa; 1330789Sahrens 1331789Sahrens if (argc != 0 || !(flags & DCMD_ADDRSPEC)) 1332789Sahrens return (DCMD_USAGE); 1333789Sahrens 1334789Sahrens if (mdb_vread(&spa, sizeof (spa), addr) == -1) { 1335789Sahrens mdb_warn("failed to read spa_t at %p", addr); 1336789Sahrens return (DCMD_ERR); 1337789Sahrens } 1338789Sahrens 1339789Sahrens if (spa.spa_root_vdev == NULL) { 1340789Sahrens mdb_printf("no vdev tree present\n"); 1341789Sahrens return (DCMD_OK); 1342789Sahrens } 1343789Sahrens 1344789Sahrens return (DCMD_OK); 1345789Sahrens } 1346789Sahrens 1347789Sahrens /* 1348789Sahrens * ::spa_vdevs 1349789Sahrens * 1350789Sahrens * -e Include error stats 1351789Sahrens * 1352789Sahrens * Print out a summarized list of vdevs for the given spa_t. 1353789Sahrens * This is accomplished by invoking "::vdev -re" on the root vdev. 1354789Sahrens */ 1355789Sahrens /* ARGSUSED */ 1356789Sahrens static int 1357789Sahrens spa_vdevs(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 1358789Sahrens { 1359789Sahrens spa_t spa; 1360789Sahrens mdb_arg_t v; 1361789Sahrens int errors = FALSE; 1362789Sahrens 1363789Sahrens if (mdb_getopts(argc, argv, 1364789Sahrens 'e', MDB_OPT_SETBITS, TRUE, &errors, 1365789Sahrens NULL) != argc) 1366789Sahrens return (DCMD_USAGE); 1367789Sahrens 1368789Sahrens if (!(flags & DCMD_ADDRSPEC)) 1369789Sahrens return (DCMD_USAGE); 1370789Sahrens 1371789Sahrens if (mdb_vread(&spa, sizeof (spa), addr) == -1) { 1372789Sahrens mdb_warn("failed to read spa_t at %p", addr); 1373789Sahrens return (DCMD_ERR); 1374789Sahrens } 1375789Sahrens 1376952Seschrock /* 1377952Seschrock * Unitialized spa_t structures can have a NULL root vdev. 1378952Seschrock */ 1379952Seschrock if (spa.spa_root_vdev == NULL) { 1380952Seschrock mdb_printf("no associated vdevs\n"); 1381952Seschrock return (DCMD_OK); 1382952Seschrock } 1383952Seschrock 1384789Sahrens v.a_type = MDB_TYPE_STRING; 1385789Sahrens v.a_un.a_str = errors ? "-re" : "-r"; 1386789Sahrens 1387789Sahrens return (mdb_call_dcmd("vdev", (uintptr_t)spa.spa_root_vdev, 1388789Sahrens flags, 1, &v)); 1389789Sahrens } 1390789Sahrens 1391789Sahrens typedef struct txg_list_walk_data { 1392789Sahrens uintptr_t lw_head[TXG_SIZE]; 1393789Sahrens int lw_txgoff; 1394789Sahrens int lw_maxoff; 1395789Sahrens size_t lw_offset; 1396789Sahrens void *lw_obj; 1397789Sahrens } txg_list_walk_data_t; 1398789Sahrens 1399789Sahrens static int 1400789Sahrens txg_list_walk_init_common(mdb_walk_state_t *wsp, int txg, int maxoff) 1401789Sahrens { 1402789Sahrens txg_list_walk_data_t *lwd; 1403789Sahrens txg_list_t list; 1404789Sahrens int i; 1405789Sahrens 1406789Sahrens lwd = mdb_alloc(sizeof (txg_list_walk_data_t), UM_SLEEP | UM_GC); 1407789Sahrens if (mdb_vread(&list, sizeof (txg_list_t), wsp->walk_addr) == -1) { 1408789Sahrens mdb_warn("failed to read txg_list_t at %#lx", wsp->walk_addr); 1409789Sahrens return (WALK_ERR); 1410789Sahrens } 1411789Sahrens 1412789Sahrens for (i = 0; i < TXG_SIZE; i++) 1413789Sahrens lwd->lw_head[i] = (uintptr_t)list.tl_head[i]; 1414789Sahrens lwd->lw_offset = list.tl_offset; 1415789Sahrens lwd->lw_obj = mdb_alloc(lwd->lw_offset + sizeof (txg_node_t), 1416789Sahrens UM_SLEEP | UM_GC); 1417789Sahrens lwd->lw_txgoff = txg; 1418789Sahrens lwd->lw_maxoff = maxoff; 1419789Sahrens 1420789Sahrens wsp->walk_addr = lwd->lw_head[lwd->lw_txgoff]; 1421789Sahrens wsp->walk_data = lwd; 1422789Sahrens 1423789Sahrens return (WALK_NEXT); 1424789Sahrens } 1425789Sahrens 1426789Sahrens static int 1427789Sahrens txg_list_walk_init(mdb_walk_state_t *wsp) 1428789Sahrens { 1429789Sahrens return (txg_list_walk_init_common(wsp, 0, TXG_SIZE-1)); 1430789Sahrens } 1431789Sahrens 1432789Sahrens static int 1433789Sahrens txg_list0_walk_init(mdb_walk_state_t *wsp) 1434789Sahrens { 1435789Sahrens return (txg_list_walk_init_common(wsp, 0, 0)); 1436789Sahrens } 1437789Sahrens 1438789Sahrens static int 1439789Sahrens txg_list1_walk_init(mdb_walk_state_t *wsp) 1440789Sahrens { 1441789Sahrens return (txg_list_walk_init_common(wsp, 1, 1)); 1442789Sahrens } 1443789Sahrens 1444789Sahrens static int 1445789Sahrens txg_list2_walk_init(mdb_walk_state_t *wsp) 1446789Sahrens { 1447789Sahrens return (txg_list_walk_init_common(wsp, 2, 2)); 1448789Sahrens } 1449789Sahrens 1450789Sahrens static int 1451789Sahrens txg_list3_walk_init(mdb_walk_state_t *wsp) 1452789Sahrens { 1453789Sahrens return (txg_list_walk_init_common(wsp, 3, 3)); 1454789Sahrens } 1455789Sahrens 1456789Sahrens static int 1457789Sahrens txg_list_walk_step(mdb_walk_state_t *wsp) 1458789Sahrens { 1459789Sahrens txg_list_walk_data_t *lwd = wsp->walk_data; 1460789Sahrens uintptr_t addr; 1461789Sahrens txg_node_t *node; 1462789Sahrens int status; 1463789Sahrens 1464789Sahrens while (wsp->walk_addr == NULL && lwd->lw_txgoff < lwd->lw_maxoff) { 1465789Sahrens lwd->lw_txgoff++; 1466789Sahrens wsp->walk_addr = lwd->lw_head[lwd->lw_txgoff]; 1467789Sahrens } 1468789Sahrens 1469789Sahrens if (wsp->walk_addr == NULL) 1470789Sahrens return (WALK_DONE); 1471789Sahrens 1472789Sahrens addr = wsp->walk_addr - lwd->lw_offset; 1473789Sahrens 1474789Sahrens if (mdb_vread(lwd->lw_obj, 1475789Sahrens lwd->lw_offset + sizeof (txg_node_t), addr) == -1) { 1476789Sahrens mdb_warn("failed to read list element at %#lx", addr); 1477789Sahrens return (WALK_ERR); 1478789Sahrens } 1479789Sahrens 1480789Sahrens status = wsp->walk_callback(addr, lwd->lw_obj, wsp->walk_cbdata); 1481789Sahrens node = (txg_node_t *)((uintptr_t)lwd->lw_obj + lwd->lw_offset); 1482789Sahrens wsp->walk_addr = (uintptr_t)node->tn_next[lwd->lw_txgoff]; 1483789Sahrens 1484789Sahrens return (status); 1485789Sahrens } 1486789Sahrens 1487789Sahrens /* ARGSUSED */ 1488789Sahrens static void 1489789Sahrens txg_list_walk_fini(mdb_walk_state_t *wsp) 1490789Sahrens { 1491789Sahrens } 1492789Sahrens 1493789Sahrens /* 1494789Sahrens * ::walk spa 1495789Sahrens * 1496789Sahrens * Walk all named spa_t structures in the namespace. This is nothing more than 1497789Sahrens * a layered avl walk. 1498789Sahrens */ 1499789Sahrens static int 1500789Sahrens spa_walk_init(mdb_walk_state_t *wsp) 1501789Sahrens { 1502789Sahrens GElf_Sym sym; 1503789Sahrens 1504789Sahrens if (wsp->walk_addr != NULL) { 1505789Sahrens mdb_warn("spa walk only supports global walks\n"); 1506789Sahrens return (WALK_ERR); 1507789Sahrens } 1508789Sahrens 1509789Sahrens if (mdb_lookup_by_obj(ZFS_OBJ_NAME, "spa_namespace_avl", &sym) == -1) { 1510789Sahrens mdb_warn("failed to find symbol 'spa_namespace_avl'"); 1511789Sahrens return (WALK_ERR); 1512789Sahrens } 1513789Sahrens 1514789Sahrens wsp->walk_addr = (uintptr_t)sym.st_value; 1515789Sahrens 1516789Sahrens if (mdb_layered_walk("avl", wsp) == -1) { 1517789Sahrens mdb_warn("failed to walk 'avl'\n"); 1518789Sahrens return (WALK_ERR); 1519789Sahrens } 1520789Sahrens 1521789Sahrens return (WALK_NEXT); 1522789Sahrens } 1523789Sahrens 1524789Sahrens static int 1525789Sahrens spa_walk_step(mdb_walk_state_t *wsp) 1526789Sahrens { 1527789Sahrens spa_t spa; 1528789Sahrens 1529789Sahrens if (mdb_vread(&spa, sizeof (spa), wsp->walk_addr) == -1) { 1530789Sahrens mdb_warn("failed to read spa_t at %p", wsp->walk_addr); 1531789Sahrens return (WALK_ERR); 1532789Sahrens } 1533789Sahrens 1534789Sahrens return (wsp->walk_callback(wsp->walk_addr, &spa, wsp->walk_cbdata)); 1535789Sahrens } 1536789Sahrens 1537789Sahrens /* 1538789Sahrens * MDB module linkage information: 1539789Sahrens * 1540789Sahrens * We declare a list of structures describing our dcmds, and a function 1541789Sahrens * named _mdb_init to return a pointer to our module information. 1542789Sahrens */ 1543789Sahrens 1544789Sahrens static const mdb_dcmd_t dcmds[] = { 1545789Sahrens { "blkptr", ":", "print blkptr_t", blkptr }, 1546789Sahrens { "dbuf", ":", "print dmu_buf_impl_t", dbuf }, 1547789Sahrens { "dbuf_stats", ":", "dbuf stats", dbuf_stats }, 1548789Sahrens { "dbufs", 1549789Sahrens "\t[-O objset_t*] [-n objset_name | \"mos\"] [-o object | \"mdn\"] \n" 1550789Sahrens "\t[-l level] [-b blkid | \"bonus\"]", 1551789Sahrens "find dmu_buf_impl_t's that meet criterion", dbufs }, 1552789Sahrens { "abuf_find", "dva_word[0] dva_word[1]", 1553789Sahrens "find arc_buf_hdr_t of a specified DVA", 1554789Sahrens abuf_find }, 1555789Sahrens { "spa", "?[-cv]", "spa_t summary", spa_print }, 1556789Sahrens { "spa_config", ":", "print spa_t configuration", spa_print_config }, 1557789Sahrens { "spa_verify", ":", "verify spa_t consistency", spa_verify }, 1558789Sahrens { "spa_space", ":[-b]", "print spa_t on-disk space usage", spa_space }, 1559789Sahrens { "spa_vdevs", ":", "given a spa_t, print vdev summary", spa_vdevs }, 1560789Sahrens { "vdev", ":[-qre]", "vdev_t summary", vdev_print }, 1561789Sahrens { "zio_pipeline", ":", "decode a zio pipeline", zio_pipeline }, 1562789Sahrens { NULL } 1563789Sahrens }; 1564789Sahrens 1565789Sahrens static const mdb_walker_t walkers[] = { 1566789Sahrens /* 1567789Sahrens * In userland, there is no generic provider of list_t walkers, so we 1568789Sahrens * need to add it. 1569789Sahrens */ 1570789Sahrens #ifndef _KERNEL 1571789Sahrens { LIST_WALK_NAME, LIST_WALK_DESC, 1572789Sahrens list_walk_init, list_walk_step, list_walk_fini }, 1573789Sahrens #endif 1574789Sahrens { "dbufs", "walk cached ZFS dbufs", 1575789Sahrens dbuf_walk_init, dbuf_walk_step, dbuf_walk_fini }, 1576789Sahrens { "zms_freelist", "walk ZFS metaslab freelist", 1577789Sahrens freelist_walk_init, freelist_walk_step, freelist_walk_fini }, 1578789Sahrens { "txg_list", "given any txg_list_t *, walk all entries in all txgs", 1579789Sahrens txg_list_walk_init, txg_list_walk_step, txg_list_walk_fini }, 1580789Sahrens { "txg_list0", "given any txg_list_t *, walk all entries in txg 0", 1581789Sahrens txg_list0_walk_init, txg_list_walk_step, txg_list_walk_fini }, 1582789Sahrens { "txg_list1", "given any txg_list_t *, walk all entries in txg 1", 1583789Sahrens txg_list1_walk_init, txg_list_walk_step, txg_list_walk_fini }, 1584789Sahrens { "txg_list2", "given any txg_list_t *, walk all entries in txg 2", 1585789Sahrens txg_list2_walk_init, txg_list_walk_step, txg_list_walk_fini }, 1586789Sahrens { "txg_list3", "given any txg_list_t *, walk all entries in txg 3", 1587789Sahrens txg_list3_walk_init, txg_list_walk_step, txg_list_walk_fini }, 1588789Sahrens { "spa", "walk all spa_t entries in the namespace", 1589789Sahrens spa_walk_init, spa_walk_step, NULL }, 1590789Sahrens { NULL } 1591789Sahrens }; 1592789Sahrens 1593789Sahrens static const mdb_modinfo_t modinfo = { 1594789Sahrens MDB_API_VERSION, dcmds, walkers 1595789Sahrens }; 1596789Sahrens 1597789Sahrens const mdb_modinfo_t * 1598789Sahrens _mdb_init(void) 1599789Sahrens { 1600789Sahrens return (&modinfo); 1601789Sahrens } 1602