1 /* 2 * Copyright (c) 2007 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_util.h" 36 37 #include <sys/sysctl.h> 38 #include <sys/ioctl_compat.h> 39 40 static int64_t getsize(const char *str, int pw); 41 static int trim_volume(volume_info_t volume); 42 static void format_volume(volume_info_t volume, int nvols,const char *label); 43 static hammer_off_t format_root_directory(const char *label); 44 static uint64_t nowtime(void); 45 static void print_volume(const volume_info_t volume); 46 static void usage(int exit_code); 47 static void test_header_junk_size(int64_t size); 48 static void test_boot_area_size(int64_t size); 49 static void test_memory_log_size(int64_t size); 50 static void test_undo_buffer_size(int64_t size); 51 52 static int ForceOpt; 53 static int64_t HeaderJunkSize = -1; 54 static int64_t BootAreaSize = -1; 55 static int64_t MemoryLogSize = -1; 56 static int64_t UndoBufferSize; 57 58 #define GIG (1024LL*1024*1024) 59 60 int 61 main(int ac, char **av) 62 { 63 off_t total; 64 off_t avg_vol_size; 65 int ch; 66 int i; 67 int nvols; 68 int eflag = 0; 69 const char *label = NULL; 70 volume_info_t volume; 71 72 /* 73 * Sanity check basic filesystem structures. No cookies for us 74 * if it gets broken! 75 */ 76 assert(sizeof(struct hammer_volume_ondisk) <= HAMMER_BUFSIZE); 77 assert(sizeof(struct hammer_volume_ondisk) <= HAMMER_MIN_VOL_JUNK); 78 assert(sizeof(struct hammer_blockmap_layer1) == 32); 79 assert(sizeof(struct hammer_blockmap_layer2) == 16); 80 81 /* 82 * Parse arguments 83 */ 84 while ((ch = getopt(ac, av, "dfEL:j:b:m:u:hC:V:")) != -1) { 85 switch(ch) { 86 case 'd': 87 ++DebugOpt; 88 break; 89 case 'f': 90 ForceOpt = 1; 91 break; 92 case 'E': 93 eflag = 1; 94 break; 95 case 'L': 96 label = optarg; 97 break; 98 case 'j': /* Not mentioned in newfs_hammer(8) */ 99 HeaderJunkSize = getsize(optarg, 2); 100 test_header_junk_size(HeaderJunkSize); 101 break; 102 case 'b': 103 BootAreaSize = getsize(optarg, 2); 104 test_boot_area_size(BootAreaSize); 105 break; 106 case 'm': 107 MemoryLogSize = getsize(optarg, 2); 108 test_memory_log_size(MemoryLogSize); 109 break; 110 case 'u': 111 UndoBufferSize = getsize(optarg, 2); 112 test_undo_buffer_size(UndoBufferSize); 113 break; 114 case 'h': 115 usage(0); 116 /* not reached */ 117 break; 118 case 'C': 119 if (hammer_parse_cache_size(optarg) == -1) { 120 usage(1); 121 /* not reached */ 122 } 123 break; 124 case 'V': 125 HammerVersion = strtol(optarg, NULL, 0); 126 if (HammerVersion < HAMMER_VOL_VERSION_MIN || 127 HammerVersion >= HAMMER_VOL_VERSION_WIP) { 128 errx(1, 129 "I don't understand how to format " 130 "HAMMER version %d", 131 HammerVersion); 132 /* not reached */ 133 } 134 break; 135 default: 136 usage(1); 137 /* not reached */ 138 break; 139 } 140 } 141 ac -= optind; 142 av += optind; 143 nvols = ac; 144 145 if (HammerVersion == (uint32_t)-1) { 146 size_t olen = sizeof(HammerVersion); 147 HammerVersion = HAMMER_VOL_VERSION_DEFAULT; 148 149 if (sysctlbyname("vfs.hammer.supported_version", 150 &HammerVersion, &olen, NULL, 0)) { 151 hwarn("HAMMER VFS not loaded, cannot get version info, " 152 "using version %d", 153 HammerVersion); 154 } else if (HammerVersion >= HAMMER_VOL_VERSION_WIP) { 155 HammerVersion = HAMMER_VOL_VERSION_WIP - 1; 156 hwarnx("HAMMER VFS supports higher version than " 157 "I understand, using version %d", 158 HammerVersion); 159 } 160 } 161 162 if (nvols == 0) { 163 errx(1, "You must specify at least one special file (volume)"); 164 /* not reached */ 165 } 166 if (nvols > HAMMER_MAX_VOLUMES) { 167 errx(1, "The maximum number of volumes is %d", 168 HAMMER_MAX_VOLUMES); 169 /* not reached */ 170 } 171 172 if (label == NULL) { 173 hwarnx("A filesystem label must be specified"); 174 usage(1); 175 /* not reached */ 176 } 177 178 /* 179 * Generate a filesystem id and lookup the filesystem type 180 */ 181 hammer_uuid_create(&Hammer_FSId); 182 if (hammer_uuid_name_lookup(&Hammer_FSType, HAMMER_FSTYPE_STRING)) { 183 errx(1, "uuids file does not have the DragonFly " 184 "HAMMER filesystem type"); 185 /* not reached */ 186 } 187 188 total = 0; 189 for (i = 0; i < nvols; ++i) { 190 volume = init_volume(av[i], O_RDWR, i); 191 printf("Volume %d %s %-15s size %s\n", 192 volume->vol_no, volume->type, volume->name, 193 sizetostr(volume->size)); 194 195 if (eflag) { 196 if (trim_volume(volume) == -1 && ForceOpt == 0) { 197 errx(1, "Use -f option to proceed"); 198 /* not reached */ 199 } 200 } 201 total += volume->size; 202 } 203 204 /* 205 * Reserve space for (future) header junk, setup our poor-man's 206 * big-block allocator. Note that the header junk space includes 207 * volume header which is 1928 bytes. 208 */ 209 if (HeaderJunkSize == -1) 210 HeaderJunkSize = HAMMER_VOL_JUNK_SIZE; 211 else if (HeaderJunkSize < (int64_t)sizeof(struct hammer_volume_ondisk)) 212 HeaderJunkSize = sizeof(struct hammer_volume_ondisk); 213 HeaderJunkSize = HAMMER_BUFSIZE_DOALIGN(HeaderJunkSize); 214 215 /* 216 * Calculate defaults for the boot area and memory log sizes, 217 * only if not specified by -b or -m option. 218 */ 219 avg_vol_size = total / nvols; 220 if (BootAreaSize == -1) 221 BootAreaSize = init_boot_area_size(BootAreaSize, avg_vol_size); 222 if (MemoryLogSize == -1) 223 MemoryLogSize = init_memory_log_size(MemoryLogSize, avg_vol_size); 224 225 /* 226 * Format the volumes. Format the root volume first so we can 227 * bootstrap the freemap. 228 */ 229 format_volume(get_root_volume(), nvols, label); 230 for (i = 0; i < nvols; ++i) { 231 if (i != HAMMER_ROOT_VOLNO) 232 format_volume(get_volume(i), nvols, label); 233 } 234 235 print_volume(get_root_volume()); 236 237 flush_all_volumes(); 238 return(0); 239 } 240 241 static 242 void 243 print_volume(const volume_info_t volume) 244 { 245 hammer_volume_ondisk_t ondisk; 246 hammer_blockmap_t blockmap; 247 hammer_off_t total = 0; 248 int i, nvols; 249 const char *name = NULL; 250 char *fsidstr; 251 252 ondisk = volume->ondisk; 253 blockmap = &ondisk->vol0_blockmap[HAMMER_ZONE_UNDO_INDEX]; 254 255 nvols = ondisk->vol_count; 256 for (i = 0; i < nvols; ++i) { 257 volume_info_t p = get_volume(i); 258 total += p->size; 259 if (p->vol_no == HAMMER_ROOT_VOLNO) { 260 assert(name == NULL); 261 name = p->name; 262 } 263 } 264 265 hammer_uuid_to_string(&Hammer_FSId, &fsidstr); 266 267 printf("---------------------------------------------\n"); 268 printf("HAMMER version %d\n", HammerVersion); 269 printf("%d volume%s total size %s\n", 270 nvols, (nvols == 1 ? "" : "s"), sizetostr(total)); 271 printf("root-volume: %s\n", name); 272 if (DebugOpt) { 273 printf("header-junk-size: %s\n", 274 sizetostr(ondisk->vol_bot_beg)); 275 } 276 printf("boot-area-size: %s\n", 277 sizetostr(ondisk->vol_mem_beg - ondisk->vol_bot_beg)); 278 printf("memory-log-size: %s\n", 279 sizetostr(ondisk->vol_buf_beg - ondisk->vol_mem_beg)); 280 printf("undo-buffer-size: %s\n", 281 sizetostr(HAMMER_OFF_LONG_ENCODE(blockmap->alloc_offset))); 282 printf("total-pre-allocated: %s\n", 283 sizetostr(HAMMER_OFF_SHORT_ENCODE(volume->vol_free_off))); 284 printf("fsid: %s\n", fsidstr); 285 printf("\n"); 286 printf("NOTE: Please remember that you may have to manually set up a\n" 287 "cron(8) job to prune and reblock the filesystem regularly.\n" 288 "By default, the system automatically runs 'hammer cleanup'\n" 289 "on a nightly basis. The periodic.conf(5) variable\n" 290 "'daily_clean_hammer_enable' can be unset to disable this.\n" 291 "Also see 'man hammer' and 'man HAMMER' for more information.\n"); 292 if (total < 10*GIG) { 293 printf("\nWARNING: The minimum UNDO/REDO FIFO is %s, " 294 "you really should not\n" 295 "try to format a HAMMER filesystem this small.\n", 296 sizetostr(HAMMER_BIGBLOCK_SIZE * 297 HAMMER_MIN_UNDO_BIGBLOCKS)); 298 } 299 if (total < 50*GIG) { 300 printf("\nWARNING: HAMMER filesystems less than 50GB are " 301 "not recommended!\n" 302 "You may have to run 'hammer prune-everything' and " 303 "'hammer reblock'\n" 304 "quite often, even if using a nohistory mount.\n"); 305 } 306 } 307 308 static 309 void 310 usage(int exit_code) 311 { 312 fprintf(stderr, 313 "usage: newfs_hammer -L label [-Efh] [-b bootsize] [-m savesize] [-u undosize]\n" 314 " [-C cachesize[:readahead]] [-V version] special ...\n" 315 ); 316 exit(exit_code); 317 } 318 319 static 320 void 321 test_header_junk_size(int64_t size) 322 { 323 if (size < HAMMER_MIN_VOL_JUNK) { 324 if (ForceOpt == 0) { 325 errx(1, "The minimum header junk size is %s", 326 sizetostr(HAMMER_MIN_VOL_JUNK)); 327 /* not reached */ 328 } else { 329 hwarnx("You have specified header junk size less than %s", 330 sizetostr(HAMMER_MIN_VOL_JUNK)); 331 } 332 } else if (size > HAMMER_MAX_VOL_JUNK) { 333 errx(1, "The maximum header junk size is %s", 334 sizetostr(HAMMER_MAX_VOL_JUNK)); 335 /* not reached */ 336 } 337 } 338 339 static 340 void 341 test_boot_area_size(int64_t size) 342 { 343 if (size < HAMMER_BOOT_MINBYTES) { 344 if (ForceOpt == 0) { 345 errx(1, "The minimum boot area size is %s", 346 sizetostr(HAMMER_BOOT_MINBYTES)); 347 /* not reached */ 348 } else { 349 hwarnx("You have specified boot area size less than %s", 350 sizetostr(HAMMER_BOOT_MINBYTES)); 351 } 352 } else if (size > HAMMER_BOOT_MAXBYTES) { 353 errx(1, "The maximum boot area size is %s", 354 sizetostr(HAMMER_BOOT_MAXBYTES)); 355 /* not reached */ 356 } 357 } 358 359 static 360 void 361 test_memory_log_size(int64_t size) 362 { 363 if (size < HAMMER_MEM_MINBYTES) { 364 if (ForceOpt == 0) { 365 errx(1, "The minimum memory log size is %s", 366 sizetostr(HAMMER_MEM_MINBYTES)); 367 /* not reached */ 368 } else { 369 hwarnx("You have specified memory log size less than %s", 370 sizetostr(HAMMER_MEM_MINBYTES)); 371 } 372 } else if (size > HAMMER_MEM_MAXBYTES) { 373 errx(1, "The maximum memory log size is %s", 374 sizetostr(HAMMER_MEM_MAXBYTES)); 375 /* not reached */ 376 } 377 } 378 379 static 380 void 381 test_undo_buffer_size(int64_t size) 382 { 383 int64_t minbuf, maxbuf; 384 385 minbuf = HAMMER_BIGBLOCK_SIZE * HAMMER_MIN_UNDO_BIGBLOCKS; 386 maxbuf = HAMMER_BIGBLOCK_SIZE * HAMMER_MAX_UNDO_BIGBLOCKS; 387 388 if (size < minbuf) { 389 if (ForceOpt == 0) { 390 errx(1, "The minimum UNDO/REDO FIFO size is %s", 391 sizetostr(minbuf)); 392 /* not reached */ 393 } else { 394 hwarnx("You have specified an UNDO/REDO FIFO size less " 395 "than %s, which may lead to VFS panics", 396 sizetostr(minbuf)); 397 } 398 } else if (size > maxbuf) { 399 errx(1, "The maximum UNDO/REDO FIFO size is %s", 400 sizetostr(maxbuf)); 401 /* not reached */ 402 } 403 } 404 405 /* 406 * Convert a string to a 64 bit signed integer with various requirements. 407 */ 408 static 409 int64_t 410 getsize(const char *str, int powerof2) 411 { 412 int64_t val; 413 char *ptr; 414 415 val = strtoll(str, &ptr, 0); 416 switch(*ptr) { 417 case 't': 418 case 'T': 419 val *= 1024; 420 /* fall through */ 421 case 'g': 422 case 'G': 423 val *= 1024; 424 /* fall through */ 425 case 'm': 426 case 'M': 427 val *= 1024; 428 /* fall through */ 429 case 'k': 430 case 'K': 431 val *= 1024; 432 break; 433 default: 434 errx(1, "Unknown suffix in number '%s'", str); 435 /* not reached */ 436 } 437 438 if (ptr[1]) { 439 errx(1, "Unknown suffix in number '%s'", str); 440 /* not reached */ 441 } 442 if ((powerof2 & 1) && (val ^ (val - 1)) != ((val << 1) - 1)) { 443 errx(1, "Value not power of 2: %s", str); 444 /* not reached */ 445 } 446 if ((powerof2 & 2) && (val & HAMMER_BUFMASK)) { 447 errx(1, "Value not an integral multiple of %dK: %s", 448 HAMMER_BUFSIZE / 1024, str); 449 /* not reached */ 450 } 451 return(val); 452 } 453 454 /* 455 * Generate a transaction id. Transaction ids are no longer time-based. 456 * Put the nail in the coffin by not making the first one time-based. 457 * 458 * We could start at 1 here but start at 2^32 to reserve a small domain for 459 * possible future use. 460 */ 461 static 462 hammer_tid_t 463 createtid(void) 464 { 465 static hammer_tid_t lasttid; 466 467 if (lasttid == 0) 468 lasttid = 0x0000000100000000ULL; 469 return(lasttid++); 470 } 471 472 static 473 uint64_t 474 nowtime(void) 475 { 476 struct timeval tv; 477 uint64_t xtime; 478 479 gettimeofday(&tv, NULL); 480 xtime = tv.tv_sec * 1000000LL + tv.tv_usec; 481 return(xtime); 482 } 483 484 /* 485 * TRIM the volume, but only if the backing store is not a regular file 486 */ 487 static 488 int 489 trim_volume(volume_info_t volume) 490 { 491 size_t olen; 492 char *dev_name, *p; 493 char sysctl_name[64]; 494 int trim_enabled; 495 off_t ioarg[2]; 496 497 if (is_regfile(volume)) { 498 hwarnx("Cannot TRIM regular file %s", volume->name); 499 return(-1); 500 } 501 if (strncmp(volume->name, "/dev/da", 7)) { 502 hwarnx("%s does not support the TRIM command", volume->name); 503 return(-1); 504 } 505 506 /* Extract a number from /dev/da?s? */ 507 dev_name = strdup(volume->name); 508 p = strtok(dev_name + strlen("/dev/da"), "s"); 509 sprintf(sysctl_name, "kern.cam.da.%s.trim_enabled", p); 510 free(dev_name); 511 512 trim_enabled = 0; 513 olen = sizeof(trim_enabled); 514 515 if (sysctlbyname(sysctl_name, &trim_enabled, &olen, NULL, 0) == -1) { 516 hwarnx("%s (%s) does not support the TRIM command", 517 volume->name, sysctl_name); 518 return(-1); 519 } 520 if (!trim_enabled) { 521 hwarnx("Erase device option selected, but sysctl (%s) " 522 "is not enabled", sysctl_name); 523 return(-1); 524 } 525 526 ioarg[0] = volume->device_offset; 527 ioarg[1] = volume->size; 528 529 printf("Trimming %s %s, sectors %llu-%llu\n", 530 volume->type, volume->name, 531 (unsigned long long)ioarg[0] / 512, 532 (unsigned long long)ioarg[1] / 512); 533 534 if (ioctl(volume->fd, IOCTLTRIM, ioarg) == -1) { 535 err(1, "Trimming %s failed", volume->name); 536 /* not reached */ 537 } 538 539 return(0); 540 } 541 542 /* 543 * Format a HAMMER volume. 544 */ 545 static 546 void 547 format_volume(volume_info_t volume, int nvols, const char *label) 548 { 549 volume_info_t root_vol; 550 hammer_volume_ondisk_t ondisk; 551 int64_t freeblks; 552 int64_t freebytes; 553 int64_t vol_buf_size; 554 hammer_off_t vol_alloc; 555 int i; 556 557 /* 558 * Initialize basic information in the on-disk volume structure. 559 */ 560 ondisk = volume->ondisk; 561 562 ondisk->vol_fsid = Hammer_FSId; 563 ondisk->vol_fstype = Hammer_FSType; 564 snprintf(ondisk->vol_label, sizeof(ondisk->vol_label), "%s", label); 565 ondisk->vol_no = volume->vol_no; 566 ondisk->vol_count = nvols; 567 ondisk->vol_version = HammerVersion; 568 569 vol_alloc = HeaderJunkSize; 570 ondisk->vol_bot_beg = vol_alloc; 571 vol_alloc += BootAreaSize; 572 ondisk->vol_mem_beg = vol_alloc; 573 vol_alloc += MemoryLogSize; 574 575 /* 576 * The remaining area is the zone 2 buffer allocation area. 577 */ 578 ondisk->vol_buf_beg = vol_alloc; 579 ondisk->vol_buf_end = volume->size & ~(int64_t)HAMMER_BUFMASK; 580 vol_buf_size = HAMMER_VOL_BUF_SIZE(ondisk); 581 582 if (vol_buf_size < (int64_t)sizeof(*ondisk)) { 583 errx(1, "volume %d %s is too small to hold the volume header", 584 volume->vol_no, volume->name); 585 /* not reached */ 586 } 587 if ((vol_buf_size & ~HAMMER_OFF_SHORT_MASK) != 0) { 588 errx(1, "volume %d %s is too large", volume->vol_no, volume->name); 589 /* not reached */ 590 } 591 592 ondisk->vol_rootvol = HAMMER_ROOT_VOLNO; 593 ondisk->vol_signature = HAMMER_FSBUF_VOLUME; 594 595 volume->vol_free_off = HAMMER_ENCODE_RAW_BUFFER(volume->vol_no, 0); 596 volume->vol_free_end = HAMMER_ENCODE_RAW_BUFFER(volume->vol_no, 597 vol_buf_size & ~HAMMER_BIGBLOCK_MASK64); 598 599 /* 600 * Format the root volume. 601 */ 602 if (volume->vol_no == HAMMER_ROOT_VOLNO) { 603 /* 604 * Check freemap counts before formatting 605 */ 606 freeblks = count_freemap(volume); 607 freebytes = freeblks * HAMMER_BIGBLOCK_SIZE64; 608 if (freebytes < 10*GIG && ForceOpt == 0) { 609 errx(1, "Cannot create a HAMMER filesystem less than 10GB " 610 "unless you use -f\n(for the size of Volume %d). " 611 "HAMMER filesystems less than 50GB are not " 612 "recommended.", HAMMER_ROOT_VOLNO); 613 /* not reached */ 614 } 615 616 /* 617 * Starting TID 618 */ 619 ondisk->vol0_next_tid = createtid(); 620 621 /* 622 * Format freemap. vol0_stat_freebigblocks is 623 * the number of big-blocks available for anything 624 * other than freemap zone at this point. 625 */ 626 format_freemap(volume); 627 assert(ondisk->vol0_stat_freebigblocks == 0); 628 ondisk->vol0_stat_freebigblocks = initialize_freemap(volume); 629 630 /* 631 * Format zones that are mapped to zone-2. 632 */ 633 for (i = 0; i < HAMMER_MAX_ZONES; ++i) { 634 if (hammer_is_index_record(i)) 635 format_blockmap(volume, i, 0); 636 } 637 638 /* 639 * Format undo zone. Formatting decrements 640 * vol0_stat_freebigblocks whenever a new big-block 641 * is allocated for undo zone. 642 */ 643 format_undomap(volume, &UndoBufferSize); 644 assert(ondisk->vol0_stat_bigblocks == 0); 645 ondisk->vol0_stat_bigblocks = ondisk->vol0_stat_freebigblocks; 646 647 /* 648 * Format the root directory. Formatting decrements 649 * vol0_stat_freebigblocks whenever a new big-block 650 * is allocated for required zones. 651 */ 652 ondisk->vol0_btree_root = format_root_directory(label); 653 ++ondisk->vol0_stat_inodes; /* root inode */ 654 } else { 655 freeblks = initialize_freemap(volume); 656 root_vol = get_root_volume(); 657 root_vol->ondisk->vol0_stat_freebigblocks += freeblks; 658 root_vol->ondisk->vol0_stat_bigblocks += freeblks; 659 } 660 } 661 662 /* 663 * Format the root directory. 664 */ 665 static 666 hammer_off_t 667 format_root_directory(const char *label) 668 { 669 hammer_off_t btree_off; 670 hammer_off_t idata_off; 671 hammer_off_t pfsd_off; 672 hammer_tid_t create_tid; 673 hammer_node_ondisk_t bnode; 674 hammer_inode_data_t idata; 675 hammer_pseudofs_data_t pfsd; 676 buffer_info_t data_buffer0 = NULL; 677 buffer_info_t data_buffer1 = NULL; 678 buffer_info_t data_buffer2 = NULL; 679 hammer_btree_elm_t elm; 680 uint64_t xtime; 681 682 /* 683 * Allocate zero-filled root btree node, inode and pfs 684 */ 685 bnode = alloc_btree_node(&btree_off, &data_buffer0); 686 idata = alloc_meta_element(&idata_off, sizeof(*idata), &data_buffer1); 687 pfsd = alloc_meta_element(&pfsd_off, sizeof(*pfsd), &data_buffer2); 688 create_tid = createtid(); 689 xtime = nowtime(); 690 691 /* 692 * Populate the inode data and inode record for the root directory. 693 */ 694 idata->version = HAMMER_INODE_DATA_VERSION; 695 idata->mode = 0755; 696 idata->ctime = xtime; 697 idata->mtime = xtime; 698 idata->atime = xtime; 699 idata->obj_type = HAMMER_OBJTYPE_DIRECTORY; 700 idata->size = 0; 701 idata->nlinks = 1; 702 if (HammerVersion >= HAMMER_VOL_VERSION_TWO) 703 idata->cap_flags |= HAMMER_INODE_CAP_DIR_LOCAL_INO; 704 if (HammerVersion >= HAMMER_VOL_VERSION_SIX) 705 idata->cap_flags |= HAMMER_INODE_CAP_DIRHASH_ALG1; 706 707 /* 708 * Populate the PFS data for the root PFS. 709 */ 710 pfsd->sync_low_tid = 1; 711 pfsd->sync_beg_tid = 0; 712 pfsd->sync_end_tid = 0; /* overriden by vol0_next_tid on root PFS */ 713 pfsd->shared_uuid = Hammer_FSId; 714 pfsd->unique_uuid = Hammer_FSId; 715 pfsd->mirror_flags = 0; 716 snprintf(pfsd->label, sizeof(pfsd->label), "%s", label); 717 718 /* 719 * Create the root of the B-Tree. The root is a leaf node so we 720 * do not have to worry about boundary elements. 721 */ 722 bnode->parent = 0; /* no parent */ 723 bnode->count = 2; 724 bnode->type = HAMMER_BTREE_TYPE_LEAF; 725 bnode->mirror_tid = 0; 726 727 /* 728 * Create the first node element for the inode. 729 */ 730 elm = &bnode->elms[0]; 731 elm->leaf.base.btype = HAMMER_BTREE_TYPE_RECORD; 732 elm->leaf.base.localization = HAMMER_DEF_LOCALIZATION | 733 HAMMER_LOCALIZE_INODE; 734 elm->leaf.base.obj_id = HAMMER_OBJID_ROOT; 735 elm->leaf.base.key = 0; 736 elm->leaf.base.create_tid = create_tid; 737 elm->leaf.base.delete_tid = 0; 738 elm->leaf.base.rec_type = HAMMER_RECTYPE_INODE; 739 elm->leaf.base.obj_type = HAMMER_OBJTYPE_DIRECTORY; 740 elm->leaf.create_ts = (uint32_t)time(NULL); 741 742 elm->leaf.data_offset = idata_off; 743 elm->leaf.data_len = sizeof(*idata); 744 hammer_crc_set_leaf(HammerVersion, idata, &elm->leaf); 745 746 /* 747 * Create the second node element for the PFS data. 748 * This is supposed to be a record part of the root ip (inode), 749 * so it should have the same obj_type value as above. 750 */ 751 elm = &bnode->elms[1]; 752 elm->leaf.base.btype = HAMMER_BTREE_TYPE_RECORD; 753 elm->leaf.base.localization = HAMMER_DEF_LOCALIZATION | 754 HAMMER_LOCALIZE_MISC; 755 elm->leaf.base.obj_id = HAMMER_OBJID_ROOT; 756 elm->leaf.base.key = 0; 757 elm->leaf.base.create_tid = create_tid; 758 elm->leaf.base.delete_tid = 0; 759 elm->leaf.base.rec_type = HAMMER_RECTYPE_PFS; 760 elm->leaf.base.obj_type = HAMMER_OBJTYPE_DIRECTORY; 761 elm->leaf.create_ts = (uint32_t)time(NULL); 762 763 elm->leaf.data_offset = pfsd_off; 764 elm->leaf.data_len = sizeof(*pfsd); 765 hammer_crc_set_leaf(HammerVersion, pfsd, &elm->leaf); 766 767 hammer_crc_set_btree(HammerVersion, bnode); 768 769 rel_buffer(data_buffer0); 770 rel_buffer(data_buffer1); 771 rel_buffer(data_buffer2); 772 773 return(btree_off); 774 } 775