2 * Copyright (c) 2007 The DragonFly Project. All rights reserved.
4 * This code is derived from software contributed to The DragonFly Project
5 * by Matthew Dillon <dillon@backplane.com>
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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
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.
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
34 * $DragonFly: src/sbin/newfs_hammer/newfs_hammer.c,v 1.21 2008/03/19 20:18:16 dillon Exp $
37 #include "newfs_hammer.h"
39 static int64_t getsize(const char *str, int64_t minval, int64_t maxval, int pw);
40 static const char *sizetostr(off_t size);
41 static void check_volume(struct volume_info *vol);
42 static void format_volume(struct volume_info *vol, int nvols,const char *label);
43 static hammer_off_t format_root(void);
44 static void usage(void);
47 main(int ac, char **av)
53 const char *label = NULL;
56 * Sanity check basic filesystem structures. No cookies for us
59 assert(sizeof(struct hammer_volume_ondisk) <= HAMMER_BUFSIZE);
60 assert(sizeof(union hammer_record_ondisk) == HAMMER_RECORD_SIZE);
61 assert(sizeof(struct hammer_blockmap_layer1) == 32);
62 assert(sizeof(struct hammer_blockmap_layer2) == 16);
65 * Generate a filesysem id and lookup the filesystem type
67 uuidgen(&Hammer_FSId, 1);
68 uuid_name_lookup(&Hammer_FSType, "DragonFly HAMMER", &status);
69 if (status != uuid_s_ok) {
70 errx(1, "uuids file does not have the DragonFly "
71 "HAMMER filesystem type");
77 while ((ch = getopt(ac, av, "L:b:m:")) != -1) {
83 BootAreaSize = getsize(optarg,
85 HAMMER_BOOT_MAXBYTES, 2);
88 MemAreaSize = getsize(optarg,
90 HAMMER_MEM_MAXBYTES, 2);
100 "newfs_hammer: A filesystem label must be specified\n");
105 * Collect volume information
113 for (i = 0; i < NumVolumes; ++i) {
114 struct volume_info *vol;
116 vol = setup_volume(i, av[i], 1, O_RDWR);
119 * Load up information on the volume and initialize
120 * its remaining fields.
127 * Calculate defaults for the boot and memory area sizes.
129 if (BootAreaSize == 0) {
130 BootAreaSize = HAMMER_BOOT_NOMBYTES;
131 while (BootAreaSize > total / NumVolumes / 256)
133 if (BootAreaSize < HAMMER_BOOT_MINBYTES)
135 } else if (BootAreaSize < HAMMER_BOOT_MINBYTES) {
136 BootAreaSize = HAMMER_BOOT_MINBYTES;
138 if (MemAreaSize == 0) {
139 MemAreaSize = HAMMER_MEM_NOMBYTES;
140 while (MemAreaSize > total / NumVolumes / 256)
142 if (MemAreaSize < HAMMER_MEM_MINBYTES)
144 } else if (MemAreaSize < HAMMER_MEM_MINBYTES) {
145 MemAreaSize = HAMMER_MEM_MINBYTES;
148 printf("---------------------------------------------\n");
149 printf("%d volume%s total size %s\n",
150 NumVolumes, (NumVolumes == 1 ? "" : "s"), sizetostr(total));
151 printf("boot-area-size: %s\n", sizetostr(BootAreaSize));
152 printf("memory-log-size: %s\n", sizetostr(MemAreaSize));
156 * Format the volumes. Format the root volume first so we can
157 * bootstrap the freemap.
159 format_volume(get_volume(RootVolNo), NumVolumes, label);
160 for (i = 0; i < NumVolumes; ++i) {
162 format_volume(get_volume(i), NumVolumes, label);
172 fprintf(stderr, "newfs_hammer vol0 [vol1 ...]\n");
177 * Convert the size in bytes to a human readable string.
180 sizetostr(off_t size)
184 if (size < 1024 / 2) {
185 snprintf(buf, sizeof(buf), "%6.2f", (double)size);
186 } else if (size < 1024 * 1024 / 2) {
187 snprintf(buf, sizeof(buf), "%6.2fKB",
188 (double)size / 1024);
189 } else if (size < 1024 * 1024 * 1024LL / 2) {
190 snprintf(buf, sizeof(buf), "%6.2fMB",
191 (double)size / (1024 * 1024));
192 } else if (size < 1024 * 1024 * 1024LL * 1024LL / 2) {
193 snprintf(buf, sizeof(buf), "%6.2fGB",
194 (double)size / (1024 * 1024 * 1024LL));
196 snprintf(buf, sizeof(buf), "%6.2fTB",
197 (double)size / (1024 * 1024 * 1024LL * 1024LL));
203 * Convert a string to a 64 bit signed integer with various requirements.
206 getsize(const char *str, int64_t minval, int64_t maxval, int powerof2)
211 val = strtoll(str, &ptr, 0);
230 errx(1, "Unknown suffix in number '%s'\n", str);
234 errx(1, "Unknown suffix in number '%s'\n", str);
238 errx(1, "Value too small: %s, min is %s\n",
239 str, sizetostr(minval));
243 errx(1, "Value too large: %s, max is %s\n",
244 str, sizetostr(maxval));
247 if ((powerof2 & 1) && (val ^ (val - 1)) != ((val << 1) - 1)) {
248 errx(1, "Value not power of 2: %s\n", str);
251 if ((powerof2 & 2) && (val & HAMMER_BUFMASK)) {
252 errx(1, "Value not an integral multiple of %dK: %s",
253 HAMMER_BUFSIZE / 1024, str);
260 * Generate a transaction id
265 static hammer_tid_t lasttid;
269 gettimeofday(&tv, NULL);
270 lasttid = tv.tv_sec * 1000000000LL +
277 * Check basic volume characteristics. HAMMER filesystems use a minimum
278 * of a 16KB filesystem buffer size.
282 check_volume(struct volume_info *vol)
284 struct partinfo pinfo;
288 * Get basic information about the volume
290 vol->fd = open(vol->name, O_RDWR);
292 err(1, "Unable to open %s R+W", vol->name);
293 if (ioctl(vol->fd, DIOCGPART, &pinfo) < 0) {
295 * Allow the formatting of regular filews as HAMMER volumes
297 if (fstat(vol->fd, &st) < 0)
298 err(1, "Unable to stat %s", vol->name);
299 vol->size = st.st_size;
300 vol->type = "REGFILE";
303 * When formatting a block device as a HAMMER volume the
304 * sector size must be compatible. HAMMER uses 16384 byte
305 * filesystem buffers.
307 if (pinfo.reserved_blocks) {
308 errx(1, "HAMMER cannot be placed in a partition "
309 "which overlaps the disklabel or MBR");
311 if (pinfo.media_blksize > 16384 ||
312 16384 % pinfo.media_blksize) {
313 errx(1, "A media sector size of %d is not supported",
314 pinfo.media_blksize);
317 vol->size = pinfo.media_size;
318 vol->type = "DEVICE";
320 printf("Volume %d %s %-15s size %s\n",
321 vol->vol_no, vol->type, vol->name,
322 sizetostr(vol->size));
325 * Reserve space for (future) header junk, setup our poor-man's
326 * bigblock allocator.
328 vol->vol_alloc = HAMMER_BUFSIZE * 16;
332 * Format a HAMMER volume. Cluster 0 will be initially placed in volume 0.
336 format_volume(struct volume_info *vol, int nvols, const char *label)
338 struct volume_info *root_vol;
339 struct hammer_volume_ondisk *ondisk;
343 * Initialize basic information in the on-disk volume structure.
345 ondisk = vol->ondisk;
347 ondisk->vol_fsid = Hammer_FSId;
348 ondisk->vol_fstype = Hammer_FSType;
349 snprintf(ondisk->vol_name, sizeof(ondisk->vol_name), "%s", label);
350 ondisk->vol_no = vol->vol_no;
351 ondisk->vol_count = nvols;
352 ondisk->vol_version = 1;
354 ondisk->vol_bot_beg = vol->vol_alloc;
355 vol->vol_alloc += BootAreaSize;
356 ondisk->vol_mem_beg = vol->vol_alloc;
357 vol->vol_alloc += MemAreaSize;
360 * The remaining area is the zone 2 buffer allocation area. These
363 ondisk->vol_buf_beg = vol->vol_alloc;
364 ondisk->vol_buf_end = vol->size & ~(int64_t)HAMMER_BUFMASK;
366 if (ondisk->vol_buf_end < ondisk->vol_buf_beg) {
367 errx(1, "volume %d %s is too small to hold the volume header",
368 vol->vol_no, vol->name);
371 ondisk->vol_nblocks = (ondisk->vol_buf_end - ondisk->vol_buf_beg) /
373 ondisk->vol_blocksize = HAMMER_BUFSIZE;
375 ondisk->vol_rootvol = RootVolNo;
376 ondisk->vol_signature = HAMMER_FSBUF_VOLUME;
378 vol->vol_free_off = HAMMER_ENCODE_RAW_BUFFER(vol->vol_no, 0);
379 vol->vol_free_end = HAMMER_ENCODE_RAW_BUFFER(vol->vol_no, (ondisk->vol_buf_end - ondisk->vol_buf_beg) & ~HAMMER_LARGEBLOCK_MASK64);
382 * Format the root volume.
384 if (vol->vol_no == RootVolNo) {
385 ondisk->vol0_next_tid = createtid();
388 &ondisk->vol0_blockmap[HAMMER_ZONE_FREEMAP_INDEX]);
390 freeblks = initialize_freemap(vol);
391 ondisk->vol0_stat_freebigblocks = freeblks;
392 ondisk->vol0_stat_bigblocks = freeblks;
395 &ondisk->vol0_blockmap[HAMMER_ZONE_BTREE_INDEX],
398 &ondisk->vol0_blockmap[HAMMER_ZONE_RECORD_INDEX],
401 &ondisk->vol0_blockmap[HAMMER_ZONE_LARGE_DATA_INDEX],
402 HAMMER_ZONE_LARGE_DATA);
404 &ondisk->vol0_blockmap[HAMMER_ZONE_SMALL_DATA_INDEX],
405 HAMMER_ZONE_SMALL_DATA);
407 format_undomap(ondisk);
409 ondisk->vol0_btree_root = format_root();
410 ++ondisk->vol0_stat_inodes; /* root inode */
412 freeblks = initialize_freemap(vol);
413 root_vol = get_volume(RootVolNo);
414 root_vol->cache.modified = 1;
415 root_vol->ondisk->vol0_stat_freebigblocks += freeblks;
416 root_vol->ondisk->vol0_stat_bigblocks += freeblks;
417 rel_volume(root_vol);
422 * Format the root directory.
428 hammer_off_t btree_off;
429 hammer_off_t rec_off;
430 hammer_node_ondisk_t bnode;
431 hammer_record_ondisk_t rec;
432 struct hammer_inode_data *idata;
433 hammer_btree_elm_t elm;
435 bnode = alloc_btree_element(&btree_off);
436 rec = alloc_record_element(&rec_off, sizeof(*idata), (void **)&idata);
439 * Populate the inode data and inode record for the root directory.
441 idata->version = HAMMER_INODE_DATA_VERSION;
444 rec->base.base.btype = HAMMER_BTREE_TYPE_RECORD;
445 rec->base.base.obj_id = HAMMER_OBJID_ROOT;
446 rec->base.base.key = 0;
447 rec->base.base.create_tid = createtid();
448 rec->base.base.delete_tid = 0;
449 rec->base.base.rec_type = HAMMER_RECTYPE_INODE;
450 rec->base.base.obj_type = HAMMER_OBJTYPE_DIRECTORY;
451 /* rec->base.data_offset - initialized by alloc_record_element */
452 /* rec->base.data_len - initialized by alloc_record_element */
453 rec->base.data_crc = crc32(idata, sizeof(*idata));
454 rec->inode.ino_atime = rec->base.base.create_tid;
455 rec->inode.ino_mtime = rec->base.base.create_tid;
456 rec->inode.ino_size = 0;
457 rec->inode.ino_nlinks = 1;
460 * Create the root of the B-Tree. The root is a leaf node so we
461 * do not have to worry about boundary elements.
464 bnode->type = HAMMER_BTREE_TYPE_LEAF;
466 elm = &bnode->elms[0];
467 elm->base = rec->base.base;
468 elm->leaf.rec_offset = rec_off;
469 elm->leaf.data_offset = rec->base.data_off;
470 elm->leaf.data_len = rec->base.data_len;
471 elm->leaf.data_crc = rec->base.data_crc;