Move the IOCTLTRIM ioctl to a better header and rename it to DAIOCTRIM.
[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
41ae0862
TK
35#include "hammer_util.h"
36
32d6a954 37#include <sys/sysctl.h>
32506cfa
SW
38
39#include <bus/cam/scsi/scsi_daio.h>
32d6a954 40
8ecda427 41static int64_t getsize(const char *str, int pw);
2dba5fa7
TK
42static int trim_volume(volume_info_t volume);
43static void format_volume(volume_info_t volume, int nvols,const char *label);
b4fed9fb 44static hammer_off_t format_root_directory(const char *label);
46137e17 45static uint64_t nowtime(void);
2dba5fa7 46static void print_volume(const volume_info_t volume);
c5792f02 47static void usage(int exit_code);
b2bafd84 48static void test_header_junk_size(int64_t size);
825a2db2
TK
49static void test_boot_area_size(int64_t size);
50static void test_memory_log_size(int64_t size);
668f11d8 51static void test_undo_buffer_size(int64_t size);
9a8bf4a7 52
b1f25588 53static int ForceOpt;
b2bafd84 54static int64_t HeaderJunkSize = -1;
e2052dd5
TK
55static int64_t BootAreaSize = -1;
56static int64_t MemoryLogSize = -1;
8303b848 57static int64_t UndoBufferSize;
0d86737d
MD
58
59#define GIG (1024LL*1024*1024)
60
9a8bf4a7
MD
61int
62main(int ac, char **av)
63{
9a8bf4a7 64 off_t total;
f819215c 65 off_t avg_vol_size;
7e1ba5da
MD
66 int ch;
67 int i;
db7b497c 68 int nvols;
1a4aebcc 69 int eflag = 0;
9a8bf4a7 70 const char *label = NULL;
2dba5fa7 71 volume_info_t volume;
9a8bf4a7
MD
72
73 /*
ed3afcca
MD
74 * Sanity check basic filesystem structures. No cookies for us
75 * if it gets broken!
9a8bf4a7 76 */
9a8bf4a7 77 assert(sizeof(struct hammer_volume_ondisk) <= HAMMER_BUFSIZE);
d454cd69 78 assert(sizeof(struct hammer_volume_ondisk) <= HAMMER_MIN_VOL_JUNK);
c3be93f2
MD
79 assert(sizeof(struct hammer_blockmap_layer1) == 32);
80 assert(sizeof(struct hammer_blockmap_layer2) == 16);
9a8bf4a7 81
9a8bf4a7
MD
82 /*
83 * Parse arguments
84 */
b2bafd84 85 while ((ch = getopt(ac, av, "dfEL:j:b:m:u:hC:V:")) != -1) {
9a8bf4a7 86 switch(ch) {
b2290779
TK
87 case 'd':
88 ++DebugOpt;
89 break;
0d86737d
MD
90 case 'f':
91 ForceOpt = 1;
92 break;
e0fb398b 93 case 'E':
1a4aebcc 94 eflag = 1;
e0fb398b 95 break;
9a8bf4a7
MD
96 case 'L':
97 label = optarg;
98 break;
b2bafd84
TK
99 case 'j': /* Not mentioned in newfs_hammer(8) */
100 HeaderJunkSize = getsize(optarg, 2);
101 test_header_junk_size(HeaderJunkSize);
102 break;
a89aec1b 103 case 'b':
8ecda427 104 BootAreaSize = getsize(optarg, 2);
825a2db2 105 test_boot_area_size(BootAreaSize);
a89aec1b 106 break;
a89aec1b 107 case 'm':
8ecda427 108 MemoryLogSize = getsize(optarg, 2);
825a2db2 109 test_memory_log_size(MemoryLogSize);
a89aec1b 110 break;
64c21cf3 111 case 'u':
8ecda427 112 UndoBufferSize = getsize(optarg, 2);
668f11d8 113 test_undo_buffer_size(UndoBufferSize);
64c21cf3 114 break;
591440d1
TK
115 case 'h':
116 usage(0);
88356ed4 117 /* not reached */
591440d1 118 break;
25ee129e 119 case 'C':
88356ed4 120 if (hammer_parse_cache_size(optarg) == -1) {
c5792f02 121 usage(1);
88356ed4
TK
122 /* not reached */
123 }
25ee129e 124 break;
47921633
MD
125 case 'V':
126 HammerVersion = strtol(optarg, NULL, 0);
127 if (HammerVersion < HAMMER_VOL_VERSION_MIN ||
6758745f 128 HammerVersion >= HAMMER_VOL_VERSION_WIP) {
47921633
MD
129 errx(1,
130 "I don't understand how to format "
7eb492eb 131 "HAMMER version %d",
47921633 132 HammerVersion);
3ad14c0f 133 /* not reached */
6758745f 134 }
47921633 135 break;
9a8bf4a7 136 default:
c5792f02 137 usage(1);
88356ed4 138 /* not reached */
9a8bf4a7
MD
139 break;
140 }
141 }
81a213a5
TK
142 ac -= optind;
143 av += optind;
144 nvols = ac;
9a8bf4a7 145
4c09d9c4 146 if (HammerVersion == (uint32_t)-1) {
47921633
MD
147 size_t olen = sizeof(HammerVersion);
148 HammerVersion = HAMMER_VOL_VERSION_DEFAULT;
1b1c194d 149
47921633 150 if (sysctlbyname("vfs.hammer.supported_version",
1b1c194d 151 &HammerVersion, &olen, NULL, 0)) {
95f03e3e
TK
152 hwarn("HAMMER VFS not loaded, cannot get version info, "
153 "using version %d",
1b1c194d
TK
154 HammerVersion);
155 } else if (HammerVersion >= HAMMER_VOL_VERSION_WIP) {
156 HammerVersion = HAMMER_VOL_VERSION_WIP - 1;
89496399 157 hwarnx("HAMMER VFS supports higher version than "
1b1c194d
TK
158 "I understand, using version %d",
159 HammerVersion);
47921633
MD
160 }
161 }
162
3ad14c0f 163 if (nvols == 0) {
02318f07 164 errx(1, "You must specify at least one special file (volume)");
3ad14c0f
TK
165 /* not reached */
166 }
167 if (nvols > HAMMER_MAX_VOLUMES) {
02318f07 168 errx(1, "The maximum number of volumes is %d",
653fa4cd 169 HAMMER_MAX_VOLUMES);
3ad14c0f
TK
170 /* not reached */
171 }
94509284 172
1b1c194d
TK
173 if (label == NULL) {
174 hwarnx("A filesystem label must be specified");
175 usage(1);
88356ed4 176 /* not reached */
1b1c194d
TK
177 }
178
81a213a5
TK
179 /*
180 * Generate a filesystem id and lookup the filesystem type
181 */
3cd578ed
TK
182 hammer_uuid_create(&Hammer_FSId);
183 if (hammer_uuid_name_lookup(&Hammer_FSType, HAMMER_FSTYPE_STRING)) {
81a213a5
TK
184 errx(1, "uuids file does not have the DragonFly "
185 "HAMMER filesystem type");
3ad14c0f 186 /* not reached */
6758745f 187 }
81a213a5 188
9a8bf4a7 189 total = 0;
db7b497c 190 for (i = 0; i < nvols; ++i) {
5ebff42a 191 volume = init_volume(av[i], O_RDWR, i);
ff8644cb 192 printf("Volume %d %s %-15s size %s\n",
5ebff42a
TK
193 volume->vol_no, volume->type, volume->name,
194 sizetostr(volume->size));
ff8644cb 195
6758745f 196 if (eflag) {
3ad14c0f 197 if (trim_volume(volume) == -1 && ForceOpt == 0) {
1b1c194d 198 errx(1, "Use -f option to proceed");
3ad14c0f
TK
199 /* not reached */
200 }
6758745f 201 }
5ebff42a 202 total += volume->size;
9a8bf4a7
MD
203 }
204
b2bafd84
TK
205 /*
206 * Reserve space for (future) header junk, setup our poor-man's
207 * big-block allocator. Note that the header junk space includes
208 * volume header which is 1928 bytes.
209 */
210 if (HeaderJunkSize == -1)
d454cd69 211 HeaderJunkSize = HAMMER_VOL_JUNK_SIZE;
b2bafd84
TK
212 else if (HeaderJunkSize < (int64_t)sizeof(struct hammer_volume_ondisk))
213 HeaderJunkSize = sizeof(struct hammer_volume_ondisk);
bbc5e78b 214 HeaderJunkSize = HAMMER_BUFSIZE_DOALIGN(HeaderJunkSize);
b2bafd84 215
a89aec1b 216 /*
c57d99af 217 * Calculate defaults for the boot area and memory log sizes,
e2052dd5 218 * only if not specified by -b or -m option.
a89aec1b 219 */
db7b497c 220 avg_vol_size = total / nvols;
e2052dd5
TK
221 if (BootAreaSize == -1)
222 BootAreaSize = init_boot_area_size(BootAreaSize, avg_vol_size);
223 if (MemoryLogSize == -1)
224 MemoryLogSize = init_memory_log_size(MemoryLogSize, avg_vol_size);
a89aec1b 225
9a8bf4a7 226 /*
c3be93f2
MD
227 * Format the volumes. Format the root volume first so we can
228 * bootstrap the freemap.
9a8bf4a7 229 */
42700c9d 230 format_volume(get_root_volume(), nvols, label);
6758745f 231 for (i = 0; i < nvols; ++i) {
7a39af79 232 if (i != HAMMER_ROOT_VOLNO)
b251a9e8 233 format_volume(get_volume(i), nvols, label);
6758745f 234 }
7e1ba5da 235
20f1a07f
TK
236 print_volume(get_root_volume());
237
238 flush_all_volumes();
239 return(0);
240}
241
242static
243void
2dba5fa7 244print_volume(const volume_info_t volume)
20f1a07f
TK
245{
246 hammer_volume_ondisk_t ondisk;
247 hammer_blockmap_t blockmap;
248 hammer_off_t total = 0;
249 int i, nvols;
ef1d1012 250 const char *name = NULL;
20f1a07f
TK
251 char *fsidstr;
252
5ebff42a 253 ondisk = volume->ondisk;
20f1a07f
TK
254 blockmap = &ondisk->vol0_blockmap[HAMMER_ZONE_UNDO_INDEX];
255
256 nvols = ondisk->vol_count;
ef1d1012 257 for (i = 0; i < nvols; ++i) {
2dba5fa7 258 volume_info_t p = get_volume(i);
ef1d1012
TK
259 total += p->size;
260 if (p->vol_no == HAMMER_ROOT_VOLNO) {
261 assert(name == NULL);
262 name = p->name;
263 }
264 }
20f1a07f 265
3cd578ed 266 hammer_uuid_to_string(&Hammer_FSId, &fsidstr);
7e1ba5da 267
64c21cf3 268 printf("---------------------------------------------\n");
87a5b325
TK
269 printf("HAMMER version %d\n", HammerVersion);
270 printf("%d volume%s total size %s\n",
271 nvols, (nvols == 1 ? "" : "s"), sizetostr(total));
ef1d1012 272 printf("root-volume: %s\n", name);
9930da22 273 if (DebugOpt) {
20f1a07f
TK
274 printf("header-junk-size: %s\n",
275 sizetostr(ondisk->vol_bot_beg));
9930da22 276 }
20f1a07f
TK
277 printf("boot-area-size: %s\n",
278 sizetostr(ondisk->vol_mem_beg - ondisk->vol_bot_beg));
279 printf("memory-log-size: %s\n",
280 sizetostr(ondisk->vol_buf_beg - ondisk->vol_mem_beg));
281 printf("undo-buffer-size: %s\n",
282 sizetostr(HAMMER_OFF_LONG_ENCODE(blockmap->alloc_offset)));
e926bade 283 printf("total-pre-allocated: %s\n",
5ebff42a 284 sizetostr(HAMMER_OFF_SHORT_ENCODE(volume->vol_free_off)));
ddc8e722 285 printf("fsid: %s\n", fsidstr);
64c21cf3 286 printf("\n");
50393a60 287 printf("NOTE: Please remember that you may have to manually set up a\n"
240a4e41 288 "cron(8) job to prune and reblock the filesystem regularly.\n"
50393a60 289 "By default, the system automatically runs 'hammer cleanup'\n"
dac7444f 290 "on a nightly basis. The periodic.conf(5) variable\n"
50393a60
SW
291 "'daily_clean_hammer_enable' can be unset to disable this.\n"
292 "Also see 'man hammer' and 'man HAMMER' for more information.\n");
6758745f 293 if (total < 10*GIG) {
6d584f65 294 printf("\nWARNING: The minimum UNDO/REDO FIFO is %s, "
20f1a07f
TK
295 "you really should not\n"
296 "try to format a HAMMER filesystem this small.\n",
297 sizetostr(HAMMER_BIGBLOCK_SIZE *
6d584f65 298 HAMMER_MIN_UNDO_BIGBLOCKS));
6758745f
TK
299 }
300 if (total < 50*GIG) {
240a4e41 301 printf("\nWARNING: HAMMER filesystems less than 50GB are "
0d86737d
MD
302 "not recommended!\n"
303 "You may have to run 'hammer prune-everything' and "
304 "'hammer reblock'\n"
305 "quite often, even if using a nohistory mount.\n");
6758745f 306 }
9a8bf4a7
MD
307}
308
309static
310void
c5792f02 311usage(int exit_code)
9a8bf4a7 312{
133fbfd7 313 fprintf(stderr,
591440d1 314 "usage: newfs_hammer -L label [-Efh] [-b bootsize] [-m savesize] [-u undosize]\n"
25ee129e 315 " [-C cachesize[:readahead]] [-V version] special ...\n"
133fbfd7 316 );
c5792f02 317 exit(exit_code);
9a8bf4a7
MD
318}
319
005a4da7
TK
320static
321void
b2bafd84
TK
322test_header_junk_size(int64_t size)
323{
d454cd69 324 if (size < HAMMER_MIN_VOL_JUNK) {
6758745f 325 if (ForceOpt == 0) {
b2bafd84 326 errx(1, "The minimum header junk size is %s",
d454cd69 327 sizetostr(HAMMER_MIN_VOL_JUNK));
3ad14c0f 328 /* not reached */
6758745f 329 } else {
95f03e3e 330 hwarnx("You have specified header junk size less than %s",
d454cd69 331 sizetostr(HAMMER_MIN_VOL_JUNK));
6758745f 332 }
d454cd69 333 } else if (size > HAMMER_MAX_VOL_JUNK) {
b2bafd84 334 errx(1, "The maximum header junk size is %s",
d454cd69 335 sizetostr(HAMMER_MAX_VOL_JUNK));
3ad14c0f 336 /* not reached */
b2bafd84
TK
337 }
338}
339
005a4da7
TK
340static
341void
825a2db2
TK
342test_boot_area_size(int64_t size)
343{
344 if (size < HAMMER_BOOT_MINBYTES) {
6758745f 345 if (ForceOpt == 0) {
e2052dd5
TK
346 errx(1, "The minimum boot area size is %s",
347 sizetostr(HAMMER_BOOT_MINBYTES));
3ad14c0f 348 /* not reached */
6758745f 349 } else {
95f03e3e 350 hwarnx("You have specified boot area size less than %s",
e2052dd5 351 sizetostr(HAMMER_BOOT_MINBYTES));
6758745f 352 }
825a2db2
TK
353 } else if (size > HAMMER_BOOT_MAXBYTES) {
354 errx(1, "The maximum boot area size is %s",
355 sizetostr(HAMMER_BOOT_MAXBYTES));
3ad14c0f 356 /* not reached */
825a2db2
TK
357 }
358}
359
005a4da7
TK
360static
361void
825a2db2
TK
362test_memory_log_size(int64_t size)
363{
364 if (size < HAMMER_MEM_MINBYTES) {
6758745f 365 if (ForceOpt == 0) {
e2052dd5
TK
366 errx(1, "The minimum memory log size is %s",
367 sizetostr(HAMMER_MEM_MINBYTES));
3ad14c0f 368 /* not reached */
6758745f 369 } else {
95f03e3e 370 hwarnx("You have specified memory log size less than %s",
e2052dd5 371 sizetostr(HAMMER_MEM_MINBYTES));
6758745f 372 }
825a2db2
TK
373 } else if (size > HAMMER_MEM_MAXBYTES) {
374 errx(1, "The maximum memory log size is %s",
375 sizetostr(HAMMER_MEM_MAXBYTES));
3ad14c0f 376 /* not reached */
825a2db2
TK
377 }
378}
379
005a4da7
TK
380static
381void
668f11d8
TK
382test_undo_buffer_size(int64_t size)
383{
6d584f65
TK
384 int64_t minbuf, maxbuf;
385
386 minbuf = HAMMER_BIGBLOCK_SIZE * HAMMER_MIN_UNDO_BIGBLOCKS;
387 maxbuf = HAMMER_BIGBLOCK_SIZE * HAMMER_MAX_UNDO_BIGBLOCKS;
388
389 if (size < minbuf) {
6758745f 390 if (ForceOpt == 0) {
6d584f65
TK
391 errx(1, "The minimum UNDO/REDO FIFO size is %s",
392 sizetostr(minbuf));
3ad14c0f 393 /* not reached */
6758745f 394 } else {
95f03e3e
TK
395 hwarnx("You have specified an UNDO/REDO FIFO size less "
396 "than %s, which may lead to VFS panics",
6d584f65 397 sizetostr(minbuf));
6758745f 398 }
6d584f65
TK
399 } else if (size > maxbuf) {
400 errx(1, "The maximum UNDO/REDO FIFO size is %s",
401 sizetostr(maxbuf));
3ad14c0f 402 /* not reached */
668f11d8
TK
403 }
404}
405
ed3afcca
MD
406/*
407 * Convert a string to a 64 bit signed integer with various requirements.
408 */
005a4da7
TK
409static
410int64_t
8ecda427 411getsize(const char *str, int powerof2)
9a8bf4a7
MD
412{
413 int64_t val;
414 char *ptr;
415
416 val = strtoll(str, &ptr, 0);
417 switch(*ptr) {
418 case 't':
419 case 'T':
420 val *= 1024;
421 /* fall through */
422 case 'g':
423 case 'G':
424 val *= 1024;
425 /* fall through */
426 case 'm':
427 case 'M':
428 val *= 1024;
429 /* fall through */
430 case 'k':
431 case 'K':
432 val *= 1024;
433 break;
434 default:
7eb492eb 435 errx(1, "Unknown suffix in number '%s'", str);
6758745f 436 /* not reached */
9a8bf4a7 437 }
8ecda427 438
6758745f 439 if (ptr[1]) {
7eb492eb 440 errx(1, "Unknown suffix in number '%s'", str);
6758745f
TK
441 /* not reached */
442 }
443 if ((powerof2 & 1) && (val ^ (val - 1)) != ((val << 1) - 1)) {
7eb492eb 444 errx(1, "Value not power of 2: %s", str);
6758745f
TK
445 /* not reached */
446 }
447 if ((powerof2 & 2) && (val & HAMMER_BUFMASK)) {
dac7444f 448 errx(1, "Value not an integral multiple of %dK: %s",
a89aec1b 449 HAMMER_BUFSIZE / 1024, str);
6758745f
TK
450 /* not reached */
451 }
9a8bf4a7
MD
452 return(val);
453}
454
ed3afcca 455/*
b5aaba7f
MD
456 * Generate a transaction id. Transaction ids are no longer time-based.
457 * Put the nail in the coffin by not making the first one time-based.
458 *
459 * We could start at 1 here but start at 2^32 to reserve a small domain for
460 * possible future use.
ed3afcca 461 */
005a4da7
TK
462static
463hammer_tid_t
9a8bf4a7
MD
464createtid(void)
465{
466 static hammer_tid_t lasttid;
9a8bf4a7 467
1d9f6aa1 468 if (lasttid == 0)
b5aaba7f 469 lasttid = 0x0000000100000000ULL;
9a8bf4a7
MD
470 return(lasttid++);
471}
472
005a4da7
TK
473static
474uint64_t
7849afbc
MD
475nowtime(void)
476{
477 struct timeval tv;
46137e17 478 uint64_t xtime;
7849afbc
MD
479
480 gettimeofday(&tv, NULL);
481 xtime = tv.tv_sec * 1000000LL + tv.tv_usec;
482 return(xtime);
483}
484
e0fb398b 485/*
06a1d31f 486 * TRIM the volume, but only if the backing store is not a regular file
e0fb398b
T
487 */
488static
461cb726 489int
2dba5fa7 490trim_volume(volume_info_t volume)
e0fb398b 491{
461cb726
TK
492 size_t olen;
493 char *dev_name, *p;
494 char sysctl_name[64];
495 int trim_enabled;
496 off_t ioarg[2];
497
06a1d31f 498 if (is_regfile(volume)) {
5ebff42a 499 hwarnx("Cannot TRIM regular file %s", volume->name);
1b1c194d 500 return(-1);
461cb726 501 }
5ebff42a
TK
502 if (strncmp(volume->name, "/dev/da", 7)) {
503 hwarnx("%s does not support the TRIM command", volume->name);
1b1c194d 504 return(-1);
461cb726 505 }
66611793 506
461cb726 507 /* Extract a number from /dev/da?s? */
5ebff42a 508 dev_name = strdup(volume->name);
461cb726
TK
509 p = strtok(dev_name + strlen("/dev/da"), "s");
510 sprintf(sysctl_name, "kern.cam.da.%s.trim_enabled", p);
511 free(dev_name);
059d6b07 512
461cb726
TK
513 trim_enabled = 0;
514 olen = sizeof(trim_enabled);
059d6b07 515
461cb726 516 if (sysctlbyname(sysctl_name, &trim_enabled, &olen, NULL, 0) == -1) {
95f03e3e 517 hwarnx("%s (%s) does not support the TRIM command",
5ebff42a 518 volume->name, sysctl_name);
1b1c194d 519 return(-1);
461cb726
TK
520 }
521 if (!trim_enabled) {
95f03e3e
TK
522 hwarnx("Erase device option selected, but sysctl (%s) "
523 "is not enabled", sysctl_name);
1b1c194d 524 return(-1);
e0fb398b 525 }
461cb726 526
5ebff42a
TK
527 ioarg[0] = volume->device_offset;
528 ioarg[1] = volume->size;
461cb726
TK
529
530 printf("Trimming %s %s, sectors %llu-%llu\n",
5ebff42a 531 volume->type, volume->name,
461cb726
TK
532 (unsigned long long)ioarg[0] / 512,
533 (unsigned long long)ioarg[1] / 512);
534
32506cfa 535 if (ioctl(volume->fd, DAIOCTRIM, ioarg) == -1) {
5ebff42a 536 err(1, "Trimming %s failed", volume->name);
3ad14c0f
TK
537 /* not reached */
538 }
461cb726
TK
539
540 return(0);
e0fb398b
T
541}
542
9a8bf4a7 543/*
f176517c 544 * Format a HAMMER volume.
9a8bf4a7
MD
545 */
546static
547void
2dba5fa7 548format_volume(volume_info_t volume, int nvols, const char *label)
9a8bf4a7 549{
2dba5fa7 550 volume_info_t root_vol;
b419d3ee 551 hammer_volume_ondisk_t ondisk;
c3be93f2 552 int64_t freeblks;
0d86737d 553 int64_t freebytes;
413cc6b1 554 int64_t vol_buf_size;
ef927d3e 555 hammer_off_t vol_alloc;
68e079b8 556 int i;
9a8bf4a7 557
ed3afcca
MD
558 /*
559 * Initialize basic information in the on-disk volume structure.
560 */
5ebff42a 561 ondisk = volume->ondisk;
ed3afcca
MD
562
563 ondisk->vol_fsid = Hammer_FSId;
564 ondisk->vol_fstype = Hammer_FSType;
6c39d27a 565 snprintf(ondisk->vol_label, sizeof(ondisk->vol_label), "%s", label);
5ebff42a 566 ondisk->vol_no = volume->vol_no;
ed3afcca 567 ondisk->vol_count = nvols;
47921633 568 ondisk->vol_version = HammerVersion;
9a8bf4a7 569
b2bafd84 570 vol_alloc = HeaderJunkSize;
ef927d3e
TK
571 ondisk->vol_bot_beg = vol_alloc;
572 vol_alloc += BootAreaSize;
573 ondisk->vol_mem_beg = vol_alloc;
3e7805d7 574 vol_alloc += MemoryLogSize;
40043e7f
MD
575
576 /*
e694ed2f 577 * The remaining area is the zone 2 buffer allocation area.
40043e7f 578 */
ef927d3e 579 ondisk->vol_buf_beg = vol_alloc;
5ebff42a 580 ondisk->vol_buf_end = volume->size & ~(int64_t)HAMMER_BUFMASK;
0dd9c298 581 vol_buf_size = HAMMER_VOL_BUF_SIZE(ondisk);
9a8bf4a7 582
6758745f 583 if (vol_buf_size < (int64_t)sizeof(*ondisk)) {
ed3afcca 584 errx(1, "volume %d %s is too small to hold the volume header",
5ebff42a 585 volume->vol_no, volume->name);
3ad14c0f 586 /* not reached */
6758745f 587 }
3ad14c0f 588 if ((vol_buf_size & ~HAMMER_OFF_SHORT_MASK) != 0) {
5ebff42a 589 errx(1, "volume %d %s is too large", volume->vol_no, volume->name);
3ad14c0f
TK
590 /* not reached */
591 }
10b51211 592
7a39af79 593 ondisk->vol_rootvol = HAMMER_ROOT_VOLNO;
c3be93f2
MD
594 ondisk->vol_signature = HAMMER_FSBUF_VOLUME;
595
5ebff42a
TK
596 volume->vol_free_off = HAMMER_ENCODE_RAW_BUFFER(volume->vol_no, 0);
597 volume->vol_free_end = HAMMER_ENCODE_RAW_BUFFER(volume->vol_no,
413cc6b1 598 vol_buf_size & ~HAMMER_BIGBLOCK_MASK64);
c3be93f2 599
9a8bf4a7 600 /*
c3be93f2 601 * Format the root volume.
9a8bf4a7 602 */
5ebff42a 603 if (volume->vol_no == HAMMER_ROOT_VOLNO) {
416571a0 604 /*
92d0a1c8 605 * Check freemap counts before formatting
416571a0 606 */
5ebff42a 607 freeblks = count_freemap(volume);
e04ee2de 608 freebytes = freeblks * HAMMER_BIGBLOCK_SIZE64;
6758745f 609 if (freebytes < 10*GIG && ForceOpt == 0) {
95033605
TK
610 errx(1, "Cannot create a HAMMER filesystem less than 10GB "
611 "unless you use -f\n(for the size of Volume %d). "
612 "HAMMER filesystems less than 50GB are not "
7eb492eb 613 "recommended.", HAMMER_ROOT_VOLNO);
3ad14c0f 614 /* not reached */
6758745f 615 }
92d0a1c8
TK
616
617 /*
618 * Starting TID
619 */
620 ondisk->vol0_next_tid = createtid();
621
042505d7
TK
622 /*
623 * Format freemap. vol0_stat_freebigblocks is
624 * the number of big-blocks available for anything
625 * other than freemap zone at this point.
626 */
5ebff42a 627 format_freemap(volume);
fac8cad6 628 assert(ondisk->vol0_stat_freebigblocks == 0);
5ebff42a 629 ondisk->vol0_stat_freebigblocks = initialize_freemap(volume);
cdb90bcd
TK
630
631 /*
632 * Format zones that are mapped to zone-2.
633 */
6758745f 634 for (i = 0; i < HAMMER_MAX_ZONES; ++i) {
f6d29b27 635 if (hammer_is_index_record(i))
5ebff42a 636 format_blockmap(volume, i, 0);
6758745f 637 }
042505d7
TK
638
639 /*
640 * Format undo zone. Formatting decrements
641 * vol0_stat_freebigblocks whenever a new big-block
642 * is allocated for undo zone.
643 */
5ebff42a 644 format_undomap(volume, &UndoBufferSize);
fac8cad6 645 assert(ondisk->vol0_stat_bigblocks == 0);
042505d7 646 ondisk->vol0_stat_bigblocks = ondisk->vol0_stat_freebigblocks;
3f673d5c 647
042505d7
TK
648 /*
649 * Format the root directory. Formatting decrements
650 * vol0_stat_freebigblocks whenever a new big-block
651 * is allocated for required zones.
652 */
b4fed9fb 653 ondisk->vol0_btree_root = format_root_directory(label);
47197d71 654 ++ondisk->vol0_stat_inodes; /* root inode */
c3be93f2 655 } else {
5ebff42a 656 freeblks = initialize_freemap(volume);
42700c9d 657 root_vol = get_root_volume();
c3be93f2
MD
658 root_vol->ondisk->vol0_stat_freebigblocks += freeblks;
659 root_vol->ondisk->vol0_stat_bigblocks += freeblks;
9a8bf4a7 660 }
9a8bf4a7
MD
661}
662
663/*
ed3afcca 664 * Format the root directory.
9a8bf4a7
MD
665 */
666static
47197d71 667hammer_off_t
b4fed9fb 668format_root_directory(const char *label)
9a8bf4a7 669{
47197d71 670 hammer_off_t btree_off;
4d8a2348 671 hammer_off_t idata_off;
d8935c61 672 hammer_off_t pfsd_off;
11ad5ade 673 hammer_tid_t create_tid;
8cd0a023 674 hammer_node_ondisk_t bnode;
71db84da 675 hammer_inode_data_t idata;
d8935c61 676 hammer_pseudofs_data_t pfsd;
c17fa600
TK
677 buffer_info_t data_buffer0 = NULL;
678 buffer_info_t data_buffer1 = NULL;
679 buffer_info_t data_buffer2 = NULL;
8cd0a023 680 hammer_btree_elm_t elm;
46137e17 681 uint64_t xtime;
ed3afcca 682
44cd685c 683 /*
baa8ac59 684 * Allocate zero-filled root btree node, inode and pfs
44cd685c 685 */
73eb8826 686 bnode = alloc_btree_node(&btree_off, &data_buffer0);
4d8a2348 687 idata = alloc_meta_element(&idata_off, sizeof(*idata), &data_buffer1);
baa8ac59 688 pfsd = alloc_meta_element(&pfsd_off, sizeof(*pfsd), &data_buffer2);
11ad5ade 689 create_tid = createtid();
7849afbc 690 xtime = nowtime();
9a8bf4a7
MD
691
692 /*
ed3afcca 693 * Populate the inode data and inode record for the root directory.
9a8bf4a7 694 */
ed3afcca
MD
695 idata->version = HAMMER_INODE_DATA_VERSION;
696 idata->mode = 0755;
7849afbc
MD
697 idata->ctime = xtime;
698 idata->mtime = xtime;
699 idata->atime = xtime;
11ad5ade
MD
700 idata->obj_type = HAMMER_OBJTYPE_DIRECTORY;
701 idata->size = 0;
702 idata->nlinks = 1;
47921633
MD
703 if (HammerVersion >= HAMMER_VOL_VERSION_TWO)
704 idata->cap_flags |= HAMMER_INODE_CAP_DIR_LOCAL_INO;
e523b881
MD
705 if (HammerVersion >= HAMMER_VOL_VERSION_SIX)
706 idata->cap_flags |= HAMMER_INODE_CAP_DIRHASH_ALG1;
9a8bf4a7 707
b4fed9fb
TK
708 /*
709 * Populate the PFS data for the root PFS.
710 */
d8935c61 711 pfsd->sync_low_tid = 1;
ddc8e722 712 pfsd->sync_beg_tid = 0;
a5ff7917 713 pfsd->sync_end_tid = 0; /* overriden by vol0_next_tid on root PFS */
d8935c61
MD
714 pfsd->shared_uuid = Hammer_FSId;
715 pfsd->unique_uuid = Hammer_FSId;
d8935c61
MD
716 pfsd->mirror_flags = 0;
717 snprintf(pfsd->label, sizeof(pfsd->label), "%s", label);
718
9a8bf4a7 719 /*
620822d2
MD
720 * Create the root of the B-Tree. The root is a leaf node so we
721 * do not have to worry about boundary elements.
9a8bf4a7 722 */
4d8a2348 723 bnode->parent = 0; /* no parent */
d8935c61 724 bnode->count = 2;
8cd0a023 725 bnode->type = HAMMER_BTREE_TYPE_LEAF;
4d8a2348 726 bnode->mirror_tid = 0;
620822d2 727
b4fed9fb
TK
728 /*
729 * Create the first node element for the inode.
730 */
8cd0a023 731 elm = &bnode->elms[0];
11ad5ade 732 elm->leaf.base.btype = HAMMER_BTREE_TYPE_RECORD;
7e52af60 733 elm->leaf.base.localization = HAMMER_DEF_LOCALIZATION |
38c04e64 734 HAMMER_LOCALIZE_INODE;
11ad5ade
MD
735 elm->leaf.base.obj_id = HAMMER_OBJID_ROOT;
736 elm->leaf.base.key = 0;
737 elm->leaf.base.create_tid = create_tid;
738 elm->leaf.base.delete_tid = 0;
739 elm->leaf.base.rec_type = HAMMER_RECTYPE_INODE;
740 elm->leaf.base.obj_type = HAMMER_OBJTYPE_DIRECTORY;
46137e17 741 elm->leaf.create_ts = (uint32_t)time(NULL);
11ad5ade 742
4d8a2348 743 elm->leaf.data_offset = idata_off;
11ad5ade 744 elm->leaf.data_len = sizeof(*idata);
4c09d9c4 745 hammer_crc_set_leaf(HammerVersion, idata, &elm->leaf);
11ad5ade 746
b4fed9fb
TK
747 /*
748 * Create the second node element for the PFS data.
935c61ab
TK
749 * This is supposed to be a record part of the root ip (inode),
750 * so it should have the same obj_type value as above.
b4fed9fb 751 */
d8935c61
MD
752 elm = &bnode->elms[1];
753 elm->leaf.base.btype = HAMMER_BTREE_TYPE_RECORD;
7e52af60 754 elm->leaf.base.localization = HAMMER_DEF_LOCALIZATION |
38c04e64 755 HAMMER_LOCALIZE_MISC;
d8935c61 756 elm->leaf.base.obj_id = HAMMER_OBJID_ROOT;
d9b1ce90 757 elm->leaf.base.key = 0;
d8935c61
MD
758 elm->leaf.base.create_tid = create_tid;
759 elm->leaf.base.delete_tid = 0;
d9b1ce90 760 elm->leaf.base.rec_type = HAMMER_RECTYPE_PFS;
935c61ab 761 elm->leaf.base.obj_type = HAMMER_OBJTYPE_DIRECTORY;
46137e17 762 elm->leaf.create_ts = (uint32_t)time(NULL);
d8935c61
MD
763
764 elm->leaf.data_offset = pfsd_off;
765 elm->leaf.data_len = sizeof(*pfsd);
4c09d9c4 766 hammer_crc_set_leaf(HammerVersion, pfsd, &elm->leaf);
d8935c61 767
4c09d9c4 768 hammer_crc_set_btree(HammerVersion, bnode);
52bae4a6 769
191b971e
TK
770 rel_buffer(data_buffer0);
771 rel_buffer(data_buffer1);
772 rel_buffer(data_buffer2);
773
47197d71 774 return(btree_off);
9a8bf4a7 775}