12d60b848STomohiro Kusumi /*
22d60b848STomohiro Kusumi  * SPDX-License-Identifier: BSD-3-Clause
32d60b848STomohiro Kusumi  *
42d60b848STomohiro Kusumi  * Copyright (c) 2022 Tomohiro Kusumi <tkusumi@netbsd.org>
52d60b848STomohiro Kusumi  * Copyright (c) 2011-2022 The DragonFly Project.  All rights reserved.
62d60b848STomohiro Kusumi  *
72d60b848STomohiro Kusumi  * This code is derived from software contributed to The DragonFly Project
82d60b848STomohiro Kusumi  * by Matthew Dillon <dillon@dragonflybsd.org>
92d60b848STomohiro Kusumi  *
102d60b848STomohiro Kusumi  * Redistribution and use in source and binary forms, with or without
112d60b848STomohiro Kusumi  * modification, are permitted provided that the following conditions
122d60b848STomohiro Kusumi  * are met:
132d60b848STomohiro Kusumi  *
142d60b848STomohiro Kusumi  * 1. Redistributions of source code must retain the above copyright
152d60b848STomohiro Kusumi  *    notice, this list of conditions and the following disclaimer.
162d60b848STomohiro Kusumi  * 2. Redistributions in binary form must reproduce the above copyright
172d60b848STomohiro Kusumi  *    notice, this list of conditions and the following disclaimer in
182d60b848STomohiro Kusumi  *    the documentation and/or other materials provided with the
192d60b848STomohiro Kusumi  *    distribution.
202d60b848STomohiro Kusumi  * 3. Neither the name of The DragonFly Project nor the names of its
212d60b848STomohiro Kusumi  *    contributors may be used to endorse or promote products derived
222d60b848STomohiro Kusumi  *    from this software without specific, prior written permission.
232d60b848STomohiro Kusumi  *
242d60b848STomohiro Kusumi  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
252d60b848STomohiro Kusumi  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
262d60b848STomohiro Kusumi  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
272d60b848STomohiro Kusumi  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
282d60b848STomohiro Kusumi  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
292d60b848STomohiro Kusumi  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
302d60b848STomohiro Kusumi  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
312d60b848STomohiro Kusumi  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
322d60b848STomohiro Kusumi  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
332d60b848STomohiro Kusumi  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
342d60b848STomohiro Kusumi  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
352d60b848STomohiro Kusumi  * SUCH DAMAGE.
362d60b848STomohiro Kusumi  */
372d60b848STomohiro Kusumi /*
382d60b848STomohiro Kusumi #include <sys/param.h>
392d60b848STomohiro Kusumi #include <sys/systm.h>
402d60b848STomohiro Kusumi #include <sys/kernel.h>
412d60b848STomohiro Kusumi #include <sys/queue.h>
422d60b848STomohiro Kusumi #include <sys/nlookup.h>
432d60b848STomohiro Kusumi #include <sys/vnode.h>
442d60b848STomohiro Kusumi #include <sys/mount.h>
452d60b848STomohiro Kusumi #include <sys/buf.h>
462d60b848STomohiro Kusumi #include <sys/uuid.h>
472d60b848STomohiro Kusumi #include <sys/objcache.h>
482d60b848STomohiro Kusumi #include <sys/lock.h>
492d60b848STomohiro Kusumi */
50a63188c8STomohiro Kusumi #include <sys/diskslice.h>
512d60b848STomohiro Kusumi 
522d60b848STomohiro Kusumi #include "hammer2.h"
532d60b848STomohiro Kusumi #include "makefs.h"
542d60b848STomohiro Kusumi 
552d60b848STomohiro Kusumi #define hprintf(X, ...)	kprintf("hammer2_ondisk: " X, ## __VA_ARGS__)
562d60b848STomohiro Kusumi 
572d60b848STomohiro Kusumi #if 0
582d60b848STomohiro Kusumi static int
596bcbb706STomohiro Kusumi hammer2_lookup_device(const char *path, int rootmount, struct m_vnode **devvp)
602d60b848STomohiro Kusumi {
616bcbb706STomohiro Kusumi 	struct m_vnode *vp = NULL;
622d60b848STomohiro Kusumi 	struct nlookupdata nd;
632d60b848STomohiro Kusumi 	int error = 0;
642d60b848STomohiro Kusumi 
652d60b848STomohiro Kusumi 	KKASSERT(path);
662d60b848STomohiro Kusumi 	KKASSERT(*path != '\0');
672d60b848STomohiro Kusumi 
682d60b848STomohiro Kusumi 	if (rootmount) {
692d60b848STomohiro Kusumi 		error = bdevvp(kgetdiskbyname(path), &vp);
702d60b848STomohiro Kusumi 		if (error)
712d60b848STomohiro Kusumi 			hprintf("cannot find %s %d\n", path, error);
722d60b848STomohiro Kusumi 	} else {
732d60b848STomohiro Kusumi 		error = nlookup_init(&nd, path, UIO_SYSSPACE, NLC_FOLLOW);
742d60b848STomohiro Kusumi 		if (error == 0)
752d60b848STomohiro Kusumi 			error = nlookup(&nd);
762d60b848STomohiro Kusumi 		if (error == 0)
772d60b848STomohiro Kusumi 			error = cache_vref(&nd.nl_nch, nd.nl_cred, &vp);
782d60b848STomohiro Kusumi 		if (error)
792d60b848STomohiro Kusumi 			hprintf("failed to nlookup %s %d\n", path, error);
802d60b848STomohiro Kusumi 		nlookup_done(&nd);
812d60b848STomohiro Kusumi 	}
822d60b848STomohiro Kusumi 
832d60b848STomohiro Kusumi 	if (error == 0) {
842d60b848STomohiro Kusumi 		KKASSERT(vp);
852d60b848STomohiro Kusumi 		if (!vn_isdisk(vp, &error)) {
862d60b848STomohiro Kusumi 			KKASSERT(error);
872d60b848STomohiro Kusumi 			hprintf("%s not a block device %d\n", path, error);
882d60b848STomohiro Kusumi 		}
892d60b848STomohiro Kusumi 	}
902d60b848STomohiro Kusumi 
912d60b848STomohiro Kusumi 	if (error && vp) {
922d60b848STomohiro Kusumi 		vrele(vp);
932d60b848STomohiro Kusumi 		vp = NULL;
942d60b848STomohiro Kusumi 	}
952d60b848STomohiro Kusumi 
962d60b848STomohiro Kusumi 	*devvp = vp;
972d60b848STomohiro Kusumi 	return error;
982d60b848STomohiro Kusumi }
992d60b848STomohiro Kusumi #endif
1002d60b848STomohiro Kusumi 
1012d60b848STomohiro Kusumi int
hammer2_open_devvp(const hammer2_devvp_list_t * devvpl,int ronly)1022d60b848STomohiro Kusumi hammer2_open_devvp(const hammer2_devvp_list_t *devvpl, int ronly)
1032d60b848STomohiro Kusumi {
1042d60b848STomohiro Kusumi #if 0
1052d60b848STomohiro Kusumi 	hammer2_devvp_t *e;
1066bcbb706STomohiro Kusumi 	struct m_vnode *devvp;
1072d60b848STomohiro Kusumi 	const char *path;
1082d60b848STomohiro Kusumi 	int count, error;
1092d60b848STomohiro Kusumi 
1102d60b848STomohiro Kusumi 	TAILQ_FOREACH(e, devvpl, entry) {
1112d60b848STomohiro Kusumi 		devvp = e->devvp;
1122d60b848STomohiro Kusumi 		path = e->path;
1132d60b848STomohiro Kusumi 		KKASSERT(devvp);
1142d60b848STomohiro Kusumi 		count = vcount(devvp);
1152d60b848STomohiro Kusumi 		if (count > 0) {
1162d60b848STomohiro Kusumi 			hprintf("%s already has %d references\n", path, count);
1172d60b848STomohiro Kusumi 			return EBUSY;
1182d60b848STomohiro Kusumi 		}
1192d60b848STomohiro Kusumi 		vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY);
1202d60b848STomohiro Kusumi 		error = vinvalbuf(devvp, V_SAVE, 0, 0);
1212d60b848STomohiro Kusumi 		if (error == 0) {
1222d60b848STomohiro Kusumi 			KKASSERT(!e->open);
1232d60b848STomohiro Kusumi 			error = VOP_OPEN(devvp, (ronly ? FREAD : FREAD|FWRITE),
1242d60b848STomohiro Kusumi 					 FSCRED, NULL);
1252d60b848STomohiro Kusumi 			if (error == 0)
1262d60b848STomohiro Kusumi 				e->open = 1;
1272d60b848STomohiro Kusumi 			else
1282d60b848STomohiro Kusumi 				hprintf("failed to open %s %d\n", path, error);
1292d60b848STomohiro Kusumi 		}
1302d60b848STomohiro Kusumi 		vn_unlock(devvp);
1312d60b848STomohiro Kusumi 		if (error)
1322d60b848STomohiro Kusumi 			return error;
1332d60b848STomohiro Kusumi 		KKASSERT(e->open);
1342d60b848STomohiro Kusumi 	}
1352d60b848STomohiro Kusumi #endif
1362d60b848STomohiro Kusumi 
1372d60b848STomohiro Kusumi 	return 0;
1382d60b848STomohiro Kusumi }
1392d60b848STomohiro Kusumi 
1402d60b848STomohiro Kusumi int
hammer2_close_devvp(const hammer2_devvp_list_t * devvpl,int ronly)1412d60b848STomohiro Kusumi hammer2_close_devvp(const hammer2_devvp_list_t *devvpl, int ronly)
1422d60b848STomohiro Kusumi {
1432d60b848STomohiro Kusumi #if 0
1442d60b848STomohiro Kusumi 	hammer2_devvp_t *e;
1456bcbb706STomohiro Kusumi 	struct m_vnode *devvp;
1462d60b848STomohiro Kusumi 
1472d60b848STomohiro Kusumi 	TAILQ_FOREACH(e, devvpl, entry) {
1482d60b848STomohiro Kusumi 		devvp = e->devvp;
1492d60b848STomohiro Kusumi 		KKASSERT(devvp);
1502d60b848STomohiro Kusumi 		if (e->open) {
1512d60b848STomohiro Kusumi 			vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY);
1522d60b848STomohiro Kusumi 			vinvalbuf(devvp, (ronly ? 0 : V_SAVE), 0, 0);
1532d60b848STomohiro Kusumi 			VOP_CLOSE(devvp, (ronly ? FREAD : FREAD|FWRITE), NULL);
1542d60b848STomohiro Kusumi 			vn_unlock(devvp);
1552d60b848STomohiro Kusumi 			e->open = 0;
1562d60b848STomohiro Kusumi 		}
1572d60b848STomohiro Kusumi 	}
1582d60b848STomohiro Kusumi #endif
1592d60b848STomohiro Kusumi 
1602d60b848STomohiro Kusumi 	return 0;
1612d60b848STomohiro Kusumi }
1622d60b848STomohiro Kusumi 
1632d60b848STomohiro Kusumi int
hammer2_init_devvp(struct m_vnode * devvp,hammer2_devvp_list_t * devvpl)1646bcbb706STomohiro Kusumi hammer2_init_devvp(struct m_vnode *devvp, hammer2_devvp_list_t *devvpl)
1652d60b848STomohiro Kusumi {
1662d60b848STomohiro Kusumi 	hammer2_devvp_t *e;
1672d60b848STomohiro Kusumi 	int error = 0;
1682d60b848STomohiro Kusumi 
1692d60b848STomohiro Kusumi 	while (1) {
1702d60b848STomohiro Kusumi 		KKASSERT(devvp);
1712d60b848STomohiro Kusumi 		e = kmalloc(sizeof(*e), M_HAMMER2, M_WAITOK | M_ZERO);
1722d60b848STomohiro Kusumi 		e->devvp = devvp;
1732d60b848STomohiro Kusumi 		TAILQ_INSERT_TAIL(devvpl, e, entry);
1742d60b848STomohiro Kusumi 		break;
1752d60b848STomohiro Kusumi 	}
1762d60b848STomohiro Kusumi 
1772d60b848STomohiro Kusumi 	return error;
1782d60b848STomohiro Kusumi }
1792d60b848STomohiro Kusumi 
1802d60b848STomohiro Kusumi void
hammer2_cleanup_devvp(hammer2_devvp_list_t * devvpl)1812d60b848STomohiro Kusumi hammer2_cleanup_devvp(hammer2_devvp_list_t *devvpl)
1822d60b848STomohiro Kusumi {
1832d60b848STomohiro Kusumi 	hammer2_devvp_t *e;
1842d60b848STomohiro Kusumi 
1852d60b848STomohiro Kusumi 	while (!TAILQ_EMPTY(devvpl)) {
1862d60b848STomohiro Kusumi 		e = TAILQ_FIRST(devvpl);
1872d60b848STomohiro Kusumi 		TAILQ_REMOVE(devvpl, e, entry);
1882d60b848STomohiro Kusumi 		/* devvp */
1892d60b848STomohiro Kusumi 		KKASSERT(e->devvp);
1902d60b848STomohiro Kusumi 		/*
1912d60b848STomohiro Kusumi 		if (e->devvp->v_rdev)
1922d60b848STomohiro Kusumi 			e->devvp->v_rdev->si_mountpoint = NULL;
1932d60b848STomohiro Kusumi 		*/
1942d60b848STomohiro Kusumi 		vrele(e->devvp);
1952d60b848STomohiro Kusumi 		e->devvp = NULL;
1962d60b848STomohiro Kusumi 		/* path */
1972d60b848STomohiro Kusumi 		/*
1982d60b848STomohiro Kusumi 		KKASSERT(e->path);
1992d60b848STomohiro Kusumi 		kfree(e->path, M_HAMMER2);
2002d60b848STomohiro Kusumi 		*/
2012d60b848STomohiro Kusumi 		e->path = NULL;
2022d60b848STomohiro Kusumi 		kfree(e, M_HAMMER2);
2032d60b848STomohiro Kusumi 	}
2042d60b848STomohiro Kusumi }
2052d60b848STomohiro Kusumi 
2062d60b848STomohiro Kusumi static int
hammer2_verify_volumes_common(const hammer2_vfsvolume_t * volumes)2072d60b848STomohiro Kusumi hammer2_verify_volumes_common(const hammer2_vfsvolume_t *volumes)
2082d60b848STomohiro Kusumi {
2092d60b848STomohiro Kusumi 	const hammer2_vfsvolume_t *vol;
210a63188c8STomohiro Kusumi 	struct partinfo part;
2112d60b848STomohiro Kusumi 	struct stat st;
2122d60b848STomohiro Kusumi 	const char *path;
2133bbcb743STomohiro Kusumi 	int i;
2142d60b848STomohiro Kusumi 
2152d60b848STomohiro Kusumi 	for (i = 0; i < HAMMER2_MAX_VOLUMES; ++i) {
2162d60b848STomohiro Kusumi 		vol = &volumes[i];
2172d60b848STomohiro Kusumi 		if (vol->id == -1)
2182d60b848STomohiro Kusumi 			continue;
2192d60b848STomohiro Kusumi 		path = vol->dev->path;
2202d60b848STomohiro Kusumi 		/* check volume fields are initialized */
2212d60b848STomohiro Kusumi 		if (!vol->dev->devvp) {
2222d60b848STomohiro Kusumi 			hprintf("%s has NULL devvp\n", path);
2232d60b848STomohiro Kusumi 			return EINVAL;
2242d60b848STomohiro Kusumi 		}
2252d60b848STomohiro Kusumi 		if (vol->offset == (hammer2_off_t)-1) {
2262d60b848STomohiro Kusumi 			hprintf("%s has bad offset 0x%016jx\n", path,
2272d60b848STomohiro Kusumi 				(intmax_t)vol->offset);
2282d60b848STomohiro Kusumi 			return EINVAL;
2292d60b848STomohiro Kusumi 		}
2302d60b848STomohiro Kusumi 		if (vol->size == (hammer2_off_t)-1) {
2312d60b848STomohiro Kusumi 			hprintf("%s has bad size 0x%016jx\n", path,
2322d60b848STomohiro Kusumi 				(intmax_t)vol->size);
2332d60b848STomohiro Kusumi 			return EINVAL;
2342d60b848STomohiro Kusumi 		}
2352d60b848STomohiro Kusumi 		/* check volume size vs block device size */
2362d60b848STomohiro Kusumi 		/*
2372d60b848STomohiro Kusumi 		if (VOP_IOCTL(vol->dev->devvp, DIOCGPART, (void*)&part, 0,
2382d60b848STomohiro Kusumi 			      curthread->td_ucred , NULL) == 0) {
2392d60b848STomohiro Kusumi 		*/
2402d60b848STomohiro Kusumi 		assert(vol->dev->devvp->fs);
2413bbcb743STomohiro Kusumi 		if (ioctl(vol->dev->devvp->fs->fd, DIOCGPART, &part) == 0) {
242a63188c8STomohiro Kusumi 			assert(part.media_blksize <= HAMMER2_PBUFSIZE);
243a63188c8STomohiro Kusumi 			assert(HAMMER2_PBUFSIZE % part.media_blksize == 0);
244a63188c8STomohiro Kusumi 			if (vol->size > part.media_size) {
245a63188c8STomohiro Kusumi 				hprintf("%s's size 0x%016jx exceeds "
246a63188c8STomohiro Kusumi 					"device size 0x%016jx\n",
247a63188c8STomohiro Kusumi 					path, (intmax_t)vol->size,
248a63188c8STomohiro Kusumi 					part.media_size);
249a63188c8STomohiro Kusumi 				return EINVAL;
250a63188c8STomohiro Kusumi 			}
2513bbcb743STomohiro Kusumi 		} else if (fstat(vol->dev->devvp->fs->fd, &st) == 0) {
2523bbcb743STomohiro Kusumi 			if (vol->size > st.st_size) {
2533bbcb743STomohiro Kusumi 				hprintf("%s's size 0x%016jx exceeds "
2543bbcb743STomohiro Kusumi 					"file size 0x%016jx\n",
2553bbcb743STomohiro Kusumi 					path, (intmax_t)vol->size,
2563bbcb743STomohiro Kusumi 					st.st_size);
2573bbcb743STomohiro Kusumi 				return EINVAL;
2583bbcb743STomohiro Kusumi 			}
2593bbcb743STomohiro Kusumi 		} else {
2603bbcb743STomohiro Kusumi 			hprintf("failed to get %s size\n", path);
2613bbcb743STomohiro Kusumi 			return EINVAL;
262a63188c8STomohiro Kusumi 		}
2632d60b848STomohiro Kusumi 	}
2642d60b848STomohiro Kusumi 
2652d60b848STomohiro Kusumi 	return 0;
2662d60b848STomohiro Kusumi }
2672d60b848STomohiro Kusumi 
2682d60b848STomohiro Kusumi static int
hammer2_verify_volumes_1(const hammer2_vfsvolume_t * volumes,const hammer2_volume_data_t * rootvoldata)2692d60b848STomohiro Kusumi hammer2_verify_volumes_1(const hammer2_vfsvolume_t *volumes,
2702d60b848STomohiro Kusumi 		         const hammer2_volume_data_t *rootvoldata)
2712d60b848STomohiro Kusumi {
2722d60b848STomohiro Kusumi 	const hammer2_vfsvolume_t *vol;
2732d60b848STomohiro Kusumi 	hammer2_off_t off;
2742d60b848STomohiro Kusumi 	const char *path;
2752d60b848STomohiro Kusumi 	int i, nvolumes = 0;
2762d60b848STomohiro Kusumi 
2772d60b848STomohiro Kusumi 	/* check initialized volume count */
2782d60b848STomohiro Kusumi 	for (i = 0; i < HAMMER2_MAX_VOLUMES; ++i) {
2792d60b848STomohiro Kusumi 		vol = &volumes[i];
2802d60b848STomohiro Kusumi 		if (vol->id != -1)
2812d60b848STomohiro Kusumi 			nvolumes++;
2822d60b848STomohiro Kusumi 	}
2832d60b848STomohiro Kusumi 	if (nvolumes != 1) {
2842d60b848STomohiro Kusumi 		hprintf("only 1 volume supported\n");
2852d60b848STomohiro Kusumi 		return EINVAL;
2862d60b848STomohiro Kusumi 	}
2872d60b848STomohiro Kusumi 
2882d60b848STomohiro Kusumi 	/* check volume header */
2892d60b848STomohiro Kusumi 	if (rootvoldata->volu_id) {
2902d60b848STomohiro Kusumi 		hprintf("volume id %d must be 0\n", rootvoldata->volu_id);
2912d60b848STomohiro Kusumi 		return EINVAL;
2922d60b848STomohiro Kusumi 	}
2932d60b848STomohiro Kusumi 	if (rootvoldata->nvolumes) {
2942d60b848STomohiro Kusumi 		hprintf("volume count %d must be 0\n", rootvoldata->nvolumes);
2952d60b848STomohiro Kusumi 		return EINVAL;
2962d60b848STomohiro Kusumi 	}
2972d60b848STomohiro Kusumi 	if (rootvoldata->total_size) {
2982d60b848STomohiro Kusumi 		hprintf("total size 0x%016jx must be 0\n",
2992d60b848STomohiro Kusumi 			(intmax_t)rootvoldata->total_size);
3002d60b848STomohiro Kusumi 		return EINVAL;
3012d60b848STomohiro Kusumi 	}
3022d60b848STomohiro Kusumi 	for (i = 0; i < HAMMER2_MAX_VOLUMES; ++i) {
3032d60b848STomohiro Kusumi 		off = rootvoldata->volu_loff[i];
3042d60b848STomohiro Kusumi 		if (off) {
3052d60b848STomohiro Kusumi 			hprintf("volume offset[%d] 0x%016jx must be 0\n", i,
3062d60b848STomohiro Kusumi 				(intmax_t)off);
3072d60b848STomohiro Kusumi 			return EINVAL;
3082d60b848STomohiro Kusumi 		}
3092d60b848STomohiro Kusumi 	}
3102d60b848STomohiro Kusumi 
3112d60b848STomohiro Kusumi 	/* check volume */
312a0373a75STomohiro Kusumi 	vol = &volumes[HAMMER2_ROOT_VOLUME];
3132d60b848STomohiro Kusumi 	path = vol->dev->path;
3142d60b848STomohiro Kusumi 	if (vol->id) {
3152d60b848STomohiro Kusumi 		hprintf("%s has non zero id %d\n", path, vol->id);
3162d60b848STomohiro Kusumi 		return EINVAL;
3172d60b848STomohiro Kusumi 	}
3182d60b848STomohiro Kusumi 	if (vol->offset) {
3192d60b848STomohiro Kusumi 		hprintf("%s has non zero offset 0x%016jx\n", path,
3202d60b848STomohiro Kusumi 			(intmax_t)vol->offset);
3212d60b848STomohiro Kusumi 		return EINVAL;
3222d60b848STomohiro Kusumi 	}
3232d60b848STomohiro Kusumi 	if (vol->size & HAMMER2_VOLUME_ALIGNMASK64) {
3242d60b848STomohiro Kusumi 		hprintf("%s's size is not 0x%016jx aligned\n", path,
3252d60b848STomohiro Kusumi 			(intmax_t)HAMMER2_VOLUME_ALIGN);
3262d60b848STomohiro Kusumi 		return EINVAL;
3272d60b848STomohiro Kusumi 	}
3282d60b848STomohiro Kusumi 
3292d60b848STomohiro Kusumi 	return 0;
3302d60b848STomohiro Kusumi }
3312d60b848STomohiro Kusumi 
3322d60b848STomohiro Kusumi static int
hammer2_verify_volumes_2(const hammer2_vfsvolume_t * volumes,const hammer2_volume_data_t * rootvoldata)3332d60b848STomohiro Kusumi hammer2_verify_volumes_2(const hammer2_vfsvolume_t *volumes,
3342d60b848STomohiro Kusumi 		         const hammer2_volume_data_t *rootvoldata)
3352d60b848STomohiro Kusumi {
3362d60b848STomohiro Kusumi 	const hammer2_vfsvolume_t *vol;
3372d60b848STomohiro Kusumi 	hammer2_off_t off, total_size = 0;
3382d60b848STomohiro Kusumi 	const char *path;
3392d60b848STomohiro Kusumi 	int i, nvolumes = 0;
3402d60b848STomohiro Kusumi 
3412d60b848STomohiro Kusumi 	/* check initialized volume count */
3422d60b848STomohiro Kusumi 	for (i = 0; i < HAMMER2_MAX_VOLUMES; ++i) {
3432d60b848STomohiro Kusumi 		vol = &volumes[i];
3442d60b848STomohiro Kusumi 		if (vol->id != -1) {
3452d60b848STomohiro Kusumi 			nvolumes++;
3462d60b848STomohiro Kusumi 			total_size += vol->size;
3472d60b848STomohiro Kusumi 		}
3482d60b848STomohiro Kusumi 	}
3492d60b848STomohiro Kusumi 
3502d60b848STomohiro Kusumi 	/* check volume header */
3512d60b848STomohiro Kusumi 	if (rootvoldata->volu_id != HAMMER2_ROOT_VOLUME) {
3522d60b848STomohiro Kusumi 		hprintf("volume id %d must be %d\n", rootvoldata->volu_id,
3532d60b848STomohiro Kusumi 			HAMMER2_ROOT_VOLUME);
3542d60b848STomohiro Kusumi 		return EINVAL;
3552d60b848STomohiro Kusumi 	}
3562d60b848STomohiro Kusumi 	if (rootvoldata->nvolumes != nvolumes) {
3572d60b848STomohiro Kusumi 		hprintf("volume header requires %d devices, %d specified\n",
3582d60b848STomohiro Kusumi 			rootvoldata->nvolumes, nvolumes);
3592d60b848STomohiro Kusumi 		return EINVAL;
3602d60b848STomohiro Kusumi 	}
3612d60b848STomohiro Kusumi 	if (rootvoldata->total_size != total_size) {
3622d60b848STomohiro Kusumi 		hprintf("total size 0x%016jx does not equal sum of volumes 0x%016jx\n",
3632d60b848STomohiro Kusumi 			rootvoldata->total_size, total_size);
3642d60b848STomohiro Kusumi 		return EINVAL;
3652d60b848STomohiro Kusumi 	}
3662d60b848STomohiro Kusumi 	for (i = 0; i < nvolumes; ++i) {
3672d60b848STomohiro Kusumi 		off = rootvoldata->volu_loff[i];
3682d60b848STomohiro Kusumi 		if (off == (hammer2_off_t)-1) {
3692d60b848STomohiro Kusumi 			hprintf("volume offset[%d] 0x%016jx must not be -1\n",
3702d60b848STomohiro Kusumi 				i, (intmax_t)off);
3712d60b848STomohiro Kusumi 			return EINVAL;
3722d60b848STomohiro Kusumi 		}
3732d60b848STomohiro Kusumi 	}
3742d60b848STomohiro Kusumi 	for (i = nvolumes; i < HAMMER2_MAX_VOLUMES; ++i) {
3752d60b848STomohiro Kusumi 		off = rootvoldata->volu_loff[i];
3762d60b848STomohiro Kusumi 		if (off != (hammer2_off_t)-1) {
3772d60b848STomohiro Kusumi 			hprintf("volume offset[%d] 0x%016jx must be -1\n",
3782d60b848STomohiro Kusumi 				i, (intmax_t)off);
3792d60b848STomohiro Kusumi 			return EINVAL;
3802d60b848STomohiro Kusumi 		}
3812d60b848STomohiro Kusumi 	}
3822d60b848STomohiro Kusumi 
3832d60b848STomohiro Kusumi 	/* check volumes */
3842d60b848STomohiro Kusumi 	for (i = 0; i < HAMMER2_MAX_VOLUMES; ++i) {
3852d60b848STomohiro Kusumi 		vol = &volumes[i];
3862d60b848STomohiro Kusumi 		if (vol->id == -1)
3872d60b848STomohiro Kusumi 			continue;
3882d60b848STomohiro Kusumi 		path = vol->dev->path;
3892d60b848STomohiro Kusumi 		/* check offset */
3902d60b848STomohiro Kusumi 		if (vol->offset & HAMMER2_FREEMAP_LEVEL1_MASK) {
3912d60b848STomohiro Kusumi 			hprintf("%s's offset 0x%016jx not 0x%016jx aligned\n",
3922d60b848STomohiro Kusumi 				path, (intmax_t)vol->offset,
3932d60b848STomohiro Kusumi 				HAMMER2_FREEMAP_LEVEL1_SIZE);
3942d60b848STomohiro Kusumi 			return EINVAL;
3952d60b848STomohiro Kusumi 		}
3962d60b848STomohiro Kusumi 		/* check vs previous volume */
3972d60b848STomohiro Kusumi 		if (i) {
3982d60b848STomohiro Kusumi 			if (vol->id <= (vol-1)->id) {
3992d60b848STomohiro Kusumi 				hprintf("%s has inconsistent id %d\n", path,
4002d60b848STomohiro Kusumi 					vol->id);
4012d60b848STomohiro Kusumi 				return EINVAL;
4022d60b848STomohiro Kusumi 			}
4032d60b848STomohiro Kusumi 			if (vol->offset != (vol-1)->offset + (vol-1)->size) {
4042d60b848STomohiro Kusumi 				hprintf("%s has inconsistent offset 0x%016jx\n",
4052d60b848STomohiro Kusumi 					path, (intmax_t)vol->offset);
4062d60b848STomohiro Kusumi 				return EINVAL;
4072d60b848STomohiro Kusumi 			}
4082d60b848STomohiro Kusumi 		} else { /* first */
4092d60b848STomohiro Kusumi 			if (vol->offset) {
4102d60b848STomohiro Kusumi 				hprintf("%s has non zero offset 0x%016jx\n",
4112d60b848STomohiro Kusumi 					path, (intmax_t)vol->offset);
4122d60b848STomohiro Kusumi 				return EINVAL;
4132d60b848STomohiro Kusumi 			}
4142d60b848STomohiro Kusumi 		}
4152d60b848STomohiro Kusumi 		/* check size for non-last and last volumes */
4162d60b848STomohiro Kusumi 		if (i != rootvoldata->nvolumes - 1) {
4172d60b848STomohiro Kusumi 			if (vol->size < HAMMER2_FREEMAP_LEVEL1_SIZE) {
4182d60b848STomohiro Kusumi 				hprintf("%s's size must be >= 0x%016jx\n", path,
4192d60b848STomohiro Kusumi 					(intmax_t)HAMMER2_FREEMAP_LEVEL1_SIZE);
4202d60b848STomohiro Kusumi 				return EINVAL;
4212d60b848STomohiro Kusumi 			}
4222d60b848STomohiro Kusumi 			if (vol->size & HAMMER2_FREEMAP_LEVEL1_MASK) {
4232d60b848STomohiro Kusumi 				hprintf("%s's size is not 0x%016jx aligned\n",
4242d60b848STomohiro Kusumi 					path,
4252d60b848STomohiro Kusumi 					(intmax_t)HAMMER2_FREEMAP_LEVEL1_SIZE);
4262d60b848STomohiro Kusumi 				return EINVAL;
4272d60b848STomohiro Kusumi 			}
4282d60b848STomohiro Kusumi 		} else { /* last */
4292d60b848STomohiro Kusumi 			if (vol->size & HAMMER2_VOLUME_ALIGNMASK64) {
4302d60b848STomohiro Kusumi 				hprintf("%s's size is not 0x%016jx aligned\n",
4312d60b848STomohiro Kusumi 					path,
4322d60b848STomohiro Kusumi 					(intmax_t)HAMMER2_VOLUME_ALIGN);
4332d60b848STomohiro Kusumi 				return EINVAL;
4342d60b848STomohiro Kusumi 			}
4352d60b848STomohiro Kusumi 		}
4362d60b848STomohiro Kusumi 	}
4372d60b848STomohiro Kusumi 
4382d60b848STomohiro Kusumi 	return 0;
4392d60b848STomohiro Kusumi }
4402d60b848STomohiro Kusumi 
4412d60b848STomohiro Kusumi static int
hammer2_verify_vfsvolumes(const hammer2_vfsvolume_t * volumes,const hammer2_volume_data_t * rootvoldata)4422d60b848STomohiro Kusumi hammer2_verify_vfsvolumes(const hammer2_vfsvolume_t *volumes,
4432d60b848STomohiro Kusumi 		       const hammer2_volume_data_t *rootvoldata)
4442d60b848STomohiro Kusumi {
4452d60b848STomohiro Kusumi 	int error;
4462d60b848STomohiro Kusumi 
4472d60b848STomohiro Kusumi 	error = hammer2_verify_volumes_common(volumes);
4482d60b848STomohiro Kusumi 	if (error)
4492d60b848STomohiro Kusumi 		return error;
4502d60b848STomohiro Kusumi 
4512d60b848STomohiro Kusumi 	if (rootvoldata->version >= HAMMER2_VOL_VERSION_MULTI_VOLUMES)
4522d60b848STomohiro Kusumi 		return hammer2_verify_volumes_2(volumes, rootvoldata);
4532d60b848STomohiro Kusumi 	else
4542d60b848STomohiro Kusumi 		return hammer2_verify_volumes_1(volumes, rootvoldata);
4552d60b848STomohiro Kusumi }
4562d60b848STomohiro Kusumi 
4572d60b848STomohiro Kusumi /*
4582d60b848STomohiro Kusumi  * Returns zone# of returned volume header or < 0 on failure.
4592d60b848STomohiro Kusumi  */
4602d60b848STomohiro Kusumi static int
hammer2_read_volume_header(struct m_vnode * devvp,const char * path,hammer2_volume_data_t * voldata)4616bcbb706STomohiro Kusumi hammer2_read_volume_header(struct m_vnode *devvp, const char *path,
4622d60b848STomohiro Kusumi 			   hammer2_volume_data_t *voldata)
4632d60b848STomohiro Kusumi {
4642d60b848STomohiro Kusumi 	hammer2_volume_data_t *vd;
4654e2eefe9STomohiro Kusumi 	struct m_buf *bp = NULL;
4662d60b848STomohiro Kusumi 	hammer2_crc32_t crc0, crc1;
467*764bf12eSTomohiro Kusumi 	hammer2_off_t size = check_volume(devvp->fs->fd);
468*764bf12eSTomohiro Kusumi 	off_t blkoff;
4692d60b848STomohiro Kusumi 	int zone = -1;
4702d60b848STomohiro Kusumi 	int i;
4712d60b848STomohiro Kusumi 
4722d60b848STomohiro Kusumi 	/*
4732d60b848STomohiro Kusumi 	 * There are up to 4 copies of the volume header (syncs iterate
4742d60b848STomohiro Kusumi 	 * between them so there is no single master).  We don't trust the
4752d60b848STomohiro Kusumi 	 * volu_size field so we don't know precisely how large the filesystem
4762d60b848STomohiro Kusumi 	 * is, so depend on the OS to return an error if we go beyond the
4772d60b848STomohiro Kusumi 	 * block device's EOF.
4782d60b848STomohiro Kusumi 	 */
4792d60b848STomohiro Kusumi 	for (i = 0; i < HAMMER2_NUM_VOLHDRS; ++i) {
480*764bf12eSTomohiro Kusumi 		/* ignore if blkoff is beyond media size */
481*764bf12eSTomohiro Kusumi 		blkoff = (off_t)i * HAMMER2_ZONE_BYTES64;
482*764bf12eSTomohiro Kusumi 		if (blkoff >= (off_t)size)
483*764bf12eSTomohiro Kusumi 			continue;
484*764bf12eSTomohiro Kusumi 
4852d60b848STomohiro Kusumi 		if (breadx(devvp, i * HAMMER2_ZONE_BYTES64, HAMMER2_VOLUME_BYTES,
4862d60b848STomohiro Kusumi 			  &bp)) {
4872d60b848STomohiro Kusumi 			brelse(bp);
4882d60b848STomohiro Kusumi 			bp = NULL;
4892d60b848STomohiro Kusumi 			continue;
4902d60b848STomohiro Kusumi 		}
4912d60b848STomohiro Kusumi 
4922d60b848STomohiro Kusumi 		vd = (struct hammer2_volume_data *)bp->b_data;
4932d60b848STomohiro Kusumi 		/* verify volume header magic */
4942d60b848STomohiro Kusumi 		if ((vd->magic != HAMMER2_VOLUME_ID_HBO) &&
4952d60b848STomohiro Kusumi 		    (vd->magic != HAMMER2_VOLUME_ID_ABO)) {
4962d60b848STomohiro Kusumi 			hprintf("%s #%d: bad magic\n", path, i);
4972d60b848STomohiro Kusumi 			brelse(bp);
4982d60b848STomohiro Kusumi 			bp = NULL;
4992d60b848STomohiro Kusumi 			continue;
5002d60b848STomohiro Kusumi 		}
5012d60b848STomohiro Kusumi 
5022d60b848STomohiro Kusumi 		if (vd->magic == HAMMER2_VOLUME_ID_ABO) {
5032d60b848STomohiro Kusumi 			/* XXX: Reversed-endianness filesystem */
5042d60b848STomohiro Kusumi 			hprintf("%s #%d: reverse-endian filesystem detected\n",
5052d60b848STomohiro Kusumi 				path, i);
5062d60b848STomohiro Kusumi 			brelse(bp);
5072d60b848STomohiro Kusumi 			bp = NULL;
5082d60b848STomohiro Kusumi 			continue;
5092d60b848STomohiro Kusumi 		}
5102d60b848STomohiro Kusumi 
5112d60b848STomohiro Kusumi 		/* verify volume header CRC's */
5122d60b848STomohiro Kusumi 		crc0 = vd->icrc_sects[HAMMER2_VOL_ICRC_SECT0];
513a0373a75STomohiro Kusumi 		crc1 = hammer2_icrc32(bp->b_data + HAMMER2_VOLUME_ICRC0_OFF,
5142d60b848STomohiro Kusumi 				      HAMMER2_VOLUME_ICRC0_SIZE);
5152d60b848STomohiro Kusumi 		if (crc0 != crc1) {
5162d60b848STomohiro Kusumi 			hprintf("%s #%d: volume header crc mismatch sect0 %08x/%08x\n",
5172d60b848STomohiro Kusumi 				path, i, crc0, crc1);
5182d60b848STomohiro Kusumi 			brelse(bp);
5192d60b848STomohiro Kusumi 			bp = NULL;
5202d60b848STomohiro Kusumi 			continue;
5212d60b848STomohiro Kusumi 		}
5222d60b848STomohiro Kusumi 		crc0 = vd->icrc_sects[HAMMER2_VOL_ICRC_SECT1];
523a0373a75STomohiro Kusumi 		crc1 = hammer2_icrc32(bp->b_data + HAMMER2_VOLUME_ICRC1_OFF,
5242d60b848STomohiro Kusumi 				      HAMMER2_VOLUME_ICRC1_SIZE);
5252d60b848STomohiro Kusumi 		if (crc0 != crc1) {
5262d60b848STomohiro Kusumi 			hprintf("%s #%d: volume header crc mismatch sect1 %08x/%08x\n",
5272d60b848STomohiro Kusumi 				path, i, crc0, crc1);
5282d60b848STomohiro Kusumi 			brelse(bp);
5292d60b848STomohiro Kusumi 			bp = NULL;
5302d60b848STomohiro Kusumi 			continue;
5312d60b848STomohiro Kusumi 		}
5322d60b848STomohiro Kusumi 		crc0 = vd->icrc_volheader;
533a0373a75STomohiro Kusumi 		crc1 = hammer2_icrc32(bp->b_data + HAMMER2_VOLUME_ICRCVH_OFF,
5342d60b848STomohiro Kusumi 				      HAMMER2_VOLUME_ICRCVH_SIZE);
5352d60b848STomohiro Kusumi 		if (crc0 != crc1) {
5362d60b848STomohiro Kusumi 			hprintf("%s #%d: volume header crc mismatch vh %08x/%08x\n",
5372d60b848STomohiro Kusumi 				path, i, crc0, crc1);
5382d60b848STomohiro Kusumi 			brelse(bp);
5392d60b848STomohiro Kusumi 			bp = NULL;
5402d60b848STomohiro Kusumi 			continue;
5412d60b848STomohiro Kusumi 		}
5422d60b848STomohiro Kusumi 
5432d60b848STomohiro Kusumi 		if (zone == -1 || voldata->mirror_tid < vd->mirror_tid) {
5442d60b848STomohiro Kusumi 			*voldata = *vd;
5452d60b848STomohiro Kusumi 			zone = i;
5462d60b848STomohiro Kusumi 		}
5472d60b848STomohiro Kusumi 		brelse(bp);
5482d60b848STomohiro Kusumi 		bp = NULL;
5492d60b848STomohiro Kusumi 	}
5502d60b848STomohiro Kusumi 
5512d60b848STomohiro Kusumi 	if (zone == -1) {
5522d60b848STomohiro Kusumi 		hprintf("%s has no valid volume headers\n", path);
5532d60b848STomohiro Kusumi 		return -EINVAL;
5542d60b848STomohiro Kusumi 	}
5552d60b848STomohiro Kusumi 	return zone;
5562d60b848STomohiro Kusumi }
5572d60b848STomohiro Kusumi 
5582d60b848STomohiro Kusumi static void
hammer2_print_uuid_mismatch(uuid_t * uuid1,uuid_t * uuid2,const char * id)5592d60b848STomohiro Kusumi hammer2_print_uuid_mismatch(uuid_t *uuid1, uuid_t *uuid2, const char *id)
5602d60b848STomohiro Kusumi {
5612d60b848STomohiro Kusumi 	char *buf1 = NULL, *buf2 = NULL;
5622d60b848STomohiro Kusumi 
5632d60b848STomohiro Kusumi 	hammer2_uuid_to_str(uuid1, &buf1);
5642d60b848STomohiro Kusumi 	hammer2_uuid_to_str(uuid2, &buf2);
5652d60b848STomohiro Kusumi 
5662d60b848STomohiro Kusumi 	hprintf("%s uuid mismatch %s vs %s\n", id, buf1, buf2);
5672d60b848STomohiro Kusumi 
5682d60b848STomohiro Kusumi 	free(buf1);
5692d60b848STomohiro Kusumi 	free(buf2);
5702d60b848STomohiro Kusumi }
5712d60b848STomohiro Kusumi 
5722d60b848STomohiro Kusumi int
hammer2_init_vfsvolumes(struct mount * mp,const hammer2_devvp_list_t * devvpl,hammer2_vfsvolume_t * volumes,hammer2_volume_data_t * rootvoldata,int * rootvolzone,struct m_vnode ** rootvoldevvp)5732d60b848STomohiro Kusumi hammer2_init_vfsvolumes(struct mount *mp, const hammer2_devvp_list_t *devvpl,
5742d60b848STomohiro Kusumi 		     hammer2_vfsvolume_t *volumes,
5752d60b848STomohiro Kusumi 		     hammer2_volume_data_t *rootvoldata,
5762d60b848STomohiro Kusumi 		     int *rootvolzone,
5776bcbb706STomohiro Kusumi 		     struct m_vnode **rootvoldevvp)
5782d60b848STomohiro Kusumi {
5792d60b848STomohiro Kusumi 	hammer2_devvp_t *e;
5802d60b848STomohiro Kusumi 	hammer2_volume_data_t *voldata;
5812d60b848STomohiro Kusumi 	hammer2_vfsvolume_t *vol;
5826bcbb706STomohiro Kusumi 	struct m_vnode *devvp;
5832d60b848STomohiro Kusumi 	const char *path;
5842d60b848STomohiro Kusumi 	uuid_t fsid, fstype;
5852d60b848STomohiro Kusumi 	int i, zone, error = 0, version = -1, nvolumes = 0;
5862d60b848STomohiro Kusumi 
5872d60b848STomohiro Kusumi 	for (i = 0; i < HAMMER2_MAX_VOLUMES; ++i) {
5882d60b848STomohiro Kusumi 		vol = &volumes[i];
5892d60b848STomohiro Kusumi 		vol->dev = NULL;
5902d60b848STomohiro Kusumi 		vol->id = -1;
5912d60b848STomohiro Kusumi 		vol->offset = (hammer2_off_t)-1;
5922d60b848STomohiro Kusumi 		vol->size = (hammer2_off_t)-1;
5932d60b848STomohiro Kusumi 	}
5942d60b848STomohiro Kusumi 
5952d60b848STomohiro Kusumi 	voldata = kmalloc(sizeof(*voldata), M_HAMMER2, M_WAITOK | M_ZERO);
5962d60b848STomohiro Kusumi 	bzero(&fsid, sizeof(fsid));
5972d60b848STomohiro Kusumi 	bzero(&fstype, sizeof(fstype));
5982d60b848STomohiro Kusumi 	bzero(rootvoldata, sizeof(*rootvoldata));
5992d60b848STomohiro Kusumi 
6002d60b848STomohiro Kusumi 	TAILQ_FOREACH(e, devvpl, entry) {
6012d60b848STomohiro Kusumi 		devvp = e->devvp;
6022d60b848STomohiro Kusumi 		path = e->path;
6032d60b848STomohiro Kusumi 		KKASSERT(devvp);
6042d60b848STomohiro Kusumi 
6052d60b848STomohiro Kusumi 		/* returns negative error or positive zone# */
6062d60b848STomohiro Kusumi 		error = hammer2_read_volume_header(devvp, path, voldata);
6072d60b848STomohiro Kusumi 		if (error < 0) {
6082d60b848STomohiro Kusumi 			hprintf("failed to read %s's volume header\n", path);
6092d60b848STomohiro Kusumi 			error = -error;
6102d60b848STomohiro Kusumi 			goto done;
6112d60b848STomohiro Kusumi 		}
6122d60b848STomohiro Kusumi 		zone = error;
6132d60b848STomohiro Kusumi 		error = 0; /* reset error */
6142d60b848STomohiro Kusumi 
6152d60b848STomohiro Kusumi 		if (voldata->volu_id >= HAMMER2_MAX_VOLUMES) {
6162d60b848STomohiro Kusumi 			hprintf("%s has bad volume id %d\n", path,
6172d60b848STomohiro Kusumi 				voldata->volu_id);
6182d60b848STomohiro Kusumi 			error = EINVAL;
6192d60b848STomohiro Kusumi 			goto done;
6202d60b848STomohiro Kusumi 		}
6212d60b848STomohiro Kusumi 		vol = &volumes[voldata->volu_id];
6222d60b848STomohiro Kusumi 		if (vol->id != -1) {
62300e4ae5cSTomohiro Kusumi 			hprintf("volume id %d already initialized\n",
62400e4ae5cSTomohiro Kusumi 				voldata->volu_id);
6252d60b848STomohiro Kusumi 			error = EINVAL;
6262d60b848STomohiro Kusumi 			goto done;
6272d60b848STomohiro Kusumi 		}
6282d60b848STomohiro Kusumi 		/* all headers must have the same version, nvolumes and uuid */
6292d60b848STomohiro Kusumi 		if (version == -1) {
6302d60b848STomohiro Kusumi 			version = voldata->version;
6312d60b848STomohiro Kusumi 			nvolumes = voldata->nvolumes;
6322d60b848STomohiro Kusumi 			fsid = voldata->fsid;
6332d60b848STomohiro Kusumi 			fstype = voldata->fstype;
6342d60b848STomohiro Kusumi 		} else {
6352d60b848STomohiro Kusumi 			if (version != (int)voldata->version) {
6362d60b848STomohiro Kusumi 				hprintf("volume version mismatch %d vs %d\n",
6372d60b848STomohiro Kusumi 					version, (int)voldata->version);
6382d60b848STomohiro Kusumi 				error = ENXIO;
6392d60b848STomohiro Kusumi 				goto done;
6402d60b848STomohiro Kusumi 			}
6412d60b848STomohiro Kusumi 			if (nvolumes != voldata->nvolumes) {
6422d60b848STomohiro Kusumi 				hprintf("volume count mismatch %d vs %d\n",
6432d60b848STomohiro Kusumi 					nvolumes, voldata->nvolumes);
6442d60b848STomohiro Kusumi 				error = ENXIO;
6452d60b848STomohiro Kusumi 				goto done;
6462d60b848STomohiro Kusumi 			}
6472d60b848STomohiro Kusumi 			if (bcmp(&fsid, &voldata->fsid, sizeof(fsid))) {
6482d60b848STomohiro Kusumi 				hammer2_print_uuid_mismatch(&fsid,
6492d60b848STomohiro Kusumi 							    &voldata->fsid, "fsid");
6502d60b848STomohiro Kusumi 				error = ENXIO;
6512d60b848STomohiro Kusumi 				goto done;
6522d60b848STomohiro Kusumi 			}
6532d60b848STomohiro Kusumi 			if (bcmp(&fstype, &voldata->fstype, sizeof(fstype))) {
6542d60b848STomohiro Kusumi 				hammer2_print_uuid_mismatch(&fstype,
6552d60b848STomohiro Kusumi 							    &voldata->fstype, "fstype");
6562d60b848STomohiro Kusumi 				error = ENXIO;
6572d60b848STomohiro Kusumi 				goto done;
6582d60b848STomohiro Kusumi 			}
6592d60b848STomohiro Kusumi 		}
6602d60b848STomohiro Kusumi 		if (version < HAMMER2_VOL_VERSION_MIN ||
6612d60b848STomohiro Kusumi 		    version > HAMMER2_VOL_VERSION_WIP) {
6622d60b848STomohiro Kusumi 			hprintf("bad volume version %d\n", version);
6632d60b848STomohiro Kusumi 			error = EINVAL;
6642d60b848STomohiro Kusumi 			goto done;
6652d60b848STomohiro Kusumi 		}
6662d60b848STomohiro Kusumi 		/* all per-volume tests passed */
6672d60b848STomohiro Kusumi 		vol->dev = e;
6682d60b848STomohiro Kusumi 		vol->id = voldata->volu_id;
6692d60b848STomohiro Kusumi 		vol->offset = voldata->volu_loff[vol->id];
6702d60b848STomohiro Kusumi 		vol->size = voldata->volu_size;
6712d60b848STomohiro Kusumi 		if (vol->id == HAMMER2_ROOT_VOLUME) {
6722d60b848STomohiro Kusumi 			bcopy(voldata, rootvoldata, sizeof(*rootvoldata));
6732d60b848STomohiro Kusumi 			*rootvolzone = zone;
6742d60b848STomohiro Kusumi 			KKASSERT(*rootvoldevvp == NULL);
6752d60b848STomohiro Kusumi 			*rootvoldevvp = e->devvp;
6762d60b848STomohiro Kusumi 		}
6772d60b848STomohiro Kusumi 		//devvp->v_rdev->si_mountpoint = mp;
6782d60b848STomohiro Kusumi 		hprintf("\"%s\" zone=%d id=%d offset=0x%016jx size=0x%016jx\n",
6792d60b848STomohiro Kusumi 			path, zone, vol->id, (intmax_t)vol->offset,
6802d60b848STomohiro Kusumi 			(intmax_t)vol->size);
6812d60b848STomohiro Kusumi 	}
6822d60b848STomohiro Kusumi done:
683185ae703STomohiro Kusumi 	if (!error) {
684185ae703STomohiro Kusumi 		if (!rootvoldata->version) {
685185ae703STomohiro Kusumi 			hprintf("root volume not found\n");
686185ae703STomohiro Kusumi 			error = EINVAL;
687185ae703STomohiro Kusumi 		}
6882d60b848STomohiro Kusumi 		if (!error)
6892d60b848STomohiro Kusumi 			error = hammer2_verify_vfsvolumes(volumes, rootvoldata);
690185ae703STomohiro Kusumi 	}
6912d60b848STomohiro Kusumi 	kfree(voldata, M_HAMMER2);
6922d60b848STomohiro Kusumi 
6932d60b848STomohiro Kusumi 	return error;
6942d60b848STomohiro Kusumi }
6952d60b848STomohiro Kusumi 
6962d60b848STomohiro Kusumi hammer2_vfsvolume_t*
hammer2_get_volume_from_hmp(hammer2_dev_t * hmp,hammer2_off_t offset)697556932ecSMatthew Dillon hammer2_get_volume_from_hmp(hammer2_dev_t *hmp, hammer2_off_t offset)
6982d60b848STomohiro Kusumi {
6992d60b848STomohiro Kusumi 	hammer2_vfsvolume_t *vol, *ret = NULL;
7002d60b848STomohiro Kusumi 	int i;
7012d60b848STomohiro Kusumi 
7022d60b848STomohiro Kusumi 	offset &= ~HAMMER2_OFF_MASK_RADIX;
7032d60b848STomohiro Kusumi 
7042d60b848STomohiro Kusumi 	/* locking is unneeded until volume-add support */
7052d60b848STomohiro Kusumi 	//hammer2_voldata_lock(hmp);
7062d60b848STomohiro Kusumi 	/* do binary search if users really use this many supported volumes */
7072d60b848STomohiro Kusumi 	for (i = 0; i < hmp->nvolumes; ++i) {
7082d60b848STomohiro Kusumi 		vol = &hmp->volumes[i];
7092d60b848STomohiro Kusumi 		if ((offset >= vol->offset) &&
7102d60b848STomohiro Kusumi 		    (offset < vol->offset + vol->size)) {
7112d60b848STomohiro Kusumi 			ret = vol;
7122d60b848STomohiro Kusumi 			break;
7132d60b848STomohiro Kusumi 		}
7142d60b848STomohiro Kusumi 	}
7152d60b848STomohiro Kusumi 	//hammer2_voldata_unlock(hmp);
7162d60b848STomohiro Kusumi 
7172d60b848STomohiro Kusumi 	if (!ret)
7182d60b848STomohiro Kusumi 		panic("no volume for offset 0x%016jx", (intmax_t)offset);
7192d60b848STomohiro Kusumi 
7202d60b848STomohiro Kusumi 	KKASSERT(ret);
7212d60b848STomohiro Kusumi 	KKASSERT(ret->dev);
7222d60b848STomohiro Kusumi 	KKASSERT(ret->dev->devvp);
7232d60b848STomohiro Kusumi 	//KKASSERT(ret->dev->path);
7242d60b848STomohiro Kusumi 
7252d60b848STomohiro Kusumi 	return ret;
7262d60b848STomohiro Kusumi }
727