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