1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #include <mdb/mdb_ctf.h> 27 #include <sys/zfs_context.h> 28 #include <sys/mdb_modapi.h> 29 #include <sys/dbuf.h> 30 #include <sys/dmu_objset.h> 31 #include <sys/dsl_dir.h> 32 #include <sys/dsl_pool.h> 33 #include <sys/metaslab_impl.h> 34 #include <sys/space_map.h> 35 #include <sys/list.h> 36 #include <sys/spa_impl.h> 37 #include <sys/vdev_impl.h> 38 #include <sys/zio_compress.h> 39 #include <ctype.h> 40 41 #ifndef _KERNEL 42 #include "../genunix/list.h" 43 #endif 44 45 #ifdef _KERNEL 46 #define ZFS_OBJ_NAME "zfs" 47 #else 48 #define ZFS_OBJ_NAME "libzpool.so.1" 49 #endif 50 51 static char * 52 local_strdup(const char *s) 53 { 54 char *s1 = mdb_alloc(strlen(s) + 1, UM_SLEEP); 55 56 (void) strcpy(s1, s); 57 return (s1); 58 } 59 60 static int 61 getmember(uintptr_t addr, const char *type, mdb_ctf_id_t *idp, 62 const char *member, int len, void *buf) 63 { 64 mdb_ctf_id_t id; 65 ulong_t off; 66 char name[64]; 67 68 if (idp == NULL) { 69 if (mdb_ctf_lookup_by_name(type, &id) == -1) { 70 mdb_warn("couldn't find type %s", type); 71 return (DCMD_ERR); 72 } 73 idp = &id; 74 } else { 75 type = name; 76 mdb_ctf_type_name(*idp, name, sizeof (name)); 77 } 78 79 if (mdb_ctf_offsetof(*idp, member, &off) == -1) { 80 mdb_warn("couldn't find member %s of type %s\n", member, type); 81 return (DCMD_ERR); 82 } 83 if (off % 8 != 0) { 84 mdb_warn("member %s of type %s is unsupported bitfield", 85 member, type); 86 return (DCMD_ERR); 87 } 88 off /= 8; 89 90 if (mdb_vread(buf, len, addr + off) == -1) { 91 mdb_warn("failed to read %s from %s at %p", 92 member, type, addr + off); 93 return (DCMD_ERR); 94 } 95 /* mdb_warn("read %s from %s at %p+%llx\n", member, type, addr, off); */ 96 97 return (0); 98 } 99 100 #define GETMEMB(addr, type, member, dest) \ 101 getmember(addr, #type, NULL, #member, sizeof (dest), &(dest)) 102 103 #define GETMEMBID(addr, ctfid, member, dest) \ 104 getmember(addr, NULL, ctfid, #member, sizeof (dest), &(dest)) 105 106 static int 107 getrefcount(uintptr_t addr, mdb_ctf_id_t *id, 108 const char *member, uint64_t *rc) 109 { 110 static int gotid; 111 static mdb_ctf_id_t rc_id; 112 ulong_t off; 113 114 if (!gotid) { 115 if (mdb_ctf_lookup_by_name("struct refcount", &rc_id) == -1) { 116 mdb_warn("couldn't find struct refcount"); 117 return (DCMD_ERR); 118 } 119 gotid = TRUE; 120 } 121 122 if (mdb_ctf_offsetof(*id, member, &off) == -1) { 123 char name[64]; 124 mdb_ctf_type_name(*id, name, sizeof (name)); 125 mdb_warn("couldn't find member %s of type %s\n", member, name); 126 return (DCMD_ERR); 127 } 128 off /= 8; 129 130 return (GETMEMBID(addr + off, &rc_id, rc_count, *rc)); 131 } 132 133 static int 134 read_symbol(char *sym_name, void **bufp) 135 { 136 GElf_Sym sym; 137 138 if (mdb_lookup_by_obj(MDB_TGT_OBJ_EVERY, sym_name, &sym)) { 139 mdb_warn("can't find symbol %s", sym_name); 140 return (DCMD_ERR); 141 } 142 143 *bufp = mdb_alloc(sym.st_size, UM_SLEEP); 144 145 if (mdb_vread(*bufp, sym.st_size, sym.st_value) == -1) { 146 mdb_warn("can't read data for symbol %s", sym_name); 147 mdb_free(*bufp, sym.st_size); 148 return (DCMD_ERR); 149 } 150 151 return (DCMD_OK); 152 } 153 154 static int verbose; 155 156 static int 157 freelist_walk_init(mdb_walk_state_t *wsp) 158 { 159 if (wsp->walk_addr == NULL) { 160 mdb_warn("must supply starting address\n"); 161 return (WALK_ERR); 162 } 163 164 wsp->walk_data = 0; /* Index into the freelist */ 165 return (WALK_NEXT); 166 } 167 168 static int 169 freelist_walk_step(mdb_walk_state_t *wsp) 170 { 171 uint64_t entry; 172 uintptr_t number = (uintptr_t)wsp->walk_data; 173 char *ddata[] = { "ALLOC", "FREE", "CONDENSE", "INVALID", 174 "INVALID", "INVALID", "INVALID", "INVALID" }; 175 int mapshift = SPA_MINBLOCKSHIFT; 176 177 if (mdb_vread(&entry, sizeof (entry), wsp->walk_addr) == -1) { 178 mdb_warn("failed to read freelist entry %p", wsp->walk_addr); 179 return (WALK_DONE); 180 } 181 wsp->walk_addr += sizeof (entry); 182 wsp->walk_data = (void *)(number + 1); 183 184 if (SM_DEBUG_DECODE(entry)) { 185 mdb_printf("DEBUG: %3u %10s: txg=%llu pass=%llu\n", 186 number, 187 ddata[SM_DEBUG_ACTION_DECODE(entry)], 188 SM_DEBUG_TXG_DECODE(entry), 189 SM_DEBUG_SYNCPASS_DECODE(entry)); 190 } else { 191 mdb_printf("Entry: %3u offsets=%08llx-%08llx type=%c " 192 "size=%06llx", number, 193 SM_OFFSET_DECODE(entry) << mapshift, 194 (SM_OFFSET_DECODE(entry) + SM_RUN_DECODE(entry)) << 195 mapshift, 196 SM_TYPE_DECODE(entry) == SM_ALLOC ? 'A' : 'F', 197 SM_RUN_DECODE(entry) << mapshift); 198 if (verbose) 199 mdb_printf(" (raw=%012llx)\n", entry); 200 mdb_printf("\n"); 201 } 202 return (WALK_NEXT); 203 } 204 205 206 static int 207 dataset_name(uintptr_t addr, char *buf) 208 { 209 static int gotid; 210 static mdb_ctf_id_t dd_id; 211 uintptr_t dd_parent; 212 char dd_myname[MAXNAMELEN]; 213 214 if (!gotid) { 215 if (mdb_ctf_lookup_by_name("struct dsl_dir", 216 &dd_id) == -1) { 217 mdb_warn("couldn't find struct dsl_dir"); 218 return (DCMD_ERR); 219 } 220 gotid = TRUE; 221 } 222 if (GETMEMBID(addr, &dd_id, dd_parent, dd_parent) || 223 GETMEMBID(addr, &dd_id, dd_myname, dd_myname)) { 224 return (DCMD_ERR); 225 } 226 227 if (dd_parent) { 228 if (dataset_name(dd_parent, buf)) 229 return (DCMD_ERR); 230 strcat(buf, "/"); 231 } 232 233 if (dd_myname[0]) 234 strcat(buf, dd_myname); 235 else 236 strcat(buf, "???"); 237 238 return (0); 239 } 240 241 static int 242 objset_name(uintptr_t addr, char *buf) 243 { 244 static int gotid; 245 static mdb_ctf_id_t os_id, ds_id; 246 uintptr_t os_dsl_dataset; 247 char ds_snapname[MAXNAMELEN]; 248 uintptr_t ds_dir; 249 250 buf[0] = '\0'; 251 252 if (!gotid) { 253 if (mdb_ctf_lookup_by_name("struct objset", 254 &os_id) == -1) { 255 mdb_warn("couldn't find struct objset"); 256 return (DCMD_ERR); 257 } 258 if (mdb_ctf_lookup_by_name("struct dsl_dataset", 259 &ds_id) == -1) { 260 mdb_warn("couldn't find struct dsl_dataset"); 261 return (DCMD_ERR); 262 } 263 264 gotid = TRUE; 265 } 266 267 if (GETMEMBID(addr, &os_id, os_dsl_dataset, os_dsl_dataset)) 268 return (DCMD_ERR); 269 270 if (os_dsl_dataset == 0) { 271 strcat(buf, "mos"); 272 return (0); 273 } 274 275 if (GETMEMBID(os_dsl_dataset, &ds_id, ds_snapname, ds_snapname) || 276 GETMEMBID(os_dsl_dataset, &ds_id, ds_dir, ds_dir)) { 277 return (DCMD_ERR); 278 } 279 280 if (ds_dir && dataset_name(ds_dir, buf)) 281 return (DCMD_ERR); 282 283 if (ds_snapname[0]) { 284 strcat(buf, "@"); 285 strcat(buf, ds_snapname); 286 } 287 return (0); 288 } 289 290 static void 291 enum_lookup(char *out, size_t size, mdb_ctf_id_t id, int val, 292 const char *prefix) 293 { 294 const char *cp; 295 size_t len = strlen(prefix); 296 297 if ((cp = mdb_ctf_enum_name(id, val)) != NULL) { 298 if (strncmp(cp, prefix, len) == 0) 299 cp += len; 300 (void) strncpy(out, cp, size); 301 } else { 302 mdb_snprintf(out, size, "? (%d)", val); 303 } 304 } 305 306 /* ARGSUSED */ 307 static int 308 zio_pipeline(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 309 { 310 mdb_ctf_id_t pipe_enum; 311 int i; 312 char stage[1024]; 313 314 if (mdb_ctf_lookup_by_name("enum zio_stage", &pipe_enum) == -1) { 315 mdb_warn("Could not find enum zio_stage"); 316 return (DCMD_ERR); 317 } 318 319 for (i = 0; i < 32; i++) { 320 if (addr & (1U << i)) { 321 enum_lookup(stage, sizeof (stage), pipe_enum, i, 322 "ZIO_STAGE_"); 323 mdb_printf(" %s\n", stage); 324 } 325 } 326 327 return (DCMD_OK); 328 } 329 330 /* ARGSUSED */ 331 static int 332 zfs_params(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 333 { 334 /* 335 * This table can be approximately generated by running: 336 * egrep "^[a-z0-9_]+ [a-z0-9_]+( =.*)?;" *.c | cut -d ' ' -f 2 337 */ 338 static const char *params[] = { 339 "arc_reduce_dnlc_percent", 340 "zfs_arc_max", 341 "zfs_arc_min", 342 "arc_shrink_shift", 343 "zfs_mdcomp_disable", 344 "zfs_prefetch_disable", 345 "zfetch_max_streams", 346 "zfetch_min_sec_reap", 347 "zfetch_block_cap", 348 "zfetch_array_rd_sz", 349 "zfs_default_bs", 350 "zfs_default_ibs", 351 "metaslab_aliquot", 352 "reference_tracking_enable", 353 "reference_history", 354 "zio_taskq_threads", 355 "spa_max_replication_override", 356 "spa_mode", 357 "zfs_flags", 358 "zfs_txg_synctime", 359 "zfs_txg_timeout", 360 "zfs_write_limit_min", 361 "zfs_write_limit_max", 362 "zfs_write_limit_shift", 363 "zfs_write_limit_override", 364 "zfs_no_write_throttle", 365 "zfs_vdev_cache_max", 366 "zfs_vdev_cache_size", 367 "zfs_vdev_cache_bshift", 368 "vdev_mirror_shift", 369 "zfs_vdev_max_pending", 370 "zfs_vdev_min_pending", 371 "zfs_scrub_limit", 372 "zfs_vdev_time_shift", 373 "zfs_vdev_ramp_rate", 374 "zfs_vdev_aggregation_limit", 375 "fzap_default_block_shift", 376 "zfs_immediate_write_sz", 377 "zfs_read_chunk_size", 378 "zil_disable", 379 "zfs_nocacheflush", 380 "metaslab_gang_bang", 381 "metaslab_df_alloc_threshold", 382 "metaslab_df_free_pct", 383 "zio_injection_enabled", 384 "zvol_immediate_write_sz", 385 }; 386 int i; 387 388 for (i = 0; i < sizeof (params) / sizeof (params[0]); i++) { 389 int sz; 390 uint64_t val64; 391 uint32_t *val32p = (uint32_t *)&val64; 392 393 sz = mdb_readvar(&val64, params[i]); 394 if (sz == 4) { 395 mdb_printf("%s = 0x%x\n", params[i], *val32p); 396 } else if (sz == 8) { 397 mdb_printf("%s = 0x%llx\n", params[i], val64); 398 } else { 399 mdb_warn("variable %s not found", params[i]); 400 } 401 } 402 403 return (DCMD_OK); 404 } 405 406 /* ARGSUSED */ 407 static int 408 blkptr(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 409 { 410 blkptr_t bp; 411 dmu_object_type_info_t *doti; 412 zio_compress_info_t *zct; 413 zio_checksum_info_t *zci; 414 int i; 415 char buf[MAXPATHLEN]; 416 417 if (mdb_vread(&bp, sizeof (blkptr_t), addr) == -1) { 418 mdb_warn("failed to read blkptr_t"); 419 return (DCMD_ERR); 420 } 421 422 if (read_symbol("dmu_ot", (void **)&doti) != DCMD_OK) 423 return (DCMD_ERR); 424 for (i = 0; i < DMU_OT_NUMTYPES; i++) { 425 mdb_readstr(buf, sizeof (buf), (uintptr_t)doti[i].ot_name); 426 doti[i].ot_name = local_strdup(buf); 427 } 428 429 if (read_symbol("zio_checksum_table", (void **)&zci) != DCMD_OK) 430 return (DCMD_ERR); 431 for (i = 0; i < ZIO_CHECKSUM_FUNCTIONS; i++) { 432 mdb_readstr(buf, sizeof (buf), (uintptr_t)zci[i].ci_name); 433 zci[i].ci_name = local_strdup(buf); 434 } 435 436 if (read_symbol("zio_compress_table", (void **)&zct) != DCMD_OK) 437 return (DCMD_ERR); 438 for (i = 0; i < ZIO_COMPRESS_FUNCTIONS; i++) { 439 mdb_readstr(buf, sizeof (buf), (uintptr_t)zct[i].ci_name); 440 zct[i].ci_name = local_strdup(buf); 441 } 442 443 /* 444 * Super-ick warning: This code is also duplicated in 445 * cmd/zdb.c . Yeah, I hate code replication, too. 446 */ 447 for (i = 0; i < BP_GET_NDVAS(&bp); i++) { 448 dva_t *dva = &bp.blk_dva[i]; 449 450 mdb_printf("DVA[%d]: vdev_id %lld / %llx\n", i, 451 DVA_GET_VDEV(dva), DVA_GET_OFFSET(dva)); 452 mdb_printf("DVA[%d]: GANG: %-5s GRID: %04x\t" 453 "ASIZE: %llx\n", i, DVA_GET_GANG(dva) ? "TRUE" : "FALSE", 454 (int)DVA_GET_GRID(dva), DVA_GET_ASIZE(dva)); 455 mdb_printf("DVA[%d]: %llu:%llx:%llx:%s%s%s%s\n", i, 456 DVA_GET_VDEV(dva), DVA_GET_OFFSET(dva), BP_GET_PSIZE(&bp), 457 BP_SHOULD_BYTESWAP(&bp) ? "e" : "", 458 !DVA_GET_GANG(dva) && BP_GET_LEVEL(&bp) != 0 ? "i" : "", 459 DVA_GET_GANG(dva) ? "g" : "", 460 BP_GET_COMPRESS(&bp) != 0 ? "d" : ""); 461 } 462 mdb_printf("LSIZE: %-16llx\t\tPSIZE: %llx\n", 463 BP_GET_LSIZE(&bp), BP_GET_PSIZE(&bp)); 464 mdb_printf("ENDIAN: %6s\t\t\t\t\tTYPE: %s\n", 465 BP_GET_BYTEORDER(&bp) ? "LITTLE" : "BIG", 466 BP_GET_TYPE(&bp) < DMU_OT_NUMTYPES ? 467 doti[BP_GET_TYPE(&bp)].ot_name : "UNKNOWN"); 468 mdb_printf("BIRTH: %-16llx LEVEL: %-2d\tFILL: %llx\n", 469 bp.blk_birth, (int)BP_GET_LEVEL(&bp), bp.blk_fill); 470 mdb_printf("CKFUNC: %-16s\t\tCOMP: %s\n", 471 BP_GET_CHECKSUM(&bp) < ZIO_CHECKSUM_FUNCTIONS ? 472 zci[BP_GET_CHECKSUM(&bp)].ci_name : "UNKNOWN", 473 BP_GET_COMPRESS(&bp) < ZIO_COMPRESS_FUNCTIONS ? 474 zct[BP_GET_COMPRESS(&bp)].ci_name : "UNKNOWN"); 475 mdb_printf("CKSUM: %llx:%llx:%llx:%llx\n", 476 bp.blk_cksum.zc_word[0], 477 bp.blk_cksum.zc_word[1], 478 bp.blk_cksum.zc_word[2], 479 bp.blk_cksum.zc_word[3]); 480 481 return (DCMD_OK); 482 } 483 484 /* ARGSUSED */ 485 static int 486 dbuf(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 487 { 488 mdb_ctf_id_t id; 489 dmu_buf_t db; 490 uintptr_t objset; 491 uint8_t level; 492 uint64_t blkid; 493 uint64_t holds; 494 char objectname[32]; 495 char blkidname[32]; 496 char path[MAXNAMELEN]; 497 498 if (DCMD_HDRSPEC(flags)) { 499 mdb_printf(" addr object lvl blkid holds os\n"); 500 } 501 502 if (mdb_ctf_lookup_by_name("struct dmu_buf_impl", &id) == -1) { 503 mdb_warn("couldn't find struct dmu_buf_impl_t"); 504 return (DCMD_ERR); 505 } 506 507 if (GETMEMBID(addr, &id, db_objset, objset) || 508 GETMEMBID(addr, &id, db, db) || 509 GETMEMBID(addr, &id, db_level, level) || 510 GETMEMBID(addr, &id, db_blkid, blkid)) { 511 return (WALK_ERR); 512 } 513 514 if (getrefcount(addr, &id, "db_holds", &holds)) { 515 return (WALK_ERR); 516 } 517 518 if (db.db_object == DMU_META_DNODE_OBJECT) 519 (void) strcpy(objectname, "mdn"); 520 else 521 (void) mdb_snprintf(objectname, sizeof (objectname), "%llx", 522 (u_longlong_t)db.db_object); 523 524 if (blkid == DB_BONUS_BLKID) 525 (void) strcpy(blkidname, "bonus"); 526 else 527 (void) mdb_snprintf(blkidname, sizeof (blkidname), "%llx", 528 (u_longlong_t)blkid); 529 530 if (objset_name(objset, path)) { 531 return (WALK_ERR); 532 } 533 534 mdb_printf("%p %8s %1u %9s %2llu %s\n", 535 addr, objectname, level, blkidname, holds, path); 536 537 return (DCMD_OK); 538 } 539 540 /* ARGSUSED */ 541 static int 542 dbuf_stats(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 543 { 544 #define HISTOSZ 32 545 uintptr_t dbp; 546 dmu_buf_impl_t db; 547 dbuf_hash_table_t ht; 548 uint64_t bucket, ndbufs; 549 uint64_t histo[HISTOSZ]; 550 uint64_t histo2[HISTOSZ]; 551 int i, maxidx; 552 553 if (mdb_readvar(&ht, "dbuf_hash_table") == -1) { 554 mdb_warn("failed to read 'dbuf_hash_table'"); 555 return (DCMD_ERR); 556 } 557 558 for (i = 0; i < HISTOSZ; i++) { 559 histo[i] = 0; 560 histo2[i] = 0; 561 } 562 563 ndbufs = 0; 564 for (bucket = 0; bucket < ht.hash_table_mask+1; bucket++) { 565 int len; 566 567 if (mdb_vread(&dbp, sizeof (void *), 568 (uintptr_t)(ht.hash_table+bucket)) == -1) { 569 mdb_warn("failed to read hash bucket %u at %p", 570 bucket, ht.hash_table+bucket); 571 return (DCMD_ERR); 572 } 573 574 len = 0; 575 while (dbp != 0) { 576 if (mdb_vread(&db, sizeof (dmu_buf_impl_t), 577 dbp) == -1) { 578 mdb_warn("failed to read dbuf at %p", dbp); 579 return (DCMD_ERR); 580 } 581 dbp = (uintptr_t)db.db_hash_next; 582 for (i = MIN(len, HISTOSZ - 1); i >= 0; i--) 583 histo2[i]++; 584 len++; 585 ndbufs++; 586 } 587 588 if (len >= HISTOSZ) 589 len = HISTOSZ-1; 590 histo[len]++; 591 } 592 593 mdb_printf("hash table has %llu buckets, %llu dbufs " 594 "(avg %llu buckets/dbuf)\n", 595 ht.hash_table_mask+1, ndbufs, 596 (ht.hash_table_mask+1)/ndbufs); 597 598 mdb_printf("\n"); 599 maxidx = 0; 600 for (i = 0; i < HISTOSZ; i++) 601 if (histo[i] > 0) 602 maxidx = i; 603 mdb_printf("hash chain length number of buckets\n"); 604 for (i = 0; i <= maxidx; i++) 605 mdb_printf("%u %llu\n", i, histo[i]); 606 607 mdb_printf("\n"); 608 maxidx = 0; 609 for (i = 0; i < HISTOSZ; i++) 610 if (histo2[i] > 0) 611 maxidx = i; 612 mdb_printf("hash chain depth number of dbufs\n"); 613 for (i = 0; i <= maxidx; i++) 614 mdb_printf("%u or more %llu %llu%%\n", 615 i, histo2[i], histo2[i]*100/ndbufs); 616 617 618 return (DCMD_OK); 619 } 620 621 typedef struct dbufs_data { 622 mdb_ctf_id_t id; 623 uint64_t objset; 624 uint64_t object; 625 uint64_t level; 626 uint64_t blkid; 627 char *osname; 628 } dbufs_data_t; 629 630 #define DBUFS_UNSET (0xbaddcafedeadbeefULL) 631 632 /* ARGSUSED */ 633 static int 634 dbufs_cb(uintptr_t addr, const void *unknown, void *arg) 635 { 636 dbufs_data_t *data = arg; 637 uintptr_t objset; 638 dmu_buf_t db; 639 uint8_t level; 640 uint64_t blkid; 641 char osname[MAXNAMELEN]; 642 643 if (GETMEMBID(addr, &data->id, db_objset, objset) || 644 GETMEMBID(addr, &data->id, db, db) || 645 GETMEMBID(addr, &data->id, db_level, level) || 646 GETMEMBID(addr, &data->id, db_blkid, blkid)) { 647 return (WALK_ERR); 648 } 649 650 if ((data->objset == DBUFS_UNSET || data->objset == objset) && 651 (data->osname == NULL || (objset_name(objset, osname) == 0 && 652 strcmp(data->osname, osname) == 0)) && 653 (data->object == DBUFS_UNSET || data->object == db.db_object) && 654 (data->level == DBUFS_UNSET || data->level == level) && 655 (data->blkid == DBUFS_UNSET || data->blkid == blkid)) { 656 mdb_printf("%#lr\n", addr); 657 } 658 return (WALK_NEXT); 659 } 660 661 /* ARGSUSED */ 662 static int 663 dbufs(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 664 { 665 dbufs_data_t data; 666 char *object = NULL; 667 char *blkid = NULL; 668 669 data.objset = data.object = data.level = data.blkid = DBUFS_UNSET; 670 data.osname = NULL; 671 672 if (mdb_getopts(argc, argv, 673 'O', MDB_OPT_UINT64, &data.objset, 674 'n', MDB_OPT_STR, &data.osname, 675 'o', MDB_OPT_STR, &object, 676 'l', MDB_OPT_UINT64, &data.level, 677 'b', MDB_OPT_STR, &blkid) != argc) { 678 return (DCMD_USAGE); 679 } 680 681 if (object) { 682 if (strcmp(object, "mdn") == 0) { 683 data.object = DMU_META_DNODE_OBJECT; 684 } else { 685 data.object = mdb_strtoull(object); 686 } 687 } 688 689 if (blkid) { 690 if (strcmp(blkid, "bonus") == 0) { 691 data.blkid = DB_BONUS_BLKID; 692 } else { 693 data.blkid = mdb_strtoull(blkid); 694 } 695 } 696 697 if (mdb_ctf_lookup_by_name("struct dmu_buf_impl", &data.id) == -1) { 698 mdb_warn("couldn't find struct dmu_buf_impl_t"); 699 return (DCMD_ERR); 700 } 701 702 if (mdb_walk("dmu_buf_impl_t", dbufs_cb, &data) != 0) { 703 mdb_warn("can't walk dbufs"); 704 return (DCMD_ERR); 705 } 706 707 return (DCMD_OK); 708 } 709 710 typedef struct abuf_find_data { 711 dva_t dva; 712 mdb_ctf_id_t id; 713 } abuf_find_data_t; 714 715 /* ARGSUSED */ 716 static int 717 abuf_find_cb(uintptr_t addr, const void *unknown, void *arg) 718 { 719 abuf_find_data_t *data = arg; 720 dva_t dva; 721 722 if (GETMEMBID(addr, &data->id, b_dva, dva)) { 723 return (WALK_ERR); 724 } 725 726 if (dva.dva_word[0] == data->dva.dva_word[0] && 727 dva.dva_word[1] == data->dva.dva_word[1]) { 728 mdb_printf("%#lr\n", addr); 729 } 730 return (WALK_NEXT); 731 } 732 733 /* ARGSUSED */ 734 static int 735 abuf_find(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 736 { 737 abuf_find_data_t data; 738 GElf_Sym sym; 739 int i; 740 const char *syms[] = { 741 "ARC_mru", 742 "ARC_mru_ghost", 743 "ARC_mfu", 744 "ARC_mfu_ghost", 745 }; 746 747 if (argc != 2) 748 return (DCMD_USAGE); 749 750 for (i = 0; i < 2; i ++) { 751 switch (argv[i].a_type) { 752 case MDB_TYPE_STRING: 753 data.dva.dva_word[i] = mdb_strtoull(argv[i].a_un.a_str); 754 break; 755 case MDB_TYPE_IMMEDIATE: 756 data.dva.dva_word[i] = argv[i].a_un.a_val; 757 break; 758 default: 759 return (DCMD_USAGE); 760 } 761 } 762 763 if (mdb_ctf_lookup_by_name("struct arc_buf_hdr", &data.id) == -1) { 764 mdb_warn("couldn't find struct arc_buf_hdr"); 765 return (DCMD_ERR); 766 } 767 768 for (i = 0; i < sizeof (syms) / sizeof (syms[0]); i++) { 769 if (mdb_lookup_by_name(syms[i], &sym)) { 770 mdb_warn("can't find symbol %s", syms[i]); 771 return (DCMD_ERR); 772 } 773 774 if (mdb_pwalk("list", abuf_find_cb, &data, sym.st_value) != 0) { 775 mdb_warn("can't walk %s", syms[i]); 776 return (DCMD_ERR); 777 } 778 } 779 780 return (DCMD_OK); 781 } 782 783 /*ARGSUSED*/ 784 static int 785 arc_print(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 786 { 787 kstat_named_t *stats; 788 GElf_Sym sym; 789 int nstats, i; 790 uint_t opt_a = FALSE; 791 uint_t opt_b = FALSE; 792 uint_t shift = 0; 793 const char *suffix; 794 795 static const char *bytestats[] = { 796 "p", "c", "c_min", "c_max", "size", NULL 797 }; 798 799 static const char *extras[] = { 800 "arc_no_grow", "arc_tempreserve", 801 "arc_meta_used", "arc_meta_limit", "arc_meta_max", 802 NULL 803 }; 804 805 if (mdb_lookup_by_name("arc_stats", &sym) == -1) { 806 mdb_warn("failed to find 'arc_stats'"); 807 return (DCMD_ERR); 808 } 809 810 stats = mdb_zalloc(sym.st_size, UM_SLEEP | UM_GC); 811 812 if (mdb_vread(stats, sym.st_size, sym.st_value) == -1) { 813 mdb_warn("couldn't read 'arc_stats' at %p", sym.st_value); 814 return (DCMD_ERR); 815 } 816 817 nstats = sym.st_size / sizeof (kstat_named_t); 818 819 /* NB: -a / opt_a are ignored for backwards compatability */ 820 if (mdb_getopts(argc, argv, 821 'a', MDB_OPT_SETBITS, TRUE, &opt_a, 822 'b', MDB_OPT_SETBITS, TRUE, &opt_b, 823 'k', MDB_OPT_SETBITS, 10, &shift, 824 'm', MDB_OPT_SETBITS, 20, &shift, 825 'g', MDB_OPT_SETBITS, 30, &shift, 826 NULL) != argc) 827 return (DCMD_USAGE); 828 829 if (!opt_b && !shift) 830 shift = 20; 831 832 switch (shift) { 833 case 0: 834 suffix = "B"; 835 break; 836 case 10: 837 suffix = "KB"; 838 break; 839 case 20: 840 suffix = "MB"; 841 break; 842 case 30: 843 suffix = "GB"; 844 break; 845 default: 846 suffix = "XX"; 847 } 848 849 for (i = 0; i < nstats; i++) { 850 int j; 851 boolean_t bytes = B_FALSE; 852 853 for (j = 0; bytestats[j]; j++) { 854 if (strcmp(stats[i].name, bytestats[j]) == 0) { 855 bytes = B_TRUE; 856 break; 857 } 858 } 859 860 if (bytes) { 861 mdb_printf("%-25s = %9llu %s\n", stats[i].name, 862 stats[i].value.ui64 >> shift, suffix); 863 } else { 864 mdb_printf("%-25s = %9llu\n", stats[i].name, 865 stats[i].value.ui64); 866 } 867 } 868 869 for (i = 0; extras[i]; i++) { 870 uint64_t buf; 871 872 if (mdb_lookup_by_name(extras[i], &sym) == -1) { 873 mdb_warn("failed to find '%s'", extras[i]); 874 return (DCMD_ERR); 875 } 876 877 if (sym.st_size != sizeof (uint64_t) && 878 sym.st_size != sizeof (uint32_t)) { 879 mdb_warn("expected scalar for variable '%s'\n", 880 extras[i]); 881 return (DCMD_ERR); 882 } 883 884 if (mdb_vread(&buf, sym.st_size, sym.st_value) == -1) { 885 mdb_warn("couldn't read '%s'", extras[i]); 886 return (DCMD_ERR); 887 } 888 889 mdb_printf("%-25s = ", extras[i]); 890 891 /* NB: all the 64-bit extras happen to be byte counts */ 892 if (sym.st_size == sizeof (uint64_t)) 893 mdb_printf("%9llu %s\n", buf >> shift, suffix); 894 895 if (sym.st_size == sizeof (uint32_t)) 896 mdb_printf("%9d\n", *((uint32_t *)&buf)); 897 } 898 return (DCMD_OK); 899 } 900 901 /* 902 * ::spa 903 * 904 * -c Print configuration information as well 905 * -v Print vdev state 906 * -e Print vdev error stats 907 * 908 * Print a summarized spa_t. When given no arguments, prints out a table of all 909 * active pools on the system. 910 */ 911 /* ARGSUSED */ 912 static int 913 spa_print(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 914 { 915 spa_t spa; 916 const char *statetab[] = { "ACTIVE", "EXPORTED", "DESTROYED", 917 "SPARE", "L2CACHE", "UNINIT", "UNAVAIL", "POTENTIAL" }; 918 const char *state; 919 int config = FALSE; 920 int vdevs = FALSE; 921 int errors = FALSE; 922 923 if (mdb_getopts(argc, argv, 924 'c', MDB_OPT_SETBITS, TRUE, &config, 925 'v', MDB_OPT_SETBITS, TRUE, &vdevs, 926 'e', MDB_OPT_SETBITS, TRUE, &errors, 927 NULL) != argc) 928 return (DCMD_USAGE); 929 930 if (!(flags & DCMD_ADDRSPEC)) { 931 if (mdb_walk_dcmd("spa", "spa", argc, argv) == -1) { 932 mdb_warn("can't walk spa"); 933 return (DCMD_ERR); 934 } 935 936 return (DCMD_OK); 937 } 938 939 if (flags & DCMD_PIPE_OUT) { 940 mdb_printf("%#lr\n", addr); 941 return (DCMD_OK); 942 } 943 944 if (DCMD_HDRSPEC(flags)) 945 mdb_printf("%<u>%-?s %9s %-*s%</u>\n", "ADDR", "STATE", 946 sizeof (uintptr_t) == 4 ? 60 : 52, "NAME"); 947 948 if (mdb_vread(&spa, sizeof (spa), addr) == -1) { 949 mdb_warn("failed to read spa_t at %p", addr); 950 return (DCMD_ERR); 951 } 952 953 if (spa.spa_state < 0 || spa.spa_state > POOL_STATE_UNAVAIL) 954 state = "UNKNOWN"; 955 else 956 state = statetab[spa.spa_state]; 957 958 mdb_printf("%0?p %9s %s\n", addr, state, spa.spa_name); 959 960 if (config) { 961 mdb_printf("\n"); 962 mdb_inc_indent(4); 963 if (mdb_call_dcmd("spa_config", addr, flags, 0, 964 NULL) != DCMD_OK) 965 return (DCMD_ERR); 966 mdb_dec_indent(4); 967 } 968 969 if (vdevs || errors) { 970 mdb_arg_t v; 971 972 v.a_type = MDB_TYPE_STRING; 973 v.a_un.a_str = "-e"; 974 975 mdb_printf("\n"); 976 mdb_inc_indent(4); 977 if (mdb_call_dcmd("spa_vdevs", addr, flags, errors ? 1 : 0, 978 &v) != DCMD_OK) 979 return (DCMD_ERR); 980 mdb_dec_indent(4); 981 } 982 983 return (DCMD_OK); 984 } 985 986 /* 987 * ::spa_config 988 * 989 * Given a spa_t, print the configuration information stored in spa_config. 990 * Since it's just an nvlist, format it as an indented list of name=value pairs. 991 * We simply read the value of spa_config and pass off to ::nvlist. 992 */ 993 /* ARGSUSED */ 994 static int 995 spa_print_config(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 996 { 997 spa_t spa; 998 999 if (argc != 0 || !(flags & DCMD_ADDRSPEC)) 1000 return (DCMD_USAGE); 1001 1002 if (mdb_vread(&spa, sizeof (spa), addr) == -1) { 1003 mdb_warn("failed to read spa_t at %p", addr); 1004 return (DCMD_ERR); 1005 } 1006 1007 if (spa.spa_config == NULL) { 1008 mdb_printf("(none)\n"); 1009 return (DCMD_OK); 1010 } 1011 1012 return (mdb_call_dcmd("nvlist", (uintptr_t)spa.spa_config, flags, 1013 0, NULL)); 1014 } 1015 1016 /* 1017 * ::vdev 1018 * 1019 * Print out a summarized vdev_t, in the following form: 1020 * 1021 * ADDR STATE AUX DESC 1022 * fffffffbcde23df0 HEALTHY - /dev/dsk/c0t0d0 1023 * 1024 * If '-r' is specified, recursively visit all children. 1025 * 1026 * With '-e', the statistics associated with the vdev are printed as well. 1027 */ 1028 static int 1029 do_print_vdev(uintptr_t addr, int flags, int depth, int stats, 1030 int recursive) 1031 { 1032 vdev_t vdev; 1033 char desc[MAXNAMELEN]; 1034 int c, children; 1035 uintptr_t *child; 1036 const char *state, *aux; 1037 1038 if (mdb_vread(&vdev, sizeof (vdev), (uintptr_t)addr) == -1) { 1039 mdb_warn("failed to read vdev_t at %p\n", (uintptr_t)addr); 1040 return (DCMD_ERR); 1041 } 1042 1043 if (flags & DCMD_PIPE_OUT) { 1044 mdb_printf("%#lr", addr); 1045 } else { 1046 if (vdev.vdev_path != NULL) { 1047 if (mdb_readstr(desc, sizeof (desc), 1048 (uintptr_t)vdev.vdev_path) == -1) { 1049 mdb_warn("failed to read vdev_path at %p\n", 1050 vdev.vdev_path); 1051 return (DCMD_ERR); 1052 } 1053 } else if (vdev.vdev_ops != NULL) { 1054 vdev_ops_t ops; 1055 if (mdb_vread(&ops, sizeof (ops), 1056 (uintptr_t)vdev.vdev_ops) == -1) { 1057 mdb_warn("failed to read vdev_ops at %p\n", 1058 vdev.vdev_ops); 1059 return (DCMD_ERR); 1060 } 1061 (void) strcpy(desc, ops.vdev_op_type); 1062 } else { 1063 (void) strcpy(desc, "<unknown>"); 1064 } 1065 1066 if (depth == 0 && DCMD_HDRSPEC(flags)) 1067 mdb_printf("%<u>%-?s %-9s %-12s %-*s%</u>\n", 1068 "ADDR", "STATE", "AUX", 1069 sizeof (uintptr_t) == 4 ? 43 : 35, 1070 "DESCRIPTION"); 1071 1072 mdb_printf("%0?p ", addr); 1073 1074 switch (vdev.vdev_state) { 1075 case VDEV_STATE_CLOSED: 1076 state = "CLOSED"; 1077 break; 1078 case VDEV_STATE_OFFLINE: 1079 state = "OFFLINE"; 1080 break; 1081 case VDEV_STATE_CANT_OPEN: 1082 state = "CANT_OPEN"; 1083 break; 1084 case VDEV_STATE_DEGRADED: 1085 state = "DEGRADED"; 1086 break; 1087 case VDEV_STATE_HEALTHY: 1088 state = "HEALTHY"; 1089 break; 1090 case VDEV_STATE_REMOVED: 1091 state = "REMOVED"; 1092 break; 1093 case VDEV_STATE_FAULTED: 1094 state = "FAULTED"; 1095 break; 1096 default: 1097 state = "UNKNOWN"; 1098 break; 1099 } 1100 1101 switch (vdev.vdev_stat.vs_aux) { 1102 case VDEV_AUX_NONE: 1103 aux = "-"; 1104 break; 1105 case VDEV_AUX_OPEN_FAILED: 1106 aux = "OPEN_FAILED"; 1107 break; 1108 case VDEV_AUX_CORRUPT_DATA: 1109 aux = "CORRUPT_DATA"; 1110 break; 1111 case VDEV_AUX_NO_REPLICAS: 1112 aux = "NO_REPLICAS"; 1113 break; 1114 case VDEV_AUX_BAD_GUID_SUM: 1115 aux = "BAD_GUID_SUM"; 1116 break; 1117 case VDEV_AUX_TOO_SMALL: 1118 aux = "TOO_SMALL"; 1119 break; 1120 case VDEV_AUX_BAD_LABEL: 1121 aux = "BAD_LABEL"; 1122 break; 1123 case VDEV_AUX_VERSION_NEWER: 1124 aux = "VERS_NEWER"; 1125 break; 1126 case VDEV_AUX_VERSION_OLDER: 1127 aux = "VERS_OLDER"; 1128 break; 1129 case VDEV_AUX_SPARED: 1130 aux = "SPARED"; 1131 break; 1132 case VDEV_AUX_ERR_EXCEEDED: 1133 aux = "ERR_EXCEEDED"; 1134 break; 1135 case VDEV_AUX_IO_FAILURE: 1136 aux = "IO_FAILURE"; 1137 break; 1138 case VDEV_AUX_BAD_LOG: 1139 aux = "BAD_LOG"; 1140 break; 1141 default: 1142 aux = "UNKNOWN"; 1143 break; 1144 } 1145 1146 mdb_printf("%-9s %-12s %*s%s\n", state, aux, depth, "", desc); 1147 1148 if (stats) { 1149 vdev_stat_t *vs = &vdev.vdev_stat; 1150 int i; 1151 1152 mdb_inc_indent(4); 1153 mdb_printf("\n"); 1154 mdb_printf("%<u> %12s %12s %12s %12s " 1155 "%12s%</u>\n", "READ", "WRITE", "FREE", "CLAIM", 1156 "IOCTL"); 1157 mdb_printf("OPS "); 1158 for (i = 1; i < ZIO_TYPES; i++) 1159 mdb_printf("%11#llx%s", vs->vs_ops[i], 1160 i == ZIO_TYPES - 1 ? "" : " "); 1161 mdb_printf("\n"); 1162 mdb_printf("BYTES "); 1163 for (i = 1; i < ZIO_TYPES; i++) 1164 mdb_printf("%11#llx%s", vs->vs_bytes[i], 1165 i == ZIO_TYPES - 1 ? "" : " "); 1166 1167 1168 mdb_printf("\n"); 1169 mdb_printf("EREAD %10#llx\n", vs->vs_read_errors); 1170 mdb_printf("EWRITE %10#llx\n", vs->vs_write_errors); 1171 mdb_printf("ECKSUM %10#llx\n", 1172 vs->vs_checksum_errors); 1173 mdb_dec_indent(4); 1174 } 1175 1176 if (stats) 1177 mdb_printf("\n"); 1178 } 1179 1180 children = vdev.vdev_children; 1181 1182 if (children == 0 || !recursive) 1183 return (DCMD_OK); 1184 1185 child = mdb_alloc(children * sizeof (void *), UM_SLEEP | UM_GC); 1186 if (mdb_vread(child, children * sizeof (void *), 1187 (uintptr_t)vdev.vdev_child) == -1) { 1188 mdb_warn("failed to read vdev children at %p", vdev.vdev_child); 1189 return (DCMD_ERR); 1190 } 1191 1192 for (c = 0; c < children; c++) { 1193 if (do_print_vdev(child[c], flags, depth + 2, stats, 1194 recursive)) 1195 return (DCMD_ERR); 1196 } 1197 1198 return (DCMD_OK); 1199 } 1200 1201 static int 1202 vdev_print(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 1203 { 1204 int recursive = FALSE; 1205 int stats = FALSE; 1206 uint64_t depth = 0; 1207 1208 if (mdb_getopts(argc, argv, 1209 'r', MDB_OPT_SETBITS, TRUE, &recursive, 1210 'e', MDB_OPT_SETBITS, TRUE, &stats, 1211 'd', MDB_OPT_UINT64, &depth, 1212 NULL) != argc) 1213 return (DCMD_USAGE); 1214 1215 if (!(flags & DCMD_ADDRSPEC)) { 1216 mdb_warn("no vdev_t address given\n"); 1217 return (DCMD_ERR); 1218 } 1219 1220 return (do_print_vdev(addr, flags, (int)depth, stats, recursive)); 1221 } 1222 1223 typedef struct metaslab_walk_data { 1224 uint64_t mw_numvdevs; 1225 uintptr_t *mw_vdevs; 1226 int mw_curvdev; 1227 uint64_t mw_nummss; 1228 uintptr_t *mw_mss; 1229 int mw_curms; 1230 } metaslab_walk_data_t; 1231 1232 static int 1233 metaslab_walk_step(mdb_walk_state_t *wsp) 1234 { 1235 metaslab_walk_data_t *mw = wsp->walk_data; 1236 metaslab_t ms; 1237 uintptr_t msp; 1238 1239 if (mw->mw_curvdev >= mw->mw_numvdevs) 1240 return (WALK_DONE); 1241 1242 if (mw->mw_mss == NULL) { 1243 uintptr_t mssp; 1244 uintptr_t vdevp; 1245 1246 ASSERT(mw->mw_curms == 0); 1247 ASSERT(mw->mw_nummss == 0); 1248 1249 vdevp = mw->mw_vdevs[mw->mw_curvdev]; 1250 if (GETMEMB(vdevp, struct vdev, vdev_ms, mssp) || 1251 GETMEMB(vdevp, struct vdev, vdev_ms_count, mw->mw_nummss)) { 1252 return (WALK_ERR); 1253 } 1254 1255 mw->mw_mss = mdb_alloc(mw->mw_nummss * sizeof (void*), 1256 UM_SLEEP | UM_GC); 1257 if (mdb_vread(mw->mw_mss, mw->mw_nummss * sizeof (void*), 1258 mssp) == -1) { 1259 mdb_warn("failed to read vdev_ms at %p", mssp); 1260 return (WALK_ERR); 1261 } 1262 } 1263 1264 if (mw->mw_curms >= mw->mw_nummss) { 1265 mw->mw_mss = NULL; 1266 mw->mw_curms = 0; 1267 mw->mw_nummss = 0; 1268 mw->mw_curvdev++; 1269 return (WALK_NEXT); 1270 } 1271 1272 msp = mw->mw_mss[mw->mw_curms]; 1273 if (mdb_vread(&ms, sizeof (metaslab_t), msp) == -1) { 1274 mdb_warn("failed to read metaslab_t at %p", msp); 1275 return (WALK_ERR); 1276 } 1277 1278 mw->mw_curms++; 1279 1280 return (wsp->walk_callback(msp, &ms, wsp->walk_cbdata)); 1281 } 1282 1283 /* ARGSUSED */ 1284 static int 1285 metaslab_walk_init(mdb_walk_state_t *wsp) 1286 { 1287 metaslab_walk_data_t *mw; 1288 uintptr_t root_vdevp; 1289 uintptr_t childp; 1290 1291 if (wsp->walk_addr == NULL) { 1292 mdb_warn("must supply address of spa_t\n"); 1293 return (WALK_ERR); 1294 } 1295 1296 mw = mdb_zalloc(sizeof (metaslab_walk_data_t), UM_SLEEP | UM_GC); 1297 1298 if (GETMEMB(wsp->walk_addr, struct spa, spa_root_vdev, root_vdevp) || 1299 GETMEMB(root_vdevp, struct vdev, vdev_children, mw->mw_numvdevs) || 1300 GETMEMB(root_vdevp, struct vdev, vdev_child, childp)) { 1301 return (DCMD_ERR); 1302 } 1303 1304 mw->mw_vdevs = mdb_alloc(mw->mw_numvdevs * sizeof (void *), 1305 UM_SLEEP | UM_GC); 1306 if (mdb_vread(mw->mw_vdevs, mw->mw_numvdevs * sizeof (void *), 1307 childp) == -1) { 1308 mdb_warn("failed to read root vdev children at %p", childp); 1309 return (DCMD_ERR); 1310 } 1311 1312 wsp->walk_data = mw; 1313 1314 return (WALK_NEXT); 1315 } 1316 1317 typedef struct mdb_spa { 1318 uintptr_t spa_dsl_pool; 1319 uintptr_t spa_root_vdev; 1320 } mdb_spa_t; 1321 1322 typedef struct mdb_dsl_dir { 1323 uintptr_t dd_phys; 1324 int64_t dd_space_towrite[TXG_SIZE]; 1325 } mdb_dsl_dir_t; 1326 1327 typedef struct mdb_dsl_dir_phys { 1328 uint64_t dd_used_bytes; 1329 uint64_t dd_compressed_bytes; 1330 uint64_t dd_uncompressed_bytes; 1331 } mdb_dsl_dir_phys_t; 1332 1333 typedef struct mdb_vdev { 1334 uintptr_t vdev_parent; 1335 uintptr_t vdev_ms; 1336 uint64_t vdev_ms_count; 1337 vdev_stat_t vdev_stat; 1338 } mdb_vdev_t; 1339 1340 typedef struct mdb_metaslab { 1341 space_map_t ms_allocmap[TXG_SIZE]; 1342 space_map_t ms_freemap[TXG_SIZE]; 1343 space_map_t ms_map; 1344 space_map_obj_t ms_smo; 1345 space_map_obj_t ms_smo_syncing; 1346 } mdb_metaslab_t; 1347 1348 typedef struct space_data { 1349 uint64_t ms_allocmap[TXG_SIZE]; 1350 uint64_t ms_freemap[TXG_SIZE]; 1351 uint64_t ms_map; 1352 uint64_t avail; 1353 uint64_t nowavail; 1354 } space_data_t; 1355 1356 /* ARGSUSED */ 1357 static int 1358 space_cb(uintptr_t addr, const void *unknown, void *arg) 1359 { 1360 space_data_t *sd = arg; 1361 mdb_metaslab_t ms; 1362 1363 if (GETMEMB(addr, struct metaslab, ms_allocmap, ms.ms_allocmap) || 1364 GETMEMB(addr, struct metaslab, ms_freemap, ms.ms_freemap) || 1365 GETMEMB(addr, struct metaslab, ms_map, ms.ms_map) || 1366 GETMEMB(addr, struct metaslab, ms_smo, ms.ms_smo) || 1367 GETMEMB(addr, struct metaslab, ms_smo_syncing, ms.ms_smo_syncing)) { 1368 return (WALK_ERR); 1369 } 1370 1371 sd->ms_allocmap[0] += ms.ms_allocmap[0].sm_space; 1372 sd->ms_allocmap[1] += ms.ms_allocmap[1].sm_space; 1373 sd->ms_allocmap[2] += ms.ms_allocmap[2].sm_space; 1374 sd->ms_allocmap[3] += ms.ms_allocmap[3].sm_space; 1375 sd->ms_freemap[0] += ms.ms_freemap[0].sm_space; 1376 sd->ms_freemap[1] += ms.ms_freemap[1].sm_space; 1377 sd->ms_freemap[2] += ms.ms_freemap[2].sm_space; 1378 sd->ms_freemap[3] += ms.ms_freemap[3].sm_space; 1379 sd->ms_map += ms.ms_map.sm_space; 1380 sd->avail += ms.ms_map.sm_size - ms.ms_smo.smo_alloc; 1381 sd->nowavail += ms.ms_map.sm_size - ms.ms_smo_syncing.smo_alloc; 1382 1383 return (WALK_NEXT); 1384 } 1385 1386 /* 1387 * ::spa_space [-b] 1388 * 1389 * Given a spa_t, print out it's on-disk space usage and in-core 1390 * estimates of future usage. If -b is given, print space in bytes. 1391 * Otherwise print in megabytes. 1392 */ 1393 /* ARGSUSED */ 1394 static int 1395 spa_space(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 1396 { 1397 mdb_spa_t spa; 1398 uintptr_t dp_root_dir; 1399 mdb_dsl_dir_t dd; 1400 mdb_dsl_dir_phys_t dsp; 1401 uint64_t children; 1402 uintptr_t childaddr; 1403 space_data_t sd; 1404 int shift = 20; 1405 char *suffix = "M"; 1406 int bits = FALSE; 1407 1408 if (mdb_getopts(argc, argv, 'b', MDB_OPT_SETBITS, TRUE, &bits, NULL) != 1409 argc) 1410 return (DCMD_USAGE); 1411 if (!(flags & DCMD_ADDRSPEC)) 1412 return (DCMD_USAGE); 1413 1414 if (bits) { 1415 shift = 0; 1416 suffix = ""; 1417 } 1418 1419 if (GETMEMB(addr, struct spa, spa_dsl_pool, spa.spa_dsl_pool) || 1420 GETMEMB(addr, struct spa, spa_root_vdev, spa.spa_root_vdev) || 1421 GETMEMB(spa.spa_root_vdev, struct vdev, vdev_children, children) || 1422 GETMEMB(spa.spa_root_vdev, struct vdev, vdev_child, childaddr) || 1423 GETMEMB(spa.spa_dsl_pool, struct dsl_pool, 1424 dp_root_dir, dp_root_dir) || 1425 GETMEMB(dp_root_dir, struct dsl_dir, dd_phys, dd.dd_phys) || 1426 GETMEMB(dp_root_dir, struct dsl_dir, 1427 dd_space_towrite, dd.dd_space_towrite) || 1428 GETMEMB(dd.dd_phys, struct dsl_dir_phys, 1429 dd_used_bytes, dsp.dd_used_bytes) || 1430 GETMEMB(dd.dd_phys, struct dsl_dir_phys, 1431 dd_compressed_bytes, dsp.dd_compressed_bytes) || 1432 GETMEMB(dd.dd_phys, struct dsl_dir_phys, 1433 dd_uncompressed_bytes, dsp.dd_uncompressed_bytes)) { 1434 return (DCMD_ERR); 1435 } 1436 1437 mdb_printf("dd_space_towrite = %llu%s %llu%s %llu%s %llu%s\n", 1438 dd.dd_space_towrite[0] >> shift, suffix, 1439 dd.dd_space_towrite[1] >> shift, suffix, 1440 dd.dd_space_towrite[2] >> shift, suffix, 1441 dd.dd_space_towrite[3] >> shift, suffix); 1442 1443 mdb_printf("dd_phys.dd_used_bytes = %llu%s\n", 1444 dsp.dd_used_bytes >> shift, suffix); 1445 mdb_printf("dd_phys.dd_compressed_bytes = %llu%s\n", 1446 dsp.dd_compressed_bytes >> shift, suffix); 1447 mdb_printf("dd_phys.dd_uncompressed_bytes = %llu%s\n", 1448 dsp.dd_uncompressed_bytes >> shift, suffix); 1449 1450 bzero(&sd, sizeof (sd)); 1451 if (mdb_pwalk("metaslab", space_cb, &sd, addr) != 0) { 1452 mdb_warn("can't walk metaslabs"); 1453 return (DCMD_ERR); 1454 } 1455 1456 mdb_printf("ms_allocmap = %llu%s %llu%s %llu%s %llu%s\n", 1457 sd.ms_allocmap[0] >> shift, suffix, 1458 sd.ms_allocmap[1] >> shift, suffix, 1459 sd.ms_allocmap[2] >> shift, suffix, 1460 sd.ms_allocmap[3] >> shift, suffix); 1461 mdb_printf("ms_freemap = %llu%s %llu%s %llu%s %llu%s\n", 1462 sd.ms_freemap[0] >> shift, suffix, 1463 sd.ms_freemap[1] >> shift, suffix, 1464 sd.ms_freemap[2] >> shift, suffix, 1465 sd.ms_freemap[3] >> shift, suffix); 1466 mdb_printf("ms_map = %llu%s\n", sd.ms_map >> shift, suffix); 1467 mdb_printf("last synced avail = %llu%s\n", sd.avail >> shift, suffix); 1468 mdb_printf("current syncing avail = %llu%s\n", 1469 sd.nowavail >> shift, suffix); 1470 1471 return (DCMD_OK); 1472 } 1473 1474 /* 1475 * ::spa_verify 1476 * 1477 * Given a spa_t, verify that that the pool is self-consistent. 1478 * Currently, it only checks to make sure that the vdev tree exists. 1479 */ 1480 /* ARGSUSED */ 1481 static int 1482 spa_verify(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 1483 { 1484 spa_t spa; 1485 1486 if (argc != 0 || !(flags & DCMD_ADDRSPEC)) 1487 return (DCMD_USAGE); 1488 1489 if (mdb_vread(&spa, sizeof (spa), addr) == -1) { 1490 mdb_warn("failed to read spa_t at %p", addr); 1491 return (DCMD_ERR); 1492 } 1493 1494 if (spa.spa_root_vdev == NULL) { 1495 mdb_printf("no vdev tree present\n"); 1496 return (DCMD_OK); 1497 } 1498 1499 return (DCMD_OK); 1500 } 1501 1502 static int 1503 spa_print_aux(spa_aux_vdev_t *sav, uint_t flags, mdb_arg_t *v, 1504 const char *name) 1505 { 1506 uintptr_t *aux; 1507 size_t len; 1508 int ret, i; 1509 1510 /* 1511 * Iterate over aux vdevs and print those out as well. This is a 1512 * little annoying because we don't have a root vdev to pass to ::vdev. 1513 * Instead, we print a single line and then call it for each child 1514 * vdev. 1515 */ 1516 if (sav->sav_count != 0) { 1517 v[1].a_type = MDB_TYPE_STRING; 1518 v[1].a_un.a_str = "-d"; 1519 v[2].a_type = MDB_TYPE_IMMEDIATE; 1520 v[2].a_un.a_val = 2; 1521 1522 len = sav->sav_count * sizeof (uintptr_t); 1523 aux = mdb_alloc(len, UM_SLEEP); 1524 if (mdb_vread(aux, len, 1525 (uintptr_t)sav->sav_vdevs) == -1) { 1526 mdb_free(aux, len); 1527 mdb_warn("failed to read l2cache vdevs at %p", 1528 sav->sav_vdevs); 1529 return (DCMD_ERR); 1530 } 1531 1532 mdb_printf("%-?s %-9s %-12s %s\n", "-", "-", "-", name); 1533 1534 for (i = 0; i < sav->sav_count; i++) { 1535 ret = mdb_call_dcmd("vdev", aux[i], flags, 3, v); 1536 if (ret != DCMD_OK) { 1537 mdb_free(aux, len); 1538 return (ret); 1539 } 1540 } 1541 1542 mdb_free(aux, len); 1543 } 1544 1545 return (0); 1546 } 1547 1548 /* 1549 * ::spa_vdevs 1550 * 1551 * -e Include error stats 1552 * 1553 * Print out a summarized list of vdevs for the given spa_t. 1554 * This is accomplished by invoking "::vdev -re" on the root vdev, as well as 1555 * iterating over the cache devices. 1556 */ 1557 /* ARGSUSED */ 1558 static int 1559 spa_vdevs(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 1560 { 1561 spa_t spa; 1562 mdb_arg_t v[3]; 1563 int errors = FALSE; 1564 int ret; 1565 1566 if (mdb_getopts(argc, argv, 1567 'e', MDB_OPT_SETBITS, TRUE, &errors, 1568 NULL) != argc) 1569 return (DCMD_USAGE); 1570 1571 if (!(flags & DCMD_ADDRSPEC)) 1572 return (DCMD_USAGE); 1573 1574 if (mdb_vread(&spa, sizeof (spa), addr) == -1) { 1575 mdb_warn("failed to read spa_t at %p", addr); 1576 return (DCMD_ERR); 1577 } 1578 1579 /* 1580 * Unitialized spa_t structures can have a NULL root vdev. 1581 */ 1582 if (spa.spa_root_vdev == NULL) { 1583 mdb_printf("no associated vdevs\n"); 1584 return (DCMD_OK); 1585 } 1586 1587 v[0].a_type = MDB_TYPE_STRING; 1588 v[0].a_un.a_str = errors ? "-re" : "-r"; 1589 1590 ret = mdb_call_dcmd("vdev", (uintptr_t)spa.spa_root_vdev, 1591 flags, 1, v); 1592 if (ret != DCMD_OK) 1593 return (ret); 1594 1595 if (spa_print_aux(&spa.spa_l2cache, flags, v, "cache") != 0 || 1596 spa_print_aux(&spa.spa_spares, flags, v, "spares") != 0) 1597 return (DCMD_ERR); 1598 1599 return (DCMD_OK); 1600 } 1601 1602 /* 1603 * ::zio 1604 * 1605 * Print a summary of zio_t and all its children. This is intended to display a 1606 * zio tree, and hence we only pick the most important pieces of information for 1607 * the main summary. More detailed information can always be found by doing a 1608 * '::print zio' on the underlying zio_t. The columns we display are: 1609 * 1610 * ADDRESS TYPE STAGE WAITER 1611 * 1612 * The 'address' column is indented by one space for each depth level as we 1613 * descend down the tree. 1614 */ 1615 1616 #define ZIO_MAXINDENT 24 1617 #define ZIO_MAXWIDTH (sizeof (uintptr_t) * 2 + ZIO_MAXINDENT) 1618 #define ZIO_WALK_SELF 0 1619 #define ZIO_WALK_CHILD 1 1620 #define ZIO_WALK_PARENT 2 1621 1622 typedef struct zio_print_args { 1623 int zpa_current_depth; 1624 int zpa_min_depth; 1625 int zpa_max_depth; 1626 int zpa_type; 1627 uint_t zpa_flags; 1628 } zio_print_args_t; 1629 1630 static int zio_child_cb(uintptr_t addr, const void *unknown, void *arg); 1631 1632 static int 1633 zio_print_cb(uintptr_t addr, const void *data, void *priv) 1634 { 1635 const zio_t *zio = data; 1636 zio_print_args_t *zpa = priv; 1637 mdb_ctf_id_t type_enum, stage_enum; 1638 int indent = zpa->zpa_current_depth; 1639 const char *type, *stage; 1640 uintptr_t laddr; 1641 1642 if (indent > ZIO_MAXINDENT) 1643 indent = ZIO_MAXINDENT; 1644 1645 if (mdb_ctf_lookup_by_name("enum zio_type", &type_enum) == -1 || 1646 mdb_ctf_lookup_by_name("enum zio_stage", &stage_enum) == -1) { 1647 mdb_warn("failed to lookup zio enums"); 1648 return (WALK_ERR); 1649 } 1650 1651 if ((type = mdb_ctf_enum_name(type_enum, zio->io_type)) != NULL) 1652 type += sizeof ("ZIO_TYPE_") - 1; 1653 else 1654 type = "?"; 1655 1656 if ((stage = mdb_ctf_enum_name(stage_enum, zio->io_stage)) != NULL) 1657 stage += sizeof ("ZIO_STAGE_") - 1; 1658 else 1659 stage = "?"; 1660 1661 if (zpa->zpa_current_depth >= zpa->zpa_min_depth) { 1662 if (zpa->zpa_flags & DCMD_PIPE_OUT) { 1663 mdb_printf("%?p\n", addr); 1664 } else { 1665 mdb_printf("%*s%-*p %-5s %-16s ", indent, "", 1666 ZIO_MAXWIDTH - indent, addr, type, stage); 1667 if (zio->io_waiter) 1668 mdb_printf("%?p\n", zio->io_waiter); 1669 else 1670 mdb_printf("-\n"); 1671 } 1672 } 1673 1674 if (zpa->zpa_current_depth >= zpa->zpa_max_depth) 1675 return (WALK_NEXT); 1676 1677 if (zpa->zpa_type == ZIO_WALK_PARENT) 1678 laddr = addr + OFFSETOF(zio_t, io_parent_list); 1679 else 1680 laddr = addr + OFFSETOF(zio_t, io_child_list); 1681 1682 zpa->zpa_current_depth++; 1683 if (mdb_pwalk("list", zio_child_cb, zpa, laddr) != 0) { 1684 mdb_warn("failed to walk zio_t children at %p\n", laddr); 1685 return (WALK_ERR); 1686 } 1687 zpa->zpa_current_depth--; 1688 1689 return (WALK_NEXT); 1690 } 1691 1692 /* ARGSUSED */ 1693 static int 1694 zio_child_cb(uintptr_t addr, const void *unknown, void *arg) 1695 { 1696 zio_link_t zl; 1697 zio_t zio; 1698 uintptr_t ziop; 1699 zio_print_args_t *zpa = arg; 1700 1701 if (mdb_vread(&zl, sizeof (zl), addr) == -1) { 1702 mdb_warn("failed to read zio_link_t at %p", addr); 1703 return (WALK_ERR); 1704 } 1705 1706 if (zpa->zpa_type == ZIO_WALK_PARENT) 1707 ziop = (uintptr_t)zl.zl_parent; 1708 else 1709 ziop = (uintptr_t)zl.zl_child; 1710 1711 if (mdb_vread(&zio, sizeof (zio_t), ziop) == -1) { 1712 mdb_warn("failed to read zio_t at %p", ziop); 1713 return (WALK_ERR); 1714 } 1715 1716 return (zio_print_cb(ziop, &zio, arg)); 1717 } 1718 1719 /* ARGSUSED */ 1720 static int 1721 zio_print(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 1722 { 1723 zio_t zio; 1724 zio_print_args_t zpa = { 0 }; 1725 1726 if (!(flags & DCMD_ADDRSPEC)) 1727 return (DCMD_USAGE); 1728 1729 if (mdb_getopts(argc, argv, 1730 'r', MDB_OPT_SETBITS, INT_MAX, &zpa.zpa_max_depth, 1731 'c', MDB_OPT_SETBITS, ZIO_WALK_CHILD, &zpa.zpa_type, 1732 'p', MDB_OPT_SETBITS, ZIO_WALK_PARENT, &zpa.zpa_type, 1733 NULL) != argc) 1734 return (DCMD_USAGE); 1735 1736 zpa.zpa_flags = flags; 1737 if (zpa.zpa_max_depth != 0) { 1738 if (zpa.zpa_type == ZIO_WALK_SELF) 1739 zpa.zpa_type = ZIO_WALK_CHILD; 1740 } else if (zpa.zpa_type != ZIO_WALK_SELF) { 1741 zpa.zpa_min_depth = 1; 1742 zpa.zpa_max_depth = 1; 1743 } 1744 1745 if (mdb_vread(&zio, sizeof (zio_t), addr) == -1) { 1746 mdb_warn("failed to read zio_t at %p", addr); 1747 return (DCMD_ERR); 1748 } 1749 1750 if (!(flags & DCMD_PIPE_OUT) && DCMD_HDRSPEC(flags)) 1751 mdb_printf("%<u>%-*s %-5s %-16s %-?s%</u>\n", ZIO_MAXWIDTH, 1752 "ADDRESS", "TYPE", "STAGE", "WAITER"); 1753 1754 if (zio_print_cb(addr, &zio, &zpa) != WALK_NEXT) 1755 return (DCMD_ERR); 1756 1757 return (DCMD_OK); 1758 } 1759 1760 /* 1761 * [addr]::zio_state 1762 * 1763 * Print a summary of all zio_t structures on the system, or for a particular 1764 * pool. This is equivalent to '::walk zio_root | ::zio'. 1765 */ 1766 /*ARGSUSED*/ 1767 static int 1768 zio_state(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 1769 { 1770 /* 1771 * MDB will remember the last address of the pipeline, so if we don't 1772 * zero this we'll end up trying to walk zio structures for a 1773 * non-existent spa_t. 1774 */ 1775 if (!(flags & DCMD_ADDRSPEC)) 1776 addr = 0; 1777 1778 return (mdb_pwalk_dcmd("zio_root", "zio", argc, argv, addr)); 1779 } 1780 1781 typedef struct txg_list_walk_data { 1782 uintptr_t lw_head[TXG_SIZE]; 1783 int lw_txgoff; 1784 int lw_maxoff; 1785 size_t lw_offset; 1786 void *lw_obj; 1787 } txg_list_walk_data_t; 1788 1789 static int 1790 txg_list_walk_init_common(mdb_walk_state_t *wsp, int txg, int maxoff) 1791 { 1792 txg_list_walk_data_t *lwd; 1793 txg_list_t list; 1794 int i; 1795 1796 lwd = mdb_alloc(sizeof (txg_list_walk_data_t), UM_SLEEP | UM_GC); 1797 if (mdb_vread(&list, sizeof (txg_list_t), wsp->walk_addr) == -1) { 1798 mdb_warn("failed to read txg_list_t at %#lx", wsp->walk_addr); 1799 return (WALK_ERR); 1800 } 1801 1802 for (i = 0; i < TXG_SIZE; i++) 1803 lwd->lw_head[i] = (uintptr_t)list.tl_head[i]; 1804 lwd->lw_offset = list.tl_offset; 1805 lwd->lw_obj = mdb_alloc(lwd->lw_offset + sizeof (txg_node_t), 1806 UM_SLEEP | UM_GC); 1807 lwd->lw_txgoff = txg; 1808 lwd->lw_maxoff = maxoff; 1809 1810 wsp->walk_addr = lwd->lw_head[lwd->lw_txgoff]; 1811 wsp->walk_data = lwd; 1812 1813 return (WALK_NEXT); 1814 } 1815 1816 static int 1817 txg_list_walk_init(mdb_walk_state_t *wsp) 1818 { 1819 return (txg_list_walk_init_common(wsp, 0, TXG_SIZE-1)); 1820 } 1821 1822 static int 1823 txg_list0_walk_init(mdb_walk_state_t *wsp) 1824 { 1825 return (txg_list_walk_init_common(wsp, 0, 0)); 1826 } 1827 1828 static int 1829 txg_list1_walk_init(mdb_walk_state_t *wsp) 1830 { 1831 return (txg_list_walk_init_common(wsp, 1, 1)); 1832 } 1833 1834 static int 1835 txg_list2_walk_init(mdb_walk_state_t *wsp) 1836 { 1837 return (txg_list_walk_init_common(wsp, 2, 2)); 1838 } 1839 1840 static int 1841 txg_list3_walk_init(mdb_walk_state_t *wsp) 1842 { 1843 return (txg_list_walk_init_common(wsp, 3, 3)); 1844 } 1845 1846 static int 1847 txg_list_walk_step(mdb_walk_state_t *wsp) 1848 { 1849 txg_list_walk_data_t *lwd = wsp->walk_data; 1850 uintptr_t addr; 1851 txg_node_t *node; 1852 int status; 1853 1854 while (wsp->walk_addr == NULL && lwd->lw_txgoff < lwd->lw_maxoff) { 1855 lwd->lw_txgoff++; 1856 wsp->walk_addr = lwd->lw_head[lwd->lw_txgoff]; 1857 } 1858 1859 if (wsp->walk_addr == NULL) 1860 return (WALK_DONE); 1861 1862 addr = wsp->walk_addr - lwd->lw_offset; 1863 1864 if (mdb_vread(lwd->lw_obj, 1865 lwd->lw_offset + sizeof (txg_node_t), addr) == -1) { 1866 mdb_warn("failed to read list element at %#lx", addr); 1867 return (WALK_ERR); 1868 } 1869 1870 status = wsp->walk_callback(addr, lwd->lw_obj, wsp->walk_cbdata); 1871 node = (txg_node_t *)((uintptr_t)lwd->lw_obj + lwd->lw_offset); 1872 wsp->walk_addr = (uintptr_t)node->tn_next[lwd->lw_txgoff]; 1873 1874 return (status); 1875 } 1876 1877 /* 1878 * ::walk spa 1879 * 1880 * Walk all named spa_t structures in the namespace. This is nothing more than 1881 * a layered avl walk. 1882 */ 1883 static int 1884 spa_walk_init(mdb_walk_state_t *wsp) 1885 { 1886 GElf_Sym sym; 1887 1888 if (wsp->walk_addr != NULL) { 1889 mdb_warn("spa walk only supports global walks\n"); 1890 return (WALK_ERR); 1891 } 1892 1893 if (mdb_lookup_by_obj(ZFS_OBJ_NAME, "spa_namespace_avl", &sym) == -1) { 1894 mdb_warn("failed to find symbol 'spa_namespace_avl'"); 1895 return (WALK_ERR); 1896 } 1897 1898 wsp->walk_addr = (uintptr_t)sym.st_value; 1899 1900 if (mdb_layered_walk("avl", wsp) == -1) { 1901 mdb_warn("failed to walk 'avl'\n"); 1902 return (WALK_ERR); 1903 } 1904 1905 return (WALK_NEXT); 1906 } 1907 1908 static int 1909 spa_walk_step(mdb_walk_state_t *wsp) 1910 { 1911 spa_t spa; 1912 1913 if (mdb_vread(&spa, sizeof (spa), wsp->walk_addr) == -1) { 1914 mdb_warn("failed to read spa_t at %p", wsp->walk_addr); 1915 return (WALK_ERR); 1916 } 1917 1918 return (wsp->walk_callback(wsp->walk_addr, &spa, wsp->walk_cbdata)); 1919 } 1920 1921 /* 1922 * [addr]::walk zio 1923 * 1924 * Walk all active zio_t structures on the system. This is simply a layered 1925 * walk on top of ::walk zio_cache, with the optional ability to limit the 1926 * structures to a particular pool. 1927 */ 1928 static int 1929 zio_walk_init(mdb_walk_state_t *wsp) 1930 { 1931 wsp->walk_data = (void *)wsp->walk_addr; 1932 1933 if (mdb_layered_walk("zio_cache", wsp) == -1) { 1934 mdb_warn("failed to walk 'zio_cache'\n"); 1935 return (WALK_ERR); 1936 } 1937 1938 return (WALK_NEXT); 1939 } 1940 1941 static int 1942 zio_walk_step(mdb_walk_state_t *wsp) 1943 { 1944 zio_t zio; 1945 1946 if (mdb_vread(&zio, sizeof (zio), wsp->walk_addr) == -1) { 1947 mdb_warn("failed to read zio_t at %p", wsp->walk_addr); 1948 return (WALK_ERR); 1949 } 1950 1951 if (wsp->walk_data != NULL && wsp->walk_data != zio.io_spa) 1952 return (WALK_NEXT); 1953 1954 return (wsp->walk_callback(wsp->walk_addr, &zio, wsp->walk_cbdata)); 1955 } 1956 1957 /* 1958 * [addr]::walk zio_root 1959 * 1960 * Walk only root zio_t structures, optionally for a particular spa_t. 1961 */ 1962 static int 1963 zio_walk_root_step(mdb_walk_state_t *wsp) 1964 { 1965 zio_t zio; 1966 1967 if (mdb_vread(&zio, sizeof (zio), wsp->walk_addr) == -1) { 1968 mdb_warn("failed to read zio_t at %p", wsp->walk_addr); 1969 return (WALK_ERR); 1970 } 1971 1972 if (wsp->walk_data != NULL && wsp->walk_data != zio.io_spa) 1973 return (WALK_NEXT); 1974 1975 /* If the parent list is not empty, ignore */ 1976 if (zio.io_parent_list.list_head.list_next != 1977 &((zio_t *)wsp->walk_addr)->io_parent_list.list_head) 1978 return (WALK_NEXT); 1979 1980 return (wsp->walk_callback(wsp->walk_addr, &zio, wsp->walk_cbdata)); 1981 } 1982 1983 #define NICENUM_BUFLEN 6 1984 1985 static int 1986 snprintfrac(char *buf, int len, 1987 uint64_t numerator, uint64_t denom, int frac_digits) 1988 { 1989 int mul = 1; 1990 int whole, frac, i; 1991 1992 for (i = frac_digits; i; i--) 1993 mul *= 10; 1994 whole = numerator / denom; 1995 frac = mul * numerator / denom - mul * whole; 1996 return (mdb_snprintf(buf, len, "%u.%0*u", whole, frac_digits, frac)); 1997 } 1998 1999 static void 2000 mdb_nicenum(uint64_t num, char *buf) 2001 { 2002 uint64_t n = num; 2003 int index = 0; 2004 char *u; 2005 2006 while (n >= 1024) { 2007 n = (n + (1024 / 2)) / 1024; /* Round up or down */ 2008 index++; 2009 } 2010 2011 u = &" \0K\0M\0G\0T\0P\0E\0"[index*2]; 2012 2013 if (index == 0) { 2014 (void) mdb_snprintf(buf, NICENUM_BUFLEN, "%llu", 2015 (u_longlong_t)n); 2016 } else if (n < 10 && (num & (num - 1)) != 0) { 2017 (void) snprintfrac(buf, NICENUM_BUFLEN, 2018 num, 1ULL << 10 * index, 2); 2019 strcat(buf, u); 2020 } else if (n < 100 && (num & (num - 1)) != 0) { 2021 (void) snprintfrac(buf, NICENUM_BUFLEN, 2022 num, 1ULL << 10 * index, 1); 2023 strcat(buf, u); 2024 } else { 2025 (void) mdb_snprintf(buf, NICENUM_BUFLEN, "%llu%s", 2026 (u_longlong_t)n, u); 2027 } 2028 } 2029 2030 /* 2031 * ::zfs_blkstats 2032 * 2033 * -v print verbose per-level information 2034 * 2035 */ 2036 static int 2037 zfs_blkstats(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 2038 { 2039 boolean_t verbose = B_FALSE; 2040 zfs_all_blkstats_t stats; 2041 dmu_object_type_t t; 2042 zfs_blkstat_t *tzb; 2043 uint64_t ditto; 2044 dmu_object_type_info_t dmu_ot[DMU_OT_NUMTYPES + 10]; 2045 /* +10 in case it grew */ 2046 2047 if (mdb_readvar(&dmu_ot, "dmu_ot") == -1) { 2048 mdb_warn("failed to read 'dmu_ot'"); 2049 return (DCMD_ERR); 2050 } 2051 2052 if (mdb_getopts(argc, argv, 2053 'v', MDB_OPT_SETBITS, TRUE, &verbose, 2054 NULL) != argc) 2055 return (DCMD_USAGE); 2056 2057 if (!(flags & DCMD_ADDRSPEC)) 2058 return (DCMD_USAGE); 2059 2060 if (GETMEMB(addr, struct spa, spa_dsl_pool, addr) || 2061 GETMEMB(addr, struct dsl_pool, dp_blkstats, addr) || 2062 mdb_vread(&stats, sizeof (zfs_all_blkstats_t), addr) == -1) { 2063 mdb_warn("failed to read data at %p;", addr); 2064 mdb_printf("maybe no stats? run \"zpool scrub\" first."); 2065 return (DCMD_ERR); 2066 } 2067 2068 tzb = &stats.zab_type[DN_MAX_LEVELS][DMU_OT_NUMTYPES]; 2069 if (tzb->zb_gangs != 0) { 2070 mdb_printf("Ganged blocks: %llu\n", 2071 (longlong_t)tzb->zb_gangs); 2072 } 2073 2074 ditto = tzb->zb_ditto_2_of_2_samevdev + tzb->zb_ditto_2_of_3_samevdev + 2075 tzb->zb_ditto_3_of_3_samevdev; 2076 if (ditto != 0) { 2077 mdb_printf("Dittoed blocks on same vdev: %llu\n", 2078 (longlong_t)ditto); 2079 } 2080 2081 mdb_printf("\nBlocks\tLSIZE\tPSIZE\tASIZE" 2082 "\t avg\t comp\t%%Total\tType\n"); 2083 2084 for (t = 0; t <= DMU_OT_NUMTYPES; t++) { 2085 char csize[NICENUM_BUFLEN], lsize[NICENUM_BUFLEN]; 2086 char psize[NICENUM_BUFLEN], asize[NICENUM_BUFLEN]; 2087 char avg[NICENUM_BUFLEN]; 2088 char comp[NICENUM_BUFLEN], pct[NICENUM_BUFLEN]; 2089 char typename[64]; 2090 int l; 2091 2092 2093 if (t == DMU_OT_DEFERRED) 2094 strcpy(typename, "deferred free"); 2095 else if (t == DMU_OT_TOTAL) 2096 strcpy(typename, "Total"); 2097 else if (mdb_readstr(typename, sizeof (typename), 2098 (uintptr_t)dmu_ot[t].ot_name) == -1) { 2099 mdb_warn("failed to read type name"); 2100 return (DCMD_ERR); 2101 } 2102 2103 if (stats.zab_type[DN_MAX_LEVELS][t].zb_asize == 0) 2104 continue; 2105 2106 for (l = -1; l < DN_MAX_LEVELS; l++) { 2107 int level = (l == -1 ? DN_MAX_LEVELS : l); 2108 zfs_blkstat_t *zb = &stats.zab_type[level][t]; 2109 2110 if (zb->zb_asize == 0) 2111 continue; 2112 2113 /* 2114 * Don't print each level unless requested. 2115 */ 2116 if (!verbose && level != DN_MAX_LEVELS) 2117 continue; 2118 2119 /* 2120 * If all the space is level 0, don't print the 2121 * level 0 separately. 2122 */ 2123 if (level == 0 && zb->zb_asize == 2124 stats.zab_type[DN_MAX_LEVELS][t].zb_asize) 2125 continue; 2126 2127 mdb_nicenum(zb->zb_count, csize); 2128 mdb_nicenum(zb->zb_lsize, lsize); 2129 mdb_nicenum(zb->zb_psize, psize); 2130 mdb_nicenum(zb->zb_asize, asize); 2131 mdb_nicenum(zb->zb_asize / zb->zb_count, avg); 2132 (void) snprintfrac(comp, NICENUM_BUFLEN, 2133 zb->zb_lsize, zb->zb_psize, 2); 2134 (void) snprintfrac(pct, NICENUM_BUFLEN, 2135 100 * zb->zb_asize, tzb->zb_asize, 2); 2136 2137 mdb_printf("%6s\t%5s\t%5s\t%5s\t%5s" 2138 "\t%5s\t%6s\t", 2139 csize, lsize, psize, asize, avg, comp, pct); 2140 2141 if (level == DN_MAX_LEVELS) 2142 mdb_printf("%s\n", typename); 2143 else 2144 mdb_printf(" L%d %s\n", 2145 level, typename); 2146 } 2147 } 2148 2149 return (DCMD_OK); 2150 } 2151 2152 /* ARGSUSED */ 2153 static int 2154 reference_cb(uintptr_t addr, const void *ignored, void *arg) 2155 { 2156 static int gotid; 2157 static mdb_ctf_id_t ref_id; 2158 uintptr_t ref_holder; 2159 uintptr_t ref_removed; 2160 uint64_t ref_number; 2161 boolean_t holder_is_str; 2162 char holder_str[128]; 2163 boolean_t removed = (boolean_t)arg; 2164 2165 if (!gotid) { 2166 if (mdb_ctf_lookup_by_name("struct reference", &ref_id) == -1) { 2167 mdb_warn("couldn't find struct reference"); 2168 return (WALK_ERR); 2169 } 2170 gotid = TRUE; 2171 } 2172 2173 if (GETMEMBID(addr, &ref_id, ref_holder, ref_holder) || 2174 GETMEMBID(addr, &ref_id, ref_removed, ref_removed) || 2175 GETMEMBID(addr, &ref_id, ref_number, ref_number)) 2176 return (WALK_ERR); 2177 2178 if (mdb_readstr(holder_str, sizeof (holder_str), ref_holder) != -1) { 2179 char *cp; 2180 holder_is_str = B_TRUE; 2181 for (cp = holder_str; *cp; cp++) { 2182 if (!isprint(*cp)) { 2183 holder_is_str = B_FALSE; 2184 break; 2185 } 2186 } 2187 } else { 2188 holder_is_str = B_FALSE; 2189 } 2190 2191 if (removed) 2192 mdb_printf("removed "); 2193 mdb_printf("reference "); 2194 if (ref_number != 1) 2195 mdb_printf("with count=%llu ", ref_number); 2196 mdb_printf("with tag %p", (void*)ref_holder); 2197 if (holder_is_str) 2198 mdb_printf(" \"%s\"", holder_str); 2199 mdb_printf(", held at:\n"); 2200 2201 (void) mdb_call_dcmd("whatis", addr, DCMD_ADDRSPEC, 0, NULL); 2202 2203 if (removed) { 2204 mdb_printf("removed at:\n"); 2205 (void) mdb_call_dcmd("whatis", ref_removed, 2206 DCMD_ADDRSPEC, 0, NULL); 2207 } 2208 2209 mdb_printf("\n"); 2210 2211 return (WALK_NEXT); 2212 } 2213 2214 /* ARGSUSED */ 2215 static int 2216 refcount(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 2217 { 2218 uint64_t rc_count, rc_removed_count; 2219 uintptr_t rc_list, rc_removed; 2220 static int gotid; 2221 static mdb_ctf_id_t rc_id; 2222 ulong_t off; 2223 2224 if (!(flags & DCMD_ADDRSPEC)) 2225 return (DCMD_USAGE); 2226 2227 if (!gotid) { 2228 if (mdb_ctf_lookup_by_name("struct refcount", &rc_id) == -1) { 2229 mdb_warn("couldn't find struct refcount"); 2230 return (DCMD_ERR); 2231 } 2232 gotid = TRUE; 2233 } 2234 2235 if (GETMEMBID(addr, &rc_id, rc_count, rc_count) || 2236 GETMEMBID(addr, &rc_id, rc_removed_count, rc_removed_count)) 2237 return (DCMD_ERR); 2238 2239 mdb_printf("refcount_t at %p has %llu current holds, " 2240 "%llu recently released holds\n", 2241 addr, (longlong_t)rc_count, (longlong_t)rc_removed_count); 2242 2243 if (rc_count > 0) 2244 mdb_printf("current holds:\n"); 2245 if (mdb_ctf_offsetof(rc_id, "rc_list", &off) == -1) 2246 return (DCMD_ERR); 2247 rc_list = addr + off/NBBY; 2248 mdb_pwalk("list", reference_cb, (void*)B_FALSE, rc_list); 2249 2250 if (rc_removed_count > 0) 2251 mdb_printf("released holds:\n"); 2252 if (mdb_ctf_offsetof(rc_id, "rc_removed", &off) == -1) 2253 return (DCMD_ERR); 2254 rc_removed = addr + off/NBBY; 2255 mdb_pwalk("list", reference_cb, (void*)B_TRUE, rc_removed); 2256 2257 return (DCMD_OK); 2258 } 2259 2260 /* 2261 * MDB module linkage information: 2262 * 2263 * We declare a list of structures describing our dcmds, and a function 2264 * named _mdb_init to return a pointer to our module information. 2265 */ 2266 2267 static const mdb_dcmd_t dcmds[] = { 2268 { "arc", "[-bkmg]", "print ARC variables", arc_print }, 2269 { "blkptr", ":", "print blkptr_t", blkptr }, 2270 { "dbuf", ":", "print dmu_buf_impl_t", dbuf }, 2271 { "dbuf_stats", ":", "dbuf stats", dbuf_stats }, 2272 { "dbufs", 2273 "\t[-O objset_t*] [-n objset_name | \"mos\"] " 2274 "[-o object | \"mdn\"] \n" 2275 "\t[-l level] [-b blkid | \"bonus\"]", 2276 "find dmu_buf_impl_t's that match specified criteria", dbufs }, 2277 { "abuf_find", "dva_word[0] dva_word[1]", 2278 "find arc_buf_hdr_t of a specified DVA", 2279 abuf_find }, 2280 { "spa", "?[-cv]", "spa_t summary", spa_print }, 2281 { "spa_config", ":", "print spa_t configuration", spa_print_config }, 2282 { "spa_verify", ":", "verify spa_t consistency", spa_verify }, 2283 { "spa_space", ":[-b]", "print spa_t on-disk space usage", spa_space }, 2284 { "spa_vdevs", ":", "given a spa_t, print vdev summary", spa_vdevs }, 2285 { "vdev", ":[-re]\n" 2286 "\t-r display recursively\n" 2287 "\t-e print statistics", 2288 "vdev_t summary", vdev_print }, 2289 { "zio", ":[cpr]\n" 2290 "\t-c display children\n" 2291 "\t-p display parents\n" 2292 "\t-r display recursively", 2293 "zio_t summary", zio_print }, 2294 { "zio_state", "?", "print out all zio_t structures on system or " 2295 "for a particular pool", zio_state }, 2296 { "zio_pipeline", ":", "decode a zio pipeline", zio_pipeline }, 2297 { "zfs_blkstats", ":[-v]", 2298 "given a spa_t, print block type stats from last scrub", 2299 zfs_blkstats }, 2300 { "zfs_params", "", "print zfs tunable parameters", zfs_params }, 2301 { "refcount", "", "print refcount_t holders", refcount }, 2302 { NULL } 2303 }; 2304 2305 static const mdb_walker_t walkers[] = { 2306 /* 2307 * In userland, there is no generic provider of list_t walkers, so we 2308 * need to add it. 2309 */ 2310 #ifndef _KERNEL 2311 { LIST_WALK_NAME, LIST_WALK_DESC, 2312 list_walk_init, list_walk_step, list_walk_fini }, 2313 #endif 2314 { "zms_freelist", "walk ZFS metaslab freelist", 2315 freelist_walk_init, freelist_walk_step, NULL }, 2316 { "txg_list", "given any txg_list_t *, walk all entries in all txgs", 2317 txg_list_walk_init, txg_list_walk_step, NULL }, 2318 { "txg_list0", "given any txg_list_t *, walk all entries in txg 0", 2319 txg_list0_walk_init, txg_list_walk_step, NULL }, 2320 { "txg_list1", "given any txg_list_t *, walk all entries in txg 1", 2321 txg_list1_walk_init, txg_list_walk_step, NULL }, 2322 { "txg_list2", "given any txg_list_t *, walk all entries in txg 2", 2323 txg_list2_walk_init, txg_list_walk_step, NULL }, 2324 { "txg_list3", "given any txg_list_t *, walk all entries in txg 3", 2325 txg_list3_walk_init, txg_list_walk_step, NULL }, 2326 { "zio", "walk all zio structures, optionally for a particular spa_t", 2327 zio_walk_init, zio_walk_step, NULL }, 2328 { "zio_root", "walk all root zio_t structures, optionally for a " 2329 "particular spa_t", 2330 zio_walk_init, zio_walk_root_step, NULL }, 2331 { "spa", "walk all spa_t entries in the namespace", 2332 spa_walk_init, spa_walk_step, NULL }, 2333 { "metaslab", "given a spa_t *, walk all metaslab_t structures", 2334 metaslab_walk_init, metaslab_walk_step, NULL }, 2335 { NULL } 2336 }; 2337 2338 static const mdb_modinfo_t modinfo = { 2339 MDB_API_VERSION, dcmds, walkers 2340 }; 2341 2342 const mdb_modinfo_t * 2343 _mdb_init(void) 2344 { 2345 return (&modinfo); 2346 } 2347