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