HAMMER VFS - Bump the default hammer rev to 6
[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 108 if (UndoBufferSize < 100*1024*1024 && ForceOpt == 0)
240a4e41 109 errx(1, "The minimum UNDO fifo size is 100MB\n");
0d86737d
MD
110 if (UndoBufferSize < 100*1024*1024) {
111 fprintf(stderr,
112 "WARNING: you have specified an UNDO "
240a4e41 113 "FIFO size less than 100MB, 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");
240a4e41 136 usage();
9a8bf4a7
MD
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 "
240a4e41 148 "supports higher version than I "
47921633
MD
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 248 printf("NOTE: Please remember that you may have to manually set up a\n"
240a4e41 249 "cron(8) job to prune and reblock the filesystem regularly.\n"
50393a60
SW
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");
bc5587bb
MD
254 if (total < 10*GIG) {
255 printf("\nWARNING: The minimum UNDO/REDO FIFO is 500MB, you"
256 "really should not\n"
257 " try to format a HAMMER filesystem this small\n");
258 }
0d86737d 259 if (total < 50*GIG) {
240a4e41 260 printf("\nWARNING: HAMMER filesystems less than 50GB are "
0d86737d
MD
261 "not recommended!\n"
262 "You may have to run 'hammer prune-everything' and "
263 "'hammer reblock'\n"
264 "quite often, even if using a nohistory mount.\n");
265 }
ed3afcca 266 flush_all_volumes();
9a8bf4a7
MD
267 return(0);
268}
269
270static
271void
272usage(void)
273{
133fbfd7 274 fprintf(stderr,
240a4e41
TN
275 "usage: newfs_hammer -L label [-f] [-b bootsize] [-m savesize] [-u undosize]\n"
276 " [-V version] special ...\n"
133fbfd7 277 );
9a8bf4a7
MD
278 exit(1);
279}
280
281/*
282 * Convert the size in bytes to a human readable string.
283 */
64c21cf3
MD
284static
285const char *
9a8bf4a7
MD
286sizetostr(off_t size)
287{
288 static char buf[32];
289
290 if (size < 1024 / 2) {
291 snprintf(buf, sizeof(buf), "%6.2f", (double)size);
292 } else if (size < 1024 * 1024 / 2) {
293 snprintf(buf, sizeof(buf), "%6.2fKB",
294 (double)size / 1024);
295 } else if (size < 1024 * 1024 * 1024LL / 2) {
296 snprintf(buf, sizeof(buf), "%6.2fMB",
297 (double)size / (1024 * 1024));
298 } else if (size < 1024 * 1024 * 1024LL * 1024LL / 2) {
299 snprintf(buf, sizeof(buf), "%6.2fGB",
300 (double)size / (1024 * 1024 * 1024LL));
301 } else {
302 snprintf(buf, sizeof(buf), "%6.2fTB",
303 (double)size / (1024 * 1024 * 1024LL * 1024LL));
304 }
305 return(buf);
306}
307
ed3afcca
MD
308/*
309 * Convert a string to a 64 bit signed integer with various requirements.
310 */
9a8bf4a7 311static int64_t
ed3afcca 312getsize(const char *str, int64_t minval, int64_t maxval, int powerof2)
9a8bf4a7
MD
313{
314 int64_t val;
315 char *ptr;
316
317 val = strtoll(str, &ptr, 0);
318 switch(*ptr) {
319 case 't':
320 case 'T':
321 val *= 1024;
322 /* fall through */
323 case 'g':
324 case 'G':
325 val *= 1024;
326 /* fall through */
327 case 'm':
328 case 'M':
329 val *= 1024;
330 /* fall through */
331 case 'k':
332 case 'K':
333 val *= 1024;
334 break;
335 default:
ed3afcca
MD
336 errx(1, "Unknown suffix in number '%s'\n", str);
337 /* not reached */
9a8bf4a7
MD
338 }
339 if (ptr[1]) {
ed3afcca
MD
340 errx(1, "Unknown suffix in number '%s'\n", str);
341 /* not reached */
9a8bf4a7
MD
342 }
343 if (val < minval) {
ed3afcca
MD
344 errx(1, "Value too small: %s, min is %s\n",
345 str, sizetostr(minval));
346 /* not reached */
9a8bf4a7
MD
347 }
348 if (val > maxval) {
ed3afcca
MD
349 errx(1, "Value too large: %s, max is %s\n",
350 str, sizetostr(maxval));
351 /* not reached */
352 }
a89aec1b 353 if ((powerof2 & 1) && (val ^ (val - 1)) != ((val << 1) - 1)) {
ed3afcca
MD
354 errx(1, "Value not power of 2: %s\n", str);
355 /* not reached */
9a8bf4a7 356 }
a89aec1b
MD
357 if ((powerof2 & 2) && (val & HAMMER_BUFMASK)) {
358 errx(1, "Value not an integral multiple of %dK: %s",
359 HAMMER_BUFSIZE / 1024, str);
360 /* not reached */
361 }
9a8bf4a7
MD
362 return(val);
363}
364
ed3afcca 365/*
b5aaba7f
MD
366 * Generate a transaction id. Transaction ids are no longer time-based.
367 * Put the nail in the coffin by not making the first one time-based.
368 *
369 * We could start at 1 here but start at 2^32 to reserve a small domain for
370 * possible future use.
ed3afcca 371 */
9a8bf4a7
MD
372static hammer_tid_t
373createtid(void)
374{
375 static hammer_tid_t lasttid;
9a8bf4a7 376
1d9f6aa1 377 if (lasttid == 0)
b5aaba7f 378 lasttid = 0x0000000100000000ULL;
9a8bf4a7
MD
379 return(lasttid++);
380}
381
7849afbc
MD
382static u_int64_t
383nowtime(void)
384{
385 struct timeval tv;
386 u_int64_t xtime;
387
388 gettimeofday(&tv, NULL);
389 xtime = tv.tv_sec * 1000000LL + tv.tv_usec;
390 return(xtime);
391}
392
9a8bf4a7
MD
393/*
394 * Check basic volume characteristics. HAMMER filesystems use a minimum
395 * of a 16KB filesystem buffer size.
396 */
397static
398void
ed3afcca 399check_volume(struct volume_info *vol)
9a8bf4a7
MD
400{
401 struct partinfo pinfo;
402 struct stat st;
403
404 /*
405 * Get basic information about the volume
406 */
ed3afcca
MD
407 vol->fd = open(vol->name, O_RDWR);
408 if (vol->fd < 0)
409 err(1, "Unable to open %s R+W", vol->name);
410 if (ioctl(vol->fd, DIOCGPART, &pinfo) < 0) {
9a8bf4a7 411 /*
133fbfd7 412 * Allow the formatting of regular files as HAMMER volumes
9a8bf4a7 413 */
ed3afcca
MD
414 if (fstat(vol->fd, &st) < 0)
415 err(1, "Unable to stat %s", vol->name);
416 vol->size = st.st_size;
417 vol->type = "REGFILE";
9a8bf4a7
MD
418 } else {
419 /*
420 * When formatting a block device as a HAMMER volume the
421 * sector size must be compatible. HAMMER uses 16384 byte
422 * filesystem buffers.
423 */
424 if (pinfo.reserved_blocks) {
ed3afcca
MD
425 errx(1, "HAMMER cannot be placed in a partition "
426 "which overlaps the disklabel or MBR");
9a8bf4a7
MD
427 }
428 if (pinfo.media_blksize > 16384 ||
429 16384 % pinfo.media_blksize) {
ed3afcca
MD
430 errx(1, "A media sector size of %d is not supported",
431 pinfo.media_blksize);
9a8bf4a7
MD
432 }
433
ed3afcca
MD
434 vol->size = pinfo.media_size;
435 vol->type = "DEVICE";
9a8bf4a7 436 }
ed3afcca
MD
437 printf("Volume %d %s %-15s size %s\n",
438 vol->vol_no, vol->type, vol->name,
439 sizetostr(vol->size));
440
441 /*
c3be93f2
MD
442 * Reserve space for (future) header junk, setup our poor-man's
443 * bigblock allocator.
ed3afcca 444 */
a89aec1b 445 vol->vol_alloc = HAMMER_BUFSIZE * 16;
9a8bf4a7
MD
446}
447
448/*
449 * Format a HAMMER volume. Cluster 0 will be initially placed in volume 0.
450 */
451static
452void
416571a0 453format_volume(struct volume_info *vol, int nvols, const char *label,
68e079b8 454 off_t total_size __unused)
9a8bf4a7 455{
c3be93f2 456 struct volume_info *root_vol;
ed3afcca 457 struct hammer_volume_ondisk *ondisk;
c3be93f2 458 int64_t freeblks;
0d86737d 459 int64_t freebytes;
68e079b8 460 int i;
9a8bf4a7 461
ed3afcca
MD
462 /*
463 * Initialize basic information in the on-disk volume structure.
464 */
465 ondisk = vol->ondisk;
466
467 ondisk->vol_fsid = Hammer_FSId;
468 ondisk->vol_fstype = Hammer_FSType;
469 snprintf(ondisk->vol_name, sizeof(ondisk->vol_name), "%s", label);
470 ondisk->vol_no = vol->vol_no;
471 ondisk->vol_count = nvols;
47921633 472 ondisk->vol_version = HammerVersion;
9a8bf4a7 473
a89aec1b
MD
474 ondisk->vol_bot_beg = vol->vol_alloc;
475 vol->vol_alloc += BootAreaSize;
476 ondisk->vol_mem_beg = vol->vol_alloc;
477 vol->vol_alloc += MemAreaSize;
40043e7f
MD
478
479 /*
480 * The remaining area is the zone 2 buffer allocation area. These
481 * buffers
482 */
47197d71
MD
483 ondisk->vol_buf_beg = vol->vol_alloc;
484 ondisk->vol_buf_end = vol->size & ~(int64_t)HAMMER_BUFMASK;
9a8bf4a7 485
47197d71 486 if (ondisk->vol_buf_end < ondisk->vol_buf_beg) {
ed3afcca
MD
487 errx(1, "volume %d %s is too small to hold the volume header",
488 vol->vol_no, vol->name);
9a8bf4a7
MD
489 }
490
47197d71
MD
491 ondisk->vol_nblocks = (ondisk->vol_buf_end - ondisk->vol_buf_beg) /
492 HAMMER_BUFSIZE;
fbc6e32a 493 ondisk->vol_blocksize = HAMMER_BUFSIZE;
9a8bf4a7 494
c3be93f2
MD
495 ondisk->vol_rootvol = RootVolNo;
496 ondisk->vol_signature = HAMMER_FSBUF_VOLUME;
497
498 vol->vol_free_off = HAMMER_ENCODE_RAW_BUFFER(vol->vol_no, 0);
499 vol->vol_free_end = HAMMER_ENCODE_RAW_BUFFER(vol->vol_no, (ondisk->vol_buf_end - ondisk->vol_buf_beg) & ~HAMMER_LARGEBLOCK_MASK64);
500
9a8bf4a7 501 /*
c3be93f2 502 * Format the root volume.
9a8bf4a7 503 */
c3be93f2 504 if (vol->vol_no == RootVolNo) {
416571a0
MD
505 /*
506 * Starting TID
507 */
47197d71 508 ondisk->vol0_next_tid = createtid();
c3be93f2
MD
509
510 format_freemap(vol,
511 &ondisk->vol0_blockmap[HAMMER_ZONE_FREEMAP_INDEX]);
512
513 freeblks = initialize_freemap(vol);
514 ondisk->vol0_stat_freebigblocks = freeblks;
c3be93f2 515
0d86737d
MD
516 freebytes = freeblks * HAMMER_LARGEBLOCK_SIZE64;
517 if (freebytes < 1*GIG && ForceOpt == 0) {
0a9528b9 518 errx(1, "Cannot create a HAMMER filesystem less than "
0d86737d 519 "1GB unless you use -f. HAMMER filesystems\n"
240a4e41 520 "less than 50GB are not recommended\n");
0d86737d
MD
521 }
522
68e079b8
MD
523 for (i = 8; i < HAMMER_MAX_ZONES; ++i) {
524 format_blockmap(&ondisk->vol0_blockmap[i],
525 HAMMER_ZONE_ENCODE(i, 0));
526 }
3f673d5c
MD
527 format_undomap(ondisk);
528
d8935c61 529 ondisk->vol0_btree_root = format_root(label);
47197d71 530 ++ondisk->vol0_stat_inodes; /* root inode */
c3be93f2
MD
531 } else {
532 freeblks = initialize_freemap(vol);
533 root_vol = get_volume(RootVolNo);
534 root_vol->cache.modified = 1;
535 root_vol->ondisk->vol0_stat_freebigblocks += freeblks;
536 root_vol->ondisk->vol0_stat_bigblocks += freeblks;
537 rel_volume(root_vol);
9a8bf4a7 538 }
9a8bf4a7
MD
539}
540
541/*
ed3afcca 542 * Format the root directory.
9a8bf4a7
MD
543 */
544static
47197d71 545hammer_off_t
d8935c61 546format_root(const char *label)
9a8bf4a7 547{
47197d71 548 hammer_off_t btree_off;
d8935c61 549 hammer_off_t pfsd_off;
11ad5ade
MD
550 hammer_off_t data_off;
551 hammer_tid_t create_tid;
8cd0a023 552 hammer_node_ondisk_t bnode;
ed3afcca 553 struct hammer_inode_data *idata;
d8935c61
MD
554 hammer_pseudofs_data_t pfsd;
555 struct buffer_info *data_buffer1 = NULL;
556 struct buffer_info *data_buffer2 = NULL;
8cd0a023 557 hammer_btree_elm_t elm;
7849afbc 558 u_int64_t xtime;
ed3afcca 559
47197d71 560 bnode = alloc_btree_element(&btree_off);
d8935c61
MD
561 idata = alloc_data_element(&data_off, sizeof(*idata), &data_buffer1);
562 pfsd = alloc_data_element(&pfsd_off, sizeof(*pfsd), &data_buffer2);
11ad5ade 563 create_tid = createtid();
7849afbc 564 xtime = nowtime();
9a8bf4a7
MD
565
566 /*
ed3afcca 567 * Populate the inode data and inode record for the root directory.
9a8bf4a7 568 */
ed3afcca
MD
569 idata->version = HAMMER_INODE_DATA_VERSION;
570 idata->mode = 0755;
7849afbc
MD
571 idata->ctime = xtime;
572 idata->mtime = xtime;
573 idata->atime = xtime;
11ad5ade
MD
574 idata->obj_type = HAMMER_OBJTYPE_DIRECTORY;
575 idata->size = 0;
576 idata->nlinks = 1;
47921633
MD
577 if (HammerVersion >= HAMMER_VOL_VERSION_TWO)
578 idata->cap_flags |= HAMMER_INODE_CAP_DIR_LOCAL_INO;
e523b881
MD
579 if (HammerVersion >= HAMMER_VOL_VERSION_SIX)
580 idata->cap_flags |= HAMMER_INODE_CAP_DIRHASH_ALG1;
9a8bf4a7 581
d8935c61 582 pfsd->sync_low_tid = 1;
ddc8e722 583 pfsd->sync_beg_tid = 0;
d8935c61
MD
584 pfsd->sync_end_tid = 0; /* overriden by vol0_next_tid on pfs0 */
585 pfsd->shared_uuid = Hammer_FSId;
586 pfsd->unique_uuid = Hammer_FSId;
dfd94fe0 587 pfsd->reserved01 = 0;
d8935c61
MD
588 pfsd->mirror_flags = 0;
589 snprintf(pfsd->label, sizeof(pfsd->label), "%s", label);
590
9a8bf4a7 591 /*
620822d2
MD
592 * Create the root of the B-Tree. The root is a leaf node so we
593 * do not have to worry about boundary elements.
9a8bf4a7 594 */
52bae4a6 595 bnode->signature = HAMMER_BTREE_SIGNATURE_GOOD;
d8935c61 596 bnode->count = 2;
8cd0a023 597 bnode->type = HAMMER_BTREE_TYPE_LEAF;
620822d2 598
8cd0a023 599 elm = &bnode->elms[0];
11ad5ade 600 elm->leaf.base.btype = HAMMER_BTREE_TYPE_RECORD;
58c17893 601 elm->leaf.base.localization = HAMMER_LOCALIZE_INODE;
11ad5ade
MD
602 elm->leaf.base.obj_id = HAMMER_OBJID_ROOT;
603 elm->leaf.base.key = 0;
604 elm->leaf.base.create_tid = create_tid;
605 elm->leaf.base.delete_tid = 0;
606 elm->leaf.base.rec_type = HAMMER_RECTYPE_INODE;
607 elm->leaf.base.obj_type = HAMMER_OBJTYPE_DIRECTORY;
1d9f6aa1 608 elm->leaf.create_ts = (u_int32_t)time(NULL);
11ad5ade 609
11ad5ade
MD
610 elm->leaf.data_offset = data_off;
611 elm->leaf.data_len = sizeof(*idata);
7849afbc 612 elm->leaf.data_crc = crc32(idata, HAMMER_INODE_CRCSIZE);
11ad5ade 613
d8935c61
MD
614 elm = &bnode->elms[1];
615 elm->leaf.base.btype = HAMMER_BTREE_TYPE_RECORD;
616 elm->leaf.base.localization = HAMMER_LOCALIZE_MISC;
617 elm->leaf.base.obj_id = HAMMER_OBJID_ROOT;
d9b1ce90 618 elm->leaf.base.key = 0;
d8935c61
MD
619 elm->leaf.base.create_tid = create_tid;
620 elm->leaf.base.delete_tid = 0;
d9b1ce90 621 elm->leaf.base.rec_type = HAMMER_RECTYPE_PFS;
d8935c61
MD
622 elm->leaf.base.obj_type = 0;
623 elm->leaf.create_ts = (u_int32_t)time(NULL);
624
625 elm->leaf.data_offset = pfsd_off;
626 elm->leaf.data_len = sizeof(*pfsd);
627 elm->leaf.data_crc = crc32(pfsd, sizeof(*pfsd));
628
11ad5ade 629 bnode->crc = crc32(&bnode->crc + 1, HAMMER_BTREE_CRCSIZE);
52bae4a6 630
47197d71 631 return(btree_off);
9a8bf4a7
MD
632}
633