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 (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. 23 * Copyright 2011 Nexenta Systems, Inc. All rights reserved. 24 * Copyright (c) 2011, 2018 by Delphix. All rights reserved. 25 * Copyright 2019 Joyent, Inc. 26 */ 27 28 /* Portions Copyright 2010 Robert Milkowski */ 29 30 /* 31 * ZFS_MDB lets dmu.h know that we don't have dmu_ot, and we will define our 32 * own macros to access the target's dmu_ot. Therefore it must be defined 33 * before including any ZFS headers. Note that we don't define 34 * DMU_OT_IS_ENCRYPTED_IMPL() or DMU_OT_BYTESWAP_IMPL(), therefore using them 35 * will result in a compilation error. If they are needed in the future, we 36 * can implement them similarly to mdb_dmu_ot_is_encrypted_impl(). 37 */ 38 #define ZFS_MDB 39 #define DMU_OT_IS_ENCRYPTED_IMPL(ot) mdb_dmu_ot_is_encrypted_impl(ot) 40 41 #include <mdb/mdb_ctf.h> 42 #include <sys/zfs_context.h> 43 #include <sys/mdb_modapi.h> 44 #include <sys/dbuf.h> 45 #include <sys/dmu_objset.h> 46 #include <sys/dsl_dir.h> 47 #include <sys/dsl_pool.h> 48 #include <sys/metaslab_impl.h> 49 #include <sys/space_map.h> 50 #include <sys/list.h> 51 #include <sys/vdev_impl.h> 52 #include <sys/zap_leaf.h> 53 #include <sys/zap_impl.h> 54 #include <ctype.h> 55 #include <sys/zfs_acl.h> 56 #include <sys/sa_impl.h> 57 #include <sys/multilist.h> 58 #include <sys/btree.h> 59 60 #ifdef _KERNEL 61 #define ZFS_OBJ_NAME "zfs" 62 extern int64_t mdb_gethrtime(void); 63 #else 64 #define ZFS_OBJ_NAME "libzpool.so.1" 65 #endif 66 67 #define ZFS_STRUCT "struct " ZFS_OBJ_NAME "`" 68 69 #ifndef _KERNEL 70 int aok; 71 #endif 72 73 enum spa_flags { 74 SPA_FLAG_CONFIG = 1 << 0, 75 SPA_FLAG_VDEVS = 1 << 1, 76 SPA_FLAG_ERRORS = 1 << 2, 77 SPA_FLAG_METASLAB_GROUPS = 1 << 3, 78 SPA_FLAG_METASLABS = 1 << 4, 79 SPA_FLAG_HISTOGRAMS = 1 << 5 80 }; 81 82 /* 83 * If any of these flags are set, call spa_vdevs in spa_print 84 */ 85 #define SPA_FLAG_ALL_VDEV \ 86 (SPA_FLAG_VDEVS | SPA_FLAG_ERRORS | SPA_FLAG_METASLAB_GROUPS | \ 87 SPA_FLAG_METASLABS) 88 89 static int 90 getmember(uintptr_t addr, const char *type, mdb_ctf_id_t *idp, 91 const char *member, int len, void *buf) 92 { 93 mdb_ctf_id_t id; 94 ulong_t off; 95 char name[64]; 96 97 if (idp == NULL) { 98 if (mdb_ctf_lookup_by_name(type, &id) == -1) { 99 mdb_warn("couldn't find type %s", type); 100 return (DCMD_ERR); 101 } 102 idp = &id; 103 } else { 104 type = name; 105 mdb_ctf_type_name(*idp, name, sizeof (name)); 106 } 107 108 if (mdb_ctf_offsetof(*idp, member, &off) == -1) { 109 mdb_warn("couldn't find member %s of type %s\n", member, type); 110 return (DCMD_ERR); 111 } 112 if (off % 8 != 0) { 113 mdb_warn("member %s of type %s is unsupported bitfield", 114 member, type); 115 return (DCMD_ERR); 116 } 117 off /= 8; 118 119 if (mdb_vread(buf, len, addr + off) == -1) { 120 mdb_warn("failed to read %s from %s at %p", 121 member, type, addr + off); 122 return (DCMD_ERR); 123 } 124 /* mdb_warn("read %s from %s at %p+%llx\n", member, type, addr, off); */ 125 126 return (0); 127 } 128 129 #define GETMEMB(addr, structname, member, dest) \ 130 getmember(addr, ZFS_STRUCT structname, NULL, #member, \ 131 sizeof (dest), &(dest)) 132 133 #define GETMEMBID(addr, ctfid, member, dest) \ 134 getmember(addr, NULL, ctfid, #member, sizeof (dest), &(dest)) 135 136 static boolean_t 137 strisprint(const char *cp) 138 { 139 for (; *cp; cp++) { 140 if (!isprint(*cp)) 141 return (B_FALSE); 142 } 143 return (B_TRUE); 144 } 145 146 /* 147 * <addr>::sm_entries <buffer length in bytes> 148 * 149 * Treat the buffer specified by the given address as a buffer that contains 150 * space map entries. Iterate over the specified number of entries and print 151 * them in both encoded and decoded form. 152 */ 153 /* ARGSUSED */ 154 static int 155 sm_entries(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 156 { 157 uint64_t bufsz = 0; 158 boolean_t preview = B_FALSE; 159 160 if (!(flags & DCMD_ADDRSPEC)) 161 return (DCMD_USAGE); 162 163 if (argc < 1) { 164 preview = B_TRUE; 165 bufsz = 2; 166 } else if (argc != 1) { 167 return (DCMD_USAGE); 168 } else { 169 switch (argv[0].a_type) { 170 case MDB_TYPE_STRING: 171 bufsz = mdb_strtoull(argv[0].a_un.a_str); 172 break; 173 case MDB_TYPE_IMMEDIATE: 174 bufsz = argv[0].a_un.a_val; 175 break; 176 default: 177 return (DCMD_USAGE); 178 } 179 } 180 181 char *actions[] = { "ALLOC", "FREE", "INVALID" }; 182 for (uintptr_t bufend = addr + bufsz; addr < bufend; 183 addr += sizeof (uint64_t)) { 184 uint64_t nwords; 185 uint64_t start_addr = addr; 186 187 uint64_t word = 0; 188 if (mdb_vread(&word, sizeof (word), addr) == -1) { 189 mdb_warn("failed to read space map entry %p", addr); 190 return (DCMD_ERR); 191 } 192 193 if (SM_PREFIX_DECODE(word) == SM_DEBUG_PREFIX) { 194 (void) mdb_printf("\t [%6llu] %s: txg %llu, " 195 "pass %llu\n", 196 (u_longlong_t)(addr), 197 actions[SM_DEBUG_ACTION_DECODE(word)], 198 (u_longlong_t)SM_DEBUG_TXG_DECODE(word), 199 (u_longlong_t)SM_DEBUG_SYNCPASS_DECODE(word)); 200 continue; 201 } 202 203 char entry_type; 204 uint64_t raw_offset, raw_run, vdev_id = SM_NO_VDEVID; 205 206 if (SM_PREFIX_DECODE(word) != SM2_PREFIX) { 207 entry_type = (SM_TYPE_DECODE(word) == SM_ALLOC) ? 208 'A' : 'F'; 209 raw_offset = SM_OFFSET_DECODE(word); 210 raw_run = SM_RUN_DECODE(word); 211 nwords = 1; 212 } else { 213 ASSERT3U(SM_PREFIX_DECODE(word), ==, SM2_PREFIX); 214 215 raw_run = SM2_RUN_DECODE(word); 216 vdev_id = SM2_VDEV_DECODE(word); 217 218 /* it is a two-word entry so we read another word */ 219 addr += sizeof (uint64_t); 220 if (addr >= bufend) { 221 mdb_warn("buffer ends in the middle of a two " 222 "word entry\n", addr); 223 return (DCMD_ERR); 224 } 225 226 if (mdb_vread(&word, sizeof (word), addr) == -1) { 227 mdb_warn("failed to read space map entry %p", 228 addr); 229 return (DCMD_ERR); 230 } 231 232 entry_type = (SM2_TYPE_DECODE(word) == SM_ALLOC) ? 233 'A' : 'F'; 234 raw_offset = SM2_OFFSET_DECODE(word); 235 nwords = 2; 236 } 237 238 (void) mdb_printf("\t [%6llx] %c range:" 239 " %010llx-%010llx size: %06llx vdev: %06llu words: %llu\n", 240 (u_longlong_t)start_addr, 241 entry_type, (u_longlong_t)raw_offset, 242 (u_longlong_t)(raw_offset + raw_run), 243 (u_longlong_t)raw_run, 244 (u_longlong_t)vdev_id, (u_longlong_t)nwords); 245 246 if (preview) 247 break; 248 } 249 return (DCMD_OK); 250 } 251 252 static int 253 mdb_dsl_dir_name(uintptr_t addr, char *buf) 254 { 255 static int gotid; 256 static mdb_ctf_id_t dd_id; 257 uintptr_t dd_parent; 258 char dd_myname[ZFS_MAX_DATASET_NAME_LEN]; 259 260 if (!gotid) { 261 if (mdb_ctf_lookup_by_name(ZFS_STRUCT "dsl_dir", 262 &dd_id) == -1) { 263 mdb_warn("couldn't find struct dsl_dir"); 264 return (DCMD_ERR); 265 } 266 gotid = TRUE; 267 } 268 if (GETMEMBID(addr, &dd_id, dd_parent, dd_parent) || 269 GETMEMBID(addr, &dd_id, dd_myname, dd_myname)) { 270 return (DCMD_ERR); 271 } 272 273 if (dd_parent) { 274 if (mdb_dsl_dir_name(dd_parent, buf)) 275 return (DCMD_ERR); 276 strcat(buf, "/"); 277 } 278 279 if (dd_myname[0]) 280 strcat(buf, dd_myname); 281 else 282 strcat(buf, "???"); 283 284 return (0); 285 } 286 287 static int 288 objset_name(uintptr_t addr, char *buf) 289 { 290 static int gotid; 291 static mdb_ctf_id_t os_id, ds_id; 292 uintptr_t os_dsl_dataset; 293 char ds_snapname[ZFS_MAX_DATASET_NAME_LEN]; 294 uintptr_t ds_dir; 295 296 buf[0] = '\0'; 297 298 if (!gotid) { 299 if (mdb_ctf_lookup_by_name(ZFS_STRUCT "objset", 300 &os_id) == -1) { 301 mdb_warn("couldn't find struct objset"); 302 return (DCMD_ERR); 303 } 304 if (mdb_ctf_lookup_by_name(ZFS_STRUCT "dsl_dataset", 305 &ds_id) == -1) { 306 mdb_warn("couldn't find struct dsl_dataset"); 307 return (DCMD_ERR); 308 } 309 310 gotid = TRUE; 311 } 312 313 if (GETMEMBID(addr, &os_id, os_dsl_dataset, os_dsl_dataset)) 314 return (DCMD_ERR); 315 316 if (os_dsl_dataset == 0) { 317 strcat(buf, "mos"); 318 return (0); 319 } 320 321 if (GETMEMBID(os_dsl_dataset, &ds_id, ds_snapname, ds_snapname) || 322 GETMEMBID(os_dsl_dataset, &ds_id, ds_dir, ds_dir)) { 323 return (DCMD_ERR); 324 } 325 326 if (ds_dir && mdb_dsl_dir_name(ds_dir, buf)) 327 return (DCMD_ERR); 328 329 if (ds_snapname[0]) { 330 strcat(buf, "@"); 331 strcat(buf, ds_snapname); 332 } 333 return (0); 334 } 335 336 static int 337 enum_lookup(char *type, int val, const char *prefix, size_t size, char *out) 338 { 339 const char *cp; 340 size_t len = strlen(prefix); 341 mdb_ctf_id_t enum_type; 342 343 if (mdb_ctf_lookup_by_name(type, &enum_type) != 0) { 344 mdb_warn("Could not find enum for %s", type); 345 return (-1); 346 } 347 348 if ((cp = mdb_ctf_enum_name(enum_type, val)) != NULL) { 349 if (strncmp(cp, prefix, len) == 0) 350 cp += len; 351 (void) strncpy(out, cp, size); 352 } else { 353 mdb_snprintf(out, size, "? (%d)", val); 354 } 355 return (0); 356 } 357 358 /* ARGSUSED */ 359 static int 360 zfs_params(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 361 { 362 /* 363 * This table can be approximately generated by running: 364 * egrep "^[a-z0-9_]+ [a-z0-9_]+( =.*)?;" *.c | cut -d ' ' -f 2 365 */ 366 static const char *params[] = { 367 "arc_lotsfree_percent", 368 "arc_pages_pp_reserve", 369 "arc_reduce_dnlc_percent", 370 "arc_swapfs_reserve", 371 "arc_zio_arena_free_shift", 372 "dbuf_cache_hiwater_pct", 373 "dbuf_cache_lowater_pct", 374 "dbuf_cache_max_bytes", 375 "dbuf_cache_max_shift", 376 "ddt_zap_indirect_blockshift", 377 "ddt_zap_leaf_blockshift", 378 "ditto_same_vdev_distance_shift", 379 "dmu_find_threads", 380 "dmu_rescan_dnode_threshold", 381 "dsl_scan_delay_completion", 382 "fzap_default_block_shift", 383 "l2arc_feed_again", 384 "l2arc_feed_min_ms", 385 "l2arc_feed_secs", 386 "l2arc_headroom", 387 "l2arc_headroom_boost", 388 "l2arc_noprefetch", 389 "l2arc_norw", 390 "l2arc_write_boost", 391 "l2arc_write_max", 392 "metaslab_aliquot", 393 "metaslab_bias_enabled", 394 "metaslab_debug_load", 395 "metaslab_debug_unload", 396 "metaslab_df_alloc_threshold", 397 "metaslab_df_free_pct", 398 "metaslab_fragmentation_factor_enabled", 399 "metaslab_force_ganging", 400 "metaslab_lba_weighting_enabled", 401 "metaslab_load_pct", 402 "metaslab_min_alloc_size", 403 "metaslab_ndf_clump_shift", 404 "metaslab_preload_enabled", 405 "metaslab_preload_limit", 406 "metaslab_trace_enabled", 407 "metaslab_trace_max_entries", 408 "metaslab_unload_delay", 409 "metaslabs_per_vdev", 410 "reference_history", 411 "reference_tracking_enable", 412 "send_holes_without_birth_time", 413 "spa_asize_inflation", 414 "spa_load_verify_data", 415 "spa_load_verify_maxinflight", 416 "spa_load_verify_metadata", 417 "spa_max_replication_override", 418 "spa_min_slop", 419 "spa_mode_global", 420 "spa_slop_shift", 421 "space_map_blksz", 422 "vdev_mirror_shift", 423 "zfetch_max_distance", 424 "zfs_abd_chunk_size", 425 "zfs_abd_scatter_enabled", 426 "zfs_arc_average_blocksize", 427 "zfs_arc_evict_batch_limit", 428 "zfs_arc_grow_retry", 429 "zfs_arc_max", 430 "zfs_arc_meta_limit", 431 "zfs_arc_meta_min", 432 "zfs_arc_min", 433 "zfs_arc_p_min_shift", 434 "zfs_arc_shrink_shift", 435 "zfs_async_block_max_blocks", 436 "zfs_ccw_retry_interval", 437 "zfs_commit_timeout_pct", 438 "zfs_compressed_arc_enabled", 439 "zfs_condense_indirect_commit_entry_delay_ticks", 440 "zfs_condense_indirect_vdevs_enable", 441 "zfs_condense_max_obsolete_bytes", 442 "zfs_condense_min_mapping_bytes", 443 "zfs_condense_pct", 444 "zfs_dbgmsg_maxsize", 445 "zfs_deadman_checktime_ms", 446 "zfs_deadman_enabled", 447 "zfs_deadman_synctime_ms", 448 "zfs_dedup_prefetch", 449 "zfs_default_bs", 450 "zfs_default_ibs", 451 "zfs_delay_max_ns", 452 "zfs_delay_min_dirty_percent", 453 "zfs_delay_resolution_ns", 454 "zfs_delay_scale", 455 "zfs_dirty_data_max", 456 "zfs_dirty_data_max_max", 457 "zfs_dirty_data_max_percent", 458 "zfs_dirty_data_sync", 459 "zfs_flags", 460 "zfs_free_bpobj_enabled", 461 "zfs_free_leak_on_eio", 462 "zfs_free_min_time_ms", 463 "zfs_fsync_sync_cnt", 464 "zfs_immediate_write_sz", 465 "zfs_indirect_condense_obsolete_pct", 466 "zfs_lua_check_instrlimit_interval", 467 "zfs_lua_max_instrlimit", 468 "zfs_lua_max_memlimit", 469 "zfs_max_recordsize", 470 "zfs_mdcomp_disable", 471 "zfs_metaslab_condense_block_threshold", 472 "zfs_metaslab_fragmentation_threshold", 473 "zfs_metaslab_segment_weight_enabled", 474 "zfs_metaslab_switch_threshold", 475 "zfs_mg_fragmentation_threshold", 476 "zfs_mg_noalloc_threshold", 477 "zfs_multilist_num_sublists", 478 "zfs_no_scrub_io", 479 "zfs_no_scrub_prefetch", 480 "zfs_nocacheflush", 481 "zfs_nopwrite_enabled", 482 "zfs_object_remap_one_indirect_delay_ticks", 483 "zfs_obsolete_min_time_ms", 484 "zfs_pd_bytes_max", 485 "zfs_per_txg_dirty_frees_percent", 486 "zfs_prefetch_disable", 487 "zfs_read_chunk_size", 488 "zfs_recover", 489 "zfs_recv_queue_length", 490 "zfs_redundant_metadata_most_ditto_level", 491 "zfs_remap_blkptr_enable", 492 "zfs_remove_max_copy_bytes", 493 "zfs_remove_max_segment", 494 "zfs_resilver_delay", 495 "zfs_resilver_min_time_ms", 496 "zfs_scan_idle", 497 "zfs_scan_min_time_ms", 498 "zfs_scrub_delay", 499 "zfs_scrub_limit", 500 "zfs_send_corrupt_data", 501 "zfs_send_queue_length", 502 "zfs_send_set_freerecords_bit", 503 "zfs_sync_pass_deferred_free", 504 "zfs_sync_pass_dont_compress", 505 "zfs_sync_pass_rewrite", 506 "zfs_sync_taskq_batch_pct", 507 "zfs_top_maxinflight", 508 "zfs_txg_timeout", 509 "zfs_vdev_aggregation_limit", 510 "zfs_vdev_async_read_max_active", 511 "zfs_vdev_async_read_min_active", 512 "zfs_vdev_async_write_active_max_dirty_percent", 513 "zfs_vdev_async_write_active_min_dirty_percent", 514 "zfs_vdev_async_write_max_active", 515 "zfs_vdev_async_write_min_active", 516 "zfs_vdev_cache_bshift", 517 "zfs_vdev_cache_max", 518 "zfs_vdev_cache_size", 519 "zfs_vdev_max_active", 520 "zfs_vdev_queue_depth_pct", 521 "zfs_vdev_read_gap_limit", 522 "zfs_vdev_removal_max_active", 523 "zfs_vdev_removal_min_active", 524 "zfs_vdev_scrub_max_active", 525 "zfs_vdev_scrub_min_active", 526 "zfs_vdev_sync_read_max_active", 527 "zfs_vdev_sync_read_min_active", 528 "zfs_vdev_sync_write_max_active", 529 "zfs_vdev_sync_write_min_active", 530 "zfs_vdev_write_gap_limit", 531 "zfs_write_implies_delete_child", 532 "zfs_zil_clean_taskq_maxalloc", 533 "zfs_zil_clean_taskq_minalloc", 534 "zfs_zil_clean_taskq_nthr_pct", 535 "zil_replay_disable", 536 "zil_slog_bulk", 537 "zio_buf_debug_limit", 538 "zio_dva_throttle_enabled", 539 "zio_injection_enabled", 540 "zvol_immediate_write_sz", 541 "zvol_maxphys", 542 "zvol_unmap_enabled", 543 "zvol_unmap_sync_enabled", 544 "zfs_max_dataset_nesting", 545 }; 546 547 for (int i = 0; i < sizeof (params) / sizeof (params[0]); i++) { 548 int sz; 549 uint64_t val64; 550 uint32_t *val32p = (uint32_t *)&val64; 551 552 sz = mdb_readvar(&val64, params[i]); 553 if (sz == 4) { 554 mdb_printf("%s = 0x%x\n", params[i], *val32p); 555 } else if (sz == 8) { 556 mdb_printf("%s = 0x%llx\n", params[i], val64); 557 } else { 558 mdb_warn("variable %s not found", params[i]); 559 } 560 } 561 562 return (DCMD_OK); 563 } 564 565 /* ARGSUSED */ 566 static int 567 dva(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 568 { 569 dva_t dva; 570 if (mdb_vread(&dva, sizeof (dva_t), addr) == -1) { 571 mdb_warn("failed to read dva_t"); 572 return (DCMD_ERR); 573 } 574 mdb_printf("<%llu:%llx:%llx>\n", 575 (u_longlong_t)DVA_GET_VDEV(&dva), 576 (u_longlong_t)DVA_GET_OFFSET(&dva), 577 (u_longlong_t)DVA_GET_ASIZE(&dva)); 578 579 return (DCMD_OK); 580 } 581 582 typedef struct mdb_dmu_object_type_info { 583 boolean_t ot_encrypt; 584 } mdb_dmu_object_type_info_t; 585 586 static boolean_t 587 mdb_dmu_ot_is_encrypted_impl(dmu_object_type_t ot) 588 { 589 mdb_dmu_object_type_info_t mdoti; 590 GElf_Sym sym; 591 size_t sz = mdb_ctf_sizeof_by_name("dmu_object_type_info_t"); 592 593 if (mdb_lookup_by_obj(ZFS_OBJ_NAME, "dmu_ot", &sym)) { 594 mdb_warn("failed to find " ZFS_OBJ_NAME "`dmu_ot"); 595 return (B_FALSE); 596 } 597 598 if (mdb_ctf_vread(&mdoti, "dmu_object_type_info_t", 599 "mdb_dmu_object_type_info_t", sym.st_value + sz * ot, 0) != 0) { 600 return (B_FALSE); 601 } 602 603 return (mdoti.ot_encrypt); 604 } 605 606 /* ARGSUSED */ 607 static int 608 blkptr(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 609 { 610 char type[80], checksum[80], compress[80]; 611 blkptr_t blk, *bp = &blk; 612 char buf[BP_SPRINTF_LEN]; 613 614 if (mdb_vread(&blk, sizeof (blkptr_t), addr) == -1) { 615 mdb_warn("failed to read blkptr_t"); 616 return (DCMD_ERR); 617 } 618 619 if (enum_lookup("enum dmu_object_type", BP_GET_TYPE(bp), "DMU_OT_", 620 sizeof (type), type) == -1 || 621 enum_lookup("enum zio_checksum", BP_GET_CHECKSUM(bp), 622 "ZIO_CHECKSUM_", sizeof (checksum), checksum) == -1 || 623 enum_lookup("enum zio_compress", BP_GET_COMPRESS(bp), 624 "ZIO_COMPRESS_", sizeof (compress), compress) == -1) { 625 mdb_warn("Could not find blkptr enumerated types"); 626 return (DCMD_ERR); 627 } 628 629 SNPRINTF_BLKPTR(mdb_snprintf, '\n', buf, sizeof (buf), bp, type, 630 checksum, compress); 631 632 mdb_printf("%s\n", buf); 633 634 return (DCMD_OK); 635 } 636 637 typedef struct mdb_dmu_buf_impl { 638 struct { 639 uint64_t db_object; 640 uintptr_t db_data; 641 } db; 642 uintptr_t db_objset; 643 uint64_t db_level; 644 uint64_t db_blkid; 645 struct { 646 uint64_t rc_count; 647 } db_holds; 648 } mdb_dmu_buf_impl_t; 649 650 /* ARGSUSED */ 651 static int 652 dbuf(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 653 { 654 mdb_dmu_buf_impl_t db; 655 char objectname[32]; 656 char blkidname[32]; 657 char path[ZFS_MAX_DATASET_NAME_LEN]; 658 int ptr_width = (int)(sizeof (void *)) * 2; 659 660 if (DCMD_HDRSPEC(flags)) 661 mdb_printf("%*s %8s %3s %9s %5s %s\n", 662 ptr_width, "addr", "object", "lvl", "blkid", "holds", "os"); 663 664 if (mdb_ctf_vread(&db, ZFS_STRUCT "dmu_buf_impl", "mdb_dmu_buf_impl_t", 665 addr, 0) == -1) 666 return (DCMD_ERR); 667 668 if (db.db.db_object == DMU_META_DNODE_OBJECT) 669 (void) strcpy(objectname, "mdn"); 670 else 671 (void) mdb_snprintf(objectname, sizeof (objectname), "%llx", 672 (u_longlong_t)db.db.db_object); 673 674 if (db.db_blkid == DMU_BONUS_BLKID) 675 (void) strcpy(blkidname, "bonus"); 676 else 677 (void) mdb_snprintf(blkidname, sizeof (blkidname), "%llx", 678 (u_longlong_t)db.db_blkid); 679 680 if (objset_name(db.db_objset, path)) { 681 return (DCMD_ERR); 682 } 683 684 mdb_printf("%*p %8s %3u %9s %5llu %s\n", ptr_width, addr, 685 objectname, (int)db.db_level, blkidname, 686 db.db_holds.rc_count, path); 687 688 return (DCMD_OK); 689 } 690 691 /* ARGSUSED */ 692 static int 693 dbuf_stats(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 694 { 695 #define HISTOSZ 32 696 uintptr_t dbp; 697 dmu_buf_impl_t db; 698 dbuf_hash_table_t ht; 699 uint64_t bucket, ndbufs; 700 uint64_t histo[HISTOSZ]; 701 uint64_t histo2[HISTOSZ]; 702 int i, maxidx; 703 704 if (mdb_readvar(&ht, "dbuf_hash_table") == -1) { 705 mdb_warn("failed to read 'dbuf_hash_table'"); 706 return (DCMD_ERR); 707 } 708 709 for (i = 0; i < HISTOSZ; i++) { 710 histo[i] = 0; 711 histo2[i] = 0; 712 } 713 714 ndbufs = 0; 715 for (bucket = 0; bucket < ht.hash_table_mask+1; bucket++) { 716 int len; 717 718 if (mdb_vread(&dbp, sizeof (void *), 719 (uintptr_t)(ht.hash_table+bucket)) == -1) { 720 mdb_warn("failed to read hash bucket %u at %p", 721 bucket, ht.hash_table+bucket); 722 return (DCMD_ERR); 723 } 724 725 len = 0; 726 while (dbp != 0) { 727 if (mdb_vread(&db, sizeof (dmu_buf_impl_t), 728 dbp) == -1) { 729 mdb_warn("failed to read dbuf at %p", dbp); 730 return (DCMD_ERR); 731 } 732 dbp = (uintptr_t)db.db_hash_next; 733 for (i = MIN(len, HISTOSZ - 1); i >= 0; i--) 734 histo2[i]++; 735 len++; 736 ndbufs++; 737 } 738 739 if (len >= HISTOSZ) 740 len = HISTOSZ-1; 741 histo[len]++; 742 } 743 744 mdb_printf("hash table has %llu buckets, %llu dbufs " 745 "(avg %llu buckets/dbuf)\n", 746 ht.hash_table_mask+1, ndbufs, 747 (ht.hash_table_mask+1)/ndbufs); 748 749 mdb_printf("\n"); 750 maxidx = 0; 751 for (i = 0; i < HISTOSZ; i++) 752 if (histo[i] > 0) 753 maxidx = i; 754 mdb_printf("hash chain length number of buckets\n"); 755 for (i = 0; i <= maxidx; i++) 756 mdb_printf("%u %llu\n", i, histo[i]); 757 758 mdb_printf("\n"); 759 maxidx = 0; 760 for (i = 0; i < HISTOSZ; i++) 761 if (histo2[i] > 0) 762 maxidx = i; 763 mdb_printf("hash chain depth number of dbufs\n"); 764 for (i = 0; i <= maxidx; i++) 765 mdb_printf("%u or more %llu %llu%%\n", 766 i, histo2[i], histo2[i]*100/ndbufs); 767 768 769 return (DCMD_OK); 770 } 771 772 #define CHAIN_END 0xffff 773 /* 774 * ::zap_leaf [-v] 775 * 776 * Print a zap_leaf_phys_t, assumed to be 16k 777 */ 778 /* ARGSUSED */ 779 static int 780 zap_leaf(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 781 { 782 char buf[16*1024]; 783 int verbose = B_FALSE; 784 int four = B_FALSE; 785 dmu_buf_t l_dbuf; 786 zap_leaf_t l; 787 zap_leaf_phys_t *zlp = (void *)buf; 788 int i; 789 790 if (mdb_getopts(argc, argv, 791 'v', MDB_OPT_SETBITS, TRUE, &verbose, 792 '4', MDB_OPT_SETBITS, TRUE, &four, 793 NULL) != argc) 794 return (DCMD_USAGE); 795 796 l_dbuf.db_data = zlp; 797 l.l_dbuf = &l_dbuf; 798 l.l_bs = 14; /* assume 16k blocks */ 799 if (four) 800 l.l_bs = 12; 801 802 if (!(flags & DCMD_ADDRSPEC)) { 803 return (DCMD_USAGE); 804 } 805 806 if (mdb_vread(buf, sizeof (buf), addr) == -1) { 807 mdb_warn("failed to read zap_leaf_phys_t at %p", addr); 808 return (DCMD_ERR); 809 } 810 811 if (zlp->l_hdr.lh_block_type != ZBT_LEAF || 812 zlp->l_hdr.lh_magic != ZAP_LEAF_MAGIC) { 813 mdb_warn("This does not appear to be a zap_leaf_phys_t"); 814 return (DCMD_ERR); 815 } 816 817 mdb_printf("zap_leaf_phys_t at %p:\n", addr); 818 mdb_printf(" lh_prefix_len = %u\n", zlp->l_hdr.lh_prefix_len); 819 mdb_printf(" lh_prefix = %llx\n", zlp->l_hdr.lh_prefix); 820 mdb_printf(" lh_nentries = %u\n", zlp->l_hdr.lh_nentries); 821 mdb_printf(" lh_nfree = %u\n", zlp->l_hdr.lh_nfree, 822 zlp->l_hdr.lh_nfree * 100 / (ZAP_LEAF_NUMCHUNKS(&l))); 823 mdb_printf(" lh_freelist = %u\n", zlp->l_hdr.lh_freelist); 824 mdb_printf(" lh_flags = %x (%s)\n", zlp->l_hdr.lh_flags, 825 zlp->l_hdr.lh_flags & ZLF_ENTRIES_CDSORTED ? 826 "ENTRIES_CDSORTED" : ""); 827 828 if (verbose) { 829 mdb_printf(" hash table:\n"); 830 for (i = 0; i < ZAP_LEAF_HASH_NUMENTRIES(&l); i++) { 831 if (zlp->l_hash[i] != CHAIN_END) 832 mdb_printf(" %u: %u\n", i, zlp->l_hash[i]); 833 } 834 } 835 836 mdb_printf(" chunks:\n"); 837 for (i = 0; i < ZAP_LEAF_NUMCHUNKS(&l); i++) { 838 /* LINTED: alignment */ 839 zap_leaf_chunk_t *zlc = &ZAP_LEAF_CHUNK(&l, i); 840 switch (zlc->l_entry.le_type) { 841 case ZAP_CHUNK_FREE: 842 if (verbose) { 843 mdb_printf(" %u: free; lf_next = %u\n", 844 i, zlc->l_free.lf_next); 845 } 846 break; 847 case ZAP_CHUNK_ENTRY: 848 mdb_printf(" %u: entry\n", i); 849 if (verbose) { 850 mdb_printf(" le_next = %u\n", 851 zlc->l_entry.le_next); 852 } 853 mdb_printf(" le_name_chunk = %u\n", 854 zlc->l_entry.le_name_chunk); 855 mdb_printf(" le_name_numints = %u\n", 856 zlc->l_entry.le_name_numints); 857 mdb_printf(" le_value_chunk = %u\n", 858 zlc->l_entry.le_value_chunk); 859 mdb_printf(" le_value_intlen = %u\n", 860 zlc->l_entry.le_value_intlen); 861 mdb_printf(" le_value_numints = %u\n", 862 zlc->l_entry.le_value_numints); 863 mdb_printf(" le_cd = %u\n", 864 zlc->l_entry.le_cd); 865 mdb_printf(" le_hash = %llx\n", 866 zlc->l_entry.le_hash); 867 break; 868 case ZAP_CHUNK_ARRAY: 869 mdb_printf(" %u: array", i); 870 if (strisprint((char *)zlc->l_array.la_array)) 871 mdb_printf(" \"%s\"", zlc->l_array.la_array); 872 mdb_printf("\n"); 873 if (verbose) { 874 int j; 875 mdb_printf(" "); 876 for (j = 0; j < ZAP_LEAF_ARRAY_BYTES; j++) { 877 mdb_printf("%02x ", 878 zlc->l_array.la_array[j]); 879 } 880 mdb_printf("\n"); 881 } 882 if (zlc->l_array.la_next != CHAIN_END) { 883 mdb_printf(" lf_next = %u\n", 884 zlc->l_array.la_next); 885 } 886 break; 887 default: 888 mdb_printf(" %u: undefined type %u\n", 889 zlc->l_entry.le_type); 890 } 891 } 892 893 return (DCMD_OK); 894 } 895 896 typedef struct dbufs_data { 897 mdb_ctf_id_t id; 898 uint64_t objset; 899 uint64_t object; 900 uint64_t level; 901 uint64_t blkid; 902 char *osname; 903 } dbufs_data_t; 904 905 #define DBUFS_UNSET (0xbaddcafedeadbeefULL) 906 907 /* ARGSUSED */ 908 static int 909 dbufs_cb(uintptr_t addr, const void *unknown, void *arg) 910 { 911 dbufs_data_t *data = arg; 912 uintptr_t objset; 913 dmu_buf_t db; 914 uint8_t level; 915 uint64_t blkid; 916 char osname[ZFS_MAX_DATASET_NAME_LEN]; 917 918 if (GETMEMBID(addr, &data->id, db_objset, objset) || 919 GETMEMBID(addr, &data->id, db, db) || 920 GETMEMBID(addr, &data->id, db_level, level) || 921 GETMEMBID(addr, &data->id, db_blkid, blkid)) { 922 return (WALK_ERR); 923 } 924 925 if ((data->objset == DBUFS_UNSET || data->objset == objset) && 926 (data->osname == NULL || (objset_name(objset, osname) == 0 && 927 strcmp(data->osname, osname) == 0)) && 928 (data->object == DBUFS_UNSET || data->object == db.db_object) && 929 (data->level == DBUFS_UNSET || data->level == level) && 930 (data->blkid == DBUFS_UNSET || data->blkid == blkid)) { 931 mdb_printf("%#lr\n", addr); 932 } 933 return (WALK_NEXT); 934 } 935 936 /* ARGSUSED */ 937 static int 938 dbufs(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 939 { 940 dbufs_data_t data; 941 char *object = NULL; 942 char *blkid = NULL; 943 944 data.objset = data.object = data.level = data.blkid = DBUFS_UNSET; 945 data.osname = NULL; 946 947 if (mdb_getopts(argc, argv, 948 'O', MDB_OPT_UINT64, &data.objset, 949 'n', MDB_OPT_STR, &data.osname, 950 'o', MDB_OPT_STR, &object, 951 'l', MDB_OPT_UINT64, &data.level, 952 'b', MDB_OPT_STR, &blkid, 953 NULL) != argc) { 954 return (DCMD_USAGE); 955 } 956 957 if (object) { 958 if (strcmp(object, "mdn") == 0) { 959 data.object = DMU_META_DNODE_OBJECT; 960 } else { 961 data.object = mdb_strtoull(object); 962 } 963 } 964 965 if (blkid) { 966 if (strcmp(blkid, "bonus") == 0) { 967 data.blkid = DMU_BONUS_BLKID; 968 } else { 969 data.blkid = mdb_strtoull(blkid); 970 } 971 } 972 973 if (mdb_ctf_lookup_by_name(ZFS_STRUCT "dmu_buf_impl", &data.id) == -1) { 974 mdb_warn("couldn't find struct dmu_buf_impl_t"); 975 return (DCMD_ERR); 976 } 977 978 if (mdb_walk("dmu_buf_impl_t", dbufs_cb, &data) != 0) { 979 mdb_warn("can't walk dbufs"); 980 return (DCMD_ERR); 981 } 982 983 return (DCMD_OK); 984 } 985 986 typedef struct abuf_find_data { 987 dva_t dva; 988 mdb_ctf_id_t id; 989 } abuf_find_data_t; 990 991 /* ARGSUSED */ 992 static int 993 abuf_find_cb(uintptr_t addr, const void *unknown, void *arg) 994 { 995 abuf_find_data_t *data = arg; 996 dva_t dva; 997 998 if (GETMEMBID(addr, &data->id, b_dva, dva)) { 999 return (WALK_ERR); 1000 } 1001 1002 if (dva.dva_word[0] == data->dva.dva_word[0] && 1003 dva.dva_word[1] == data->dva.dva_word[1]) { 1004 mdb_printf("%#lr\n", addr); 1005 } 1006 return (WALK_NEXT); 1007 } 1008 1009 /* ARGSUSED */ 1010 static int 1011 abuf_find(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 1012 { 1013 abuf_find_data_t data; 1014 GElf_Sym sym; 1015 int i; 1016 const char *syms[] = { 1017 "ARC_mru", 1018 "ARC_mru_ghost", 1019 "ARC_mfu", 1020 "ARC_mfu_ghost", 1021 }; 1022 1023 if (argc != 2) 1024 return (DCMD_USAGE); 1025 1026 for (i = 0; i < 2; i ++) { 1027 switch (argv[i].a_type) { 1028 case MDB_TYPE_STRING: 1029 data.dva.dva_word[i] = mdb_strtoull(argv[i].a_un.a_str); 1030 break; 1031 case MDB_TYPE_IMMEDIATE: 1032 data.dva.dva_word[i] = argv[i].a_un.a_val; 1033 break; 1034 default: 1035 return (DCMD_USAGE); 1036 } 1037 } 1038 1039 if (mdb_ctf_lookup_by_name(ZFS_STRUCT "arc_buf_hdr", &data.id) == -1) { 1040 mdb_warn("couldn't find struct arc_buf_hdr"); 1041 return (DCMD_ERR); 1042 } 1043 1044 for (i = 0; i < sizeof (syms) / sizeof (syms[0]); i++) { 1045 if (mdb_lookup_by_obj(ZFS_OBJ_NAME, syms[i], &sym)) { 1046 mdb_warn("can't find symbol %s", syms[i]); 1047 return (DCMD_ERR); 1048 } 1049 1050 if (mdb_pwalk("list", abuf_find_cb, &data, sym.st_value) != 0) { 1051 mdb_warn("can't walk %s", syms[i]); 1052 return (DCMD_ERR); 1053 } 1054 } 1055 1056 return (DCMD_OK); 1057 } 1058 1059 1060 typedef struct dbgmsg_arg { 1061 boolean_t da_verbose; 1062 boolean_t da_address; 1063 } dbgmsg_arg_t; 1064 1065 /* ARGSUSED */ 1066 static int 1067 dbgmsg_cb(uintptr_t addr, const void *unknown, void *arg) 1068 { 1069 static mdb_ctf_id_t id; 1070 static boolean_t gotid; 1071 static ulong_t off; 1072 1073 dbgmsg_arg_t *da = arg; 1074 time_t timestamp; 1075 char buf[1024]; 1076 1077 if (!gotid) { 1078 if (mdb_ctf_lookup_by_name(ZFS_STRUCT "zfs_dbgmsg", &id) == 1079 -1) { 1080 mdb_warn("couldn't find struct zfs_dbgmsg"); 1081 return (WALK_ERR); 1082 } 1083 gotid = TRUE; 1084 if (mdb_ctf_offsetof(id, "zdm_msg", &off) == -1) { 1085 mdb_warn("couldn't find zdm_msg"); 1086 return (WALK_ERR); 1087 } 1088 off /= 8; 1089 } 1090 1091 1092 if (GETMEMBID(addr, &id, zdm_timestamp, timestamp)) { 1093 return (WALK_ERR); 1094 } 1095 1096 if (mdb_readstr(buf, sizeof (buf), addr + off) == -1) { 1097 mdb_warn("failed to read zdm_msg at %p\n", addr + off); 1098 return (DCMD_ERR); 1099 } 1100 1101 if (da->da_address) 1102 mdb_printf("%p ", addr); 1103 if (da->da_verbose) 1104 mdb_printf("%Y ", timestamp); 1105 1106 mdb_printf("%s\n", buf); 1107 1108 if (da->da_verbose) 1109 (void) mdb_call_dcmd("whatis", addr, DCMD_ADDRSPEC, 0, NULL); 1110 1111 return (WALK_NEXT); 1112 } 1113 1114 /* ARGSUSED */ 1115 static int 1116 dbgmsg(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 1117 { 1118 GElf_Sym sym; 1119 dbgmsg_arg_t da = { 0 }; 1120 1121 if (mdb_getopts(argc, argv, 1122 'v', MDB_OPT_SETBITS, B_TRUE, &da.da_verbose, 1123 'a', MDB_OPT_SETBITS, B_TRUE, &da.da_address, 1124 NULL) != argc) 1125 return (DCMD_USAGE); 1126 1127 if (mdb_lookup_by_obj(ZFS_OBJ_NAME, "zfs_dbgmsgs", &sym)) { 1128 mdb_warn("can't find zfs_dbgmsgs"); 1129 return (DCMD_ERR); 1130 } 1131 1132 if (mdb_pwalk("list", dbgmsg_cb, &da, sym.st_value) != 0) { 1133 mdb_warn("can't walk zfs_dbgmsgs"); 1134 return (DCMD_ERR); 1135 } 1136 1137 return (DCMD_OK); 1138 } 1139 1140 /*ARGSUSED*/ 1141 static int 1142 arc_print(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 1143 { 1144 kstat_named_t *stats; 1145 GElf_Sym sym; 1146 int nstats, i; 1147 uint_t opt_a = FALSE; 1148 uint_t opt_b = FALSE; 1149 uint_t shift = 0; 1150 const char *suffix; 1151 1152 static const char *bytestats[] = { 1153 "p", "c", "c_min", "c_max", "size", "duplicate_buffers_size", 1154 "arc_meta_used", "arc_meta_limit", "arc_meta_max", 1155 "arc_meta_min", "hdr_size", "data_size", "metadata_size", 1156 "other_size", "anon_size", "anon_evictable_data", 1157 "anon_evictable_metadata", "mru_size", "mru_evictable_data", 1158 "mru_evictable_metadata", "mru_ghost_size", 1159 "mru_ghost_evictable_data", "mru_ghost_evictable_metadata", 1160 "mfu_size", "mfu_evictable_data", "mfu_evictable_metadata", 1161 "mfu_ghost_size", "mfu_ghost_evictable_data", 1162 "mfu_ghost_evictable_metadata", "evict_l2_cached", 1163 "evict_l2_eligible", "evict_l2_ineligible", "l2_read_bytes", 1164 "l2_write_bytes", "l2_size", "l2_asize", "l2_hdr_size", 1165 "compressed_size", "uncompressed_size", "overhead_size", 1166 NULL 1167 }; 1168 1169 static const char *extras[] = { 1170 "arc_no_grow", "arc_tempreserve", 1171 NULL 1172 }; 1173 1174 if (mdb_lookup_by_obj(ZFS_OBJ_NAME, "arc_stats", &sym) == -1) { 1175 mdb_warn("failed to find 'arc_stats'"); 1176 return (DCMD_ERR); 1177 } 1178 1179 stats = mdb_zalloc(sym.st_size, UM_SLEEP | UM_GC); 1180 1181 if (mdb_vread(stats, sym.st_size, sym.st_value) == -1) { 1182 mdb_warn("couldn't read 'arc_stats' at %p", sym.st_value); 1183 return (DCMD_ERR); 1184 } 1185 1186 nstats = sym.st_size / sizeof (kstat_named_t); 1187 1188 /* NB: -a / opt_a are ignored for backwards compatability */ 1189 if (mdb_getopts(argc, argv, 1190 'a', MDB_OPT_SETBITS, TRUE, &opt_a, 1191 'b', MDB_OPT_SETBITS, TRUE, &opt_b, 1192 'k', MDB_OPT_SETBITS, 10, &shift, 1193 'm', MDB_OPT_SETBITS, 20, &shift, 1194 'g', MDB_OPT_SETBITS, 30, &shift, 1195 NULL) != argc) 1196 return (DCMD_USAGE); 1197 1198 if (!opt_b && !shift) 1199 shift = 20; 1200 1201 switch (shift) { 1202 case 0: 1203 suffix = "B"; 1204 break; 1205 case 10: 1206 suffix = "KB"; 1207 break; 1208 case 20: 1209 suffix = "MB"; 1210 break; 1211 case 30: 1212 suffix = "GB"; 1213 break; 1214 default: 1215 suffix = "XX"; 1216 } 1217 1218 for (i = 0; i < nstats; i++) { 1219 int j; 1220 boolean_t bytes = B_FALSE; 1221 1222 for (j = 0; bytestats[j]; j++) { 1223 if (strcmp(stats[i].name, bytestats[j]) == 0) { 1224 bytes = B_TRUE; 1225 break; 1226 } 1227 } 1228 1229 if (bytes) { 1230 mdb_printf("%-25s = %9llu %s\n", stats[i].name, 1231 stats[i].value.ui64 >> shift, suffix); 1232 } else { 1233 mdb_printf("%-25s = %9llu\n", stats[i].name, 1234 stats[i].value.ui64); 1235 } 1236 } 1237 1238 for (i = 0; extras[i]; i++) { 1239 uint64_t buf; 1240 1241 if (mdb_lookup_by_obj(ZFS_OBJ_NAME, extras[i], &sym) == -1) { 1242 mdb_warn("failed to find '%s'", extras[i]); 1243 return (DCMD_ERR); 1244 } 1245 1246 if (sym.st_size != sizeof (uint64_t) && 1247 sym.st_size != sizeof (uint32_t)) { 1248 mdb_warn("expected scalar for variable '%s'\n", 1249 extras[i]); 1250 return (DCMD_ERR); 1251 } 1252 1253 if (mdb_vread(&buf, sym.st_size, sym.st_value) == -1) { 1254 mdb_warn("couldn't read '%s'", extras[i]); 1255 return (DCMD_ERR); 1256 } 1257 1258 mdb_printf("%-25s = ", extras[i]); 1259 1260 /* NB: all the 64-bit extras happen to be byte counts */ 1261 if (sym.st_size == sizeof (uint64_t)) 1262 mdb_printf("%9llu %s\n", buf >> shift, suffix); 1263 1264 if (sym.st_size == sizeof (uint32_t)) 1265 mdb_printf("%9d\n", *((uint32_t *)&buf)); 1266 } 1267 return (DCMD_OK); 1268 } 1269 1270 typedef struct mdb_spa_print { 1271 pool_state_t spa_state; 1272 char spa_name[ZFS_MAX_DATASET_NAME_LEN]; 1273 uintptr_t spa_normal_class; 1274 } mdb_spa_print_t; 1275 1276 1277 const char histo_stars[] = "****************************************"; 1278 const int histo_width = sizeof (histo_stars) - 1; 1279 1280 static void 1281 dump_histogram(const uint64_t *histo, int size, int offset) 1282 { 1283 int i; 1284 int minidx = size - 1; 1285 int maxidx = 0; 1286 uint64_t max = 0; 1287 1288 for (i = 0; i < size; i++) { 1289 if (histo[i] > max) 1290 max = histo[i]; 1291 if (histo[i] > 0 && i > maxidx) 1292 maxidx = i; 1293 if (histo[i] > 0 && i < minidx) 1294 minidx = i; 1295 } 1296 1297 if (max < histo_width) 1298 max = histo_width; 1299 1300 for (i = minidx; i <= maxidx; i++) { 1301 mdb_printf("%3u: %6llu %s\n", 1302 i + offset, (u_longlong_t)histo[i], 1303 &histo_stars[(max - histo[i]) * histo_width / max]); 1304 } 1305 } 1306 1307 typedef struct mdb_metaslab_class { 1308 uint64_t mc_histogram[RANGE_TREE_HISTOGRAM_SIZE]; 1309 } mdb_metaslab_class_t; 1310 1311 /* 1312 * spa_class_histogram(uintptr_t class_addr) 1313 * 1314 * Prints free space histogram for a device class 1315 * 1316 * Returns DCMD_OK, or DCMD_ERR. 1317 */ 1318 static int 1319 spa_class_histogram(uintptr_t class_addr) 1320 { 1321 mdb_metaslab_class_t mc; 1322 if (mdb_ctf_vread(&mc, "metaslab_class_t", 1323 "mdb_metaslab_class_t", class_addr, 0) == -1) 1324 return (DCMD_ERR); 1325 1326 mdb_inc_indent(4); 1327 dump_histogram(mc.mc_histogram, RANGE_TREE_HISTOGRAM_SIZE, 0); 1328 mdb_dec_indent(4); 1329 return (DCMD_OK); 1330 } 1331 1332 /* 1333 * ::spa 1334 * 1335 * -c Print configuration information as well 1336 * -v Print vdev state 1337 * -e Print vdev error stats 1338 * -m Print vdev metaslab info 1339 * -M print vdev metaslab group info 1340 * -h Print histogram info (must be combined with -m or -M) 1341 * 1342 * Print a summarized spa_t. When given no arguments, prints out a table of all 1343 * active pools on the system. 1344 */ 1345 /* ARGSUSED */ 1346 static int 1347 spa_print(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 1348 { 1349 const char *statetab[] = { "ACTIVE", "EXPORTED", "DESTROYED", 1350 "SPARE", "L2CACHE", "UNINIT", "UNAVAIL", "POTENTIAL" }; 1351 const char *state; 1352 int spa_flags = 0; 1353 1354 if (mdb_getopts(argc, argv, 1355 'c', MDB_OPT_SETBITS, SPA_FLAG_CONFIG, &spa_flags, 1356 'v', MDB_OPT_SETBITS, SPA_FLAG_VDEVS, &spa_flags, 1357 'e', MDB_OPT_SETBITS, SPA_FLAG_ERRORS, &spa_flags, 1358 'M', MDB_OPT_SETBITS, SPA_FLAG_METASLAB_GROUPS, &spa_flags, 1359 'm', MDB_OPT_SETBITS, SPA_FLAG_METASLABS, &spa_flags, 1360 'h', MDB_OPT_SETBITS, SPA_FLAG_HISTOGRAMS, &spa_flags, 1361 NULL) != argc) 1362 return (DCMD_USAGE); 1363 1364 if (!(flags & DCMD_ADDRSPEC)) { 1365 if (mdb_walk_dcmd("spa", "spa", argc, argv) == -1) { 1366 mdb_warn("can't walk spa"); 1367 return (DCMD_ERR); 1368 } 1369 1370 return (DCMD_OK); 1371 } 1372 1373 if (flags & DCMD_PIPE_OUT) { 1374 mdb_printf("%#lr\n", addr); 1375 return (DCMD_OK); 1376 } 1377 1378 if (DCMD_HDRSPEC(flags)) 1379 mdb_printf("%<u>%-?s %9s %-*s%</u>\n", "ADDR", "STATE", 1380 sizeof (uintptr_t) == 4 ? 60 : 52, "NAME"); 1381 1382 mdb_spa_print_t spa; 1383 if (mdb_ctf_vread(&spa, "spa_t", "mdb_spa_print_t", addr, 0) == -1) 1384 return (DCMD_ERR); 1385 1386 if (spa.spa_state < 0 || spa.spa_state > POOL_STATE_UNAVAIL) 1387 state = "UNKNOWN"; 1388 else 1389 state = statetab[spa.spa_state]; 1390 1391 mdb_printf("%0?p %9s %s\n", addr, state, spa.spa_name); 1392 if (spa_flags & SPA_FLAG_HISTOGRAMS) 1393 spa_class_histogram(spa.spa_normal_class); 1394 1395 if (spa_flags & SPA_FLAG_CONFIG) { 1396 mdb_printf("\n"); 1397 mdb_inc_indent(4); 1398 if (mdb_call_dcmd("spa_config", addr, flags, 0, 1399 NULL) != DCMD_OK) 1400 return (DCMD_ERR); 1401 mdb_dec_indent(4); 1402 } 1403 1404 if (spa_flags & SPA_FLAG_ALL_VDEV) { 1405 mdb_arg_t v; 1406 char opts[100] = "-"; 1407 int args = 1408 (spa_flags | SPA_FLAG_VDEVS) == SPA_FLAG_VDEVS ? 0 : 1; 1409 1410 if (spa_flags & SPA_FLAG_ERRORS) 1411 strcat(opts, "e"); 1412 if (spa_flags & SPA_FLAG_METASLABS) 1413 strcat(opts, "m"); 1414 if (spa_flags & SPA_FLAG_METASLAB_GROUPS) 1415 strcat(opts, "M"); 1416 if (spa_flags & SPA_FLAG_HISTOGRAMS) 1417 strcat(opts, "h"); 1418 1419 v.a_type = MDB_TYPE_STRING; 1420 v.a_un.a_str = opts; 1421 1422 mdb_printf("\n"); 1423 mdb_inc_indent(4); 1424 if (mdb_call_dcmd("spa_vdevs", addr, flags, args, 1425 &v) != DCMD_OK) 1426 return (DCMD_ERR); 1427 mdb_dec_indent(4); 1428 } 1429 1430 return (DCMD_OK); 1431 } 1432 1433 typedef struct mdb_spa_config_spa { 1434 uintptr_t spa_config; 1435 } mdb_spa_config_spa_t; 1436 1437 /* 1438 * ::spa_config 1439 * 1440 * Given a spa_t, print the configuration information stored in spa_config. 1441 * Since it's just an nvlist, format it as an indented list of name=value pairs. 1442 * We simply read the value of spa_config and pass off to ::nvlist. 1443 */ 1444 /* ARGSUSED */ 1445 static int 1446 spa_print_config(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 1447 { 1448 mdb_spa_config_spa_t spa; 1449 1450 if (argc != 0 || !(flags & DCMD_ADDRSPEC)) 1451 return (DCMD_USAGE); 1452 1453 if (mdb_ctf_vread(&spa, ZFS_STRUCT "spa", "mdb_spa_config_spa_t", 1454 addr, 0) == -1) 1455 return (DCMD_ERR); 1456 1457 if (spa.spa_config == 0) { 1458 mdb_printf("(none)\n"); 1459 return (DCMD_OK); 1460 } 1461 1462 return (mdb_call_dcmd("nvlist", spa.spa_config, flags, 1463 0, NULL)); 1464 } 1465 1466 typedef struct mdb_range_tree { 1467 struct { 1468 uint64_t bt_num_elems; 1469 uint64_t bt_num_nodes; 1470 } rt_root; 1471 uint64_t rt_space; 1472 range_seg_type_t rt_type; 1473 uint8_t rt_shift; 1474 uint64_t rt_start; 1475 } mdb_range_tree_t; 1476 1477 typedef struct mdb_metaslab_group { 1478 uint64_t mg_fragmentation; 1479 uint64_t mg_histogram[RANGE_TREE_HISTOGRAM_SIZE]; 1480 uintptr_t mg_vd; 1481 } mdb_metaslab_group_t; 1482 1483 typedef struct mdb_metaslab { 1484 uint64_t ms_id; 1485 uint64_t ms_start; 1486 uint64_t ms_size; 1487 int64_t ms_deferspace; 1488 uint64_t ms_fragmentation; 1489 uint64_t ms_weight; 1490 uintptr_t ms_allocating[TXG_SIZE]; 1491 uintptr_t ms_checkpointing; 1492 uintptr_t ms_freeing; 1493 uintptr_t ms_freed; 1494 uintptr_t ms_allocatable; 1495 uintptr_t ms_unflushed_frees; 1496 uintptr_t ms_unflushed_allocs; 1497 uintptr_t ms_sm; 1498 } mdb_metaslab_t; 1499 1500 typedef struct mdb_space_map_phys_t { 1501 int64_t smp_alloc; 1502 uint64_t smp_histogram[SPACE_MAP_HISTOGRAM_SIZE]; 1503 } mdb_space_map_phys_t; 1504 1505 typedef struct mdb_space_map { 1506 uint64_t sm_size; 1507 uint8_t sm_shift; 1508 uintptr_t sm_phys; 1509 } mdb_space_map_t; 1510 1511 typedef struct mdb_vdev { 1512 uint64_t vdev_id; 1513 uint64_t vdev_state; 1514 uintptr_t vdev_ops; 1515 struct { 1516 uint64_t vs_aux; 1517 uint64_t vs_ops[VS_ZIO_TYPES]; 1518 uint64_t vs_bytes[VS_ZIO_TYPES]; 1519 uint64_t vs_read_errors; 1520 uint64_t vs_write_errors; 1521 uint64_t vs_checksum_errors; 1522 } vdev_stat; 1523 uintptr_t vdev_child; 1524 uint64_t vdev_children; 1525 uint64_t vdev_ms_count; 1526 uintptr_t vdev_mg; 1527 uintptr_t vdev_ms; 1528 uintptr_t vdev_path; 1529 } mdb_vdev_t; 1530 1531 typedef struct mdb_vdev_ops { 1532 char vdev_op_type[16]; 1533 } mdb_vdev_ops_t; 1534 1535 static int 1536 metaslab_stats(mdb_vdev_t *vd, int spa_flags) 1537 { 1538 mdb_inc_indent(4); 1539 mdb_printf("%<u>%-?s %6s %20s %10s %10s %10s%</u>\n", "ADDR", "ID", 1540 "OFFSET", "FREE", "FRAG", "UCMU"); 1541 1542 uintptr_t *vdev_ms = mdb_alloc(vd->vdev_ms_count * sizeof (vdev_ms), 1543 UM_SLEEP | UM_GC); 1544 if (mdb_vread(vdev_ms, vd->vdev_ms_count * sizeof (uintptr_t), 1545 vd->vdev_ms) == -1) { 1546 mdb_warn("failed to read vdev_ms at %p\n", vd->vdev_ms); 1547 return (DCMD_ERR); 1548 } 1549 1550 for (int m = 0; m < vd->vdev_ms_count; m++) { 1551 mdb_metaslab_t ms; 1552 mdb_space_map_t sm = { 0 }; 1553 mdb_space_map_phys_t smp = { 0 }; 1554 mdb_range_tree_t rt; 1555 uint64_t uallocs, ufrees, raw_free, raw_uchanges_mem; 1556 char free[MDB_NICENUM_BUFLEN]; 1557 char uchanges_mem[MDB_NICENUM_BUFLEN]; 1558 1559 if (mdb_ctf_vread(&ms, "metaslab_t", "mdb_metaslab_t", 1560 vdev_ms[m], 0) == -1) 1561 return (DCMD_ERR); 1562 1563 if (ms.ms_sm != 0 && 1564 mdb_ctf_vread(&sm, "space_map_t", "mdb_space_map_t", 1565 ms.ms_sm, 0) == -1) 1566 return (DCMD_ERR); 1567 1568 if (mdb_ctf_vread(&rt, "range_tree_t", "mdb_range_tree_t", 1569 ms.ms_unflushed_frees, 0) == -1) 1570 return (DCMD_ERR); 1571 ufrees = rt.rt_space; 1572 raw_uchanges_mem = rt.rt_root.bt_num_nodes * BTREE_LEAF_SIZE; 1573 1574 if (mdb_ctf_vread(&rt, "range_tree_t", "mdb_range_tree_t", 1575 ms.ms_unflushed_allocs, 0) == -1) 1576 return (DCMD_ERR); 1577 uallocs = rt.rt_space; 1578 raw_uchanges_mem += rt.rt_root.bt_num_nodes * BTREE_LEAF_SIZE; 1579 mdb_nicenum(raw_uchanges_mem, uchanges_mem); 1580 1581 raw_free = ms.ms_size; 1582 if (ms.ms_sm != 0 && sm.sm_phys != 0) { 1583 (void) mdb_ctf_vread(&smp, "space_map_phys_t", 1584 "mdb_space_map_phys_t", sm.sm_phys, 0); 1585 raw_free -= smp.smp_alloc; 1586 } 1587 raw_free += ufrees - uallocs; 1588 mdb_nicenum(raw_free, free); 1589 1590 mdb_printf("%0?p %6llu %20llx %10s ", vdev_ms[m], ms.ms_id, 1591 ms.ms_start, free); 1592 if (ms.ms_fragmentation == ZFS_FRAG_INVALID) 1593 mdb_printf("%9s ", "-"); 1594 else 1595 mdb_printf("%9llu%% ", ms.ms_fragmentation); 1596 mdb_printf("%10s\n", uchanges_mem); 1597 1598 if ((spa_flags & SPA_FLAG_HISTOGRAMS) && ms.ms_sm != 0 && 1599 sm.sm_phys != 0) { 1600 dump_histogram(smp.smp_histogram, 1601 SPACE_MAP_HISTOGRAM_SIZE, sm.sm_shift); 1602 } 1603 } 1604 mdb_dec_indent(4); 1605 return (DCMD_OK); 1606 } 1607 1608 static int 1609 metaslab_group_stats(mdb_vdev_t *vd, int spa_flags) 1610 { 1611 mdb_metaslab_group_t mg; 1612 if (mdb_ctf_vread(&mg, "metaslab_group_t", "mdb_metaslab_group_t", 1613 vd->vdev_mg, 0) == -1) { 1614 mdb_warn("failed to read vdev_mg at %p\n", vd->vdev_mg); 1615 return (DCMD_ERR); 1616 } 1617 1618 mdb_inc_indent(4); 1619 mdb_printf("%<u>%-?s %7s %9s%</u>\n", "ADDR", "FRAG", "UCMU"); 1620 1621 if (mg.mg_fragmentation == ZFS_FRAG_INVALID) 1622 mdb_printf("%0?p %6s\n", vd->vdev_mg, "-"); 1623 else 1624 mdb_printf("%0?p %6llu%%", vd->vdev_mg, mg.mg_fragmentation); 1625 1626 1627 uintptr_t *vdev_ms = mdb_alloc(vd->vdev_ms_count * sizeof (vdev_ms), 1628 UM_SLEEP | UM_GC); 1629 if (mdb_vread(vdev_ms, vd->vdev_ms_count * sizeof (uintptr_t), 1630 vd->vdev_ms) == -1) { 1631 mdb_warn("failed to read vdev_ms at %p\n", vd->vdev_ms); 1632 return (DCMD_ERR); 1633 } 1634 1635 uint64_t raw_uchanges_mem = 0; 1636 char uchanges_mem[MDB_NICENUM_BUFLEN]; 1637 for (int m = 0; m < vd->vdev_ms_count; m++) { 1638 mdb_metaslab_t ms; 1639 mdb_range_tree_t rt; 1640 1641 if (mdb_ctf_vread(&ms, "metaslab_t", "mdb_metaslab_t", 1642 vdev_ms[m], 0) == -1) 1643 return (DCMD_ERR); 1644 1645 if (mdb_ctf_vread(&rt, "range_tree_t", "mdb_range_tree_t", 1646 ms.ms_unflushed_frees, 0) == -1) 1647 return (DCMD_ERR); 1648 raw_uchanges_mem += rt.rt_root.bt_num_nodes * BTREE_LEAF_SIZE; 1649 1650 if (mdb_ctf_vread(&rt, "range_tree_t", "mdb_range_tree_t", 1651 ms.ms_unflushed_allocs, 0) == -1) 1652 return (DCMD_ERR); 1653 raw_uchanges_mem += rt.rt_root.bt_num_nodes * BTREE_LEAF_SIZE; 1654 } 1655 mdb_nicenum(raw_uchanges_mem, uchanges_mem); 1656 mdb_printf("%10s\n", uchanges_mem); 1657 1658 if (spa_flags & SPA_FLAG_HISTOGRAMS) 1659 dump_histogram(mg.mg_histogram, RANGE_TREE_HISTOGRAM_SIZE, 0); 1660 mdb_dec_indent(4); 1661 return (DCMD_OK); 1662 } 1663 1664 /* 1665 * ::vdev 1666 * 1667 * Print out a summarized vdev_t, in the following form: 1668 * 1669 * ADDR STATE AUX DESC 1670 * fffffffbcde23df0 HEALTHY - /dev/dsk/c0t0d0 1671 * 1672 * If '-r' is specified, recursively visit all children. 1673 * 1674 * With '-e', the statistics associated with the vdev are printed as well. 1675 */ 1676 static int 1677 do_print_vdev(uintptr_t addr, int flags, int depth, boolean_t recursive, 1678 int spa_flags) 1679 { 1680 mdb_vdev_t vd; 1681 if (mdb_ctf_vread(&vd, "vdev_t", "mdb_vdev_t", 1682 (uintptr_t)addr, 0) == -1) 1683 return (DCMD_ERR); 1684 1685 if (flags & DCMD_PIPE_OUT) { 1686 mdb_printf("%#lr\n", addr); 1687 } else { 1688 char desc[MAXNAMELEN]; 1689 if (vd.vdev_path != 0) { 1690 if (mdb_readstr(desc, sizeof (desc), 1691 (uintptr_t)vd.vdev_path) == -1) { 1692 mdb_warn("failed to read vdev_path at %p\n", 1693 vd.vdev_path); 1694 return (DCMD_ERR); 1695 } 1696 } else if (vd.vdev_ops != 0) { 1697 vdev_ops_t ops; 1698 if (mdb_vread(&ops, sizeof (ops), 1699 (uintptr_t)vd.vdev_ops) == -1) { 1700 mdb_warn("failed to read vdev_ops at %p\n", 1701 vd.vdev_ops); 1702 return (DCMD_ERR); 1703 } 1704 (void) strcpy(desc, ops.vdev_op_type); 1705 } else { 1706 (void) strcpy(desc, "<unknown>"); 1707 } 1708 1709 if (depth == 0 && DCMD_HDRSPEC(flags)) 1710 mdb_printf("%<u>%-?s %-9s %-12s %-*s%</u>\n", 1711 "ADDR", "STATE", "AUX", 1712 sizeof (uintptr_t) == 4 ? 43 : 35, 1713 "DESCRIPTION"); 1714 1715 mdb_printf("%0?p ", addr); 1716 1717 const char *state, *aux; 1718 switch (vd.vdev_state) { 1719 case VDEV_STATE_CLOSED: 1720 state = "CLOSED"; 1721 break; 1722 case VDEV_STATE_OFFLINE: 1723 state = "OFFLINE"; 1724 break; 1725 case VDEV_STATE_CANT_OPEN: 1726 state = "CANT_OPEN"; 1727 break; 1728 case VDEV_STATE_DEGRADED: 1729 state = "DEGRADED"; 1730 break; 1731 case VDEV_STATE_HEALTHY: 1732 state = "HEALTHY"; 1733 break; 1734 case VDEV_STATE_REMOVED: 1735 state = "REMOVED"; 1736 break; 1737 case VDEV_STATE_FAULTED: 1738 state = "FAULTED"; 1739 break; 1740 default: 1741 state = "UNKNOWN"; 1742 break; 1743 } 1744 1745 switch (vd.vdev_stat.vs_aux) { 1746 case VDEV_AUX_NONE: 1747 aux = "-"; 1748 break; 1749 case VDEV_AUX_OPEN_FAILED: 1750 aux = "OPEN_FAILED"; 1751 break; 1752 case VDEV_AUX_CORRUPT_DATA: 1753 aux = "CORRUPT_DATA"; 1754 break; 1755 case VDEV_AUX_NO_REPLICAS: 1756 aux = "NO_REPLICAS"; 1757 break; 1758 case VDEV_AUX_BAD_GUID_SUM: 1759 aux = "BAD_GUID_SUM"; 1760 break; 1761 case VDEV_AUX_TOO_SMALL: 1762 aux = "TOO_SMALL"; 1763 break; 1764 case VDEV_AUX_BAD_LABEL: 1765 aux = "BAD_LABEL"; 1766 break; 1767 case VDEV_AUX_VERSION_NEWER: 1768 aux = "VERS_NEWER"; 1769 break; 1770 case VDEV_AUX_VERSION_OLDER: 1771 aux = "VERS_OLDER"; 1772 break; 1773 case VDEV_AUX_UNSUP_FEAT: 1774 aux = "UNSUP_FEAT"; 1775 break; 1776 case VDEV_AUX_SPARED: 1777 aux = "SPARED"; 1778 break; 1779 case VDEV_AUX_ERR_EXCEEDED: 1780 aux = "ERR_EXCEEDED"; 1781 break; 1782 case VDEV_AUX_IO_FAILURE: 1783 aux = "IO_FAILURE"; 1784 break; 1785 case VDEV_AUX_BAD_LOG: 1786 aux = "BAD_LOG"; 1787 break; 1788 case VDEV_AUX_EXTERNAL: 1789 aux = "EXTERNAL"; 1790 break; 1791 case VDEV_AUX_SPLIT_POOL: 1792 aux = "SPLIT_POOL"; 1793 break; 1794 case VDEV_AUX_CHILDREN_OFFLINE: 1795 aux = "CHILDREN_OFFLINE"; 1796 break; 1797 default: 1798 aux = "UNKNOWN"; 1799 break; 1800 } 1801 1802 mdb_printf("%-9s %-12s %*s%s\n", state, aux, depth, "", desc); 1803 1804 if (spa_flags & SPA_FLAG_ERRORS) { 1805 int i; 1806 1807 mdb_inc_indent(4); 1808 mdb_printf("\n"); 1809 mdb_printf("%<u> %12s %12s %12s %12s " 1810 "%12s%</u>\n", "READ", "WRITE", "FREE", "CLAIM", 1811 "IOCTL"); 1812 mdb_printf("OPS "); 1813 for (i = 1; i < VS_ZIO_TYPES; i++) 1814 mdb_printf("%11#llx%s", 1815 vd.vdev_stat.vs_ops[i], 1816 i == VS_ZIO_TYPES - 1 ? "" : " "); 1817 mdb_printf("\n"); 1818 mdb_printf("BYTES "); 1819 for (i = 1; i < VS_ZIO_TYPES; i++) 1820 mdb_printf("%11#llx%s", 1821 vd.vdev_stat.vs_bytes[i], 1822 i == VS_ZIO_TYPES - 1 ? "" : " "); 1823 1824 1825 mdb_printf("\n"); 1826 mdb_printf("EREAD %10#llx\n", 1827 vd.vdev_stat.vs_read_errors); 1828 mdb_printf("EWRITE %10#llx\n", 1829 vd.vdev_stat.vs_write_errors); 1830 mdb_printf("ECKSUM %10#llx\n", 1831 vd.vdev_stat.vs_checksum_errors); 1832 mdb_dec_indent(4); 1833 mdb_printf("\n"); 1834 } 1835 1836 if ((spa_flags & SPA_FLAG_METASLAB_GROUPS) && 1837 vd.vdev_mg != 0) { 1838 metaslab_group_stats(&vd, spa_flags); 1839 } 1840 if ((spa_flags & SPA_FLAG_METASLABS) && vd.vdev_ms != 0) { 1841 metaslab_stats(&vd, spa_flags); 1842 } 1843 } 1844 1845 uint64_t children = vd.vdev_children; 1846 if (children == 0 || !recursive) 1847 return (DCMD_OK); 1848 1849 uintptr_t *child = mdb_alloc(children * sizeof (child), 1850 UM_SLEEP | UM_GC); 1851 if (mdb_vread(child, children * sizeof (void *), vd.vdev_child) == -1) { 1852 mdb_warn("failed to read vdev children at %p", vd.vdev_child); 1853 return (DCMD_ERR); 1854 } 1855 1856 for (uint64_t c = 0; c < children; c++) { 1857 if (do_print_vdev(child[c], flags, depth + 2, recursive, 1858 spa_flags)) { 1859 return (DCMD_ERR); 1860 } 1861 } 1862 1863 return (DCMD_OK); 1864 } 1865 1866 static int 1867 vdev_print(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 1868 { 1869 uint64_t depth = 0; 1870 boolean_t recursive = B_FALSE; 1871 int spa_flags = 0; 1872 1873 if (mdb_getopts(argc, argv, 1874 'e', MDB_OPT_SETBITS, SPA_FLAG_ERRORS, &spa_flags, 1875 'm', MDB_OPT_SETBITS, SPA_FLAG_METASLABS, &spa_flags, 1876 'M', MDB_OPT_SETBITS, SPA_FLAG_METASLAB_GROUPS, &spa_flags, 1877 'h', MDB_OPT_SETBITS, SPA_FLAG_HISTOGRAMS, &spa_flags, 1878 'r', MDB_OPT_SETBITS, TRUE, &recursive, 1879 'd', MDB_OPT_UINT64, &depth, NULL) != argc) 1880 return (DCMD_USAGE); 1881 1882 if (!(flags & DCMD_ADDRSPEC)) { 1883 mdb_warn("no vdev_t address given\n"); 1884 return (DCMD_ERR); 1885 } 1886 1887 return (do_print_vdev(addr, flags, (int)depth, recursive, spa_flags)); 1888 } 1889 1890 typedef struct mdb_metaslab_alloc_trace { 1891 uintptr_t mat_mg; 1892 uintptr_t mat_msp; 1893 uint64_t mat_size; 1894 uint64_t mat_weight; 1895 uint64_t mat_offset; 1896 uint32_t mat_dva_id; 1897 int mat_allocator; 1898 } mdb_metaslab_alloc_trace_t; 1899 1900 static void 1901 metaslab_print_weight(uint64_t weight) 1902 { 1903 char buf[100]; 1904 1905 if (WEIGHT_IS_SPACEBASED(weight)) { 1906 mdb_nicenum( 1907 weight & ~(METASLAB_ACTIVE_MASK | METASLAB_WEIGHT_TYPE), 1908 buf); 1909 } else { 1910 char size[MDB_NICENUM_BUFLEN]; 1911 mdb_nicenum(1ULL << WEIGHT_GET_INDEX(weight), size); 1912 (void) mdb_snprintf(buf, sizeof (buf), "%llu x %s", 1913 WEIGHT_GET_COUNT(weight), size); 1914 } 1915 mdb_printf("%11s ", buf); 1916 } 1917 1918 /* ARGSUSED */ 1919 static int 1920 metaslab_weight(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 1921 { 1922 uint64_t weight = 0; 1923 char active; 1924 1925 if (argc == 0 && (flags & DCMD_ADDRSPEC)) { 1926 if (mdb_vread(&weight, sizeof (uint64_t), addr) == -1) { 1927 mdb_warn("failed to read weight at %p\n", addr); 1928 return (DCMD_ERR); 1929 } 1930 } else if (argc == 1 && !(flags & DCMD_ADDRSPEC)) { 1931 weight = (argv[0].a_type == MDB_TYPE_IMMEDIATE) ? 1932 argv[0].a_un.a_val : mdb_strtoull(argv[0].a_un.a_str); 1933 } else { 1934 return (DCMD_USAGE); 1935 } 1936 1937 if (DCMD_HDRSPEC(flags)) { 1938 mdb_printf("%<u>%-6s %9s %9s%</u>\n", 1939 "ACTIVE", "ALGORITHM", "WEIGHT"); 1940 } 1941 1942 if (weight & METASLAB_WEIGHT_PRIMARY) 1943 active = 'P'; 1944 else if (weight & METASLAB_WEIGHT_SECONDARY) 1945 active = 'S'; 1946 else 1947 active = '-'; 1948 mdb_printf("%6c %8s ", active, 1949 WEIGHT_IS_SPACEBASED(weight) ? "SPACE" : "SEGMENT"); 1950 metaslab_print_weight(weight); 1951 mdb_printf("\n"); 1952 1953 return (DCMD_OK); 1954 } 1955 1956 /* ARGSUSED */ 1957 static int 1958 metaslab_trace(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 1959 { 1960 mdb_metaslab_alloc_trace_t mat; 1961 mdb_metaslab_group_t mg = { 0 }; 1962 char result_type[100]; 1963 1964 if (mdb_ctf_vread(&mat, "metaslab_alloc_trace_t", 1965 "mdb_metaslab_alloc_trace_t", addr, 0) == -1) { 1966 return (DCMD_ERR); 1967 } 1968 1969 if (!(flags & DCMD_PIPE_OUT) && DCMD_HDRSPEC(flags)) { 1970 mdb_printf("%<u>%6s %6s %8s %11s %11s %18s %18s%</u>\n", 1971 "MSID", "DVA", "ASIZE", "ALLOCATOR", "WEIGHT", "RESULT", 1972 "VDEV"); 1973 } 1974 1975 if (mat.mat_msp != 0) { 1976 mdb_metaslab_t ms; 1977 1978 if (mdb_ctf_vread(&ms, "metaslab_t", "mdb_metaslab_t", 1979 mat.mat_msp, 0) == -1) { 1980 return (DCMD_ERR); 1981 } 1982 mdb_printf("%6llu ", ms.ms_id); 1983 } else { 1984 mdb_printf("%6s ", "-"); 1985 } 1986 1987 mdb_printf("%6d %8llx %11llx ", mat.mat_dva_id, mat.mat_size, 1988 mat.mat_allocator); 1989 1990 metaslab_print_weight(mat.mat_weight); 1991 1992 if ((int64_t)mat.mat_offset < 0) { 1993 if (enum_lookup("enum trace_alloc_type", mat.mat_offset, 1994 "TRACE_", sizeof (result_type), result_type) == -1) { 1995 mdb_warn("Could not find enum for trace_alloc_type"); 1996 return (DCMD_ERR); 1997 } 1998 mdb_printf("%18s ", result_type); 1999 } else { 2000 mdb_printf("%<b>%18llx%</b> ", mat.mat_offset); 2001 } 2002 2003 if (mat.mat_mg != 0 && 2004 mdb_ctf_vread(&mg, "metaslab_group_t", "mdb_metaslab_group_t", 2005 mat.mat_mg, 0) == -1) { 2006 return (DCMD_ERR); 2007 } 2008 2009 if (mg.mg_vd != 0) { 2010 mdb_vdev_t vdev; 2011 char desc[MAXNAMELEN]; 2012 2013 if (mdb_ctf_vread(&vdev, "vdev_t", "mdb_vdev_t", 2014 mg.mg_vd, 0) == -1) { 2015 return (DCMD_ERR); 2016 } 2017 2018 if (vdev.vdev_path != 0) { 2019 char path[MAXNAMELEN]; 2020 2021 if (mdb_readstr(path, sizeof (path), 2022 vdev.vdev_path) == -1) { 2023 mdb_warn("failed to read vdev_path at %p\n", 2024 vdev.vdev_path); 2025 return (DCMD_ERR); 2026 } 2027 char *slash; 2028 if ((slash = strrchr(path, '/')) != NULL) { 2029 strcpy(desc, slash + 1); 2030 } else { 2031 strcpy(desc, path); 2032 } 2033 } else if (vdev.vdev_ops != 0) { 2034 mdb_vdev_ops_t ops; 2035 if (mdb_ctf_vread(&ops, "vdev_ops_t", "mdb_vdev_ops_t", 2036 vdev.vdev_ops, 0) == -1) { 2037 mdb_warn("failed to read vdev_ops at %p\n", 2038 vdev.vdev_ops); 2039 return (DCMD_ERR); 2040 } 2041 (void) mdb_snprintf(desc, sizeof (desc), 2042 "%s-%llu", ops.vdev_op_type, vdev.vdev_id); 2043 } else { 2044 (void) strcpy(desc, "<unknown>"); 2045 } 2046 mdb_printf("%18s\n", desc); 2047 } 2048 2049 return (DCMD_OK); 2050 } 2051 2052 typedef struct metaslab_walk_data { 2053 uint64_t mw_numvdevs; 2054 uintptr_t *mw_vdevs; 2055 int mw_curvdev; 2056 uint64_t mw_nummss; 2057 uintptr_t *mw_mss; 2058 int mw_curms; 2059 } metaslab_walk_data_t; 2060 2061 static int 2062 metaslab_walk_step(mdb_walk_state_t *wsp) 2063 { 2064 metaslab_walk_data_t *mw = wsp->walk_data; 2065 metaslab_t ms; 2066 uintptr_t msp; 2067 2068 if (mw->mw_curvdev >= mw->mw_numvdevs) 2069 return (WALK_DONE); 2070 2071 if (mw->mw_mss == NULL) { 2072 uintptr_t mssp; 2073 uintptr_t vdevp; 2074 2075 ASSERT(mw->mw_curms == 0); 2076 ASSERT(mw->mw_nummss == 0); 2077 2078 vdevp = mw->mw_vdevs[mw->mw_curvdev]; 2079 if (GETMEMB(vdevp, "vdev", vdev_ms, mssp) || 2080 GETMEMB(vdevp, "vdev", vdev_ms_count, mw->mw_nummss)) { 2081 return (WALK_ERR); 2082 } 2083 2084 mw->mw_mss = mdb_alloc(mw->mw_nummss * sizeof (void*), 2085 UM_SLEEP | UM_GC); 2086 if (mdb_vread(mw->mw_mss, mw->mw_nummss * sizeof (void*), 2087 mssp) == -1) { 2088 mdb_warn("failed to read vdev_ms at %p", mssp); 2089 return (WALK_ERR); 2090 } 2091 } 2092 2093 if (mw->mw_curms >= mw->mw_nummss) { 2094 mw->mw_mss = NULL; 2095 mw->mw_curms = 0; 2096 mw->mw_nummss = 0; 2097 mw->mw_curvdev++; 2098 return (WALK_NEXT); 2099 } 2100 2101 msp = mw->mw_mss[mw->mw_curms]; 2102 if (mdb_vread(&ms, sizeof (metaslab_t), msp) == -1) { 2103 mdb_warn("failed to read metaslab_t at %p", msp); 2104 return (WALK_ERR); 2105 } 2106 2107 mw->mw_curms++; 2108 2109 return (wsp->walk_callback(msp, &ms, wsp->walk_cbdata)); 2110 } 2111 2112 static int 2113 metaslab_walk_init(mdb_walk_state_t *wsp) 2114 { 2115 metaslab_walk_data_t *mw; 2116 uintptr_t root_vdevp; 2117 uintptr_t childp; 2118 2119 if (wsp->walk_addr == 0) { 2120 mdb_warn("must supply address of spa_t\n"); 2121 return (WALK_ERR); 2122 } 2123 2124 mw = mdb_zalloc(sizeof (metaslab_walk_data_t), UM_SLEEP | UM_GC); 2125 2126 if (GETMEMB(wsp->walk_addr, "spa", spa_root_vdev, root_vdevp) || 2127 GETMEMB(root_vdevp, "vdev", vdev_children, mw->mw_numvdevs) || 2128 GETMEMB(root_vdevp, "vdev", vdev_child, childp)) { 2129 return (DCMD_ERR); 2130 } 2131 2132 mw->mw_vdevs = mdb_alloc(mw->mw_numvdevs * sizeof (void *), 2133 UM_SLEEP | UM_GC); 2134 if (mdb_vread(mw->mw_vdevs, mw->mw_numvdevs * sizeof (void *), 2135 childp) == -1) { 2136 mdb_warn("failed to read root vdev children at %p", childp); 2137 return (DCMD_ERR); 2138 } 2139 2140 wsp->walk_data = mw; 2141 2142 return (WALK_NEXT); 2143 } 2144 2145 typedef struct mdb_spa { 2146 uintptr_t spa_dsl_pool; 2147 uintptr_t spa_root_vdev; 2148 } mdb_spa_t; 2149 2150 typedef struct mdb_dsl_pool { 2151 uintptr_t dp_root_dir; 2152 } mdb_dsl_pool_t; 2153 2154 typedef struct mdb_dsl_dir { 2155 uintptr_t dd_dbuf; 2156 int64_t dd_space_towrite[TXG_SIZE]; 2157 } mdb_dsl_dir_t; 2158 2159 typedef struct mdb_dsl_dir_phys { 2160 uint64_t dd_used_bytes; 2161 uint64_t dd_compressed_bytes; 2162 uint64_t dd_uncompressed_bytes; 2163 } mdb_dsl_dir_phys_t; 2164 2165 typedef struct space_data { 2166 uint64_t ms_allocating[TXG_SIZE]; 2167 uint64_t ms_checkpointing; 2168 uint64_t ms_freeing; 2169 uint64_t ms_freed; 2170 uint64_t ms_unflushed_frees; 2171 uint64_t ms_unflushed_allocs; 2172 uint64_t ms_allocatable; 2173 int64_t ms_deferspace; 2174 uint64_t avail; 2175 } space_data_t; 2176 2177 /* ARGSUSED */ 2178 static int 2179 space_cb(uintptr_t addr, const void *unknown, void *arg) 2180 { 2181 space_data_t *sd = arg; 2182 mdb_metaslab_t ms; 2183 mdb_range_tree_t rt; 2184 mdb_space_map_t sm = { 0 }; 2185 mdb_space_map_phys_t smp = { 0 }; 2186 uint64_t uallocs, ufrees; 2187 int i; 2188 2189 if (mdb_ctf_vread(&ms, "metaslab_t", "mdb_metaslab_t", 2190 addr, 0) == -1) 2191 return (WALK_ERR); 2192 2193 for (i = 0; i < TXG_SIZE; i++) { 2194 if (mdb_ctf_vread(&rt, "range_tree_t", 2195 "mdb_range_tree_t", ms.ms_allocating[i], 0) == -1) 2196 return (WALK_ERR); 2197 sd->ms_allocating[i] += rt.rt_space; 2198 } 2199 2200 if (mdb_ctf_vread(&rt, "range_tree_t", 2201 "mdb_range_tree_t", ms.ms_checkpointing, 0) == -1) 2202 return (WALK_ERR); 2203 sd->ms_checkpointing += rt.rt_space; 2204 2205 if (mdb_ctf_vread(&rt, "range_tree_t", 2206 "mdb_range_tree_t", ms.ms_freeing, 0) == -1) 2207 return (WALK_ERR); 2208 sd->ms_freeing += rt.rt_space; 2209 2210 if (mdb_ctf_vread(&rt, "range_tree_t", 2211 "mdb_range_tree_t", ms.ms_freed, 0) == -1) 2212 return (WALK_ERR); 2213 sd->ms_freed += rt.rt_space; 2214 2215 if (mdb_ctf_vread(&rt, "range_tree_t", 2216 "mdb_range_tree_t", ms.ms_allocatable, 0) == -1) 2217 return (WALK_ERR); 2218 sd->ms_allocatable += rt.rt_space; 2219 2220 if (mdb_ctf_vread(&rt, "range_tree_t", 2221 "mdb_range_tree_t", ms.ms_unflushed_frees, 0) == -1) 2222 return (WALK_ERR); 2223 sd->ms_unflushed_frees += rt.rt_space; 2224 ufrees = rt.rt_space; 2225 2226 if (mdb_ctf_vread(&rt, "range_tree_t", 2227 "mdb_range_tree_t", ms.ms_unflushed_allocs, 0) == -1) 2228 return (WALK_ERR); 2229 sd->ms_unflushed_allocs += rt.rt_space; 2230 uallocs = rt.rt_space; 2231 2232 if (ms.ms_sm != 0 && 2233 mdb_ctf_vread(&sm, "space_map_t", 2234 "mdb_space_map_t", ms.ms_sm, 0) == -1) 2235 return (WALK_ERR); 2236 2237 if (sm.sm_phys != 0) { 2238 (void) mdb_ctf_vread(&smp, "space_map_phys_t", 2239 "mdb_space_map_phys_t", sm.sm_phys, 0); 2240 } 2241 2242 sd->ms_deferspace += ms.ms_deferspace; 2243 sd->avail += sm.sm_size - smp.smp_alloc + ufrees - uallocs; 2244 2245 return (WALK_NEXT); 2246 } 2247 2248 /* 2249 * ::spa_space [-b] 2250 * 2251 * Given a spa_t, print out it's on-disk space usage and in-core 2252 * estimates of future usage. If -b is given, print space in bytes. 2253 * Otherwise print in megabytes. 2254 */ 2255 /* ARGSUSED */ 2256 static int 2257 spa_space(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 2258 { 2259 mdb_spa_t spa; 2260 mdb_dsl_pool_t dp; 2261 mdb_dsl_dir_t dd; 2262 mdb_dmu_buf_impl_t db; 2263 mdb_dsl_dir_phys_t dsp; 2264 space_data_t sd; 2265 int shift = 20; 2266 char *suffix = "M"; 2267 int bytes = B_FALSE; 2268 2269 if (mdb_getopts(argc, argv, 'b', MDB_OPT_SETBITS, TRUE, &bytes, NULL) != 2270 argc) 2271 return (DCMD_USAGE); 2272 if (!(flags & DCMD_ADDRSPEC)) 2273 return (DCMD_USAGE); 2274 2275 if (bytes) { 2276 shift = 0; 2277 suffix = ""; 2278 } 2279 2280 if (mdb_ctf_vread(&spa, ZFS_STRUCT "spa", "mdb_spa_t", 2281 addr, 0) == -1 || 2282 mdb_ctf_vread(&dp, ZFS_STRUCT "dsl_pool", "mdb_dsl_pool_t", 2283 spa.spa_dsl_pool, 0) == -1 || 2284 mdb_ctf_vread(&dd, ZFS_STRUCT "dsl_dir", "mdb_dsl_dir_t", 2285 dp.dp_root_dir, 0) == -1 || 2286 mdb_ctf_vread(&db, ZFS_STRUCT "dmu_buf_impl", "mdb_dmu_buf_impl_t", 2287 dd.dd_dbuf, 0) == -1 || 2288 mdb_ctf_vread(&dsp, ZFS_STRUCT "dsl_dir_phys", 2289 "mdb_dsl_dir_phys_t", db.db.db_data, 0) == -1) { 2290 return (DCMD_ERR); 2291 } 2292 2293 mdb_printf("dd_space_towrite = %llu%s %llu%s %llu%s %llu%s\n", 2294 dd.dd_space_towrite[0] >> shift, suffix, 2295 dd.dd_space_towrite[1] >> shift, suffix, 2296 dd.dd_space_towrite[2] >> shift, suffix, 2297 dd.dd_space_towrite[3] >> shift, suffix); 2298 2299 mdb_printf("dd_phys.dd_used_bytes = %llu%s\n", 2300 dsp.dd_used_bytes >> shift, suffix); 2301 mdb_printf("dd_phys.dd_compressed_bytes = %llu%s\n", 2302 dsp.dd_compressed_bytes >> shift, suffix); 2303 mdb_printf("dd_phys.dd_uncompressed_bytes = %llu%s\n", 2304 dsp.dd_uncompressed_bytes >> shift, suffix); 2305 2306 bzero(&sd, sizeof (sd)); 2307 if (mdb_pwalk("metaslab", space_cb, &sd, addr) != 0) { 2308 mdb_warn("can't walk metaslabs"); 2309 return (DCMD_ERR); 2310 } 2311 2312 mdb_printf("ms_allocmap = %llu%s %llu%s %llu%s %llu%s\n", 2313 sd.ms_allocating[0] >> shift, suffix, 2314 sd.ms_allocating[1] >> shift, suffix, 2315 sd.ms_allocating[2] >> shift, suffix, 2316 sd.ms_allocating[3] >> shift, suffix); 2317 mdb_printf("ms_checkpointing = %llu%s\n", 2318 sd.ms_checkpointing >> shift, suffix); 2319 mdb_printf("ms_freeing = %llu%s\n", 2320 sd.ms_freeing >> shift, suffix); 2321 mdb_printf("ms_freed = %llu%s\n", 2322 sd.ms_freed >> shift, suffix); 2323 mdb_printf("ms_unflushed_frees = %llu%s\n", 2324 sd.ms_unflushed_frees >> shift, suffix); 2325 mdb_printf("ms_unflushed_allocs = %llu%s\n", 2326 sd.ms_unflushed_allocs >> shift, suffix); 2327 mdb_printf("ms_allocatable = %llu%s\n", 2328 sd.ms_allocatable >> shift, suffix); 2329 mdb_printf("ms_deferspace = %llu%s\n", 2330 sd.ms_deferspace >> shift, suffix); 2331 mdb_printf("current avail = %llu%s\n", 2332 sd.avail >> shift, suffix); 2333 2334 return (DCMD_OK); 2335 } 2336 2337 typedef struct mdb_spa_aux_vdev { 2338 int sav_count; 2339 uintptr_t sav_vdevs; 2340 } mdb_spa_aux_vdev_t; 2341 2342 typedef struct mdb_spa_vdevs { 2343 uintptr_t spa_root_vdev; 2344 mdb_spa_aux_vdev_t spa_l2cache; 2345 mdb_spa_aux_vdev_t spa_spares; 2346 } mdb_spa_vdevs_t; 2347 2348 static int 2349 spa_print_aux(mdb_spa_aux_vdev_t *sav, uint_t flags, mdb_arg_t *v, 2350 const char *name) 2351 { 2352 uintptr_t *aux; 2353 size_t len; 2354 int ret, i; 2355 2356 /* 2357 * Iterate over aux vdevs and print those out as well. This is a 2358 * little annoying because we don't have a root vdev to pass to ::vdev. 2359 * Instead, we print a single line and then call it for each child 2360 * vdev. 2361 */ 2362 if (sav->sav_count != 0) { 2363 v[1].a_type = MDB_TYPE_STRING; 2364 v[1].a_un.a_str = "-d"; 2365 v[2].a_type = MDB_TYPE_IMMEDIATE; 2366 v[2].a_un.a_val = 2; 2367 2368 len = sav->sav_count * sizeof (uintptr_t); 2369 aux = mdb_alloc(len, UM_SLEEP); 2370 if (mdb_vread(aux, len, sav->sav_vdevs) == -1) { 2371 mdb_free(aux, len); 2372 mdb_warn("failed to read l2cache vdevs at %p", 2373 sav->sav_vdevs); 2374 return (DCMD_ERR); 2375 } 2376 2377 mdb_printf("%-?s %-9s %-12s %s\n", "-", "-", "-", name); 2378 2379 for (i = 0; i < sav->sav_count; i++) { 2380 ret = mdb_call_dcmd("vdev", aux[i], flags, 3, v); 2381 if (ret != DCMD_OK) { 2382 mdb_free(aux, len); 2383 return (ret); 2384 } 2385 } 2386 2387 mdb_free(aux, len); 2388 } 2389 2390 return (0); 2391 } 2392 2393 /* 2394 * ::spa_vdevs 2395 * 2396 * -e Include error stats 2397 * -m Include metaslab information 2398 * -M Include metaslab group information 2399 * -h Include histogram information (requires -m or -M) 2400 * 2401 * Print out a summarized list of vdevs for the given spa_t. 2402 * This is accomplished by invoking "::vdev -re" on the root vdev, as well as 2403 * iterating over the cache devices. 2404 */ 2405 /* ARGSUSED */ 2406 static int 2407 spa_vdevs(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 2408 { 2409 mdb_arg_t v[3]; 2410 int ret; 2411 char opts[100] = "-r"; 2412 int spa_flags = 0; 2413 2414 if (mdb_getopts(argc, argv, 2415 'e', MDB_OPT_SETBITS, SPA_FLAG_ERRORS, &spa_flags, 2416 'm', MDB_OPT_SETBITS, SPA_FLAG_METASLABS, &spa_flags, 2417 'M', MDB_OPT_SETBITS, SPA_FLAG_METASLAB_GROUPS, &spa_flags, 2418 'h', MDB_OPT_SETBITS, SPA_FLAG_HISTOGRAMS, &spa_flags, 2419 NULL) != argc) 2420 return (DCMD_USAGE); 2421 2422 if (!(flags & DCMD_ADDRSPEC)) 2423 return (DCMD_USAGE); 2424 2425 mdb_spa_vdevs_t spa; 2426 if (mdb_ctf_vread(&spa, "spa_t", "mdb_spa_vdevs_t", addr, 0) == -1) 2427 return (DCMD_ERR); 2428 2429 /* 2430 * Unitialized spa_t structures can have a NULL root vdev. 2431 */ 2432 if (spa.spa_root_vdev == 0) { 2433 mdb_printf("no associated vdevs\n"); 2434 return (DCMD_OK); 2435 } 2436 2437 if (spa_flags & SPA_FLAG_ERRORS) 2438 strcat(opts, "e"); 2439 if (spa_flags & SPA_FLAG_METASLABS) 2440 strcat(opts, "m"); 2441 if (spa_flags & SPA_FLAG_METASLAB_GROUPS) 2442 strcat(opts, "M"); 2443 if (spa_flags & SPA_FLAG_HISTOGRAMS) 2444 strcat(opts, "h"); 2445 2446 v[0].a_type = MDB_TYPE_STRING; 2447 v[0].a_un.a_str = opts; 2448 2449 ret = mdb_call_dcmd("vdev", (uintptr_t)spa.spa_root_vdev, 2450 flags, 1, v); 2451 if (ret != DCMD_OK) 2452 return (ret); 2453 2454 if (spa_print_aux(&spa.spa_l2cache, flags, v, "cache") != 0 || 2455 spa_print_aux(&spa.spa_spares, flags, v, "spares") != 0) 2456 return (DCMD_ERR); 2457 2458 return (DCMD_OK); 2459 } 2460 2461 /* 2462 * ::zio 2463 * 2464 * Print a summary of zio_t and all its children. This is intended to display a 2465 * zio tree, and hence we only pick the most important pieces of information for 2466 * the main summary. More detailed information can always be found by doing a 2467 * '::print zio' on the underlying zio_t. The columns we display are: 2468 * 2469 * ADDRESS TYPE STAGE WAITER TIME_ELAPSED 2470 * 2471 * The 'address' column is indented by one space for each depth level as we 2472 * descend down the tree. 2473 */ 2474 2475 #define ZIO_MAXINDENT 7 2476 #define ZIO_MAXWIDTH (sizeof (uintptr_t) * 2 + ZIO_MAXINDENT) 2477 #define ZIO_WALK_SELF 0 2478 #define ZIO_WALK_CHILD 1 2479 #define ZIO_WALK_PARENT 2 2480 2481 typedef struct zio_print_args { 2482 int zpa_current_depth; 2483 int zpa_min_depth; 2484 int zpa_max_depth; 2485 int zpa_type; 2486 uint_t zpa_flags; 2487 } zio_print_args_t; 2488 2489 typedef struct mdb_zio { 2490 enum zio_type io_type; 2491 enum zio_stage io_stage; 2492 uintptr_t io_waiter; 2493 uintptr_t io_spa; 2494 struct { 2495 struct { 2496 uintptr_t list_next; 2497 } list_head; 2498 } io_parent_list; 2499 int io_error; 2500 } mdb_zio_t; 2501 2502 typedef struct mdb_zio_timestamp { 2503 hrtime_t io_timestamp; 2504 } mdb_zio_timestamp_t; 2505 2506 static int zio_child_cb(uintptr_t addr, const void *unknown, void *arg); 2507 2508 static int 2509 zio_print_cb(uintptr_t addr, zio_print_args_t *zpa) 2510 { 2511 mdb_ctf_id_t type_enum, stage_enum; 2512 int indent = zpa->zpa_current_depth; 2513 const char *type, *stage; 2514 uintptr_t laddr; 2515 mdb_zio_t zio; 2516 mdb_zio_timestamp_t zio_timestamp = { 0 }; 2517 2518 if (mdb_ctf_vread(&zio, ZFS_STRUCT "zio", "mdb_zio_t", addr, 0) == -1) 2519 return (WALK_ERR); 2520 (void) mdb_ctf_vread(&zio_timestamp, ZFS_STRUCT "zio", 2521 "mdb_zio_timestamp_t", addr, MDB_CTF_VREAD_QUIET); 2522 2523 if (indent > ZIO_MAXINDENT) 2524 indent = ZIO_MAXINDENT; 2525 2526 if (mdb_ctf_lookup_by_name("enum zio_type", &type_enum) == -1 || 2527 mdb_ctf_lookup_by_name("enum zio_stage", &stage_enum) == -1) { 2528 mdb_warn("failed to lookup zio enums"); 2529 return (WALK_ERR); 2530 } 2531 2532 if ((type = mdb_ctf_enum_name(type_enum, zio.io_type)) != NULL) 2533 type += sizeof ("ZIO_TYPE_") - 1; 2534 else 2535 type = "?"; 2536 2537 if (zio.io_error == 0) { 2538 stage = mdb_ctf_enum_name(stage_enum, zio.io_stage); 2539 if (stage != NULL) 2540 stage += sizeof ("ZIO_STAGE_") - 1; 2541 else 2542 stage = "?"; 2543 } else { 2544 stage = "FAILED"; 2545 } 2546 2547 if (zpa->zpa_current_depth >= zpa->zpa_min_depth) { 2548 if (zpa->zpa_flags & DCMD_PIPE_OUT) { 2549 mdb_printf("%?p\n", addr); 2550 } else { 2551 mdb_printf("%*s%-*p %-5s %-16s ", indent, "", 2552 ZIO_MAXWIDTH - indent, addr, type, stage); 2553 if (zio.io_waiter != 0) 2554 mdb_printf("%-16lx ", zio.io_waiter); 2555 else 2556 mdb_printf("%-16s ", "-"); 2557 #ifdef _KERNEL 2558 if (zio_timestamp.io_timestamp != 0) { 2559 mdb_printf("%llums", (mdb_gethrtime() - 2560 zio_timestamp.io_timestamp) / 2561 1000000); 2562 } else { 2563 mdb_printf("%-12s ", "-"); 2564 } 2565 #else 2566 mdb_printf("%-12s ", "-"); 2567 #endif 2568 mdb_printf("\n"); 2569 } 2570 } 2571 2572 if (zpa->zpa_current_depth >= zpa->zpa_max_depth) 2573 return (WALK_NEXT); 2574 2575 if (zpa->zpa_type == ZIO_WALK_PARENT) 2576 laddr = addr + mdb_ctf_offsetof_by_name(ZFS_STRUCT "zio", 2577 "io_parent_list"); 2578 else 2579 laddr = addr + mdb_ctf_offsetof_by_name(ZFS_STRUCT "zio", 2580 "io_child_list"); 2581 2582 zpa->zpa_current_depth++; 2583 if (mdb_pwalk("list", zio_child_cb, zpa, laddr) != 0) { 2584 mdb_warn("failed to walk zio_t children at %p\n", laddr); 2585 return (WALK_ERR); 2586 } 2587 zpa->zpa_current_depth--; 2588 2589 return (WALK_NEXT); 2590 } 2591 2592 /* ARGSUSED */ 2593 static int 2594 zio_child_cb(uintptr_t addr, const void *unknown, void *arg) 2595 { 2596 zio_link_t zl; 2597 uintptr_t ziop; 2598 zio_print_args_t *zpa = arg; 2599 2600 if (mdb_vread(&zl, sizeof (zl), addr) == -1) { 2601 mdb_warn("failed to read zio_link_t at %p", addr); 2602 return (WALK_ERR); 2603 } 2604 2605 if (zpa->zpa_type == ZIO_WALK_PARENT) 2606 ziop = (uintptr_t)zl.zl_parent; 2607 else 2608 ziop = (uintptr_t)zl.zl_child; 2609 2610 return (zio_print_cb(ziop, zpa)); 2611 } 2612 2613 /* ARGSUSED */ 2614 static int 2615 zio_print(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 2616 { 2617 zio_print_args_t zpa = { 0 }; 2618 2619 if (!(flags & DCMD_ADDRSPEC)) 2620 return (DCMD_USAGE); 2621 2622 if (mdb_getopts(argc, argv, 2623 'r', MDB_OPT_SETBITS, INT_MAX, &zpa.zpa_max_depth, 2624 'c', MDB_OPT_SETBITS, ZIO_WALK_CHILD, &zpa.zpa_type, 2625 'p', MDB_OPT_SETBITS, ZIO_WALK_PARENT, &zpa.zpa_type, 2626 NULL) != argc) 2627 return (DCMD_USAGE); 2628 2629 zpa.zpa_flags = flags; 2630 if (zpa.zpa_max_depth != 0) { 2631 if (zpa.zpa_type == ZIO_WALK_SELF) 2632 zpa.zpa_type = ZIO_WALK_CHILD; 2633 } else if (zpa.zpa_type != ZIO_WALK_SELF) { 2634 zpa.zpa_min_depth = 1; 2635 zpa.zpa_max_depth = 1; 2636 } 2637 2638 if (!(flags & DCMD_PIPE_OUT) && DCMD_HDRSPEC(flags)) { 2639 mdb_printf("%<u>%-*s %-5s %-16s %-16s %-12s%</u>\n", 2640 ZIO_MAXWIDTH, "ADDRESS", "TYPE", "STAGE", "WAITER", 2641 "TIME_ELAPSED"); 2642 } 2643 2644 if (zio_print_cb(addr, &zpa) != WALK_NEXT) 2645 return (DCMD_ERR); 2646 2647 return (DCMD_OK); 2648 } 2649 2650 /* 2651 * [addr]::zio_state 2652 * 2653 * Print a summary of all zio_t structures on the system, or for a particular 2654 * pool. This is equivalent to '::walk zio_root | ::zio'. 2655 */ 2656 /*ARGSUSED*/ 2657 static int 2658 zio_state(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 2659 { 2660 /* 2661 * MDB will remember the last address of the pipeline, so if we don't 2662 * zero this we'll end up trying to walk zio structures for a 2663 * non-existent spa_t. 2664 */ 2665 if (!(flags & DCMD_ADDRSPEC)) 2666 addr = 0; 2667 2668 return (mdb_pwalk_dcmd("zio_root", "zio", argc, argv, addr)); 2669 } 2670 2671 2672 typedef struct mdb_zfs_btree_hdr { 2673 uintptr_t bth_parent; 2674 boolean_t bth_core; 2675 /* 2676 * For both leaf and core nodes, represents the number of elements in 2677 * the node. For core nodes, they will have bth_count + 1 children. 2678 */ 2679 uint32_t bth_count; 2680 } mdb_zfs_btree_hdr_t; 2681 2682 typedef struct mdb_zfs_btree_core { 2683 mdb_zfs_btree_hdr_t btc_hdr; 2684 uintptr_t btc_children[BTREE_CORE_ELEMS + 1]; 2685 uint8_t btc_elems[]; 2686 } mdb_zfs_btree_core_t; 2687 2688 typedef struct mdb_zfs_btree_leaf { 2689 mdb_zfs_btree_hdr_t btl_hdr; 2690 uint8_t btl_elems[]; 2691 } mdb_zfs_btree_leaf_t; 2692 2693 typedef struct mdb_zfs_btree { 2694 uintptr_t bt_root; 2695 size_t bt_elem_size; 2696 } mdb_zfs_btree_t; 2697 2698 typedef struct btree_walk_data { 2699 mdb_zfs_btree_t bwd_btree; 2700 mdb_zfs_btree_hdr_t *bwd_node; 2701 uint64_t bwd_offset; // In units of bt_node_size 2702 } btree_walk_data_t; 2703 2704 static uintptr_t 2705 btree_leftmost_child(uintptr_t addr, mdb_zfs_btree_hdr_t *buf) 2706 { 2707 size_t size = offsetof(zfs_btree_core_t, btc_children) + 2708 sizeof (uintptr_t); 2709 for (;;) { 2710 if (mdb_vread(buf, size, addr) == -1) { 2711 mdb_warn("failed to read at %p\n", addr); 2712 return ((uintptr_t)0ULL); 2713 } 2714 if (!buf->bth_core) 2715 return (addr); 2716 mdb_zfs_btree_core_t *node = (mdb_zfs_btree_core_t *)buf; 2717 addr = node->btc_children[0]; 2718 } 2719 } 2720 2721 static int 2722 btree_walk_step(mdb_walk_state_t *wsp) 2723 { 2724 btree_walk_data_t *bwd = wsp->walk_data; 2725 size_t elem_size = bwd->bwd_btree.bt_elem_size; 2726 if (wsp->walk_addr == 0ULL) 2727 return (WALK_DONE); 2728 2729 if (!bwd->bwd_node->bth_core) { 2730 /* 2731 * For the first element in a leaf node, read in the full 2732 * leaf, since we only had part of it read in before. 2733 */ 2734 if (bwd->bwd_offset == 0) { 2735 if (mdb_vread(bwd->bwd_node, BTREE_LEAF_SIZE, 2736 wsp->walk_addr) == -1) { 2737 mdb_warn("failed to read at %p\n", 2738 wsp->walk_addr); 2739 return (WALK_ERR); 2740 } 2741 } 2742 2743 int status = wsp->walk_callback((uintptr_t)(wsp->walk_addr + 2744 offsetof(mdb_zfs_btree_leaf_t, btl_elems) + 2745 bwd->bwd_offset * elem_size), bwd->bwd_node, 2746 wsp->walk_cbdata); 2747 if (status != WALK_NEXT) 2748 return (status); 2749 bwd->bwd_offset++; 2750 2751 /* Find the next element, if we're at the end of the leaf. */ 2752 while (bwd->bwd_offset == bwd->bwd_node->bth_count) { 2753 uintptr_t par = bwd->bwd_node->bth_parent; 2754 uintptr_t cur = wsp->walk_addr; 2755 wsp->walk_addr = par; 2756 if (par == 0ULL) 2757 return (WALK_NEXT); 2758 2759 size_t size = sizeof (zfs_btree_core_t) + 2760 BTREE_CORE_ELEMS * elem_size; 2761 if (mdb_vread(bwd->bwd_node, size, wsp->walk_addr) == 2762 -1) { 2763 mdb_warn("failed to read at %p\n", 2764 wsp->walk_addr); 2765 return (WALK_ERR); 2766 } 2767 mdb_zfs_btree_core_t *node = 2768 (mdb_zfs_btree_core_t *)bwd->bwd_node; 2769 int i; 2770 for (i = 0; i <= bwd->bwd_node->bth_count; i++) { 2771 if (node->btc_children[i] == cur) 2772 break; 2773 } 2774 if (i > bwd->bwd_node->bth_count) { 2775 mdb_warn("btree parent/child mismatch at " 2776 "%#lx\n", cur); 2777 return (WALK_ERR); 2778 } 2779 bwd->bwd_offset = i; 2780 } 2781 return (WALK_NEXT); 2782 } 2783 2784 if (!bwd->bwd_node->bth_core) { 2785 mdb_warn("Invalid btree node at %#lx\n", wsp->walk_addr); 2786 return (WALK_ERR); 2787 } 2788 mdb_zfs_btree_core_t *node = (mdb_zfs_btree_core_t *)bwd->bwd_node; 2789 int status = wsp->walk_callback((uintptr_t)(wsp->walk_addr + 2790 offsetof(mdb_zfs_btree_core_t, btc_elems) + bwd->bwd_offset * 2791 elem_size), bwd->bwd_node, wsp->walk_cbdata); 2792 if (status != WALK_NEXT) 2793 return (status); 2794 2795 uintptr_t new_child = node->btc_children[bwd->bwd_offset + 1]; 2796 wsp->walk_addr = btree_leftmost_child(new_child, bwd->bwd_node); 2797 if (wsp->walk_addr == 0ULL) 2798 return (WALK_ERR); 2799 2800 bwd->bwd_offset = 0; 2801 return (WALK_NEXT); 2802 } 2803 2804 static int 2805 btree_walk_init(mdb_walk_state_t *wsp) 2806 { 2807 btree_walk_data_t *bwd; 2808 2809 if (wsp->walk_addr == 0ULL) { 2810 mdb_warn("must supply address of zfs_btree_t\n"); 2811 return (WALK_ERR); 2812 } 2813 2814 bwd = mdb_zalloc(sizeof (btree_walk_data_t), UM_SLEEP); 2815 if (mdb_ctf_vread(&bwd->bwd_btree, "zfs_btree_t", "mdb_zfs_btree_t", 2816 wsp->walk_addr, 0) == -1) { 2817 mdb_free(bwd, sizeof (*bwd)); 2818 return (WALK_ERR); 2819 } 2820 2821 if (bwd->bwd_btree.bt_elem_size == 0) { 2822 mdb_warn("invalid or uninitialized btree at %#lx\n", 2823 wsp->walk_addr); 2824 mdb_free(bwd, sizeof (*bwd)); 2825 return (WALK_ERR); 2826 } 2827 2828 size_t size = MAX(BTREE_LEAF_SIZE, sizeof (zfs_btree_core_t) + 2829 BTREE_CORE_ELEMS * bwd->bwd_btree.bt_elem_size); 2830 bwd->bwd_node = mdb_zalloc(size, UM_SLEEP); 2831 2832 uintptr_t node = (uintptr_t)bwd->bwd_btree.bt_root; 2833 if (node == 0ULL) { 2834 wsp->walk_addr = 0ULL; 2835 wsp->walk_data = bwd; 2836 return (WALK_NEXT); 2837 } 2838 node = btree_leftmost_child(node, bwd->bwd_node); 2839 if (node == 0ULL) { 2840 mdb_free(bwd->bwd_node, size); 2841 mdb_free(bwd, sizeof (*bwd)); 2842 return (WALK_ERR); 2843 } 2844 bwd->bwd_offset = 0; 2845 2846 wsp->walk_addr = node; 2847 wsp->walk_data = bwd; 2848 return (WALK_NEXT); 2849 } 2850 2851 static void 2852 btree_walk_fini(mdb_walk_state_t *wsp) 2853 { 2854 btree_walk_data_t *bwd = (btree_walk_data_t *)wsp->walk_data; 2855 2856 if (bwd == NULL) 2857 return; 2858 2859 size_t size = MAX(BTREE_LEAF_SIZE, sizeof (zfs_btree_core_t) + 2860 BTREE_CORE_ELEMS * bwd->bwd_btree.bt_elem_size); 2861 if (bwd->bwd_node != NULL) 2862 mdb_free(bwd->bwd_node, size); 2863 2864 mdb_free(bwd, sizeof (*bwd)); 2865 } 2866 2867 typedef struct mdb_multilist { 2868 uint64_t ml_num_sublists; 2869 uintptr_t ml_sublists; 2870 } mdb_multilist_t; 2871 2872 typedef struct multilist_walk_data { 2873 uint64_t mwd_idx; 2874 mdb_multilist_t mwd_ml; 2875 } multilist_walk_data_t; 2876 2877 /* ARGSUSED */ 2878 static int 2879 multilist_print_cb(uintptr_t addr, const void *unknown, void *arg) 2880 { 2881 mdb_printf("%#lr\n", addr); 2882 return (WALK_NEXT); 2883 } 2884 2885 static int 2886 multilist_walk_step(mdb_walk_state_t *wsp) 2887 { 2888 multilist_walk_data_t *mwd = wsp->walk_data; 2889 2890 if (mwd->mwd_idx >= mwd->mwd_ml.ml_num_sublists) 2891 return (WALK_DONE); 2892 2893 wsp->walk_addr = mwd->mwd_ml.ml_sublists + 2894 mdb_ctf_sizeof_by_name("multilist_sublist_t") * mwd->mwd_idx + 2895 mdb_ctf_offsetof_by_name("multilist_sublist_t", "mls_list"); 2896 2897 mdb_pwalk("list", multilist_print_cb, (void*)NULL, wsp->walk_addr); 2898 mwd->mwd_idx++; 2899 2900 return (WALK_NEXT); 2901 } 2902 2903 static int 2904 multilist_walk_init(mdb_walk_state_t *wsp) 2905 { 2906 multilist_walk_data_t *mwd; 2907 2908 if (wsp->walk_addr == 0) { 2909 mdb_warn("must supply address of multilist_t\n"); 2910 return (WALK_ERR); 2911 } 2912 2913 mwd = mdb_zalloc(sizeof (multilist_walk_data_t), UM_SLEEP | UM_GC); 2914 if (mdb_ctf_vread(&mwd->mwd_ml, "multilist_t", "mdb_multilist_t", 2915 wsp->walk_addr, 0) == -1) { 2916 return (WALK_ERR); 2917 } 2918 2919 if (mwd->mwd_ml.ml_num_sublists == 0 || 2920 mwd->mwd_ml.ml_sublists == 0) { 2921 mdb_warn("invalid or uninitialized multilist at %#lx\n", 2922 wsp->walk_addr); 2923 return (WALK_ERR); 2924 } 2925 2926 wsp->walk_data = mwd; 2927 return (WALK_NEXT); 2928 } 2929 2930 typedef struct mdb_txg_list { 2931 size_t tl_offset; 2932 uintptr_t tl_head[TXG_SIZE]; 2933 } mdb_txg_list_t; 2934 2935 typedef struct txg_list_walk_data { 2936 uintptr_t lw_head[TXG_SIZE]; 2937 int lw_txgoff; 2938 int lw_maxoff; 2939 size_t lw_offset; 2940 void *lw_obj; 2941 } txg_list_walk_data_t; 2942 2943 static int 2944 txg_list_walk_init_common(mdb_walk_state_t *wsp, int txg, int maxoff) 2945 { 2946 txg_list_walk_data_t *lwd; 2947 mdb_txg_list_t list; 2948 int i; 2949 2950 lwd = mdb_alloc(sizeof (txg_list_walk_data_t), UM_SLEEP | UM_GC); 2951 if (mdb_ctf_vread(&list, "txg_list_t", "mdb_txg_list_t", wsp->walk_addr, 2952 0) == -1) { 2953 mdb_warn("failed to read txg_list_t at %#lx", wsp->walk_addr); 2954 return (WALK_ERR); 2955 } 2956 2957 for (i = 0; i < TXG_SIZE; i++) 2958 lwd->lw_head[i] = list.tl_head[i]; 2959 lwd->lw_offset = list.tl_offset; 2960 lwd->lw_obj = mdb_alloc(lwd->lw_offset + sizeof (txg_node_t), 2961 UM_SLEEP | UM_GC); 2962 lwd->lw_txgoff = txg; 2963 lwd->lw_maxoff = maxoff; 2964 2965 wsp->walk_addr = lwd->lw_head[lwd->lw_txgoff]; 2966 wsp->walk_data = lwd; 2967 2968 return (WALK_NEXT); 2969 } 2970 2971 static int 2972 txg_list_walk_init(mdb_walk_state_t *wsp) 2973 { 2974 return (txg_list_walk_init_common(wsp, 0, TXG_SIZE-1)); 2975 } 2976 2977 static int 2978 txg_list0_walk_init(mdb_walk_state_t *wsp) 2979 { 2980 return (txg_list_walk_init_common(wsp, 0, 0)); 2981 } 2982 2983 static int 2984 txg_list1_walk_init(mdb_walk_state_t *wsp) 2985 { 2986 return (txg_list_walk_init_common(wsp, 1, 1)); 2987 } 2988 2989 static int 2990 txg_list2_walk_init(mdb_walk_state_t *wsp) 2991 { 2992 return (txg_list_walk_init_common(wsp, 2, 2)); 2993 } 2994 2995 static int 2996 txg_list3_walk_init(mdb_walk_state_t *wsp) 2997 { 2998 return (txg_list_walk_init_common(wsp, 3, 3)); 2999 } 3000 3001 static int 3002 txg_list_walk_step(mdb_walk_state_t *wsp) 3003 { 3004 txg_list_walk_data_t *lwd = wsp->walk_data; 3005 uintptr_t addr; 3006 txg_node_t *node; 3007 int status; 3008 3009 while (wsp->walk_addr == 0 && lwd->lw_txgoff < lwd->lw_maxoff) { 3010 lwd->lw_txgoff++; 3011 wsp->walk_addr = lwd->lw_head[lwd->lw_txgoff]; 3012 } 3013 3014 if (wsp->walk_addr == 0) 3015 return (WALK_DONE); 3016 3017 addr = wsp->walk_addr - lwd->lw_offset; 3018 3019 if (mdb_vread(lwd->lw_obj, 3020 lwd->lw_offset + sizeof (txg_node_t), addr) == -1) { 3021 mdb_warn("failed to read list element at %#lx", addr); 3022 return (WALK_ERR); 3023 } 3024 3025 status = wsp->walk_callback(addr, lwd->lw_obj, wsp->walk_cbdata); 3026 node = (txg_node_t *)((uintptr_t)lwd->lw_obj + lwd->lw_offset); 3027 wsp->walk_addr = (uintptr_t)node->tn_next[lwd->lw_txgoff]; 3028 3029 return (status); 3030 } 3031 3032 /* 3033 * ::walk spa 3034 * 3035 * Walk all named spa_t structures in the namespace. This is nothing more than 3036 * a layered avl walk. 3037 */ 3038 static int 3039 spa_walk_init(mdb_walk_state_t *wsp) 3040 { 3041 GElf_Sym sym; 3042 3043 if (wsp->walk_addr != 0) { 3044 mdb_warn("spa walk only supports global walks\n"); 3045 return (WALK_ERR); 3046 } 3047 3048 if (mdb_lookup_by_obj(ZFS_OBJ_NAME, "spa_namespace_avl", &sym) == -1) { 3049 mdb_warn("failed to find symbol 'spa_namespace_avl'"); 3050 return (WALK_ERR); 3051 } 3052 3053 wsp->walk_addr = (uintptr_t)sym.st_value; 3054 3055 if (mdb_layered_walk("avl", wsp) == -1) { 3056 mdb_warn("failed to walk 'avl'\n"); 3057 return (WALK_ERR); 3058 } 3059 3060 return (WALK_NEXT); 3061 } 3062 3063 static int 3064 spa_walk_step(mdb_walk_state_t *wsp) 3065 { 3066 return (wsp->walk_callback(wsp->walk_addr, NULL, wsp->walk_cbdata)); 3067 } 3068 3069 /* 3070 * [addr]::walk zio 3071 * 3072 * Walk all active zio_t structures on the system. This is simply a layered 3073 * walk on top of ::walk zio_cache, with the optional ability to limit the 3074 * structures to a particular pool. 3075 */ 3076 static int 3077 zio_walk_init(mdb_walk_state_t *wsp) 3078 { 3079 wsp->walk_data = (void *)wsp->walk_addr; 3080 3081 if (mdb_layered_walk("zio_cache", wsp) == -1) { 3082 mdb_warn("failed to walk 'zio_cache'\n"); 3083 return (WALK_ERR); 3084 } 3085 3086 return (WALK_NEXT); 3087 } 3088 3089 static int 3090 zio_walk_step(mdb_walk_state_t *wsp) 3091 { 3092 mdb_zio_t zio; 3093 uintptr_t spa = (uintptr_t)wsp->walk_data; 3094 3095 if (mdb_ctf_vread(&zio, ZFS_STRUCT "zio", "mdb_zio_t", 3096 wsp->walk_addr, 0) == -1) 3097 return (WALK_ERR); 3098 3099 if (spa != 0 && spa != zio.io_spa) 3100 return (WALK_NEXT); 3101 3102 return (wsp->walk_callback(wsp->walk_addr, &zio, wsp->walk_cbdata)); 3103 } 3104 3105 /* 3106 * [addr]::walk zio_root 3107 * 3108 * Walk only root zio_t structures, optionally for a particular spa_t. 3109 */ 3110 static int 3111 zio_walk_root_step(mdb_walk_state_t *wsp) 3112 { 3113 mdb_zio_t zio; 3114 uintptr_t spa = (uintptr_t)wsp->walk_data; 3115 3116 if (mdb_ctf_vread(&zio, ZFS_STRUCT "zio", "mdb_zio_t", 3117 wsp->walk_addr, 0) == -1) 3118 return (WALK_ERR); 3119 3120 if (spa != 0 && spa != zio.io_spa) 3121 return (WALK_NEXT); 3122 3123 /* If the parent list is not empty, ignore */ 3124 if (zio.io_parent_list.list_head.list_next != 3125 wsp->walk_addr + 3126 mdb_ctf_offsetof_by_name(ZFS_STRUCT "zio", "io_parent_list") + 3127 mdb_ctf_offsetof_by_name("struct list", "list_head")) 3128 return (WALK_NEXT); 3129 3130 return (wsp->walk_callback(wsp->walk_addr, &zio, wsp->walk_cbdata)); 3131 } 3132 3133 /* 3134 * ::zfs_blkstats 3135 * 3136 * -v print verbose per-level information 3137 * 3138 */ 3139 static int 3140 zfs_blkstats(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 3141 { 3142 boolean_t verbose = B_FALSE; 3143 zfs_all_blkstats_t stats; 3144 dmu_object_type_t t; 3145 zfs_blkstat_t *tzb; 3146 uint64_t ditto; 3147 3148 if (mdb_getopts(argc, argv, 3149 'v', MDB_OPT_SETBITS, TRUE, &verbose, 3150 NULL) != argc) 3151 return (DCMD_USAGE); 3152 3153 if (!(flags & DCMD_ADDRSPEC)) 3154 return (DCMD_USAGE); 3155 3156 if (GETMEMB(addr, "spa", spa_dsl_pool, addr) || 3157 GETMEMB(addr, "dsl_pool", dp_blkstats, addr) || 3158 mdb_vread(&stats, sizeof (zfs_all_blkstats_t), addr) == -1) { 3159 mdb_warn("failed to read data at %p;", addr); 3160 mdb_printf("maybe no stats? run \"zpool scrub\" first."); 3161 return (DCMD_ERR); 3162 } 3163 3164 tzb = &stats.zab_type[DN_MAX_LEVELS][DMU_OT_TOTAL]; 3165 if (tzb->zb_gangs != 0) { 3166 mdb_printf("Ganged blocks: %llu\n", 3167 (longlong_t)tzb->zb_gangs); 3168 } 3169 3170 ditto = tzb->zb_ditto_2_of_2_samevdev + tzb->zb_ditto_2_of_3_samevdev + 3171 tzb->zb_ditto_3_of_3_samevdev; 3172 if (ditto != 0) { 3173 mdb_printf("Dittoed blocks on same vdev: %llu\n", 3174 (longlong_t)ditto); 3175 } 3176 3177 mdb_printf("\nBlocks\tLSIZE\tPSIZE\tASIZE" 3178 "\t avg\t comp\t%%Total\tType\n"); 3179 3180 for (t = 0; t <= DMU_OT_TOTAL; t++) { 3181 char csize[MDB_NICENUM_BUFLEN], lsize[MDB_NICENUM_BUFLEN]; 3182 char psize[MDB_NICENUM_BUFLEN], asize[MDB_NICENUM_BUFLEN]; 3183 char avg[MDB_NICENUM_BUFLEN]; 3184 char comp[MDB_NICENUM_BUFLEN], pct[MDB_NICENUM_BUFLEN]; 3185 char typename[64]; 3186 int l; 3187 3188 3189 if (t == DMU_OT_DEFERRED) 3190 strcpy(typename, "deferred free"); 3191 else if (t == DMU_OT_OTHER) 3192 strcpy(typename, "other"); 3193 else if (t == DMU_OT_TOTAL) 3194 strcpy(typename, "Total"); 3195 else if (enum_lookup("enum dmu_object_type", 3196 t, "DMU_OT_", sizeof (typename), typename) == -1) { 3197 mdb_warn("failed to read type name"); 3198 return (DCMD_ERR); 3199 } 3200 3201 if (stats.zab_type[DN_MAX_LEVELS][t].zb_asize == 0) 3202 continue; 3203 3204 for (l = -1; l < DN_MAX_LEVELS; l++) { 3205 int level = (l == -1 ? DN_MAX_LEVELS : l); 3206 zfs_blkstat_t *zb = &stats.zab_type[level][t]; 3207 3208 if (zb->zb_asize == 0) 3209 continue; 3210 3211 /* 3212 * Don't print each level unless requested. 3213 */ 3214 if (!verbose && level != DN_MAX_LEVELS) 3215 continue; 3216 3217 /* 3218 * If all the space is level 0, don't print the 3219 * level 0 separately. 3220 */ 3221 if (level == 0 && zb->zb_asize == 3222 stats.zab_type[DN_MAX_LEVELS][t].zb_asize) 3223 continue; 3224 3225 mdb_nicenum(zb->zb_count, csize); 3226 mdb_nicenum(zb->zb_lsize, lsize); 3227 mdb_nicenum(zb->zb_psize, psize); 3228 mdb_nicenum(zb->zb_asize, asize); 3229 mdb_nicenum(zb->zb_asize / zb->zb_count, avg); 3230 (void) mdb_snprintfrac(comp, MDB_NICENUM_BUFLEN, 3231 zb->zb_lsize, zb->zb_psize, 2); 3232 (void) mdb_snprintfrac(pct, MDB_NICENUM_BUFLEN, 3233 100 * zb->zb_asize, tzb->zb_asize, 2); 3234 3235 mdb_printf("%6s\t%5s\t%5s\t%5s\t%5s" 3236 "\t%5s\t%6s\t", 3237 csize, lsize, psize, asize, avg, comp, pct); 3238 3239 if (level == DN_MAX_LEVELS) 3240 mdb_printf("%s\n", typename); 3241 else 3242 mdb_printf(" L%d %s\n", 3243 level, typename); 3244 } 3245 } 3246 3247 return (DCMD_OK); 3248 } 3249 3250 typedef struct mdb_reference { 3251 uintptr_t ref_holder; 3252 uintptr_t ref_removed; 3253 uint64_t ref_number; 3254 } mdb_reference_t; 3255 3256 /* ARGSUSED */ 3257 static int 3258 reference_cb(uintptr_t addr, const void *ignored, void *arg) 3259 { 3260 mdb_reference_t ref; 3261 boolean_t holder_is_str = B_FALSE; 3262 char holder_str[128]; 3263 boolean_t removed = (boolean_t)arg; 3264 3265 if (mdb_ctf_vread(&ref, "reference_t", "mdb_reference_t", addr, 3266 0) == -1) 3267 return (DCMD_ERR); 3268 3269 if (mdb_readstr(holder_str, sizeof (holder_str), 3270 ref.ref_holder) != -1) 3271 holder_is_str = strisprint(holder_str); 3272 3273 if (removed) 3274 mdb_printf("removed "); 3275 mdb_printf("reference "); 3276 if (ref.ref_number != 1) 3277 mdb_printf("with count=%llu ", ref.ref_number); 3278 mdb_printf("with tag %lx", ref.ref_holder); 3279 if (holder_is_str) 3280 mdb_printf(" \"%s\"", holder_str); 3281 mdb_printf(", held at:\n"); 3282 3283 (void) mdb_call_dcmd("whatis", addr, DCMD_ADDRSPEC, 0, NULL); 3284 3285 if (removed) { 3286 mdb_printf("removed at:\n"); 3287 (void) mdb_call_dcmd("whatis", ref.ref_removed, 3288 DCMD_ADDRSPEC, 0, NULL); 3289 } 3290 3291 mdb_printf("\n"); 3292 3293 return (WALK_NEXT); 3294 } 3295 3296 typedef struct mdb_zfs_refcount { 3297 uint64_t rc_count; 3298 } mdb_zfs_refcount_t; 3299 3300 typedef struct mdb_zfs_refcount_removed { 3301 uint64_t rc_removed_count; 3302 } mdb_zfs_refcount_removed_t; 3303 3304 typedef struct mdb_zfs_refcount_tracked { 3305 boolean_t rc_tracked; 3306 } mdb_zfs_refcount_tracked_t; 3307 3308 /* ARGSUSED */ 3309 static int 3310 zfs_refcount(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 3311 { 3312 mdb_zfs_refcount_t rc; 3313 mdb_zfs_refcount_removed_t rcr; 3314 mdb_zfs_refcount_tracked_t rct; 3315 int off; 3316 boolean_t released = B_FALSE; 3317 3318 if (!(flags & DCMD_ADDRSPEC)) 3319 return (DCMD_USAGE); 3320 3321 if (mdb_getopts(argc, argv, 3322 'r', MDB_OPT_SETBITS, B_TRUE, &released, 3323 NULL) != argc) 3324 return (DCMD_USAGE); 3325 3326 if (mdb_ctf_vread(&rc, "zfs_refcount_t", "mdb_zfs_refcount_t", addr, 3327 0) == -1) 3328 return (DCMD_ERR); 3329 3330 if (mdb_ctf_vread(&rcr, "zfs_refcount_t", "mdb_zfs_refcount_removed_t", 3331 addr, MDB_CTF_VREAD_QUIET) == -1) { 3332 mdb_printf("zfs_refcount_t at %p has %llu holds (untracked)\n", 3333 addr, (longlong_t)rc.rc_count); 3334 return (DCMD_OK); 3335 } 3336 3337 if (mdb_ctf_vread(&rct, "zfs_refcount_t", "mdb_zfs_refcount_tracked_t", 3338 addr, MDB_CTF_VREAD_QUIET) == -1) { 3339 /* If this is an old target, it might be tracked. */ 3340 rct.rc_tracked = B_TRUE; 3341 } 3342 3343 mdb_printf("zfs_refcount_t at %p has %llu current holds, " 3344 "%llu recently released holds\n", 3345 addr, (longlong_t)rc.rc_count, (longlong_t)rcr.rc_removed_count); 3346 3347 if (rct.rc_tracked && rc.rc_count > 0) 3348 mdb_printf("current holds:\n"); 3349 off = mdb_ctf_offsetof_by_name("zfs_refcount_t", "rc_list"); 3350 if (off == -1) 3351 return (DCMD_ERR); 3352 mdb_pwalk("list", reference_cb, (void*)B_FALSE, addr + off); 3353 3354 if (released && rcr.rc_removed_count > 0) { 3355 mdb_printf("released holds:\n"); 3356 3357 off = mdb_ctf_offsetof_by_name("zfs_refcount_t", "rc_removed"); 3358 if (off == -1) 3359 return (DCMD_ERR); 3360 mdb_pwalk("list", reference_cb, (void*)B_TRUE, addr + off); 3361 } 3362 3363 return (DCMD_OK); 3364 } 3365 3366 /* ARGSUSED */ 3367 static int 3368 sa_attr_table(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 3369 { 3370 sa_attr_table_t *table; 3371 sa_os_t sa_os; 3372 char *name; 3373 int i; 3374 3375 if (mdb_vread(&sa_os, sizeof (sa_os_t), addr) == -1) { 3376 mdb_warn("failed to read sa_os at %p", addr); 3377 return (DCMD_ERR); 3378 } 3379 3380 table = mdb_alloc(sizeof (sa_attr_table_t) * sa_os.sa_num_attrs, 3381 UM_SLEEP | UM_GC); 3382 name = mdb_alloc(MAXPATHLEN, UM_SLEEP | UM_GC); 3383 3384 if (mdb_vread(table, sizeof (sa_attr_table_t) * sa_os.sa_num_attrs, 3385 (uintptr_t)sa_os.sa_attr_table) == -1) { 3386 mdb_warn("failed to read sa_os at %p", addr); 3387 return (DCMD_ERR); 3388 } 3389 3390 mdb_printf("%<u>%-10s %-10s %-10s %-10s %s%</u>\n", 3391 "ATTR ID", "REGISTERED", "LENGTH", "BSWAP", "NAME"); 3392 for (i = 0; i != sa_os.sa_num_attrs; i++) { 3393 mdb_readstr(name, MAXPATHLEN, (uintptr_t)table[i].sa_name); 3394 mdb_printf("%5x %8x %8x %8x %-s\n", 3395 (int)table[i].sa_attr, (int)table[i].sa_registered, 3396 (int)table[i].sa_length, table[i].sa_byteswap, name); 3397 } 3398 3399 return (DCMD_OK); 3400 } 3401 3402 static int 3403 sa_get_off_table(uintptr_t addr, uint32_t **off_tab, int attr_count) 3404 { 3405 uintptr_t idx_table; 3406 3407 if (GETMEMB(addr, "sa_idx_tab", sa_idx_tab, idx_table)) { 3408 mdb_printf("can't find offset table in sa_idx_tab\n"); 3409 return (-1); 3410 } 3411 3412 *off_tab = mdb_alloc(attr_count * sizeof (uint32_t), 3413 UM_SLEEP | UM_GC); 3414 3415 if (mdb_vread(*off_tab, 3416 attr_count * sizeof (uint32_t), idx_table) == -1) { 3417 mdb_warn("failed to attribute offset table %p", idx_table); 3418 return (-1); 3419 } 3420 3421 return (DCMD_OK); 3422 } 3423 3424 /*ARGSUSED*/ 3425 static int 3426 sa_attr_print(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 3427 { 3428 uint32_t *offset_tab; 3429 int attr_count; 3430 uint64_t attr_id; 3431 uintptr_t attr_addr; 3432 uintptr_t bonus_tab, spill_tab; 3433 uintptr_t db_bonus, db_spill; 3434 uintptr_t os, os_sa; 3435 uintptr_t db_data; 3436 3437 if (argc != 1) 3438 return (DCMD_USAGE); 3439 3440 if (argv[0].a_type == MDB_TYPE_STRING) 3441 attr_id = mdb_strtoull(argv[0].a_un.a_str); 3442 else 3443 return (DCMD_USAGE); 3444 3445 if (GETMEMB(addr, "sa_handle", sa_bonus_tab, bonus_tab) || 3446 GETMEMB(addr, "sa_handle", sa_spill_tab, spill_tab) || 3447 GETMEMB(addr, "sa_handle", sa_os, os) || 3448 GETMEMB(addr, "sa_handle", sa_bonus, db_bonus) || 3449 GETMEMB(addr, "sa_handle", sa_spill, db_spill)) { 3450 mdb_printf("Can't find necessary information in sa_handle " 3451 "in sa_handle\n"); 3452 return (DCMD_ERR); 3453 } 3454 3455 if (GETMEMB(os, "objset", os_sa, os_sa)) { 3456 mdb_printf("Can't find os_sa in objset\n"); 3457 return (DCMD_ERR); 3458 } 3459 3460 if (GETMEMB(os_sa, "sa_os", sa_num_attrs, attr_count)) { 3461 mdb_printf("Can't find sa_num_attrs\n"); 3462 return (DCMD_ERR); 3463 } 3464 3465 if (attr_id > attr_count) { 3466 mdb_printf("attribute id number is out of range\n"); 3467 return (DCMD_ERR); 3468 } 3469 3470 if (bonus_tab) { 3471 if (sa_get_off_table(bonus_tab, &offset_tab, 3472 attr_count) == -1) { 3473 return (DCMD_ERR); 3474 } 3475 3476 if (GETMEMB(db_bonus, "dmu_buf", db_data, db_data)) { 3477 mdb_printf("can't find db_data in bonus dbuf\n"); 3478 return (DCMD_ERR); 3479 } 3480 } 3481 3482 if (bonus_tab && !TOC_ATTR_PRESENT(offset_tab[attr_id]) && 3483 spill_tab == 0) { 3484 mdb_printf("Attribute does not exist\n"); 3485 return (DCMD_ERR); 3486 } else if (!TOC_ATTR_PRESENT(offset_tab[attr_id]) && spill_tab) { 3487 if (sa_get_off_table(spill_tab, &offset_tab, 3488 attr_count) == -1) { 3489 return (DCMD_ERR); 3490 } 3491 if (GETMEMB(db_spill, "dmu_buf", db_data, db_data)) { 3492 mdb_printf("can't find db_data in spill dbuf\n"); 3493 return (DCMD_ERR); 3494 } 3495 if (!TOC_ATTR_PRESENT(offset_tab[attr_id])) { 3496 mdb_printf("Attribute does not exist\n"); 3497 return (DCMD_ERR); 3498 } 3499 } 3500 attr_addr = db_data + TOC_OFF(offset_tab[attr_id]); 3501 mdb_printf("%p\n", attr_addr); 3502 return (DCMD_OK); 3503 } 3504 3505 /* ARGSUSED */ 3506 static int 3507 zfs_ace_print_common(uintptr_t addr, uint_t flags, 3508 uint64_t id, uint32_t access_mask, uint16_t ace_flags, 3509 uint16_t ace_type, int verbose) 3510 { 3511 if (DCMD_HDRSPEC(flags) && !verbose) 3512 mdb_printf("%<u>%-?s %-8s %-8s %-8s %s%</u>\n", 3513 "ADDR", "FLAGS", "MASK", "TYPE", "ID"); 3514 3515 if (!verbose) { 3516 mdb_printf("%0?p %-8x %-8x %-8x %-llx\n", addr, 3517 ace_flags, access_mask, ace_type, id); 3518 return (DCMD_OK); 3519 } 3520 3521 switch (ace_flags & ACE_TYPE_FLAGS) { 3522 case ACE_OWNER: 3523 mdb_printf("owner@:"); 3524 break; 3525 case (ACE_IDENTIFIER_GROUP | ACE_GROUP): 3526 mdb_printf("group@:"); 3527 break; 3528 case ACE_EVERYONE: 3529 mdb_printf("everyone@:"); 3530 break; 3531 case ACE_IDENTIFIER_GROUP: 3532 mdb_printf("group:%llx:", (u_longlong_t)id); 3533 break; 3534 case 0: /* User entry */ 3535 mdb_printf("user:%llx:", (u_longlong_t)id); 3536 break; 3537 } 3538 3539 /* print out permission mask */ 3540 if (access_mask & ACE_READ_DATA) 3541 mdb_printf("r"); 3542 else 3543 mdb_printf("-"); 3544 if (access_mask & ACE_WRITE_DATA) 3545 mdb_printf("w"); 3546 else 3547 mdb_printf("-"); 3548 if (access_mask & ACE_EXECUTE) 3549 mdb_printf("x"); 3550 else 3551 mdb_printf("-"); 3552 if (access_mask & ACE_APPEND_DATA) 3553 mdb_printf("p"); 3554 else 3555 mdb_printf("-"); 3556 if (access_mask & ACE_DELETE) 3557 mdb_printf("d"); 3558 else 3559 mdb_printf("-"); 3560 if (access_mask & ACE_DELETE_CHILD) 3561 mdb_printf("D"); 3562 else 3563 mdb_printf("-"); 3564 if (access_mask & ACE_READ_ATTRIBUTES) 3565 mdb_printf("a"); 3566 else 3567 mdb_printf("-"); 3568 if (access_mask & ACE_WRITE_ATTRIBUTES) 3569 mdb_printf("A"); 3570 else 3571 mdb_printf("-"); 3572 if (access_mask & ACE_READ_NAMED_ATTRS) 3573 mdb_printf("R"); 3574 else 3575 mdb_printf("-"); 3576 if (access_mask & ACE_WRITE_NAMED_ATTRS) 3577 mdb_printf("W"); 3578 else 3579 mdb_printf("-"); 3580 if (access_mask & ACE_READ_ACL) 3581 mdb_printf("c"); 3582 else 3583 mdb_printf("-"); 3584 if (access_mask & ACE_WRITE_ACL) 3585 mdb_printf("C"); 3586 else 3587 mdb_printf("-"); 3588 if (access_mask & ACE_WRITE_OWNER) 3589 mdb_printf("o"); 3590 else 3591 mdb_printf("-"); 3592 if (access_mask & ACE_SYNCHRONIZE) 3593 mdb_printf("s"); 3594 else 3595 mdb_printf("-"); 3596 3597 mdb_printf(":"); 3598 3599 /* Print out inheritance flags */ 3600 if (ace_flags & ACE_FILE_INHERIT_ACE) 3601 mdb_printf("f"); 3602 else 3603 mdb_printf("-"); 3604 if (ace_flags & ACE_DIRECTORY_INHERIT_ACE) 3605 mdb_printf("d"); 3606 else 3607 mdb_printf("-"); 3608 if (ace_flags & ACE_INHERIT_ONLY_ACE) 3609 mdb_printf("i"); 3610 else 3611 mdb_printf("-"); 3612 if (ace_flags & ACE_NO_PROPAGATE_INHERIT_ACE) 3613 mdb_printf("n"); 3614 else 3615 mdb_printf("-"); 3616 if (ace_flags & ACE_SUCCESSFUL_ACCESS_ACE_FLAG) 3617 mdb_printf("S"); 3618 else 3619 mdb_printf("-"); 3620 if (ace_flags & ACE_FAILED_ACCESS_ACE_FLAG) 3621 mdb_printf("F"); 3622 else 3623 mdb_printf("-"); 3624 if (ace_flags & ACE_INHERITED_ACE) 3625 mdb_printf("I"); 3626 else 3627 mdb_printf("-"); 3628 3629 switch (ace_type) { 3630 case ACE_ACCESS_ALLOWED_ACE_TYPE: 3631 mdb_printf(":allow\n"); 3632 break; 3633 case ACE_ACCESS_DENIED_ACE_TYPE: 3634 mdb_printf(":deny\n"); 3635 break; 3636 case ACE_SYSTEM_AUDIT_ACE_TYPE: 3637 mdb_printf(":audit\n"); 3638 break; 3639 case ACE_SYSTEM_ALARM_ACE_TYPE: 3640 mdb_printf(":alarm\n"); 3641 break; 3642 default: 3643 mdb_printf(":?\n"); 3644 } 3645 return (DCMD_OK); 3646 } 3647 3648 /* ARGSUSED */ 3649 static int 3650 zfs_ace_print(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 3651 { 3652 zfs_ace_t zace; 3653 int verbose = FALSE; 3654 uint64_t id; 3655 3656 if (!(flags & DCMD_ADDRSPEC)) 3657 return (DCMD_USAGE); 3658 3659 if (mdb_getopts(argc, argv, 3660 'v', MDB_OPT_SETBITS, TRUE, &verbose, TRUE, NULL) != argc) 3661 return (DCMD_USAGE); 3662 3663 if (mdb_vread(&zace, sizeof (zfs_ace_t), addr) == -1) { 3664 mdb_warn("failed to read zfs_ace_t"); 3665 return (DCMD_ERR); 3666 } 3667 3668 if ((zace.z_hdr.z_flags & ACE_TYPE_FLAGS) == 0 || 3669 (zace.z_hdr.z_flags & ACE_TYPE_FLAGS) == ACE_IDENTIFIER_GROUP) 3670 id = zace.z_fuid; 3671 else 3672 id = -1; 3673 3674 return (zfs_ace_print_common(addr, flags, id, zace.z_hdr.z_access_mask, 3675 zace.z_hdr.z_flags, zace.z_hdr.z_type, verbose)); 3676 } 3677 3678 /* ARGSUSED */ 3679 static int 3680 zfs_ace0_print(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 3681 { 3682 ace_t ace; 3683 uint64_t id; 3684 int verbose = FALSE; 3685 3686 if (!(flags & DCMD_ADDRSPEC)) 3687 return (DCMD_USAGE); 3688 3689 if (mdb_getopts(argc, argv, 3690 'v', MDB_OPT_SETBITS, TRUE, &verbose, TRUE, NULL) != argc) 3691 return (DCMD_USAGE); 3692 3693 if (mdb_vread(&ace, sizeof (ace_t), addr) == -1) { 3694 mdb_warn("failed to read ace_t"); 3695 return (DCMD_ERR); 3696 } 3697 3698 if ((ace.a_flags & ACE_TYPE_FLAGS) == 0 || 3699 (ace.a_flags & ACE_TYPE_FLAGS) == ACE_IDENTIFIER_GROUP) 3700 id = ace.a_who; 3701 else 3702 id = -1; 3703 3704 return (zfs_ace_print_common(addr, flags, id, ace.a_access_mask, 3705 ace.a_flags, ace.a_type, verbose)); 3706 } 3707 3708 typedef struct acl_dump_args { 3709 int a_argc; 3710 const mdb_arg_t *a_argv; 3711 uint16_t a_version; 3712 int a_flags; 3713 } acl_dump_args_t; 3714 3715 /* ARGSUSED */ 3716 static int 3717 acl_aces_cb(uintptr_t addr, const void *unknown, void *arg) 3718 { 3719 acl_dump_args_t *acl_args = (acl_dump_args_t *)arg; 3720 3721 if (acl_args->a_version == 1) { 3722 if (mdb_call_dcmd("zfs_ace", addr, 3723 DCMD_ADDRSPEC|acl_args->a_flags, acl_args->a_argc, 3724 acl_args->a_argv) != DCMD_OK) { 3725 return (WALK_ERR); 3726 } 3727 } else { 3728 if (mdb_call_dcmd("zfs_ace0", addr, 3729 DCMD_ADDRSPEC|acl_args->a_flags, acl_args->a_argc, 3730 acl_args->a_argv) != DCMD_OK) { 3731 return (WALK_ERR); 3732 } 3733 } 3734 acl_args->a_flags = DCMD_LOOP; 3735 return (WALK_NEXT); 3736 } 3737 3738 /* ARGSUSED */ 3739 static int 3740 acl_cb(uintptr_t addr, const void *unknown, void *arg) 3741 { 3742 acl_dump_args_t *acl_args = (acl_dump_args_t *)arg; 3743 3744 if (acl_args->a_version == 1) { 3745 if (mdb_pwalk("zfs_acl_node_aces", acl_aces_cb, 3746 arg, addr) != 0) { 3747 mdb_warn("can't walk ACEs"); 3748 return (DCMD_ERR); 3749 } 3750 } else { 3751 if (mdb_pwalk("zfs_acl_node_aces0", acl_aces_cb, 3752 arg, addr) != 0) { 3753 mdb_warn("can't walk ACEs"); 3754 return (DCMD_ERR); 3755 } 3756 } 3757 return (WALK_NEXT); 3758 } 3759 3760 /* ARGSUSED */ 3761 static int 3762 zfs_acl_dump(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 3763 { 3764 zfs_acl_t zacl; 3765 int verbose = FALSE; 3766 acl_dump_args_t acl_args; 3767 3768 if (!(flags & DCMD_ADDRSPEC)) 3769 return (DCMD_USAGE); 3770 3771 if (mdb_getopts(argc, argv, 3772 'v', MDB_OPT_SETBITS, TRUE, &verbose, NULL) != argc) 3773 return (DCMD_USAGE); 3774 3775 if (mdb_vread(&zacl, sizeof (zfs_acl_t), addr) == -1) { 3776 mdb_warn("failed to read zfs_acl_t"); 3777 return (DCMD_ERR); 3778 } 3779 3780 acl_args.a_argc = argc; 3781 acl_args.a_argv = argv; 3782 acl_args.a_version = zacl.z_version; 3783 acl_args.a_flags = DCMD_LOOPFIRST; 3784 3785 if (mdb_pwalk("zfs_acl_node", acl_cb, &acl_args, addr) != 0) { 3786 mdb_warn("can't walk ACL"); 3787 return (DCMD_ERR); 3788 } 3789 3790 return (DCMD_OK); 3791 } 3792 3793 /* ARGSUSED */ 3794 static int 3795 zfs_acl_node_walk_init(mdb_walk_state_t *wsp) 3796 { 3797 if (wsp->walk_addr == 0) { 3798 mdb_warn("must supply address of zfs_acl_node_t\n"); 3799 return (WALK_ERR); 3800 } 3801 3802 wsp->walk_addr += 3803 mdb_ctf_offsetof_by_name(ZFS_STRUCT "zfs_acl", "z_acl"); 3804 3805 if (mdb_layered_walk("list", wsp) == -1) { 3806 mdb_warn("failed to walk 'list'\n"); 3807 return (WALK_ERR); 3808 } 3809 3810 return (WALK_NEXT); 3811 } 3812 3813 static int 3814 zfs_acl_node_walk_step(mdb_walk_state_t *wsp) 3815 { 3816 zfs_acl_node_t aclnode; 3817 3818 if (mdb_vread(&aclnode, sizeof (zfs_acl_node_t), 3819 wsp->walk_addr) == -1) { 3820 mdb_warn("failed to read zfs_acl_node at %p", wsp->walk_addr); 3821 return (WALK_ERR); 3822 } 3823 3824 return (wsp->walk_callback(wsp->walk_addr, &aclnode, wsp->walk_cbdata)); 3825 } 3826 3827 typedef struct ace_walk_data { 3828 int ace_count; 3829 int ace_version; 3830 } ace_walk_data_t; 3831 3832 static int 3833 zfs_aces_walk_init_common(mdb_walk_state_t *wsp, int version, 3834 int ace_count, uintptr_t ace_data) 3835 { 3836 ace_walk_data_t *ace_walk_data; 3837 3838 if (wsp->walk_addr == 0) { 3839 mdb_warn("must supply address of zfs_acl_node_t\n"); 3840 return (WALK_ERR); 3841 } 3842 3843 ace_walk_data = mdb_alloc(sizeof (ace_walk_data_t), UM_SLEEP | UM_GC); 3844 3845 ace_walk_data->ace_count = ace_count; 3846 ace_walk_data->ace_version = version; 3847 3848 wsp->walk_addr = ace_data; 3849 wsp->walk_data = ace_walk_data; 3850 3851 return (WALK_NEXT); 3852 } 3853 3854 static int 3855 zfs_acl_node_aces_walk_init_common(mdb_walk_state_t *wsp, int version) 3856 { 3857 static int gotid; 3858 static mdb_ctf_id_t acl_id; 3859 int z_ace_count; 3860 uintptr_t z_acldata; 3861 3862 if (!gotid) { 3863 if (mdb_ctf_lookup_by_name("struct zfs_acl_node", 3864 &acl_id) == -1) { 3865 mdb_warn("couldn't find struct zfs_acl_node"); 3866 return (DCMD_ERR); 3867 } 3868 gotid = TRUE; 3869 } 3870 3871 if (GETMEMBID(wsp->walk_addr, &acl_id, z_ace_count, z_ace_count)) { 3872 return (DCMD_ERR); 3873 } 3874 if (GETMEMBID(wsp->walk_addr, &acl_id, z_acldata, z_acldata)) { 3875 return (DCMD_ERR); 3876 } 3877 3878 return (zfs_aces_walk_init_common(wsp, version, 3879 z_ace_count, z_acldata)); 3880 } 3881 3882 /* ARGSUSED */ 3883 static int 3884 zfs_acl_node_aces_walk_init(mdb_walk_state_t *wsp) 3885 { 3886 return (zfs_acl_node_aces_walk_init_common(wsp, 1)); 3887 } 3888 3889 /* ARGSUSED */ 3890 static int 3891 zfs_acl_node_aces0_walk_init(mdb_walk_state_t *wsp) 3892 { 3893 return (zfs_acl_node_aces_walk_init_common(wsp, 0)); 3894 } 3895 3896 static int 3897 zfs_aces_walk_step(mdb_walk_state_t *wsp) 3898 { 3899 ace_walk_data_t *ace_data = wsp->walk_data; 3900 zfs_ace_t zace; 3901 ace_t *acep; 3902 int status; 3903 int entry_type; 3904 int allow_type; 3905 uintptr_t ptr; 3906 3907 if (ace_data->ace_count == 0) 3908 return (WALK_DONE); 3909 3910 if (mdb_vread(&zace, sizeof (zfs_ace_t), wsp->walk_addr) == -1) { 3911 mdb_warn("failed to read zfs_ace_t at %#lx", 3912 wsp->walk_addr); 3913 return (WALK_ERR); 3914 } 3915 3916 switch (ace_data->ace_version) { 3917 case 0: 3918 acep = (ace_t *)&zace; 3919 entry_type = acep->a_flags & ACE_TYPE_FLAGS; 3920 allow_type = acep->a_type; 3921 break; 3922 case 1: 3923 entry_type = zace.z_hdr.z_flags & ACE_TYPE_FLAGS; 3924 allow_type = zace.z_hdr.z_type; 3925 break; 3926 default: 3927 return (WALK_ERR); 3928 } 3929 3930 ptr = (uintptr_t)wsp->walk_addr; 3931 switch (entry_type) { 3932 case ACE_OWNER: 3933 case ACE_EVERYONE: 3934 case (ACE_IDENTIFIER_GROUP | ACE_GROUP): 3935 ptr += ace_data->ace_version == 0 ? 3936 sizeof (ace_t) : sizeof (zfs_ace_hdr_t); 3937 break; 3938 case ACE_IDENTIFIER_GROUP: 3939 default: 3940 switch (allow_type) { 3941 case ACE_ACCESS_ALLOWED_OBJECT_ACE_TYPE: 3942 case ACE_ACCESS_DENIED_OBJECT_ACE_TYPE: 3943 case ACE_SYSTEM_AUDIT_OBJECT_ACE_TYPE: 3944 case ACE_SYSTEM_ALARM_OBJECT_ACE_TYPE: 3945 ptr += ace_data->ace_version == 0 ? 3946 sizeof (ace_t) : sizeof (zfs_object_ace_t); 3947 break; 3948 default: 3949 ptr += ace_data->ace_version == 0 ? 3950 sizeof (ace_t) : sizeof (zfs_ace_t); 3951 break; 3952 } 3953 } 3954 3955 ace_data->ace_count--; 3956 status = wsp->walk_callback(wsp->walk_addr, 3957 (void *)(uintptr_t)&zace, wsp->walk_cbdata); 3958 3959 wsp->walk_addr = ptr; 3960 return (status); 3961 } 3962 3963 typedef struct mdb_zfs_rrwlock { 3964 uintptr_t rr_writer; 3965 boolean_t rr_writer_wanted; 3966 } mdb_zfs_rrwlock_t; 3967 3968 static uint_t rrw_key; 3969 3970 /* ARGSUSED */ 3971 static int 3972 rrwlock(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 3973 { 3974 mdb_zfs_rrwlock_t rrw; 3975 3976 if (rrw_key == 0) { 3977 if (mdb_ctf_readsym(&rrw_key, "uint_t", "rrw_tsd_key", 0) == -1) 3978 return (DCMD_ERR); 3979 } 3980 3981 if (mdb_ctf_vread(&rrw, "rrwlock_t", "mdb_zfs_rrwlock_t", addr, 3982 0) == -1) 3983 return (DCMD_ERR); 3984 3985 if (rrw.rr_writer != 0) { 3986 mdb_printf("write lock held by thread %lx\n", rrw.rr_writer); 3987 return (DCMD_OK); 3988 } 3989 3990 if (rrw.rr_writer_wanted) { 3991 mdb_printf("writer wanted\n"); 3992 } 3993 3994 mdb_printf("anonymous references:\n"); 3995 (void) mdb_call_dcmd("zfs_refcount", addr + 3996 mdb_ctf_offsetof_by_name(ZFS_STRUCT "rrwlock", "rr_anon_rcount"), 3997 DCMD_ADDRSPEC, 0, NULL); 3998 3999 mdb_printf("linked references:\n"); 4000 (void) mdb_call_dcmd("zfs_refcount", addr + 4001 mdb_ctf_offsetof_by_name(ZFS_STRUCT "rrwlock", "rr_linked_rcount"), 4002 DCMD_ADDRSPEC, 0, NULL); 4003 4004 /* 4005 * XXX This should find references from 4006 * "::walk thread | ::tsd -v <rrw_key>", but there is no support 4007 * for programmatic consumption of dcmds, so this would be 4008 * difficult, potentially requiring reimplementing ::tsd (both 4009 * user and kernel versions) in this MDB module. 4010 */ 4011 4012 return (DCMD_OK); 4013 } 4014 4015 typedef struct mdb_arc_buf_hdr_t { 4016 uint16_t b_psize; 4017 uint16_t b_lsize; 4018 struct { 4019 uint32_t b_bufcnt; 4020 uintptr_t b_state; 4021 } b_l1hdr; 4022 } mdb_arc_buf_hdr_t; 4023 4024 enum arc_cflags { 4025 ARC_CFLAG_VERBOSE = 1 << 0, 4026 ARC_CFLAG_ANON = 1 << 1, 4027 ARC_CFLAG_MRU = 1 << 2, 4028 ARC_CFLAG_MFU = 1 << 3, 4029 ARC_CFLAG_BUFS = 1 << 4, 4030 }; 4031 4032 typedef struct arc_compression_stats_data { 4033 GElf_Sym anon_sym; /* ARC_anon symbol */ 4034 GElf_Sym mru_sym; /* ARC_mru symbol */ 4035 GElf_Sym mrug_sym; /* ARC_mru_ghost symbol */ 4036 GElf_Sym mfu_sym; /* ARC_mfu symbol */ 4037 GElf_Sym mfug_sym; /* ARC_mfu_ghost symbol */ 4038 GElf_Sym l2c_sym; /* ARC_l2c_only symbol */ 4039 uint64_t *anon_c_hist; /* histogram of compressed sizes in anon */ 4040 uint64_t *anon_u_hist; /* histogram of uncompressed sizes in anon */ 4041 uint64_t *anon_bufs; /* histogram of buffer counts in anon state */ 4042 uint64_t *mru_c_hist; /* histogram of compressed sizes in mru */ 4043 uint64_t *mru_u_hist; /* histogram of uncompressed sizes in mru */ 4044 uint64_t *mru_bufs; /* histogram of buffer counts in mru */ 4045 uint64_t *mfu_c_hist; /* histogram of compressed sizes in mfu */ 4046 uint64_t *mfu_u_hist; /* histogram of uncompressed sizes in mfu */ 4047 uint64_t *mfu_bufs; /* histogram of buffer counts in mfu */ 4048 uint64_t *all_c_hist; /* histogram of compressed anon + mru + mfu */ 4049 uint64_t *all_u_hist; /* histogram of uncompressed anon + mru + mfu */ 4050 uint64_t *all_bufs; /* histogram of buffer counts in all states */ 4051 int arc_cflags; /* arc compression flags, specified by user */ 4052 int hist_nbuckets; /* number of buckets in each histogram */ 4053 } arc_compression_stats_data_t; 4054 4055 int 4056 highbit64(uint64_t i) 4057 { 4058 int h = 1; 4059 4060 if (i == 0) 4061 return (0); 4062 if (i & 0xffffffff00000000ULL) { 4063 h += 32; i >>= 32; 4064 } 4065 if (i & 0xffff0000) { 4066 h += 16; i >>= 16; 4067 } 4068 if (i & 0xff00) { 4069 h += 8; i >>= 8; 4070 } 4071 if (i & 0xf0) { 4072 h += 4; i >>= 4; 4073 } 4074 if (i & 0xc) { 4075 h += 2; i >>= 2; 4076 } 4077 if (i & 0x2) { 4078 h += 1; 4079 } 4080 return (h); 4081 } 4082 4083 /* ARGSUSED */ 4084 static int 4085 arc_compression_stats_cb(uintptr_t addr, const void *unknown, void *arg) 4086 { 4087 arc_compression_stats_data_t *data = arg; 4088 mdb_arc_buf_hdr_t hdr; 4089 int cbucket, ubucket, bufcnt; 4090 4091 if (mdb_ctf_vread(&hdr, "arc_buf_hdr_t", "mdb_arc_buf_hdr_t", 4092 addr, 0) == -1) { 4093 return (WALK_ERR); 4094 } 4095 4096 /* 4097 * Headers in the ghost states, or the l2c_only state don't have 4098 * arc buffers linked off of them. Thus, their compressed size 4099 * is meaningless, so we skip these from the stats. 4100 */ 4101 if (hdr.b_l1hdr.b_state == data->mrug_sym.st_value || 4102 hdr.b_l1hdr.b_state == data->mfug_sym.st_value || 4103 hdr.b_l1hdr.b_state == data->l2c_sym.st_value) { 4104 return (WALK_NEXT); 4105 } 4106 4107 /* 4108 * The physical size (compressed) and logical size 4109 * (uncompressed) are in units of SPA_MINBLOCKSIZE. By default, 4110 * we use the log2 of this value (rounded down to the nearest 4111 * integer) to determine the bucket to assign this header to. 4112 * Thus, the histogram is logarithmic with respect to the size 4113 * of the header. For example, the following is a mapping of the 4114 * bucket numbers and the range of header sizes they correspond to: 4115 * 4116 * 0: 0 byte headers 4117 * 1: 512 byte headers 4118 * 2: [1024 - 2048) byte headers 4119 * 3: [2048 - 4096) byte headers 4120 * 4: [4096 - 8192) byte headers 4121 * 5: [8192 - 16394) byte headers 4122 * 6: [16384 - 32768) byte headers 4123 * 7: [32768 - 65536) byte headers 4124 * 8: [65536 - 131072) byte headers 4125 * 9: 131072 byte headers 4126 * 4127 * If the ARC_CFLAG_VERBOSE flag was specified, we use the 4128 * physical and logical sizes directly. Thus, the histogram will 4129 * no longer be logarithmic; instead it will be linear with 4130 * respect to the size of the header. The following is a mapping 4131 * of the first many bucket numbers and the header size they 4132 * correspond to: 4133 * 4134 * 0: 0 byte headers 4135 * 1: 512 byte headers 4136 * 2: 1024 byte headers 4137 * 3: 1536 byte headers 4138 * 4: 2048 byte headers 4139 * 5: 2560 byte headers 4140 * 6: 3072 byte headers 4141 * 4142 * And so on. Keep in mind that a range of sizes isn't used in 4143 * the case of linear scale because the headers can only 4144 * increment or decrement in sizes of 512 bytes. So, it's not 4145 * possible for a header to be sized in between whats listed 4146 * above. 4147 * 4148 * Also, the above mapping values were calculated assuming a 4149 * SPA_MINBLOCKSHIFT of 512 bytes and a SPA_MAXBLOCKSIZE of 128K. 4150 */ 4151 4152 if (data->arc_cflags & ARC_CFLAG_VERBOSE) { 4153 cbucket = hdr.b_psize; 4154 ubucket = hdr.b_lsize; 4155 } else { 4156 cbucket = highbit64(hdr.b_psize); 4157 ubucket = highbit64(hdr.b_lsize); 4158 } 4159 4160 bufcnt = hdr.b_l1hdr.b_bufcnt; 4161 if (bufcnt >= data->hist_nbuckets) 4162 bufcnt = data->hist_nbuckets - 1; 4163 4164 /* Ensure we stay within the bounds of the histogram array */ 4165 ASSERT3U(cbucket, <, data->hist_nbuckets); 4166 ASSERT3U(ubucket, <, data->hist_nbuckets); 4167 4168 if (hdr.b_l1hdr.b_state == data->anon_sym.st_value) { 4169 data->anon_c_hist[cbucket]++; 4170 data->anon_u_hist[ubucket]++; 4171 data->anon_bufs[bufcnt]++; 4172 } else if (hdr.b_l1hdr.b_state == data->mru_sym.st_value) { 4173 data->mru_c_hist[cbucket]++; 4174 data->mru_u_hist[ubucket]++; 4175 data->mru_bufs[bufcnt]++; 4176 } else if (hdr.b_l1hdr.b_state == data->mfu_sym.st_value) { 4177 data->mfu_c_hist[cbucket]++; 4178 data->mfu_u_hist[ubucket]++; 4179 data->mfu_bufs[bufcnt]++; 4180 } 4181 4182 data->all_c_hist[cbucket]++; 4183 data->all_u_hist[ubucket]++; 4184 data->all_bufs[bufcnt]++; 4185 4186 return (WALK_NEXT); 4187 } 4188 4189 /* ARGSUSED */ 4190 static int 4191 arc_compression_stats(uintptr_t addr, uint_t flags, int argc, 4192 const mdb_arg_t *argv) 4193 { 4194 arc_compression_stats_data_t data = { 0 }; 4195 unsigned int max_shifted = SPA_MAXBLOCKSIZE >> SPA_MINBLOCKSHIFT; 4196 unsigned int hist_size; 4197 char range[32]; 4198 int rc = DCMD_OK; 4199 4200 if (mdb_getopts(argc, argv, 4201 'v', MDB_OPT_SETBITS, ARC_CFLAG_VERBOSE, &data.arc_cflags, 4202 'a', MDB_OPT_SETBITS, ARC_CFLAG_ANON, &data.arc_cflags, 4203 'b', MDB_OPT_SETBITS, ARC_CFLAG_BUFS, &data.arc_cflags, 4204 'r', MDB_OPT_SETBITS, ARC_CFLAG_MRU, &data.arc_cflags, 4205 'f', MDB_OPT_SETBITS, ARC_CFLAG_MFU, &data.arc_cflags, 4206 NULL) != argc) 4207 return (DCMD_USAGE); 4208 4209 if (mdb_lookup_by_obj(ZFS_OBJ_NAME, "ARC_anon", &data.anon_sym) || 4210 mdb_lookup_by_obj(ZFS_OBJ_NAME, "ARC_mru", &data.mru_sym) || 4211 mdb_lookup_by_obj(ZFS_OBJ_NAME, "ARC_mru_ghost", &data.mrug_sym) || 4212 mdb_lookup_by_obj(ZFS_OBJ_NAME, "ARC_mfu", &data.mfu_sym) || 4213 mdb_lookup_by_obj(ZFS_OBJ_NAME, "ARC_mfu_ghost", &data.mfug_sym) || 4214 mdb_lookup_by_obj(ZFS_OBJ_NAME, "ARC_l2c_only", &data.l2c_sym)) { 4215 mdb_warn("can't find arc state symbol"); 4216 return (DCMD_ERR); 4217 } 4218 4219 /* 4220 * Determine the maximum expected size for any header, and use 4221 * this to determine the number of buckets needed for each 4222 * histogram. If ARC_CFLAG_VERBOSE is specified, this value is 4223 * used directly; otherwise the log2 of the maximum size is 4224 * used. Thus, if using a log2 scale there's a maximum of 10 4225 * possible buckets, while the linear scale (when using 4226 * ARC_CFLAG_VERBOSE) has a maximum of 257 buckets. 4227 */ 4228 if (data.arc_cflags & ARC_CFLAG_VERBOSE) 4229 data.hist_nbuckets = max_shifted + 1; 4230 else 4231 data.hist_nbuckets = highbit64(max_shifted) + 1; 4232 4233 hist_size = sizeof (uint64_t) * data.hist_nbuckets; 4234 4235 data.anon_c_hist = mdb_zalloc(hist_size, UM_SLEEP); 4236 data.anon_u_hist = mdb_zalloc(hist_size, UM_SLEEP); 4237 data.anon_bufs = mdb_zalloc(hist_size, UM_SLEEP); 4238 4239 data.mru_c_hist = mdb_zalloc(hist_size, UM_SLEEP); 4240 data.mru_u_hist = mdb_zalloc(hist_size, UM_SLEEP); 4241 data.mru_bufs = mdb_zalloc(hist_size, UM_SLEEP); 4242 4243 data.mfu_c_hist = mdb_zalloc(hist_size, UM_SLEEP); 4244 data.mfu_u_hist = mdb_zalloc(hist_size, UM_SLEEP); 4245 data.mfu_bufs = mdb_zalloc(hist_size, UM_SLEEP); 4246 4247 data.all_c_hist = mdb_zalloc(hist_size, UM_SLEEP); 4248 data.all_u_hist = mdb_zalloc(hist_size, UM_SLEEP); 4249 data.all_bufs = mdb_zalloc(hist_size, UM_SLEEP); 4250 4251 if (mdb_walk("arc_buf_hdr_t_full", arc_compression_stats_cb, 4252 &data) != 0) { 4253 mdb_warn("can't walk arc_buf_hdr's"); 4254 rc = DCMD_ERR; 4255 goto out; 4256 } 4257 4258 if (data.arc_cflags & ARC_CFLAG_VERBOSE) { 4259 rc = mdb_snprintf(range, sizeof (range), 4260 "[n*%llu, (n+1)*%llu)", SPA_MINBLOCKSIZE, 4261 SPA_MINBLOCKSIZE); 4262 } else { 4263 rc = mdb_snprintf(range, sizeof (range), 4264 "[2^(n-1)*%llu, 2^n*%llu)", SPA_MINBLOCKSIZE, 4265 SPA_MINBLOCKSIZE); 4266 } 4267 4268 if (rc < 0) { 4269 /* snprintf failed, abort the dcmd */ 4270 rc = DCMD_ERR; 4271 goto out; 4272 } else { 4273 /* snprintf succeeded above, reset return code */ 4274 rc = DCMD_OK; 4275 } 4276 4277 if (data.arc_cflags & ARC_CFLAG_ANON) { 4278 if (data.arc_cflags & ARC_CFLAG_BUFS) { 4279 mdb_printf("Histogram of the number of anon buffers " 4280 "that are associated with an arc hdr.\n"); 4281 dump_histogram(data.anon_bufs, data.hist_nbuckets, 0); 4282 mdb_printf("\n"); 4283 } 4284 mdb_printf("Histogram of compressed anon buffers.\n" 4285 "Each bucket represents buffers of size: %s.\n", range); 4286 dump_histogram(data.anon_c_hist, data.hist_nbuckets, 0); 4287 mdb_printf("\n"); 4288 4289 mdb_printf("Histogram of uncompressed anon buffers.\n" 4290 "Each bucket represents buffers of size: %s.\n", range); 4291 dump_histogram(data.anon_u_hist, data.hist_nbuckets, 0); 4292 mdb_printf("\n"); 4293 } 4294 4295 if (data.arc_cflags & ARC_CFLAG_MRU) { 4296 if (data.arc_cflags & ARC_CFLAG_BUFS) { 4297 mdb_printf("Histogram of the number of mru buffers " 4298 "that are associated with an arc hdr.\n"); 4299 dump_histogram(data.mru_bufs, data.hist_nbuckets, 0); 4300 mdb_printf("\n"); 4301 } 4302 mdb_printf("Histogram of compressed mru buffers.\n" 4303 "Each bucket represents buffers of size: %s.\n", range); 4304 dump_histogram(data.mru_c_hist, data.hist_nbuckets, 0); 4305 mdb_printf("\n"); 4306 4307 mdb_printf("Histogram of uncompressed mru buffers.\n" 4308 "Each bucket represents buffers of size: %s.\n", range); 4309 dump_histogram(data.mru_u_hist, data.hist_nbuckets, 0); 4310 mdb_printf("\n"); 4311 } 4312 4313 if (data.arc_cflags & ARC_CFLAG_MFU) { 4314 if (data.arc_cflags & ARC_CFLAG_BUFS) { 4315 mdb_printf("Histogram of the number of mfu buffers " 4316 "that are associated with an arc hdr.\n"); 4317 dump_histogram(data.mfu_bufs, data.hist_nbuckets, 0); 4318 mdb_printf("\n"); 4319 } 4320 4321 mdb_printf("Histogram of compressed mfu buffers.\n" 4322 "Each bucket represents buffers of size: %s.\n", range); 4323 dump_histogram(data.mfu_c_hist, data.hist_nbuckets, 0); 4324 mdb_printf("\n"); 4325 4326 mdb_printf("Histogram of uncompressed mfu buffers.\n" 4327 "Each bucket represents buffers of size: %s.\n", range); 4328 dump_histogram(data.mfu_u_hist, data.hist_nbuckets, 0); 4329 mdb_printf("\n"); 4330 } 4331 4332 if (data.arc_cflags & ARC_CFLAG_BUFS) { 4333 mdb_printf("Histogram of all buffers that " 4334 "are associated with an arc hdr.\n"); 4335 dump_histogram(data.all_bufs, data.hist_nbuckets, 0); 4336 mdb_printf("\n"); 4337 } 4338 4339 mdb_printf("Histogram of all compressed buffers.\n" 4340 "Each bucket represents buffers of size: %s.\n", range); 4341 dump_histogram(data.all_c_hist, data.hist_nbuckets, 0); 4342 mdb_printf("\n"); 4343 4344 mdb_printf("Histogram of all uncompressed buffers.\n" 4345 "Each bucket represents buffers of size: %s.\n", range); 4346 dump_histogram(data.all_u_hist, data.hist_nbuckets, 0); 4347 4348 out: 4349 mdb_free(data.anon_c_hist, hist_size); 4350 mdb_free(data.anon_u_hist, hist_size); 4351 mdb_free(data.anon_bufs, hist_size); 4352 4353 mdb_free(data.mru_c_hist, hist_size); 4354 mdb_free(data.mru_u_hist, hist_size); 4355 mdb_free(data.mru_bufs, hist_size); 4356 4357 mdb_free(data.mfu_c_hist, hist_size); 4358 mdb_free(data.mfu_u_hist, hist_size); 4359 mdb_free(data.mfu_bufs, hist_size); 4360 4361 mdb_free(data.all_c_hist, hist_size); 4362 mdb_free(data.all_u_hist, hist_size); 4363 mdb_free(data.all_bufs, hist_size); 4364 4365 return (rc); 4366 } 4367 4368 typedef struct mdb_range_seg64 { 4369 uint64_t rs_start; 4370 uint64_t rs_end; 4371 } mdb_range_seg64_t; 4372 4373 typedef struct mdb_range_seg32 { 4374 uint32_t rs_start; 4375 uint32_t rs_end; 4376 } mdb_range_seg32_t; 4377 4378 /* ARGSUSED */ 4379 static int 4380 range_tree_cb(uintptr_t addr, const void *unknown, void *arg) 4381 { 4382 mdb_range_tree_t *rt = (mdb_range_tree_t *)arg; 4383 uint64_t start, end; 4384 4385 if (rt->rt_type == RANGE_SEG64) { 4386 mdb_range_seg64_t rs; 4387 4388 if (mdb_ctf_vread(&rs, ZFS_STRUCT "range_seg64", 4389 "mdb_range_seg64_t", addr, 0) == -1) 4390 return (DCMD_ERR); 4391 start = rs.rs_start; 4392 end = rs.rs_end; 4393 } else { 4394 ASSERT3U(rt->rt_type, ==, RANGE_SEG32); 4395 mdb_range_seg32_t rs; 4396 4397 if (mdb_ctf_vread(&rs, ZFS_STRUCT "range_seg32", 4398 "mdb_range_seg32_t", addr, 0) == -1) 4399 return (DCMD_ERR); 4400 start = ((uint64_t)rs.rs_start << rt->rt_shift) + rt->rt_start; 4401 end = ((uint64_t)rs.rs_end << rt->rt_shift) + rt->rt_start; 4402 } 4403 4404 mdb_printf("\t[%llx %llx) (length %llx)\n", start, end, end - start); 4405 4406 return (0); 4407 } 4408 4409 /* ARGSUSED */ 4410 static int 4411 range_tree(uintptr_t addr, uint_t flags, int argc, 4412 const mdb_arg_t *argv) 4413 { 4414 mdb_range_tree_t rt; 4415 uintptr_t btree_addr; 4416 4417 if (!(flags & DCMD_ADDRSPEC)) 4418 return (DCMD_USAGE); 4419 4420 if (mdb_ctf_vread(&rt, ZFS_STRUCT "range_tree", "mdb_range_tree_t", 4421 addr, 0) == -1) 4422 return (DCMD_ERR); 4423 4424 mdb_printf("%p: range tree of %llu entries, %llu bytes\n", 4425 addr, rt.rt_root.bt_num_elems, rt.rt_space); 4426 4427 btree_addr = addr + 4428 mdb_ctf_offsetof_by_name(ZFS_STRUCT "range_tree", "rt_root"); 4429 4430 if (mdb_pwalk("zfs_btree", range_tree_cb, &rt, btree_addr) != 0) { 4431 mdb_warn("can't walk range_tree segments"); 4432 return (DCMD_ERR); 4433 } 4434 return (DCMD_OK); 4435 } 4436 4437 typedef struct mdb_spa_log_sm { 4438 uint64_t sls_sm_obj; 4439 uint64_t sls_txg; 4440 uint64_t sls_nblocks; 4441 uint64_t sls_mscount; 4442 } mdb_spa_log_sm_t; 4443 4444 /* ARGSUSED */ 4445 static int 4446 logsm_stats_cb(uintptr_t addr, const void *unknown, void *arg) 4447 { 4448 mdb_spa_log_sm_t sls; 4449 if (mdb_ctf_vread(&sls, ZFS_STRUCT "spa_log_sm", "mdb_spa_log_sm_t", 4450 addr, 0) == -1) 4451 return (WALK_ERR); 4452 4453 mdb_printf("%7lld %7lld %7lld %7lld\n", 4454 sls.sls_txg, sls.sls_nblocks, sls.sls_mscount, sls.sls_sm_obj); 4455 4456 return (WALK_NEXT); 4457 } 4458 typedef struct mdb_log_summary_entry { 4459 uint64_t lse_start; 4460 uint64_t lse_blkcount; 4461 uint64_t lse_mscount; 4462 } mdb_log_summary_entry_t; 4463 4464 /* ARGSUSED */ 4465 static int 4466 logsm_summary_cb(uintptr_t addr, const void *unknown, void *arg) 4467 { 4468 mdb_log_summary_entry_t lse; 4469 if (mdb_ctf_vread(&lse, ZFS_STRUCT "log_summary_entry", 4470 "mdb_log_summary_entry_t", addr, 0) == -1) 4471 return (WALK_ERR); 4472 4473 mdb_printf("%7lld %7lld %7lld\n", 4474 lse.lse_start, lse.lse_blkcount, lse.lse_mscount); 4475 return (WALK_NEXT); 4476 } 4477 4478 /* ARGSUSED */ 4479 static int 4480 logsm_stats(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 4481 { 4482 if (!(flags & DCMD_ADDRSPEC)) 4483 return (DCMD_USAGE); 4484 4485 uintptr_t sls_avl_addr = addr + 4486 mdb_ctf_offsetof_by_name(ZFS_STRUCT "spa", "spa_sm_logs_by_txg"); 4487 uintptr_t summary_addr = addr + 4488 mdb_ctf_offsetof_by_name(ZFS_STRUCT "spa", "spa_log_summary"); 4489 4490 mdb_printf("Log Entries:\n"); 4491 mdb_printf("%7s %7s %7s %7s\n", "txg", "blk", "ms", "obj"); 4492 if (mdb_pwalk("avl", logsm_stats_cb, NULL, sls_avl_addr) != 0) 4493 return (DCMD_ERR); 4494 4495 mdb_printf("\nSummary Entries:\n"); 4496 mdb_printf("%7s %7s %7s\n", "txg", "blk", "ms"); 4497 if (mdb_pwalk("list", logsm_summary_cb, NULL, summary_addr) != 0) 4498 return (DCMD_ERR); 4499 4500 return (DCMD_OK); 4501 } 4502 4503 /* 4504 * MDB module linkage information: 4505 * 4506 * We declare a list of structures describing our dcmds, and a function 4507 * named _mdb_init to return a pointer to our module information. 4508 */ 4509 4510 static const mdb_dcmd_t dcmds[] = { 4511 { "arc", "[-bkmg]", "print ARC variables", arc_print }, 4512 { "blkptr", ":", "print blkptr_t", blkptr }, 4513 { "dva", ":", "print dva_t", dva }, 4514 { "dbuf", ":", "print dmu_buf_impl_t", dbuf }, 4515 { "dbuf_stats", ":", "dbuf stats", dbuf_stats }, 4516 { "dbufs", 4517 "\t[-O objset_t*] [-n objset_name | \"mos\"] " 4518 "[-o object | \"mdn\"] \n" 4519 "\t[-l level] [-b blkid | \"bonus\"]", 4520 "find dmu_buf_impl_t's that match specified criteria", dbufs }, 4521 { "abuf_find", "dva_word[0] dva_word[1]", 4522 "find arc_buf_hdr_t of a specified DVA", 4523 abuf_find }, 4524 { "logsm_stats", ":", "print log space map statistics of a spa_t", 4525 logsm_stats}, 4526 { "spa", "?[-cevmMh]\n" 4527 "\t-c display spa config\n" 4528 "\t-e display vdev statistics\n" 4529 "\t-v display vdev information\n" 4530 "\t-m display metaslab statistics\n" 4531 "\t-M display metaslab group statistics\n" 4532 "\t-h display histogram (requires -m or -M)\n", 4533 "spa_t summary", spa_print }, 4534 { "spa_config", ":", "print spa_t configuration", spa_print_config }, 4535 { "spa_space", ":[-b]", "print spa_t on-disk space usage", spa_space }, 4536 { "spa_vdevs", ":[-emMh]\n" 4537 "\t-e display vdev statistics\n" 4538 "\t-m dispaly metaslab statistics\n" 4539 "\t-M display metaslab group statistic\n" 4540 "\t-h display histogram (requires -m or -M)\n", 4541 "given a spa_t, print vdev summary", spa_vdevs }, 4542 { "sm_entries", "<buffer length in bytes>", 4543 "print out space map entries from a buffer decoded", 4544 sm_entries}, 4545 { "vdev", ":[-remMh]\n" 4546 "\t-r display recursively\n" 4547 "\t-e display statistics\n" 4548 "\t-m display metaslab statistics (top level vdev only)\n" 4549 "\t-M display metaslab group statistics (top level vdev only)\n" 4550 "\t-h display histogram (requires -m or -M)\n", 4551 "vdev_t summary", vdev_print }, 4552 { "zio", ":[-cpr]\n" 4553 "\t-c display children\n" 4554 "\t-p display parents\n" 4555 "\t-r display recursively", 4556 "zio_t summary", zio_print }, 4557 { "zio_state", "?", "print out all zio_t structures on system or " 4558 "for a particular pool", zio_state }, 4559 { "zfs_blkstats", ":[-v]", 4560 "given a spa_t, print block type stats from last scrub", 4561 zfs_blkstats }, 4562 { "zfs_params", "", "print zfs tunable parameters", zfs_params }, 4563 { "zfs_refcount", ":[-r]\n" 4564 "\t-r display recently removed references", 4565 "print zfs_refcount_t holders", zfs_refcount }, 4566 { "zap_leaf", "", "print zap_leaf_phys_t", zap_leaf }, 4567 { "zfs_aces", ":[-v]", "print all ACEs from a zfs_acl_t", 4568 zfs_acl_dump }, 4569 { "zfs_ace", ":[-v]", "print zfs_ace", zfs_ace_print }, 4570 { "zfs_ace0", ":[-v]", "print zfs_ace0", zfs_ace0_print }, 4571 { "sa_attr_table", ":", "print SA attribute table from sa_os_t", 4572 sa_attr_table}, 4573 { "sa_attr", ": attr_id", 4574 "print SA attribute address when given sa_handle_t", sa_attr_print}, 4575 { "zfs_dbgmsg", ":[-va]", 4576 "print zfs debug log", dbgmsg}, 4577 { "rrwlock", ":", 4578 "print rrwlock_t, including readers", rrwlock}, 4579 { "metaslab_weight", "weight", 4580 "print metaslab weight", metaslab_weight}, 4581 { "metaslab_trace", ":", 4582 "print metaslab allocation trace records", metaslab_trace}, 4583 { "arc_compression_stats", ":[-vabrf]\n" 4584 "\t-v verbose, display a linearly scaled histogram\n" 4585 "\t-a display ARC_anon state statistics individually\n" 4586 "\t-r display ARC_mru state statistics individually\n" 4587 "\t-f display ARC_mfu state statistics individually\n" 4588 "\t-b display histogram of buffer counts\n", 4589 "print a histogram of compressed arc buffer sizes", 4590 arc_compression_stats}, 4591 { "range_tree", ":", 4592 "print entries in range_tree_t", range_tree}, 4593 { NULL } 4594 }; 4595 4596 static const mdb_walker_t walkers[] = { 4597 { "txg_list", "given any txg_list_t *, walk all entries in all txgs", 4598 txg_list_walk_init, txg_list_walk_step, NULL }, 4599 { "txg_list0", "given any txg_list_t *, walk all entries in txg 0", 4600 txg_list0_walk_init, txg_list_walk_step, NULL }, 4601 { "txg_list1", "given any txg_list_t *, walk all entries in txg 1", 4602 txg_list1_walk_init, txg_list_walk_step, NULL }, 4603 { "txg_list2", "given any txg_list_t *, walk all entries in txg 2", 4604 txg_list2_walk_init, txg_list_walk_step, NULL }, 4605 { "txg_list3", "given any txg_list_t *, walk all entries in txg 3", 4606 txg_list3_walk_init, txg_list_walk_step, NULL }, 4607 { "zio", "walk all zio structures, optionally for a particular spa_t", 4608 zio_walk_init, zio_walk_step, NULL }, 4609 { "zio_root", 4610 "walk all root zio_t structures, optionally for a particular spa_t", 4611 zio_walk_init, zio_walk_root_step, NULL }, 4612 { "spa", "walk all spa_t entries in the namespace", 4613 spa_walk_init, spa_walk_step, NULL }, 4614 { "metaslab", "given a spa_t *, walk all metaslab_t structures", 4615 metaslab_walk_init, metaslab_walk_step, NULL }, 4616 { "multilist", "given a multilist_t *, walk all list_t structures", 4617 multilist_walk_init, multilist_walk_step, NULL }, 4618 { "zfs_acl_node", "given a zfs_acl_t, walk all zfs_acl_nodes", 4619 zfs_acl_node_walk_init, zfs_acl_node_walk_step, NULL }, 4620 { "zfs_acl_node_aces", "given a zfs_acl_node_t, walk all ACEs", 4621 zfs_acl_node_aces_walk_init, zfs_aces_walk_step, NULL }, 4622 { "zfs_acl_node_aces0", 4623 "given a zfs_acl_node_t, walk all ACEs as ace_t", 4624 zfs_acl_node_aces0_walk_init, zfs_aces_walk_step, NULL }, 4625 { "zfs_btree", "given a zfs_btree_t *, walk all entries", 4626 btree_walk_init, btree_walk_step, btree_walk_fini }, 4627 { NULL } 4628 }; 4629 4630 static const mdb_modinfo_t modinfo = { 4631 MDB_API_VERSION, dcmds, walkers 4632 }; 4633 4634 const mdb_modinfo_t * 4635 _mdb_init(void) 4636 { 4637 return (&modinfo); 4638 } 4639