1 /* 2 * Copyright (c) 2008 The DragonFly Project. All rights reserved. 3 * 4 * This code is derived from software contributed to The DragonFly Project 5 * by Matthew Dillon <dillon@backplane.com> 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in 15 * the documentation and/or other materials provided with the 16 * distribution. 17 * 3. Neither the name of The DragonFly Project nor the names of its 18 * contributors may be used to endorse or promote products derived 19 * from this software without specific, prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 24 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 25 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 26 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, 27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 29 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 30 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 31 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 */ 34 35 #include "hammer.h" 36 37 #include <sys/tree.h> 38 #include <libutil.h> 39 40 #define FLAG_TOOFARLEFT 0x0001 41 #define FLAG_TOOFARRIGHT 0x0002 42 #define FLAG_BADTYPE 0x0004 43 #define FLAG_BADCHILDPARENT 0x0008 44 #define FLAG_BADMIRRORTID 0x0010 45 46 static struct { 47 struct hammer_base_elm base; 48 int limit; /* # of fields to test */ 49 int filter; /* filter type (default -1) */ 50 int obfuscate; /* obfuscate direntry name */ 51 int indent; /* use depth indentation */ 52 zone_stat_t stats; 53 } opt; 54 55 static __inline void print_btree(hammer_off_t node_offset); 56 static __inline void print_subtree(hammer_btree_elm_t elm); 57 static void print_btree_node(hammer_off_t node_offset, hammer_tid_t mirror_tid, 58 hammer_btree_elm_t lbe); 59 static int test_node_count(hammer_node_ondisk_t node, char *badmp); 60 static void print_btree_elm(hammer_node_ondisk_t node, hammer_off_t node_offset, 61 hammer_btree_elm_t elm, hammer_btree_elm_t lbe, const char *ext); 62 static int get_elm_flags(hammer_node_ondisk_t node, hammer_off_t node_offset, 63 hammer_btree_elm_t elm, hammer_btree_elm_t lbe); 64 static int test_lr(hammer_btree_elm_t elm, hammer_btree_elm_t lbe); 65 static int test_rbn_lr(hammer_btree_elm_t elm, hammer_btree_elm_t lbe); 66 static void print_bigblock_fill(hammer_off_t offset); 67 static const char *check_data_crc(hammer_btree_elm_t elm, const char **whichp); 68 static hammer_crc_t get_inode_crc(hammer_btree_leaf_elm_t leaf, 69 const char **whichp); 70 static hammer_crc_t get_buf_crc(hammer_btree_leaf_elm_t leaf, 71 const char **whichp); 72 static void print_record(hammer_btree_elm_t elm); 73 static int init_btree_search(const char *arg); 74 static int test_btree_search(hammer_btree_elm_t elm); 75 static __inline int test_btree_match(hammer_btree_elm_t elm); 76 static int test_btree_out_of_range(hammer_btree_elm_t elm); 77 static void hexdump_record(const void *ptr, int length, const char *hdr); 78 79 static int num_bad_node = 0; 80 static int num_bad_elm = 0; 81 static int num_bad_rec = 0; 82 static int depth; 83 84 static const char* _indents[] = { 85 "", 86 "\t", 87 "\t\t", 88 "\t\t\t", 89 "\t\t\t\t", 90 "\t\t\t\t\t", 91 "\t\t\t\t\t\t", 92 "\t\t\t\t\t\t\t", 93 "\t\t\t\t\t\t\t\t", 94 "\t\t\t\t\t\t\t\t\t", /* deep enough */ 95 }; 96 #define INDENT _indents[opt.indent ? depth : 0] 97 98 void 99 hammer_cmd_show(const char *arg, int filter, int obfuscate, int indent) 100 { 101 volume_info_t volume; 102 hammer_volume_ondisk_t ondisk; 103 zone_stat_t stats = NULL; 104 105 volume = get_root_volume(); 106 ondisk = volume->ondisk; 107 108 print_blockmap(volume); 109 110 if (VerboseOpt) 111 stats = hammer_init_zone_stat_bits(); 112 113 bzero(&opt, sizeof(opt)); 114 opt.filter = filter; 115 opt.obfuscate = obfuscate; 116 opt.indent = indent; 117 opt.stats = stats; 118 119 if (init_btree_search(arg) > 0) { 120 printf("arg=\"%s\"", arg); 121 if (opt.limit > 0) 122 printf(" lo=%08x", opt.base.localization); 123 if (opt.limit > 1) 124 printf(" objid=%016jx", (uintmax_t)opt.base.obj_id); 125 if (opt.limit > 2) 126 printf(" rt=%02x", opt.base.rec_type); 127 if (opt.limit > 3) 128 printf(" key=%016jx", (uintmax_t)opt.base.key); 129 if (opt.limit > 4) 130 printf(" tid=%016jx", (uintmax_t)opt.base.create_tid); 131 printf("\n"); 132 } 133 print_btree(ondisk->vol0_btree_root); 134 135 if (stats) { 136 hammer_print_zone_stat(stats); 137 hammer_cleanup_zone_stat(stats); 138 } 139 140 if (num_bad_node || VerboseOpt) 141 printf("%d bad nodes\n", num_bad_node); 142 if (num_bad_elm || VerboseOpt) 143 printf("%d bad elms\n", num_bad_elm); 144 if (num_bad_rec || VerboseOpt) 145 printf("%d bad records\n", num_bad_rec); 146 } 147 148 static __inline 149 void 150 print_btree(hammer_off_t node_offset) 151 { 152 depth = -1; 153 print_btree_node(node_offset, HAMMER_MAX_TID, NULL); 154 assert(depth == -1); 155 } 156 157 static __inline 158 void 159 print_subtree(hammer_btree_elm_t elm) 160 { 161 hammer_btree_internal_elm_t i = &elm->internal; 162 print_btree_node(i->subtree_offset, i->mirror_tid, elm); 163 } 164 165 static 166 void 167 print_btree_node(hammer_off_t node_offset, hammer_tid_t mirror_tid, 168 hammer_btree_elm_t lbe) 169 { 170 buffer_info_t buffer = NULL; 171 hammer_node_ondisk_t node; 172 hammer_btree_elm_t elm; 173 int i; 174 char badc = ' '; /* good */ 175 char badm = ' '; /* good */ 176 const char *ext; 177 178 depth++; 179 node = get_buffer_data(node_offset, &buffer, 0); 180 181 if (node == NULL) { 182 badc = 'B'; 183 badm = 'I'; 184 } else { 185 if (!hammer_crc_test_btree(HammerVersion, node)) 186 badc = 'B'; 187 if (node->mirror_tid > mirror_tid) { 188 badc = 'B'; 189 badm = 'M'; 190 } 191 if (test_node_count(node, &badm) == -1) { 192 badc = 'B'; 193 assert(badm != ' '); 194 } 195 } 196 197 if (badm != ' ' || badc != ' ') /* not good */ 198 ++num_bad_node; 199 200 printf("%s%c%c NODE %016jx ", 201 INDENT, badc, badm, (uintmax_t)node_offset); 202 printf("cnt=%02d p=%016jx type=%c depth=%d mirror=%016jx", 203 node->count, 204 (uintmax_t)node->parent, 205 (node->type ? node->type : '?'), 206 depth, 207 (uintmax_t)node->mirror_tid); 208 printf(" fill="); 209 print_bigblock_fill(node_offset); 210 printf(" {\n"); 211 212 if (opt.stats) 213 hammer_add_zone_stat(opt.stats, node_offset, sizeof(*node)); 214 215 for (i = 0; i < node->count; ++i) { 216 elm = &node->elms[i]; 217 ext = NULL; 218 if (opt.limit) { 219 switch (node->type) { 220 case HAMMER_BTREE_TYPE_INTERNAL: 221 if (!test_btree_out_of_range(elm)) 222 ext = "*"; 223 break; 224 case HAMMER_BTREE_TYPE_LEAF: 225 if (test_btree_match(elm)) 226 ext = "*"; 227 break; 228 } 229 } 230 print_btree_elm(node, node_offset, elm, lbe, ext); 231 } 232 if (node->type == HAMMER_BTREE_TYPE_INTERNAL) { 233 assert(i == node->count); /* boundary */ 234 elm = &node->elms[i]; 235 print_btree_elm(node, node_offset, elm, lbe, NULL); 236 } 237 printf("%s }\n", INDENT); 238 239 if (node->type == HAMMER_BTREE_TYPE_INTERNAL) { 240 for (i = 0; i < node->count; ++i) { 241 elm = &node->elms[i]; 242 if (opt.limit && opt.filter) { 243 if (test_btree_out_of_range(elm)) 244 continue; 245 } 246 if (elm->internal.subtree_offset) { 247 print_subtree(elm); 248 /* 249 * Cause show to do normal iteration after 250 * seeking to the lo:objid:rt:key:tid 251 * by default 252 */ 253 if (opt.limit && opt.filter == -1) /* default */ 254 opt.filter = 0; 255 } 256 } 257 } 258 rel_buffer(buffer); 259 depth--; 260 } 261 262 static 263 int 264 test_node_count(hammer_node_ondisk_t node, char *badmp) 265 { 266 hammer_node_ondisk_t parent_node; 267 buffer_info_t buffer = NULL; 268 int maxcount; 269 270 maxcount = hammer_node_max_elements(node->type); 271 272 if (maxcount == -1) { 273 *badmp = 'U'; 274 return(-1); 275 } else if (node->count > maxcount) { 276 *badmp = 'C'; 277 return(-1); 278 } else if (node->count == 0) { 279 parent_node = get_buffer_data(node->parent, &buffer, 0); 280 if (parent_node->count != 1) { 281 *badmp = 'C'; 282 rel_buffer(buffer); 283 return(-1); 284 } 285 rel_buffer(buffer); 286 } 287 288 return(0); 289 } 290 291 static __inline 292 int 293 is_root_btree_beg(uint8_t type, int i, hammer_btree_elm_t elm) 294 { 295 /* 296 * elm->base.btype depends on what the original node had 297 * so it could be anything but HAMMER_BTREE_TYPE_NONE. 298 */ 299 return (type == HAMMER_BTREE_TYPE_INTERNAL && 300 i == 0 && 301 elm->base.localization == HAMMER_MIN_ONDISK_LOCALIZATION && 302 elm->base.obj_id == (int64_t)HAMMER_MIN_OBJID && 303 elm->base.key == (int64_t)HAMMER_MIN_KEY && 304 elm->base.create_tid == 1 && 305 elm->base.delete_tid == 1 && 306 elm->base.rec_type == HAMMER_MIN_RECTYPE && 307 elm->base.obj_type == 0 && 308 elm->base.btype != HAMMER_BTREE_TYPE_NONE); 309 } 310 311 static __inline 312 int 313 is_root_btree_end(uint8_t type, int i, hammer_btree_elm_t elm) 314 { 315 return (type == HAMMER_BTREE_TYPE_INTERNAL && 316 i != 0 && 317 elm->base.localization == HAMMER_MAX_ONDISK_LOCALIZATION && 318 elm->base.obj_id == HAMMER_MAX_OBJID && 319 elm->base.key == HAMMER_MAX_KEY && 320 elm->base.create_tid == HAMMER_MAX_TID && 321 elm->base.delete_tid == 0 && 322 elm->base.rec_type == HAMMER_MAX_RECTYPE && 323 elm->base.obj_type == 0 && 324 elm->base.btype == HAMMER_BTREE_TYPE_NONE); 325 } 326 327 static 328 void 329 print_btree_elm(hammer_node_ondisk_t node, hammer_off_t node_offset, 330 hammer_btree_elm_t elm, hammer_btree_elm_t lbe, const char *ext) 331 { 332 char flagstr[8] = { 0, '-', '-', '-', '-', '-', '-', 0 }; 333 char deleted; 334 char rootelm; 335 const char *label; 336 const char *p; 337 const char *which; 338 int flags; 339 int i = ((char*)elm - (char*)node) / (int)sizeof(*elm) - 1; 340 341 flags = get_elm_flags(node, node_offset, elm, lbe); 342 flagstr[0] = flags ? 'B' : 'G'; 343 if (flags & FLAG_TOOFARLEFT) 344 flagstr[2] = 'L'; 345 if (flags & FLAG_TOOFARRIGHT) 346 flagstr[3] = 'R'; 347 if (flags & FLAG_BADTYPE) 348 flagstr[4] = 'T'; 349 if (flags & FLAG_BADCHILDPARENT) 350 flagstr[5] = 'C'; 351 if (flags & FLAG_BADMIRRORTID) 352 flagstr[6] = 'M'; 353 if (flagstr[0] == 'B') 354 ++num_bad_elm; 355 356 /* 357 * Check if elm is derived from root split 358 */ 359 if (is_root_btree_beg(node->type, i, elm)) 360 rootelm = '>'; 361 else if (is_root_btree_end(node->type, i, elm)) 362 rootelm = '<'; 363 else 364 rootelm = ' '; 365 366 if (elm->base.delete_tid) 367 deleted = 'd'; 368 else 369 deleted = ' '; 370 371 if (node->type == HAMMER_BTREE_TYPE_INTERNAL && node->count == i) 372 label = "RBN"; 373 else 374 label = "ELM"; 375 376 printf("%s%s %s %2d %c ", 377 INDENT, flagstr, label, i, hammer_elm_btype(elm)); 378 printf("lo=%08x objid=%016jx rt=%02x key=%016jx tid=%016jx\n", 379 elm->base.localization, 380 (uintmax_t)elm->base.obj_id, 381 elm->base.rec_type, 382 (uintmax_t)elm->base.key, 383 (uintmax_t)elm->base.create_tid); 384 printf("%s %c del=%016jx ot=%02x", 385 INDENT, 386 (rootelm == ' ' ? deleted : rootelm), 387 (uintmax_t)elm->base.delete_tid, 388 elm->base.obj_type); 389 390 switch(node->type) { 391 case HAMMER_BTREE_TYPE_INTERNAL: 392 printf(" suboff=%016jx mirror=%016jx", 393 (uintmax_t)elm->internal.subtree_offset, 394 (uintmax_t)elm->internal.mirror_tid); 395 if (ext) 396 printf(" %s", ext); 397 break; 398 case HAMMER_BTREE_TYPE_LEAF: 399 switch(elm->base.btype) { 400 case HAMMER_BTREE_TYPE_RECORD: 401 printf(" dataoff=%016jx/%d", 402 (uintmax_t)elm->leaf.data_offset, 403 elm->leaf.data_len); 404 p = check_data_crc(elm, &which); 405 printf(" %scrc=%08x", which, elm->leaf.data_crc); 406 if (p) { 407 printf(" error=%s", p); 408 ++num_bad_rec; 409 } 410 printf(" fill="); 411 print_bigblock_fill(elm->leaf.data_offset); 412 if (QuietOpt < 2) 413 print_record(elm); 414 if (opt.stats) { 415 hammer_add_zone_stat(opt.stats, 416 elm->leaf.data_offset, 417 elm->leaf.data_len); 418 } 419 break; 420 default: 421 printf(" badtype=%d", elm->base.btype); 422 break; 423 } 424 if (ext) 425 printf(" %s", ext); 426 break; 427 } 428 printf("\n"); 429 } 430 431 static 432 int 433 get_elm_flags(hammer_node_ondisk_t node, hammer_off_t node_offset, 434 hammer_btree_elm_t elm, hammer_btree_elm_t lbe) 435 { 436 hammer_off_t child_offset; 437 int flags = 0; 438 int i = ((char*)elm - (char*)node) / (int)sizeof(*elm) - 1; 439 440 switch(node->type) { 441 case HAMMER_BTREE_TYPE_INTERNAL: 442 child_offset = elm->internal.subtree_offset; 443 if (elm->internal.mirror_tid > node->mirror_tid) 444 flags |= FLAG_BADMIRRORTID; 445 446 if (i == node->count) { 447 if (child_offset != 0) 448 flags |= FLAG_BADCHILDPARENT; 449 switch(elm->base.btype) { 450 case HAMMER_BTREE_TYPE_NONE: 451 flags |= test_rbn_lr(elm, lbe); 452 break; 453 default: 454 flags |= FLAG_BADTYPE; 455 break; 456 } 457 } else { 458 if (child_offset == 0) { 459 flags |= FLAG_BADCHILDPARENT; 460 } else { 461 buffer_info_t buffer = NULL; 462 hammer_node_ondisk_t subnode; 463 subnode = get_buffer_data(child_offset, &buffer, 0); 464 if (subnode == NULL) 465 flags |= FLAG_BADCHILDPARENT; 466 else if (subnode->parent != node_offset) 467 flags |= FLAG_BADCHILDPARENT; 468 rel_buffer(buffer); 469 } 470 switch(elm->base.btype) { 471 case HAMMER_BTREE_TYPE_INTERNAL: 472 case HAMMER_BTREE_TYPE_LEAF: 473 flags |= test_lr(elm, lbe); 474 break; 475 default: 476 flags |= FLAG_BADTYPE; 477 break; 478 } 479 } 480 break; 481 case HAMMER_BTREE_TYPE_LEAF: 482 if (elm->leaf.data_offset == 0) 483 flags |= FLAG_BADCHILDPARENT; 484 if (elm->leaf.data_len == 0) 485 flags |= FLAG_BADCHILDPARENT; 486 487 if (node->mirror_tid == 0 && 488 !(node->parent == 0 && node->count == 2)) { 489 flags |= FLAG_BADMIRRORTID; 490 } 491 if (elm->base.create_tid && node->mirror_tid && 492 elm->base.create_tid > node->mirror_tid) { 493 flags |= FLAG_BADMIRRORTID; 494 } 495 if (elm->base.delete_tid && node->mirror_tid && 496 elm->base.delete_tid > node->mirror_tid) { 497 flags |= FLAG_BADMIRRORTID; 498 } 499 switch(elm->base.btype) { 500 case HAMMER_BTREE_TYPE_RECORD: 501 flags |= test_lr(elm, lbe); 502 break; 503 default: 504 flags |= FLAG_BADTYPE; 505 break; 506 } 507 break; 508 default: 509 flags |= FLAG_BADTYPE; 510 break; 511 } 512 return(flags); 513 } 514 515 /* 516 * Taken from /usr/src/sys/vfs/hammer/hammer_btree.c. 517 */ 518 static 519 int 520 hammer_btree_cmp(hammer_base_elm_t key1, hammer_base_elm_t key2) 521 { 522 if (key1->localization < key2->localization) 523 return(-5); 524 if (key1->localization > key2->localization) 525 return(5); 526 527 if (key1->obj_id < key2->obj_id) 528 return(-4); 529 if (key1->obj_id > key2->obj_id) 530 return(4); 531 532 if (key1->rec_type < key2->rec_type) 533 return(-3); 534 if (key1->rec_type > key2->rec_type) 535 return(3); 536 537 if (key1->key < key2->key) 538 return(-2); 539 if (key1->key > key2->key) 540 return(2); 541 542 if (key1->create_tid == 0) { 543 if (key2->create_tid == 0) 544 return(0); 545 return(1); 546 } 547 if (key2->create_tid == 0) 548 return(-1); 549 if (key1->create_tid < key2->create_tid) 550 return(-1); 551 if (key1->create_tid > key2->create_tid) 552 return(1); 553 return(0); 554 } 555 556 static 557 int 558 test_lr(hammer_btree_elm_t elm, hammer_btree_elm_t lbe) 559 { 560 if (lbe) { 561 hammer_btree_elm_t rbe = lbe + 1; 562 if (hammer_btree_cmp(&elm->base, &lbe->base) < 0) 563 return(FLAG_TOOFARLEFT); 564 if (hammer_btree_cmp(&elm->base, &rbe->base) >= 0) 565 return(FLAG_TOOFARRIGHT); 566 } 567 return(0); 568 } 569 570 static 571 int 572 test_rbn_lr(hammer_btree_elm_t rbn, hammer_btree_elm_t lbe) 573 { 574 if (lbe) { 575 hammer_btree_elm_t rbe = lbe + 1; 576 if (hammer_btree_cmp(&rbn->base, &lbe->base) < 0) 577 return(FLAG_TOOFARLEFT); 578 if (hammer_btree_cmp(&rbn->base, &rbe->base) > 0) 579 return(FLAG_TOOFARRIGHT); 580 } 581 return(0); 582 } 583 584 static 585 void 586 print_bigblock_fill(hammer_off_t offset) 587 { 588 struct hammer_blockmap_layer1 layer1; 589 struct hammer_blockmap_layer2 layer2; 590 int fill; 591 int error; 592 593 blockmap_lookup_save(offset, &layer1, &layer2, &error); 594 printf("z%d:v%d:%d:%d:%lu=", 595 HAMMER_ZONE_DECODE(offset), 596 HAMMER_VOL_DECODE(offset), 597 HAMMER_BLOCKMAP_LAYER1_INDEX(offset), 598 HAMMER_BLOCKMAP_LAYER2_INDEX(offset), 599 offset & HAMMER_BIGBLOCK_MASK64); 600 601 if (error) { 602 printf("B%d", error); 603 } else { 604 fill = layer2.bytes_free * 100 / HAMMER_BIGBLOCK_SIZE; 605 printf("%d%%", 100 - fill); 606 } 607 } 608 609 /* 610 * Check the generic crc on a data element. Inodes record types are 611 * special in that some of their fields are not CRCed. 612 * 613 * Also check that the zone is valid. 614 */ 615 static 616 const char * 617 check_data_crc(hammer_btree_elm_t elm, const char **whichp) 618 { 619 hammer_crc_t crc; 620 621 *whichp = ""; 622 if (elm->leaf.data_offset == 0 || elm->leaf.data_len == 0) 623 return("ZO"); /* zero offset or length */ 624 625 switch (elm->leaf.base.rec_type) { 626 case HAMMER_RECTYPE_INODE: 627 if (elm->leaf.data_len != sizeof(struct hammer_inode_data)) 628 return("BI"); /* bad inode size */ 629 crc = get_inode_crc(&elm->leaf, whichp); 630 break; 631 default: 632 crc = get_buf_crc(&elm->leaf, whichp); 633 break; 634 } 635 636 if (crc == 0) 637 return("Bx"); /* bad crc */ 638 if (crc != elm->leaf.data_crc) 639 return("BX"); /* bad crc */ 640 return(NULL); /* success */ 641 } 642 643 static 644 hammer_crc_t 645 get_inode_crc(hammer_btree_leaf_elm_t leaf, const char **whichp) 646 { 647 buffer_info_t data_buffer = NULL; 648 hammer_crc_t crc; 649 char *ptr; 650 651 ptr = get_buffer_data(leaf->data_offset, &data_buffer, 0); 652 653 if (HammerVersion >= HAMMER_VOL_VERSION_SEVEN) { 654 crc = iscsi_crc32(ptr, HAMMER_INODE_CRCSIZE); 655 if (crc == leaf->data_crc) { 656 *whichp = "i"; 657 goto end; 658 } 659 } 660 661 crc = crc32(ptr, HAMMER_INODE_CRCSIZE); 662 if (crc == leaf->data_crc) { 663 *whichp = "o"; 664 goto end; 665 } 666 667 *whichp = ""; 668 end: 669 rel_buffer(data_buffer); 670 return(crc); 671 } 672 673 typedef uint32_t (*crc32_ext_fn)(const void *, size_t, uint32_t); 674 675 static 676 hammer_crc_t 677 __get_buf_crc(hammer_btree_leaf_elm_t leaf, crc32_ext_fn f) 678 { 679 buffer_info_t data_buffer = NULL; 680 hammer_off_t buf_offset; 681 hammer_crc_t crc = 0; 682 int32_t buf_len, len; 683 char *ptr; 684 685 buf_offset = leaf->data_offset; 686 buf_len = leaf->data_len; 687 688 while (buf_len) { 689 ptr = get_buffer_data(buf_offset, &data_buffer, 0); 690 len = HAMMER_BUFSIZE - ((int)buf_offset & HAMMER_BUFMASK); 691 if (len > buf_len) 692 len = (int)buf_len; 693 assert(len <= HAMMER_BUFSIZE); 694 crc = f(ptr, len, crc); 695 buf_len -= len; 696 buf_offset += len; 697 } 698 rel_buffer(data_buffer); 699 700 return(crc); 701 } 702 703 static 704 hammer_crc_t 705 get_buf_crc(hammer_btree_leaf_elm_t leaf, const char **whichp) 706 { 707 hammer_crc_t crc; 708 709 if (HammerVersion >= HAMMER_VOL_VERSION_SEVEN) { 710 crc = __get_buf_crc(leaf, iscsi_crc32_ext); 711 if (crc == leaf->data_crc) { 712 *whichp = "i"; 713 goto end; 714 } 715 } 716 717 crc = __get_buf_crc(leaf, crc32_ext); 718 if (crc == leaf->data_crc) { 719 *whichp = "o"; 720 goto end; 721 } 722 723 *whichp = ""; 724 end: 725 return(crc); 726 } 727 728 static 729 void 730 print_config(char *cfgtxt) 731 { 732 char *token; 733 734 printf("\n%s%17s", INDENT, ""); 735 printf("config text=\"\n"); 736 if (cfgtxt != NULL) { 737 while((token = strsep(&cfgtxt, "\r\n")) != NULL) { 738 if (strlen(token)) { 739 printf("%s%17s %s\n", 740 INDENT, "", token); 741 } 742 } 743 } 744 printf("%s%17s \"", INDENT, ""); 745 } 746 747 static 748 void 749 print_record(hammer_btree_elm_t elm) 750 { 751 buffer_info_t data_buffer; 752 hammer_off_t data_offset; 753 int32_t data_len; 754 hammer_data_ondisk_t data; 755 char *str1 = NULL; 756 char *str2 = NULL; 757 758 data_offset = elm->leaf.data_offset; 759 data_len = elm->leaf.data_len; 760 assert(data_offset != 0); 761 assert(data_len != 0); 762 763 data_buffer = NULL; 764 data = get_buffer_data(data_offset, &data_buffer, 0); 765 assert(data != NULL); 766 767 switch(elm->leaf.base.rec_type) { 768 case HAMMER_RECTYPE_UNKNOWN: 769 printf("\n%s%17s", INDENT, ""); 770 printf("unknown"); 771 break; 772 case HAMMER_RECTYPE_INODE: 773 printf("\n%s%17s", INDENT, ""); 774 printf("inode size=%jd nlinks=%jd", 775 (intmax_t)data->inode.size, 776 (intmax_t)data->inode.nlinks); 777 printf(" mode=%05o uflags=%08x caps=%02x", 778 data->inode.mode, 779 data->inode.uflags, 780 data->inode.cap_flags); 781 printf(" pobjid=%016jx ot=%02x\n", 782 (uintmax_t)data->inode.parent_obj_id, 783 data->inode.obj_type); 784 printf("%s%17s", INDENT, ""); 785 printf(" ctime=%016jx mtime=%016jx atime=%016jx", 786 (uintmax_t)data->inode.ctime, 787 (uintmax_t)data->inode.mtime, 788 (uintmax_t)data->inode.atime); 789 if (data->inode.ext.symlink[0]) { 790 printf(" symlink=\"%s\"", 791 data->inode.ext.symlink); 792 } 793 break; 794 case HAMMER_RECTYPE_DIRENTRY: 795 data_len -= HAMMER_ENTRY_NAME_OFF; 796 printf("\n%s%17s", INDENT, ""); 797 printf("dir-entry objid=%016jx lo=%08x", 798 (uintmax_t)data->entry.obj_id, 799 data->entry.localization); 800 if (!opt.obfuscate) { 801 printf(" name=\"%*.*s\"", 802 data_len, data_len, data->entry.name); 803 } 804 break; 805 case HAMMER_RECTYPE_FIX: 806 switch(elm->leaf.base.key) { 807 case HAMMER_FIXKEY_SYMLINK: 808 data_len -= HAMMER_SYMLINK_NAME_OFF; 809 printf("\n%s%17s", INDENT, ""); 810 printf("fix-symlink name=\"%*.*s\"", 811 data_len, data_len, data->symlink.name); 812 break; 813 } 814 break; 815 case HAMMER_RECTYPE_PFS: 816 printf("\n%s%17s", INDENT, ""); 817 printf("pfs sync_beg_tid=%016jx sync_end_tid=%016jx\n", 818 (uintmax_t)data->pfsd.sync_beg_tid, 819 (uintmax_t)data->pfsd.sync_end_tid); 820 hammer_uuid_to_string(&data->pfsd.shared_uuid, &str1); 821 hammer_uuid_to_string(&data->pfsd.unique_uuid, &str2); 822 printf("%17s", ""); 823 printf(" shared_uuid=%s\n", str1); 824 printf("%17s", ""); 825 printf(" unique_uuid=%s\n", str2); 826 printf("%17s", ""); 827 printf(" mirror_flags=%08x label=\"%s\"", 828 data->pfsd.mirror_flags, data->pfsd.label); 829 if (data->pfsd.snapshots[0]) 830 printf(" snapshots=\"%s\"", data->pfsd.snapshots); 831 free(str1); 832 free(str2); 833 break; 834 case HAMMER_RECTYPE_SNAPSHOT: 835 printf("\n%s%17s", INDENT, ""); 836 printf("snapshot tid=%016jx label=\"%s\"", 837 (uintmax_t)data->snap.tid, data->snap.label); 838 break; 839 case HAMMER_RECTYPE_CONFIG: 840 if (VerboseOpt > 2) { 841 char *p = strdup(data->config.text); 842 print_config(p); 843 free(p); 844 } 845 break; 846 case HAMMER_RECTYPE_DATA: 847 if (VerboseOpt > 3) { 848 printf("\n"); 849 hexdump_record(data, data_len, "\t\t "); 850 } 851 break; 852 case HAMMER_RECTYPE_EXT: 853 case HAMMER_RECTYPE_DB: 854 if (VerboseOpt > 2) { 855 printf("\n"); 856 hexdump_record(data, data_len, "\t\t "); 857 } 858 break; 859 default: 860 assert(0); 861 break; 862 } 863 rel_buffer(data_buffer); 864 } 865 866 /* 867 * HAMMER userspace only supports buffer size upto HAMMER_BUFSIZE 868 * which is 16KB. Passing record data length larger than 16KB to 869 * hexdump(3) is invalid even if the leaf node elm says >16KB data. 870 */ 871 static 872 void 873 hexdump_record(const void *ptr, int length, const char *hdr) 874 { 875 int data_len = length; 876 877 if (data_len > HAMMER_BUFSIZE) /* XXX */ 878 data_len = HAMMER_BUFSIZE; 879 hexdump(ptr, data_len, hdr, 0); 880 881 if (length > data_len) 882 printf("%s....\n", hdr); 883 } 884 885 static __inline __always_inline 886 unsigned long 887 _strtoul(const char *p, int base) 888 { 889 unsigned long retval; 890 891 errno = 0; /* clear */ 892 retval = strtoul(p, NULL, base); 893 if (errno == ERANGE && retval == ULONG_MAX) { 894 err(1, "strtoul"); 895 /* not reached */ 896 } 897 return retval; 898 } 899 900 static __inline __always_inline 901 unsigned long long 902 _strtoull(const char *p, int base) 903 { 904 unsigned long long retval; 905 906 errno = 0; /* clear */ 907 retval = strtoull(p, NULL, base); 908 if (errno == ERANGE && retval == ULLONG_MAX) { 909 err(1, "strtoull"); 910 /* not reached */ 911 } 912 return retval; 913 } 914 915 static 916 int 917 init_btree_search(const char *arg) 918 { 919 char *s, *p; 920 int i = 0; 921 922 bzero(&opt.base, sizeof(opt.base)); 923 opt.limit = 0; 924 925 if (arg == NULL) 926 return(-1); 927 if (strcmp(arg, "none") == 0) 928 return(-1); 929 930 s = strdup(arg); 931 if (s == NULL) 932 return(-1); 933 934 while ((p = s) != NULL) { 935 if ((s = strchr(s, ':')) != NULL) 936 *s++ = 0; 937 if (++i == 1) { 938 opt.base.localization = _strtoul(p, 16); 939 } else if (i == 2) { 940 opt.base.obj_id = _strtoull(p, 16); 941 } else if (i == 3) { 942 opt.base.rec_type = _strtoul(p, 16); 943 } else if (i == 4) { 944 opt.base.key = _strtoull(p, 16); 945 } else if (i == 5) { 946 opt.base.create_tid = _strtoull(p, 16); 947 break; 948 } 949 } 950 opt.limit = i; 951 free(s); 952 953 return(i); 954 } 955 956 static 957 int 958 test_btree_search(hammer_btree_elm_t elm) 959 { 960 hammer_base_elm_t base1 = &elm->base; 961 hammer_base_elm_t base2 = &opt.base; 962 int limit = opt.limit; 963 964 if (base1->localization < base2->localization) 965 return(-5); 966 if (base1->localization > base2->localization) 967 return(5); 968 if (limit == 1) 969 return(0); /* ignore below */ 970 971 if (base1->obj_id < base2->obj_id) 972 return(-4); 973 if (base1->obj_id > base2->obj_id) 974 return(4); 975 if (limit == 2) 976 return(0); /* ignore below */ 977 978 if (base1->rec_type < base2->rec_type) 979 return(-3); 980 if (base1->rec_type > base2->rec_type) 981 return(3); 982 if (limit == 3) 983 return(0); /* ignore below */ 984 985 if (base1->key < base2->key) 986 return(-2); 987 if (base1->key > base2->key) 988 return(2); 989 if (limit == 4) 990 return(0); /* ignore below */ 991 992 if (base1->create_tid == 0) { 993 if (base2->create_tid == 0) 994 return(0); 995 return(1); 996 } 997 if (base2->create_tid == 0) 998 return(-1); 999 if (base1->create_tid < base2->create_tid) 1000 return(-1); 1001 if (base1->create_tid > base2->create_tid) 1002 return(1); 1003 return(0); 1004 } 1005 1006 static __inline 1007 int 1008 test_btree_match(hammer_btree_elm_t elm) 1009 { 1010 if (test_btree_search(elm) == 0) 1011 return(1); 1012 return(0); 1013 } 1014 1015 static 1016 int 1017 test_btree_out_of_range(hammer_btree_elm_t elm) 1018 { 1019 if (test_btree_search(elm) > 0) 1020 return(1); /* conditions < this elm */ 1021 1022 if (opt.limit >= 5) { 1023 if (test_btree_search(elm + 1) <= 0) 1024 return(1); /* next elm <= conditions */ 1025 } else { 1026 if (test_btree_search(elm + 1) < 0) 1027 return(1); /* next elm < conditions */ 1028 } 1029 return(0); 1030 } 1031 1032 /* 1033 * Dump the UNDO FIFO 1034 */ 1035 void 1036 hammer_cmd_show_undo(void) 1037 { 1038 volume_info_t volume; 1039 hammer_blockmap_t rootmap; 1040 hammer_off_t scan_offset; 1041 hammer_fifo_any_t head; 1042 hammer_fifo_head_t hdr; 1043 buffer_info_t data_buffer = NULL; 1044 zone_stat_t stats = NULL; 1045 1046 volume = get_root_volume(); 1047 rootmap = &volume->ondisk->vol0_blockmap[HAMMER_ZONE_UNDO_INDEX]; 1048 1049 print_blockmap(volume); 1050 1051 if (VerboseOpt) 1052 stats = hammer_init_zone_stat_bits(); 1053 1054 scan_offset = HAMMER_ENCODE_UNDO(0); 1055 while (scan_offset < rootmap->alloc_offset) { 1056 head = get_buffer_data(scan_offset, &data_buffer, 0); 1057 hdr = &head->head; 1058 printf("%016jx ", scan_offset); 1059 1060 switch(hdr->hdr_type) { 1061 case HAMMER_HEAD_TYPE_PAD: 1062 printf("PAD(%d)", hdr->hdr_size); 1063 break; 1064 case HAMMER_HEAD_TYPE_DUMMY: 1065 printf("DUMMY(%d)\tseq=%08x", 1066 hdr->hdr_size, hdr->hdr_seq); 1067 break; 1068 case HAMMER_HEAD_TYPE_UNDO: 1069 printf("UNDO(%u)\tseq=%08x offset=%016jx bytes=%d", 1070 hdr->hdr_size, hdr->hdr_seq, 1071 (uintmax_t)head->undo.undo_offset, 1072 head->undo.undo_data_bytes); 1073 break; 1074 case HAMMER_HEAD_TYPE_REDO: 1075 printf("REDO(%u)\tseq=%08x offset=%016jx bytes=%d " 1076 "objid=%016jx flags=%08x lo=%08x", 1077 hdr->hdr_size, hdr->hdr_seq, 1078 (uintmax_t)head->redo.redo_offset, 1079 head->redo.redo_data_bytes, 1080 (uintmax_t)head->redo.redo_objid, 1081 head->redo.redo_flags, 1082 head->redo.redo_localization); 1083 break; 1084 default: 1085 printf("%04x(%d)\tseq=%08x", 1086 hdr->hdr_type, hdr->hdr_size, hdr->hdr_seq); 1087 break; 1088 } 1089 1090 if (scan_offset == rootmap->first_offset) 1091 printf(" >"); 1092 if (scan_offset == rootmap->next_offset) 1093 printf(" <"); 1094 printf("\n"); 1095 1096 if (stats) 1097 hammer_add_zone_stat(stats, scan_offset, hdr->hdr_size); 1098 1099 if ((hdr->hdr_size & HAMMER_HEAD_ALIGN_MASK) || 1100 hdr->hdr_size == 0 || 1101 hdr->hdr_size > HAMMER_UNDO_ALIGN - 1102 ((u_int)scan_offset & HAMMER_UNDO_MASK)) { 1103 printf("Illegal size field, skipping to " 1104 "next boundary\n"); 1105 scan_offset = HAMMER_UNDO_DOALIGN(scan_offset); 1106 } else { 1107 scan_offset += hdr->hdr_size; 1108 } 1109 } 1110 rel_buffer(data_buffer); 1111 1112 if (stats) { 1113 hammer_print_zone_stat(stats); 1114 hammer_cleanup_zone_stat(stats); 1115 } 1116 } 1117