| Commit | Line | Data |
|---|---|---|
| 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 | 39 | static int64_t getsize(const char *str, int64_t minval, int64_t maxval, int pw); |
| 9a8bf4a7 | 40 | static const char *sizetostr(off_t size); |
| ed3afcca | 41 | static void check_volume(struct volume_info *vol); |
| 416571a0 MD |
42 | static void format_volume(struct volume_info *vol, int nvols,const char *label, |
| 43 | off_t total_size); | |
| d8935c61 | 44 | static hammer_off_t format_root(const char *label); |
| 7849afbc | 45 | static u_int64_t nowtime(void); |
| ed3afcca | 46 | static void usage(void); |
| 9a8bf4a7 | 47 | |
| 0d86737d | 48 | static int ForceOpt = 0; |
| 47921633 | 49 | static int HammerVersion = -1; |
| 0d86737d MD |
50 | |
| 51 | #define GIG (1024LL*1024*1024) | |
| 52 | ||
| 9a8bf4a7 MD |
53 | int |
| 54 | main(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 | ||
| 270 | static | |
| 271 | void | |
| 272 | usage(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 |
284 | static |
| 285 | const char * | |
| 9a8bf4a7 MD |
286 | sizetostr(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 | 311 | static int64_t |
| ed3afcca | 312 | getsize(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 |
372 | static hammer_tid_t |
| 373 | createtid(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 |
382 | static u_int64_t |
| 383 | nowtime(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 | */ | |
| 397 | static | |
| 398 | void | |
| ed3afcca | 399 | check_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 | */ | |
| 451 | static | |
| 452 | void | |
| 416571a0 | 453 | format_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 | */ |
| 544 | static | |
| 47197d71 | 545 | hammer_off_t |
| d8935c61 | 546 | format_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 |