hammer2 - Add peer_type field to LNK_CONN and LNK_SPAN
[dragonfly.git] / sbin / newfs_hammer2 / newfs_hammer2.c
1 /*
2  * Copyright (c) 2011-2012 The DragonFly Project.  All rights reserved.
3  *
4  * This code is derived from software contributed to The DragonFly Project
5  * by Matthew Dillon <dillon@dragonflybsd.org>
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
35 #include <sys/types.h>
36 #include <sys/diskslice.h>
37 #include <sys/diskmbr.h>
38 #include <sys/stat.h>
39 #include <sys/time.h>
40 #include <sys/sysctl.h>
41 #include <vfs/hammer2/hammer2_disk.h>
42
43 #include <stdio.h>
44 #include <stdlib.h>
45 #include <stdarg.h>
46 #include <stddef.h>
47 #include <unistd.h>
48 #include <string.h>
49 #include <errno.h>
50 #include <fcntl.h>
51 #include <assert.h>
52 #include <err.h>
53 #include <uuid.h>
54
55 static hammer2_off_t check_volume(const char *path, int *fdp);
56 static int64_t getsize(const char *str, int64_t minval, int64_t maxval, int pw);
57 static const char *sizetostr(hammer2_off_t size);
58 static uint64_t nowtime(void);
59 static void usage(void);
60
61 static void format_hammer2(int fd, hammer2_off_t total_space,
62                                 hammer2_off_t free_space);
63 static void alloc_direct(hammer2_off_t *basep, hammer2_blockref_t *bref,
64                                 size_t bytes);
65 static hammer2_key_t dirhash(const unsigned char *name, size_t len);
66
67 static int Hammer2Version = -1;
68 static int ForceOpt = 0;
69 static uuid_t Hammer2_FSType;   /* static filesystem type id for HAMMER2 */
70 static uuid_t Hammer2_FSId;     /* unique filesystem id in volu header */
71 static uuid_t Hammer2_SPFSId;   /* PFS id in super-root inode */
72 static uuid_t Hammer2_RPFSId;   /* PFS id in root inode */
73 static const char *Label = "ROOT";
74 static hammer2_off_t BootAreaSize;
75 static hammer2_off_t AuxAreaSize;
76
77 #define GIG     ((hammer2_off_t)1024*1024*1024)
78
79 int
80 main(int ac, char **av)
81 {
82         uint32_t status;
83         hammer2_off_t total_space;
84         hammer2_off_t free_space;
85         hammer2_off_t reserved_space;
86         int ch;
87         int fd = -1;
88         char *fsidstr;
89         char *spfsidstr;
90         char *rpfsidstr;
91
92         /*
93          * Sanity check basic filesystem structures.  No cookies for us
94          * if it gets broken!
95          */
96         assert(sizeof(hammer2_volume_data_t) == HAMMER2_VOLUME_BYTES);
97         assert(sizeof(hammer2_inode_data_t) == HAMMER2_INODE_BYTES);
98         assert(sizeof(hammer2_blockref_t) == HAMMER2_BLOCKREF_BYTES);
99
100         /*
101          * Generate a filesystem id and lookup the filesystem type
102          */
103         srandomdev();
104         uuidgen(&Hammer2_FSId, 1);
105         uuidgen(&Hammer2_SPFSId, 1);
106         uuidgen(&Hammer2_RPFSId, 1);
107         uuid_from_string(HAMMER2_UUID_STRING, &Hammer2_FSType, &status);
108         /*uuid_name_lookup(&Hammer2_FSType, "DragonFly HAMMER2", &status);*/
109         if (status != uuid_s_ok) {
110                 errx(1, "uuids file does not have the DragonFly "
111                         "HAMMER filesystem type");
112         }
113
114         /*
115          * Parse arguments
116          */
117         while ((ch = getopt(ac, av, "fL:b:m:r:V:")) != -1) {
118                 switch(ch) {
119                 case 'f':
120                         ForceOpt = 1;
121                         break;
122                 case 'L':
123                         Label = optarg;
124                         if (strlen(Label) > HAMMER2_INODE_MAXNAME) {
125                                 errx(1, "Root directory label too long "
126                                         "(64 chars max)\n");
127                         }
128                         break;
129                 case 'b':
130                         BootAreaSize = getsize(optarg,
131                                          HAMMER2_NEWFS_ALIGN,
132                                          HAMMER2_BOOT_MAX_BYTES, 2);
133                         break;
134                 case 'r':
135                         AuxAreaSize = getsize(optarg,
136                                          HAMMER2_NEWFS_ALIGN,
137                                          HAMMER2_REDO_MAX_BYTES, 2);
138                         break;
139                 case 'V':
140                         Hammer2Version = strtol(optarg, NULL, 0);
141                         if (Hammer2Version < HAMMER2_VOL_VERSION_MIN ||
142                             Hammer2Version >= HAMMER2_VOL_VERSION_WIP) {
143                                 errx(1,
144                                      "I don't understand how to format "
145                                      "HAMMER2 version %d\n",
146                                      Hammer2Version);
147                         }
148                         break;
149                 default:
150                         usage();
151                         break;
152                 }
153         }
154
155         if (Hammer2Version < 0) {
156                 size_t olen = sizeof(Hammer2Version);
157                 Hammer2Version = HAMMER2_VOL_VERSION_DEFAULT;
158                 if (sysctlbyname("vfs.hammer2.supported_version",
159                                  &Hammer2Version, &olen, NULL, 0) == 0) {
160                         if (Hammer2Version >= HAMMER2_VOL_VERSION_WIP) {
161                                 Hammer2Version = HAMMER2_VOL_VERSION_WIP - 1;
162                                 fprintf(stderr,
163                                         "newfs_hammer: WARNING: HAMMER2 VFS "
164                                         "supports higher version than I "
165                                         "understand,\n"
166                                         "using version %d\n",
167                                         Hammer2Version);
168                         }
169                 } else {
170                         fprintf(stderr,
171                                 "newfs_hammer: WARNING: HAMMER2 VFS not "
172                                 "loaded, cannot get version info.\n"
173                                 "Using version %d\n",
174                                 HAMMER2_VOL_VERSION_DEFAULT);
175                 }
176         }
177
178         /*
179          * Collect volume information.
180          */
181         ac -= optind;
182         av += optind;
183
184         if (ac != 1) {
185                 fprintf(stderr, "Exactly one disk device must be specified\n");
186                 exit(1);
187         }
188         total_space = check_volume(av[0], &fd);
189
190         /*
191          * ~typically 8MB alignment to avoid edge cases for reserved blocks
192          * and so raid stripes (if any) operate efficiently.
193          */
194         total_space &= ~HAMMER2_VOLUME_ALIGNMASK64;
195
196         /*
197          * Calculate defaults for the boot area size and round to the
198          * volume alignment boundary.
199          */
200         if (BootAreaSize == 0) {
201                 BootAreaSize = HAMMER2_BOOT_NOM_BYTES;
202                 while (BootAreaSize > total_space / 20)
203                         BootAreaSize >>= 1;
204                 if (BootAreaSize < HAMMER2_BOOT_MIN_BYTES)
205                         BootAreaSize = HAMMER2_BOOT_MIN_BYTES;
206         } else if (BootAreaSize < HAMMER2_BOOT_MIN_BYTES) {
207                 BootAreaSize = HAMMER2_BOOT_MIN_BYTES;
208         }
209         BootAreaSize = (BootAreaSize + HAMMER2_VOLUME_ALIGNMASK64) &
210                        ~HAMMER2_VOLUME_ALIGNMASK64;
211
212         /*
213          * Calculate defaults for the redo area size and round to the
214          * volume alignment boundary.
215          */
216         if (AuxAreaSize == 0) {
217                 AuxAreaSize = HAMMER2_REDO_NOM_BYTES;
218                 while (AuxAreaSize > total_space / 20)
219                         AuxAreaSize >>= 1;
220                 if (AuxAreaSize < HAMMER2_REDO_MIN_BYTES)
221                         AuxAreaSize = HAMMER2_REDO_MIN_BYTES;
222         } else if (AuxAreaSize < HAMMER2_REDO_MIN_BYTES) {
223                 AuxAreaSize = HAMMER2_REDO_MIN_BYTES;
224         }
225         AuxAreaSize = (AuxAreaSize + HAMMER2_VOLUME_ALIGNMASK64) &
226                        ~HAMMER2_VOLUME_ALIGNMASK64;
227
228         /*
229          * We'll need to stuff this in the volume header soon.
230          */
231         uuid_to_string(&Hammer2_FSId, &fsidstr, &status);
232         uuid_to_string(&Hammer2_SPFSId, &spfsidstr, &status);
233         uuid_to_string(&Hammer2_RPFSId, &rpfsidstr, &status);
234
235         /*
236          * Calculate the amount of reserved space.  HAMMER2_ZONE_SEG (4MB)
237          * is reserved at the beginning of every 2GB of storage, rounded up.
238          * Thus a 200MB filesystem will still have a 4MB reserve area.
239          *
240          * We also include the boot and redo areas in the reserve.  The
241          * reserve is used to help 'df' calculate the amount of available
242          * space.
243          */
244         reserved_space = ((total_space + HAMMER2_ZONE_MASK64) /
245                           HAMMER2_ZONE_BYTES64) * HAMMER2_ZONE_SEG64;
246
247         free_space = total_space - reserved_space -
248                      BootAreaSize - AuxAreaSize;
249
250         format_hammer2(fd, total_space, free_space);
251         fsync(fd);
252         close(fd);
253
254         printf("---------------------------------------------\n");
255         printf("total-size:       %s (%jd bytes)\n",
256                sizetostr(total_space),
257                (intmax_t)total_space);
258         printf("root-label:       %s\n", Label);
259         printf("version:            %d\n", Hammer2Version);
260         printf("boot-area-size:   %s\n", sizetostr(BootAreaSize));
261         printf("aux-area-size:    %s\n", sizetostr(AuxAreaSize));
262         printf("topo-reserved:    %s\n", sizetostr(reserved_space));
263         printf("free-space:       %s\n", sizetostr(free_space));
264         printf("fsid:             %s\n", fsidstr);
265         printf("supr-pfsid:       %s\n", spfsidstr);
266         printf("root-pfsid:       %s\n", rpfsidstr);
267         printf("\n");
268
269         return(0);
270 }
271
272 static
273 void
274 usage(void)
275 {
276         fprintf(stderr,
277                 "usage: newfs_hammer -L label [-f] [-b bootsize] "
278                 "[-r redosize] [-V version] special ...\n"
279         );
280         exit(1);
281 }
282
283 /*
284  * Convert the size in bytes to a human readable string.
285  */
286 static
287 const char *
288 sizetostr(hammer2_off_t size)
289 {
290         static char buf[32];
291
292         if (size < 1024 / 2) {
293                 snprintf(buf, sizeof(buf), "%6.2f", (double)size);
294         } else if (size < 1024 * 1024 / 2) {
295                 snprintf(buf, sizeof(buf), "%6.2fKB",
296                         (double)size / 1024);
297         } else if (size < 1024 * 1024 * 1024LL / 2) {
298                 snprintf(buf, sizeof(buf), "%6.2fMB",
299                         (double)size / (1024 * 1024));
300         } else if (size < 1024 * 1024 * 1024LL * 1024LL / 2) {
301                 snprintf(buf, sizeof(buf), "%6.2fGB",
302                         (double)size / (1024 * 1024 * 1024LL));
303         } else {
304                 snprintf(buf, sizeof(buf), "%6.2fTB",
305                         (double)size / (1024 * 1024 * 1024LL * 1024LL));
306         }
307         return(buf);
308 }
309
310 /*
311  * Convert a string to a 64 bit signed integer with various requirements.
312  */
313 static int64_t
314 getsize(const char *str, int64_t minval, int64_t maxval, int powerof2)
315 {
316         int64_t val;
317         char *ptr;
318
319         val = strtoll(str, &ptr, 0);
320         switch(*ptr) {
321         case 't':
322         case 'T':
323                 val *= 1024;
324                 /* fall through */
325         case 'g':
326         case 'G':
327                 val *= 1024;
328                 /* fall through */
329         case 'm':
330         case 'M':
331                 val *= 1024;
332                 /* fall through */
333         case 'k':
334         case 'K':
335                 val *= 1024;
336                 break;
337         default:
338                 errx(1, "Unknown suffix in number '%s'\n", str);
339                 /* not reached */
340         }
341         if (ptr[1]) {
342                 errx(1, "Unknown suffix in number '%s'\n", str);
343                 /* not reached */
344         }
345         if (val < minval) {
346                 errx(1, "Value too small: %s, min is %s\n",
347                      str, sizetostr(minval));
348                 /* not reached */
349         }
350         if (val > maxval) {
351                 errx(1, "Value too large: %s, max is %s\n",
352                      str, sizetostr(maxval));
353                 /* not reached */
354         }
355         if ((powerof2 & 1) && (val ^ (val - 1)) != ((val << 1) - 1)) {
356                 errx(1, "Value not power of 2: %s\n", str);
357                 /* not reached */
358         }
359         if ((powerof2 & 2) && (val & HAMMER2_NEWFS_ALIGNMASK)) {
360                 errx(1, "Value not an integral multiple of %dK: %s",
361                      HAMMER2_NEWFS_ALIGN / 1024, str);
362                 /* not reached */
363         }
364         return(val);
365 }
366
367 static uint64_t
368 nowtime(void)
369 {
370         struct timeval tv;
371         uint64_t xtime;
372
373         gettimeofday(&tv, NULL);
374         xtime = tv.tv_sec * 1000000LL + tv.tv_usec;
375         return(xtime);
376 }
377
378 /*
379  * Figure out how big the volume is.
380  */
381 static
382 hammer2_off_t
383 check_volume(const char *path, int *fdp)
384 {
385         struct partinfo pinfo;
386         struct stat st;
387         hammer2_off_t size;
388
389         /*
390          * Get basic information about the volume
391          */
392         *fdp = open(path, O_RDWR);
393         if (*fdp < 0)
394                 err(1, "Unable to open %s R+W", path);
395         if (ioctl(*fdp, DIOCGPART, &pinfo) < 0) {
396                 /*
397                  * Allow the formatting of regular files as HAMMER2 volumes
398                  */
399                 if (fstat(*fdp, &st) < 0)
400                         err(1, "Unable to stat %s", path);
401                 size = st.st_size;
402         } else {
403                 /*
404                  * When formatting a block device as a HAMMER2 volume the
405                  * sector size must be compatible.  HAMMER2 uses 64K
406                  * filesystem buffers but logical buffers for direct I/O
407                  * can be as small as HAMMER2_LOGSIZE (16KB).
408                  */
409                 if (pinfo.reserved_blocks) {
410                         errx(1, "HAMMER cannot be placed in a partition "
411                                 "which overlaps the disklabel or MBR");
412                 }
413                 if (pinfo.media_blksize > HAMMER2_PBUFSIZE ||
414                     HAMMER2_PBUFSIZE % pinfo.media_blksize) {
415                         errx(1, "A media sector size of %d is not supported",
416                              pinfo.media_blksize);
417                 }
418                 size = pinfo.media_size;
419         }
420         printf("Volume %-15s size %s\n", path, sizetostr(size));
421         return (size);
422 }
423
424 /*
425  * Create the volume header, the super-root directory inode, and
426  * the writable snapshot subdirectory (named via the label) which
427  * is to be the initial mount point, or at least the first mount point.
428  *
429  * [----reserved_area----][boot_area][aux_area]
430  * [[vol_hdr]...         ]                      [sroot][root]
431  *
432  * The sroot and root inodes eat 512 bytes each.  newfs labels can only be
433  * 64 bytes so the root (snapshot) inode does not need to extend past 512
434  * bytes.  We use the correct hash slot correct but note that because
435  * directory hashes are chained 16x, any slot in the inode will work.
436  *
437  * Also format the allocation map.
438  *
439  * NOTE: The passed total_space is 8MB-aligned to avoid edge cases.
440  */
441 static
442 void
443 format_hammer2(int fd, hammer2_off_t total_space, hammer2_off_t free_space)
444 {
445         char *buf = malloc(HAMMER2_PBUFSIZE);
446         hammer2_volume_data_t *vol;
447         hammer2_inode_data_t *rawip;
448         hammer2_blockref_t sroot_blockref;
449         hammer2_blockref_t root_blockref;
450         uint64_t now;
451         hammer2_off_t volu_base = 0;
452         hammer2_off_t boot_base = HAMMER2_ZONE_SEG;
453         hammer2_off_t aux_base = boot_base + BootAreaSize;
454         hammer2_off_t alloc_base = aux_base + AuxAreaSize;
455         hammer2_off_t tmp_base;
456         size_t n;
457         int i;
458
459         /*
460          * Clear the entire reserve for the first 2G segment and
461          * make sure we can write to the last block.
462          */
463         bzero(buf, HAMMER2_PBUFSIZE);
464         tmp_base = volu_base;
465         for (i = 0; i < HAMMER2_ZONE_BLOCKS_SEG; ++i) {
466                 n = pwrite(fd, buf, HAMMER2_PBUFSIZE, tmp_base);
467                 if (n != HAMMER2_PBUFSIZE) {
468                         perror("write");
469                         exit(1);
470                 }
471                 tmp_base += HAMMER2_PBUFSIZE;
472         }
473
474         n = pwrite(fd, buf, HAMMER2_PBUFSIZE,
475                    volu_base + total_space - HAMMER2_PBUFSIZE);
476         if (n != HAMMER2_PBUFSIZE) {
477                 perror("write (at-end-of-volume)");
478                 exit(1);
479         }
480
481         /*
482          * Reserve space for the super-root inode and the root inode.
483          * Put them in the same 64K block.
484          */
485         assert((alloc_base & HAMMER2_PBUFMASK) == 0);
486
487         alloc_base &= ~HAMMER2_PBUFMASK64;
488         alloc_direct(&alloc_base, &sroot_blockref, HAMMER2_INODE_BYTES);
489         alloc_direct(&alloc_base, &root_blockref, HAMMER2_INODE_BYTES);
490         assert(((sroot_blockref.data_off ^ root_blockref.data_off) &
491                 HAMMER2_OFF_MASK_HI) == 0);
492
493         bzero(buf, HAMMER2_PBUFSIZE);
494         now = nowtime();
495
496         /*
497          * Format the root directory inode, which is left empty.
498          */
499         rawip = (void *)(buf + (HAMMER2_OFF_MASK_LO & root_blockref.data_off));
500         rawip->version = HAMMER2_INODE_VERSION_ONE;
501         rawip->ctime = now;
502         rawip->mtime = now;
503         /* rawip->atime = now; NOT IMPL MUST BE ZERO */
504         rawip->btime = now;
505         rawip->type = HAMMER2_OBJTYPE_DIRECTORY;
506         rawip->mode = 0755;
507         rawip->inum = 1;                /* root inode, inumber 1 */
508         rawip->nlinks = 1;              /* directory link count compat */
509
510         rawip->name_len = strlen(Label);
511         bcopy(Label, rawip->filename, rawip->name_len);
512         rawip->name_key = dirhash(rawip->filename, rawip->name_len);
513
514         /*
515          * Compression mode and supported copyids.
516          */
517         rawip->comp_algo = HAMMER2_COMP_AUTOZERO;
518
519         rawip->pfs_clid = Hammer2_RPFSId;
520         rawip->pfs_type = HAMMER2_PFSTYPE_MASTER;
521         rawip->op_flags |= HAMMER2_OPFLAG_PFSROOT;
522
523         /* rawip->u.blockset is left empty */
524
525         /*
526          * The root blockref will be stored in the super-root inode as
527          * the only directory entry.  The copyid here is the actual copyid
528          * of the storage ref.
529          *
530          * The key field for a directory entry's blockref is essentially
531          * the name key for the entry.
532          */
533         root_blockref.key = rawip->name_key;
534         root_blockref.copyid = HAMMER2_COPYID_LOCAL;
535         root_blockref.keybits = 0;
536         root_blockref.check.iscsi32.value =
537                                         hammer2_icrc32(rawip, sizeof(*rawip));
538         root_blockref.type = HAMMER2_BREF_TYPE_INODE;
539         root_blockref.methods = HAMMER2_ENC_CHECKMETHOD(HAMMER2_CHECK_ICRC) |
540                                 HAMMER2_ENC_COMPMETHOD(HAMMER2_COMP_AUTOZERO);
541
542         /*
543          * Format the super-root directory inode, giving it one directory
544          * entry (root_blockref) and fixup the icrc method.
545          *
546          * The superroot contains one directory entry pointing at the root
547          * inode (named via the label).  Inodes contain one blockset which
548          * is fully associative so we can put the entry anywhere without
549          * having to worry about the hash.  Use index 0.
550          */
551         rawip = (void *)(buf + (HAMMER2_OFF_MASK_LO & sroot_blockref.data_off));
552         rawip->version = HAMMER2_INODE_VERSION_ONE;
553         rawip->ctime = now;
554         rawip->mtime = now;
555         /* rawip->atime = now; NOT IMPL MUST BE ZERO */
556         rawip->btime = now;
557         rawip->type = HAMMER2_OBJTYPE_DIRECTORY;
558         rawip->mode = 0700;             /* super-root - root only */
559         rawip->inum = 0;                /* super root inode, inumber 0 */
560         rawip->nlinks = 2;              /* directory link count compat */
561
562         rawip->name_len = 0;            /* super-root is unnamed */
563         rawip->name_key = 0;
564
565         rawip->comp_algo = HAMMER2_COMP_AUTOZERO;
566
567         /*
568          * The super-root is flagged as a PFS and typically given its own
569          * random FSID, making it possible to mirror an entire HAMMER2 disk
570          * snapshots and all if desired.  PFS ids are used to match up
571          * mirror sources and targets and cluster copy sources and targets.
572          */
573         rawip->pfs_clid = Hammer2_SPFSId;
574         rawip->pfs_type = HAMMER2_PFSTYPE_MASTER;
575         rawip->op_flags |= HAMMER2_OPFLAG_PFSROOT;
576
577         /*
578          * The super-root has one directory entry pointing at the named
579          * root inode.
580          */
581         rawip->u.blockset.blockref[0] = root_blockref;
582
583         /*
584          * The sroot blockref will be stored in the volume header.
585          */
586         sroot_blockref.copyid = HAMMER2_COPYID_LOCAL;
587         sroot_blockref.keybits = 0;
588         sroot_blockref.check.iscsi32.value =
589                                         hammer2_icrc32(rawip, sizeof(*rawip));
590         sroot_blockref.type = HAMMER2_BREF_TYPE_INODE;
591         sroot_blockref.methods = HAMMER2_ENC_CHECKMETHOD(HAMMER2_CHECK_ICRC) |
592                                  HAMMER2_ENC_COMPMETHOD(HAMMER2_COMP_AUTOZERO);
593
594         /*
595          * Write out the 64K HAMMER2 block containing the root and sroot.
596          */
597         n = pwrite(fd, buf, HAMMER2_PBUFSIZE,
598                    root_blockref.data_off & HAMMER2_OFF_MASK_HI);
599         if (n != HAMMER2_PBUFSIZE) {
600                 perror("write");
601                 exit(1);
602         }
603
604         /*
605          * Format the volume header.
606          *
607          * The volume header points to sroot_blockref.  Also be absolutely
608          * sure that allocator_beg is set.
609          */
610         bzero(buf, HAMMER2_PBUFSIZE);
611         vol = (void *)buf;
612
613         vol->magic = HAMMER2_VOLUME_ID_HBO;
614         vol->boot_beg = boot_base;
615         vol->boot_end = boot_base + BootAreaSize;
616         vol->aux_beg = aux_base;
617         vol->aux_end = aux_base + AuxAreaSize;
618         vol->volu_size = total_space;
619         vol->version = Hammer2Version;
620         vol->flags = 0;
621
622         vol->fsid = Hammer2_FSId;
623         vol->fstype = Hammer2_FSType;
624
625         vol->peer_type = HAMMER2_PEER_HAMMER2;  /* LNK_CONN identification */
626
627         vol->allocator_size = free_space;
628         vol->allocator_free = free_space;
629         vol->allocator_beg = alloc_base;
630
631         vol->sroot_blockset.blockref[0] = sroot_blockref;
632         vol->mirror_tid = 0;
633         vol->alloc_tid = 16;
634         vol->icrc_sects[HAMMER2_VOL_ICRC_SECT1] =
635                         hammer2_icrc32((char *)vol + HAMMER2_VOLUME_ICRC1_OFF,
636                                        HAMMER2_VOLUME_ICRC1_SIZE);
637
638         /*
639          * Set ICRC_SECT0 after all remaining elements of sect0 have been
640          * populated in the volume header.  Note hat ICRC_SECT* (except for
641          * SECT0) are part of sect0.
642          */
643         vol->icrc_sects[HAMMER2_VOL_ICRC_SECT0] =
644                         hammer2_icrc32((char *)vol + HAMMER2_VOLUME_ICRC0_OFF,
645                                        HAMMER2_VOLUME_ICRC0_SIZE);
646         vol->icrc_volheader =
647                         hammer2_icrc32((char *)vol + HAMMER2_VOLUME_ICRCVH_OFF,
648                                        HAMMER2_VOLUME_ICRCVH_SIZE);
649
650         /*
651          * Write the volume header and all alternates.
652          */
653         for (i = 0; i < HAMMER2_NUM_VOLHDRS; ++i) {
654                 if (i * HAMMER2_ZONE_BYTES64 >= total_space)
655                         break;
656                 n = pwrite(fd, buf, HAMMER2_PBUFSIZE,
657                            volu_base + i * HAMMER2_ZONE_BYTES64);
658                 if (n != HAMMER2_PBUFSIZE) {
659                         perror("write");
660                         exit(1);
661                 }
662         }
663
664         /*
665          * Cleanup
666          */
667         free(buf);
668 }
669
670 static void
671 alloc_direct(hammer2_off_t *basep, hammer2_blockref_t *bref, size_t bytes)
672 {
673         int radix;
674
675         radix = 0;
676         assert(bytes);
677         while ((bytes & 1) == 0) {
678                 bytes >>= 1;
679                 ++radix;
680         }
681         assert(bytes == 1);
682         if (radix < HAMMER2_MIN_RADIX)
683                 radix = HAMMER2_MIN_RADIX;
684
685         bzero(bref, sizeof(*bref));
686         bref->data_off = *basep | radix;
687         bref->vradix = radix;
688
689         *basep += 1U << radix;
690 }
691
692 /*
693  * Borrow HAMMER1's directory hash algorithm #1 with a few modifications.
694  * The filename is split into fields which are hashed separately and then
695  * added together.
696  *
697  * Differences include: bit 63 must be set to 1 for HAMMER2 (HAMMER1 sets
698  * it to 0), this is because bit63=0 is used for hidden hardlinked inodes.
699  * (This means we do not need to do a 0-check/or-with-0x100000000 either).
700  *
701  * Also, the iscsi crc code is used instead of the old crc32 code.
702  */
703 static hammer2_key_t
704 dirhash(const unsigned char *name, size_t len)
705 {
706         const unsigned char *aname = name;
707         uint32_t crcx;
708         uint64_t key;
709         size_t i;
710         size_t j;
711
712         /*
713          * Filesystem version 6 or better will create directories
714          * using the ALG1 dirhash.  This hash breaks the filename
715          * up into domains separated by special characters and
716          * hashes each domain independently.
717          *
718          * We also do a simple sub-sort using the first character
719          * of the filename in the top 5-bits.
720          */
721         key = 0;
722
723         /*
724          * m32
725          */
726         crcx = 0;
727         for (i = j = 0; i < len; ++i) {
728                 if (aname[i] == '.' ||
729                     aname[i] == '-' ||
730                     aname[i] == '_' ||
731                     aname[i] == '~') {
732                         if (i != j)
733                                 crcx += hammer2_icrc32(aname + j, i - j);
734                         j = i + 1;
735                 }
736         }
737         if (i != j)
738                 crcx += hammer2_icrc32(aname + j, i - j);
739
740         /*
741          * The directory hash utilizes the top 32 bits of the 64-bit key.
742          * Bit 63 must be set to 1.
743          */
744         crcx |= 0x80000000U;
745         key |= (uint64_t)crcx << 32;
746
747         /*
748          * l16 - crc of entire filename
749          *
750          * This crc reduces degenerate hash collision conditions
751          */
752         crcx = hammer2_icrc32(aname, len);
753         crcx = crcx ^ (crcx << 16);
754         key |= crcx & 0xFFFF0000U;
755
756         /*
757          * Set bit 15.  This allows readdir to strip bit 63 so a positive
758          * 64-bit cookie/offset can always be returned, and still guarantee
759          * that the values 0x0000-0x7FFF are available for artificial entries.
760          * ('.' and '..').
761          */
762         key |= 0x8000U;
763
764         return (key);
765 }