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