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
 

Reply via email to