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.17 2008/02/08 08:30:58 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
);
62 * Generate a filesysem id and lookup the filesystem type
64 uuidgen(&Hammer_FSId
, 1);
65 uuid_name_lookup(&Hammer_FSType
, "DragonFly HAMMER", &status
);
66 if (status
!= uuid_s_ok
) {
67 errx(1, "uuids file does not have the DragonFly "
68 "HAMMER filesystem type");
74 while ((ch
= getopt(ac
, av
, "L:b:m:")) != -1) {
80 BootAreaSize
= getsize(optarg
,
82 HAMMER_BOOT_MAXBYTES
, 2);
85 MemAreaSize
= getsize(optarg
,
87 HAMMER_MEM_MAXBYTES
, 2);
97 "newfs_hammer: A filesystem label must be specified\n");
102 * Collect volume information
110 for (i
= 0; i
< NumVolumes
; ++i
) {
111 struct volume_info
*vol
;
113 vol
= setup_volume(i
, av
[i
], 1, O_RDWR
);
116 * Load up information on the volume and initialize
117 * its remaining fields.
124 * Calculate defaults for the boot and memory area sizes.
126 if (BootAreaSize
== 0) {
127 BootAreaSize
= HAMMER_BOOT_NOMBYTES
;
128 while (BootAreaSize
> total
/ NumVolumes
/ 256)
130 if (BootAreaSize
< HAMMER_BOOT_MINBYTES
)
132 } else if (BootAreaSize
< HAMMER_BOOT_MINBYTES
) {
133 BootAreaSize
= HAMMER_BOOT_MINBYTES
;
135 if (MemAreaSize
== 0) {
136 MemAreaSize
= HAMMER_MEM_NOMBYTES
;
137 while (MemAreaSize
> total
/ NumVolumes
/ 256)
139 if (MemAreaSize
< HAMMER_MEM_MINBYTES
)
141 } else if (MemAreaSize
< HAMMER_MEM_MINBYTES
) {
142 MemAreaSize
= HAMMER_MEM_MINBYTES
;
145 printf("---------------------------------------------\n");
146 printf("%d volume%s total size %s\n",
147 NumVolumes
, (NumVolumes
== 1 ? "" : "s"), sizetostr(total
));
148 printf("boot-area-size: %s\n", sizetostr(BootAreaSize
));
149 printf("memory-log-size: %s\n", sizetostr(MemAreaSize
));
153 * Format the volumes.
155 for (i
= 0; i
< NumVolumes
; ++i
) {
156 format_volume(get_volume(i
), NumVolumes
, label
);
166 fprintf(stderr
, "newfs_hammer vol0 [vol1 ...]\n");
171 * Convert the size in bytes to a human readable string.
174 sizetostr(off_t size
)
178 if (size
< 1024 / 2) {
179 snprintf(buf
, sizeof(buf
), "%6.2f", (double)size
);
180 } else if (size
< 1024 * 1024 / 2) {
181 snprintf(buf
, sizeof(buf
), "%6.2fKB",
182 (double)size
/ 1024);
183 } else if (size
< 1024 * 1024 * 1024LL / 2) {
184 snprintf(buf
, sizeof(buf
), "%6.2fMB",
185 (double)size
/ (1024 * 1024));
186 } else if (size
< 1024 * 1024 * 1024LL * 1024LL / 2) {
187 snprintf(buf
, sizeof(buf
), "%6.2fGB",
188 (double)size
/ (1024 * 1024 * 1024LL));
190 snprintf(buf
, sizeof(buf
), "%6.2fTB",
191 (double)size
/ (1024 * 1024 * 1024LL * 1024LL));
197 * Convert a string to a 64 bit signed integer with various requirements.
200 getsize(const char *str
, int64_t minval
, int64_t maxval
, int powerof2
)
205 val
= strtoll(str
, &ptr
, 0);
224 errx(1, "Unknown suffix in number '%s'\n", str
);
228 errx(1, "Unknown suffix in number '%s'\n", str
);
232 errx(1, "Value too small: %s, min is %s\n",
233 str
, sizetostr(minval
));
237 errx(1, "Value too large: %s, max is %s\n",
238 str
, sizetostr(maxval
));
241 if ((powerof2
& 1) && (val
^ (val
- 1)) != ((val
<< 1) - 1)) {
242 errx(1, "Value not power of 2: %s\n", str
);
245 if ((powerof2
& 2) && (val
& HAMMER_BUFMASK
)) {
246 errx(1, "Value not an integral multiple of %dK: %s",
247 HAMMER_BUFSIZE
/ 1024, str
);
254 * Generate a transaction id
259 static hammer_tid_t lasttid
;
263 gettimeofday(&tv
, NULL
);
264 lasttid
= tv
.tv_sec
* 1000000000LL +
271 * Check basic volume characteristics. HAMMER filesystems use a minimum
272 * of a 16KB filesystem buffer size.
276 check_volume(struct volume_info
*vol
)
278 struct partinfo pinfo
;
282 * Get basic information about the volume
284 vol
->fd
= open(vol
->name
, O_RDWR
);
286 err(1, "Unable to open %s R+W", vol
->name
);
287 if (ioctl(vol
->fd
, DIOCGPART
, &pinfo
) < 0) {
289 * Allow the formatting of regular filews as HAMMER volumes
291 if (fstat(vol
->fd
, &st
) < 0)
292 err(1, "Unable to stat %s", vol
->name
);
293 vol
->size
= st
.st_size
;
294 vol
->type
= "REGFILE";
297 * When formatting a block device as a HAMMER volume the
298 * sector size must be compatible. HAMMER uses 16384 byte
299 * filesystem buffers.
301 if (pinfo
.reserved_blocks
) {
302 errx(1, "HAMMER cannot be placed in a partition "
303 "which overlaps the disklabel or MBR");
305 if (pinfo
.media_blksize
> 16384 ||
306 16384 % pinfo
.media_blksize
) {
307 errx(1, "A media sector size of %d is not supported",
308 pinfo
.media_blksize
);
311 vol
->size
= pinfo
.media_size
;
312 vol
->type
= "DEVICE";
314 printf("Volume %d %s %-15s size %s\n",
315 vol
->vol_no
, vol
->type
, vol
->name
,
316 sizetostr(vol
->size
));
319 * Reserve space for (future) header junk
321 vol
->vol_alloc
= HAMMER_BUFSIZE
* 16;
325 * Format a HAMMER volume. Cluster 0 will be initially placed in volume 0.
329 format_volume(struct volume_info
*vol
, int nvols
, const char *label
)
331 struct hammer_volume_ondisk
*ondisk
;
334 * Initialize basic information in the on-disk volume structure.
336 ondisk
= vol
->ondisk
;
338 ondisk
->vol_fsid
= Hammer_FSId
;
339 ondisk
->vol_fstype
= Hammer_FSType
;
340 snprintf(ondisk
->vol_name
, sizeof(ondisk
->vol_name
), "%s", label
);
341 ondisk
->vol_no
= vol
->vol_no
;
342 ondisk
->vol_count
= nvols
;
343 ondisk
->vol_version
= 1;
345 ondisk
->vol_bot_beg
= vol
->vol_alloc
;
346 vol
->vol_alloc
+= BootAreaSize
;
347 ondisk
->vol_mem_beg
= vol
->vol_alloc
;
348 vol
->vol_alloc
+= MemAreaSize
;
349 ondisk
->vol_buf_beg
= vol
->vol_alloc
;
350 ondisk
->vol_buf_end
= vol
->size
& ~(int64_t)HAMMER_BUFMASK
;
352 if (ondisk
->vol_buf_end
< ondisk
->vol_buf_beg
) {
353 errx(1, "volume %d %s is too small to hold the volume header",
354 vol
->vol_no
, vol
->name
);
357 ondisk
->vol_nblocks
= (ondisk
->vol_buf_end
- ondisk
->vol_buf_beg
) /
359 ondisk
->vol_blocksize
= HAMMER_BUFSIZE
;
362 * Assign the root volume to volume 0.
364 ondisk
->vol_rootvol
= 0;
365 ondisk
->vol_signature
= HAMMER_FSBUF_VOLUME
;
366 if (ondisk
->vol_no
== (int)ondisk
->vol_rootvol
) {
368 * Create an empty FIFO starting at the first buffer
369 * in volume 0. hammer_off_t must be properly formatted
370 * (see vfs/hammer/hammer_disk.h)
372 ondisk
->vol0_fifo_beg
= HAMMER_ENCODE_RAW_BUFFER(0, 0);
373 ondisk
->vol0_fifo_end
= ondisk
->vol0_fifo_beg
;
374 ondisk
->vol0_next_tid
= createtid();
375 ondisk
->vol0_next_seq
= 1;
377 ondisk
->vol0_btree_root
= format_root();
378 ++ondisk
->vol0_stat_inodes
; /* root inode */
384 * Format the root directory.
390 hammer_off_t btree_off
;
391 hammer_off_t rec_off
;
392 hammer_node_ondisk_t bnode
;
393 hammer_record_ondisk_t rec
;
394 struct hammer_inode_data
*idata
;
395 hammer_btree_elm_t elm
;
397 bnode
= alloc_btree_element(&btree_off
);
398 rec
= alloc_record_element(&rec_off
, HAMMER_RECTYPE_INODE
,
399 sizeof(rec
->inode
), sizeof(*idata
),
403 * Populate the inode data and inode record for the root directory.
405 idata
->version
= HAMMER_INODE_DATA_VERSION
;
408 rec
->base
.base
.btype
= HAMMER_BTREE_TYPE_RECORD
;
409 rec
->base
.base
.obj_id
= HAMMER_OBJID_ROOT
;
410 rec
->base
.base
.key
= 0;
411 rec
->base
.base
.create_tid
= createtid();
412 rec
->base
.base
.delete_tid
= 0;
413 rec
->base
.base
.rec_type
= HAMMER_RECTYPE_INODE
;
414 rec
->base
.base
.obj_type
= HAMMER_OBJTYPE_DIRECTORY
;
415 /* rec->base.data_offset - initialized by alloc_record_element */
416 /* rec->base.data_len - initialized by alloc_record_element */
417 rec
->base
.head
.hdr_crc
= crc32(idata
, sizeof(*idata
));
418 rec
->inode
.ino_atime
= rec
->base
.base
.create_tid
;
419 rec
->inode
.ino_mtime
= rec
->base
.base
.create_tid
;
420 rec
->inode
.ino_size
= 0;
421 rec
->inode
.ino_nlinks
= 1;
424 * Create the root of the B-Tree. The root is a leaf node so we
425 * do not have to worry about boundary elements.
428 bnode
->type
= HAMMER_BTREE_TYPE_LEAF
;
430 elm
= &bnode
->elms
[0];
431 elm
->base
= rec
->base
.base
;
432 elm
->leaf
.rec_offset
= rec_off
;
433 elm
->leaf
.data_offset
= rec
->base
.data_off
;
434 elm
->leaf
.data_len
= rec
->base
.data_len
;
435 elm
->leaf
.data_crc
= rec
->base
.head
.hdr_crc
;