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