Enhance the comment
[dragonfly.git] / sbin / newfs_hammer / newfs_hammer.c
blobba06e04782fb3b8bbfdc6958c5e709cf25d872c9
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:
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.
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.
34 * $DragonFly: src/sbin/newfs_hammer/newfs_hammer.c,v 1.10 2007/12/14 08:05:37 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 int32_t format_cluster(struct volume_info *vol, int isroot);
44 static void format_root(struct cluster_info *cluster);
45 static void usage(void);
47 struct hammer_alist_config Buf_alist_config;
48 struct hammer_alist_config Vol_normal_alist_config;
49 struct hammer_alist_config Vol_super_alist_config;
50 struct hammer_alist_config Supercl_alist_config;
51 struct hammer_alist_config Clu_master_alist_config;
52 struct hammer_alist_config Clu_slave_alist_config;
53 uuid_t Hammer_FSType;
54 uuid_t Hammer_FSId;
55 int64_t ClusterSize;
56 int64_t BootAreaSize;
57 int64_t MemAreaSize;
58 int UsingSuperClusters;
59 int NumVolumes;
60 struct volume_info *VolBase;
62 int
63 main(int ac, char **av)
65 int i;
66 int ch;
67 u_int32_t status;
68 off_t total;
69 int64_t max_volume_size;
70 const char *label = NULL;
73 * Sanity check basic filesystem structures. No cookies for us
74 * if it gets broken!
76 assert(sizeof(struct hammer_almeta) == HAMMER_ALMETA_SIZE);
77 assert(sizeof(struct hammer_fsbuf_head) == HAMMER_FSBUF_HEAD_SIZE);
78 assert(sizeof(struct hammer_volume_ondisk) <= HAMMER_BUFSIZE);
79 assert(sizeof(struct hammer_cluster_ondisk) <= HAMMER_BUFSIZE);
80 assert(sizeof(struct hammer_fsbuf_data) == HAMMER_BUFSIZE);
81 assert(sizeof(struct hammer_fsbuf_recs) == HAMMER_BUFSIZE);
82 assert(sizeof(struct hammer_fsbuf_btree) == HAMMER_BUFSIZE);
83 assert(sizeof(union hammer_fsbuf_ondisk) == HAMMER_BUFSIZE);
86 * Generate a filesysem id and lookup the filesystem type
88 uuidgen(&Hammer_FSId, 1);
89 uuid_name_lookup(&Hammer_FSType, "DragonFly HAMMER", &status);
90 if (status != uuid_s_ok) {
91 errx(1, "uuids file does not have the DragonFly "
92 "HAMMER filesystem type");
96 * Initialize the alist templates we will be using
98 hammer_alist_template(&Buf_alist_config, HAMMER_FSBUF_MAXBLKS,
99 1, HAMMER_FSBUF_METAELMS);
100 hammer_alist_template(&Vol_normal_alist_config, HAMMER_VOL_MAXCLUSTERS,
101 1, HAMMER_VOL_METAELMS_1LYR);
102 hammer_alist_template(&Vol_super_alist_config,
103 HAMMER_VOL_MAXSUPERCLUSTERS * HAMMER_SCL_MAXCLUSTERS,
104 HAMMER_SCL_MAXCLUSTERS, HAMMER_VOL_METAELMS_2LYR);
105 hammer_super_alist_template(&Vol_super_alist_config);
106 hammer_alist_template(&Supercl_alist_config, HAMMER_VOL_MAXCLUSTERS,
107 1, HAMMER_SUPERCL_METAELMS);
108 hammer_alist_template(&Clu_master_alist_config, HAMMER_CLU_MAXBUFFERS,
109 1, HAMMER_CLU_MASTER_METAELMS);
110 hammer_alist_template(&Clu_slave_alist_config,
111 HAMMER_CLU_MAXBUFFERS * HAMMER_FSBUF_MAXBLKS,
112 HAMMER_FSBUF_MAXBLKS, HAMMER_CLU_SLAVE_METAELMS);
113 hammer_buffer_alist_template(&Clu_slave_alist_config);
116 * Parse arguments
118 while ((ch = getopt(ac, av, "L:b:c:m:S")) != -1) {
119 switch(ch) {
120 case 'L':
121 label = optarg;
122 break;
123 case 'b':
124 BootAreaSize = getsize(optarg,
125 HAMMER_BUFSIZE,
126 HAMMER_BOOT_MAXBYTES, 2);
127 break;
128 case 'c':
129 ClusterSize = getsize(optarg,
130 HAMMER_BUFSIZE * 256LL,
131 HAMMER_CLU_MAXBYTES, 1);
132 break;
133 case 'm':
134 MemAreaSize = getsize(optarg,
135 HAMMER_BUFSIZE,
136 HAMMER_MEM_MAXBYTES, 2);
137 break;
138 case 'S':
140 * Force the use of super-clusters
142 UsingSuperClusters = 1;
143 break;
144 default:
145 usage();
146 break;
150 if (label == NULL) {
151 fprintf(stderr,
152 "newfs_hammer: A filesystem label must be specified\n");
153 exit(1);
157 * Collect volume information
159 ac -= optind;
160 av += optind;
161 NumVolumes = ac;
163 total = 0;
164 for (i = 0; i < NumVolumes; ++i) {
165 struct volume_info *vol;
167 vol = calloc(1, sizeof(struct volume_info));
168 vol->fd = -1;
169 vol->vol_no = i;
170 vol->name = av[i];
171 vol->next = VolBase;
172 VolBase = vol;
175 * Load up information on the volume and initialize
176 * its remaining fields.
178 check_volume(vol);
179 total += vol->size;
183 * Calculate the size of a cluster. A cluster is broken
184 * down into 256 chunks which must be at least filesystem buffer
185 * sized. This gives us a minimum chunk size of around 4MB.
187 if (ClusterSize == 0) {
188 ClusterSize = HAMMER_BUFSIZE * 256;
189 while (ClusterSize < total / NumVolumes / 256 &&
190 ClusterSize < HAMMER_CLU_MAXBYTES) {
191 ClusterSize <<= 1;
196 * Calculate defaults for the boot and memory area sizes.
198 if (BootAreaSize == 0) {
199 BootAreaSize = HAMMER_BOOT_NOMBYTES;
200 while (BootAreaSize > total / NumVolumes / 256)
201 BootAreaSize >>= 1;
202 if (BootAreaSize < HAMMER_BOOT_MINBYTES)
203 BootAreaSize = 0;
204 } else if (BootAreaSize < HAMMER_BOOT_MINBYTES) {
205 BootAreaSize = HAMMER_BOOT_MINBYTES;
207 if (MemAreaSize == 0) {
208 MemAreaSize = HAMMER_MEM_NOMBYTES;
209 while (MemAreaSize > total / NumVolumes / 256)
210 MemAreaSize >>= 1;
211 if (MemAreaSize < HAMMER_MEM_MINBYTES)
212 MemAreaSize = 0;
213 } else if (MemAreaSize < HAMMER_MEM_MINBYTES) {
214 MemAreaSize = HAMMER_MEM_MINBYTES;
217 printf("---------------------------------------------\n");
218 printf("%d volume%s total size %s\n",
219 NumVolumes, (NumVolumes == 1 ? "" : "s"), sizetostr(total));
220 printf("cluster-size: %s\n", sizetostr(ClusterSize));
222 if (UsingSuperClusters) {
223 max_volume_size = (int64_t)HAMMER_VOL_MAXSUPERCLUSTERS * \
224 HAMMER_SCL_MAXCLUSTERS * ClusterSize;
225 } else {
226 max_volume_size = HAMMER_VOL_MAXCLUSTERS * ClusterSize;
228 printf("max-volume-size: %s\n", sizetostr(max_volume_size));
230 printf("max-filesystem-size: %s\n",
231 (max_volume_size * 32768LL < max_volume_size) ?
232 "Unlimited" :
233 sizetostr(max_volume_size * 32768LL));
234 printf("boot-area-size: %s\n", sizetostr(BootAreaSize));
235 printf("memory-log-size: %s\n", sizetostr(MemAreaSize));
236 printf("\n");
239 * Format the volumes.
241 for (i = 0; i < NumVolumes; ++i) {
242 format_volume(get_volume(i), NumVolumes, label);
244 flush_all_volumes();
245 return(0);
248 static
249 void
250 usage(void)
252 fprintf(stderr, "newfs_hammer vol0 [vol1 ...]\n");
253 exit(1);
257 * Convert the size in bytes to a human readable string.
259 static const char *
260 sizetostr(off_t size)
262 static char buf[32];
264 if (size < 1024 / 2) {
265 snprintf(buf, sizeof(buf), "%6.2f", (double)size);
266 } else if (size < 1024 * 1024 / 2) {
267 snprintf(buf, sizeof(buf), "%6.2fKB",
268 (double)size / 1024);
269 } else if (size < 1024 * 1024 * 1024LL / 2) {
270 snprintf(buf, sizeof(buf), "%6.2fMB",
271 (double)size / (1024 * 1024));
272 } else if (size < 1024 * 1024 * 1024LL * 1024LL / 2) {
273 snprintf(buf, sizeof(buf), "%6.2fGB",
274 (double)size / (1024 * 1024 * 1024LL));
275 } else {
276 snprintf(buf, sizeof(buf), "%6.2fTB",
277 (double)size / (1024 * 1024 * 1024LL * 1024LL));
279 return(buf);
283 * Convert a string to a 64 bit signed integer with various requirements.
285 static int64_t
286 getsize(const char *str, int64_t minval, int64_t maxval, int powerof2)
288 int64_t val;
289 char *ptr;
291 val = strtoll(str, &ptr, 0);
292 switch(*ptr) {
293 case 't':
294 case 'T':
295 val *= 1024;
296 /* fall through */
297 case 'g':
298 case 'G':
299 val *= 1024;
300 /* fall through */
301 case 'm':
302 case 'M':
303 val *= 1024;
304 /* fall through */
305 case 'k':
306 case 'K':
307 val *= 1024;
308 break;
309 default:
310 errx(1, "Unknown suffix in number '%s'\n", str);
311 /* not reached */
313 if (ptr[1]) {
314 errx(1, "Unknown suffix in number '%s'\n", str);
315 /* not reached */
317 if (val < minval) {
318 errx(1, "Value too small: %s, min is %s\n",
319 str, sizetostr(minval));
320 /* not reached */
322 if (val > maxval) {
323 errx(1, "Value too large: %s, max is %s\n",
324 str, sizetostr(maxval));
325 /* not reached */
327 if ((powerof2 & 1) && (val ^ (val - 1)) != ((val << 1) - 1)) {
328 errx(1, "Value not power of 2: %s\n", str);
329 /* not reached */
331 if ((powerof2 & 2) && (val & HAMMER_BUFMASK)) {
332 errx(1, "Value not an integral multiple of %dK: %s",
333 HAMMER_BUFSIZE / 1024, str);
334 /* not reached */
336 return(val);
340 * Generate a transaction id
342 static hammer_tid_t
343 createtid(void)
345 static hammer_tid_t lasttid;
346 struct timeval tv;
348 if (lasttid == 0) {
349 gettimeofday(&tv, NULL);
350 lasttid = tv.tv_sec * 1000000000LL +
351 tv.tv_usec * 1000LL;
353 return(lasttid++);
357 * Check basic volume characteristics. HAMMER filesystems use a minimum
358 * of a 16KB filesystem buffer size.
360 static
361 void
362 check_volume(struct volume_info *vol)
364 struct partinfo pinfo;
365 struct stat st;
368 * Get basic information about the volume
370 vol->fd = open(vol->name, O_RDWR);
371 if (vol->fd < 0)
372 err(1, "Unable to open %s R+W", vol->name);
373 if (ioctl(vol->fd, DIOCGPART, &pinfo) < 0) {
375 * Allow the formatting of regular filews as HAMMER volumes
377 if (fstat(vol->fd, &st) < 0)
378 err(1, "Unable to stat %s", vol->name);
379 vol->size = st.st_size;
380 vol->type = "REGFILE";
381 } else {
383 * When formatting a block device as a HAMMER volume the
384 * sector size must be compatible. HAMMER uses 16384 byte
385 * filesystem buffers.
387 if (pinfo.reserved_blocks) {
388 errx(1, "HAMMER cannot be placed in a partition "
389 "which overlaps the disklabel or MBR");
391 if (pinfo.media_blksize > 16384 ||
392 16384 % pinfo.media_blksize) {
393 errx(1, "A media sector size of %d is not supported",
394 pinfo.media_blksize);
397 vol->size = pinfo.media_size;
398 vol->type = "DEVICE";
400 printf("Volume %d %s %-15s size %s\n",
401 vol->vol_no, vol->type, vol->name,
402 sizetostr(vol->size));
405 * Strictly speaking we do not need to enable super clusters unless
406 * we have volumes > 2TB, but turning them on doesn't really hurt
407 * and if we don't the user may get confused if he tries to expand
408 * the size of an existing volume.
410 if (vol->size > 200LL * 1024 * 1024 * 1024 && !UsingSuperClusters) {
411 UsingSuperClusters = 1;
412 printf("Enabling super-clusters\n");
416 * Reserve space for (future) header junk
418 vol->vol_alloc = HAMMER_BUFSIZE * 16;
422 * Format a HAMMER volume. Cluster 0 will be initially placed in volume 0.
424 static
425 void
426 format_volume(struct volume_info *vol, int nvols, const char *label)
428 struct hammer_volume_ondisk *ondisk;
429 int32_t nclusters;
430 int32_t minclsize;
431 int32_t nscl_groups;
432 int64_t scl_group_size;
433 int64_t scl_header_size;
434 int64_t n64;
437 * The last cluster in a volume may wind up truncated. It must be
438 * at least minclsize to really be workable as a cluster.
440 minclsize = (int32_t)(ClusterSize / 4);
441 if (minclsize < HAMMER_BUFSIZE * 64)
442 minclsize = HAMMER_BUFSIZE * 64;
445 * Initialize basic information in the on-disk volume structure.
447 ondisk = vol->ondisk;
449 ondisk->vol_fsid = Hammer_FSId;
450 ondisk->vol_fstype = Hammer_FSType;
451 snprintf(ondisk->vol_name, sizeof(ondisk->vol_name), "%s", label);
452 ondisk->vol_no = vol->vol_no;
453 ondisk->vol_count = nvols;
454 ondisk->vol_version = 1;
455 ondisk->vol_clsize = (int32_t)ClusterSize;
456 if (UsingSuperClusters)
457 ondisk->vol_flags = HAMMER_VOLF_USINGSUPERCL;
459 ondisk->vol_bot_beg = vol->vol_alloc;
460 vol->vol_alloc += BootAreaSize;
461 ondisk->vol_mem_beg = vol->vol_alloc;
462 vol->vol_alloc += MemAreaSize;
463 ondisk->vol_clo_beg = vol->vol_alloc;
464 ondisk->vol_clo_end = vol->size;
466 if (ondisk->vol_clo_end < ondisk->vol_clo_beg) {
467 errx(1, "volume %d %s is too small to hold the volume header",
468 vol->vol_no, vol->name);
472 * Our A-lists have been initialized but are marked all-allocated.
473 * Calculate the actual number of clusters in the volume and free
474 * them to get the filesystem ready for work. The clusters will
475 * be initialized on-demand.
477 * If using super-clusters we must still calculate nclusters but
478 * we only need to initialize superclusters that are not going
479 * to wind up in the all-free state, which will only be the last
480 * supercluster. hammer_alist_free() will recurse into the
481 * supercluster infrastructure and create the necessary superclusters.
483 * NOTE: The nclusters calculation ensures that the volume EOF does
484 * not occur in the middle of a supercluster buffer array.
486 if (UsingSuperClusters) {
488 * Figure out how many full super-cluster groups we will have.
489 * This calculation does not include the partial supercluster
490 * group at the end.
492 scl_header_size = (int64_t)HAMMER_BUFSIZE *
493 HAMMER_VOL_SUPERCLUSTER_GROUP;
494 scl_group_size = scl_header_size +
495 (int64_t)HAMMER_VOL_SUPERCLUSTER_GROUP *
496 ClusterSize * HAMMER_SCL_MAXCLUSTERS;
497 nscl_groups = (ondisk->vol_clo_end - ondisk->vol_clo_beg) /
498 scl_group_size;
499 nclusters = nscl_groups * HAMMER_SCL_MAXCLUSTERS *
500 HAMMER_VOL_SUPERCLUSTER_GROUP;
503 * Figure out how much space we have left and calculate the
504 * remaining number of clusters.
506 n64 = (ondisk->vol_clo_end - ondisk->vol_clo_beg) -
507 (nscl_groups * scl_group_size);
508 if (n64 > scl_header_size) {
509 nclusters += (n64 + minclsize) / ClusterSize;
511 printf("%d clusters, %d full super-cluster groups\n",
512 nclusters, nscl_groups);
513 hammer_alist_free(&vol->clu_alist, 0, nclusters);
514 } else {
515 nclusters = (ondisk->vol_clo_end - ondisk->vol_clo_beg +
516 minclsize) / ClusterSize;
517 if (nclusters > HAMMER_VOL_MAXCLUSTERS) {
518 errx(1, "Volume is too large, max %s\n",
519 sizetostr(nclusters * ClusterSize));
521 hammer_alist_free(&vol->clu_alist, 0, nclusters);
523 ondisk->vol_nclusters = nclusters;
524 ondisk->vol_nblocks = nclusters * ClusterSize / HAMMER_BUFSIZE -
525 nclusters;
526 ondisk->vol_blocksize = HAMMER_BUFSIZE;
529 * Place the root cluster in volume 0.
531 ondisk->vol_rootvol = 0;
532 if (ondisk->vol_no == ondisk->vol_rootvol) {
533 ondisk->vol0_root_clu_id = format_cluster(vol, 1);
534 ondisk->vol0_recid = 1;
535 /* global next TID */
536 ondisk->vol0_nexttid = createtid();
541 * Format a hammer cluster. Returns byte offset in volume of cluster.
543 static
544 int32_t
545 format_cluster(struct volume_info *vol, int isroot)
547 hammer_tid_t clu_id = createtid();
548 struct cluster_info *cluster;
549 struct hammer_cluster_ondisk *ondisk;
550 int nbuffers;
551 int clno;
554 * Allocate a cluster
556 clno = hammer_alist_alloc(&vol->clu_alist, 1);
557 if (clno == HAMMER_ALIST_BLOCK_NONE) {
558 fprintf(stderr, "volume %d %s has insufficient space\n",
559 vol->vol_no, vol->name);
560 exit(1);
562 cluster = get_cluster(vol, clno);
563 printf("allocate cluster id=%016llx %d@%08llx\n",
564 clu_id, clno, cluster->clu_offset);
566 ondisk = cluster->ondisk;
568 ondisk->vol_fsid = vol->ondisk->vol_fsid;
569 ondisk->vol_fstype = vol->ondisk->vol_fstype;
570 ondisk->clu_gen = 1;
571 ondisk->clu_id = clu_id;
572 ondisk->clu_no = clno;
573 ondisk->clu_flags = 0;
574 ondisk->clu_start = HAMMER_BUFSIZE;
575 if (vol->size - cluster->clu_offset > ClusterSize)
576 ondisk->clu_limit = (u_int32_t)ClusterSize;
577 else
578 ondisk->clu_limit = (u_int32_t)(vol->size - cluster->clu_offset);
581 * In-band filesystem buffer management A-List. The first filesystem
582 * buffer is the cluster header itself.
584 nbuffers = ondisk->clu_limit / HAMMER_BUFSIZE;
585 hammer_alist_free(&cluster->alist_master, 1, nbuffers - 1);
586 printf("cluster %d has %d buffers\n", cluster->clu_no, nbuffers);
589 * Buffer Iterators in elements. Each buffer has 256 elements.
590 * The data and B-Tree indices are forward allocations while the
591 * record index allocates backwards.
593 ondisk->idx_data = 1 * HAMMER_FSBUF_MAXBLKS;
594 ondisk->idx_index = 0 * HAMMER_FSBUF_MAXBLKS;
595 ondisk->idx_record = nbuffers * HAMMER_FSBUF_MAXBLKS;
598 * Iterator for whole-buffer data allocations. The iterator is
599 * the buf_no.
601 ondisk->idx_ldata = 1;
604 * Initialize root cluster's parent cluster info. -1's
605 * indicate we are the root cluster and no parent exists.
607 ondisk->clu_btree_parent_vol_no = -1;
608 ondisk->clu_btree_parent_clu_no = -1;
609 ondisk->clu_btree_parent_offset = -1;
610 ondisk->clu_btree_parent_clu_gen = -1;
613 * Cluster 0 is the root cluster. Set the B-Tree range for this
614 * cluster to the entire key space and format the root directory.
616 * Note that delete_tid for the ending range must be set to 0,
617 * 0 indicates 'not deleted', aka 'the most recent'. See
618 * hammer_btree_cmp() in sys/vfs/hammer/hammer_btree.c.
620 * The root cluster's key space represents the entire key space for
621 * the filesystem. The btree_end element appears to be inclusive
622 * only because we can't overflow our variables. It's actually
623 * non-inclusive... that is, it is a right-side boundary element.
625 if (isroot) {
626 ondisk->clu_btree_beg.obj_id = -0x8000000000000000LL;
627 ondisk->clu_btree_beg.key = -0x8000000000000000LL;
628 ondisk->clu_btree_beg.create_tid = 0;
629 ondisk->clu_btree_beg.delete_tid = 0;
630 ondisk->clu_btree_beg.rec_type = 0;
631 ondisk->clu_btree_beg.obj_type = 0;
633 ondisk->clu_btree_end.obj_id = 0x7FFFFFFFFFFFFFFFLL;
634 ondisk->clu_btree_end.key = 0x7FFFFFFFFFFFFFFFLL;
635 ondisk->clu_btree_end.create_tid = 0xFFFFFFFFFFFFFFFFULL;
636 ondisk->clu_btree_end.delete_tid = 0; /* special case */
637 ondisk->clu_btree_end.rec_type = 0xFFFFU;
638 ondisk->clu_btree_end.obj_type = 0;
640 format_root(cluster);
644 * Write-out and update the index, record, and cluster buffers
646 return(clno);
650 * Format the root directory.
652 static
653 void
654 format_root(struct cluster_info *cluster)
656 int32_t btree_off;
657 int32_t rec_off;
658 int32_t data_off;
659 hammer_node_ondisk_t bnode;
660 union hammer_record_ondisk *rec;
661 struct hammer_inode_data *idata;
662 hammer_btree_elm_t elm;
664 bnode = alloc_btree_element(cluster, &btree_off);
665 rec = alloc_record_element(cluster, &rec_off);
666 idata = alloc_data_element(cluster, sizeof(*idata), &data_off);
669 * Populate the inode data and inode record for the root directory.
671 idata->version = HAMMER_INODE_DATA_VERSION;
672 idata->mode = 0755;
674 rec->base.base.obj_id = 1;
675 rec->base.base.key = 0;
676 rec->base.base.create_tid = createtid();
677 rec->base.base.delete_tid = 0;
678 rec->base.base.rec_type = HAMMER_RECTYPE_INODE;
679 rec->base.base.obj_type = HAMMER_OBJTYPE_DIRECTORY;
680 rec->base.data_offset = data_off;
681 rec->base.data_len = sizeof(*idata);
682 rec->base.data_crc = crc32(idata, sizeof(*idata));
683 rec->inode.ino_atime = rec->base.base.create_tid;
684 rec->inode.ino_mtime = rec->base.base.create_tid;
685 rec->inode.ino_size = 0;
686 rec->inode.ino_nlinks = 1;
688 ++cluster->volume->ondisk->vol0_stat_inodes;
691 * Assign the cluster's root B-Tree node.
693 assert(cluster->ondisk->clu_btree_root == 0);
694 cluster->ondisk->clu_btree_root = btree_off;
697 * Create the root of the B-Tree. The root is a leaf node so we
698 * do not have to worry about boundary elements.
700 bnode->count = 1;
701 bnode->type = HAMMER_BTREE_TYPE_LEAF;
703 elm = &bnode->elms[0];
704 elm->base = rec->base.base;
705 elm->leaf.rec_offset = rec_off;
706 elm->leaf.data_offset = rec->base.data_offset;
707 elm->leaf.data_len = rec->base.data_len;
708 elm->leaf.data_crc = rec->base.data_crc;
711 void
712 panic(const char *ctl, ...)
714 va_list va;
716 va_start(va, ctl);
717 vfprintf(stderr, ctl, va);
718 va_end(va);
719 fprintf(stderr, "\n");
720 exit(1);