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