Initialize idx_ldata - a forward iterator for allocating large (16K) data
[dragonfly.git] / sbin / newfs_hammer / newfs_hammer.c
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  * 
34  * $DragonFly: src/sbin/newfs_hammer/newfs_hammer.c,v 1.8 2007/11/26 21:39:09 dillon Exp $
35  */
36
37 #include "newfs_hammer.h"
38
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);
46
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;
61
62 int
63 main(int ac, char **av)
64 {
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;
71
72         /*
73          * Sanity check basic filesystem structures.  No cookies for us
74          * if it gets broken!
75          */
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);
84
85         /*
86          * Generate a filesysem id and lookup the filesystem type
87          */
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");
93         }
94
95         /*
96          * Initialize the alist templates we will be using
97          */
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,
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, HAMMER_CLU_MAXBUFFERS,
111                               HAMMER_FSBUF_MAXBLKS, HAMMER_CLU_SLAVE_METAELMS);
112         hammer_buffer_alist_template(&Clu_slave_alist_config);
113
114         /*
115          * Parse arguments
116          */
117         while ((ch = getopt(ac, av, "L:b:c:m:S")) != -1) {
118                 switch(ch) {
119                 case 'L':
120                         label = optarg;
121                         break;
122                 case 'b':
123                         BootAreaSize = getsize(optarg,
124                                          HAMMER_BUFSIZE,
125                                          HAMMER_BOOT_MAXBYTES, 2);
126                         break;
127                 case 'c':
128                         ClusterSize = getsize(optarg, 
129                                          HAMMER_BUFSIZE * 256LL,
130                                          HAMMER_CLU_MAXBYTES, 1);
131                         break;
132                 case 'm':
133                         MemAreaSize = getsize(optarg,
134                                          HAMMER_BUFSIZE,
135                                          HAMMER_MEM_MAXBYTES, 2);
136                         break;
137                 case 'S':
138                         /*
139                          * Force the use of super-clusters
140                          */
141                         UsingSuperClusters = 1;
142                         break;
143                 default:
144                         usage();
145                         break;
146                 }
147         }
148
149         if (label == NULL) {
150                 fprintf(stderr,
151                         "newfs_hammer: A filesystem label must be specified\n");
152                 exit(1);
153         }
154
155         /*
156          * Collect volume information
157          */
158         ac -= optind;
159         av += optind;
160         NumVolumes = ac;
161
162         total = 0;
163         for (i = 0; i < NumVolumes; ++i) {
164                 struct volume_info *vol;
165
166                 vol = calloc(1, sizeof(struct volume_info));
167                 vol->fd = -1;
168                 vol->vol_no = i;
169                 vol->name = av[i];
170                 vol->next = VolBase;
171                 VolBase = vol;
172
173                 /*
174                  * Load up information on the volume and initialize
175                  * its remaining fields.
176                  */
177                 check_volume(vol);
178                 total += vol->size;
179         }
180
181         /*
182          * Calculate the size of a cluster.  A cluster is broken
183          * down into 256 chunks which must be at least filesystem buffer
184          * sized.  This gives us a minimum chunk size of around 4MB.
185          */
186         if (ClusterSize == 0) {
187                 ClusterSize = HAMMER_BUFSIZE * 256;
188                 while (ClusterSize < total / NumVolumes / 256 &&
189                        ClusterSize < HAMMER_CLU_MAXBYTES) {
190                         ClusterSize <<= 1;
191                 }
192         }
193
194         /*
195          * Calculate defaults for the boot and memory area sizes.
196          */
197         if (BootAreaSize == 0) {
198                 BootAreaSize = HAMMER_BOOT_NOMBYTES;
199                 while (BootAreaSize > total / NumVolumes / 256)
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;
208                 while (MemAreaSize > total / NumVolumes / 256)
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
216         printf("---------------------------------------------\n");
217         printf("%d volume%s total size %s\n",
218                 NumVolumes, (NumVolumes == 1 ? "" : "s"), sizetostr(total));
219         printf("cluster-size:        %s\n", sizetostr(ClusterSize));
220
221         if (UsingSuperClusters) {
222                 max_volume_size = (int64_t)HAMMER_VOL_MAXSUPERCLUSTERS * \
223                                   HAMMER_SCL_MAXCLUSTERS * ClusterSize;
224         } else {
225                 max_volume_size = HAMMER_VOL_MAXCLUSTERS * ClusterSize;
226         }
227         printf("max-volume-size:     %s\n", sizetostr(max_volume_size));
228
229         printf("max-filesystem-size: %s\n",
230                (max_volume_size * 32768LL < max_volume_size) ?
231                "Unlimited" :
232                sizetostr(max_volume_size * 32768LL));
233         printf("boot-area-size:      %s\n", sizetostr(BootAreaSize));
234         printf("memory-log-size:     %s\n", sizetostr(MemAreaSize));
235         printf("\n");
236
237         /*
238          * Format the volumes.
239          */
240         for (i = 0; i < NumVolumes; ++i) {
241                 format_volume(get_volume(i), NumVolumes, label);
242         }
243         flush_all_volumes();
244         return(0);
245 }
246
247 static
248 void
249 usage(void)
250 {
251         fprintf(stderr, "newfs_hammer vol0 [vol1 ...]\n");
252         exit(1);
253 }
254
255 /*
256  * Convert the size in bytes to a human readable string.
257  */
258 static const char *
259 sizetostr(off_t size)
260 {
261         static char buf[32];
262
263         if (size < 1024 / 2) {
264                 snprintf(buf, sizeof(buf), "%6.2f", (double)size);
265         } else if (size < 1024 * 1024 / 2) {
266                 snprintf(buf, sizeof(buf), "%6.2fKB",
267                         (double)size / 1024);
268         } else if (size < 1024 * 1024 * 1024LL / 2) {
269                 snprintf(buf, sizeof(buf), "%6.2fMB",
270                         (double)size / (1024 * 1024));
271         } else if (size < 1024 * 1024 * 1024LL * 1024LL / 2) {
272                 snprintf(buf, sizeof(buf), "%6.2fGB",
273                         (double)size / (1024 * 1024 * 1024LL));
274         } else {
275                 snprintf(buf, sizeof(buf), "%6.2fTB",
276                         (double)size / (1024 * 1024 * 1024LL * 1024LL));
277         }
278         return(buf);
279 }
280
281 /*
282  * Convert a string to a 64 bit signed integer with various requirements.
283  */
284 static int64_t
285 getsize(const char *str, int64_t minval, int64_t maxval, int powerof2)
286 {
287         int64_t val;
288         char *ptr;
289
290         val = strtoll(str, &ptr, 0);
291         switch(*ptr) {
292         case 't':
293         case 'T':
294                 val *= 1024;
295                 /* fall through */
296         case 'g':
297         case 'G':
298                 val *= 1024;
299                 /* fall through */
300         case 'm':
301         case 'M':
302                 val *= 1024;
303                 /* fall through */
304         case 'k':
305         case 'K':
306                 val *= 1024;
307                 break;
308         default:
309                 errx(1, "Unknown suffix in number '%s'\n", str);
310                 /* not reached */
311         }
312         if (ptr[1]) {
313                 errx(1, "Unknown suffix in number '%s'\n", str);
314                 /* not reached */
315         }
316         if (val < minval) {
317                 errx(1, "Value too small: %s, min is %s\n",
318                      str, sizetostr(minval));
319                 /* not reached */
320         }
321         if (val > maxval) {
322                 errx(1, "Value too large: %s, max is %s\n",
323                      str, sizetostr(maxval));
324                 /* not reached */
325         }
326         if ((powerof2 & 1) && (val ^ (val - 1)) != ((val << 1) - 1)) {
327                 errx(1, "Value not power of 2: %s\n", str);
328                 /* not reached */
329         }
330         if ((powerof2 & 2) && (val & HAMMER_BUFMASK)) {
331                 errx(1, "Value not an integral multiple of %dK: %s", 
332                      HAMMER_BUFSIZE / 1024, str);
333                 /* not reached */
334         }
335         return(val);
336 }
337
338 /*
339  * Generate a transaction id
340  */
341 static hammer_tid_t
342 createtid(void)
343 {
344         static hammer_tid_t lasttid;
345         struct timeval tv;
346
347         if (lasttid == 0) {
348                 gettimeofday(&tv, NULL);
349                 lasttid = tv.tv_sec * 1000000000LL +
350                           tv.tv_usec * 1000LL;
351         }
352         return(lasttid++);
353 }
354
355 /*
356  * Check basic volume characteristics.  HAMMER filesystems use a minimum
357  * of a 16KB filesystem buffer size.
358  */
359 static
360 void
361 check_volume(struct volume_info *vol)
362 {
363         struct partinfo pinfo;
364         struct stat st;
365
366         /*
367          * Get basic information about the volume
368          */
369         vol->fd = open(vol->name, O_RDWR);
370         if (vol->fd < 0)
371                 err(1, "Unable to open %s R+W", vol->name);
372         if (ioctl(vol->fd, DIOCGPART, &pinfo) < 0) {
373                 /*
374                  * Allow the formatting of regular filews as HAMMER volumes
375                  */
376                 if (fstat(vol->fd, &st) < 0)
377                         err(1, "Unable to stat %s", vol->name);
378                 vol->size = st.st_size;
379                 vol->type = "REGFILE";
380         } else {
381                 /*
382                  * When formatting a block device as a HAMMER volume the
383                  * sector size must be compatible.  HAMMER uses 16384 byte
384                  * filesystem buffers.
385                  */
386                 if (pinfo.reserved_blocks) {
387                         errx(1, "HAMMER cannot be placed in a partition "
388                                 "which overlaps the disklabel or MBR");
389                 }
390                 if (pinfo.media_blksize > 16384 ||
391                     16384 % pinfo.media_blksize) {
392                         errx(1, "A media sector size of %d is not supported",
393                              pinfo.media_blksize);
394                 }
395
396                 vol->size = pinfo.media_size;
397                 vol->type = "DEVICE";
398         }
399         printf("Volume %d %s %-15s size %s\n",
400                vol->vol_no, vol->type, vol->name,
401                sizetostr(vol->size));
402
403         /*
404          * Strictly speaking we do not need to enable super clusters unless
405          * we have volumes > 2TB, but turning them on doesn't really hurt
406          * and if we don't the user may get confused if he tries to expand
407          * the size of an existing volume.
408          */
409         if (vol->size > 200LL * 1024 * 1024 * 1024 && !UsingSuperClusters) {
410                 UsingSuperClusters = 1;
411                 printf("Enabling super-clusters\n");
412         }
413
414         /*
415          * Reserve space for (future) header junk
416          */
417         vol->vol_alloc = HAMMER_BUFSIZE * 16;
418 }
419
420 /*
421  * Format a HAMMER volume.  Cluster 0 will be initially placed in volume 0.
422  */
423 static
424 void
425 format_volume(struct volume_info *vol, int nvols, const char *label)
426 {
427         struct hammer_volume_ondisk *ondisk;
428         int32_t nclusters;
429         int32_t minclsize;
430         int32_t nscl_groups;
431         int64_t scl_group_size;
432         int64_t scl_header_size;
433         int64_t n64;
434
435         /*
436          * The last cluster in a volume may wind up truncated.  It must be
437          * at least minclsize to really be workable as a cluster.
438          */
439         minclsize = (int32_t)(ClusterSize / 4);
440         if (minclsize < HAMMER_BUFSIZE * 64)
441                 minclsize = HAMMER_BUFSIZE * 64;
442
443         /*
444          * Initialize basic information in the on-disk volume structure.
445          */
446         ondisk = vol->ondisk;
447
448         ondisk->vol_fsid = Hammer_FSId;
449         ondisk->vol_fstype = Hammer_FSType;
450         snprintf(ondisk->vol_name, sizeof(ondisk->vol_name), "%s", label);
451         ondisk->vol_no = vol->vol_no;
452         ondisk->vol_count = nvols;
453         ondisk->vol_version = 1;
454         ondisk->vol_clsize = (int32_t)ClusterSize;
455         if (UsingSuperClusters)
456                 ondisk->vol_flags = HAMMER_VOLF_USINGSUPERCL;
457
458         ondisk->vol_bot_beg = vol->vol_alloc;
459         vol->vol_alloc += BootAreaSize;
460         ondisk->vol_mem_beg = vol->vol_alloc;
461         vol->vol_alloc += MemAreaSize;
462         ondisk->vol_clo_beg = vol->vol_alloc;
463         ondisk->vol_clo_end = vol->size;
464
465         if (ondisk->vol_clo_end < ondisk->vol_clo_beg) {
466                 errx(1, "volume %d %s is too small to hold the volume header",
467                      vol->vol_no, vol->name);
468         }
469
470         /*
471          * Our A-lists have been initialized but are marked all-allocated.
472          * Calculate the actual number of clusters in the volume and free
473          * them to get the filesystem ready for work.  The clusters will
474          * be initialized on-demand.
475          *
476          * If using super-clusters we must still calculate nclusters but
477          * we only need to initialize superclusters that are not going
478          * to wind up in the all-free state, which will only be the last
479          * supercluster.  hammer_alist_free() will recurse into the
480          * supercluster infrastructure and create the necessary superclusters.
481          *
482          * NOTE: The nclusters calculation ensures that the volume EOF does
483          * not occur in the middle of a supercluster buffer array.
484          */
485         if (UsingSuperClusters) {
486                 /*
487                  * Figure out how many full super-cluster groups we will have.
488                  * This calculation does not include the partial supercluster
489                  * group at the end.
490                  */
491                 scl_header_size = (int64_t)HAMMER_BUFSIZE *
492                                   HAMMER_VOL_SUPERCLUSTER_GROUP;
493                 scl_group_size = scl_header_size +
494                                  (int64_t)HAMMER_VOL_SUPERCLUSTER_GROUP *
495                                  ClusterSize * HAMMER_SCL_MAXCLUSTERS;
496                 nscl_groups = (ondisk->vol_clo_end - ondisk->vol_clo_beg) /
497                                 scl_group_size;
498                 nclusters = nscl_groups * HAMMER_SCL_MAXCLUSTERS *
499                                 HAMMER_VOL_SUPERCLUSTER_GROUP;
500
501                 /*
502                  * Figure out how much space we have left and calculate the
503                  * remaining number of clusters.
504                  */
505                 n64 = (ondisk->vol_clo_end - ondisk->vol_clo_beg) -
506                         (nscl_groups * scl_group_size);
507                 if (n64 > scl_header_size) {
508                         nclusters += (n64 + minclsize) / ClusterSize;
509                 }
510                 printf("%d clusters, %d full super-cluster groups\n",
511                         nclusters, nscl_groups);
512                 hammer_alist_free(&vol->clu_alist, 0, nclusters);
513         } else {
514                 nclusters = (ondisk->vol_clo_end - ondisk->vol_clo_beg +
515                              minclsize) / ClusterSize;
516                 if (nclusters > HAMMER_VOL_MAXCLUSTERS) {
517                         errx(1, "Volume is too large, max %s\n",
518                              sizetostr(nclusters * ClusterSize));
519                 }
520                 hammer_alist_free(&vol->clu_alist, 0, nclusters);
521         }
522         ondisk->vol_nclusters = nclusters;
523
524         /*
525          * Place the root cluster in volume 0.
526          */
527         ondisk->vol_rootvol = 0;
528         if (ondisk->vol_no == ondisk->vol_rootvol) {
529                 ondisk->vol0_root_clu_id = format_cluster(vol, 1);
530                 ondisk->vol0_recid = 1;
531                 /* global next TID */
532                 ondisk->vol0_nexttid = createtid();
533         }
534 }
535
536 /*
537  * Format a hammer cluster.  Returns byte offset in volume of cluster.
538  */
539 static
540 int32_t
541 format_cluster(struct volume_info *vol, int isroot)
542 {
543         hammer_tid_t clu_id = createtid();
544         struct cluster_info *cluster;
545         struct hammer_cluster_ondisk *ondisk;
546         int nbuffers;
547         int clno;
548
549         /*
550          * Allocate a cluster
551          */
552         clno = hammer_alist_alloc(&vol->clu_alist, 1);
553         if (clno == HAMMER_ALIST_BLOCK_NONE) {
554                 fprintf(stderr, "volume %d %s has insufficient space\n",
555                         vol->vol_no, vol->name);
556                 exit(1);
557         }
558         cluster = get_cluster(vol, clno);
559         printf("allocate cluster id=%016llx %d@%08llx\n",
560                clu_id, clno, cluster->clu_offset);
561
562         ondisk = cluster->ondisk;
563
564         ondisk->vol_fsid = vol->ondisk->vol_fsid;
565         ondisk->vol_fstype = vol->ondisk->vol_fstype;
566         ondisk->clu_gen = 1;
567         ondisk->clu_id = clu_id;
568         ondisk->clu_no = clno;
569         ondisk->clu_flags = 0;
570         ondisk->clu_start = HAMMER_BUFSIZE;
571         if (vol->size - cluster->clu_offset > ClusterSize)
572                 ondisk->clu_limit = (u_int32_t)ClusterSize;
573         else
574                 ondisk->clu_limit = (u_int32_t)(vol->size - cluster->clu_offset);
575
576         /*
577          * In-band filesystem buffer management A-List.  The first filesystem
578          * buffer is the cluster header itself.
579          */
580         nbuffers = ondisk->clu_limit / HAMMER_BUFSIZE;
581         hammer_alist_free(&cluster->alist_master, 1, nbuffers - 1);
582         printf("cluster %d has %d buffers\n", cluster->clu_no, nbuffers);
583
584         /*
585          * Buffer Iterators in elements.  Each buffer has 256 elements.
586          * The data and B-Tree indices are forward allocations while the
587          * record index allocates backwards.
588          */
589         ondisk->idx_data = 1 * HAMMER_FSBUF_MAXBLKS;
590         ondisk->idx_index = 0 * HAMMER_FSBUF_MAXBLKS;
591         ondisk->idx_record = nbuffers * HAMMER_FSBUF_MAXBLKS;
592
593         /*
594          * Iterator for whole-buffer data allocations. The iterator is
595          * the buf_no.
596          */
597         ondisk->idx_ldata = 1;
598
599         /*
600          * Initialize root cluster's parent cluster info.  -1's
601          * indicate we are the root cluster and no parent exists.
602          */
603         ondisk->clu_btree_parent_vol_no = -1;
604         ondisk->clu_btree_parent_clu_no = -1;
605         ondisk->clu_btree_parent_offset = -1;
606         ondisk->clu_btree_parent_clu_gen = -1;
607
608         /*
609          * Cluster 0 is the root cluster.  Set the B-Tree range for this
610          * cluster to the entire key space and format the root directory. 
611          *
612          * Note that delete_tid for the ending range must be set to 0,
613          * 0 indicates 'not deleted', aka 'the most recent'.  See
614          * hammer_btree_cmp() in sys/vfs/hammer/hammer_btree.c.
615          *
616          * The root cluster's key space represents the entire key space for
617          * the filesystem.  The btree_end element appears to be inclusive
618          * only because we can't overflow our variables.  It's actually
619          * non-inclusive... that is, it is a right-side boundary element.
620          */
621         if (isroot) {
622                 ondisk->clu_btree_beg.obj_id = -0x8000000000000000LL;
623                 ondisk->clu_btree_beg.key = -0x8000000000000000LL;
624                 ondisk->clu_btree_beg.create_tid = 0;
625                 ondisk->clu_btree_beg.delete_tid = 0;
626                 ondisk->clu_btree_beg.rec_type = 0;
627                 ondisk->clu_btree_beg.obj_type = 0;
628
629                 ondisk->clu_btree_end.obj_id = 0x7FFFFFFFFFFFFFFFLL;
630                 ondisk->clu_btree_end.key = 0x7FFFFFFFFFFFFFFFLL;
631                 ondisk->clu_btree_end.create_tid = 0xFFFFFFFFFFFFFFFFULL;
632                 ondisk->clu_btree_end.delete_tid = 0;   /* special case */
633                 ondisk->clu_btree_end.rec_type = 0xFFFFU;
634                 ondisk->clu_btree_end.obj_type = 0;
635
636                 format_root(cluster);
637         }
638
639         /*
640          * Write-out and update the index, record, and cluster buffers
641          */
642         return(clno);
643 }
644
645 /*
646  * Format the root directory.
647  */
648 static
649 void
650 format_root(struct cluster_info *cluster)
651 {
652         int32_t btree_off;
653         int32_t rec_off;
654         int32_t data_off;
655         hammer_node_ondisk_t bnode;
656         union hammer_record_ondisk *rec;
657         struct hammer_inode_data *idata;
658         hammer_btree_elm_t elm;
659
660         bnode = alloc_btree_element(cluster, &btree_off);
661         rec = alloc_record_element(cluster, &rec_off);
662         idata = alloc_data_element(cluster, sizeof(*idata), &data_off);
663
664         /*
665          * Populate the inode data and inode record for the root directory.
666          */
667         idata->version = HAMMER_INODE_DATA_VERSION;
668         idata->mode = 0755;
669
670         rec->base.base.obj_id = 1;
671         rec->base.base.key = 0;
672         rec->base.base.create_tid = createtid();
673         rec->base.base.delete_tid = 0;
674         rec->base.base.rec_type = HAMMER_RECTYPE_INODE;
675         rec->base.base.obj_type = HAMMER_OBJTYPE_DIRECTORY;
676         rec->base.data_offset = data_off;
677         rec->base.data_len = sizeof(*idata);
678         rec->base.data_crc = crc32(idata, sizeof(*idata));
679         rec->inode.ino_atime  = rec->base.base.create_tid;
680         rec->inode.ino_mtime  = rec->base.base.create_tid;
681         rec->inode.ino_size   = 0;
682         rec->inode.ino_nlinks = 1;
683
684         /*
685          * Assign the cluster's root B-Tree node.
686          */
687         assert(cluster->ondisk->clu_btree_root == 0);
688         cluster->ondisk->clu_btree_root = btree_off;
689
690         /*
691          * Create the root of the B-Tree.  The root is a leaf node so we
692          * do not have to worry about boundary elements.
693          */
694         bnode->count = 1;
695         bnode->type = HAMMER_BTREE_TYPE_LEAF;
696
697         elm = &bnode->elms[0];
698         elm->base = rec->base.base;
699         elm->leaf.rec_offset = rec_off;
700         elm->leaf.data_offset = rec->base.data_offset;
701         elm->leaf.data_len = rec->base.data_len;
702         elm->leaf.data_crc = rec->base.data_crc;
703 }
704
705 void
706 panic(const char *ctl, ...)
707 {
708         va_list va;
709
710         va_start(va, ctl);
711         vfprintf(stderr, ctl, va);
712         va_end(va);
713         fprintf(stderr, "\n");
714         exit(1);
715 }
716