Module Name: src Committed By: tkusumi Date: Sun Jan 10 12:38:41 UTC 2021
Modified Files: src/usr.sbin/fstyp: fstyp.h hammer.c hammer2.c hammer2_disk.h Log Message: fstyp: Sync HAMMER1/2 with DragonFly BSD taken-from: DragonFly BSD To generate a diff of this commit: cvs rdiff -u -r1.8 -r1.9 src/usr.sbin/fstyp/fstyp.h cvs rdiff -u -r1.3 -r1.4 src/usr.sbin/fstyp/hammer.c cvs rdiff -u -r1.6 -r1.7 src/usr.sbin/fstyp/hammer2.c cvs rdiff -u -r1.2 -r1.3 src/usr.sbin/fstyp/hammer2_disk.h Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/usr.sbin/fstyp/fstyp.h diff -u src/usr.sbin/fstyp/fstyp.h:1.8 src/usr.sbin/fstyp/fstyp.h:1.9 --- src/usr.sbin/fstyp/fstyp.h:1.8 Wed Jan 1 09:08:52 2020 +++ src/usr.sbin/fstyp/fstyp.h Sun Jan 10 12:38:40 2021 @@ -1,4 +1,4 @@ -/* $NetBSD: fstyp.h,v 1.8 2020/01/01 09:08:52 tkusumi Exp $ */ +/* $NetBSD: fstyp.h,v 1.9 2021/01/10 12:38:40 tkusumi Exp $ */ /*- * Copyright (c) 2017 The NetBSD Foundation, Inc. @@ -74,5 +74,7 @@ int fstyp_zfs(FILE *, char *, size_t); int fsvtyp_hammer(const char *, char *, size_t); int fsvtyp_hammer_partial(const char *, char *, size_t); +int fsvtyp_hammer2(const char *, char *, size_t); +int fsvtyp_hammer2_partial(const char *, char *, size_t); #endif /* !FSTYP_H */ Index: src/usr.sbin/fstyp/hammer.c diff -u src/usr.sbin/fstyp/hammer.c:1.3 src/usr.sbin/fstyp/hammer.c:1.4 --- src/usr.sbin/fstyp/hammer.c:1.3 Wed Jan 15 15:30:46 2020 +++ src/usr.sbin/fstyp/hammer.c Sun Jan 10 12:38:40 2021 @@ -1,4 +1,4 @@ -/* $NetBSD: hammer.c,v 1.3 2020/01/15 15:30:46 tkusumi Exp $ */ +/* $NetBSD: hammer.c,v 1.4 2021/01/10 12:38:40 tkusumi Exp $ */ /*- * Copyright (c) 2016-2019 The DragonFly Project @@ -27,13 +27,13 @@ * SUCH DAMAGE. */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: hammer.c,v 1.3 2020/01/15 15:30:46 tkusumi Exp $"); +__KERNEL_RCSID(0, "$NetBSD: hammer.c,v 1.4 2021/01/10 12:38:40 tkusumi Exp $"); #include <stdio.h> #include <stdlib.h> #include <string.h> #include <err.h> -#include <assert.h> +#include <uuid.h> #include "fstyp.h" #include "hammer_disk.h" @@ -41,13 +41,7 @@ __KERNEL_RCSID(0, "$NetBSD: hammer.c,v 1 static hammer_volume_ondisk_t read_ondisk(FILE *fp) { - hammer_volume_ondisk_t ondisk; - - ondisk = read_buf(fp, 0, sizeof(*ondisk)); - if (ondisk == NULL) - err(1, "failed to read ondisk"); - - return (ondisk); + return (read_buf(fp, 0, sizeof(struct hammer_volume_ondisk))); } static int @@ -61,32 +55,49 @@ test_ondisk(const hammer_volume_ondisk_t ondisk->vol_signature != HAMMER_FSBUF_VOLUME_REV) return (1); if (ondisk->vol_rootvol != HAMMER_ROOT_VOLNO) - return (2); + return (1); if (ondisk->vol_no < 0 || ondisk->vol_no > HAMMER_MAX_VOLUMES - 1) - return (3); + return (1); if (ondisk->vol_count < 1 || ondisk->vol_count > HAMMER_MAX_VOLUMES) - return (4); + return (1); if (count == 0) { count = ondisk->vol_count; - assert(count != 0); + if (count == 0) + return (1); memcpy(&fsid, &ondisk->vol_fsid, sizeof(fsid)); memcpy(&fstype, &ondisk->vol_fstype, sizeof(fstype)); strlcpy(label, ondisk->vol_label, sizeof(label)); } else { if (ondisk->vol_count != count) - return (5); - if (memcmp(&ondisk->vol_fsid, &fsid, sizeof(fsid))) - return (6); - if (memcmp(&ondisk->vol_fstype, &fstype, sizeof(fstype))) - return (7); + return (1); + if (!uuid_equal(&ondisk->vol_fsid, &fsid, NULL)) + return (1); + if (!uuid_equal(&ondisk->vol_fstype, &fstype, NULL)) + return (1); if (strcmp(ondisk->vol_label, label)) - return (8); + return (1); } return (0); } +static const char* +extract_device_name(const char *devpath) +{ + const char *p; + + p = strrchr(devpath, '/'); + if (p) { + p++; + if (*p == 0) + p = NULL; + } else { + p = devpath; + } + return (p); +} + int fstyp_hammer(FILE *fp, char *label, size_t size) { @@ -96,6 +107,8 @@ fstyp_hammer(FILE *fp, char *label, size const char *p; #endif ondisk = read_ondisk(fp); + if (!ondisk) + goto fail; if (ondisk->vol_no != HAMMER_ROOT_VOLNO) goto fail; if (ondisk->vol_count != 1) @@ -109,15 +122,11 @@ fstyp_hammer(FILE *fp, char *label, size */ #ifdef HAS_DEVPATH /* Add device name to help support multiple autofs -media mounts. */ - p = strrchr(devpath, '/'); - if (p) { - p++; - if (*p == 0) - strlcpy(label, ondisk->vol_label, size); - else - snprintf(label, size, "%s_%s", ondisk->vol_label, p); - } else - snprintf(label, size, "%s_%s", ondisk->vol_label, devpath); + p = extract_device_name(devpath); + if (p) + snprintf(label, size, "%s_%s", ondisk->vol_label, p); + else + strlcpy(label, ondisk->vol_label, size); #else strlcpy(label, ondisk->vol_label, size); #endif @@ -130,20 +139,23 @@ fail: static int test_volume(const char *volpath) { - hammer_volume_ondisk_t ondisk; + hammer_volume_ondisk_t ondisk = NULL; FILE *fp; int volno = -1; if ((fp = fopen(volpath, "r")) == NULL) - err(1, "failed to open %s", volpath); + goto fail; ondisk = read_ondisk(fp); - fclose(fp); + if (!ondisk) + goto fail; if (test_ondisk(ondisk)) goto fail; volno = ondisk->vol_no; fail: + if (fp) + fclose(fp); free(ondisk); return (volno); } @@ -152,8 +164,8 @@ static int __fsvtyp_hammer(const char *blkdevs, char *label, size_t size, int partial) { hammer_volume_ondisk_t ondisk = NULL; - FILE *fp; - char *dup, *p, *volpath, x[HAMMER_MAX_VOLUMES]; + FILE *fp = NULL; + char *dup = NULL, *p, *volpath, *rootvolpath, x[HAMMER_MAX_VOLUMES]; int i, volno, error = 1; if (!blkdevs) @@ -164,6 +176,7 @@ __fsvtyp_hammer(const char *blkdevs, cha p = dup; volpath = NULL; + rootvolpath = NULL; volno = -1; while (p) { volpath = p; @@ -171,19 +184,23 @@ __fsvtyp_hammer(const char *blkdevs, cha *p++ = '\0'; if ((volno = test_volume(volpath)) == -1) break; - assert(volno >= 0); - assert(volno < HAMMER_MAX_VOLUMES); + if (volno < 0 || volno >= HAMMER_MAX_VOLUMES) + goto fail; x[volno]++; + if (volno == HAMMER_ROOT_VOLNO) + rootvolpath = volpath; } - if (!volpath) - err(1, "invalid path %s", blkdevs); + /* If no rootvolpath, proceed only if partial mode with volpath. */ + if (rootvolpath) + volpath = rootvolpath; + else if (!partial || !volpath) + goto fail; if ((fp = fopen(volpath, "r")) == NULL) - err(1, "failed to open %s", volpath); + goto fail; ondisk = read_ondisk(fp); - fclose(fp); - - free(dup); + if (!ondisk) + goto fail; if (volno == -1) goto fail; @@ -202,11 +219,18 @@ __fsvtyp_hammer(const char *blkdevs, cha if (x[i] != 0) goto fail; success: - /* XXX autofs -media mount can't handle multiple mounts */ - strlcpy(label, ondisk->vol_label, size); + /* Add device name to help support multiple autofs -media mounts. */ + p = __UNCONST(extract_device_name(volpath)); + if (p) + snprintf(label, size, "%s_%s", ondisk->vol_label, p); + else + strlcpy(label, ondisk->vol_label, size); error = 0; fail: + if (fp) + fclose(fp); free(ondisk); + free(dup); return (error); } Index: src/usr.sbin/fstyp/hammer2.c diff -u src/usr.sbin/fstyp/hammer2.c:1.6 src/usr.sbin/fstyp/hammer2.c:1.7 --- src/usr.sbin/fstyp/hammer2.c:1.6 Wed Sep 23 14:39:23 2020 +++ src/usr.sbin/fstyp/hammer2.c Sun Jan 10 12:38:40 2021 @@ -1,4 +1,4 @@ -/* $NetBSD: hammer2.c,v 1.6 2020/09/23 14:39:23 tkusumi Exp $ */ +/* $NetBSD: hammer2.c,v 1.7 2021/01/10 12:38:40 tkusumi Exp $ */ /*- * Copyright (c) 2017-2019 The DragonFly Project @@ -27,7 +27,7 @@ * SUCH DAMAGE. */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: hammer2.c,v 1.6 2020/09/23 14:39:23 tkusumi Exp $"); +__KERNEL_RCSID(0, "$NetBSD: hammer2.c,v 1.7 2021/01/10 12:38:40 tkusumi Exp $"); #include <stdio.h> #include <stdlib.h> @@ -35,28 +35,93 @@ __KERNEL_RCSID(0, "$NetBSD: hammer2.c,v #include <string.h> #include <err.h> #include <assert.h> +#include <uuid.h> #include "fstyp.h" #include "hammer2_disk.h" -static hammer2_volume_data_t* -read_voldata(FILE *fp) +static ssize_t +get_file_size(FILE *fp) { - hammer2_volume_data_t *voldata; + ssize_t siz; + + if (fseek(fp, 0, SEEK_END) == -1) { + warnx("hammer2: failed to seek media end"); + return (-1); + } + + siz = ftell(fp); + if (siz == -1) { + warnx("hammer2: failed to tell media end"); + return (-1); + } + + return (siz); +} + +static hammer2_volume_data_t * +read_voldata(FILE *fp, int i) +{ + if (i < 0 || i >= HAMMER2_NUM_VOLHDRS) + return (NULL); - voldata = read_buf(fp, 0, sizeof(*voldata)); - if (voldata == NULL) - err(1, "failed to read volume data"); + if ((hammer2_off_t)i * (hammer2_off_t)HAMMER2_ZONE_BYTES64 >= (hammer2_off_t)get_file_size(fp)) + return (NULL); - return (voldata); + return (read_buf(fp, (off_t)i * (off_t)HAMMER2_ZONE_BYTES64, + sizeof(hammer2_volume_data_t))); } static int -test_voldata(const hammer2_volume_data_t *voldata) +test_voldata(FILE *fp) { - if (voldata->magic != HAMMER2_VOLUME_ID_HBO && - voldata->magic != HAMMER2_VOLUME_ID_ABO) - return (1); + hammer2_volume_data_t *voldata; + int i; + static int count = 0; + static uuid_t fsid, fstype; + + for (i = 0; i < HAMMER2_NUM_VOLHDRS; i++) { + if ((hammer2_off_t)i * (hammer2_off_t)HAMMER2_ZONE_BYTES64 >= (hammer2_off_t)get_file_size(fp)) + break; + voldata = read_voldata(fp, i); + if (voldata == NULL) { + warnx("hammer2: failed to read volume data"); + return (1); + } + if (voldata->magic != HAMMER2_VOLUME_ID_HBO && + voldata->magic != HAMMER2_VOLUME_ID_ABO) { + free(voldata); + return (1); + } + if (voldata->volu_id > HAMMER2_MAX_VOLUMES - 1) { + free(voldata); + return (1); + } + if (voldata->nvolumes > HAMMER2_MAX_VOLUMES) { + free(voldata); + return (1); + } + + if (count == 0) { + count = voldata->nvolumes; + memcpy(&fsid, &voldata->fsid, sizeof(fsid)); + memcpy(&fstype, &voldata->fstype, sizeof(fstype)); + } else { + if (voldata->nvolumes != count) { + free(voldata); + return (1); + } + if (!uuid_equal(&fsid, &voldata->fsid, NULL)) { + free(voldata); + return (1); + } + if (!uuid_equal(&fstype, &voldata->fstype, NULL)) { + free(voldata); + return (1); + } + } + free(voldata); + } return (0); } @@ -66,7 +131,7 @@ read_media(FILE *fp, const hammer2_block { hammer2_media_data_t *media; hammer2_off_t io_off, io_base; - size_t bytes, io_bytes, boff; + size_t bytes, io_bytes, boff, fbytes; bytes = (bref->data_off & HAMMER2_OFF_MASK_RADIX); if (bytes) @@ -74,30 +139,44 @@ read_media(FILE *fp, const hammer2_block *media_bytes = bytes; if (!bytes) { - warnx("blockref has no data"); + warnx("hammer2: blockref has no data"); return (NULL); } io_off = bref->data_off & ~HAMMER2_OFF_MASK_RADIX; io_base = io_off & ~(hammer2_off_t)(HAMMER2_LBUFSIZE - 1); - boff = (size_t)(io_off - io_base); + boff = io_off - io_base; io_bytes = HAMMER2_LBUFSIZE; while (io_bytes + boff < bytes) io_bytes <<= 1; if (io_bytes > sizeof(hammer2_media_data_t)) { - warnx("invalid I/O bytes"); + warnx("hammer2: invalid I/O bytes"); return (NULL); } - if (fseek(fp, (long int)io_base, SEEK_SET) == -1) { - warnx("failed to seek media"); + /* + * XXX fp is currently always root volume, so read fails if io_base is + * beyond root volume limit. Fail with a message before read_buf() then. + */ + fbytes = (size_t)get_file_size(fp); + if ((ssize_t)fbytes == -1) { + warnx("hammer2: failed to get media size"); + return (NULL); + } + if (io_base >= fbytes) { + warnx("hammer2: XXX read beyond HAMMER2 root volume limit unsupported"); + return (NULL); + } + + if (fseeko(fp, (off_t)io_base, SEEK_SET) == -1) { + warnx("hammer2: failed to seek media"); return (NULL); } media = read_buf(fp, (off_t)io_base, io_bytes); if (media == NULL) { - warnx("failed to read media"); + warnx("hammer2: failed to read media"); return (NULL); } if (boff) @@ -140,8 +219,10 @@ find_pfs(FILE *fp, const hammer2_blockre strlen(pfs))) *res = true; } - } else - assert(0); + } else { + free(media); + return (-1); + } } break; case HAMMER2_BREF_TYPE_INDIRECT: @@ -173,7 +254,7 @@ extract_device_name(const char *devpath) char *p, *head; if (!devpath) - return NULL; + return (NULL); p = strdup(devpath); head = p; @@ -187,18 +268,18 @@ extract_device_name(const char *devpath) p++; if (*p == 0) { free(head); - return NULL; + return (NULL); } p = strdup(p); free(head); - return p; + return (p); } - return head; + return (head); } static int -read_label(FILE *fp, char *label, size_t size) +read_label(FILE *fp, char *label, size_t size, const char *devpath) { hammer2_blockref_t broot, best, *bref; hammer2_media_data_t *vols[HAMMER2_NUM_VOLHDRS], *media; @@ -209,16 +290,20 @@ read_label(FILE *fp, char *label, size_t char *devname; best_i = -1; + memset(vols, 0, sizeof(vols)); memset(&best, 0, sizeof(best)); for (i = 0; i < HAMMER2_NUM_VOLHDRS; i++) { + if ((hammer2_off_t)i * (hammer2_off_t)HAMMER2_ZONE_BYTES64 >= (hammer2_off_t)get_file_size(fp)) + break; memset(&broot, 0, sizeof(broot)); broot.type = HAMMER2_BREF_TYPE_VOLUME; - broot.data_off = ((hammer2_off_t)i * - (hammer2_off_t)HAMMER2_ZONE_BYTES64) | HAMMER2_PBUFRADIX; - vols[i] = read_buf(fp, - (off_t)(broot.data_off & ~HAMMER2_OFF_MASK_RADIX), - sizeof(*vols[i])); + broot.data_off = ((hammer2_off_t)i * (hammer2_off_t)HAMMER2_ZONE_BYTES64) | HAMMER2_PBUFRADIX; + vols[i] = (void*)read_voldata(fp, i); + if (vols[i] == NULL) { + warnx("hammer2: failed to read volume data"); + goto fail; + } broot.mirror_tid = vols[i]->voldata.mirror_tid; if (best_i < 0 || best.mirror_tid < broot.mirror_tid) { best_i = i; @@ -228,7 +313,7 @@ read_label(FILE *fp, char *label, size_t bref = &vols[best_i]->voldata.sroot_blockset.blockref[0]; if (bref->type != HAMMER2_BREF_TYPE_INODE) { - warnx("blockref type is not inode"); + /* Don't print error as devpath could be non-root volume. */ goto fail; } @@ -298,15 +383,132 @@ fail: int fstyp_hammer2(FILE *fp, char *label, size_t size) { - hammer2_volume_data_t *voldata; + hammer2_volume_data_t *voldata = read_voldata(fp, 0); int error = 1; - voldata = read_voldata(fp); - if (test_voldata(voldata)) + if (voldata->volu_id != HAMMER2_ROOT_VOLUME) + goto fail; + if (voldata->nvolumes != 0) + goto fail; + if (test_voldata(fp)) + goto fail; + + error = read_label(fp, label, size, NULL); +fail: + free(voldata); + return (error); +} + +static int +__fsvtyp_hammer2(const char *blkdevs, char *label, size_t size, int partial) +{ + hammer2_volume_data_t *voldata = NULL; + FILE *fp = NULL; + char *dup = NULL, *target_label = NULL, *p, *volpath, *rootvolpath; + char x[HAMMER2_MAX_VOLUMES]; + int i, volid, error = 1; + + if (!blkdevs) + goto fail; + + memset(x, 0, sizeof(x)); + p = dup = strdup(blkdevs); + if ((p = strchr(p, '@')) != NULL) { + *p++ = '\0'; + target_label = p; + } + p = dup; + + volpath = NULL; + rootvolpath = NULL; + volid = -1; + while (p) { + volpath = p; + if ((p = strchr(p, ':')) != NULL) + *p++ = '\0'; + if ((fp = fopen(volpath, "r")) == NULL) { + warnx("hammer2: failed to open %s", volpath); + goto fail; + } + if (test_voldata(fp)) + break; + voldata = read_voldata(fp, 0); + fclose(fp); + if (voldata == NULL) { + warnx("hammer2: failed to read volume data"); + goto fail; + } + volid = voldata->volu_id; + free(voldata); + voldata = NULL; + if (volid < 0 || volid >= HAMMER2_MAX_VOLUMES) + goto fail; + x[volid]++; + if (volid == HAMMER2_ROOT_VOLUME) + rootvolpath = volpath; + } + + /* If no rootvolpath, proceed only if partial mode with volpath. */ + if (rootvolpath) + volpath = rootvolpath; + else if (!partial || !volpath) + goto fail; + if ((fp = fopen(volpath, "r")) == NULL) { + warnx("hammer2: failed to open %s", volpath); + goto fail; + } + voldata = read_voldata(fp, 0); + if (voldata == NULL) { + warnx("hammer2: failed to read volume data"); + goto fail; + } + + if (volid == -1) goto fail; + if (partial) + goto success; - error = read_label(fp, label, size); + for (i = 0; i < HAMMER2_MAX_VOLUMES; i++) + if (x[i] > 1) + goto fail; + for (i = 0; i < HAMMER2_MAX_VOLUMES; i++) + if (x[i] == 0) + break; + if (voldata->nvolumes != i) + goto fail; + for (; i < HAMMER2_MAX_VOLUMES; i++) + if (x[i] != 0) + goto fail; +success: + /* Reconstruct @label format path using only root volume. */ + if (target_label) { + size_t siz = strlen(volpath) + strlen(target_label) + 2; + p = calloc(1, siz); + snprintf(p, siz, "%s@%s", volpath, target_label); + volpath = p; + } + error = read_label(fp, label, size, volpath); + if (target_label) + free(p); + /* If in partial mode, read label but ignore error. */ + if (partial) + error = 0; fail: + if (fp) + fclose(fp); free(voldata); + free(dup); return (error); } + +int +fsvtyp_hammer2(const char *blkdevs, char *label, size_t size) +{ + return (__fsvtyp_hammer2(blkdevs, label, size, 0)); +} + +int +fsvtyp_hammer2_partial(const char *blkdevs, char *label, size_t size) +{ + return (__fsvtyp_hammer2(blkdevs, label, size, 1)); +} Index: src/usr.sbin/fstyp/hammer2_disk.h diff -u src/usr.sbin/fstyp/hammer2_disk.h:1.2 src/usr.sbin/fstyp/hammer2_disk.h:1.3 --- src/usr.sbin/fstyp/hammer2_disk.h:1.2 Wed Sep 23 14:39:23 2020 +++ src/usr.sbin/fstyp/hammer2_disk.h Sun Jan 10 12:38:40 2021 @@ -1,4 +1,4 @@ -/* $NetBSD: hammer2_disk.h,v 1.2 2020/09/23 14:39:23 tkusumi Exp $ */ +/* $NetBSD: hammer2_disk.h,v 1.3 2021/01/10 12:38:40 tkusumi Exp $ */ /* * Copyright (c) 2011-2019 The DragonFly Project. All rights reserved. @@ -35,7 +35,7 @@ * SUCH DAMAGE. */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: hammer2_disk.h,v 1.2 2020/09/23 14:39:23 tkusumi Exp $"); +__KERNEL_RCSID(0, "$NetBSD: hammer2_disk.h,v 1.3 2021/01/10 12:38:40 tkusumi Exp $"); #ifndef _VFS_HAMMER2_DISK_H_ #define _VFS_HAMMER2_DISK_H_ @@ -126,9 +126,7 @@ __KERNEL_RCSID(0, "$NetBSD: hammer2_disk /* * In HAMMER2, arrays of blockrefs are fully set-associative, meaning that - * any element can occur at any index and holes can be anywhere. As a - * future optimization we will be able to flag that such arrays are sorted - * and thus optimize lookups, but for now we don't. + * any element can occur at any index and holes can be anywhere. * * Inodes embed either 512 bytes of direct data or an array of 4 blockrefs, * resulting in highly efficient storage for files <= 512 bytes and for files @@ -344,7 +342,7 @@ __KERNEL_RCSID(0, "$NetBSD: hammer2_disk #define HAMMER2_FREEMAP_LEVEL3_RADIX 46 /* 64TB */ #define HAMMER2_FREEMAP_LEVEL2_RADIX 38 /* 256GB */ #define HAMMER2_FREEMAP_LEVEL1_RADIX 30 /* 1GB */ -#define HAMMER2_FREEMAP_LEVEL0_RADIX 22 /* 4MB (128by in l-1 leaf) */ +#define HAMMER2_FREEMAP_LEVEL0_RADIX 22 /* 4MB (x 256 in l-1 leaf) */ #define HAMMER2_FREEMAP_LEVELN_PSIZE 32768 /* physical bytes */ @@ -723,6 +721,7 @@ typedef struct hammer2_blockref hammer2_ #define HAMMER2_BREF_TYPE_DIRENT 4 #define HAMMER2_BREF_TYPE_FREEMAP_NODE 5 #define HAMMER2_BREF_TYPE_FREEMAP_LEAF 6 +#define HAMMER2_BREF_TYPE_INVALID 7 #define HAMMER2_BREF_TYPE_FREEMAP 254 /* pseudo-type */ #define HAMMER2_BREF_TYPE_VOLUME 255 /* pseudo-type */ @@ -780,17 +779,12 @@ typedef struct hammer2_blockref hammer2_ /* * HAMMER2 block references are collected into sets of 4 blockrefs. These - * sets are fully associative, meaning the elements making up a set are - * not sorted in any way and may contain duplicate entries, holes, or - * entries which shortcut multiple levels of indirection. Sets are used - * in various ways: - * - * (1) When redundancy is desired a set may contain several duplicate - * entries pointing to different copies of the same data. Up to 4 copies - * are supported. + * sets are fully associative, meaning the elements making up a set may + * contain duplicate entries, holes, but valid elements are always sorted. * - * (2) The blockrefs in a set can shortcut multiple levels of indirections - * within the bounds imposed by the parent of set. + * When redundancy is desired a set may contain several duplicate + * entries pointing to different copies of the same data. Up to 4 copies + * are supported. Not implemented. * * When a set fills up another level of indirection is inserted, moving * some or all of the set's contents into indirect blocks placed under the @@ -861,6 +855,32 @@ typedef struct hammer2_blockset hammer2_ * 01 (reserved) * 10 Possibly free * 11 Allocated + * + * ========== + * level6 freemap + * blockref[0] : 4EB + * blockref[1] : 4EB + * blockref[2] : 4EB + * blockref[3] : 4EB + * ----------------------------------------------------------------------- + * 4 x 128B = 512B : 4 x 4EB = 16EB + * + * level2-5 FREEMAP_NODE + * blockref[0] : 1GB,256GB,64TB,16PB + * blockref[1] : 1GB,256GB,64TB,16PB + * ... + * blockref[255] : 1GB,256GB,64TB,16PB + * ----------------------------------------------------------------------- + * 256 x 128B = 32KB : 256 x 1GB,256GB,64TB,16PB = 256GB,64TB,16PB,4EB + * + * level1 FREEMAP_LEAF + * bmap_data[0] : 8 x 8B = 512bits = 256 x 2bits -> 256 x 16KB = 4MB + * bmap_data[1] : 8 x 8B = 512bits = 256 x 2bits -> 256 x 16KB = 4MB + * ... + * bmap_data[255] : 8 x 8B = 512bits = 256 x 2bits -> 256 x 16KB = 4MB + * ----------------------------------------------------------------------- + * 256 x 128B = 32KB : 256 x 4MB = 1GB + * ========== */ struct hammer2_bmap_data { int32_t linear; /* 00 linear sub-granular allocation offset */ @@ -1133,6 +1153,16 @@ typedef struct hammer2_inode_data hammer #define HAMMER2_VOLUME_ID_HBO 0x48414d3205172011LLU #define HAMMER2_VOLUME_ID_ABO 0x11201705324d4148LLU +/* + * If volume version is HAMMER2_VOL_VERSION_MULTI_VOLUMES or above, max + * HAMMER2_MAX_VOLUMES volumes are supported. There must be 1 (and only 1) + * volume with volume id HAMMER2_ROOT_VOLUME. + * Otherwise filesystem only supports 1 volume, and that volume must have + * volume id HAMMER2_ROOT_VOLUME(0) which was a reserved field then. + */ +#define HAMMER2_MAX_VOLUMES 64 +#define HAMMER2_ROOT_VOLUME 0 + struct hammer2_volume_data { /* * sector #0 - 512 bytes @@ -1149,8 +1179,10 @@ struct hammer2_volume_data { uint8_t copyid; /* 0038 copyid of phys vol */ uint8_t freemap_version; /* 0039 freemap algorithm */ uint8_t peer_type; /* 003A HAMMER2_PEER_xxx */ - uint8_t reserved003B; /* 003B */ - uint32_t reserved003C; /* 003C */ + uint8_t volu_id; /* 003B */ + uint8_t nvolumes; /* 003C */ + uint8_t reserved003D; /* 003D */ + uint16_t reserved003E; /* 003E */ uuid_t fsid; /* 0040 */ uuid_t fstype; /* 0050 */ @@ -1181,7 +1213,9 @@ struct hammer2_volume_data { hammer2_tid_t reserved0088; /* 0088 */ hammer2_tid_t freemap_tid; /* 0090 committed tid (fmap) */ hammer2_tid_t bulkfree_tid; /* 0098 bulkfree incremental */ - hammer2_tid_t reserved00A0[5]; /* 00A0-00C7 */ + hammer2_tid_t reserved00A0[4]; /* 00A0-00BF */ + + hammer2_off_t total_size; /* 00C0 Total volume size, bytes */ /* * Copyids are allocated dynamically from the copyexists bitmap. @@ -1211,19 +1245,25 @@ struct hammer2_volume_data { /* * sector #1 - 512 bytes * - * The entire sector is used by a blockset. + * The entire sector is used by a blockset, but currently only first + * blockref is used. */ hammer2_blockset_t sroot_blockset; /* 0200-03FF Superroot dir */ /* - * sector #2-7 + * sector #2-6 */ char sector2[512]; /* 0400-05FF reserved */ char sector3[512]; /* 0600-07FF reserved */ hammer2_blockset_t freemap_blockset; /* 0800-09FF freemap */ char sector5[512]; /* 0A00-0BFF reserved */ char sector6[512]; /* 0C00-0DFF reserved */ - char sector7[512]; /* 0E00-0FFF reserved */ + + /* + * sector #7 - 512 bytes + * Maximum 64 volume offsets within logical offset. + */ + hammer2_off_t volu_loff[HAMMER2_MAX_VOLUMES]; /* * sector #8-71 - 32768 bytes @@ -1232,10 +1272,6 @@ struct hammer2_volume_data { * specify local and remote copies operating as masters or slaves. * copyid's 0 and 255 are reserved (0 indicates an empty slot and 255 * indicates the local media). - * - * Each inode contains a set of up to 8 copyids, either inherited - * from its parent or explicitly specified in the inode, which - * indexes into this array. */ /* 1000-8FFF copyinfo config */ hammer2_volconf_t copyinfo[HAMMER2_COPYID_COUNT]; @@ -1279,9 +1315,11 @@ typedef struct hammer2_volume_data hamme #define HAMMER2_VOLUME_ICRC1_SIZE (512) #define HAMMER2_VOLUME_ICRCVH_SIZE (65536 - 4) +#define HAMMER2_VOL_VERSION_MULTI_VOLUMES 2 + #define HAMMER2_VOL_VERSION_MIN 1 -#define HAMMER2_VOL_VERSION_DEFAULT 1 -#define HAMMER2_VOL_VERSION_WIP 2 +#define HAMMER2_VOL_VERSION_DEFAULT HAMMER2_VOL_VERSION_MULTI_VOLUMES +#define HAMMER2_VOL_VERSION_WIP (HAMMER2_VOL_VERSION_MULTI_VOLUMES + 1) #define HAMMER2_NUM_VOLHDRS 4