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