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