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