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 /* 23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #include "mdinclude.h" 28 29 typedef struct submirror_cb { 30 minor_t un_self_id; 31 int un_nsm; 32 ushort_t mm_un_nsm; 33 }submirror_cb_t; 34 35 void 36 print_setname(int setno) 37 { 38 char setname[1024]; 39 40 if (setno != 0) { 41 if (mdb_readstr(setname, 1024, 42 (uintptr_t)set_dbs[setno].s_setname) == -1) { 43 mdb_warn("failed to read setname at 0x%p\n", 44 set_dbs[setno].s_setname); 45 } 46 mdb_printf("%s/", setname); 47 } 48 } 49 50 void 51 print_stripe(void *un_addr, void *mdcptr, uint_t verbose) 52 { 53 ms_unit_t ms; 54 int setno; 55 minor_t un_self_id; 56 md_parent_t un_parent; 57 diskaddr_t un_total_blocks; 58 59 /* read in the device */ 60 un_self_id = ((mdc_unit_t *)mdcptr)->un_self_id; 61 un_parent = ((mdc_unit_t *)mdcptr)->un_parent; 62 un_total_blocks = ((mdc_unit_t *)mdcptr)->un_total_blocks; 63 if (mdb_vread(&ms, sizeof (ms_unit_t), 64 (uintptr_t)un_addr) == -1) { 65 mdb_warn("failed to read ms_unit_t at %p\n", un_addr); 66 return; 67 } 68 69 setno = MD_MIN2SET(un_self_id); 70 print_setname(setno); 71 72 mdb_printf("d%u: ", MD_MIN2UNIT(un_self_id)); 73 if (un_parent == ((unit_t)-1)) { 74 mdb_printf("Concat/Stripe"); 75 } else { 76 mdb_printf("Subdevice of d%u", MD_MIN2UNIT(un_parent)); 77 } 78 if (verbose) { 79 mdb_printf("\t< %p::print ms_unit_t >\n", un_addr); 80 } else { 81 mdb_printf("\t< %p>\n", un_addr); 82 } 83 mdb_inc_indent(2); 84 mdb_printf("Size: %llu blocks\n", un_total_blocks); 85 mdb_printf("Rows: %u\n", ms.un_nrows); 86 mdb_dec_indent(2); 87 } 88 89 /* ARGSUSED */ 90 int 91 print_submirror(uintptr_t addr, void *arg, submirror_cb_t *data) 92 { 93 uintptr_t un_addr; 94 mdc_unit_t mdc_sm; 95 96 if (mdb_vread(&un_addr, sizeof (void *), addr) == -1) { 97 mdb_warn("failed to read submirror at %p\n", addr); 98 return (WALK_ERR); 99 } 100 if (un_addr != NULL) { 101 if (mdb_vread(&mdc_sm, sizeof (mdc_unit_t), un_addr) == -1) { 102 mdb_warn("failed to read mdc_unit_t at %p", un_addr); 103 return (WALK_ERR); 104 } 105 if (mdc_sm.un_parent == data->un_self_id) { 106 /* this is one of the sub mirrors */ 107 mdb_printf("Submirror %u: d%u ", 108 data->un_nsm, MD_MIN2UNIT(mdc_sm.un_self_id)); 109 mdb_printf("Size: %llu\n", mdc_sm.un_total_blocks); 110 data->un_nsm++; 111 if (data->un_nsm == data->mm_un_nsm) 112 return (WALK_DONE); 113 } 114 } 115 return (WALK_NEXT); 116 } 117 118 /* 119 * Construct an RLE count for the number of 'cleared' bits in the given 'bm' 120 * Output the RLE count in form: [<set>.<cleared>.<set>.<cleared>...] 121 * RLE is Run Length Encoding, a method for compactly describing a bitmap 122 * as a series of numbers indicating the count of consecutive set or cleared 123 * bits. 124 * 125 * Input: 126 * <bm> bitmap to scan 127 * <size> length of bitmap (in bits) 128 * <comp_bm> RLE count array to be updated 129 * <opstr> Descriptive text for bitmap RLE count display 130 */ 131 static void 132 print_comp_bm(unsigned char *bm, uint_t size, ushort_t *comp_bm, char *opstr) 133 { 134 int cnt_clean, tot_dirty, cur_idx; 135 int i, cur_clean, cur_dirty, printit, max_set_cnt, max_reset_cnt; 136 137 cnt_clean = 1; 138 printit = 0; 139 cur_clean = 0; 140 cur_dirty = 0; 141 cur_idx = 0; 142 tot_dirty = 0; 143 max_set_cnt = max_reset_cnt = 0; 144 for (i = 0; i < size; i++) { 145 if (isset(bm, i)) { 146 /* If we're counting clean bits, flush the count out */ 147 if (cnt_clean) { 148 cnt_clean = 0; 149 comp_bm[cur_idx] = cur_clean; 150 printit = 1; 151 if (cur_clean > max_reset_cnt) { 152 max_reset_cnt = cur_clean; 153 } 154 } 155 cur_clean = 0; 156 cur_dirty++; 157 tot_dirty++; 158 } else { 159 if (!cnt_clean) { 160 cnt_clean = 1; 161 comp_bm[cur_idx] = cur_dirty; 162 printit = 1; 163 if (cur_dirty > max_set_cnt) { 164 max_set_cnt = cur_dirty; 165 } 166 } 167 cur_dirty = 0; 168 cur_clean++; 169 } 170 if (printit) { 171 mdb_printf("%u.", comp_bm[cur_idx++]); 172 printit = 0; 173 } 174 } 175 176 mdb_printf("\nTotal %s bits = %lu\n", opstr, tot_dirty); 177 mdb_printf("Total %s transactions = %lu\n", opstr, cur_idx); 178 mdb_printf("Maximum %s set count = %lu, reset count = %lu\n", opstr, 179 max_set_cnt, max_reset_cnt); 180 } 181 182 void 183 print_mirror(void *un_addr, void *mdcptr, uint_t verbose) 184 { 185 mm_unit_t mm, *mmp; 186 void **ptr; 187 int setno = 0; 188 minor_t un_self_id; 189 diskaddr_t un_total_blocks; 190 ushort_t mm_un_nsm; 191 submirror_cb_t data; 192 uint_t num_rr, rr_blksize; 193 ushort_t *comp_rr; 194 unsigned char *rr_dirty_bm, *rr_goingclean_bm; 195 uintptr_t un_dbm, un_gcbm; 196 197 /* read in the device */ 198 if (mdb_vread(&mm, sizeof (mm_unit_t), 199 (uintptr_t)un_addr) == -1) { 200 mdb_warn("failed to read mm_unit_t at %p\n", un_addr); 201 return; 202 } 203 204 mmp = &mm; 205 206 un_self_id = ((mdc_unit_t *)mdcptr)->un_self_id; 207 un_total_blocks = ((mdc_unit_t *)mdcptr)->un_total_blocks; 208 mm_un_nsm = mm.un_nsm; 209 setno = MD_MIN2SET(un_self_id); 210 print_setname(setno); 211 212 mdb_printf("d%u: Mirror", MD_MIN2UNIT(un_self_id)); 213 if (verbose) { 214 mdb_printf("\t< %p::print mm_unit_t >\n", un_addr); 215 } else { 216 mdb_printf("\t< %p >\n", un_addr); 217 } 218 mdb_inc_indent(2); 219 mdb_printf("Size: %llu blocks\n", un_total_blocks); 220 221 /* 222 * Dump out the current un_dirty_bm together with its size 223 * Also, attempt to Run Length encode the bitmap to see if this 224 * is a viable option 225 */ 226 num_rr = mm.un_rrd_num; 227 rr_blksize = mm.un_rrd_blksize; 228 229 un_dbm = (uintptr_t)mmp->un_dirty_bm; 230 un_gcbm = (uintptr_t)mmp->un_goingclean_bm; 231 232 mdb_printf("RR size: %lu bits\n", num_rr); 233 mdb_printf("RR block size: %lu blocks\n", rr_blksize); 234 235 rr_dirty_bm = (unsigned char *)mdb_alloc(num_rr, UM_SLEEP|UM_GC); 236 rr_goingclean_bm = (unsigned char *)mdb_alloc(num_rr, UM_SLEEP|UM_GC); 237 comp_rr = (ushort_t *)mdb_alloc(num_rr * sizeof (ushort_t), 238 UM_SLEEP|UM_GC); 239 240 if (mdb_vread(rr_dirty_bm, num_rr, un_dbm) == -1) { 241 mdb_warn("failed to read un_dirty_bm at %p\n", un_dbm); 242 return; 243 } 244 if (mdb_vread(rr_goingclean_bm, num_rr, un_gcbm) == -1) { 245 mdb_warn("failed to read un_goingclean_bm at %p\n", un_gcbm); 246 return; 247 } 248 249 print_comp_bm(rr_dirty_bm, num_rr, comp_rr, "dirty"); 250 251 print_comp_bm(rr_goingclean_bm, num_rr, comp_rr, "clean"); 252 253 /* 254 * find the sub mirrors, search through each metadevice looking 255 * at the un_parent. 256 */ 257 ptr = mdset[setno].s_un; 258 259 data.un_self_id = un_self_id; 260 data.un_nsm = 0; 261 data.mm_un_nsm = mm_un_nsm; 262 263 if (mdb_pwalk("md_units", (mdb_walk_cb_t)print_submirror, &data, 264 (uintptr_t)ptr) == -1) { 265 mdb_warn("unable to walk units\n"); 266 return; 267 } 268 269 mdb_dec_indent(2); 270 } 271 272 void 273 print_raid(void *un_addr, void *mdcptr, uint_t verbose) 274 { 275 mr_unit_t mr; 276 minor_t un_self_id; 277 diskaddr_t un_total_blocks; 278 mdc_unit_t mdc_sc; 279 void **ptr; 280 void *addr; 281 int setno = 0; 282 int i; 283 minor_t sc_un_self_id; 284 md_parent_t sc_parent; 285 diskaddr_t sc_total_blocks; 286 287 /* read in the device */ 288 if (mdb_vread(&mr, sizeof (mr_unit_t), (uintptr_t)un_addr) == -1) { 289 mdb_warn("failed to read mr_unit_t at %p\n", un_addr); 290 return; 291 } 292 un_self_id = ((mdc_unit_t *)mdcptr)->un_self_id; 293 un_total_blocks = ((mdc_unit_t *)mdcptr)->un_total_blocks; 294 setno = MD_MIN2SET(un_self_id); 295 print_setname(setno); 296 297 mdb_printf("d%u: Raid", MD_MIN2UNIT(un_self_id)); 298 if (verbose) { 299 mdb_printf("\t< %p ::print mr_unit_t>\n", un_addr); 300 } else { 301 mdb_printf("\t< %p >\n", un_addr); 302 } 303 mdb_inc_indent(2); 304 mdb_printf("Size: %llu\n", un_total_blocks); 305 306 /* 307 * find the sub components if any, search through each metadevice 308 * looking at the un_parent. 309 */ 310 ptr = mdset[setno].s_un; 311 for (i = 0; i < md_nunits; i++, ptr++) { 312 if (mdb_vread(&addr, sizeof (void *), (uintptr_t)ptr) == -1) { 313 mdb_warn("failed to read addr at %p\n", ptr); 314 continue; 315 } 316 if (addr != NULL) { 317 if (mdb_vread(&mdc_sc, sizeof (mdc_unit_t), 318 (uintptr_t)addr) == -1) { 319 mdb_warn("failed to read mdc_unit_t at %p", 320 un_addr); 321 continue; 322 } 323 sc_parent = mdc_sc.un_parent; 324 sc_un_self_id = mdc_sc.un_self_id; 325 sc_total_blocks = mdc_sc.un_total_blocks; 326 if (sc_parent == un_self_id) { 327 /* this is one of the sub components */ 328 mdb_printf("Subdevice %u ", 329 MD_MIN2UNIT(sc_un_self_id)); 330 mdb_printf("Size: %llu\n", sc_total_blocks); 331 } 332 } 333 } 334 mdb_dec_indent(2); 335 } 336 337 void 338 print_sp(void *un_addr, void *mdcptr, uint_t verbose) 339 { 340 mp_unit_t mp; 341 minor_t un_self_id; 342 diskaddr_t un_total_blocks; 343 int setno = 0; 344 uintptr_t extaddr; 345 int i; 346 347 /* read in the device */ 348 if (mdb_vread(&mp, sizeof (mp_unit_t), (uintptr_t)un_addr) == -1) { 349 mdb_warn("failed to read mp_unit_t at %p\n", un_addr); 350 return; 351 } 352 un_self_id = ((mdc_unit_t *)mdcptr)->un_self_id; 353 un_total_blocks = ((mdc_unit_t *)mdcptr)->un_total_blocks; 354 setno = MD_MIN2SET(un_self_id); 355 print_setname(setno); 356 357 mdb_printf("d%u: Soft Partition", MD_MIN2UNIT(un_self_id)); 358 if (verbose) { 359 mdb_printf("\t< %p ::print mp_unit_t >\n", un_addr); 360 } else { 361 mdb_printf("\t< %p >\n", un_addr); 362 } 363 mdb_inc_indent(2); 364 mdb_printf("Size: %llu\n", un_total_blocks); 365 mdb_inc_indent(2); 366 mdb_printf("Extent\tStart Block\tBlock count\n"); 367 extaddr = (uintptr_t)un_addr + sizeof (mp_unit_t) - sizeof (mp_ext_t); 368 for (i = 0; i < mp.un_numexts; i++) { 369 mp_ext_t mpext; 370 371 if (mdb_vread(&mpext, sizeof (mp_ext_t), extaddr) == -1) { 372 mdb_warn("failed to read mp_ext_t at %p\n", extaddr); 373 return; 374 } 375 mdb_printf(" %d \t %llu\t %llu\n", 376 i, mpext.un_poff, mpext.un_len); 377 extaddr += sizeof (mp_ext_t); 378 } 379 mdb_dec_indent(2); 380 mdb_dec_indent(2); 381 382 } 383 384 void 385 print_trans(void *un_addr, void *mdcptr, uint_t verbose) 386 { 387 mt_unit_t mt; 388 minor_t un_self_id; 389 int setno = 0; 390 391 /* read in the device */ 392 if (mdb_vread(&mt, sizeof (mt_unit_t), (uintptr_t)un_addr) == -1) { 393 mdb_warn("failed to read mt_unit_t at %p\n", un_addr); 394 return; 395 } 396 un_self_id = ((mdc_unit32_od_t *)mdcptr)->un_self_id; 397 setno = MD_MIN2SET(un_self_id); 398 print_setname(setno); 399 400 mdb_printf("d%u: Trans", MD_MIN2UNIT(un_self_id)); 401 if (verbose) { 402 mdb_printf("\t< %p ::print mt_unit_t>\n", un_addr); 403 } else { 404 mdb_printf("\t< %p >\n", un_addr); 405 } 406 407 } 408 409 void 410 print_device(void *un_addr, void *mdcptr, uint_t verbose) 411 { 412 u_longlong_t un_type; 413 414 un_type = ((mdc_unit_t *)mdcptr)->un_type; 415 416 switch (un_type) { 417 case MD_DEVICE: /* stripe/concat */ 418 print_stripe(un_addr, mdcptr, verbose); 419 break; 420 case MD_METAMIRROR: 421 print_mirror(un_addr, mdcptr, verbose); 422 break; 423 case MD_METATRANS: 424 print_trans(un_addr, mdcptr, verbose); 425 break; 426 case MD_METARAID: 427 print_raid(un_addr, mdcptr, verbose); 428 break; 429 case MD_METASP: 430 print_sp(un_addr, mdcptr, verbose); 431 break; 432 case MD_UNDEFINED: 433 mdb_warn("undefined metadevice at %p\n", un_addr); 434 break; 435 default: 436 mdb_warn("invalid metadevice at %p\n", un_addr); 437 break; 438 } 439 } 440 441 /* ARGSUSED */ 442 /* 443 * usage: ::metastat [-v] 444 */ 445 int 446 metastat(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 447 { 448 mdc_unit_t mdc; 449 uintptr_t un_addr; 450 uint_t verbose = FALSE; 451 452 snarf_sets(); 453 454 if (mdb_getopts(argc, argv, 'v', MDB_OPT_SETBITS, TRUE, &verbose, NULL) 455 != argc) { 456 return (DCMD_USAGE); 457 } 458 459 if (!(flags & DCMD_ADDRSPEC)) { 460 if (mdb_walk_dcmd("md_units", "metastat", argc, 461 argv) == -1) { 462 mdb_warn("failed to walk units"); 463 return (DCMD_ERR); 464 } 465 return (DCMD_OK); 466 } 467 if (!(flags & DCMD_LOOP)) { 468 /* user passed set addr */ 469 if (mdb_pwalk_dcmd("md_units", "metastat", argc, 470 argv, addr) == -1) { 471 mdb_warn("failed to walk units"); 472 return (DCMD_ERR); 473 } 474 return (DCMD_OK); 475 } 476 477 if (mdb_vread(&un_addr, sizeof (void *), addr) == -1) { 478 mdb_warn("failed to read un_addr at %p", addr); 479 return (DCMD_ERR); 480 } 481 482 if (un_addr != NULL) { 483 if (mdb_vread(&mdc, sizeof (mdc_unit_t), un_addr) == -1) { 484 mdb_warn("failed to read mdc_unit_t at %p", un_addr); 485 return (DCMD_ERR); 486 } 487 print_device((void *)un_addr, (void *)&mdc, verbose); 488 mdb_dec_indent(2); 489 } 490 return (DCMD_OK); 491 } 492