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 (c) 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 59 #ifdef _KERNEL 60 #define ZFS_OBJ_NAME "zfs" 61 extern int64_t mdb_gethrtime(void); 62 #else 63 #define ZFS_OBJ_NAME "libzpool.so.1" 64 #endif 65 66 #define ZFS_STRUCT "struct " ZFS_OBJ_NAME "`" 67 68 #ifndef _KERNEL 69 int aok; 70 #endif 71 72 enum spa_flags { 73 SPA_FLAG_CONFIG = 1 << 0, 74 SPA_FLAG_VDEVS = 1 << 1, 75 SPA_FLAG_ERRORS = 1 << 2, 76 SPA_FLAG_METASLAB_GROUPS = 1 << 3, 77 SPA_FLAG_METASLABS = 1 << 4, 78 SPA_FLAG_HISTOGRAMS = 1 << 5 79 }; 80 81 /* 82 * If any of these flags are set, call spa_vdevs in spa_print 83 */ 84 #define SPA_FLAG_ALL_VDEV \ 85 (SPA_FLAG_VDEVS | SPA_FLAG_ERRORS | SPA_FLAG_METASLAB_GROUPS | \ 86 SPA_FLAG_METASLABS) 87 88 static int 89 getmember(uintptr_t addr, const char *type, mdb_ctf_id_t *idp, 90 const char *member, int len, void *buf) 91 { 92 mdb_ctf_id_t id; 93 ulong_t off; 94 char name[64]; 95 96 if (idp == NULL) { 97 if (mdb_ctf_lookup_by_name(type, &id) == -1) { 98 mdb_warn("couldn't find type %s", type); 99 return (DCMD_ERR); 100 } 101 idp = &id; 102 } else { 103 type = name; 104 mdb_ctf_type_name(*idp, name, sizeof (name)); 105 } 106 107 if (mdb_ctf_offsetof(*idp, member, &off) == -1) { 108 mdb_warn("couldn't find member %s of type %s\n", member, type); 109 return (DCMD_ERR); 110 } 111 if (off % 8 != 0) { 112 mdb_warn("member %s of type %s is unsupported bitfield", 113 member, type); 114 return (DCMD_ERR); 115 } 116 off /= 8; 117 118 if (mdb_vread(buf, len, addr + off) == -1) { 119 mdb_warn("failed to read %s from %s at %p", 120 member, type, addr + off); 121 return (DCMD_ERR); 122 } 123 /* mdb_warn("read %s from %s at %p+%llx\n", member, type, addr, off); */ 124 125 return (0); 126 } 127 128 #define GETMEMB(addr, structname, member, dest) \ 129 getmember(addr, ZFS_STRUCT structname, NULL, #member, \ 130 sizeof (dest), &(dest)) 131 132 #define GETMEMBID(addr, ctfid, member, dest) \ 133 getmember(addr, NULL, ctfid, #member, sizeof (dest), &(dest)) 134 135 static boolean_t 136 strisprint(const char *cp) 137 { 138 for (; *cp; cp++) { 139 if (!isprint(*cp)) 140 return (B_FALSE); 141 } 142 return (B_TRUE); 143 } 144 145 /* 146 * <addr>::sm_entries <buffer length in bytes> 147 * 148 * Treat the buffer specified by the given address as a buffer that contains 149 * space map entries. Iterate over the specified number of entries and print 150 * them in both encoded and decoded form. 151 */ 152 /* ARGSUSED */ 153 static int 154 sm_entries(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 155 { 156 uint64_t bufsz = 0; 157 boolean_t preview = B_FALSE; 158 159 if (!(flags & DCMD_ADDRSPEC)) 160 return (DCMD_USAGE); 161 162 if (argc < 1) { 163 preview = B_TRUE; 164 bufsz = 2; 165 } else if (argc != 1) { 166 return (DCMD_USAGE); 167 } else { 168 switch (argv[0].a_type) { 169 case MDB_TYPE_STRING: 170 bufsz = mdb_strtoull(argv[0].a_un.a_str); 171 break; 172 case MDB_TYPE_IMMEDIATE: 173 bufsz = argv[0].a_un.a_val; 174 break; 175 default: 176 return (DCMD_USAGE); 177 } 178 } 179 180 char *actions[] = { "ALLOC", "FREE", "INVALID" }; 181 for (uintptr_t bufend = addr + bufsz; addr < bufend; 182 addr += sizeof (uint64_t)) { 183 uint64_t nwords; 184 uint64_t start_addr = addr; 185 186 uint64_t word = 0; 187 if (mdb_vread(&word, sizeof (word), addr) == -1) { 188 mdb_warn("failed to read space map entry %p", addr); 189 return (DCMD_ERR); 190 } 191 192 if (SM_PREFIX_DECODE(word) == SM_DEBUG_PREFIX) { 193 (void) mdb_printf("\t [%6llu] %s: txg %llu, " 194 "pass %llu\n", 195 (u_longlong_t)(addr), 196 actions[SM_DEBUG_ACTION_DECODE(word)], 197 (u_longlong_t)SM_DEBUG_TXG_DECODE(word), 198 (u_longlong_t)SM_DEBUG_SYNCPASS_DECODE(word)); 199 continue; 200 } 201 202 char entry_type; 203 uint64_t raw_offset, raw_run, vdev_id = SM_NO_VDEVID; 204 205 if (SM_PREFIX_DECODE(word) != SM2_PREFIX) { 206 entry_type = (SM_TYPE_DECODE(word) == SM_ALLOC) ? 207 'A' : 'F'; 208 raw_offset = SM_OFFSET_DECODE(word); 209 raw_run = SM_RUN_DECODE(word); 210 nwords = 1; 211 } else { 212 ASSERT3U(SM_PREFIX_DECODE(word), ==, SM2_PREFIX); 213 214 raw_run = SM2_RUN_DECODE(word); 215 vdev_id = SM2_VDEV_DECODE(word); 216 217 /* it is a two-word entry so we read another word */ 218 addr += sizeof (uint64_t); 219 if (addr >= bufend) { 220 mdb_warn("buffer ends in the middle of a two " 221 "word entry\n", addr); 222 return (DCMD_ERR); 223 } 224 225 if (mdb_vread(&word, sizeof (word), addr) == -1) { 226 mdb_warn("failed to read space map entry %p", 227 addr); 228 return (DCMD_ERR); 229 } 230 231 entry_type = (SM2_TYPE_DECODE(word) == SM_ALLOC) ? 232 'A' : 'F'; 233 raw_offset = SM2_OFFSET_DECODE(word); 234 nwords = 2; 235 } 236 237 (void) mdb_printf("\t [%6llx] %c range:" 238 " %010llx-%010llx size: %06llx vdev: %06llu words: %llu\n", 239 (u_longlong_t)start_addr, 240 entry_type, (u_longlong_t)raw_offset, 241 (u_longlong_t)(raw_offset + raw_run), 242 (u_longlong_t)raw_run, 243 (u_longlong_t)vdev_id, (u_longlong_t)nwords); 244 245 if (preview) 246 break; 247 } 248 return (DCMD_OK); 249 } 250 251 static int 252 mdb_dsl_dir_name(uintptr_t addr, char *buf) 253 { 254 static int gotid; 255 static mdb_ctf_id_t dd_id; 256 uintptr_t dd_parent; 257 char dd_myname[ZFS_MAX_DATASET_NAME_LEN]; 258 259 if (!gotid) { 260 if (mdb_ctf_lookup_by_name(ZFS_STRUCT "dsl_dir", 261 &dd_id) == -1) { 262 mdb_warn("couldn't find struct dsl_dir"); 263 return (DCMD_ERR); 264 } 265 gotid = TRUE; 266 } 267 if (GETMEMBID(addr, &dd_id, dd_parent, dd_parent) || 268 GETMEMBID(addr, &dd_id, dd_myname, dd_myname)) { 269 return (DCMD_ERR); 270 } 271 272 if (dd_parent) { 273 if (mdb_dsl_dir_name(dd_parent, buf)) 274 return (DCMD_ERR); 275 strcat(buf, "/"); 276 } 277 278 if (dd_myname[0]) 279 strcat(buf, dd_myname); 280 else 281 strcat(buf, "???"); 282 283 return (0); 284 } 285 286 static int 287 objset_name(uintptr_t addr, char *buf) 288 { 289 static int gotid; 290 static mdb_ctf_id_t os_id, ds_id; 291 uintptr_t os_dsl_dataset; 292 char ds_snapname[ZFS_MAX_DATASET_NAME_LEN]; 293 uintptr_t ds_dir; 294 295 buf[0] = '\0'; 296 297 if (!gotid) { 298 if (mdb_ctf_lookup_by_name(ZFS_STRUCT "objset", 299 &os_id) == -1) { 300 mdb_warn("couldn't find struct objset"); 301 return (DCMD_ERR); 302 } 303 if (mdb_ctf_lookup_by_name(ZFS_STRUCT "dsl_dataset", 304 &ds_id) == -1) { 305 mdb_warn("couldn't find struct dsl_dataset"); 306 return (DCMD_ERR); 307 } 308 309 gotid = TRUE; 310 } 311 312 if (GETMEMBID(addr, &os_id, os_dsl_dataset, os_dsl_dataset)) 313 return (DCMD_ERR); 314 315 if (os_dsl_dataset == 0) { 316 strcat(buf, "mos"); 317 return (0); 318 } 319 320 if (GETMEMBID(os_dsl_dataset, &ds_id, ds_snapname, ds_snapname) || 321 GETMEMBID(os_dsl_dataset, &ds_id, ds_dir, ds_dir)) { 322 return (DCMD_ERR); 323 } 324 325 if (ds_dir && mdb_dsl_dir_name(ds_dir, buf)) 326 return (DCMD_ERR); 327 328 if (ds_snapname[0]) { 329 strcat(buf, "@"); 330 strcat(buf, ds_snapname); 331 } 332 return (0); 333 } 334 335 static int 336 enum_lookup(char *type, int val, const char *prefix, size_t size, char *out) 337 { 338 const char *cp; 339 size_t len = strlen(prefix); 340 mdb_ctf_id_t enum_type; 341 342 if (mdb_ctf_lookup_by_name(type, &enum_type) != 0) { 343 mdb_warn("Could not find enum for %s", type); 344 return (-1); 345 } 346 347 if ((cp = mdb_ctf_enum_name(enum_type, val)) != NULL) { 348 if (strncmp(cp, prefix, len) == 0) 349 cp += len; 350 (void) strncpy(out, cp, size); 351 } else { 352 mdb_snprintf(out, size, "? (%d)", val); 353 } 354 return (0); 355 } 356 357 /* ARGSUSED */ 358 static int 359 zfs_params(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 360 { 361 /* 362 * This table can be approximately generated by running: 363 * egrep "^[a-z0-9_]+ [a-z0-9_]+( =.*)?;" *.c | cut -d ' ' -f 2 364 */ 365 static const char *params[] = { 366 "arc_lotsfree_percent", 367 "arc_pages_pp_reserve", 368 "arc_reduce_dnlc_percent", 369 "arc_swapfs_reserve", 370 "arc_zio_arena_free_shift", 371 "dbuf_cache_hiwater_pct", 372 "dbuf_cache_lowater_pct", 373 "dbuf_cache_max_bytes", 374 "dbuf_cache_max_shift", 375 "ddt_zap_indirect_blockshift", 376 "ddt_zap_leaf_blockshift", 377 "ditto_same_vdev_distance_shift", 378 "dmu_find_threads", 379 "dmu_rescan_dnode_threshold", 380 "dsl_scan_delay_completion", 381 "fzap_default_block_shift", 382 "l2arc_feed_again", 383 "l2arc_feed_min_ms", 384 "l2arc_feed_secs", 385 "l2arc_headroom", 386 "l2arc_headroom_boost", 387 "l2arc_noprefetch", 388 "l2arc_norw", 389 "l2arc_write_boost", 390 "l2arc_write_max", 391 "metaslab_aliquot", 392 "metaslab_bias_enabled", 393 "metaslab_debug_load", 394 "metaslab_debug_unload", 395 "metaslab_df_alloc_threshold", 396 "metaslab_df_free_pct", 397 "metaslab_fragmentation_factor_enabled", 398 "metaslab_force_ganging", 399 "metaslab_lba_weighting_enabled", 400 "metaslab_load_pct", 401 "metaslab_min_alloc_size", 402 "metaslab_ndf_clump_shift", 403 "metaslab_preload_enabled", 404 "metaslab_preload_limit", 405 "metaslab_trace_enabled", 406 "metaslab_trace_max_entries", 407 "metaslab_unload_delay", 408 "metaslabs_per_vdev", 409 "reference_history", 410 "reference_tracking_enable", 411 "send_holes_without_birth_time", 412 "spa_asize_inflation", 413 "spa_load_verify_data", 414 "spa_load_verify_maxinflight", 415 "spa_load_verify_metadata", 416 "spa_max_replication_override", 417 "spa_min_slop", 418 "spa_mode_global", 419 "spa_slop_shift", 420 "space_map_blksz", 421 "vdev_mirror_shift", 422 "zfetch_max_distance", 423 "zfs_abd_chunk_size", 424 "zfs_abd_scatter_enabled", 425 "zfs_arc_average_blocksize", 426 "zfs_arc_evict_batch_limit", 427 "zfs_arc_grow_retry", 428 "zfs_arc_max", 429 "zfs_arc_meta_limit", 430 "zfs_arc_meta_min", 431 "zfs_arc_min", 432 "zfs_arc_p_min_shift", 433 "zfs_arc_shrink_shift", 434 "zfs_async_block_max_blocks", 435 "zfs_ccw_retry_interval", 436 "zfs_commit_timeout_pct", 437 "zfs_compressed_arc_enabled", 438 "zfs_condense_indirect_commit_entry_delay_ticks", 439 "zfs_condense_indirect_vdevs_enable", 440 "zfs_condense_max_obsolete_bytes", 441 "zfs_condense_min_mapping_bytes", 442 "zfs_condense_pct", 443 "zfs_dbgmsg_maxsize", 444 "zfs_deadman_checktime_ms", 445 "zfs_deadman_enabled", 446 "zfs_deadman_synctime_ms", 447 "zfs_dedup_prefetch", 448 "zfs_default_bs", 449 "zfs_default_ibs", 450 "zfs_delay_max_ns", 451 "zfs_delay_min_dirty_percent", 452 "zfs_delay_resolution_ns", 453 "zfs_delay_scale", 454 "zfs_dirty_data_max", 455 "zfs_dirty_data_max_max", 456 "zfs_dirty_data_max_percent", 457 "zfs_dirty_data_sync", 458 "zfs_flags", 459 "zfs_free_bpobj_enabled", 460 "zfs_free_leak_on_eio", 461 "zfs_free_min_time_ms", 462 "zfs_fsync_sync_cnt", 463 "zfs_immediate_write_sz", 464 "zfs_indirect_condense_obsolete_pct", 465 "zfs_lua_check_instrlimit_interval", 466 "zfs_lua_max_instrlimit", 467 "zfs_lua_max_memlimit", 468 "zfs_max_recordsize", 469 "zfs_mdcomp_disable", 470 "zfs_metaslab_condense_block_threshold", 471 "zfs_metaslab_fragmentation_threshold", 472 "zfs_metaslab_segment_weight_enabled", 473 "zfs_metaslab_switch_threshold", 474 "zfs_mg_fragmentation_threshold", 475 "zfs_mg_noalloc_threshold", 476 "zfs_multilist_num_sublists", 477 "zfs_no_scrub_io", 478 "zfs_no_scrub_prefetch", 479 "zfs_nocacheflush", 480 "zfs_nopwrite_enabled", 481 "zfs_object_remap_one_indirect_delay_ticks", 482 "zfs_obsolete_min_time_ms", 483 "zfs_pd_bytes_max", 484 "zfs_per_txg_dirty_frees_percent", 485 "zfs_prefetch_disable", 486 "zfs_read_chunk_size", 487 "zfs_recover", 488 "zfs_recv_queue_length", 489 "zfs_redundant_metadata_most_ditto_level", 490 "zfs_remap_blkptr_enable", 491 "zfs_remove_max_copy_bytes", 492 "zfs_remove_max_segment", 493 "zfs_resilver_delay", 494 "zfs_resilver_min_time_ms", 495 "zfs_scan_idle", 496 "zfs_scan_min_time_ms", 497 "zfs_scrub_delay", 498 "zfs_scrub_limit", 499 "zfs_send_corrupt_data", 500 "zfs_send_queue_length", 501 "zfs_send_set_freerecords_bit", 502 "zfs_sync_pass_deferred_free", 503 "zfs_sync_pass_dont_compress", 504 "zfs_sync_pass_rewrite", 505 "zfs_sync_taskq_batch_pct", 506 "zfs_top_maxinflight", 507 "zfs_txg_timeout", 508 "zfs_vdev_aggregation_limit", 509 "zfs_vdev_async_read_max_active", 510 "zfs_vdev_async_read_min_active", 511 "zfs_vdev_async_write_active_max_dirty_percent", 512 "zfs_vdev_async_write_active_min_dirty_percent", 513 "zfs_vdev_async_write_max_active", 514 "zfs_vdev_async_write_min_active", 515 "zfs_vdev_cache_bshift", 516 "zfs_vdev_cache_max", 517 "zfs_vdev_cache_size", 518 "zfs_vdev_max_active", 519 "zfs_vdev_queue_depth_pct", 520 "zfs_vdev_read_gap_limit", 521 "zfs_vdev_removal_max_active", 522 "zfs_vdev_removal_min_active", 523 "zfs_vdev_scrub_max_active", 524 "zfs_vdev_scrub_min_active", 525 "zfs_vdev_sync_read_max_active", 526 "zfs_vdev_sync_read_min_active", 527 "zfs_vdev_sync_write_max_active", 528 "zfs_vdev_sync_write_min_active", 529 "zfs_vdev_write_gap_limit", 530 "zfs_write_implies_delete_child", 531 "zfs_zil_clean_taskq_maxalloc", 532 "zfs_zil_clean_taskq_minalloc", 533 "zfs_zil_clean_taskq_nthr_pct", 534 "zil_replay_disable", 535 "zil_slog_bulk", 536 "zio_buf_debug_limit", 537 "zio_dva_throttle_enabled", 538 "zio_injection_enabled", 539 "zvol_immediate_write_sz", 540 "zvol_maxphys", 541 "zvol_unmap_enabled", 542 "zvol_unmap_sync_enabled", 543 "zfs_max_dataset_nesting", 544 }; 545 546 for (int i = 0; i < sizeof (params) / sizeof (params[0]); i++) { 547 int sz; 548 uint64_t val64; 549 uint32_t *val32p = (uint32_t *)&val64; 550 551 sz = mdb_readvar(&val64, params[i]); 552 if (sz == 4) { 553 mdb_printf("%s = 0x%x\n", params[i], *val32p); 554 } else if (sz == 8) { 555 mdb_printf("%s = 0x%llx\n", params[i], val64); 556 } else { 557 mdb_warn("variable %s not found", params[i]); 558 } 559 } 560 561 return (DCMD_OK); 562 } 563 564 /* ARGSUSED */ 565 static int 566 dva(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 567 { 568 dva_t dva; 569 if (mdb_vread(&dva, sizeof (dva_t), addr) == -1) { 570 mdb_warn("failed to read dva_t"); 571 return (DCMD_ERR); 572 } 573 mdb_printf("<%llu:%llx:%llx>\n", 574 (u_longlong_t)DVA_GET_VDEV(&dva), 575 (u_longlong_t)DVA_GET_OFFSET(&dva), 576 (u_longlong_t)DVA_GET_ASIZE(&dva)); 577 578 return (DCMD_OK); 579 } 580 581 typedef struct mdb_dmu_object_type_info { 582 boolean_t ot_encrypt; 583 } mdb_dmu_object_type_info_t; 584 585 static boolean_t 586 mdb_dmu_ot_is_encrypted_impl(dmu_object_type_t ot) 587 { 588 mdb_dmu_object_type_info_t mdoti; 589 GElf_Sym sym; 590 size_t sz = mdb_ctf_sizeof_by_name("dmu_object_type_info_t"); 591 592 if (mdb_lookup_by_obj(ZFS_OBJ_NAME, "dmu_ot", &sym)) { 593 mdb_warn("failed to find " ZFS_OBJ_NAME "`dmu_ot"); 594 return (B_FALSE); 595 } 596 597 if (mdb_ctf_vread(&mdoti, "dmu_object_type_info_t", 598 "mdb_dmu_object_type_info_t", sym.st_value + sz * ot, 0) != 0) { 599 return (B_FALSE); 600 } 601 602 return (mdoti.ot_encrypt); 603 } 604 605 /* ARGSUSED */ 606 static int 607 blkptr(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 608 { 609 char type[80], checksum[80], compress[80]; 610 blkptr_t blk, *bp = &blk; 611 char buf[BP_SPRINTF_LEN]; 612 613 if (mdb_vread(&blk, sizeof (blkptr_t), addr) == -1) { 614 mdb_warn("failed to read blkptr_t"); 615 return (DCMD_ERR); 616 } 617 618 if (enum_lookup("enum dmu_object_type", BP_GET_TYPE(bp), "DMU_OT_", 619 sizeof (type), type) == -1 || 620 enum_lookup("enum zio_checksum", BP_GET_CHECKSUM(bp), 621 "ZIO_CHECKSUM_", sizeof (checksum), checksum) == -1 || 622 enum_lookup("enum zio_compress", BP_GET_COMPRESS(bp), 623 "ZIO_COMPRESS_", sizeof (compress), compress) == -1) { 624 mdb_warn("Could not find blkptr enumerated types"); 625 return (DCMD_ERR); 626 } 627 628 SNPRINTF_BLKPTR(mdb_snprintf, '\n', buf, sizeof (buf), bp, type, 629 checksum, compress); 630 631 mdb_printf("%s\n", buf); 632 633 return (DCMD_OK); 634 } 635 636 typedef struct mdb_dmu_buf_impl { 637 struct { 638 uint64_t db_object; 639 uintptr_t db_data; 640 } db; 641 uintptr_t db_objset; 642 uint64_t db_level; 643 uint64_t db_blkid; 644 struct { 645 uint64_t rc_count; 646 } db_holds; 647 } mdb_dmu_buf_impl_t; 648 649 /* ARGSUSED */ 650 static int 651 dbuf(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 652 { 653 mdb_dmu_buf_impl_t db; 654 char objectname[32]; 655 char blkidname[32]; 656 char path[ZFS_MAX_DATASET_NAME_LEN]; 657 int ptr_width = (int)(sizeof (void *)) * 2; 658 659 if (DCMD_HDRSPEC(flags)) 660 mdb_printf("%*s %8s %3s %9s %5s %s\n", 661 ptr_width, "addr", "object", "lvl", "blkid", "holds", "os"); 662 663 if (mdb_ctf_vread(&db, ZFS_STRUCT "dmu_buf_impl", "mdb_dmu_buf_impl_t", 664 addr, 0) == -1) 665 return (DCMD_ERR); 666 667 if (db.db.db_object == DMU_META_DNODE_OBJECT) 668 (void) strcpy(objectname, "mdn"); 669 else 670 (void) mdb_snprintf(objectname, sizeof (objectname), "%llx", 671 (u_longlong_t)db.db.db_object); 672 673 if (db.db_blkid == DMU_BONUS_BLKID) 674 (void) strcpy(blkidname, "bonus"); 675 else 676 (void) mdb_snprintf(blkidname, sizeof (blkidname), "%llx", 677 (u_longlong_t)db.db_blkid); 678 679 if (objset_name(db.db_objset, path)) { 680 return (DCMD_ERR); 681 } 682 683 mdb_printf("%*p %8s %3u %9s %5llu %s\n", ptr_width, addr, 684 objectname, (int)db.db_level, blkidname, 685 db.db_holds.rc_count, path); 686 687 return (DCMD_OK); 688 } 689 690 /* ARGSUSED */ 691 static int 692 dbuf_stats(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 693 { 694 #define HISTOSZ 32 695 uintptr_t dbp; 696 dmu_buf_impl_t db; 697 dbuf_hash_table_t ht; 698 uint64_t bucket, ndbufs; 699 uint64_t histo[HISTOSZ]; 700 uint64_t histo2[HISTOSZ]; 701 int i, maxidx; 702 703 if (mdb_readvar(&ht, "dbuf_hash_table") == -1) { 704 mdb_warn("failed to read 'dbuf_hash_table'"); 705 return (DCMD_ERR); 706 } 707 708 for (i = 0; i < HISTOSZ; i++) { 709 histo[i] = 0; 710 histo2[i] = 0; 711 } 712 713 ndbufs = 0; 714 for (bucket = 0; bucket < ht.hash_table_mask+1; bucket++) { 715 int len; 716 717 if (mdb_vread(&dbp, sizeof (void *), 718 (uintptr_t)(ht.hash_table+bucket)) == -1) { 719 mdb_warn("failed to read hash bucket %u at %p", 720 bucket, ht.hash_table+bucket); 721 return (DCMD_ERR); 722 } 723 724 len = 0; 725 while (dbp != 0) { 726 if (mdb_vread(&db, sizeof (dmu_buf_impl_t), 727 dbp) == -1) { 728 mdb_warn("failed to read dbuf at %p", dbp); 729 return (DCMD_ERR); 730 } 731 dbp = (uintptr_t)db.db_hash_next; 732 for (i = MIN(len, HISTOSZ - 1); i >= 0; i--) 733 histo2[i]++; 734 len++; 735 ndbufs++; 736 } 737 738 if (len >= HISTOSZ) 739 len = HISTOSZ-1; 740 histo[len]++; 741 } 742 743 mdb_printf("hash table has %llu buckets, %llu dbufs " 744 "(avg %llu buckets/dbuf)\n", 745 ht.hash_table_mask+1, ndbufs, 746 (ht.hash_table_mask+1)/ndbufs); 747 748 mdb_printf("\n"); 749 maxidx = 0; 750 for (i = 0; i < HISTOSZ; i++) 751 if (histo[i] > 0) 752 maxidx = i; 753 mdb_printf("hash chain length number of buckets\n"); 754 for (i = 0; i <= maxidx; i++) 755 mdb_printf("%u %llu\n", i, histo[i]); 756 757 mdb_printf("\n"); 758 maxidx = 0; 759 for (i = 0; i < HISTOSZ; i++) 760 if (histo2[i] > 0) 761 maxidx = i; 762 mdb_printf("hash chain depth number of dbufs\n"); 763 for (i = 0; i <= maxidx; i++) 764 mdb_printf("%u or more %llu %llu%%\n", 765 i, histo2[i], histo2[i]*100/ndbufs); 766 767 768 return (DCMD_OK); 769 } 770 771 #define CHAIN_END 0xffff 772 /* 773 * ::zap_leaf [-v] 774 * 775 * Print a zap_leaf_phys_t, assumed to be 16k 776 */ 777 /* ARGSUSED */ 778 static int 779 zap_leaf(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 780 { 781 char buf[16*1024]; 782 int verbose = B_FALSE; 783 int four = B_FALSE; 784 dmu_buf_t l_dbuf; 785 zap_leaf_t l; 786 zap_leaf_phys_t *zlp = (void *)buf; 787 int i; 788 789 if (mdb_getopts(argc, argv, 790 'v', MDB_OPT_SETBITS, TRUE, &verbose, 791 '4', MDB_OPT_SETBITS, TRUE, &four, 792 NULL) != argc) 793 return (DCMD_USAGE); 794 795 l_dbuf.db_data = zlp; 796 l.l_dbuf = &l_dbuf; 797 l.l_bs = 14; /* assume 16k blocks */ 798 if (four) 799 l.l_bs = 12; 800 801 if (!(flags & DCMD_ADDRSPEC)) { 802 return (DCMD_USAGE); 803 } 804 805 if (mdb_vread(buf, sizeof (buf), addr) == -1) { 806 mdb_warn("failed to read zap_leaf_phys_t at %p", addr); 807 return (DCMD_ERR); 808 } 809 810 if (zlp->l_hdr.lh_block_type != ZBT_LEAF || 811 zlp->l_hdr.lh_magic != ZAP_LEAF_MAGIC) { 812 mdb_warn("This does not appear to be a zap_leaf_phys_t"); 813 return (DCMD_ERR); 814 } 815 816 mdb_printf("zap_leaf_phys_t at %p:\n", addr); 817 mdb_printf(" lh_prefix_len = %u\n", zlp->l_hdr.lh_prefix_len); 818 mdb_printf(" lh_prefix = %llx\n", zlp->l_hdr.lh_prefix); 819 mdb_printf(" lh_nentries = %u\n", zlp->l_hdr.lh_nentries); 820 mdb_printf(" lh_nfree = %u\n", zlp->l_hdr.lh_nfree, 821 zlp->l_hdr.lh_nfree * 100 / (ZAP_LEAF_NUMCHUNKS(&l))); 822 mdb_printf(" lh_freelist = %u\n", zlp->l_hdr.lh_freelist); 823 mdb_printf(" lh_flags = %x (%s)\n", zlp->l_hdr.lh_flags, 824 zlp->l_hdr.lh_flags & ZLF_ENTRIES_CDSORTED ? 825 "ENTRIES_CDSORTED" : ""); 826 827 if (verbose) { 828 mdb_printf(" hash table:\n"); 829 for (i = 0; i < ZAP_LEAF_HASH_NUMENTRIES(&l); i++) { 830 if (zlp->l_hash[i] != CHAIN_END) 831 mdb_printf(" %u: %u\n", i, zlp->l_hash[i]); 832 } 833 } 834 835 mdb_printf(" chunks:\n"); 836 for (i = 0; i < ZAP_LEAF_NUMCHUNKS(&l); i++) { 837 /* LINTED: alignment */ 838 zap_leaf_chunk_t *zlc = &ZAP_LEAF_CHUNK(&l, i); 839 switch (zlc->l_entry.le_type) { 840 case ZAP_CHUNK_FREE: 841 if (verbose) { 842 mdb_printf(" %u: free; lf_next = %u\n", 843 i, zlc->l_free.lf_next); 844 } 845 break; 846 case ZAP_CHUNK_ENTRY: 847 mdb_printf(" %u: entry\n", i); 848 if (verbose) { 849 mdb_printf(" le_next = %u\n", 850 zlc->l_entry.le_next); 851 } 852 mdb_printf(" le_name_chunk = %u\n", 853 zlc->l_entry.le_name_chunk); 854 mdb_printf(" le_name_numints = %u\n", 855 zlc->l_entry.le_name_numints); 856 mdb_printf(" le_value_chunk = %u\n", 857 zlc->l_entry.le_value_chunk); 858 mdb_printf(" le_value_intlen = %u\n", 859 zlc->l_entry.le_value_intlen); 860 mdb_printf(" le_value_numints = %u\n", 861 zlc->l_entry.le_value_numints); 862 mdb_printf(" le_cd = %u\n", 863 zlc->l_entry.le_cd); 864 mdb_printf(" le_hash = %llx\n", 865 zlc->l_entry.le_hash); 866 break; 867 case ZAP_CHUNK_ARRAY: 868 mdb_printf(" %u: array", i); 869 if (strisprint((char *)zlc->l_array.la_array)) 870 mdb_printf(" \"%s\"", zlc->l_array.la_array); 871 mdb_printf("\n"); 872 if (verbose) { 873 int j; 874 mdb_printf(" "); 875 for (j = 0; j < ZAP_LEAF_ARRAY_BYTES; j++) { 876 mdb_printf("%02x ", 877 zlc->l_array.la_array[j]); 878 } 879 mdb_printf("\n"); 880 } 881 if (zlc->l_array.la_next != CHAIN_END) { 882 mdb_printf(" lf_next = %u\n", 883 zlc->l_array.la_next); 884 } 885 break; 886 default: 887 mdb_printf(" %u: undefined type %u\n", 888 zlc->l_entry.le_type); 889 } 890 } 891 892 return (DCMD_OK); 893 } 894 895 typedef struct dbufs_data { 896 mdb_ctf_id_t id; 897 uint64_t objset; 898 uint64_t object; 899 uint64_t level; 900 uint64_t blkid; 901 char *osname; 902 } dbufs_data_t; 903 904 #define DBUFS_UNSET (0xbaddcafedeadbeefULL) 905 906 /* ARGSUSED */ 907 static int 908 dbufs_cb(uintptr_t addr, const void *unknown, void *arg) 909 { 910 dbufs_data_t *data = arg; 911 uintptr_t objset; 912 dmu_buf_t db; 913 uint8_t level; 914 uint64_t blkid; 915 char osname[ZFS_MAX_DATASET_NAME_LEN]; 916 917 if (GETMEMBID(addr, &data->id, db_objset, objset) || 918 GETMEMBID(addr, &data->id, db, db) || 919 GETMEMBID(addr, &data->id, db_level, level) || 920 GETMEMBID(addr, &data->id, db_blkid, blkid)) { 921 return (WALK_ERR); 922 } 923 924 if ((data->objset == DBUFS_UNSET || data->objset == objset) && 925 (data->osname == NULL || (objset_name(objset, osname) == 0 && 926 strcmp(data->osname, osname) == 0)) && 927 (data->object == DBUFS_UNSET || data->object == db.db_object) && 928 (data->level == DBUFS_UNSET || data->level == level) && 929 (data->blkid == DBUFS_UNSET || data->blkid == blkid)) { 930 mdb_printf("%#lr\n", addr); 931 } 932 return (WALK_NEXT); 933 } 934 935 /* ARGSUSED */ 936 static int 937 dbufs(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 938 { 939 dbufs_data_t data; 940 char *object = NULL; 941 char *blkid = NULL; 942 943 data.objset = data.object = data.level = data.blkid = DBUFS_UNSET; 944 data.osname = NULL; 945 946 if (mdb_getopts(argc, argv, 947 'O', MDB_OPT_UINT64, &data.objset, 948 'n', MDB_OPT_STR, &data.osname, 949 'o', MDB_OPT_STR, &object, 950 'l', MDB_OPT_UINT64, &data.level, 951 'b', MDB_OPT_STR, &blkid) != argc) { 952 return (DCMD_USAGE); 953 } 954 955 if (object) { 956 if (strcmp(object, "mdn") == 0) { 957 data.object = DMU_META_DNODE_OBJECT; 958 } else { 959 data.object = mdb_strtoull(object); 960 } 961 } 962 963 if (blkid) { 964 if (strcmp(blkid, "bonus") == 0) { 965 data.blkid = DMU_BONUS_BLKID; 966 } else { 967 data.blkid = mdb_strtoull(blkid); 968 } 969 } 970 971 if (mdb_ctf_lookup_by_name(ZFS_STRUCT "dmu_buf_impl", &data.id) == -1) { 972 mdb_warn("couldn't find struct dmu_buf_impl_t"); 973 return (DCMD_ERR); 974 } 975 976 if (mdb_walk("dmu_buf_impl_t", dbufs_cb, &data) != 0) { 977 mdb_warn("can't walk dbufs"); 978 return (DCMD_ERR); 979 } 980 981 return (DCMD_OK); 982 } 983 984 typedef struct abuf_find_data { 985 dva_t dva; 986 mdb_ctf_id_t id; 987 } abuf_find_data_t; 988 989 /* ARGSUSED */ 990 static int 991 abuf_find_cb(uintptr_t addr, const void *unknown, void *arg) 992 { 993 abuf_find_data_t *data = arg; 994 dva_t dva; 995 996 if (GETMEMBID(addr, &data->id, b_dva, dva)) { 997 return (WALK_ERR); 998 } 999 1000 if (dva.dva_word[0] == data->dva.dva_word[0] && 1001 dva.dva_word[1] == data->dva.dva_word[1]) { 1002 mdb_printf("%#lr\n", addr); 1003 } 1004 return (WALK_NEXT); 1005 } 1006 1007 /* ARGSUSED */ 1008 static int 1009 abuf_find(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 1010 { 1011 abuf_find_data_t data; 1012 GElf_Sym sym; 1013 int i; 1014 const char *syms[] = { 1015 "ARC_mru", 1016 "ARC_mru_ghost", 1017 "ARC_mfu", 1018 "ARC_mfu_ghost", 1019 }; 1020 1021 if (argc != 2) 1022 return (DCMD_USAGE); 1023 1024 for (i = 0; i < 2; i ++) { 1025 switch (argv[i].a_type) { 1026 case MDB_TYPE_STRING: 1027 data.dva.dva_word[i] = mdb_strtoull(argv[i].a_un.a_str); 1028 break; 1029 case MDB_TYPE_IMMEDIATE: 1030 data.dva.dva_word[i] = argv[i].a_un.a_val; 1031 break; 1032 default: 1033 return (DCMD_USAGE); 1034 } 1035 } 1036 1037 if (mdb_ctf_lookup_by_name(ZFS_STRUCT "arc_buf_hdr", &data.id) == -1) { 1038 mdb_warn("couldn't find struct arc_buf_hdr"); 1039 return (DCMD_ERR); 1040 } 1041 1042 for (i = 0; i < sizeof (syms) / sizeof (syms[0]); i++) { 1043 if (mdb_lookup_by_obj(ZFS_OBJ_NAME, syms[i], &sym)) { 1044 mdb_warn("can't find symbol %s", syms[i]); 1045 return (DCMD_ERR); 1046 } 1047 1048 if (mdb_pwalk("list", abuf_find_cb, &data, sym.st_value) != 0) { 1049 mdb_warn("can't walk %s", syms[i]); 1050 return (DCMD_ERR); 1051 } 1052 } 1053 1054 return (DCMD_OK); 1055 } 1056 1057 1058 typedef struct dbgmsg_arg { 1059 boolean_t da_verbose; 1060 boolean_t da_address; 1061 } dbgmsg_arg_t; 1062 1063 /* ARGSUSED */ 1064 static int 1065 dbgmsg_cb(uintptr_t addr, const void *unknown, void *arg) 1066 { 1067 static mdb_ctf_id_t id; 1068 static boolean_t gotid; 1069 static ulong_t off; 1070 1071 dbgmsg_arg_t *da = arg; 1072 time_t timestamp; 1073 char buf[1024]; 1074 1075 if (!gotid) { 1076 if (mdb_ctf_lookup_by_name(ZFS_STRUCT "zfs_dbgmsg", &id) == 1077 -1) { 1078 mdb_warn("couldn't find struct zfs_dbgmsg"); 1079 return (WALK_ERR); 1080 } 1081 gotid = TRUE; 1082 if (mdb_ctf_offsetof(id, "zdm_msg", &off) == -1) { 1083 mdb_warn("couldn't find zdm_msg"); 1084 return (WALK_ERR); 1085 } 1086 off /= 8; 1087 } 1088 1089 1090 if (GETMEMBID(addr, &id, zdm_timestamp, timestamp)) { 1091 return (WALK_ERR); 1092 } 1093 1094 if (mdb_readstr(buf, sizeof (buf), addr + off) == -1) { 1095 mdb_warn("failed to read zdm_msg at %p\n", addr + off); 1096 return (DCMD_ERR); 1097 } 1098 1099 if (da->da_address) 1100 mdb_printf("%p ", addr); 1101 if (da->da_verbose) 1102 mdb_printf("%Y ", timestamp); 1103 1104 mdb_printf("%s\n", buf); 1105 1106 if (da->da_verbose) 1107 (void) mdb_call_dcmd("whatis", addr, DCMD_ADDRSPEC, 0, NULL); 1108 1109 return (WALK_NEXT); 1110 } 1111 1112 /* ARGSUSED */ 1113 static int 1114 dbgmsg(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 1115 { 1116 GElf_Sym sym; 1117 dbgmsg_arg_t da = { 0 }; 1118 1119 if (mdb_getopts(argc, argv, 1120 'v', MDB_OPT_SETBITS, B_TRUE, &da.da_verbose, 1121 'a', MDB_OPT_SETBITS, B_TRUE, &da.da_address, 1122 NULL) != argc) 1123 return (DCMD_USAGE); 1124 1125 if (mdb_lookup_by_obj(ZFS_OBJ_NAME, "zfs_dbgmsgs", &sym)) { 1126 mdb_warn("can't find zfs_dbgmsgs"); 1127 return (DCMD_ERR); 1128 } 1129 1130 if (mdb_pwalk("list", dbgmsg_cb, &da, sym.st_value) != 0) { 1131 mdb_warn("can't walk zfs_dbgmsgs"); 1132 return (DCMD_ERR); 1133 } 1134 1135 return (DCMD_OK); 1136 } 1137 1138 /*ARGSUSED*/ 1139 static int 1140 arc_print(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 1141 { 1142 kstat_named_t *stats; 1143 GElf_Sym sym; 1144 int nstats, i; 1145 uint_t opt_a = FALSE; 1146 uint_t opt_b = FALSE; 1147 uint_t shift = 0; 1148 const char *suffix; 1149 1150 static const char *bytestats[] = { 1151 "p", "c", "c_min", "c_max", "size", "duplicate_buffers_size", 1152 "arc_meta_used", "arc_meta_limit", "arc_meta_max", 1153 "arc_meta_min", "hdr_size", "data_size", "metadata_size", 1154 "other_size", "anon_size", "anon_evictable_data", 1155 "anon_evictable_metadata", "mru_size", "mru_evictable_data", 1156 "mru_evictable_metadata", "mru_ghost_size", 1157 "mru_ghost_evictable_data", "mru_ghost_evictable_metadata", 1158 "mfu_size", "mfu_evictable_data", "mfu_evictable_metadata", 1159 "mfu_ghost_size", "mfu_ghost_evictable_data", 1160 "mfu_ghost_evictable_metadata", "evict_l2_cached", 1161 "evict_l2_eligible", "evict_l2_ineligible", "l2_read_bytes", 1162 "l2_write_bytes", "l2_size", "l2_asize", "l2_hdr_size", 1163 "compressed_size", "uncompressed_size", "overhead_size", 1164 NULL 1165 }; 1166 1167 static const char *extras[] = { 1168 "arc_no_grow", "arc_tempreserve", 1169 NULL 1170 }; 1171 1172 if (mdb_lookup_by_obj(ZFS_OBJ_NAME, "arc_stats", &sym) == -1) { 1173 mdb_warn("failed to find 'arc_stats'"); 1174 return (DCMD_ERR); 1175 } 1176 1177 stats = mdb_zalloc(sym.st_size, UM_SLEEP | UM_GC); 1178 1179 if (mdb_vread(stats, sym.st_size, sym.st_value) == -1) { 1180 mdb_warn("couldn't read 'arc_stats' at %p", sym.st_value); 1181 return (DCMD_ERR); 1182 } 1183 1184 nstats = sym.st_size / sizeof (kstat_named_t); 1185 1186 /* NB: -a / opt_a are ignored for backwards compatability */ 1187 if (mdb_getopts(argc, argv, 1188 'a', MDB_OPT_SETBITS, TRUE, &opt_a, 1189 'b', MDB_OPT_SETBITS, TRUE, &opt_b, 1190 'k', MDB_OPT_SETBITS, 10, &shift, 1191 'm', MDB_OPT_SETBITS, 20, &shift, 1192 'g', MDB_OPT_SETBITS, 30, &shift, 1193 NULL) != argc) 1194 return (DCMD_USAGE); 1195 1196 if (!opt_b && !shift) 1197 shift = 20; 1198 1199 switch (shift) { 1200 case 0: 1201 suffix = "B"; 1202 break; 1203 case 10: 1204 suffix = "KB"; 1205 break; 1206 case 20: 1207 suffix = "MB"; 1208 break; 1209 case 30: 1210 suffix = "GB"; 1211 break; 1212 default: 1213 suffix = "XX"; 1214 } 1215 1216 for (i = 0; i < nstats; i++) { 1217 int j; 1218 boolean_t bytes = B_FALSE; 1219 1220 for (j = 0; bytestats[j]; j++) { 1221 if (strcmp(stats[i].name, bytestats[j]) == 0) { 1222 bytes = B_TRUE; 1223 break; 1224 } 1225 } 1226 1227 if (bytes) { 1228 mdb_printf("%-25s = %9llu %s\n", stats[i].name, 1229 stats[i].value.ui64 >> shift, suffix); 1230 } else { 1231 mdb_printf("%-25s = %9llu\n", stats[i].name, 1232 stats[i].value.ui64); 1233 } 1234 } 1235 1236 for (i = 0; extras[i]; i++) { 1237 uint64_t buf; 1238 1239 if (mdb_lookup_by_obj(ZFS_OBJ_NAME, extras[i], &sym) == -1) { 1240 mdb_warn("failed to find '%s'", extras[i]); 1241 return (DCMD_ERR); 1242 } 1243 1244 if (sym.st_size != sizeof (uint64_t) && 1245 sym.st_size != sizeof (uint32_t)) { 1246 mdb_warn("expected scalar for variable '%s'\n", 1247 extras[i]); 1248 return (DCMD_ERR); 1249 } 1250 1251 if (mdb_vread(&buf, sym.st_size, sym.st_value) == -1) { 1252 mdb_warn("couldn't read '%s'", extras[i]); 1253 return (DCMD_ERR); 1254 } 1255 1256 mdb_printf("%-25s = ", extras[i]); 1257 1258 /* NB: all the 64-bit extras happen to be byte counts */ 1259 if (sym.st_size == sizeof (uint64_t)) 1260 mdb_printf("%9llu %s\n", buf >> shift, suffix); 1261 1262 if (sym.st_size == sizeof (uint32_t)) 1263 mdb_printf("%9d\n", *((uint32_t *)&buf)); 1264 } 1265 return (DCMD_OK); 1266 } 1267 1268 typedef struct mdb_spa_print { 1269 pool_state_t spa_state; 1270 char spa_name[ZFS_MAX_DATASET_NAME_LEN]; 1271 uintptr_t spa_normal_class; 1272 } mdb_spa_print_t; 1273 1274 1275 const char histo_stars[] = "****************************************"; 1276 const int histo_width = sizeof (histo_stars) - 1; 1277 1278 static void 1279 dump_histogram(const uint64_t *histo, int size, int offset) 1280 { 1281 int i; 1282 int minidx = size - 1; 1283 int maxidx = 0; 1284 uint64_t max = 0; 1285 1286 for (i = 0; i < size; i++) { 1287 if (histo[i] > max) 1288 max = histo[i]; 1289 if (histo[i] > 0 && i > maxidx) 1290 maxidx = i; 1291 if (histo[i] > 0 && i < minidx) 1292 minidx = i; 1293 } 1294 1295 if (max < histo_width) 1296 max = histo_width; 1297 1298 for (i = minidx; i <= maxidx; i++) { 1299 mdb_printf("%3u: %6llu %s\n", 1300 i + offset, (u_longlong_t)histo[i], 1301 &histo_stars[(max - histo[i]) * histo_width / max]); 1302 } 1303 } 1304 1305 typedef struct mdb_metaslab_class { 1306 uint64_t mc_histogram[RANGE_TREE_HISTOGRAM_SIZE]; 1307 } mdb_metaslab_class_t; 1308 1309 /* 1310 * spa_class_histogram(uintptr_t class_addr) 1311 * 1312 * Prints free space histogram for a device class 1313 * 1314 * Returns DCMD_OK, or DCMD_ERR. 1315 */ 1316 static int 1317 spa_class_histogram(uintptr_t class_addr) 1318 { 1319 mdb_metaslab_class_t mc; 1320 if (mdb_ctf_vread(&mc, "metaslab_class_t", 1321 "mdb_metaslab_class_t", class_addr, 0) == -1) 1322 return (DCMD_ERR); 1323 1324 mdb_inc_indent(4); 1325 dump_histogram(mc.mc_histogram, RANGE_TREE_HISTOGRAM_SIZE, 0); 1326 mdb_dec_indent(4); 1327 return (DCMD_OK); 1328 } 1329 1330 /* 1331 * ::spa 1332 * 1333 * -c Print configuration information as well 1334 * -v Print vdev state 1335 * -e Print vdev error stats 1336 * -m Print vdev metaslab info 1337 * -M print vdev metaslab group info 1338 * -h Print histogram info (must be combined with -m or -M) 1339 * 1340 * Print a summarized spa_t. When given no arguments, prints out a table of all 1341 * active pools on the system. 1342 */ 1343 /* ARGSUSED */ 1344 static int 1345 spa_print(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 1346 { 1347 const char *statetab[] = { "ACTIVE", "EXPORTED", "DESTROYED", 1348 "SPARE", "L2CACHE", "UNINIT", "UNAVAIL", "POTENTIAL" }; 1349 const char *state; 1350 int spa_flags = 0; 1351 1352 if (mdb_getopts(argc, argv, 1353 'c', MDB_OPT_SETBITS, SPA_FLAG_CONFIG, &spa_flags, 1354 'v', MDB_OPT_SETBITS, SPA_FLAG_VDEVS, &spa_flags, 1355 'e', MDB_OPT_SETBITS, SPA_FLAG_ERRORS, &spa_flags, 1356 'M', MDB_OPT_SETBITS, SPA_FLAG_METASLAB_GROUPS, &spa_flags, 1357 'm', MDB_OPT_SETBITS, SPA_FLAG_METASLABS, &spa_flags, 1358 'h', MDB_OPT_SETBITS, SPA_FLAG_HISTOGRAMS, &spa_flags, 1359 NULL) != argc) 1360 return (DCMD_USAGE); 1361 1362 if (!(flags & DCMD_ADDRSPEC)) { 1363 if (mdb_walk_dcmd("spa", "spa", argc, argv) == -1) { 1364 mdb_warn("can't walk spa"); 1365 return (DCMD_ERR); 1366 } 1367 1368 return (DCMD_OK); 1369 } 1370 1371 if (flags & DCMD_PIPE_OUT) { 1372 mdb_printf("%#lr\n", addr); 1373 return (DCMD_OK); 1374 } 1375 1376 if (DCMD_HDRSPEC(flags)) 1377 mdb_printf("%<u>%-?s %9s %-*s%</u>\n", "ADDR", "STATE", 1378 sizeof (uintptr_t) == 4 ? 60 : 52, "NAME"); 1379 1380 mdb_spa_print_t spa; 1381 if (mdb_ctf_vread(&spa, "spa_t", "mdb_spa_print_t", addr, 0) == -1) 1382 return (DCMD_ERR); 1383 1384 if (spa.spa_state < 0 || spa.spa_state > POOL_STATE_UNAVAIL) 1385 state = "UNKNOWN"; 1386 else 1387 state = statetab[spa.spa_state]; 1388 1389 mdb_printf("%0?p %9s %s\n", addr, state, spa.spa_name); 1390 if (spa_flags & SPA_FLAG_HISTOGRAMS) 1391 spa_class_histogram(spa.spa_normal_class); 1392 1393 if (spa_flags & SPA_FLAG_CONFIG) { 1394 mdb_printf("\n"); 1395 mdb_inc_indent(4); 1396 if (mdb_call_dcmd("spa_config", addr, flags, 0, 1397 NULL) != DCMD_OK) 1398 return (DCMD_ERR); 1399 mdb_dec_indent(4); 1400 } 1401 1402 if (spa_flags & SPA_FLAG_ALL_VDEV) { 1403 mdb_arg_t v; 1404 char opts[100] = "-"; 1405 int args = 1406 (spa_flags | SPA_FLAG_VDEVS) == SPA_FLAG_VDEVS ? 0 : 1; 1407 1408 if (spa_flags & SPA_FLAG_ERRORS) 1409 strcat(opts, "e"); 1410 if (spa_flags & SPA_FLAG_METASLABS) 1411 strcat(opts, "m"); 1412 if (spa_flags & SPA_FLAG_METASLAB_GROUPS) 1413 strcat(opts, "M"); 1414 if (spa_flags & SPA_FLAG_HISTOGRAMS) 1415 strcat(opts, "h"); 1416 1417 v.a_type = MDB_TYPE_STRING; 1418 v.a_un.a_str = opts; 1419 1420 mdb_printf("\n"); 1421 mdb_inc_indent(4); 1422 if (mdb_call_dcmd("spa_vdevs", addr, flags, args, 1423 &v) != DCMD_OK) 1424 return (DCMD_ERR); 1425 mdb_dec_indent(4); 1426 } 1427 1428 return (DCMD_OK); 1429 } 1430 1431 typedef struct mdb_spa_config_spa { 1432 uintptr_t spa_config; 1433 } mdb_spa_config_spa_t; 1434 1435 /* 1436 * ::spa_config 1437 * 1438 * Given a spa_t, print the configuration information stored in spa_config. 1439 * Since it's just an nvlist, format it as an indented list of name=value pairs. 1440 * We simply read the value of spa_config and pass off to ::nvlist. 1441 */ 1442 /* ARGSUSED */ 1443 static int 1444 spa_print_config(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 1445 { 1446 mdb_spa_config_spa_t spa; 1447 1448 if (argc != 0 || !(flags & DCMD_ADDRSPEC)) 1449 return (DCMD_USAGE); 1450 1451 if (mdb_ctf_vread(&spa, ZFS_STRUCT "spa", "mdb_spa_config_spa_t", 1452 addr, 0) == -1) 1453 return (DCMD_ERR); 1454 1455 if (spa.spa_config == 0) { 1456 mdb_printf("(none)\n"); 1457 return (DCMD_OK); 1458 } 1459 1460 return (mdb_call_dcmd("nvlist", spa.spa_config, flags, 1461 0, NULL)); 1462 } 1463 1464 1465 1466 typedef struct mdb_range_tree { 1467 struct { 1468 uint64_t avl_numnodes; 1469 } rt_root; 1470 uint64_t rt_space; 1471 } mdb_range_tree_t; 1472 1473 typedef struct mdb_metaslab_group { 1474 uint64_t mg_fragmentation; 1475 uint64_t mg_histogram[RANGE_TREE_HISTOGRAM_SIZE]; 1476 uintptr_t mg_vd; 1477 } mdb_metaslab_group_t; 1478 1479 typedef struct mdb_metaslab { 1480 uint64_t ms_id; 1481 uint64_t ms_start; 1482 uint64_t ms_size; 1483 int64_t ms_deferspace; 1484 uint64_t ms_fragmentation; 1485 uint64_t ms_weight; 1486 uintptr_t ms_allocating[TXG_SIZE]; 1487 uintptr_t ms_checkpointing; 1488 uintptr_t ms_freeing; 1489 uintptr_t ms_freed; 1490 uintptr_t ms_allocatable; 1491 uintptr_t ms_unflushed_frees; 1492 uintptr_t ms_unflushed_allocs; 1493 uintptr_t ms_sm; 1494 } mdb_metaslab_t; 1495 1496 typedef struct mdb_space_map_phys_t { 1497 int64_t smp_alloc; 1498 uint64_t smp_histogram[SPACE_MAP_HISTOGRAM_SIZE]; 1499 } mdb_space_map_phys_t; 1500 1501 typedef struct mdb_space_map { 1502 uint64_t sm_size; 1503 uint8_t sm_shift; 1504 uintptr_t sm_phys; 1505 } mdb_space_map_t; 1506 1507 typedef struct mdb_vdev { 1508 uint64_t vdev_id; 1509 uint64_t vdev_state; 1510 uintptr_t vdev_ops; 1511 struct { 1512 uint64_t vs_aux; 1513 uint64_t vs_ops[VS_ZIO_TYPES]; 1514 uint64_t vs_bytes[VS_ZIO_TYPES]; 1515 uint64_t vs_read_errors; 1516 uint64_t vs_write_errors; 1517 uint64_t vs_checksum_errors; 1518 } vdev_stat; 1519 uintptr_t vdev_child; 1520 uint64_t vdev_children; 1521 uint64_t vdev_ms_count; 1522 uintptr_t vdev_mg; 1523 uintptr_t vdev_ms; 1524 uintptr_t vdev_path; 1525 } mdb_vdev_t; 1526 1527 typedef struct mdb_vdev_ops { 1528 char vdev_op_type[16]; 1529 } mdb_vdev_ops_t; 1530 1531 static int 1532 metaslab_stats(mdb_vdev_t *vd, int spa_flags) 1533 { 1534 mdb_inc_indent(4); 1535 mdb_printf("%<u>%-?s %6s %20s %10s %10s %10s%</u>\n", "ADDR", "ID", 1536 "OFFSET", "FREE", "FRAG", "UCMU"); 1537 1538 uintptr_t *vdev_ms = mdb_alloc(vd->vdev_ms_count * sizeof (vdev_ms), 1539 UM_SLEEP | UM_GC); 1540 if (mdb_vread(vdev_ms, vd->vdev_ms_count * sizeof (uintptr_t), 1541 vd->vdev_ms) == -1) { 1542 mdb_warn("failed to read vdev_ms at %p\n", vd->vdev_ms); 1543 return (DCMD_ERR); 1544 } 1545 1546 for (int m = 0; m < vd->vdev_ms_count; m++) { 1547 mdb_metaslab_t ms; 1548 mdb_space_map_t sm = { 0 }; 1549 mdb_space_map_phys_t smp = { 0 }; 1550 mdb_range_tree_t rt; 1551 uint64_t uallocs, ufrees, raw_free, raw_uchanges_mem; 1552 char free[MDB_NICENUM_BUFLEN]; 1553 char uchanges_mem[MDB_NICENUM_BUFLEN]; 1554 1555 if (mdb_ctf_vread(&ms, "metaslab_t", "mdb_metaslab_t", 1556 vdev_ms[m], 0) == -1) 1557 return (DCMD_ERR); 1558 1559 if (ms.ms_sm != 0 && 1560 mdb_ctf_vread(&sm, "space_map_t", "mdb_space_map_t", 1561 ms.ms_sm, 0) == -1) 1562 return (DCMD_ERR); 1563 1564 if (mdb_ctf_vread(&rt, "range_tree_t", "mdb_range_tree_t", 1565 ms.ms_unflushed_frees, 0) == -1) 1566 return (DCMD_ERR); 1567 ufrees = rt.rt_space; 1568 raw_uchanges_mem = rt.rt_root.avl_numnodes * 1569 mdb_ctf_sizeof_by_name("range_seg_t"); 1570 1571 if (mdb_ctf_vread(&rt, "range_tree_t", "mdb_range_tree_t", 1572 ms.ms_unflushed_allocs, 0) == -1) 1573 return (DCMD_ERR); 1574 uallocs = rt.rt_space; 1575 raw_uchanges_mem += rt.rt_root.avl_numnodes * 1576 mdb_ctf_sizeof_by_name("range_seg_t"); 1577 mdb_nicenum(raw_uchanges_mem, uchanges_mem); 1578 1579 raw_free = ms.ms_size; 1580 if (ms.ms_sm != 0 && sm.sm_phys != 0) { 1581 (void) mdb_ctf_vread(&smp, "space_map_phys_t", 1582 "mdb_space_map_phys_t", sm.sm_phys, 0); 1583 raw_free -= smp.smp_alloc; 1584 } 1585 raw_free += ufrees - uallocs; 1586 mdb_nicenum(raw_free, free); 1587 1588 mdb_printf("%0?p %6llu %20llx %10s ", vdev_ms[m], ms.ms_id, 1589 ms.ms_start, free); 1590 if (ms.ms_fragmentation == ZFS_FRAG_INVALID) 1591 mdb_printf("%9s ", "-"); 1592 else 1593 mdb_printf("%9llu%% ", ms.ms_fragmentation); 1594 mdb_printf("%10s\n", uchanges_mem); 1595 1596 if ((spa_flags & SPA_FLAG_HISTOGRAMS) && ms.ms_sm != 0 && 1597 sm.sm_phys != 0) { 1598 dump_histogram(smp.smp_histogram, 1599 SPACE_MAP_HISTOGRAM_SIZE, sm.sm_shift); 1600 } 1601 } 1602 mdb_dec_indent(4); 1603 return (DCMD_OK); 1604 } 1605 1606 static int 1607 metaslab_group_stats(mdb_vdev_t *vd, int spa_flags) 1608 { 1609 mdb_metaslab_group_t mg; 1610 if (mdb_ctf_vread(&mg, "metaslab_group_t", "mdb_metaslab_group_t", 1611 vd->vdev_mg, 0) == -1) { 1612 mdb_warn("failed to read vdev_mg at %p\n", vd->vdev_mg); 1613 return (DCMD_ERR); 1614 } 1615 1616 mdb_inc_indent(4); 1617 mdb_printf("%<u>%-?s %7s %9s%</u>\n", "ADDR", "FRAG", "UCMU"); 1618 1619 if (mg.mg_fragmentation == ZFS_FRAG_INVALID) 1620 mdb_printf("%0?p %6s\n", vd->vdev_mg, "-"); 1621 else 1622 mdb_printf("%0?p %6llu%%", vd->vdev_mg, mg.mg_fragmentation); 1623 1624 1625 uintptr_t *vdev_ms = mdb_alloc(vd->vdev_ms_count * sizeof (vdev_ms), 1626 UM_SLEEP | UM_GC); 1627 if (mdb_vread(vdev_ms, vd->vdev_ms_count * sizeof (uintptr_t), 1628 vd->vdev_ms) == -1) { 1629 mdb_warn("failed to read vdev_ms at %p\n", vd->vdev_ms); 1630 return (DCMD_ERR); 1631 } 1632 1633 uint64_t raw_uchanges_mem = 0; 1634 char uchanges_mem[MDB_NICENUM_BUFLEN]; 1635 for (int m = 0; m < vd->vdev_ms_count; m++) { 1636 mdb_metaslab_t ms; 1637 mdb_range_tree_t rt; 1638 1639 if (mdb_ctf_vread(&ms, "metaslab_t", "mdb_metaslab_t", 1640 vdev_ms[m], 0) == -1) 1641 return (DCMD_ERR); 1642 1643 if (mdb_ctf_vread(&rt, "range_tree_t", "mdb_range_tree_t", 1644 ms.ms_unflushed_frees, 0) == -1) 1645 return (DCMD_ERR); 1646 raw_uchanges_mem += 1647 rt.rt_root.avl_numnodes * sizeof (range_seg_t); 1648 1649 if (mdb_ctf_vread(&rt, "range_tree_t", "mdb_range_tree_t", 1650 ms.ms_unflushed_allocs, 0) == -1) 1651 return (DCMD_ERR); 1652 raw_uchanges_mem += 1653 rt.rt_root.avl_numnodes * sizeof (range_seg_t); 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 typedef struct mdb_multilist { 2672 uint64_t ml_num_sublists; 2673 uintptr_t ml_sublists; 2674 } mdb_multilist_t; 2675 2676 typedef struct multilist_walk_data { 2677 uint64_t mwd_idx; 2678 mdb_multilist_t mwd_ml; 2679 } multilist_walk_data_t; 2680 2681 /* ARGSUSED */ 2682 static int 2683 multilist_print_cb(uintptr_t addr, const void *unknown, void *arg) 2684 { 2685 mdb_printf("%#lr\n", addr); 2686 return (WALK_NEXT); 2687 } 2688 2689 static int 2690 multilist_walk_step(mdb_walk_state_t *wsp) 2691 { 2692 multilist_walk_data_t *mwd = wsp->walk_data; 2693 2694 if (mwd->mwd_idx >= mwd->mwd_ml.ml_num_sublists) 2695 return (WALK_DONE); 2696 2697 wsp->walk_addr = mwd->mwd_ml.ml_sublists + 2698 mdb_ctf_sizeof_by_name("multilist_sublist_t") * mwd->mwd_idx + 2699 mdb_ctf_offsetof_by_name("multilist_sublist_t", "mls_list"); 2700 2701 mdb_pwalk("list", multilist_print_cb, (void*)NULL, wsp->walk_addr); 2702 mwd->mwd_idx++; 2703 2704 return (WALK_NEXT); 2705 } 2706 2707 static int 2708 multilist_walk_init(mdb_walk_state_t *wsp) 2709 { 2710 multilist_walk_data_t *mwd; 2711 2712 if (wsp->walk_addr == 0) { 2713 mdb_warn("must supply address of multilist_t\n"); 2714 return (WALK_ERR); 2715 } 2716 2717 mwd = mdb_zalloc(sizeof (multilist_walk_data_t), UM_SLEEP | UM_GC); 2718 if (mdb_ctf_vread(&mwd->mwd_ml, "multilist_t", "mdb_multilist_t", 2719 wsp->walk_addr, 0) == -1) { 2720 return (WALK_ERR); 2721 } 2722 2723 if (mwd->mwd_ml.ml_num_sublists == 0 || 2724 mwd->mwd_ml.ml_sublists == 0) { 2725 mdb_warn("invalid or uninitialized multilist at %#lx\n", 2726 wsp->walk_addr); 2727 return (WALK_ERR); 2728 } 2729 2730 wsp->walk_data = mwd; 2731 return (WALK_NEXT); 2732 } 2733 2734 typedef struct mdb_txg_list { 2735 size_t tl_offset; 2736 uintptr_t tl_head[TXG_SIZE]; 2737 } mdb_txg_list_t; 2738 2739 typedef struct txg_list_walk_data { 2740 uintptr_t lw_head[TXG_SIZE]; 2741 int lw_txgoff; 2742 int lw_maxoff; 2743 size_t lw_offset; 2744 void *lw_obj; 2745 } txg_list_walk_data_t; 2746 2747 static int 2748 txg_list_walk_init_common(mdb_walk_state_t *wsp, int txg, int maxoff) 2749 { 2750 txg_list_walk_data_t *lwd; 2751 mdb_txg_list_t list; 2752 int i; 2753 2754 lwd = mdb_alloc(sizeof (txg_list_walk_data_t), UM_SLEEP | UM_GC); 2755 if (mdb_ctf_vread(&list, "txg_list_t", "mdb_txg_list_t", wsp->walk_addr, 2756 0) == -1) { 2757 mdb_warn("failed to read txg_list_t at %#lx", wsp->walk_addr); 2758 return (WALK_ERR); 2759 } 2760 2761 for (i = 0; i < TXG_SIZE; i++) 2762 lwd->lw_head[i] = list.tl_head[i]; 2763 lwd->lw_offset = list.tl_offset; 2764 lwd->lw_obj = mdb_alloc(lwd->lw_offset + sizeof (txg_node_t), 2765 UM_SLEEP | UM_GC); 2766 lwd->lw_txgoff = txg; 2767 lwd->lw_maxoff = maxoff; 2768 2769 wsp->walk_addr = lwd->lw_head[lwd->lw_txgoff]; 2770 wsp->walk_data = lwd; 2771 2772 return (WALK_NEXT); 2773 } 2774 2775 static int 2776 txg_list_walk_init(mdb_walk_state_t *wsp) 2777 { 2778 return (txg_list_walk_init_common(wsp, 0, TXG_SIZE-1)); 2779 } 2780 2781 static int 2782 txg_list0_walk_init(mdb_walk_state_t *wsp) 2783 { 2784 return (txg_list_walk_init_common(wsp, 0, 0)); 2785 } 2786 2787 static int 2788 txg_list1_walk_init(mdb_walk_state_t *wsp) 2789 { 2790 return (txg_list_walk_init_common(wsp, 1, 1)); 2791 } 2792 2793 static int 2794 txg_list2_walk_init(mdb_walk_state_t *wsp) 2795 { 2796 return (txg_list_walk_init_common(wsp, 2, 2)); 2797 } 2798 2799 static int 2800 txg_list3_walk_init(mdb_walk_state_t *wsp) 2801 { 2802 return (txg_list_walk_init_common(wsp, 3, 3)); 2803 } 2804 2805 static int 2806 txg_list_walk_step(mdb_walk_state_t *wsp) 2807 { 2808 txg_list_walk_data_t *lwd = wsp->walk_data; 2809 uintptr_t addr; 2810 txg_node_t *node; 2811 int status; 2812 2813 while (wsp->walk_addr == 0 && lwd->lw_txgoff < lwd->lw_maxoff) { 2814 lwd->lw_txgoff++; 2815 wsp->walk_addr = lwd->lw_head[lwd->lw_txgoff]; 2816 } 2817 2818 if (wsp->walk_addr == 0) 2819 return (WALK_DONE); 2820 2821 addr = wsp->walk_addr - lwd->lw_offset; 2822 2823 if (mdb_vread(lwd->lw_obj, 2824 lwd->lw_offset + sizeof (txg_node_t), addr) == -1) { 2825 mdb_warn("failed to read list element at %#lx", addr); 2826 return (WALK_ERR); 2827 } 2828 2829 status = wsp->walk_callback(addr, lwd->lw_obj, wsp->walk_cbdata); 2830 node = (txg_node_t *)((uintptr_t)lwd->lw_obj + lwd->lw_offset); 2831 wsp->walk_addr = (uintptr_t)node->tn_next[lwd->lw_txgoff]; 2832 2833 return (status); 2834 } 2835 2836 /* 2837 * ::walk spa 2838 * 2839 * Walk all named spa_t structures in the namespace. This is nothing more than 2840 * a layered avl walk. 2841 */ 2842 static int 2843 spa_walk_init(mdb_walk_state_t *wsp) 2844 { 2845 GElf_Sym sym; 2846 2847 if (wsp->walk_addr != 0) { 2848 mdb_warn("spa walk only supports global walks\n"); 2849 return (WALK_ERR); 2850 } 2851 2852 if (mdb_lookup_by_obj(ZFS_OBJ_NAME, "spa_namespace_avl", &sym) == -1) { 2853 mdb_warn("failed to find symbol 'spa_namespace_avl'"); 2854 return (WALK_ERR); 2855 } 2856 2857 wsp->walk_addr = (uintptr_t)sym.st_value; 2858 2859 if (mdb_layered_walk("avl", wsp) == -1) { 2860 mdb_warn("failed to walk 'avl'\n"); 2861 return (WALK_ERR); 2862 } 2863 2864 return (WALK_NEXT); 2865 } 2866 2867 static int 2868 spa_walk_step(mdb_walk_state_t *wsp) 2869 { 2870 return (wsp->walk_callback(wsp->walk_addr, NULL, wsp->walk_cbdata)); 2871 } 2872 2873 /* 2874 * [addr]::walk zio 2875 * 2876 * Walk all active zio_t structures on the system. This is simply a layered 2877 * walk on top of ::walk zio_cache, with the optional ability to limit the 2878 * structures to a particular pool. 2879 */ 2880 static int 2881 zio_walk_init(mdb_walk_state_t *wsp) 2882 { 2883 wsp->walk_data = (void *)wsp->walk_addr; 2884 2885 if (mdb_layered_walk("zio_cache", wsp) == -1) { 2886 mdb_warn("failed to walk 'zio_cache'\n"); 2887 return (WALK_ERR); 2888 } 2889 2890 return (WALK_NEXT); 2891 } 2892 2893 static int 2894 zio_walk_step(mdb_walk_state_t *wsp) 2895 { 2896 mdb_zio_t zio; 2897 uintptr_t spa = (uintptr_t)wsp->walk_data; 2898 2899 if (mdb_ctf_vread(&zio, ZFS_STRUCT "zio", "mdb_zio_t", 2900 wsp->walk_addr, 0) == -1) 2901 return (WALK_ERR); 2902 2903 if (spa != 0 && spa != zio.io_spa) 2904 return (WALK_NEXT); 2905 2906 return (wsp->walk_callback(wsp->walk_addr, &zio, wsp->walk_cbdata)); 2907 } 2908 2909 /* 2910 * [addr]::walk zio_root 2911 * 2912 * Walk only root zio_t structures, optionally for a particular spa_t. 2913 */ 2914 static int 2915 zio_walk_root_step(mdb_walk_state_t *wsp) 2916 { 2917 mdb_zio_t zio; 2918 uintptr_t spa = (uintptr_t)wsp->walk_data; 2919 2920 if (mdb_ctf_vread(&zio, ZFS_STRUCT "zio", "mdb_zio_t", 2921 wsp->walk_addr, 0) == -1) 2922 return (WALK_ERR); 2923 2924 if (spa != 0 && spa != zio.io_spa) 2925 return (WALK_NEXT); 2926 2927 /* If the parent list is not empty, ignore */ 2928 if (zio.io_parent_list.list_head.list_next != 2929 wsp->walk_addr + 2930 mdb_ctf_offsetof_by_name(ZFS_STRUCT "zio", "io_parent_list") + 2931 mdb_ctf_offsetof_by_name("struct list", "list_head")) 2932 return (WALK_NEXT); 2933 2934 return (wsp->walk_callback(wsp->walk_addr, &zio, wsp->walk_cbdata)); 2935 } 2936 2937 /* 2938 * ::zfs_blkstats 2939 * 2940 * -v print verbose per-level information 2941 * 2942 */ 2943 static int 2944 zfs_blkstats(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 2945 { 2946 boolean_t verbose = B_FALSE; 2947 zfs_all_blkstats_t stats; 2948 dmu_object_type_t t; 2949 zfs_blkstat_t *tzb; 2950 uint64_t ditto; 2951 2952 if (mdb_getopts(argc, argv, 2953 'v', MDB_OPT_SETBITS, TRUE, &verbose, 2954 NULL) != argc) 2955 return (DCMD_USAGE); 2956 2957 if (!(flags & DCMD_ADDRSPEC)) 2958 return (DCMD_USAGE); 2959 2960 if (GETMEMB(addr, "spa", spa_dsl_pool, addr) || 2961 GETMEMB(addr, "dsl_pool", dp_blkstats, addr) || 2962 mdb_vread(&stats, sizeof (zfs_all_blkstats_t), addr) == -1) { 2963 mdb_warn("failed to read data at %p;", addr); 2964 mdb_printf("maybe no stats? run \"zpool scrub\" first."); 2965 return (DCMD_ERR); 2966 } 2967 2968 tzb = &stats.zab_type[DN_MAX_LEVELS][DMU_OT_TOTAL]; 2969 if (tzb->zb_gangs != 0) { 2970 mdb_printf("Ganged blocks: %llu\n", 2971 (longlong_t)tzb->zb_gangs); 2972 } 2973 2974 ditto = tzb->zb_ditto_2_of_2_samevdev + tzb->zb_ditto_2_of_3_samevdev + 2975 tzb->zb_ditto_3_of_3_samevdev; 2976 if (ditto != 0) { 2977 mdb_printf("Dittoed blocks on same vdev: %llu\n", 2978 (longlong_t)ditto); 2979 } 2980 2981 mdb_printf("\nBlocks\tLSIZE\tPSIZE\tASIZE" 2982 "\t avg\t comp\t%%Total\tType\n"); 2983 2984 for (t = 0; t <= DMU_OT_TOTAL; t++) { 2985 char csize[MDB_NICENUM_BUFLEN], lsize[MDB_NICENUM_BUFLEN]; 2986 char psize[MDB_NICENUM_BUFLEN], asize[MDB_NICENUM_BUFLEN]; 2987 char avg[MDB_NICENUM_BUFLEN]; 2988 char comp[MDB_NICENUM_BUFLEN], pct[MDB_NICENUM_BUFLEN]; 2989 char typename[64]; 2990 int l; 2991 2992 2993 if (t == DMU_OT_DEFERRED) 2994 strcpy(typename, "deferred free"); 2995 else if (t == DMU_OT_OTHER) 2996 strcpy(typename, "other"); 2997 else if (t == DMU_OT_TOTAL) 2998 strcpy(typename, "Total"); 2999 else if (enum_lookup("enum dmu_object_type", 3000 t, "DMU_OT_", sizeof (typename), typename) == -1) { 3001 mdb_warn("failed to read type name"); 3002 return (DCMD_ERR); 3003 } 3004 3005 if (stats.zab_type[DN_MAX_LEVELS][t].zb_asize == 0) 3006 continue; 3007 3008 for (l = -1; l < DN_MAX_LEVELS; l++) { 3009 int level = (l == -1 ? DN_MAX_LEVELS : l); 3010 zfs_blkstat_t *zb = &stats.zab_type[level][t]; 3011 3012 if (zb->zb_asize == 0) 3013 continue; 3014 3015 /* 3016 * Don't print each level unless requested. 3017 */ 3018 if (!verbose && level != DN_MAX_LEVELS) 3019 continue; 3020 3021 /* 3022 * If all the space is level 0, don't print the 3023 * level 0 separately. 3024 */ 3025 if (level == 0 && zb->zb_asize == 3026 stats.zab_type[DN_MAX_LEVELS][t].zb_asize) 3027 continue; 3028 3029 mdb_nicenum(zb->zb_count, csize); 3030 mdb_nicenum(zb->zb_lsize, lsize); 3031 mdb_nicenum(zb->zb_psize, psize); 3032 mdb_nicenum(zb->zb_asize, asize); 3033 mdb_nicenum(zb->zb_asize / zb->zb_count, avg); 3034 (void) mdb_snprintfrac(comp, MDB_NICENUM_BUFLEN, 3035 zb->zb_lsize, zb->zb_psize, 2); 3036 (void) mdb_snprintfrac(pct, MDB_NICENUM_BUFLEN, 3037 100 * zb->zb_asize, tzb->zb_asize, 2); 3038 3039 mdb_printf("%6s\t%5s\t%5s\t%5s\t%5s" 3040 "\t%5s\t%6s\t", 3041 csize, lsize, psize, asize, avg, comp, pct); 3042 3043 if (level == DN_MAX_LEVELS) 3044 mdb_printf("%s\n", typename); 3045 else 3046 mdb_printf(" L%d %s\n", 3047 level, typename); 3048 } 3049 } 3050 3051 return (DCMD_OK); 3052 } 3053 3054 typedef struct mdb_reference { 3055 uintptr_t ref_holder; 3056 uintptr_t ref_removed; 3057 uint64_t ref_number; 3058 } mdb_reference_t; 3059 3060 /* ARGSUSED */ 3061 static int 3062 reference_cb(uintptr_t addr, const void *ignored, void *arg) 3063 { 3064 mdb_reference_t ref; 3065 boolean_t holder_is_str = B_FALSE; 3066 char holder_str[128]; 3067 boolean_t removed = (boolean_t)arg; 3068 3069 if (mdb_ctf_vread(&ref, "reference_t", "mdb_reference_t", addr, 3070 0) == -1) 3071 return (DCMD_ERR); 3072 3073 if (mdb_readstr(holder_str, sizeof (holder_str), 3074 ref.ref_holder) != -1) 3075 holder_is_str = strisprint(holder_str); 3076 3077 if (removed) 3078 mdb_printf("removed "); 3079 mdb_printf("reference "); 3080 if (ref.ref_number != 1) 3081 mdb_printf("with count=%llu ", ref.ref_number); 3082 mdb_printf("with tag %lx", ref.ref_holder); 3083 if (holder_is_str) 3084 mdb_printf(" \"%s\"", holder_str); 3085 mdb_printf(", held at:\n"); 3086 3087 (void) mdb_call_dcmd("whatis", addr, DCMD_ADDRSPEC, 0, NULL); 3088 3089 if (removed) { 3090 mdb_printf("removed at:\n"); 3091 (void) mdb_call_dcmd("whatis", ref.ref_removed, 3092 DCMD_ADDRSPEC, 0, NULL); 3093 } 3094 3095 mdb_printf("\n"); 3096 3097 return (WALK_NEXT); 3098 } 3099 3100 typedef struct mdb_refcount { 3101 uint64_t rc_count; 3102 } mdb_refcount_t; 3103 3104 typedef struct mdb_refcount_removed { 3105 uint64_t rc_removed_count; 3106 } mdb_refcount_removed_t; 3107 3108 typedef struct mdb_refcount_tracked { 3109 boolean_t rc_tracked; 3110 } mdb_refcount_tracked_t; 3111 3112 /* ARGSUSED */ 3113 static int 3114 refcount(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 3115 { 3116 mdb_refcount_t rc; 3117 mdb_refcount_removed_t rcr; 3118 mdb_refcount_tracked_t rct; 3119 int off; 3120 boolean_t released = B_FALSE; 3121 3122 if (!(flags & DCMD_ADDRSPEC)) 3123 return (DCMD_USAGE); 3124 3125 if (mdb_getopts(argc, argv, 3126 'r', MDB_OPT_SETBITS, B_TRUE, &released, 3127 NULL) != argc) 3128 return (DCMD_USAGE); 3129 3130 if (mdb_ctf_vread(&rc, "refcount_t", "mdb_refcount_t", addr, 3131 0) == -1) 3132 return (DCMD_ERR); 3133 3134 if (mdb_ctf_vread(&rcr, "refcount_t", "mdb_refcount_removed_t", addr, 3135 MDB_CTF_VREAD_QUIET) == -1) { 3136 mdb_printf("refcount_t at %p has %llu holds (untracked)\n", 3137 addr, (longlong_t)rc.rc_count); 3138 return (DCMD_OK); 3139 } 3140 3141 if (mdb_ctf_vread(&rct, "refcount_t", "mdb_refcount_tracked_t", addr, 3142 MDB_CTF_VREAD_QUIET) == -1) { 3143 /* If this is an old target, it might be tracked. */ 3144 rct.rc_tracked = B_TRUE; 3145 } 3146 3147 mdb_printf("refcount_t at %p has %llu current holds, " 3148 "%llu recently released holds\n", 3149 addr, (longlong_t)rc.rc_count, (longlong_t)rcr.rc_removed_count); 3150 3151 if (rct.rc_tracked && rc.rc_count > 0) 3152 mdb_printf("current holds:\n"); 3153 off = mdb_ctf_offsetof_by_name("refcount_t", "rc_list"); 3154 if (off == -1) 3155 return (DCMD_ERR); 3156 mdb_pwalk("list", reference_cb, (void*)B_FALSE, addr + off); 3157 3158 if (released && rcr.rc_removed_count > 0) { 3159 mdb_printf("released holds:\n"); 3160 3161 off = mdb_ctf_offsetof_by_name("refcount_t", "rc_removed"); 3162 if (off == -1) 3163 return (DCMD_ERR); 3164 mdb_pwalk("list", reference_cb, (void*)B_TRUE, addr + off); 3165 } 3166 3167 return (DCMD_OK); 3168 } 3169 3170 /* ARGSUSED */ 3171 static int 3172 sa_attr_table(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 3173 { 3174 sa_attr_table_t *table; 3175 sa_os_t sa_os; 3176 char *name; 3177 int i; 3178 3179 if (mdb_vread(&sa_os, sizeof (sa_os_t), addr) == -1) { 3180 mdb_warn("failed to read sa_os at %p", addr); 3181 return (DCMD_ERR); 3182 } 3183 3184 table = mdb_alloc(sizeof (sa_attr_table_t) * sa_os.sa_num_attrs, 3185 UM_SLEEP | UM_GC); 3186 name = mdb_alloc(MAXPATHLEN, UM_SLEEP | UM_GC); 3187 3188 if (mdb_vread(table, sizeof (sa_attr_table_t) * sa_os.sa_num_attrs, 3189 (uintptr_t)sa_os.sa_attr_table) == -1) { 3190 mdb_warn("failed to read sa_os at %p", addr); 3191 return (DCMD_ERR); 3192 } 3193 3194 mdb_printf("%<u>%-10s %-10s %-10s %-10s %s%</u>\n", 3195 "ATTR ID", "REGISTERED", "LENGTH", "BSWAP", "NAME"); 3196 for (i = 0; i != sa_os.sa_num_attrs; i++) { 3197 mdb_readstr(name, MAXPATHLEN, (uintptr_t)table[i].sa_name); 3198 mdb_printf("%5x %8x %8x %8x %-s\n", 3199 (int)table[i].sa_attr, (int)table[i].sa_registered, 3200 (int)table[i].sa_length, table[i].sa_byteswap, name); 3201 } 3202 3203 return (DCMD_OK); 3204 } 3205 3206 static int 3207 sa_get_off_table(uintptr_t addr, uint32_t **off_tab, int attr_count) 3208 { 3209 uintptr_t idx_table; 3210 3211 if (GETMEMB(addr, "sa_idx_tab", sa_idx_tab, idx_table)) { 3212 mdb_printf("can't find offset table in sa_idx_tab\n"); 3213 return (-1); 3214 } 3215 3216 *off_tab = mdb_alloc(attr_count * sizeof (uint32_t), 3217 UM_SLEEP | UM_GC); 3218 3219 if (mdb_vread(*off_tab, 3220 attr_count * sizeof (uint32_t), idx_table) == -1) { 3221 mdb_warn("failed to attribute offset table %p", idx_table); 3222 return (-1); 3223 } 3224 3225 return (DCMD_OK); 3226 } 3227 3228 /*ARGSUSED*/ 3229 static int 3230 sa_attr_print(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 3231 { 3232 uint32_t *offset_tab; 3233 int attr_count; 3234 uint64_t attr_id; 3235 uintptr_t attr_addr; 3236 uintptr_t bonus_tab, spill_tab; 3237 uintptr_t db_bonus, db_spill; 3238 uintptr_t os, os_sa; 3239 uintptr_t db_data; 3240 3241 if (argc != 1) 3242 return (DCMD_USAGE); 3243 3244 if (argv[0].a_type == MDB_TYPE_STRING) 3245 attr_id = mdb_strtoull(argv[0].a_un.a_str); 3246 else 3247 return (DCMD_USAGE); 3248 3249 if (GETMEMB(addr, "sa_handle", sa_bonus_tab, bonus_tab) || 3250 GETMEMB(addr, "sa_handle", sa_spill_tab, spill_tab) || 3251 GETMEMB(addr, "sa_handle", sa_os, os) || 3252 GETMEMB(addr, "sa_handle", sa_bonus, db_bonus) || 3253 GETMEMB(addr, "sa_handle", sa_spill, db_spill)) { 3254 mdb_printf("Can't find necessary information in sa_handle " 3255 "in sa_handle\n"); 3256 return (DCMD_ERR); 3257 } 3258 3259 if (GETMEMB(os, "objset", os_sa, os_sa)) { 3260 mdb_printf("Can't find os_sa in objset\n"); 3261 return (DCMD_ERR); 3262 } 3263 3264 if (GETMEMB(os_sa, "sa_os", sa_num_attrs, attr_count)) { 3265 mdb_printf("Can't find sa_num_attrs\n"); 3266 return (DCMD_ERR); 3267 } 3268 3269 if (attr_id > attr_count) { 3270 mdb_printf("attribute id number is out of range\n"); 3271 return (DCMD_ERR); 3272 } 3273 3274 if (bonus_tab) { 3275 if (sa_get_off_table(bonus_tab, &offset_tab, 3276 attr_count) == -1) { 3277 return (DCMD_ERR); 3278 } 3279 3280 if (GETMEMB(db_bonus, "dmu_buf", db_data, db_data)) { 3281 mdb_printf("can't find db_data in bonus dbuf\n"); 3282 return (DCMD_ERR); 3283 } 3284 } 3285 3286 if (bonus_tab && !TOC_ATTR_PRESENT(offset_tab[attr_id]) && 3287 spill_tab == 0) { 3288 mdb_printf("Attribute does not exist\n"); 3289 return (DCMD_ERR); 3290 } else if (!TOC_ATTR_PRESENT(offset_tab[attr_id]) && spill_tab) { 3291 if (sa_get_off_table(spill_tab, &offset_tab, 3292 attr_count) == -1) { 3293 return (DCMD_ERR); 3294 } 3295 if (GETMEMB(db_spill, "dmu_buf", db_data, db_data)) { 3296 mdb_printf("can't find db_data in spill dbuf\n"); 3297 return (DCMD_ERR); 3298 } 3299 if (!TOC_ATTR_PRESENT(offset_tab[attr_id])) { 3300 mdb_printf("Attribute does not exist\n"); 3301 return (DCMD_ERR); 3302 } 3303 } 3304 attr_addr = db_data + TOC_OFF(offset_tab[attr_id]); 3305 mdb_printf("%p\n", attr_addr); 3306 return (DCMD_OK); 3307 } 3308 3309 /* ARGSUSED */ 3310 static int 3311 zfs_ace_print_common(uintptr_t addr, uint_t flags, 3312 uint64_t id, uint32_t access_mask, uint16_t ace_flags, 3313 uint16_t ace_type, int verbose) 3314 { 3315 if (DCMD_HDRSPEC(flags) && !verbose) 3316 mdb_printf("%<u>%-?s %-8s %-8s %-8s %s%</u>\n", 3317 "ADDR", "FLAGS", "MASK", "TYPE", "ID"); 3318 3319 if (!verbose) { 3320 mdb_printf("%0?p %-8x %-8x %-8x %-llx\n", addr, 3321 ace_flags, access_mask, ace_type, id); 3322 return (DCMD_OK); 3323 } 3324 3325 switch (ace_flags & ACE_TYPE_FLAGS) { 3326 case ACE_OWNER: 3327 mdb_printf("owner@:"); 3328 break; 3329 case (ACE_IDENTIFIER_GROUP | ACE_GROUP): 3330 mdb_printf("group@:"); 3331 break; 3332 case ACE_EVERYONE: 3333 mdb_printf("everyone@:"); 3334 break; 3335 case ACE_IDENTIFIER_GROUP: 3336 mdb_printf("group:%llx:", (u_longlong_t)id); 3337 break; 3338 case 0: /* User entry */ 3339 mdb_printf("user:%llx:", (u_longlong_t)id); 3340 break; 3341 } 3342 3343 /* print out permission mask */ 3344 if (access_mask & ACE_READ_DATA) 3345 mdb_printf("r"); 3346 else 3347 mdb_printf("-"); 3348 if (access_mask & ACE_WRITE_DATA) 3349 mdb_printf("w"); 3350 else 3351 mdb_printf("-"); 3352 if (access_mask & ACE_EXECUTE) 3353 mdb_printf("x"); 3354 else 3355 mdb_printf("-"); 3356 if (access_mask & ACE_APPEND_DATA) 3357 mdb_printf("p"); 3358 else 3359 mdb_printf("-"); 3360 if (access_mask & ACE_DELETE) 3361 mdb_printf("d"); 3362 else 3363 mdb_printf("-"); 3364 if (access_mask & ACE_DELETE_CHILD) 3365 mdb_printf("D"); 3366 else 3367 mdb_printf("-"); 3368 if (access_mask & ACE_READ_ATTRIBUTES) 3369 mdb_printf("a"); 3370 else 3371 mdb_printf("-"); 3372 if (access_mask & ACE_WRITE_ATTRIBUTES) 3373 mdb_printf("A"); 3374 else 3375 mdb_printf("-"); 3376 if (access_mask & ACE_READ_NAMED_ATTRS) 3377 mdb_printf("R"); 3378 else 3379 mdb_printf("-"); 3380 if (access_mask & ACE_WRITE_NAMED_ATTRS) 3381 mdb_printf("W"); 3382 else 3383 mdb_printf("-"); 3384 if (access_mask & ACE_READ_ACL) 3385 mdb_printf("c"); 3386 else 3387 mdb_printf("-"); 3388 if (access_mask & ACE_WRITE_ACL) 3389 mdb_printf("C"); 3390 else 3391 mdb_printf("-"); 3392 if (access_mask & ACE_WRITE_OWNER) 3393 mdb_printf("o"); 3394 else 3395 mdb_printf("-"); 3396 if (access_mask & ACE_SYNCHRONIZE) 3397 mdb_printf("s"); 3398 else 3399 mdb_printf("-"); 3400 3401 mdb_printf(":"); 3402 3403 /* Print out inheritance flags */ 3404 if (ace_flags & ACE_FILE_INHERIT_ACE) 3405 mdb_printf("f"); 3406 else 3407 mdb_printf("-"); 3408 if (ace_flags & ACE_DIRECTORY_INHERIT_ACE) 3409 mdb_printf("d"); 3410 else 3411 mdb_printf("-"); 3412 if (ace_flags & ACE_INHERIT_ONLY_ACE) 3413 mdb_printf("i"); 3414 else 3415 mdb_printf("-"); 3416 if (ace_flags & ACE_NO_PROPAGATE_INHERIT_ACE) 3417 mdb_printf("n"); 3418 else 3419 mdb_printf("-"); 3420 if (ace_flags & ACE_SUCCESSFUL_ACCESS_ACE_FLAG) 3421 mdb_printf("S"); 3422 else 3423 mdb_printf("-"); 3424 if (ace_flags & ACE_FAILED_ACCESS_ACE_FLAG) 3425 mdb_printf("F"); 3426 else 3427 mdb_printf("-"); 3428 if (ace_flags & ACE_INHERITED_ACE) 3429 mdb_printf("I"); 3430 else 3431 mdb_printf("-"); 3432 3433 switch (ace_type) { 3434 case ACE_ACCESS_ALLOWED_ACE_TYPE: 3435 mdb_printf(":allow\n"); 3436 break; 3437 case ACE_ACCESS_DENIED_ACE_TYPE: 3438 mdb_printf(":deny\n"); 3439 break; 3440 case ACE_SYSTEM_AUDIT_ACE_TYPE: 3441 mdb_printf(":audit\n"); 3442 break; 3443 case ACE_SYSTEM_ALARM_ACE_TYPE: 3444 mdb_printf(":alarm\n"); 3445 break; 3446 default: 3447 mdb_printf(":?\n"); 3448 } 3449 return (DCMD_OK); 3450 } 3451 3452 /* ARGSUSED */ 3453 static int 3454 zfs_ace_print(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 3455 { 3456 zfs_ace_t zace; 3457 int verbose = FALSE; 3458 uint64_t id; 3459 3460 if (!(flags & DCMD_ADDRSPEC)) 3461 return (DCMD_USAGE); 3462 3463 if (mdb_getopts(argc, argv, 3464 'v', MDB_OPT_SETBITS, TRUE, &verbose, TRUE, NULL) != argc) 3465 return (DCMD_USAGE); 3466 3467 if (mdb_vread(&zace, sizeof (zfs_ace_t), addr) == -1) { 3468 mdb_warn("failed to read zfs_ace_t"); 3469 return (DCMD_ERR); 3470 } 3471 3472 if ((zace.z_hdr.z_flags & ACE_TYPE_FLAGS) == 0 || 3473 (zace.z_hdr.z_flags & ACE_TYPE_FLAGS) == ACE_IDENTIFIER_GROUP) 3474 id = zace.z_fuid; 3475 else 3476 id = -1; 3477 3478 return (zfs_ace_print_common(addr, flags, id, zace.z_hdr.z_access_mask, 3479 zace.z_hdr.z_flags, zace.z_hdr.z_type, verbose)); 3480 } 3481 3482 /* ARGSUSED */ 3483 static int 3484 zfs_ace0_print(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 3485 { 3486 ace_t ace; 3487 uint64_t id; 3488 int verbose = FALSE; 3489 3490 if (!(flags & DCMD_ADDRSPEC)) 3491 return (DCMD_USAGE); 3492 3493 if (mdb_getopts(argc, argv, 3494 'v', MDB_OPT_SETBITS, TRUE, &verbose, TRUE, NULL) != argc) 3495 return (DCMD_USAGE); 3496 3497 if (mdb_vread(&ace, sizeof (ace_t), addr) == -1) { 3498 mdb_warn("failed to read ace_t"); 3499 return (DCMD_ERR); 3500 } 3501 3502 if ((ace.a_flags & ACE_TYPE_FLAGS) == 0 || 3503 (ace.a_flags & ACE_TYPE_FLAGS) == ACE_IDENTIFIER_GROUP) 3504 id = ace.a_who; 3505 else 3506 id = -1; 3507 3508 return (zfs_ace_print_common(addr, flags, id, ace.a_access_mask, 3509 ace.a_flags, ace.a_type, verbose)); 3510 } 3511 3512 typedef struct acl_dump_args { 3513 int a_argc; 3514 const mdb_arg_t *a_argv; 3515 uint16_t a_version; 3516 int a_flags; 3517 } acl_dump_args_t; 3518 3519 /* ARGSUSED */ 3520 static int 3521 acl_aces_cb(uintptr_t addr, const void *unknown, void *arg) 3522 { 3523 acl_dump_args_t *acl_args = (acl_dump_args_t *)arg; 3524 3525 if (acl_args->a_version == 1) { 3526 if (mdb_call_dcmd("zfs_ace", addr, 3527 DCMD_ADDRSPEC|acl_args->a_flags, acl_args->a_argc, 3528 acl_args->a_argv) != DCMD_OK) { 3529 return (WALK_ERR); 3530 } 3531 } else { 3532 if (mdb_call_dcmd("zfs_ace0", addr, 3533 DCMD_ADDRSPEC|acl_args->a_flags, acl_args->a_argc, 3534 acl_args->a_argv) != DCMD_OK) { 3535 return (WALK_ERR); 3536 } 3537 } 3538 acl_args->a_flags = DCMD_LOOP; 3539 return (WALK_NEXT); 3540 } 3541 3542 /* ARGSUSED */ 3543 static int 3544 acl_cb(uintptr_t addr, const void *unknown, void *arg) 3545 { 3546 acl_dump_args_t *acl_args = (acl_dump_args_t *)arg; 3547 3548 if (acl_args->a_version == 1) { 3549 if (mdb_pwalk("zfs_acl_node_aces", acl_aces_cb, 3550 arg, addr) != 0) { 3551 mdb_warn("can't walk ACEs"); 3552 return (DCMD_ERR); 3553 } 3554 } else { 3555 if (mdb_pwalk("zfs_acl_node_aces0", acl_aces_cb, 3556 arg, addr) != 0) { 3557 mdb_warn("can't walk ACEs"); 3558 return (DCMD_ERR); 3559 } 3560 } 3561 return (WALK_NEXT); 3562 } 3563 3564 /* ARGSUSED */ 3565 static int 3566 zfs_acl_dump(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 3567 { 3568 zfs_acl_t zacl; 3569 int verbose = FALSE; 3570 acl_dump_args_t acl_args; 3571 3572 if (!(flags & DCMD_ADDRSPEC)) 3573 return (DCMD_USAGE); 3574 3575 if (mdb_getopts(argc, argv, 3576 'v', MDB_OPT_SETBITS, TRUE, &verbose, TRUE, NULL) != argc) 3577 return (DCMD_USAGE); 3578 3579 if (mdb_vread(&zacl, sizeof (zfs_acl_t), addr) == -1) { 3580 mdb_warn("failed to read zfs_acl_t"); 3581 return (DCMD_ERR); 3582 } 3583 3584 acl_args.a_argc = argc; 3585 acl_args.a_argv = argv; 3586 acl_args.a_version = zacl.z_version; 3587 acl_args.a_flags = DCMD_LOOPFIRST; 3588 3589 if (mdb_pwalk("zfs_acl_node", acl_cb, &acl_args, addr) != 0) { 3590 mdb_warn("can't walk ACL"); 3591 return (DCMD_ERR); 3592 } 3593 3594 return (DCMD_OK); 3595 } 3596 3597 /* ARGSUSED */ 3598 static int 3599 zfs_acl_node_walk_init(mdb_walk_state_t *wsp) 3600 { 3601 if (wsp->walk_addr == 0) { 3602 mdb_warn("must supply address of zfs_acl_node_t\n"); 3603 return (WALK_ERR); 3604 } 3605 3606 wsp->walk_addr += 3607 mdb_ctf_offsetof_by_name(ZFS_STRUCT "zfs_acl", "z_acl"); 3608 3609 if (mdb_layered_walk("list", wsp) == -1) { 3610 mdb_warn("failed to walk 'list'\n"); 3611 return (WALK_ERR); 3612 } 3613 3614 return (WALK_NEXT); 3615 } 3616 3617 static int 3618 zfs_acl_node_walk_step(mdb_walk_state_t *wsp) 3619 { 3620 zfs_acl_node_t aclnode; 3621 3622 if (mdb_vread(&aclnode, sizeof (zfs_acl_node_t), 3623 wsp->walk_addr) == -1) { 3624 mdb_warn("failed to read zfs_acl_node at %p", wsp->walk_addr); 3625 return (WALK_ERR); 3626 } 3627 3628 return (wsp->walk_callback(wsp->walk_addr, &aclnode, wsp->walk_cbdata)); 3629 } 3630 3631 typedef struct ace_walk_data { 3632 int ace_count; 3633 int ace_version; 3634 } ace_walk_data_t; 3635 3636 static int 3637 zfs_aces_walk_init_common(mdb_walk_state_t *wsp, int version, 3638 int ace_count, uintptr_t ace_data) 3639 { 3640 ace_walk_data_t *ace_walk_data; 3641 3642 if (wsp->walk_addr == 0) { 3643 mdb_warn("must supply address of zfs_acl_node_t\n"); 3644 return (WALK_ERR); 3645 } 3646 3647 ace_walk_data = mdb_alloc(sizeof (ace_walk_data_t), UM_SLEEP | UM_GC); 3648 3649 ace_walk_data->ace_count = ace_count; 3650 ace_walk_data->ace_version = version; 3651 3652 wsp->walk_addr = ace_data; 3653 wsp->walk_data = ace_walk_data; 3654 3655 return (WALK_NEXT); 3656 } 3657 3658 static int 3659 zfs_acl_node_aces_walk_init_common(mdb_walk_state_t *wsp, int version) 3660 { 3661 static int gotid; 3662 static mdb_ctf_id_t acl_id; 3663 int z_ace_count; 3664 uintptr_t z_acldata; 3665 3666 if (!gotid) { 3667 if (mdb_ctf_lookup_by_name("struct zfs_acl_node", 3668 &acl_id) == -1) { 3669 mdb_warn("couldn't find struct zfs_acl_node"); 3670 return (DCMD_ERR); 3671 } 3672 gotid = TRUE; 3673 } 3674 3675 if (GETMEMBID(wsp->walk_addr, &acl_id, z_ace_count, z_ace_count)) { 3676 return (DCMD_ERR); 3677 } 3678 if (GETMEMBID(wsp->walk_addr, &acl_id, z_acldata, z_acldata)) { 3679 return (DCMD_ERR); 3680 } 3681 3682 return (zfs_aces_walk_init_common(wsp, version, 3683 z_ace_count, z_acldata)); 3684 } 3685 3686 /* ARGSUSED */ 3687 static int 3688 zfs_acl_node_aces_walk_init(mdb_walk_state_t *wsp) 3689 { 3690 return (zfs_acl_node_aces_walk_init_common(wsp, 1)); 3691 } 3692 3693 /* ARGSUSED */ 3694 static int 3695 zfs_acl_node_aces0_walk_init(mdb_walk_state_t *wsp) 3696 { 3697 return (zfs_acl_node_aces_walk_init_common(wsp, 0)); 3698 } 3699 3700 static int 3701 zfs_aces_walk_step(mdb_walk_state_t *wsp) 3702 { 3703 ace_walk_data_t *ace_data = wsp->walk_data; 3704 zfs_ace_t zace; 3705 ace_t *acep; 3706 int status; 3707 int entry_type; 3708 int allow_type; 3709 uintptr_t ptr; 3710 3711 if (ace_data->ace_count == 0) 3712 return (WALK_DONE); 3713 3714 if (mdb_vread(&zace, sizeof (zfs_ace_t), wsp->walk_addr) == -1) { 3715 mdb_warn("failed to read zfs_ace_t at %#lx", 3716 wsp->walk_addr); 3717 return (WALK_ERR); 3718 } 3719 3720 switch (ace_data->ace_version) { 3721 case 0: 3722 acep = (ace_t *)&zace; 3723 entry_type = acep->a_flags & ACE_TYPE_FLAGS; 3724 allow_type = acep->a_type; 3725 break; 3726 case 1: 3727 entry_type = zace.z_hdr.z_flags & ACE_TYPE_FLAGS; 3728 allow_type = zace.z_hdr.z_type; 3729 break; 3730 default: 3731 return (WALK_ERR); 3732 } 3733 3734 ptr = (uintptr_t)wsp->walk_addr; 3735 switch (entry_type) { 3736 case ACE_OWNER: 3737 case ACE_EVERYONE: 3738 case (ACE_IDENTIFIER_GROUP | ACE_GROUP): 3739 ptr += ace_data->ace_version == 0 ? 3740 sizeof (ace_t) : sizeof (zfs_ace_hdr_t); 3741 break; 3742 case ACE_IDENTIFIER_GROUP: 3743 default: 3744 switch (allow_type) { 3745 case ACE_ACCESS_ALLOWED_OBJECT_ACE_TYPE: 3746 case ACE_ACCESS_DENIED_OBJECT_ACE_TYPE: 3747 case ACE_SYSTEM_AUDIT_OBJECT_ACE_TYPE: 3748 case ACE_SYSTEM_ALARM_OBJECT_ACE_TYPE: 3749 ptr += ace_data->ace_version == 0 ? 3750 sizeof (ace_t) : sizeof (zfs_object_ace_t); 3751 break; 3752 default: 3753 ptr += ace_data->ace_version == 0 ? 3754 sizeof (ace_t) : sizeof (zfs_ace_t); 3755 break; 3756 } 3757 } 3758 3759 ace_data->ace_count--; 3760 status = wsp->walk_callback(wsp->walk_addr, 3761 (void *)(uintptr_t)&zace, wsp->walk_cbdata); 3762 3763 wsp->walk_addr = ptr; 3764 return (status); 3765 } 3766 3767 typedef struct mdb_zfs_rrwlock { 3768 uintptr_t rr_writer; 3769 boolean_t rr_writer_wanted; 3770 } mdb_zfs_rrwlock_t; 3771 3772 static uint_t rrw_key; 3773 3774 /* ARGSUSED */ 3775 static int 3776 rrwlock(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 3777 { 3778 mdb_zfs_rrwlock_t rrw; 3779 3780 if (rrw_key == 0) { 3781 if (mdb_ctf_readsym(&rrw_key, "uint_t", "rrw_tsd_key", 0) == -1) 3782 return (DCMD_ERR); 3783 } 3784 3785 if (mdb_ctf_vread(&rrw, "rrwlock_t", "mdb_zfs_rrwlock_t", addr, 3786 0) == -1) 3787 return (DCMD_ERR); 3788 3789 if (rrw.rr_writer != 0) { 3790 mdb_printf("write lock held by thread %lx\n", rrw.rr_writer); 3791 return (DCMD_OK); 3792 } 3793 3794 if (rrw.rr_writer_wanted) { 3795 mdb_printf("writer wanted\n"); 3796 } 3797 3798 mdb_printf("anonymous references:\n"); 3799 (void) mdb_call_dcmd("refcount", addr + 3800 mdb_ctf_offsetof_by_name(ZFS_STRUCT "rrwlock", "rr_anon_rcount"), 3801 DCMD_ADDRSPEC, 0, NULL); 3802 3803 mdb_printf("linked references:\n"); 3804 (void) mdb_call_dcmd("refcount", addr + 3805 mdb_ctf_offsetof_by_name(ZFS_STRUCT "rrwlock", "rr_linked_rcount"), 3806 DCMD_ADDRSPEC, 0, NULL); 3807 3808 /* 3809 * XXX This should find references from 3810 * "::walk thread | ::tsd -v <rrw_key>", but there is no support 3811 * for programmatic consumption of dcmds, so this would be 3812 * difficult, potentially requiring reimplementing ::tsd (both 3813 * user and kernel versions) in this MDB module. 3814 */ 3815 3816 return (DCMD_OK); 3817 } 3818 3819 typedef struct mdb_arc_buf_hdr_t { 3820 uint16_t b_psize; 3821 uint16_t b_lsize; 3822 struct { 3823 uint32_t b_bufcnt; 3824 uintptr_t b_state; 3825 } b_l1hdr; 3826 } mdb_arc_buf_hdr_t; 3827 3828 enum arc_cflags { 3829 ARC_CFLAG_VERBOSE = 1 << 0, 3830 ARC_CFLAG_ANON = 1 << 1, 3831 ARC_CFLAG_MRU = 1 << 2, 3832 ARC_CFLAG_MFU = 1 << 3, 3833 ARC_CFLAG_BUFS = 1 << 4, 3834 }; 3835 3836 typedef struct arc_compression_stats_data { 3837 GElf_Sym anon_sym; /* ARC_anon symbol */ 3838 GElf_Sym mru_sym; /* ARC_mru symbol */ 3839 GElf_Sym mrug_sym; /* ARC_mru_ghost symbol */ 3840 GElf_Sym mfu_sym; /* ARC_mfu symbol */ 3841 GElf_Sym mfug_sym; /* ARC_mfu_ghost symbol */ 3842 GElf_Sym l2c_sym; /* ARC_l2c_only symbol */ 3843 uint64_t *anon_c_hist; /* histogram of compressed sizes in anon */ 3844 uint64_t *anon_u_hist; /* histogram of uncompressed sizes in anon */ 3845 uint64_t *anon_bufs; /* histogram of buffer counts in anon state */ 3846 uint64_t *mru_c_hist; /* histogram of compressed sizes in mru */ 3847 uint64_t *mru_u_hist; /* histogram of uncompressed sizes in mru */ 3848 uint64_t *mru_bufs; /* histogram of buffer counts in mru */ 3849 uint64_t *mfu_c_hist; /* histogram of compressed sizes in mfu */ 3850 uint64_t *mfu_u_hist; /* histogram of uncompressed sizes in mfu */ 3851 uint64_t *mfu_bufs; /* histogram of buffer counts in mfu */ 3852 uint64_t *all_c_hist; /* histogram of compressed anon + mru + mfu */ 3853 uint64_t *all_u_hist; /* histogram of uncompressed anon + mru + mfu */ 3854 uint64_t *all_bufs; /* histogram of buffer counts in all states */ 3855 int arc_cflags; /* arc compression flags, specified by user */ 3856 int hist_nbuckets; /* number of buckets in each histogram */ 3857 } arc_compression_stats_data_t; 3858 3859 int 3860 highbit64(uint64_t i) 3861 { 3862 int h = 1; 3863 3864 if (i == 0) 3865 return (0); 3866 if (i & 0xffffffff00000000ULL) { 3867 h += 32; i >>= 32; 3868 } 3869 if (i & 0xffff0000) { 3870 h += 16; i >>= 16; 3871 } 3872 if (i & 0xff00) { 3873 h += 8; i >>= 8; 3874 } 3875 if (i & 0xf0) { 3876 h += 4; i >>= 4; 3877 } 3878 if (i & 0xc) { 3879 h += 2; i >>= 2; 3880 } 3881 if (i & 0x2) { 3882 h += 1; 3883 } 3884 return (h); 3885 } 3886 3887 /* ARGSUSED */ 3888 static int 3889 arc_compression_stats_cb(uintptr_t addr, const void *unknown, void *arg) 3890 { 3891 arc_compression_stats_data_t *data = arg; 3892 mdb_arc_buf_hdr_t hdr; 3893 int cbucket, ubucket, bufcnt; 3894 3895 if (mdb_ctf_vread(&hdr, "arc_buf_hdr_t", "mdb_arc_buf_hdr_t", 3896 addr, 0) == -1) { 3897 return (WALK_ERR); 3898 } 3899 3900 /* 3901 * Headers in the ghost states, or the l2c_only state don't have 3902 * arc buffers linked off of them. Thus, their compressed size 3903 * is meaningless, so we skip these from the stats. 3904 */ 3905 if (hdr.b_l1hdr.b_state == data->mrug_sym.st_value || 3906 hdr.b_l1hdr.b_state == data->mfug_sym.st_value || 3907 hdr.b_l1hdr.b_state == data->l2c_sym.st_value) { 3908 return (WALK_NEXT); 3909 } 3910 3911 /* 3912 * The physical size (compressed) and logical size 3913 * (uncompressed) are in units of SPA_MINBLOCKSIZE. By default, 3914 * we use the log2 of this value (rounded down to the nearest 3915 * integer) to determine the bucket to assign this header to. 3916 * Thus, the histogram is logarithmic with respect to the size 3917 * of the header. For example, the following is a mapping of the 3918 * bucket numbers and the range of header sizes they correspond to: 3919 * 3920 * 0: 0 byte headers 3921 * 1: 512 byte headers 3922 * 2: [1024 - 2048) byte headers 3923 * 3: [2048 - 4096) byte headers 3924 * 4: [4096 - 8192) byte headers 3925 * 5: [8192 - 16394) byte headers 3926 * 6: [16384 - 32768) byte headers 3927 * 7: [32768 - 65536) byte headers 3928 * 8: [65536 - 131072) byte headers 3929 * 9: 131072 byte headers 3930 * 3931 * If the ARC_CFLAG_VERBOSE flag was specified, we use the 3932 * physical and logical sizes directly. Thus, the histogram will 3933 * no longer be logarithmic; instead it will be linear with 3934 * respect to the size of the header. The following is a mapping 3935 * of the first many bucket numbers and the header size they 3936 * correspond to: 3937 * 3938 * 0: 0 byte headers 3939 * 1: 512 byte headers 3940 * 2: 1024 byte headers 3941 * 3: 1536 byte headers 3942 * 4: 2048 byte headers 3943 * 5: 2560 byte headers 3944 * 6: 3072 byte headers 3945 * 3946 * And so on. Keep in mind that a range of sizes isn't used in 3947 * the case of linear scale because the headers can only 3948 * increment or decrement in sizes of 512 bytes. So, it's not 3949 * possible for a header to be sized in between whats listed 3950 * above. 3951 * 3952 * Also, the above mapping values were calculated assuming a 3953 * SPA_MINBLOCKSHIFT of 512 bytes and a SPA_MAXBLOCKSIZE of 128K. 3954 */ 3955 3956 if (data->arc_cflags & ARC_CFLAG_VERBOSE) { 3957 cbucket = hdr.b_psize; 3958 ubucket = hdr.b_lsize; 3959 } else { 3960 cbucket = highbit64(hdr.b_psize); 3961 ubucket = highbit64(hdr.b_lsize); 3962 } 3963 3964 bufcnt = hdr.b_l1hdr.b_bufcnt; 3965 if (bufcnt >= data->hist_nbuckets) 3966 bufcnt = data->hist_nbuckets - 1; 3967 3968 /* Ensure we stay within the bounds of the histogram array */ 3969 ASSERT3U(cbucket, <, data->hist_nbuckets); 3970 ASSERT3U(ubucket, <, data->hist_nbuckets); 3971 3972 if (hdr.b_l1hdr.b_state == data->anon_sym.st_value) { 3973 data->anon_c_hist[cbucket]++; 3974 data->anon_u_hist[ubucket]++; 3975 data->anon_bufs[bufcnt]++; 3976 } else if (hdr.b_l1hdr.b_state == data->mru_sym.st_value) { 3977 data->mru_c_hist[cbucket]++; 3978 data->mru_u_hist[ubucket]++; 3979 data->mru_bufs[bufcnt]++; 3980 } else if (hdr.b_l1hdr.b_state == data->mfu_sym.st_value) { 3981 data->mfu_c_hist[cbucket]++; 3982 data->mfu_u_hist[ubucket]++; 3983 data->mfu_bufs[bufcnt]++; 3984 } 3985 3986 data->all_c_hist[cbucket]++; 3987 data->all_u_hist[ubucket]++; 3988 data->all_bufs[bufcnt]++; 3989 3990 return (WALK_NEXT); 3991 } 3992 3993 /* ARGSUSED */ 3994 static int 3995 arc_compression_stats(uintptr_t addr, uint_t flags, int argc, 3996 const mdb_arg_t *argv) 3997 { 3998 arc_compression_stats_data_t data = { 0 }; 3999 unsigned int max_shifted = SPA_MAXBLOCKSIZE >> SPA_MINBLOCKSHIFT; 4000 unsigned int hist_size; 4001 char range[32]; 4002 int rc = DCMD_OK; 4003 4004 if (mdb_getopts(argc, argv, 4005 'v', MDB_OPT_SETBITS, ARC_CFLAG_VERBOSE, &data.arc_cflags, 4006 'a', MDB_OPT_SETBITS, ARC_CFLAG_ANON, &data.arc_cflags, 4007 'b', MDB_OPT_SETBITS, ARC_CFLAG_BUFS, &data.arc_cflags, 4008 'r', MDB_OPT_SETBITS, ARC_CFLAG_MRU, &data.arc_cflags, 4009 'f', MDB_OPT_SETBITS, ARC_CFLAG_MFU, &data.arc_cflags) != argc) 4010 return (DCMD_USAGE); 4011 4012 if (mdb_lookup_by_obj(ZFS_OBJ_NAME, "ARC_anon", &data.anon_sym) || 4013 mdb_lookup_by_obj(ZFS_OBJ_NAME, "ARC_mru", &data.mru_sym) || 4014 mdb_lookup_by_obj(ZFS_OBJ_NAME, "ARC_mru_ghost", &data.mrug_sym) || 4015 mdb_lookup_by_obj(ZFS_OBJ_NAME, "ARC_mfu", &data.mfu_sym) || 4016 mdb_lookup_by_obj(ZFS_OBJ_NAME, "ARC_mfu_ghost", &data.mfug_sym) || 4017 mdb_lookup_by_obj(ZFS_OBJ_NAME, "ARC_l2c_only", &data.l2c_sym)) { 4018 mdb_warn("can't find arc state symbol"); 4019 return (DCMD_ERR); 4020 } 4021 4022 /* 4023 * Determine the maximum expected size for any header, and use 4024 * this to determine the number of buckets needed for each 4025 * histogram. If ARC_CFLAG_VERBOSE is specified, this value is 4026 * used directly; otherwise the log2 of the maximum size is 4027 * used. Thus, if using a log2 scale there's a maximum of 10 4028 * possible buckets, while the linear scale (when using 4029 * ARC_CFLAG_VERBOSE) has a maximum of 257 buckets. 4030 */ 4031 if (data.arc_cflags & ARC_CFLAG_VERBOSE) 4032 data.hist_nbuckets = max_shifted + 1; 4033 else 4034 data.hist_nbuckets = highbit64(max_shifted) + 1; 4035 4036 hist_size = sizeof (uint64_t) * data.hist_nbuckets; 4037 4038 data.anon_c_hist = mdb_zalloc(hist_size, UM_SLEEP); 4039 data.anon_u_hist = mdb_zalloc(hist_size, UM_SLEEP); 4040 data.anon_bufs = mdb_zalloc(hist_size, UM_SLEEP); 4041 4042 data.mru_c_hist = mdb_zalloc(hist_size, UM_SLEEP); 4043 data.mru_u_hist = mdb_zalloc(hist_size, UM_SLEEP); 4044 data.mru_bufs = mdb_zalloc(hist_size, UM_SLEEP); 4045 4046 data.mfu_c_hist = mdb_zalloc(hist_size, UM_SLEEP); 4047 data.mfu_u_hist = mdb_zalloc(hist_size, UM_SLEEP); 4048 data.mfu_bufs = mdb_zalloc(hist_size, UM_SLEEP); 4049 4050 data.all_c_hist = mdb_zalloc(hist_size, UM_SLEEP); 4051 data.all_u_hist = mdb_zalloc(hist_size, UM_SLEEP); 4052 data.all_bufs = mdb_zalloc(hist_size, UM_SLEEP); 4053 4054 if (mdb_walk("arc_buf_hdr_t_full", arc_compression_stats_cb, 4055 &data) != 0) { 4056 mdb_warn("can't walk arc_buf_hdr's"); 4057 rc = DCMD_ERR; 4058 goto out; 4059 } 4060 4061 if (data.arc_cflags & ARC_CFLAG_VERBOSE) { 4062 rc = mdb_snprintf(range, sizeof (range), 4063 "[n*%llu, (n+1)*%llu)", SPA_MINBLOCKSIZE, 4064 SPA_MINBLOCKSIZE); 4065 } else { 4066 rc = mdb_snprintf(range, sizeof (range), 4067 "[2^(n-1)*%llu, 2^n*%llu)", SPA_MINBLOCKSIZE, 4068 SPA_MINBLOCKSIZE); 4069 } 4070 4071 if (rc < 0) { 4072 /* snprintf failed, abort the dcmd */ 4073 rc = DCMD_ERR; 4074 goto out; 4075 } else { 4076 /* snprintf succeeded above, reset return code */ 4077 rc = DCMD_OK; 4078 } 4079 4080 if (data.arc_cflags & ARC_CFLAG_ANON) { 4081 if (data.arc_cflags & ARC_CFLAG_BUFS) { 4082 mdb_printf("Histogram of the number of anon buffers " 4083 "that are associated with an arc hdr.\n"); 4084 dump_histogram(data.anon_bufs, data.hist_nbuckets, 0); 4085 mdb_printf("\n"); 4086 } 4087 mdb_printf("Histogram of compressed anon buffers.\n" 4088 "Each bucket represents buffers of size: %s.\n", range); 4089 dump_histogram(data.anon_c_hist, data.hist_nbuckets, 0); 4090 mdb_printf("\n"); 4091 4092 mdb_printf("Histogram of uncompressed anon buffers.\n" 4093 "Each bucket represents buffers of size: %s.\n", range); 4094 dump_histogram(data.anon_u_hist, data.hist_nbuckets, 0); 4095 mdb_printf("\n"); 4096 } 4097 4098 if (data.arc_cflags & ARC_CFLAG_MRU) { 4099 if (data.arc_cflags & ARC_CFLAG_BUFS) { 4100 mdb_printf("Histogram of the number of mru buffers " 4101 "that are associated with an arc hdr.\n"); 4102 dump_histogram(data.mru_bufs, data.hist_nbuckets, 0); 4103 mdb_printf("\n"); 4104 } 4105 mdb_printf("Histogram of compressed mru buffers.\n" 4106 "Each bucket represents buffers of size: %s.\n", range); 4107 dump_histogram(data.mru_c_hist, data.hist_nbuckets, 0); 4108 mdb_printf("\n"); 4109 4110 mdb_printf("Histogram of uncompressed mru buffers.\n" 4111 "Each bucket represents buffers of size: %s.\n", range); 4112 dump_histogram(data.mru_u_hist, data.hist_nbuckets, 0); 4113 mdb_printf("\n"); 4114 } 4115 4116 if (data.arc_cflags & ARC_CFLAG_MFU) { 4117 if (data.arc_cflags & ARC_CFLAG_BUFS) { 4118 mdb_printf("Histogram of the number of mfu buffers " 4119 "that are associated with an arc hdr.\n"); 4120 dump_histogram(data.mfu_bufs, data.hist_nbuckets, 0); 4121 mdb_printf("\n"); 4122 } 4123 4124 mdb_printf("Histogram of compressed mfu buffers.\n" 4125 "Each bucket represents buffers of size: %s.\n", range); 4126 dump_histogram(data.mfu_c_hist, data.hist_nbuckets, 0); 4127 mdb_printf("\n"); 4128 4129 mdb_printf("Histogram of uncompressed mfu buffers.\n" 4130 "Each bucket represents buffers of size: %s.\n", range); 4131 dump_histogram(data.mfu_u_hist, data.hist_nbuckets, 0); 4132 mdb_printf("\n"); 4133 } 4134 4135 if (data.arc_cflags & ARC_CFLAG_BUFS) { 4136 mdb_printf("Histogram of all buffers that " 4137 "are associated with an arc hdr.\n"); 4138 dump_histogram(data.all_bufs, data.hist_nbuckets, 0); 4139 mdb_printf("\n"); 4140 } 4141 4142 mdb_printf("Histogram of all compressed buffers.\n" 4143 "Each bucket represents buffers of size: %s.\n", range); 4144 dump_histogram(data.all_c_hist, data.hist_nbuckets, 0); 4145 mdb_printf("\n"); 4146 4147 mdb_printf("Histogram of all uncompressed buffers.\n" 4148 "Each bucket represents buffers of size: %s.\n", range); 4149 dump_histogram(data.all_u_hist, data.hist_nbuckets, 0); 4150 4151 out: 4152 mdb_free(data.anon_c_hist, hist_size); 4153 mdb_free(data.anon_u_hist, hist_size); 4154 mdb_free(data.anon_bufs, hist_size); 4155 4156 mdb_free(data.mru_c_hist, hist_size); 4157 mdb_free(data.mru_u_hist, hist_size); 4158 mdb_free(data.mru_bufs, hist_size); 4159 4160 mdb_free(data.mfu_c_hist, hist_size); 4161 mdb_free(data.mfu_u_hist, hist_size); 4162 mdb_free(data.mfu_bufs, hist_size); 4163 4164 mdb_free(data.all_c_hist, hist_size); 4165 mdb_free(data.all_u_hist, hist_size); 4166 mdb_free(data.all_bufs, hist_size); 4167 4168 return (rc); 4169 } 4170 4171 typedef struct mdb_range_seg { 4172 uint64_t rs_start; 4173 uint64_t rs_end; 4174 } mdb_range_seg_t; 4175 4176 /* ARGSUSED */ 4177 static int 4178 range_tree_cb(uintptr_t addr, const void *unknown, void *arg) 4179 { 4180 mdb_range_seg_t rs; 4181 4182 if (mdb_ctf_vread(&rs, ZFS_STRUCT "range_seg", "mdb_range_seg_t", 4183 addr, 0) == -1) 4184 return (DCMD_ERR); 4185 4186 mdb_printf("\t[%llx %llx) (length %llx)\n", 4187 rs.rs_start, rs.rs_end, rs.rs_end - rs.rs_start); 4188 4189 return (0); 4190 } 4191 4192 /* ARGSUSED */ 4193 static int 4194 range_tree(uintptr_t addr, uint_t flags, int argc, 4195 const mdb_arg_t *argv) 4196 { 4197 mdb_range_tree_t rt; 4198 uintptr_t avl_addr; 4199 4200 if (!(flags & DCMD_ADDRSPEC)) 4201 return (DCMD_USAGE); 4202 4203 if (mdb_ctf_vread(&rt, ZFS_STRUCT "range_tree", "mdb_range_tree_t", 4204 addr, 0) == -1) 4205 return (DCMD_ERR); 4206 4207 mdb_printf("%p: range tree of %llu entries, %llu bytes\n", 4208 addr, rt.rt_root.avl_numnodes, rt.rt_space); 4209 4210 avl_addr = addr + 4211 mdb_ctf_offsetof_by_name(ZFS_STRUCT "range_tree", "rt_root"); 4212 4213 if (mdb_pwalk("avl", range_tree_cb, NULL, avl_addr) != 0) { 4214 mdb_warn("can't walk range_tree segments"); 4215 return (DCMD_ERR); 4216 } 4217 return (DCMD_OK); 4218 } 4219 4220 typedef struct mdb_spa_log_sm { 4221 uint64_t sls_sm_obj; 4222 uint64_t sls_txg; 4223 uint64_t sls_nblocks; 4224 uint64_t sls_mscount; 4225 } mdb_spa_log_sm_t; 4226 4227 /* ARGSUSED */ 4228 static int 4229 logsm_stats_cb(uintptr_t addr, const void *unknown, void *arg) 4230 { 4231 mdb_spa_log_sm_t sls; 4232 if (mdb_ctf_vread(&sls, ZFS_STRUCT "spa_log_sm", "mdb_spa_log_sm_t", 4233 addr, 0) == -1) 4234 return (WALK_ERR); 4235 4236 mdb_printf("%7lld %7lld %7lld %7lld\n", 4237 sls.sls_txg, sls.sls_nblocks, sls.sls_mscount, sls.sls_sm_obj); 4238 4239 return (WALK_NEXT); 4240 } 4241 typedef struct mdb_log_summary_entry { 4242 uint64_t lse_start; 4243 uint64_t lse_blkcount; 4244 uint64_t lse_mscount; 4245 } mdb_log_summary_entry_t; 4246 4247 /* ARGSUSED */ 4248 static int 4249 logsm_summary_cb(uintptr_t addr, const void *unknown, void *arg) 4250 { 4251 mdb_log_summary_entry_t lse; 4252 if (mdb_ctf_vread(&lse, ZFS_STRUCT "log_summary_entry", 4253 "mdb_log_summary_entry_t", addr, 0) == -1) 4254 return (WALK_ERR); 4255 4256 mdb_printf("%7lld %7lld %7lld\n", 4257 lse.lse_start, lse.lse_blkcount, lse.lse_mscount); 4258 return (WALK_NEXT); 4259 } 4260 4261 /* ARGSUSED */ 4262 static int 4263 logsm_stats(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 4264 { 4265 if (!(flags & DCMD_ADDRSPEC)) 4266 return (DCMD_USAGE); 4267 4268 uintptr_t sls_avl_addr = addr + 4269 mdb_ctf_offsetof_by_name(ZFS_STRUCT "spa", "spa_sm_logs_by_txg"); 4270 uintptr_t summary_addr = addr + 4271 mdb_ctf_offsetof_by_name(ZFS_STRUCT "spa", "spa_log_summary"); 4272 4273 mdb_printf("Log Entries:\n"); 4274 mdb_printf("%7s %7s %7s %7s\n", "txg", "blk", "ms", "obj"); 4275 if (mdb_pwalk("avl", logsm_stats_cb, NULL, sls_avl_addr) != 0) 4276 return (DCMD_ERR); 4277 4278 mdb_printf("\nSummary Entries:\n"); 4279 mdb_printf("%7s %7s %7s\n", "txg", "blk", "ms"); 4280 if (mdb_pwalk("list", logsm_summary_cb, NULL, summary_addr) != 0) 4281 return (DCMD_ERR); 4282 4283 return (DCMD_OK); 4284 } 4285 4286 /* 4287 * MDB module linkage information: 4288 * 4289 * We declare a list of structures describing our dcmds, and a function 4290 * named _mdb_init to return a pointer to our module information. 4291 */ 4292 4293 static const mdb_dcmd_t dcmds[] = { 4294 { "arc", "[-bkmg]", "print ARC variables", arc_print }, 4295 { "blkptr", ":", "print blkptr_t", blkptr }, 4296 { "dva", ":", "print dva_t", dva }, 4297 { "dbuf", ":", "print dmu_buf_impl_t", dbuf }, 4298 { "dbuf_stats", ":", "dbuf stats", dbuf_stats }, 4299 { "dbufs", 4300 "\t[-O objset_t*] [-n objset_name | \"mos\"] " 4301 "[-o object | \"mdn\"] \n" 4302 "\t[-l level] [-b blkid | \"bonus\"]", 4303 "find dmu_buf_impl_t's that match specified criteria", dbufs }, 4304 { "abuf_find", "dva_word[0] dva_word[1]", 4305 "find arc_buf_hdr_t of a specified DVA", 4306 abuf_find }, 4307 { "logsm_stats", ":", "print log space map statistics of a spa_t", 4308 logsm_stats}, 4309 { "spa", "?[-cevmMh]\n" 4310 "\t-c display spa config\n" 4311 "\t-e display vdev statistics\n" 4312 "\t-v display vdev information\n" 4313 "\t-m display metaslab statistics\n" 4314 "\t-M display metaslab group statistics\n" 4315 "\t-h display histogram (requires -m or -M)\n", 4316 "spa_t summary", spa_print }, 4317 { "spa_config", ":", "print spa_t configuration", spa_print_config }, 4318 { "spa_space", ":[-b]", "print spa_t on-disk space usage", spa_space }, 4319 { "spa_vdevs", ":[-emMh]\n" 4320 "\t-e display vdev statistics\n" 4321 "\t-m dispaly metaslab statistics\n" 4322 "\t-M display metaslab group statistic\n" 4323 "\t-h display histogram (requires -m or -M)\n", 4324 "given a spa_t, print vdev summary", spa_vdevs }, 4325 { "sm_entries", "<buffer length in bytes>", 4326 "print out space map entries from a buffer decoded", 4327 sm_entries}, 4328 { "vdev", ":[-remMh]\n" 4329 "\t-r display recursively\n" 4330 "\t-e display statistics\n" 4331 "\t-m display metaslab statistics (top level vdev only)\n" 4332 "\t-M display metaslab group statistics (top level vdev only)\n" 4333 "\t-h display histogram (requires -m or -M)\n", 4334 "vdev_t summary", vdev_print }, 4335 { "zio", ":[-cpr]\n" 4336 "\t-c display children\n" 4337 "\t-p display parents\n" 4338 "\t-r display recursively", 4339 "zio_t summary", zio_print }, 4340 { "zio_state", "?", "print out all zio_t structures on system or " 4341 "for a particular pool", zio_state }, 4342 { "zfs_blkstats", ":[-v]", 4343 "given a spa_t, print block type stats from last scrub", 4344 zfs_blkstats }, 4345 { "zfs_params", "", "print zfs tunable parameters", zfs_params }, 4346 { "refcount", ":[-r]\n" 4347 "\t-r display recently removed references", 4348 "print refcount_t holders", refcount }, 4349 { "zap_leaf", "", "print zap_leaf_phys_t", zap_leaf }, 4350 { "zfs_aces", ":[-v]", "print all ACEs from a zfs_acl_t", 4351 zfs_acl_dump }, 4352 { "zfs_ace", ":[-v]", "print zfs_ace", zfs_ace_print }, 4353 { "zfs_ace0", ":[-v]", "print zfs_ace0", zfs_ace0_print }, 4354 { "sa_attr_table", ":", "print SA attribute table from sa_os_t", 4355 sa_attr_table}, 4356 { "sa_attr", ": attr_id", 4357 "print SA attribute address when given sa_handle_t", sa_attr_print}, 4358 { "zfs_dbgmsg", ":[-va]", 4359 "print zfs debug log", dbgmsg}, 4360 { "rrwlock", ":", 4361 "print rrwlock_t, including readers", rrwlock}, 4362 { "metaslab_weight", "weight", 4363 "print metaslab weight", metaslab_weight}, 4364 { "metaslab_trace", ":", 4365 "print metaslab allocation trace records", metaslab_trace}, 4366 { "arc_compression_stats", ":[-vabrf]\n" 4367 "\t-v verbose, display a linearly scaled histogram\n" 4368 "\t-a display ARC_anon state statistics individually\n" 4369 "\t-r display ARC_mru state statistics individually\n" 4370 "\t-f display ARC_mfu state statistics individually\n" 4371 "\t-b display histogram of buffer counts\n", 4372 "print a histogram of compressed arc buffer sizes", 4373 arc_compression_stats}, 4374 { "range_tree", ":", 4375 "print entries in range_tree_t", range_tree}, 4376 { NULL } 4377 }; 4378 4379 static const mdb_walker_t walkers[] = { 4380 { "txg_list", "given any txg_list_t *, walk all entries in all txgs", 4381 txg_list_walk_init, txg_list_walk_step, NULL }, 4382 { "txg_list0", "given any txg_list_t *, walk all entries in txg 0", 4383 txg_list0_walk_init, txg_list_walk_step, NULL }, 4384 { "txg_list1", "given any txg_list_t *, walk all entries in txg 1", 4385 txg_list1_walk_init, txg_list_walk_step, NULL }, 4386 { "txg_list2", "given any txg_list_t *, walk all entries in txg 2", 4387 txg_list2_walk_init, txg_list_walk_step, NULL }, 4388 { "txg_list3", "given any txg_list_t *, walk all entries in txg 3", 4389 txg_list3_walk_init, txg_list_walk_step, NULL }, 4390 { "zio", "walk all zio structures, optionally for a particular spa_t", 4391 zio_walk_init, zio_walk_step, NULL }, 4392 { "zio_root", 4393 "walk all root zio_t structures, optionally for a particular spa_t", 4394 zio_walk_init, zio_walk_root_step, NULL }, 4395 { "spa", "walk all spa_t entries in the namespace", 4396 spa_walk_init, spa_walk_step, NULL }, 4397 { "metaslab", "given a spa_t *, walk all metaslab_t structures", 4398 metaslab_walk_init, metaslab_walk_step, NULL }, 4399 { "multilist", "given a multilist_t *, walk all list_t structures", 4400 multilist_walk_init, multilist_walk_step, NULL }, 4401 { "zfs_acl_node", "given a zfs_acl_t, walk all zfs_acl_nodes", 4402 zfs_acl_node_walk_init, zfs_acl_node_walk_step, NULL }, 4403 { "zfs_acl_node_aces", "given a zfs_acl_node_t, walk all ACEs", 4404 zfs_acl_node_aces_walk_init, zfs_aces_walk_step, NULL }, 4405 { "zfs_acl_node_aces0", 4406 "given a zfs_acl_node_t, walk all ACEs as ace_t", 4407 zfs_acl_node_aces0_walk_init, zfs_aces_walk_step, NULL }, 4408 { NULL } 4409 }; 4410 4411 static const mdb_modinfo_t modinfo = { 4412 MDB_API_VERSION, dcmds, walkers 4413 }; 4414 4415 const mdb_modinfo_t * 4416 _mdb_init(void) 4417 { 4418 return (&modinfo); 4419 } 4420