1*789Sahrens /* 2*789Sahrens * CDDL HEADER START 3*789Sahrens * 4*789Sahrens * The contents of this file are subject to the terms of the 5*789Sahrens * Common Development and Distribution License, Version 1.0 only 6*789Sahrens * (the "License"). You may not use this file except in compliance 7*789Sahrens * with the License. 8*789Sahrens * 9*789Sahrens * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*789Sahrens * or http://www.opensolaris.org/os/licensing. 11*789Sahrens * See the License for the specific language governing permissions 12*789Sahrens * and limitations under the License. 13*789Sahrens * 14*789Sahrens * When distributing Covered Code, include this CDDL HEADER in each 15*789Sahrens * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*789Sahrens * If applicable, add the following below this CDDL HEADER, with the 17*789Sahrens * fields enclosed by brackets "[]" replaced with your own identifying 18*789Sahrens * information: Portions Copyright [yyyy] [name of copyright owner] 19*789Sahrens * 20*789Sahrens * CDDL HEADER END 21*789Sahrens */ 22*789Sahrens /* 23*789Sahrens * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24*789Sahrens * Use is subject to license terms. 25*789Sahrens */ 26*789Sahrens 27*789Sahrens #pragma ident "%Z%%M% %I% %E% SMI" 28*789Sahrens 29*789Sahrens #include <mdb/mdb_ctf.h> 30*789Sahrens #include <sys/zfs_context.h> 31*789Sahrens #include <sys/mdb_modapi.h> 32*789Sahrens #include <sys/dbuf.h> 33*789Sahrens #include <sys/dmu_objset.h> 34*789Sahrens #include <sys/dsl_dir.h> 35*789Sahrens #include <sys/dsl_pool.h> 36*789Sahrens #include <sys/metaslab_impl.h> 37*789Sahrens #include <sys/space_map.h> 38*789Sahrens #include <sys/list.h> 39*789Sahrens #include <sys/spa_impl.h> 40*789Sahrens #include <sys/vdev_impl.h> 41*789Sahrens #include <sys/zio_compress.h> 42*789Sahrens 43*789Sahrens #ifndef _KERNEL 44*789Sahrens #include "../genunix/list.h" 45*789Sahrens #endif 46*789Sahrens 47*789Sahrens #ifdef _KERNEL 48*789Sahrens #define ZFS_OBJ_NAME "zfs" 49*789Sahrens #else 50*789Sahrens #define ZFS_OBJ_NAME "libzpool.so.1" 51*789Sahrens #endif 52*789Sahrens 53*789Sahrens static char * 54*789Sahrens local_strdup(const char *s) 55*789Sahrens { 56*789Sahrens char *s1 = mdb_alloc(strlen(s) + 1, UM_SLEEP); 57*789Sahrens 58*789Sahrens (void) strcpy(s1, s); 59*789Sahrens return (s1); 60*789Sahrens } 61*789Sahrens 62*789Sahrens static int 63*789Sahrens getmember(uintptr_t addr, const char *type, mdb_ctf_id_t *idp, 64*789Sahrens const char *member, int len, void *buf) 65*789Sahrens { 66*789Sahrens mdb_ctf_id_t id; 67*789Sahrens ulong_t off; 68*789Sahrens char name[64]; 69*789Sahrens 70*789Sahrens if (idp == NULL) { 71*789Sahrens if (mdb_ctf_lookup_by_name(type, &id) == -1) { 72*789Sahrens mdb_warn("couldn't find type %s", type); 73*789Sahrens return (DCMD_ERR); 74*789Sahrens } 75*789Sahrens idp = &id; 76*789Sahrens } else { 77*789Sahrens type = name; 78*789Sahrens mdb_ctf_type_name(*idp, name, sizeof (name)); 79*789Sahrens } 80*789Sahrens 81*789Sahrens if (mdb_ctf_offsetof(*idp, member, &off) == -1) { 82*789Sahrens mdb_warn("couldn't find member %s of type %s\n", member, type); 83*789Sahrens return (DCMD_ERR); 84*789Sahrens } 85*789Sahrens if (off % 8 != 0) { 86*789Sahrens mdb_warn("member %s of type %s is unsupported bitfield", 87*789Sahrens member, type); 88*789Sahrens return (DCMD_ERR); 89*789Sahrens } 90*789Sahrens off /= 8; 91*789Sahrens 92*789Sahrens if (mdb_vread(buf, len, addr + off) == -1) { 93*789Sahrens mdb_warn("failed to read %s from %s at %p", 94*789Sahrens member, type, addr + off); 95*789Sahrens return (DCMD_ERR); 96*789Sahrens } 97*789Sahrens /* mdb_warn("read %s from %s at %p+%llx\n", member, type, addr, off); */ 98*789Sahrens 99*789Sahrens return (0); 100*789Sahrens } 101*789Sahrens 102*789Sahrens #define GETMEMB(addr, type, member, dest) \ 103*789Sahrens getmember(addr, #type, NULL, #member, sizeof (dest), &(dest)) 104*789Sahrens 105*789Sahrens #define GETMEMBID(addr, ctfid, member, dest) \ 106*789Sahrens getmember(addr, NULL, ctfid, #member, sizeof (dest), &(dest)) 107*789Sahrens 108*789Sahrens static int 109*789Sahrens getrefcount(uintptr_t addr, mdb_ctf_id_t *id, 110*789Sahrens const char *member, uint64_t *rc) 111*789Sahrens { 112*789Sahrens static int gotid; 113*789Sahrens static mdb_ctf_id_t rc_id; 114*789Sahrens ulong_t off; 115*789Sahrens 116*789Sahrens if (!gotid) { 117*789Sahrens if (mdb_ctf_lookup_by_name("struct refcount", &rc_id) == -1) { 118*789Sahrens mdb_warn("couldn't find struct refcount"); 119*789Sahrens return (DCMD_ERR); 120*789Sahrens } 121*789Sahrens gotid = TRUE; 122*789Sahrens } 123*789Sahrens 124*789Sahrens if (mdb_ctf_offsetof(*id, member, &off) == -1) { 125*789Sahrens char name[64]; 126*789Sahrens mdb_ctf_type_name(*id, name, sizeof (name)); 127*789Sahrens mdb_warn("couldn't find member %s of type %s\n", member, name); 128*789Sahrens return (DCMD_ERR); 129*789Sahrens } 130*789Sahrens off /= 8; 131*789Sahrens 132*789Sahrens return (GETMEMBID(addr + off, &rc_id, rc_count, *rc)); 133*789Sahrens } 134*789Sahrens 135*789Sahrens static int 136*789Sahrens read_symbol(char *sym_name, void **bufp) 137*789Sahrens { 138*789Sahrens GElf_Sym sym; 139*789Sahrens 140*789Sahrens if (mdb_lookup_by_obj(MDB_TGT_OBJ_EVERY, sym_name, &sym)) { 141*789Sahrens mdb_warn("can't find symbol %s", sym_name); 142*789Sahrens return (DCMD_ERR); 143*789Sahrens } 144*789Sahrens 145*789Sahrens *bufp = mdb_alloc(sym.st_size, UM_SLEEP); 146*789Sahrens 147*789Sahrens if (mdb_vread(*bufp, sym.st_size, sym.st_value) == -1) { 148*789Sahrens mdb_warn("can't read data for symbol %s", sym_name); 149*789Sahrens mdb_free(*bufp, sym.st_size); 150*789Sahrens return (DCMD_ERR); 151*789Sahrens } 152*789Sahrens 153*789Sahrens return (DCMD_OK); 154*789Sahrens } 155*789Sahrens 156*789Sahrens static int verbose; 157*789Sahrens 158*789Sahrens static int 159*789Sahrens freelist_walk_init(mdb_walk_state_t *wsp) 160*789Sahrens { 161*789Sahrens if (wsp->walk_addr == NULL) { 162*789Sahrens mdb_warn("must supply starting address\n"); 163*789Sahrens return (WALK_ERR); 164*789Sahrens } 165*789Sahrens 166*789Sahrens wsp->walk_data = 0; /* Index into the freelist */ 167*789Sahrens return (WALK_NEXT); 168*789Sahrens } 169*789Sahrens 170*789Sahrens static int 171*789Sahrens freelist_walk_step(mdb_walk_state_t *wsp) 172*789Sahrens { 173*789Sahrens uint64_t entry; 174*789Sahrens uintptr_t number = (uintptr_t)wsp->walk_data; 175*789Sahrens char *ddata[] = { "ALLOC", "FREE", "CONDENSE", "INVALID" }; 176*789Sahrens int mapshift = SPA_MINBLOCKSHIFT; 177*789Sahrens 178*789Sahrens if (mdb_vread(&entry, sizeof (entry), wsp->walk_addr) == -1) { 179*789Sahrens mdb_warn("failed to read freelist entry %p", wsp->walk_addr); 180*789Sahrens return (WALK_DONE); 181*789Sahrens } 182*789Sahrens wsp->walk_addr += sizeof (entry); 183*789Sahrens wsp->walk_data = (void *)(number + 1); 184*789Sahrens 185*789Sahrens if (SM_DEBUG_DECODE(entry)) { 186*789Sahrens mdb_printf("DEBUG: %3u %10s: txg=%llu pass=%llu\n", 187*789Sahrens number, 188*789Sahrens ddata[SM_DEBUG_ACTION_DECODE(entry)], 189*789Sahrens SM_DEBUG_TXG_DECODE(entry), 190*789Sahrens SM_DEBUG_SYNCPASS_DECODE(entry)); 191*789Sahrens } else { 192*789Sahrens mdb_printf("Entry: %3u offsets=%08llx-%08llx type=%c " 193*789Sahrens "size=%06llx", number, 194*789Sahrens SM_OFFSET_DECODE(entry) << mapshift, 195*789Sahrens (SM_OFFSET_DECODE(entry) + SM_RUN_DECODE(entry)) << 196*789Sahrens mapshift, 197*789Sahrens SM_TYPE_DECODE(entry) == SM_ALLOC ? 'A' : 'F', 198*789Sahrens SM_RUN_DECODE(entry) << mapshift); 199*789Sahrens if (verbose) 200*789Sahrens mdb_printf(" (raw=%012llx)\n", entry); 201*789Sahrens mdb_printf("\n"); 202*789Sahrens } 203*789Sahrens return (WALK_NEXT); 204*789Sahrens } 205*789Sahrens 206*789Sahrens /* ARGSUSED */ 207*789Sahrens static void 208*789Sahrens freelist_walk_fini(mdb_walk_state_t *wsp) 209*789Sahrens { 210*789Sahrens } 211*789Sahrens 212*789Sahrens typedef struct dbuf_walk_data { 213*789Sahrens dbuf_hash_table_t ht; 214*789Sahrens int64_t bucket; 215*789Sahrens uintptr_t dbp; 216*789Sahrens dmu_buf_impl_t db; 217*789Sahrens } dbuf_walk_data_t; 218*789Sahrens 219*789Sahrens static int 220*789Sahrens dbuf_walk_init(mdb_walk_state_t *wsp) 221*789Sahrens { 222*789Sahrens dbuf_walk_data_t *dwd; 223*789Sahrens 224*789Sahrens if (wsp->walk_addr != NULL) { 225*789Sahrens mdb_warn("must supply starting address\n"); 226*789Sahrens return (WALK_ERR); 227*789Sahrens } 228*789Sahrens 229*789Sahrens dwd = mdb_alloc(sizeof (dbuf_walk_data_t), UM_SLEEP); 230*789Sahrens 231*789Sahrens if (mdb_readvar(&dwd->ht, "dbuf_hash_table") == -1) { 232*789Sahrens mdb_warn("failed to read 'dbuf_hash_table'"); 233*789Sahrens mdb_free(dwd, sizeof (dbuf_walk_data_t)); 234*789Sahrens return (WALK_ERR); 235*789Sahrens } 236*789Sahrens dwd->bucket = -1; 237*789Sahrens dwd->dbp = 0; 238*789Sahrens wsp->walk_data = dwd; 239*789Sahrens return (WALK_NEXT); 240*789Sahrens } 241*789Sahrens 242*789Sahrens static int 243*789Sahrens dbuf_walk_step(mdb_walk_state_t *wsp) 244*789Sahrens { 245*789Sahrens int status; 246*789Sahrens dbuf_walk_data_t *dwd = wsp->walk_data; 247*789Sahrens 248*789Sahrens while (dwd->dbp == 0) { 249*789Sahrens dwd->bucket++; 250*789Sahrens if (dwd->bucket == dwd->ht.hash_table_mask+1) 251*789Sahrens return (WALK_DONE); 252*789Sahrens 253*789Sahrens if (mdb_vread(&dwd->dbp, sizeof (void *), 254*789Sahrens (uintptr_t)(dwd->ht.hash_table+dwd->bucket)) == -1) { 255*789Sahrens mdb_warn("failed to read hash bucket %u at %p", 256*789Sahrens dwd->bucket, dwd->ht.hash_table+dwd->bucket); 257*789Sahrens return (WALK_DONE); 258*789Sahrens } 259*789Sahrens } 260*789Sahrens 261*789Sahrens wsp->walk_addr = dwd->dbp; 262*789Sahrens if (mdb_vread(&dwd->db, sizeof (dmu_buf_impl_t), 263*789Sahrens wsp->walk_addr) == -1) { 264*789Sahrens mdb_warn("failed to read dbuf at %p", wsp->walk_addr); 265*789Sahrens return (WALK_DONE); 266*789Sahrens } 267*789Sahrens status = wsp->walk_callback(wsp->walk_addr, &dwd->db, wsp->walk_cbdata); 268*789Sahrens 269*789Sahrens dwd->dbp = (uintptr_t)dwd->db.db_hash_next; 270*789Sahrens return (status); 271*789Sahrens } 272*789Sahrens 273*789Sahrens static void 274*789Sahrens dbuf_walk_fini(mdb_walk_state_t *wsp) 275*789Sahrens { 276*789Sahrens dbuf_walk_data_t *dwd = wsp->walk_data; 277*789Sahrens mdb_free(dwd, sizeof (dbuf_walk_data_t)); 278*789Sahrens } 279*789Sahrens 280*789Sahrens static int 281*789Sahrens dataset_name(uintptr_t addr, char *buf) 282*789Sahrens { 283*789Sahrens static int gotid; 284*789Sahrens static mdb_ctf_id_t dd_id; 285*789Sahrens uintptr_t dd_parent; 286*789Sahrens char dd_myname[MAXNAMELEN]; 287*789Sahrens 288*789Sahrens if (!gotid) { 289*789Sahrens if (mdb_ctf_lookup_by_name("struct dsl_dir", 290*789Sahrens &dd_id) == -1) { 291*789Sahrens mdb_warn("couldn't find struct dsl_dir"); 292*789Sahrens return (DCMD_ERR); 293*789Sahrens } 294*789Sahrens gotid = TRUE; 295*789Sahrens } 296*789Sahrens if (GETMEMBID(addr, &dd_id, dd_parent, dd_parent) || 297*789Sahrens GETMEMBID(addr, &dd_id, dd_myname, dd_myname)) { 298*789Sahrens return (DCMD_ERR); 299*789Sahrens } 300*789Sahrens 301*789Sahrens if (dd_parent) { 302*789Sahrens if (dataset_name(dd_parent, buf)) 303*789Sahrens return (DCMD_ERR); 304*789Sahrens strcat(buf, "/"); 305*789Sahrens } 306*789Sahrens 307*789Sahrens if (dd_myname[0]) 308*789Sahrens strcat(buf, dd_myname); 309*789Sahrens else 310*789Sahrens strcat(buf, "???"); 311*789Sahrens 312*789Sahrens return (0); 313*789Sahrens } 314*789Sahrens 315*789Sahrens static int 316*789Sahrens objset_name(uintptr_t addr, char *buf) 317*789Sahrens { 318*789Sahrens static int gotid; 319*789Sahrens static mdb_ctf_id_t osi_id, ds_id; 320*789Sahrens uintptr_t os_dsl_dataset; 321*789Sahrens char ds_snapname[MAXNAMELEN]; 322*789Sahrens uintptr_t ds_dir; 323*789Sahrens 324*789Sahrens buf[0] = '\0'; 325*789Sahrens 326*789Sahrens if (!gotid) { 327*789Sahrens if (mdb_ctf_lookup_by_name("struct objset_impl", 328*789Sahrens &osi_id) == -1) { 329*789Sahrens mdb_warn("couldn't find struct objset_impl"); 330*789Sahrens return (DCMD_ERR); 331*789Sahrens } 332*789Sahrens if (mdb_ctf_lookup_by_name("struct dsl_dataset", 333*789Sahrens &ds_id) == -1) { 334*789Sahrens mdb_warn("couldn't find struct dsl_dataset"); 335*789Sahrens return (DCMD_ERR); 336*789Sahrens } 337*789Sahrens 338*789Sahrens gotid = TRUE; 339*789Sahrens } 340*789Sahrens 341*789Sahrens if (GETMEMBID(addr, &osi_id, os_dsl_dataset, os_dsl_dataset)) 342*789Sahrens return (DCMD_ERR); 343*789Sahrens 344*789Sahrens if (os_dsl_dataset == 0) { 345*789Sahrens strcat(buf, "mos"); 346*789Sahrens return (0); 347*789Sahrens } 348*789Sahrens 349*789Sahrens if (GETMEMBID(os_dsl_dataset, &ds_id, ds_snapname, ds_snapname) || 350*789Sahrens GETMEMBID(os_dsl_dataset, &ds_id, ds_dir, ds_dir)) { 351*789Sahrens return (DCMD_ERR); 352*789Sahrens } 353*789Sahrens 354*789Sahrens if (ds_dir && dataset_name(ds_dir, buf)) 355*789Sahrens return (DCMD_ERR); 356*789Sahrens 357*789Sahrens if (ds_snapname[0]) { 358*789Sahrens strcat(buf, "@"); 359*789Sahrens strcat(buf, ds_snapname); 360*789Sahrens } 361*789Sahrens return (0); 362*789Sahrens } 363*789Sahrens 364*789Sahrens static void 365*789Sahrens enum_lookup(char *out, size_t size, mdb_ctf_id_t id, int val, 366*789Sahrens const char *prefix) 367*789Sahrens { 368*789Sahrens const char *cp; 369*789Sahrens size_t len = strlen(prefix); 370*789Sahrens 371*789Sahrens if ((cp = mdb_ctf_enum_name(id, val)) != NULL) { 372*789Sahrens if (strncmp(cp, prefix, len) == 0) 373*789Sahrens cp += len; 374*789Sahrens (void) strncpy(out, cp, size); 375*789Sahrens } else { 376*789Sahrens mdb_snprintf(out, size, "? (%d)", val); 377*789Sahrens } 378*789Sahrens } 379*789Sahrens 380*789Sahrens /* ARGSUSED */ 381*789Sahrens static int 382*789Sahrens zio_pipeline(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 383*789Sahrens { 384*789Sahrens mdb_ctf_id_t pipe_enum; 385*789Sahrens int i; 386*789Sahrens char stage[1024]; 387*789Sahrens 388*789Sahrens if (mdb_ctf_lookup_by_name("enum zio_stage", &pipe_enum) == -1) { 389*789Sahrens mdb_warn("Could not find enum zio_stage"); 390*789Sahrens return (DCMD_ERR); 391*789Sahrens } 392*789Sahrens 393*789Sahrens for (i = 0; i < 32; i++) { 394*789Sahrens if (addr & (1U << i)) { 395*789Sahrens enum_lookup(stage, sizeof (stage), pipe_enum, i, 396*789Sahrens "ZIO_STAGE_"); 397*789Sahrens mdb_printf(" %s\n", stage); 398*789Sahrens } 399*789Sahrens } 400*789Sahrens 401*789Sahrens return (DCMD_OK); 402*789Sahrens } 403*789Sahrens 404*789Sahrens /* ARGSUSED */ 405*789Sahrens static int 406*789Sahrens blkptr(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 407*789Sahrens { 408*789Sahrens blkptr_t bp; 409*789Sahrens dva_t *dva; 410*789Sahrens dmu_object_type_info_t *doti; 411*789Sahrens zio_compress_info_t *zct; 412*789Sahrens zio_checksum_info_t *zci; 413*789Sahrens int i; 414*789Sahrens char buf[MAXPATHLEN]; 415*789Sahrens 416*789Sahrens if (mdb_vread(&bp, sizeof (blkptr_t), addr) == -1) { 417*789Sahrens mdb_warn("failed to read blkptr_t"); 418*789Sahrens return (DCMD_ERR); 419*789Sahrens } 420*789Sahrens 421*789Sahrens if (read_symbol("dmu_ot", (void **)&doti) != DCMD_OK) 422*789Sahrens return (DCMD_ERR); 423*789Sahrens for (i = 0; i < DMU_OT_NUMTYPES; i++) { 424*789Sahrens mdb_readstr(buf, sizeof (buf), (uintptr_t)doti[i].ot_name); 425*789Sahrens doti[i].ot_name = local_strdup(buf); 426*789Sahrens } 427*789Sahrens 428*789Sahrens if (read_symbol("zio_checksum_table", (void **)&zci) != DCMD_OK) 429*789Sahrens return (DCMD_ERR); 430*789Sahrens for (i = 0; i < ZIO_CHECKSUM_FUNCTIONS; i++) { 431*789Sahrens mdb_readstr(buf, sizeof (buf), (uintptr_t)zci[i].ci_name); 432*789Sahrens zci[i].ci_name = local_strdup(buf); 433*789Sahrens } 434*789Sahrens 435*789Sahrens if (read_symbol("zio_compress_table", (void **)&zct) != DCMD_OK) 436*789Sahrens return (DCMD_ERR); 437*789Sahrens for (i = 0; i < ZIO_COMPRESS_FUNCTIONS; i++) { 438*789Sahrens mdb_readstr(buf, sizeof (buf), (uintptr_t)zct[i].ci_name); 439*789Sahrens zct[i].ci_name = local_strdup(buf); 440*789Sahrens } 441*789Sahrens 442*789Sahrens for (i = 0; i < SPA_DVAS_PER_BP; i++) { 443*789Sahrens dva = &bp.blk_dva[i]; 444*789Sahrens mdb_printf("DVA[%d]: vdev_id %lld / %llx\n", i, 445*789Sahrens DVA_GET_VDEV(dva), DVA_GET_OFFSET(dva)); 446*789Sahrens mdb_printf("DVA[%d]: GRID: %04x\t" 447*789Sahrens "ASIZE: %llx\n", i, DVA_GET_GRID(dva), DVA_GET_ASIZE(dva)); 448*789Sahrens } 449*789Sahrens mdb_printf("LSIZE: %-16llx\t\tPSIZE: %llx\n", 450*789Sahrens BP_GET_LSIZE(&bp), BP_GET_PSIZE(&bp)); 451*789Sahrens mdb_printf("ENDIAN: %6s GANG: %-5s\tTYPE: %s\n", 452*789Sahrens BP_GET_BYTEORDER(&bp) ? "LITTLE" : "BIG", 453*789Sahrens DVA_GET_GANG(dva) ? "TRUE" : "FALSE", 454*789Sahrens doti[BP_GET_TYPE(&bp)].ot_name); 455*789Sahrens mdb_printf("BIRTH: %-16llx LEVEL: %-2d\tFILL: %llx\n", 456*789Sahrens bp.blk_birth, BP_GET_LEVEL(&bp), bp.blk_fill); 457*789Sahrens mdb_printf("CKFUNC: %-16s\t\tCOMP: %s\n", 458*789Sahrens zci[BP_GET_CHECKSUM(&bp)].ci_name, 459*789Sahrens zct[BP_GET_COMPRESS(&bp)].ci_name); 460*789Sahrens mdb_printf("CKSUM: %llx:%llx:%llx:%llx\n", 461*789Sahrens bp.blk_cksum.zc_word[0], 462*789Sahrens bp.blk_cksum.zc_word[1], 463*789Sahrens bp.blk_cksum.zc_word[2], 464*789Sahrens bp.blk_cksum.zc_word[3]); 465*789Sahrens 466*789Sahrens return (DCMD_OK); 467*789Sahrens } 468*789Sahrens 469*789Sahrens /* ARGSUSED */ 470*789Sahrens static int 471*789Sahrens dbuf(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 472*789Sahrens { 473*789Sahrens mdb_ctf_id_t id; 474*789Sahrens dmu_buf_t db; 475*789Sahrens uintptr_t objset; 476*789Sahrens uint8_t level; 477*789Sahrens uint64_t blkid; 478*789Sahrens uint64_t holds; 479*789Sahrens char objectname[32]; 480*789Sahrens char blkidname[32]; 481*789Sahrens char path[MAXNAMELEN]; 482*789Sahrens 483*789Sahrens if (DCMD_HDRSPEC(flags)) { 484*789Sahrens mdb_printf(" addr object lvl blkid holds os\n"); 485*789Sahrens } 486*789Sahrens 487*789Sahrens if (mdb_ctf_lookup_by_name("struct dmu_buf_impl", &id) == -1) { 488*789Sahrens mdb_warn("couldn't find struct dmu_buf_impl_t"); 489*789Sahrens return (DCMD_ERR); 490*789Sahrens } 491*789Sahrens 492*789Sahrens if (GETMEMBID(addr, &id, db_objset, objset) || 493*789Sahrens GETMEMBID(addr, &id, db, db) || 494*789Sahrens GETMEMBID(addr, &id, db_level, level) || 495*789Sahrens GETMEMBID(addr, &id, db_blkid, blkid)) { 496*789Sahrens return (WALK_ERR); 497*789Sahrens } 498*789Sahrens 499*789Sahrens if (getrefcount(addr, &id, "db_holds", &holds)) { 500*789Sahrens return (WALK_ERR); 501*789Sahrens } 502*789Sahrens 503*789Sahrens if (db.db_object == DMU_META_DNODE_OBJECT) 504*789Sahrens (void) strcpy(objectname, "mdn"); 505*789Sahrens else 506*789Sahrens (void) mdb_snprintf(objectname, sizeof (objectname), "%llx", 507*789Sahrens (u_longlong_t)db.db_object); 508*789Sahrens 509*789Sahrens if (blkid == DB_BONUS_BLKID) 510*789Sahrens (void) strcpy(blkidname, "bonus"); 511*789Sahrens else 512*789Sahrens (void) mdb_snprintf(blkidname, sizeof (blkidname), "%llx", 513*789Sahrens (u_longlong_t)blkid); 514*789Sahrens 515*789Sahrens if (objset_name(objset, path)) { 516*789Sahrens return (WALK_ERR); 517*789Sahrens } 518*789Sahrens 519*789Sahrens mdb_printf("%p %8s %1u %9s %2llu %s\n", 520*789Sahrens addr, objectname, level, blkidname, holds, path); 521*789Sahrens 522*789Sahrens return (DCMD_OK); 523*789Sahrens } 524*789Sahrens 525*789Sahrens /* ARGSUSED */ 526*789Sahrens static int 527*789Sahrens dbuf_stats(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 528*789Sahrens { 529*789Sahrens #define HISTOSZ 32 530*789Sahrens uintptr_t dbp; 531*789Sahrens dmu_buf_impl_t db; 532*789Sahrens dbuf_hash_table_t ht; 533*789Sahrens uint64_t bucket, ndbufs; 534*789Sahrens uint64_t histo[HISTOSZ]; 535*789Sahrens uint64_t histo2[HISTOSZ]; 536*789Sahrens int i, maxidx; 537*789Sahrens 538*789Sahrens if (mdb_readvar(&ht, "dbuf_hash_table") == -1) { 539*789Sahrens mdb_warn("failed to read 'dbuf_hash_table'"); 540*789Sahrens return (DCMD_ERR); 541*789Sahrens } 542*789Sahrens 543*789Sahrens for (i = 0; i < HISTOSZ; i++) { 544*789Sahrens histo[i] = 0; 545*789Sahrens histo2[i] = 0; 546*789Sahrens } 547*789Sahrens 548*789Sahrens ndbufs = 0; 549*789Sahrens for (bucket = 0; bucket < ht.hash_table_mask+1; bucket++) { 550*789Sahrens int len; 551*789Sahrens 552*789Sahrens if (mdb_vread(&dbp, sizeof (void *), 553*789Sahrens (uintptr_t)(ht.hash_table+bucket)) == -1) { 554*789Sahrens mdb_warn("failed to read hash bucket %u at %p", 555*789Sahrens bucket, ht.hash_table+bucket); 556*789Sahrens return (DCMD_ERR); 557*789Sahrens } 558*789Sahrens 559*789Sahrens len = 0; 560*789Sahrens while (dbp != 0) { 561*789Sahrens if (mdb_vread(&db, sizeof (dmu_buf_impl_t), 562*789Sahrens dbp) == -1) { 563*789Sahrens mdb_warn("failed to read dbuf at %p", dbp); 564*789Sahrens return (DCMD_ERR); 565*789Sahrens } 566*789Sahrens dbp = (uintptr_t)db.db_hash_next; 567*789Sahrens for (i = MIN(len, HISTOSZ - 1); i >= 0; i--) 568*789Sahrens histo2[i]++; 569*789Sahrens len++; 570*789Sahrens ndbufs++; 571*789Sahrens } 572*789Sahrens 573*789Sahrens if (len >= HISTOSZ) 574*789Sahrens len = HISTOSZ-1; 575*789Sahrens histo[len]++; 576*789Sahrens } 577*789Sahrens 578*789Sahrens mdb_printf("hash table has %llu buckets, %llu dbufs " 579*789Sahrens "(avg %llu buckets/dbuf)\n", 580*789Sahrens ht.hash_table_mask+1, ndbufs, 581*789Sahrens (ht.hash_table_mask+1)/ndbufs); 582*789Sahrens 583*789Sahrens mdb_printf("\n"); 584*789Sahrens maxidx = 0; 585*789Sahrens for (i = 0; i < HISTOSZ; i++) 586*789Sahrens if (histo[i] > 0) 587*789Sahrens maxidx = i; 588*789Sahrens mdb_printf("hash chain length number of buckets\n"); 589*789Sahrens for (i = 0; i <= maxidx; i++) 590*789Sahrens mdb_printf("%u %llu\n", i, histo[i]); 591*789Sahrens 592*789Sahrens mdb_printf("\n"); 593*789Sahrens maxidx = 0; 594*789Sahrens for (i = 0; i < HISTOSZ; i++) 595*789Sahrens if (histo2[i] > 0) 596*789Sahrens maxidx = i; 597*789Sahrens mdb_printf("hash chain depth number of dbufs\n"); 598*789Sahrens for (i = 0; i <= maxidx; i++) 599*789Sahrens mdb_printf("%u or more %llu %llu%%\n", 600*789Sahrens i, histo2[i], histo2[i]*100/ndbufs); 601*789Sahrens 602*789Sahrens 603*789Sahrens return (DCMD_OK); 604*789Sahrens } 605*789Sahrens 606*789Sahrens typedef struct dbufs_data { 607*789Sahrens mdb_ctf_id_t id; 608*789Sahrens uint64_t objset; 609*789Sahrens uint64_t object; 610*789Sahrens uint64_t level; 611*789Sahrens uint64_t blkid; 612*789Sahrens char *osname; 613*789Sahrens } dbufs_data_t; 614*789Sahrens 615*789Sahrens #define DBUFS_UNSET (0xbaddcafedeadbeefULL) 616*789Sahrens 617*789Sahrens /* ARGSUSED */ 618*789Sahrens static int 619*789Sahrens dbufs_cb(uintptr_t addr, const void *unknown, void *arg) 620*789Sahrens { 621*789Sahrens dbufs_data_t *data = arg; 622*789Sahrens uintptr_t objset; 623*789Sahrens dmu_buf_t db; 624*789Sahrens uint8_t level; 625*789Sahrens uint64_t blkid; 626*789Sahrens char osname[MAXNAMELEN]; 627*789Sahrens 628*789Sahrens if (GETMEMBID(addr, &data->id, db_objset, objset) || 629*789Sahrens GETMEMBID(addr, &data->id, db, db) || 630*789Sahrens GETMEMBID(addr, &data->id, db_level, level) || 631*789Sahrens GETMEMBID(addr, &data->id, db_blkid, blkid)) { 632*789Sahrens return (WALK_ERR); 633*789Sahrens } 634*789Sahrens 635*789Sahrens if ((data->objset == DBUFS_UNSET || data->objset == objset) && 636*789Sahrens (data->osname == NULL || (objset_name(objset, osname) == 0 && 637*789Sahrens strcmp(data->osname, osname) == 0)) && 638*789Sahrens (data->object == DBUFS_UNSET || data->object == db.db_object) && 639*789Sahrens (data->level == DBUFS_UNSET || data->level == level) && 640*789Sahrens (data->blkid == DBUFS_UNSET || data->blkid == blkid)) { 641*789Sahrens mdb_printf("%#lr\n", addr); 642*789Sahrens } 643*789Sahrens return (WALK_NEXT); 644*789Sahrens } 645*789Sahrens 646*789Sahrens /* ARGSUSED */ 647*789Sahrens static int 648*789Sahrens dbufs(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 649*789Sahrens { 650*789Sahrens dbufs_data_t data; 651*789Sahrens char *object = NULL; 652*789Sahrens char *blkid = NULL; 653*789Sahrens 654*789Sahrens data.objset = data.object = data.level = data.blkid = DBUFS_UNSET; 655*789Sahrens data.osname = NULL; 656*789Sahrens 657*789Sahrens if (mdb_getopts(argc, argv, 658*789Sahrens 'O', MDB_OPT_UINT64, &data.objset, 659*789Sahrens 'n', MDB_OPT_STR, &data.osname, 660*789Sahrens 'o', MDB_OPT_STR, &object, 661*789Sahrens 'l', MDB_OPT_UINT64, &data.level, 662*789Sahrens 'b', MDB_OPT_STR, &blkid) != argc) { 663*789Sahrens return (DCMD_USAGE); 664*789Sahrens } 665*789Sahrens 666*789Sahrens if (object) { 667*789Sahrens if (strcmp(object, "mdn") == 0) { 668*789Sahrens data.object = DMU_META_DNODE_OBJECT; 669*789Sahrens } else { 670*789Sahrens data.object = mdb_strtoull(object); 671*789Sahrens } 672*789Sahrens } 673*789Sahrens 674*789Sahrens if (blkid) { 675*789Sahrens if (strcmp(blkid, "bonus") == 0) { 676*789Sahrens data.blkid = DB_BONUS_BLKID; 677*789Sahrens } else { 678*789Sahrens data.blkid = mdb_strtoull(blkid); 679*789Sahrens } 680*789Sahrens } 681*789Sahrens 682*789Sahrens if (mdb_ctf_lookup_by_name("struct dmu_buf_impl", &data.id) == -1) { 683*789Sahrens mdb_warn("couldn't find struct dmu_buf_impl_t"); 684*789Sahrens return (DCMD_ERR); 685*789Sahrens } 686*789Sahrens 687*789Sahrens if (mdb_pwalk("dbufs", dbufs_cb, &data, 0) != 0) { 688*789Sahrens mdb_warn("can't walk dbufs"); 689*789Sahrens return (DCMD_ERR); 690*789Sahrens } 691*789Sahrens 692*789Sahrens return (DCMD_OK); 693*789Sahrens } 694*789Sahrens 695*789Sahrens typedef struct abuf_find_data { 696*789Sahrens dva_t dva; 697*789Sahrens mdb_ctf_id_t id; 698*789Sahrens } abuf_find_data_t; 699*789Sahrens 700*789Sahrens /* ARGSUSED */ 701*789Sahrens static int 702*789Sahrens abuf_find_cb(uintptr_t addr, const void *unknown, void *arg) 703*789Sahrens { 704*789Sahrens abuf_find_data_t *data = arg; 705*789Sahrens dva_t dva; 706*789Sahrens 707*789Sahrens if (GETMEMBID(addr, &data->id, b_dva, dva)) { 708*789Sahrens return (WALK_ERR); 709*789Sahrens } 710*789Sahrens 711*789Sahrens if (dva.dva_word[0] == data->dva.dva_word[0] && 712*789Sahrens dva.dva_word[1] == data->dva.dva_word[1]) { 713*789Sahrens mdb_printf("%#lr\n", addr); 714*789Sahrens } 715*789Sahrens return (WALK_NEXT); 716*789Sahrens } 717*789Sahrens 718*789Sahrens /* ARGSUSED */ 719*789Sahrens static int 720*789Sahrens abuf_find(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 721*789Sahrens { 722*789Sahrens abuf_find_data_t data; 723*789Sahrens GElf_Sym sym; 724*789Sahrens int i; 725*789Sahrens const char *syms[] = { 726*789Sahrens "ARC_mru_top", 727*789Sahrens "ARC_mru_bot", 728*789Sahrens "ARC_mfu_top", 729*789Sahrens "ARC_mfu_bot", 730*789Sahrens }; 731*789Sahrens 732*789Sahrens if (argc != 2) 733*789Sahrens return (DCMD_USAGE); 734*789Sahrens 735*789Sahrens for (i = 0; i < 2; i ++) { 736*789Sahrens switch (argv[i].a_type) { 737*789Sahrens case MDB_TYPE_STRING: 738*789Sahrens data.dva.dva_word[i] = mdb_strtoull(argv[i].a_un.a_str); 739*789Sahrens break; 740*789Sahrens case MDB_TYPE_IMMEDIATE: 741*789Sahrens data.dva.dva_word[i] = argv[i].a_un.a_val; 742*789Sahrens break; 743*789Sahrens default: 744*789Sahrens return (DCMD_USAGE); 745*789Sahrens } 746*789Sahrens } 747*789Sahrens 748*789Sahrens if (mdb_ctf_lookup_by_name("struct arc_buf_hdr", &data.id) == -1) { 749*789Sahrens mdb_warn("couldn't find struct arc_buf_hdr"); 750*789Sahrens return (DCMD_ERR); 751*789Sahrens } 752*789Sahrens 753*789Sahrens for (i = 0; i < sizeof (syms) / sizeof (syms[0]); i++) { 754*789Sahrens if (mdb_lookup_by_name(syms[i], &sym)) { 755*789Sahrens mdb_warn("can't find symbol %s", syms[i]); 756*789Sahrens return (DCMD_ERR); 757*789Sahrens } 758*789Sahrens 759*789Sahrens if (mdb_pwalk("list", abuf_find_cb, &data, sym.st_value) != 0) { 760*789Sahrens mdb_warn("can't walk %s", syms[i]); 761*789Sahrens return (DCMD_ERR); 762*789Sahrens } 763*789Sahrens } 764*789Sahrens 765*789Sahrens return (DCMD_OK); 766*789Sahrens } 767*789Sahrens 768*789Sahrens void 769*789Sahrens abuf_help(void) 770*789Sahrens { 771*789Sahrens mdb_printf("::abuf_find dva_word[0] dva_word[1]\n"); 772*789Sahrens } 773*789Sahrens 774*789Sahrens /* 775*789Sahrens * ::spa 776*789Sahrens * 777*789Sahrens * -c Print configuration information as well 778*789Sahrens * -v Print vdev state 779*789Sahrens * -e Print vdev error stats 780*789Sahrens * 781*789Sahrens * Print a summarized spa_t. When given no arguments, prints out a table of all 782*789Sahrens * active pools on the system. 783*789Sahrens */ 784*789Sahrens /* ARGSUSED */ 785*789Sahrens static int 786*789Sahrens spa_print(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 787*789Sahrens { 788*789Sahrens spa_t spa; 789*789Sahrens char poolname[MAXNAMELEN]; 790*789Sahrens const char *statetab[] = { "ACTIVE", "EXPORTED", "DESTROYED", 791*789Sahrens "UNINIT", "UNAVAIL" }; 792*789Sahrens const char *state; 793*789Sahrens int config = FALSE; 794*789Sahrens int vdevs = FALSE; 795*789Sahrens int errors = FALSE; 796*789Sahrens 797*789Sahrens if (mdb_getopts(argc, argv, 798*789Sahrens 'c', MDB_OPT_SETBITS, TRUE, &config, 799*789Sahrens 'v', MDB_OPT_SETBITS, TRUE, &vdevs, 800*789Sahrens 'e', MDB_OPT_SETBITS, TRUE, &errors, 801*789Sahrens NULL) != argc) 802*789Sahrens return (DCMD_USAGE); 803*789Sahrens 804*789Sahrens if (!(flags & DCMD_ADDRSPEC)) { 805*789Sahrens if (mdb_walk_dcmd("spa", "spa", argc, argv) == -1) { 806*789Sahrens mdb_warn("can't walk spa"); 807*789Sahrens return (DCMD_ERR); 808*789Sahrens } 809*789Sahrens 810*789Sahrens return (DCMD_OK); 811*789Sahrens } 812*789Sahrens 813*789Sahrens if (flags & DCMD_PIPE_OUT) { 814*789Sahrens mdb_printf("%#lr\n", addr); 815*789Sahrens return (DCMD_OK); 816*789Sahrens } 817*789Sahrens 818*789Sahrens if (DCMD_HDRSPEC(flags)) 819*789Sahrens mdb_printf("%<u>%-?s %9s %-*s%</u>\n", "ADDR", "STATE", 820*789Sahrens sizeof (uintptr_t) == 4 ? 60 : 52, "NAME"); 821*789Sahrens 822*789Sahrens if (mdb_vread(&spa, sizeof (spa), addr) == -1) { 823*789Sahrens mdb_warn("failed to read spa_t at %p", addr); 824*789Sahrens return (DCMD_ERR); 825*789Sahrens } 826*789Sahrens 827*789Sahrens if (mdb_readstr(poolname, sizeof (poolname), (uintptr_t)spa.spa_name) 828*789Sahrens == -1) { 829*789Sahrens mdb_warn("failed to read pool name at %p", spa.spa_name); 830*789Sahrens return (DCMD_ERR); 831*789Sahrens } 832*789Sahrens 833*789Sahrens if (spa.spa_state < 0 || spa.spa_state > POOL_STATE_UNAVAIL) 834*789Sahrens state = "UKNNOWN"; 835*789Sahrens else 836*789Sahrens state = statetab[spa.spa_state]; 837*789Sahrens 838*789Sahrens mdb_printf("%0?p %9s %s\n", addr, state, poolname); 839*789Sahrens 840*789Sahrens if (config) { 841*789Sahrens mdb_printf("\n"); 842*789Sahrens mdb_inc_indent(4); 843*789Sahrens if (mdb_call_dcmd("spa_config", addr, flags, 0, 844*789Sahrens NULL) != DCMD_OK) 845*789Sahrens return (DCMD_ERR); 846*789Sahrens mdb_dec_indent(4); 847*789Sahrens } 848*789Sahrens 849*789Sahrens if (vdevs || errors) { 850*789Sahrens mdb_arg_t v; 851*789Sahrens 852*789Sahrens v.a_type = MDB_TYPE_STRING; 853*789Sahrens v.a_un.a_str = "-e"; 854*789Sahrens 855*789Sahrens mdb_printf("\n"); 856*789Sahrens mdb_inc_indent(4); 857*789Sahrens if (mdb_call_dcmd("spa_vdevs", addr, flags, errors ? 1 : 0, 858*789Sahrens &v) != DCMD_OK) 859*789Sahrens return (DCMD_ERR); 860*789Sahrens mdb_dec_indent(4); 861*789Sahrens } 862*789Sahrens 863*789Sahrens return (DCMD_OK); 864*789Sahrens } 865*789Sahrens 866*789Sahrens /* 867*789Sahrens * ::spa_config 868*789Sahrens * 869*789Sahrens * Given a spa_t, print the configuration information stored in spa_config. 870*789Sahrens * Since it's just an nvlist, format it as an indented list of name=value pairs. 871*789Sahrens * We simply read the value of spa_config and pass off to ::nvlist. 872*789Sahrens */ 873*789Sahrens /* ARGSUSED */ 874*789Sahrens static int 875*789Sahrens spa_print_config(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 876*789Sahrens { 877*789Sahrens spa_t spa; 878*789Sahrens 879*789Sahrens if (argc != 0 || !(flags & DCMD_ADDRSPEC)) 880*789Sahrens return (DCMD_USAGE); 881*789Sahrens 882*789Sahrens if (mdb_vread(&spa, sizeof (spa), addr) == -1) { 883*789Sahrens mdb_warn("failed to read spa_t at %p", addr); 884*789Sahrens return (DCMD_ERR); 885*789Sahrens } 886*789Sahrens 887*789Sahrens if (spa.spa_config == NULL) { 888*789Sahrens mdb_printf("(none)\n"); 889*789Sahrens return (DCMD_OK); 890*789Sahrens } 891*789Sahrens 892*789Sahrens return (mdb_call_dcmd("nvlist", (uintptr_t)spa.spa_config, flags, 893*789Sahrens 0, NULL)); 894*789Sahrens } 895*789Sahrens 896*789Sahrens void 897*789Sahrens vdev_help(void) 898*789Sahrens { 899*789Sahrens mdb_printf("[vdev_t*]::vdev [-qr]\n" 900*789Sahrens "\t-> -q display vdev_queue parameters\n" 901*789Sahrens "\t-> -r recursive (visit all children)\n"); 902*789Sahrens } 903*789Sahrens 904*789Sahrens /* 905*789Sahrens * ::vdev 906*789Sahrens * 907*789Sahrens * Print out a summarized vdev_t, in the following form: 908*789Sahrens * 909*789Sahrens * ADDR STATE AUX DESC 910*789Sahrens * fffffffbcde23df0 HEALTHY - /dev/dsk/c0t0d0 911*789Sahrens * 912*789Sahrens * or with "-q" to print out a vdev_t's vdev_queue parameters: 913*789Sahrens * 914*789Sahrens * vdev_t: c26ae4c0 915*789Sahrens * c26ae73c min pending 0x2 916*789Sahrens * c26ae744 max pending 0x23 917*789Sahrens * c26ae74c agg limit 0x20000 918*789Sahrens * c26ae754 time shift 0x4 919*789Sahrens * c26ae75c ramp rate 0x2 920*789Sahrens * 921*789Sahrens * If '-r' is specified, recursively visit all children. 922*789Sahrens * 923*789Sahrens * With '-e', the statistics associated with the vdev are printed as well. 924*789Sahrens */ 925*789Sahrens static int 926*789Sahrens do_print_vdev(uintptr_t addr, int flags, int depth, int queue, int stats, 927*789Sahrens int recursive) 928*789Sahrens { 929*789Sahrens vdev_t vdev; 930*789Sahrens char desc[MAXNAMELEN]; 931*789Sahrens int c, children; 932*789Sahrens uintptr_t *child; 933*789Sahrens const char *state, *aux; 934*789Sahrens 935*789Sahrens if (mdb_vread(&vdev, sizeof (vdev), (uintptr_t)addr) == -1) { 936*789Sahrens mdb_warn("failed to read vdev_t at %p\n", (uintptr_t)addr); 937*789Sahrens return (DCMD_ERR); 938*789Sahrens } 939*789Sahrens 940*789Sahrens if (flags & DCMD_PIPE_OUT) { 941*789Sahrens mdb_printf("%#lr", addr); 942*789Sahrens } else { 943*789Sahrens if (vdev.vdev_path != NULL) { 944*789Sahrens if (mdb_readstr(desc, sizeof (desc), 945*789Sahrens (uintptr_t)vdev.vdev_path) == -1) { 946*789Sahrens mdb_warn("failed to read vdev_path at %p\n", 947*789Sahrens vdev.vdev_path); 948*789Sahrens return (DCMD_ERR); 949*789Sahrens } 950*789Sahrens } else if (vdev.vdev_ops != NULL) { 951*789Sahrens vdev_ops_t ops; 952*789Sahrens if (mdb_vread(&ops, sizeof (ops), 953*789Sahrens (uintptr_t)vdev.vdev_ops) == -1) { 954*789Sahrens mdb_warn("failed to read vdev_ops at %p\n", 955*789Sahrens vdev.vdev_ops); 956*789Sahrens return (DCMD_ERR); 957*789Sahrens } 958*789Sahrens (void) strcpy(desc, ops.vdev_op_type); 959*789Sahrens } else { 960*789Sahrens (void) strcpy(desc, "<unknown>"); 961*789Sahrens } 962*789Sahrens 963*789Sahrens if (depth == 0 && DCMD_HDRSPEC(flags)) 964*789Sahrens mdb_printf("%<u>%-?s %-9s %-12s %-*s%</u>\n", 965*789Sahrens "ADDR", "STATE", "AUX", 966*789Sahrens sizeof (uintptr_t) == 4 ? 43 : 35, 967*789Sahrens "DESCRIPTION"); 968*789Sahrens 969*789Sahrens mdb_printf("%0?p ", addr); 970*789Sahrens 971*789Sahrens switch (vdev.vdev_state) { 972*789Sahrens case VDEV_STATE_CLOSED: 973*789Sahrens state = "CLOSED"; 974*789Sahrens break; 975*789Sahrens case VDEV_STATE_OFFLINE: 976*789Sahrens state = "OFFLINE"; 977*789Sahrens break; 978*789Sahrens case VDEV_STATE_CANT_OPEN: 979*789Sahrens state = "CANT_OPEN"; 980*789Sahrens break; 981*789Sahrens case VDEV_STATE_DEGRADED: 982*789Sahrens state = "DEGRADED"; 983*789Sahrens break; 984*789Sahrens case VDEV_STATE_HEALTHY: 985*789Sahrens state = "HEALTHY"; 986*789Sahrens break; 987*789Sahrens default: 988*789Sahrens state = "UNKNOWN"; 989*789Sahrens break; 990*789Sahrens } 991*789Sahrens 992*789Sahrens switch (vdev.vdev_stat.vs_aux) { 993*789Sahrens case VDEV_AUX_NONE: 994*789Sahrens aux = "-"; 995*789Sahrens break; 996*789Sahrens case VDEV_AUX_OPEN_FAILED: 997*789Sahrens aux = "OPEN_FAILED"; 998*789Sahrens break; 999*789Sahrens case VDEV_AUX_CORRUPT_DATA: 1000*789Sahrens aux = "CORRUPT_DATA"; 1001*789Sahrens break; 1002*789Sahrens case VDEV_AUX_NO_REPLICAS: 1003*789Sahrens aux = "NO_REPLICAS"; 1004*789Sahrens break; 1005*789Sahrens case VDEV_AUX_BAD_GUID_SUM: 1006*789Sahrens aux = "BAD_GUID_SUM"; 1007*789Sahrens break; 1008*789Sahrens case VDEV_AUX_TOO_SMALL: 1009*789Sahrens aux = "TOO_SMALL"; 1010*789Sahrens break; 1011*789Sahrens case VDEV_AUX_BAD_LABEL: 1012*789Sahrens aux = "BAD_LABEL"; 1013*789Sahrens break; 1014*789Sahrens default: 1015*789Sahrens aux = "UNKNOWN"; 1016*789Sahrens break; 1017*789Sahrens } 1018*789Sahrens 1019*789Sahrens mdb_printf("%-9s %-12s %*s%s\n", state, aux, depth, "", desc); 1020*789Sahrens 1021*789Sahrens if (queue) { 1022*789Sahrens mdb_inc_indent(4); 1023*789Sahrens mdb_printf("\n"); 1024*789Sahrens mdb_printf("%p min pending 0x%llx\n", 1025*789Sahrens (uintptr_t)(addr + offsetof(vdev_t, 1026*789Sahrens vdev_queue.vq_min_pending)), 1027*789Sahrens vdev.vdev_queue.vq_min_pending); 1028*789Sahrens mdb_printf("%p max pending 0x%llx\n", 1029*789Sahrens (uintptr_t)(addr + offsetof(vdev_t, 1030*789Sahrens vdev_queue.vq_max_pending)), 1031*789Sahrens vdev.vdev_queue.vq_max_pending); 1032*789Sahrens mdb_printf("%p agg limit 0x%llx\n", 1033*789Sahrens (uintptr_t)(addr + offsetof(vdev_t, 1034*789Sahrens vdev_queue.vq_agg_limit)), 1035*789Sahrens vdev.vdev_queue.vq_agg_limit); 1036*789Sahrens mdb_printf("%p time shift 0x%llx\n", 1037*789Sahrens (uintptr_t)(addr + offsetof(vdev_t, 1038*789Sahrens vdev_queue.vq_time_shift)), 1039*789Sahrens vdev.vdev_queue.vq_time_shift); 1040*789Sahrens mdb_printf("%p ramp rate 0x%llx\n", 1041*789Sahrens (uintptr_t)(addr + offsetof(vdev_t, 1042*789Sahrens vdev_queue.vq_ramp_rate)), 1043*789Sahrens vdev.vdev_queue.vq_ramp_rate); 1044*789Sahrens mdb_dec_indent(4); 1045*789Sahrens } 1046*789Sahrens 1047*789Sahrens if (stats) { 1048*789Sahrens vdev_stat_t *vs = &vdev.vdev_stat; 1049*789Sahrens int i; 1050*789Sahrens 1051*789Sahrens mdb_inc_indent(4); 1052*789Sahrens mdb_printf("\n"); 1053*789Sahrens mdb_printf("%<u> %12s %12s %12s %12s " 1054*789Sahrens "%12s%</u>\n", "READ", "WRITE", "FREE", "CLAIM", 1055*789Sahrens "IOCTL"); 1056*789Sahrens mdb_printf("OPS "); 1057*789Sahrens for (i = 1; i < ZIO_TYPES; i++) 1058*789Sahrens mdb_printf("%11#llx%s", vs->vs_ops[i], 1059*789Sahrens i == ZIO_TYPES - 1 ? "" : " "); 1060*789Sahrens mdb_printf("\n"); 1061*789Sahrens mdb_printf("BYTES "); 1062*789Sahrens for (i = 1; i < ZIO_TYPES; i++) 1063*789Sahrens mdb_printf("%11#llx%s", vs->vs_bytes[i], 1064*789Sahrens i == ZIO_TYPES - 1 ? "" : " "); 1065*789Sahrens 1066*789Sahrens 1067*789Sahrens mdb_printf("\n"); 1068*789Sahrens mdb_printf("EREAD %10#llx\n", vs->vs_read_errors); 1069*789Sahrens mdb_printf("EWRITE %10#llx\n", vs->vs_write_errors); 1070*789Sahrens mdb_printf("ECKSUM %10#llx\n", 1071*789Sahrens vs->vs_checksum_errors); 1072*789Sahrens mdb_dec_indent(4); 1073*789Sahrens } 1074*789Sahrens 1075*789Sahrens if (queue || stats) 1076*789Sahrens mdb_printf("\n"); 1077*789Sahrens } 1078*789Sahrens 1079*789Sahrens children = vdev.vdev_children; 1080*789Sahrens 1081*789Sahrens if (children == 0 || !recursive) 1082*789Sahrens return (DCMD_OK); 1083*789Sahrens 1084*789Sahrens child = mdb_alloc(children * sizeof (void *), UM_SLEEP | UM_GC); 1085*789Sahrens if (mdb_vread(child, children * sizeof (void *), 1086*789Sahrens (uintptr_t)vdev.vdev_child) == -1) { 1087*789Sahrens mdb_warn("failed to read vdev children at %p", vdev.vdev_child); 1088*789Sahrens return (DCMD_ERR); 1089*789Sahrens } 1090*789Sahrens 1091*789Sahrens for (c = 0; c < children; c++) { 1092*789Sahrens if (do_print_vdev(child[c], flags, depth + 2, queue, stats, 1093*789Sahrens recursive)) 1094*789Sahrens return (DCMD_ERR); 1095*789Sahrens } 1096*789Sahrens 1097*789Sahrens return (DCMD_OK); 1098*789Sahrens } 1099*789Sahrens 1100*789Sahrens static int 1101*789Sahrens vdev_print(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 1102*789Sahrens { 1103*789Sahrens int print_queue = FALSE; 1104*789Sahrens int recursive = FALSE; 1105*789Sahrens int stats = FALSE; 1106*789Sahrens 1107*789Sahrens if (mdb_getopts(argc, argv, 1108*789Sahrens 'q', MDB_OPT_SETBITS, TRUE, &print_queue, 1109*789Sahrens 'r', MDB_OPT_SETBITS, TRUE, &recursive, 1110*789Sahrens 'e', MDB_OPT_SETBITS, TRUE, &stats, 1111*789Sahrens NULL) != argc) 1112*789Sahrens return (DCMD_USAGE); 1113*789Sahrens 1114*789Sahrens if (!(flags & DCMD_ADDRSPEC)) { 1115*789Sahrens mdb_warn("no vdev_t address given\n"); 1116*789Sahrens return (DCMD_ERR); 1117*789Sahrens } 1118*789Sahrens 1119*789Sahrens return (do_print_vdev(addr, flags, 0, print_queue, stats, recursive)); 1120*789Sahrens } 1121*789Sahrens 1122*789Sahrens typedef struct mdb_spa { 1123*789Sahrens uintptr_t spa_dsl_pool; 1124*789Sahrens uintptr_t spa_root_vdev; 1125*789Sahrens } mdb_spa_t; 1126*789Sahrens 1127*789Sahrens typedef struct mdb_dsl_dir { 1128*789Sahrens uintptr_t dd_phys; 1129*789Sahrens uint64_t dd_used_bytes; 1130*789Sahrens int64_t dd_space_towrite[TXG_SIZE]; 1131*789Sahrens } mdb_dsl_dir_t; 1132*789Sahrens 1133*789Sahrens typedef struct mdb_dsl_dir_phys { 1134*789Sahrens uint64_t dd_used_bytes; 1135*789Sahrens uint64_t dd_compressed_bytes; 1136*789Sahrens uint64_t dd_uncompressed_bytes; 1137*789Sahrens } mdb_dsl_dir_phys_t; 1138*789Sahrens 1139*789Sahrens typedef struct mdb_vdev { 1140*789Sahrens uintptr_t vdev_parent; 1141*789Sahrens uintptr_t vdev_ms; 1142*789Sahrens uint64_t vdev_ms_count; 1143*789Sahrens vdev_stat_t vdev_stat; 1144*789Sahrens } mdb_vdev_t; 1145*789Sahrens 1146*789Sahrens typedef struct mdb_metaslab { 1147*789Sahrens space_map_t ms_allocmap[TXG_SIZE]; 1148*789Sahrens space_map_t ms_freemap[TXG_SIZE]; 1149*789Sahrens space_map_t ms_map; 1150*789Sahrens uint64_t ms_usable_space; 1151*789Sahrens } mdb_metaslab_t; 1152*789Sahrens 1153*789Sahrens /* 1154*789Sahrens * ::spa_space [-b] 1155*789Sahrens * 1156*789Sahrens * Given a spa_t, print out it's on-disk space usage and in-core 1157*789Sahrens * estimates of future usage. If -b is given, print space in bytes. 1158*789Sahrens * Otherwise print in megabytes. 1159*789Sahrens */ 1160*789Sahrens /* ARGSUSED */ 1161*789Sahrens static int 1162*789Sahrens spa_space(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 1163*789Sahrens { 1164*789Sahrens mdb_spa_t spa; 1165*789Sahrens uintptr_t dp_root_dir; 1166*789Sahrens mdb_dsl_dir_t dd; 1167*789Sahrens mdb_dsl_dir_phys_t dsp; 1168*789Sahrens uint64_t children; 1169*789Sahrens uintptr_t childaddr; 1170*789Sahrens uintptr_t *child; 1171*789Sahrens uint64_t ms_allocmap[TXG_SIZE] = {0, 0, 0, 0}; 1172*789Sahrens uint64_t ms_freemap[TXG_SIZE] = {0, 0, 0, 0}; 1173*789Sahrens uint64_t ms_map = 0; 1174*789Sahrens uint64_t ms_usable_space = 0; 1175*789Sahrens int i, j; 1176*789Sahrens int havecompressed = TRUE; 1177*789Sahrens int shift = 20; 1178*789Sahrens char *suffix = "M"; 1179*789Sahrens int bits = FALSE; 1180*789Sahrens 1181*789Sahrens if (mdb_getopts(argc, argv, 'b', MDB_OPT_SETBITS, TRUE, &bits, NULL) != 1182*789Sahrens argc) 1183*789Sahrens return (DCMD_USAGE); 1184*789Sahrens if (!(flags & DCMD_ADDRSPEC)) 1185*789Sahrens return (DCMD_USAGE); 1186*789Sahrens 1187*789Sahrens if (bits) { 1188*789Sahrens shift = 0; 1189*789Sahrens suffix = ""; 1190*789Sahrens } 1191*789Sahrens 1192*789Sahrens if (GETMEMB(addr, struct spa, spa_dsl_pool, spa.spa_dsl_pool) || 1193*789Sahrens GETMEMB(addr, struct spa, spa_root_vdev, spa.spa_root_vdev) || 1194*789Sahrens GETMEMB(spa.spa_root_vdev, struct vdev, vdev_children, children) || 1195*789Sahrens GETMEMB(spa.spa_root_vdev, struct vdev, vdev_child, childaddr) || 1196*789Sahrens GETMEMB(spa.spa_dsl_pool, struct dsl_pool, 1197*789Sahrens dp_root_dir, dp_root_dir) || 1198*789Sahrens GETMEMB(dp_root_dir, struct dsl_dir, dd_phys, dd.dd_phys) || 1199*789Sahrens GETMEMB(dp_root_dir, struct dsl_dir, 1200*789Sahrens dd_used_bytes, dd.dd_used_bytes) || 1201*789Sahrens GETMEMB(dp_root_dir, struct dsl_dir, 1202*789Sahrens dd_space_towrite, dd.dd_space_towrite) || 1203*789Sahrens GETMEMB(dd.dd_phys, struct dsl_dir_phys, 1204*789Sahrens dd_used_bytes, dsp.dd_used_bytes)) { 1205*789Sahrens return (DCMD_ERR); 1206*789Sahrens } 1207*789Sahrens 1208*789Sahrens if (GETMEMB(dd.dd_phys, struct dsl_dir_phys, 1209*789Sahrens dd_compressed_bytes, dsp.dd_compressed_bytes) || 1210*789Sahrens GETMEMB(dd.dd_phys, struct dsl_dir_phys, 1211*789Sahrens dd_uncompressed_bytes, dsp.dd_uncompressed_bytes)) { 1212*789Sahrens havecompressed = FALSE; 1213*789Sahrens } 1214*789Sahrens 1215*789Sahrens child = mdb_alloc(children * sizeof (void *), UM_SLEEP | UM_GC); 1216*789Sahrens if (mdb_vread(child, children * sizeof (void *), childaddr) == -1) { 1217*789Sahrens mdb_warn("failed to read root vdev children at %p", childaddr); 1218*789Sahrens return (DCMD_ERR); 1219*789Sahrens } 1220*789Sahrens 1221*789Sahrens mdb_printf("dd_space_towrite = %llu%s %llu%s %llu%s %llu%s\n", 1222*789Sahrens dd.dd_space_towrite[0] >> shift, suffix, 1223*789Sahrens dd.dd_space_towrite[1] >> shift, suffix, 1224*789Sahrens dd.dd_space_towrite[2] >> shift, suffix, 1225*789Sahrens dd.dd_space_towrite[3] >> shift, suffix); 1226*789Sahrens mdb_printf("dd_used_bytes = %llu%s\n", 1227*789Sahrens dd.dd_used_bytes >> shift, suffix); 1228*789Sahrens 1229*789Sahrens mdb_printf("dd_phys.dd_used_bytes = %llu%s\n", 1230*789Sahrens dsp.dd_used_bytes >> shift, suffix); 1231*789Sahrens if (havecompressed) { 1232*789Sahrens mdb_printf("dd_phys.dd_compressed_bytes = %llu%s\n", 1233*789Sahrens dsp.dd_compressed_bytes >> shift, suffix); 1234*789Sahrens mdb_printf("dd_phys.dd_uncompressed_bytes = %llu%s\n", 1235*789Sahrens dsp.dd_uncompressed_bytes >> shift, suffix); 1236*789Sahrens } 1237*789Sahrens 1238*789Sahrens for (i = 0; i < children; i++) { 1239*789Sahrens mdb_vdev_t vd; 1240*789Sahrens uintptr_t *vdev_ms; 1241*789Sahrens 1242*789Sahrens if (GETMEMB(child[i], struct vdev, 1243*789Sahrens vdev_parent, vd.vdev_parent) || 1244*789Sahrens GETMEMB(child[i], struct vdev, 1245*789Sahrens vdev_stat, vd.vdev_stat) || 1246*789Sahrens GETMEMB(child[i], struct vdev, vdev_ms, vd.vdev_ms) || 1247*789Sahrens GETMEMB(child[i], struct vdev, 1248*789Sahrens vdev_ms_count, vd.vdev_ms_count)) { 1249*789Sahrens return (DCMD_ERR); 1250*789Sahrens } 1251*789Sahrens 1252*789Sahrens /* 1253*789Sahrens * If this is the root vdev, its stats are the pool-wide stats. 1254*789Sahrens */ 1255*789Sahrens if (vd.vdev_parent == NULL) { 1256*789Sahrens mdb_printf("pool_alloc = %llu%s\n", 1257*789Sahrens vd.vdev_stat.vs_alloc >> shift, suffix); 1258*789Sahrens mdb_printf("pool_space = %llu%s\n", 1259*789Sahrens vd.vdev_stat.vs_space >> shift, suffix); 1260*789Sahrens } 1261*789Sahrens 1262*789Sahrens /* 1263*789Sahrens * If this is not a top-level vdev, it doesn't have space. 1264*789Sahrens */ 1265*789Sahrens if (vd.vdev_parent != spa.spa_root_vdev) 1266*789Sahrens continue; 1267*789Sahrens 1268*789Sahrens vdev_ms = mdb_alloc(vd.vdev_ms_count * sizeof (void*), 1269*789Sahrens UM_SLEEP | UM_GC); 1270*789Sahrens if (mdb_vread(vdev_ms, vd.vdev_ms_count * sizeof (void*), 1271*789Sahrens (uintptr_t)vd.vdev_ms) == -1) { 1272*789Sahrens mdb_warn("failed to read vdev_ms at %p", vd.vdev_ms); 1273*789Sahrens return (DCMD_ERR); 1274*789Sahrens } 1275*789Sahrens 1276*789Sahrens for (j = 0; j < vd.vdev_ms_count; j++) { 1277*789Sahrens mdb_metaslab_t ms; 1278*789Sahrens 1279*789Sahrens if (GETMEMB(vdev_ms[j], struct metaslab, 1280*789Sahrens ms_allocmap, ms.ms_allocmap) || 1281*789Sahrens GETMEMB(vdev_ms[j], struct metaslab, 1282*789Sahrens ms_freemap, ms.ms_freemap) || 1283*789Sahrens GETMEMB(vdev_ms[j], struct metaslab, 1284*789Sahrens ms_map, ms.ms_map) || 1285*789Sahrens GETMEMB(vdev_ms[j], struct metaslab, 1286*789Sahrens ms_usable_space, ms.ms_usable_space)) { 1287*789Sahrens return (DCMD_ERR); 1288*789Sahrens } 1289*789Sahrens 1290*789Sahrens ms_allocmap[0] += ms.ms_allocmap[0].sm_space; 1291*789Sahrens ms_allocmap[1] += ms.ms_allocmap[1].sm_space; 1292*789Sahrens ms_allocmap[2] += ms.ms_allocmap[2].sm_space; 1293*789Sahrens ms_allocmap[3] += ms.ms_allocmap[3].sm_space; 1294*789Sahrens ms_freemap[0] += ms.ms_freemap[0].sm_space; 1295*789Sahrens ms_freemap[1] += ms.ms_freemap[1].sm_space; 1296*789Sahrens ms_freemap[2] += ms.ms_freemap[2].sm_space; 1297*789Sahrens ms_freemap[3] += ms.ms_freemap[3].sm_space; 1298*789Sahrens ms_map += ms.ms_map.sm_space; 1299*789Sahrens ms_usable_space += ms.ms_usable_space; 1300*789Sahrens } 1301*789Sahrens } 1302*789Sahrens 1303*789Sahrens mdb_printf("ms_allocmap = %llu%s %llu%s %llu%s %llu%s\n", 1304*789Sahrens ms_allocmap[0] >> shift, suffix, 1305*789Sahrens ms_allocmap[1] >> shift, suffix, 1306*789Sahrens ms_allocmap[2] >> shift, suffix, 1307*789Sahrens ms_allocmap[3] >> shift, suffix); 1308*789Sahrens mdb_printf("ms_freemap = %llu%s %llu%s %llu%s %llu%s\n", 1309*789Sahrens ms_freemap[0] >> shift, suffix, 1310*789Sahrens ms_freemap[1] >> shift, suffix, 1311*789Sahrens ms_freemap[2] >> shift, suffix, 1312*789Sahrens ms_freemap[3] >> shift, suffix); 1313*789Sahrens mdb_printf("ms_map = %llu%s\n", ms_map >> shift, suffix); 1314*789Sahrens mdb_printf("ms_usable_space = %llu%s\n", 1315*789Sahrens ms_usable_space >> shift, suffix); 1316*789Sahrens 1317*789Sahrens return (DCMD_OK); 1318*789Sahrens } 1319*789Sahrens 1320*789Sahrens /* 1321*789Sahrens * ::spa_verify 1322*789Sahrens * 1323*789Sahrens * Given a spa_t, verify that that the pool is self-consistent. 1324*789Sahrens * Currently, it only checks to make sure that the vdev tree exists. 1325*789Sahrens */ 1326*789Sahrens /* ARGSUSED */ 1327*789Sahrens static int 1328*789Sahrens spa_verify(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 1329*789Sahrens { 1330*789Sahrens spa_t spa; 1331*789Sahrens 1332*789Sahrens if (argc != 0 || !(flags & DCMD_ADDRSPEC)) 1333*789Sahrens return (DCMD_USAGE); 1334*789Sahrens 1335*789Sahrens if (mdb_vread(&spa, sizeof (spa), addr) == -1) { 1336*789Sahrens mdb_warn("failed to read spa_t at %p", addr); 1337*789Sahrens return (DCMD_ERR); 1338*789Sahrens } 1339*789Sahrens 1340*789Sahrens if (spa.spa_root_vdev == NULL) { 1341*789Sahrens mdb_printf("no vdev tree present\n"); 1342*789Sahrens return (DCMD_OK); 1343*789Sahrens } 1344*789Sahrens 1345*789Sahrens return (DCMD_OK); 1346*789Sahrens } 1347*789Sahrens 1348*789Sahrens /* 1349*789Sahrens * ::spa_vdevs 1350*789Sahrens * 1351*789Sahrens * -e Include error stats 1352*789Sahrens * 1353*789Sahrens * Print out a summarized list of vdevs for the given spa_t. 1354*789Sahrens * This is accomplished by invoking "::vdev -re" on the root vdev. 1355*789Sahrens */ 1356*789Sahrens /* ARGSUSED */ 1357*789Sahrens static int 1358*789Sahrens spa_vdevs(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 1359*789Sahrens { 1360*789Sahrens spa_t spa; 1361*789Sahrens mdb_arg_t v; 1362*789Sahrens int errors = FALSE; 1363*789Sahrens 1364*789Sahrens if (mdb_getopts(argc, argv, 1365*789Sahrens 'e', MDB_OPT_SETBITS, TRUE, &errors, 1366*789Sahrens NULL) != argc) 1367*789Sahrens return (DCMD_USAGE); 1368*789Sahrens 1369*789Sahrens if (!(flags & DCMD_ADDRSPEC)) 1370*789Sahrens return (DCMD_USAGE); 1371*789Sahrens 1372*789Sahrens if (mdb_vread(&spa, sizeof (spa), addr) == -1) { 1373*789Sahrens mdb_warn("failed to read spa_t at %p", addr); 1374*789Sahrens return (DCMD_ERR); 1375*789Sahrens } 1376*789Sahrens 1377*789Sahrens v.a_type = MDB_TYPE_STRING; 1378*789Sahrens v.a_un.a_str = errors ? "-re" : "-r"; 1379*789Sahrens 1380*789Sahrens return (mdb_call_dcmd("vdev", (uintptr_t)spa.spa_root_vdev, 1381*789Sahrens flags, 1, &v)); 1382*789Sahrens } 1383*789Sahrens 1384*789Sahrens typedef struct txg_list_walk_data { 1385*789Sahrens uintptr_t lw_head[TXG_SIZE]; 1386*789Sahrens int lw_txgoff; 1387*789Sahrens int lw_maxoff; 1388*789Sahrens size_t lw_offset; 1389*789Sahrens void *lw_obj; 1390*789Sahrens } txg_list_walk_data_t; 1391*789Sahrens 1392*789Sahrens static int 1393*789Sahrens txg_list_walk_init_common(mdb_walk_state_t *wsp, int txg, int maxoff) 1394*789Sahrens { 1395*789Sahrens txg_list_walk_data_t *lwd; 1396*789Sahrens txg_list_t list; 1397*789Sahrens int i; 1398*789Sahrens 1399*789Sahrens lwd = mdb_alloc(sizeof (txg_list_walk_data_t), UM_SLEEP | UM_GC); 1400*789Sahrens if (mdb_vread(&list, sizeof (txg_list_t), wsp->walk_addr) == -1) { 1401*789Sahrens mdb_warn("failed to read txg_list_t at %#lx", wsp->walk_addr); 1402*789Sahrens return (WALK_ERR); 1403*789Sahrens } 1404*789Sahrens 1405*789Sahrens for (i = 0; i < TXG_SIZE; i++) 1406*789Sahrens lwd->lw_head[i] = (uintptr_t)list.tl_head[i]; 1407*789Sahrens lwd->lw_offset = list.tl_offset; 1408*789Sahrens lwd->lw_obj = mdb_alloc(lwd->lw_offset + sizeof (txg_node_t), 1409*789Sahrens UM_SLEEP | UM_GC); 1410*789Sahrens lwd->lw_txgoff = txg; 1411*789Sahrens lwd->lw_maxoff = maxoff; 1412*789Sahrens 1413*789Sahrens wsp->walk_addr = lwd->lw_head[lwd->lw_txgoff]; 1414*789Sahrens wsp->walk_data = lwd; 1415*789Sahrens 1416*789Sahrens return (WALK_NEXT); 1417*789Sahrens } 1418*789Sahrens 1419*789Sahrens static int 1420*789Sahrens txg_list_walk_init(mdb_walk_state_t *wsp) 1421*789Sahrens { 1422*789Sahrens return (txg_list_walk_init_common(wsp, 0, TXG_SIZE-1)); 1423*789Sahrens } 1424*789Sahrens 1425*789Sahrens static int 1426*789Sahrens txg_list0_walk_init(mdb_walk_state_t *wsp) 1427*789Sahrens { 1428*789Sahrens return (txg_list_walk_init_common(wsp, 0, 0)); 1429*789Sahrens } 1430*789Sahrens 1431*789Sahrens static int 1432*789Sahrens txg_list1_walk_init(mdb_walk_state_t *wsp) 1433*789Sahrens { 1434*789Sahrens return (txg_list_walk_init_common(wsp, 1, 1)); 1435*789Sahrens } 1436*789Sahrens 1437*789Sahrens static int 1438*789Sahrens txg_list2_walk_init(mdb_walk_state_t *wsp) 1439*789Sahrens { 1440*789Sahrens return (txg_list_walk_init_common(wsp, 2, 2)); 1441*789Sahrens } 1442*789Sahrens 1443*789Sahrens static int 1444*789Sahrens txg_list3_walk_init(mdb_walk_state_t *wsp) 1445*789Sahrens { 1446*789Sahrens return (txg_list_walk_init_common(wsp, 3, 3)); 1447*789Sahrens } 1448*789Sahrens 1449*789Sahrens static int 1450*789Sahrens txg_list_walk_step(mdb_walk_state_t *wsp) 1451*789Sahrens { 1452*789Sahrens txg_list_walk_data_t *lwd = wsp->walk_data; 1453*789Sahrens uintptr_t addr; 1454*789Sahrens txg_node_t *node; 1455*789Sahrens int status; 1456*789Sahrens 1457*789Sahrens while (wsp->walk_addr == NULL && lwd->lw_txgoff < lwd->lw_maxoff) { 1458*789Sahrens lwd->lw_txgoff++; 1459*789Sahrens wsp->walk_addr = lwd->lw_head[lwd->lw_txgoff]; 1460*789Sahrens } 1461*789Sahrens 1462*789Sahrens if (wsp->walk_addr == NULL) 1463*789Sahrens return (WALK_DONE); 1464*789Sahrens 1465*789Sahrens addr = wsp->walk_addr - lwd->lw_offset; 1466*789Sahrens 1467*789Sahrens if (mdb_vread(lwd->lw_obj, 1468*789Sahrens lwd->lw_offset + sizeof (txg_node_t), addr) == -1) { 1469*789Sahrens mdb_warn("failed to read list element at %#lx", addr); 1470*789Sahrens return (WALK_ERR); 1471*789Sahrens } 1472*789Sahrens 1473*789Sahrens status = wsp->walk_callback(addr, lwd->lw_obj, wsp->walk_cbdata); 1474*789Sahrens node = (txg_node_t *)((uintptr_t)lwd->lw_obj + lwd->lw_offset); 1475*789Sahrens wsp->walk_addr = (uintptr_t)node->tn_next[lwd->lw_txgoff]; 1476*789Sahrens 1477*789Sahrens return (status); 1478*789Sahrens } 1479*789Sahrens 1480*789Sahrens /* ARGSUSED */ 1481*789Sahrens static void 1482*789Sahrens txg_list_walk_fini(mdb_walk_state_t *wsp) 1483*789Sahrens { 1484*789Sahrens } 1485*789Sahrens 1486*789Sahrens /* 1487*789Sahrens * ::walk spa 1488*789Sahrens * 1489*789Sahrens * Walk all named spa_t structures in the namespace. This is nothing more than 1490*789Sahrens * a layered avl walk. 1491*789Sahrens */ 1492*789Sahrens static int 1493*789Sahrens spa_walk_init(mdb_walk_state_t *wsp) 1494*789Sahrens { 1495*789Sahrens GElf_Sym sym; 1496*789Sahrens 1497*789Sahrens if (wsp->walk_addr != NULL) { 1498*789Sahrens mdb_warn("spa walk only supports global walks\n"); 1499*789Sahrens return (WALK_ERR); 1500*789Sahrens } 1501*789Sahrens 1502*789Sahrens if (mdb_lookup_by_obj(ZFS_OBJ_NAME, "spa_namespace_avl", &sym) == -1) { 1503*789Sahrens mdb_warn("failed to find symbol 'spa_namespace_avl'"); 1504*789Sahrens return (WALK_ERR); 1505*789Sahrens } 1506*789Sahrens 1507*789Sahrens wsp->walk_addr = (uintptr_t)sym.st_value; 1508*789Sahrens 1509*789Sahrens if (mdb_layered_walk("avl", wsp) == -1) { 1510*789Sahrens mdb_warn("failed to walk 'avl'\n"); 1511*789Sahrens return (WALK_ERR); 1512*789Sahrens } 1513*789Sahrens 1514*789Sahrens return (WALK_NEXT); 1515*789Sahrens } 1516*789Sahrens 1517*789Sahrens static int 1518*789Sahrens spa_walk_step(mdb_walk_state_t *wsp) 1519*789Sahrens { 1520*789Sahrens spa_t spa; 1521*789Sahrens 1522*789Sahrens if (mdb_vread(&spa, sizeof (spa), wsp->walk_addr) == -1) { 1523*789Sahrens mdb_warn("failed to read spa_t at %p", wsp->walk_addr); 1524*789Sahrens return (WALK_ERR); 1525*789Sahrens } 1526*789Sahrens 1527*789Sahrens return (wsp->walk_callback(wsp->walk_addr, &spa, wsp->walk_cbdata)); 1528*789Sahrens } 1529*789Sahrens 1530*789Sahrens /* 1531*789Sahrens * MDB module linkage information: 1532*789Sahrens * 1533*789Sahrens * We declare a list of structures describing our dcmds, and a function 1534*789Sahrens * named _mdb_init to return a pointer to our module information. 1535*789Sahrens */ 1536*789Sahrens 1537*789Sahrens static const mdb_dcmd_t dcmds[] = { 1538*789Sahrens { "blkptr", ":", "print blkptr_t", blkptr }, 1539*789Sahrens { "dbuf", ":", "print dmu_buf_impl_t", dbuf }, 1540*789Sahrens { "dbuf_stats", ":", "dbuf stats", dbuf_stats }, 1541*789Sahrens { "dbufs", 1542*789Sahrens "\t[-O objset_t*] [-n objset_name | \"mos\"] [-o object | \"mdn\"] \n" 1543*789Sahrens "\t[-l level] [-b blkid | \"bonus\"]", 1544*789Sahrens "find dmu_buf_impl_t's that meet criterion", dbufs }, 1545*789Sahrens { "abuf_find", "dva_word[0] dva_word[1]", 1546*789Sahrens "find arc_buf_hdr_t of a specified DVA", 1547*789Sahrens abuf_find }, 1548*789Sahrens { "spa", "?[-cv]", "spa_t summary", spa_print }, 1549*789Sahrens { "spa_config", ":", "print spa_t configuration", spa_print_config }, 1550*789Sahrens { "spa_verify", ":", "verify spa_t consistency", spa_verify }, 1551*789Sahrens { "spa_space", ":[-b]", "print spa_t on-disk space usage", spa_space }, 1552*789Sahrens { "spa_vdevs", ":", "given a spa_t, print vdev summary", spa_vdevs }, 1553*789Sahrens { "vdev", ":[-qre]", "vdev_t summary", vdev_print }, 1554*789Sahrens { "zio_pipeline", ":", "decode a zio pipeline", zio_pipeline }, 1555*789Sahrens { NULL } 1556*789Sahrens }; 1557*789Sahrens 1558*789Sahrens static const mdb_walker_t walkers[] = { 1559*789Sahrens /* 1560*789Sahrens * In userland, there is no generic provider of list_t walkers, so we 1561*789Sahrens * need to add it. 1562*789Sahrens */ 1563*789Sahrens #ifndef _KERNEL 1564*789Sahrens { LIST_WALK_NAME, LIST_WALK_DESC, 1565*789Sahrens list_walk_init, list_walk_step, list_walk_fini }, 1566*789Sahrens #endif 1567*789Sahrens { "dbufs", "walk cached ZFS dbufs", 1568*789Sahrens dbuf_walk_init, dbuf_walk_step, dbuf_walk_fini }, 1569*789Sahrens { "zms_freelist", "walk ZFS metaslab freelist", 1570*789Sahrens freelist_walk_init, freelist_walk_step, freelist_walk_fini }, 1571*789Sahrens { "txg_list", "given any txg_list_t *, walk all entries in all txgs", 1572*789Sahrens txg_list_walk_init, txg_list_walk_step, txg_list_walk_fini }, 1573*789Sahrens { "txg_list0", "given any txg_list_t *, walk all entries in txg 0", 1574*789Sahrens txg_list0_walk_init, txg_list_walk_step, txg_list_walk_fini }, 1575*789Sahrens { "txg_list1", "given any txg_list_t *, walk all entries in txg 1", 1576*789Sahrens txg_list1_walk_init, txg_list_walk_step, txg_list_walk_fini }, 1577*789Sahrens { "txg_list2", "given any txg_list_t *, walk all entries in txg 2", 1578*789Sahrens txg_list2_walk_init, txg_list_walk_step, txg_list_walk_fini }, 1579*789Sahrens { "txg_list3", "given any txg_list_t *, walk all entries in txg 3", 1580*789Sahrens txg_list3_walk_init, txg_list_walk_step, txg_list_walk_fini }, 1581*789Sahrens { "spa", "walk all spa_t entries in the namespace", 1582*789Sahrens spa_walk_init, spa_walk_step, NULL }, 1583*789Sahrens { NULL } 1584*789Sahrens }; 1585*789Sahrens 1586*789Sahrens static const mdb_modinfo_t modinfo = { 1587*789Sahrens MDB_API_VERSION, dcmds, walkers 1588*789Sahrens }; 1589*789Sahrens 1590*789Sahrens const mdb_modinfo_t * 1591*789Sahrens _mdb_init(void) 1592*789Sahrens { 1593*789Sahrens return (&modinfo); 1594*789Sahrens } 1595