xref: /dflybsd-src/sys/vfs/hammer/hammer_vfsops.c (revision 47637bffad7ba04e4e0d59cde1529523d59ec099)
1427e5fc6SMatthew Dillon /*
2b84de5afSMatthew Dillon  * Copyright (c) 2007-2008 The DragonFly Project.  All rights reserved.
3427e5fc6SMatthew Dillon  *
4427e5fc6SMatthew Dillon  * This code is derived from software contributed to The DragonFly Project
5427e5fc6SMatthew Dillon  * by Matthew Dillon <dillon@backplane.com>
6427e5fc6SMatthew Dillon  *
7427e5fc6SMatthew Dillon  * Redistribution and use in source and binary forms, with or without
8427e5fc6SMatthew Dillon  * modification, are permitted provided that the following conditions
9427e5fc6SMatthew Dillon  * are met:
10427e5fc6SMatthew Dillon  *
11427e5fc6SMatthew Dillon  * 1. Redistributions of source code must retain the above copyright
12427e5fc6SMatthew Dillon  *    notice, this list of conditions and the following disclaimer.
13427e5fc6SMatthew Dillon  * 2. Redistributions in binary form must reproduce the above copyright
14427e5fc6SMatthew Dillon  *    notice, this list of conditions and the following disclaimer in
15427e5fc6SMatthew Dillon  *    the documentation and/or other materials provided with the
16427e5fc6SMatthew Dillon  *    distribution.
17427e5fc6SMatthew Dillon  * 3. Neither the name of The DragonFly Project nor the names of its
18427e5fc6SMatthew Dillon  *    contributors may be used to endorse or promote products derived
19427e5fc6SMatthew Dillon  *    from this software without specific, prior written permission.
20427e5fc6SMatthew Dillon  *
21427e5fc6SMatthew Dillon  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22427e5fc6SMatthew Dillon  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23427e5fc6SMatthew Dillon  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24427e5fc6SMatthew Dillon  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
25427e5fc6SMatthew Dillon  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26427e5fc6SMatthew Dillon  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
27427e5fc6SMatthew Dillon  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28427e5fc6SMatthew Dillon  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29427e5fc6SMatthew Dillon  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30427e5fc6SMatthew Dillon  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31427e5fc6SMatthew Dillon  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32427e5fc6SMatthew Dillon  * SUCH DAMAGE.
33427e5fc6SMatthew Dillon  *
34*47637bffSMatthew Dillon  * $DragonFly: src/sys/vfs/hammer/hammer_vfsops.c,v 1.39 2008/06/07 07:41:51 dillon Exp $
35427e5fc6SMatthew Dillon  */
36427e5fc6SMatthew Dillon 
37427e5fc6SMatthew Dillon #include <sys/param.h>
38427e5fc6SMatthew Dillon #include <sys/systm.h>
39427e5fc6SMatthew Dillon #include <sys/kernel.h>
40427e5fc6SMatthew Dillon #include <sys/vnode.h>
41427e5fc6SMatthew Dillon #include <sys/mount.h>
42427e5fc6SMatthew Dillon #include <sys/malloc.h>
43427e5fc6SMatthew Dillon #include <sys/nlookup.h>
44427e5fc6SMatthew Dillon #include <sys/fcntl.h>
45b3deaf57SMatthew Dillon #include <sys/sysctl.h>
46427e5fc6SMatthew Dillon #include <sys/buf.h>
47427e5fc6SMatthew Dillon #include <sys/buf2.h>
48427e5fc6SMatthew Dillon #include "hammer.h"
49427e5fc6SMatthew Dillon 
502f85fa4dSMatthew Dillon int hammer_debug_io;
51d5ef456eSMatthew Dillon int hammer_debug_general;
5277062c8aSMatthew Dillon int hammer_debug_debug;
53e8599db1SMatthew Dillon int hammer_debug_inode;
547d683b0fSMatthew Dillon int hammer_debug_locks;
55b3deaf57SMatthew Dillon int hammer_debug_btree;
56d113fda1SMatthew Dillon int hammer_debug_tid;
5746fe7ae1SMatthew Dillon int hammer_debug_recover;	/* -1 will disable, +1 will force */
5846fe7ae1SMatthew Dillon int hammer_debug_recover_faults;
59b3deaf57SMatthew Dillon int hammer_count_inodes;
60b3deaf57SMatthew Dillon int hammer_count_records;
61b3deaf57SMatthew Dillon int hammer_count_record_datas;
62b3deaf57SMatthew Dillon int hammer_count_volumes;
63b3deaf57SMatthew Dillon int hammer_count_buffers;
64b3deaf57SMatthew Dillon int hammer_count_nodes;
659480ff55SMatthew Dillon int hammer_count_dirtybufs;		/* global */
66*47637bffSMatthew Dillon int hammer_stats_btree_iterations;
67*47637bffSMatthew Dillon int hammer_stats_record_iterations;
689480ff55SMatthew Dillon int hammer_limit_dirtybufs = 100;	/* per-mount */
69*47637bffSMatthew Dillon int hammer_limit_irecs = 8192;		/* per-inode */
70*47637bffSMatthew Dillon int hammer_limit_recs = 16384;		/* as a whole */
711f07f686SMatthew Dillon int hammer_bio_count;
727d683b0fSMatthew Dillon int64_t hammer_contention_count;
73f03c9cf4SMatthew Dillon int64_t hammer_zone_limit;
74b3deaf57SMatthew Dillon 
75b3deaf57SMatthew Dillon SYSCTL_NODE(_vfs, OID_AUTO, hammer, CTLFLAG_RW, 0, "HAMMER filesystem");
76d5ef456eSMatthew Dillon SYSCTL_INT(_vfs_hammer, OID_AUTO, debug_general, CTLFLAG_RW,
77d5ef456eSMatthew Dillon 	   &hammer_debug_general, 0, "");
782f85fa4dSMatthew Dillon SYSCTL_INT(_vfs_hammer, OID_AUTO, debug_io, CTLFLAG_RW,
792f85fa4dSMatthew Dillon 	   &hammer_debug_io, 0, "");
8077062c8aSMatthew Dillon SYSCTL_INT(_vfs_hammer, OID_AUTO, debug_debug, CTLFLAG_RW,
8177062c8aSMatthew Dillon 	   &hammer_debug_debug, 0, "");
82e8599db1SMatthew Dillon SYSCTL_INT(_vfs_hammer, OID_AUTO, debug_inode, CTLFLAG_RW,
83e8599db1SMatthew Dillon 	   &hammer_debug_inode, 0, "");
847d683b0fSMatthew Dillon SYSCTL_INT(_vfs_hammer, OID_AUTO, debug_locks, CTLFLAG_RW,
857d683b0fSMatthew Dillon 	   &hammer_debug_locks, 0, "");
86b3deaf57SMatthew Dillon SYSCTL_INT(_vfs_hammer, OID_AUTO, debug_btree, CTLFLAG_RW,
87b3deaf57SMatthew Dillon 	   &hammer_debug_btree, 0, "");
88d113fda1SMatthew Dillon SYSCTL_INT(_vfs_hammer, OID_AUTO, debug_tid, CTLFLAG_RW,
89d113fda1SMatthew Dillon 	   &hammer_debug_tid, 0, "");
90b33e2cc0SMatthew Dillon SYSCTL_INT(_vfs_hammer, OID_AUTO, debug_recover, CTLFLAG_RW,
91b33e2cc0SMatthew Dillon 	   &hammer_debug_recover, 0, "");
9246fe7ae1SMatthew Dillon SYSCTL_INT(_vfs_hammer, OID_AUTO, debug_recover_faults, CTLFLAG_RW,
9346fe7ae1SMatthew Dillon 	   &hammer_debug_recover_faults, 0, "");
949480ff55SMatthew Dillon 
959480ff55SMatthew Dillon SYSCTL_INT(_vfs_hammer, OID_AUTO, limit_dirtybufs, CTLFLAG_RW,
969480ff55SMatthew Dillon 	   &hammer_limit_dirtybufs, 0, "");
97*47637bffSMatthew Dillon SYSCTL_INT(_vfs_hammer, OID_AUTO, limit_irecs, CTLFLAG_RW,
98*47637bffSMatthew Dillon 	   &hammer_limit_irecs, 0, "");
99*47637bffSMatthew Dillon SYSCTL_INT(_vfs_hammer, OID_AUTO, limit_recs, CTLFLAG_RW,
100*47637bffSMatthew Dillon 	   &hammer_limit_recs, 0, "");
1019480ff55SMatthew Dillon 
102b3deaf57SMatthew Dillon SYSCTL_INT(_vfs_hammer, OID_AUTO, count_inodes, CTLFLAG_RD,
103b3deaf57SMatthew Dillon 	   &hammer_count_inodes, 0, "");
104b3deaf57SMatthew Dillon SYSCTL_INT(_vfs_hammer, OID_AUTO, count_records, CTLFLAG_RD,
105b3deaf57SMatthew Dillon 	   &hammer_count_records, 0, "");
106b3deaf57SMatthew Dillon SYSCTL_INT(_vfs_hammer, OID_AUTO, count_record_datas, CTLFLAG_RD,
107b3deaf57SMatthew Dillon 	   &hammer_count_record_datas, 0, "");
108b3deaf57SMatthew Dillon SYSCTL_INT(_vfs_hammer, OID_AUTO, count_volumes, CTLFLAG_RD,
109b3deaf57SMatthew Dillon 	   &hammer_count_volumes, 0, "");
110b3deaf57SMatthew Dillon SYSCTL_INT(_vfs_hammer, OID_AUTO, count_buffers, CTLFLAG_RD,
111b3deaf57SMatthew Dillon 	   &hammer_count_buffers, 0, "");
112b3deaf57SMatthew Dillon SYSCTL_INT(_vfs_hammer, OID_AUTO, count_nodes, CTLFLAG_RD,
113b3deaf57SMatthew Dillon 	   &hammer_count_nodes, 0, "");
1149480ff55SMatthew Dillon SYSCTL_INT(_vfs_hammer, OID_AUTO, count_dirtybufs, CTLFLAG_RD,
1159480ff55SMatthew Dillon 	   &hammer_count_dirtybufs, 0, "");
116f03c9cf4SMatthew Dillon SYSCTL_QUAD(_vfs_hammer, OID_AUTO, zone_limit, CTLFLAG_RW,
117f03c9cf4SMatthew Dillon 	   &hammer_zone_limit, 0, "");
1187d683b0fSMatthew Dillon SYSCTL_QUAD(_vfs_hammer, OID_AUTO, contention_count, CTLFLAG_RW,
1197d683b0fSMatthew Dillon 	   &hammer_contention_count, 0, "");
120b3deaf57SMatthew Dillon 
121427e5fc6SMatthew Dillon /*
122427e5fc6SMatthew Dillon  * VFS ABI
123427e5fc6SMatthew Dillon  */
124427e5fc6SMatthew Dillon static void	hammer_free_hmp(struct mount *mp);
125427e5fc6SMatthew Dillon 
126427e5fc6SMatthew Dillon static int	hammer_vfs_mount(struct mount *mp, char *path, caddr_t data,
127427e5fc6SMatthew Dillon 				struct ucred *cred);
128427e5fc6SMatthew Dillon static int	hammer_vfs_unmount(struct mount *mp, int mntflags);
129427e5fc6SMatthew Dillon static int	hammer_vfs_root(struct mount *mp, struct vnode **vpp);
130427e5fc6SMatthew Dillon static int	hammer_vfs_statfs(struct mount *mp, struct statfs *sbp,
131427e5fc6SMatthew Dillon 				struct ucred *cred);
1326f97fce3SMatthew Dillon static int	hammer_vfs_statvfs(struct mount *mp, struct statvfs *sbp,
1336f97fce3SMatthew Dillon 				struct ucred *cred);
134427e5fc6SMatthew Dillon static int	hammer_vfs_sync(struct mount *mp, int waitfor);
135513ca7d7SMatthew Dillon static int	hammer_vfs_vget(struct mount *mp, ino_t ino,
136513ca7d7SMatthew Dillon 				struct vnode **vpp);
137427e5fc6SMatthew Dillon static int	hammer_vfs_init(struct vfsconf *conf);
138513ca7d7SMatthew Dillon static int	hammer_vfs_fhtovp(struct mount *mp, struct fid *fhp,
139513ca7d7SMatthew Dillon 				struct vnode **vpp);
140513ca7d7SMatthew Dillon static int	hammer_vfs_vptofh(struct vnode *vp, struct fid *fhp);
141513ca7d7SMatthew Dillon static int	hammer_vfs_checkexp(struct mount *mp, struct sockaddr *nam,
142513ca7d7SMatthew Dillon 				int *exflagsp, struct ucred **credanonp);
143513ca7d7SMatthew Dillon 
144427e5fc6SMatthew Dillon 
145427e5fc6SMatthew Dillon static struct vfsops hammer_vfsops = {
146427e5fc6SMatthew Dillon 	.vfs_mount	= hammer_vfs_mount,
147427e5fc6SMatthew Dillon 	.vfs_unmount	= hammer_vfs_unmount,
148427e5fc6SMatthew Dillon 	.vfs_root 	= hammer_vfs_root,
149427e5fc6SMatthew Dillon 	.vfs_statfs	= hammer_vfs_statfs,
1506f97fce3SMatthew Dillon 	.vfs_statvfs	= hammer_vfs_statvfs,
151427e5fc6SMatthew Dillon 	.vfs_sync	= hammer_vfs_sync,
152427e5fc6SMatthew Dillon 	.vfs_vget	= hammer_vfs_vget,
153513ca7d7SMatthew Dillon 	.vfs_init	= hammer_vfs_init,
154513ca7d7SMatthew Dillon 	.vfs_vptofh	= hammer_vfs_vptofh,
155513ca7d7SMatthew Dillon 	.vfs_fhtovp	= hammer_vfs_fhtovp,
156513ca7d7SMatthew Dillon 	.vfs_checkexp	= hammer_vfs_checkexp
157427e5fc6SMatthew Dillon };
158427e5fc6SMatthew Dillon 
159427e5fc6SMatthew Dillon MALLOC_DEFINE(M_HAMMER, "hammer-mount", "hammer mount");
160427e5fc6SMatthew Dillon 
161427e5fc6SMatthew Dillon VFS_SET(hammer_vfsops, hammer, 0);
162427e5fc6SMatthew Dillon MODULE_VERSION(hammer, 1);
163427e5fc6SMatthew Dillon 
164427e5fc6SMatthew Dillon static int
165427e5fc6SMatthew Dillon hammer_vfs_init(struct vfsconf *conf)
166427e5fc6SMatthew Dillon {
16747197d71SMatthew Dillon 	/*hammer_init_alist_config();*/
168427e5fc6SMatthew Dillon 	return(0);
169427e5fc6SMatthew Dillon }
170427e5fc6SMatthew Dillon 
171427e5fc6SMatthew Dillon static int
172427e5fc6SMatthew Dillon hammer_vfs_mount(struct mount *mp, char *mntpt, caddr_t data,
173427e5fc6SMatthew Dillon 		 struct ucred *cred)
174427e5fc6SMatthew Dillon {
175427e5fc6SMatthew Dillon 	struct hammer_mount_info info;
176a89aec1bSMatthew Dillon 	hammer_mount_t hmp;
177a89aec1bSMatthew Dillon 	hammer_volume_t rootvol;
17827ea2398SMatthew Dillon 	struct vnode *rootvp;
179427e5fc6SMatthew Dillon 	const char *upath;	/* volume name in userspace */
180427e5fc6SMatthew Dillon 	char *path;		/* volume name in system space */
181427e5fc6SMatthew Dillon 	int error;
182427e5fc6SMatthew Dillon 	int i;
183427e5fc6SMatthew Dillon 
184427e5fc6SMatthew Dillon 	if ((error = copyin(data, &info, sizeof(info))) != 0)
185427e5fc6SMatthew Dillon 		return (error);
18651c35492SMatthew Dillon 	if ((mp->mnt_flag & MNT_UPDATE) == 0) {
187427e5fc6SMatthew Dillon 		if (info.nvolumes <= 0 || info.nvolumes >= 32768)
188427e5fc6SMatthew Dillon 			return (EINVAL);
18951c35492SMatthew Dillon 	}
190427e5fc6SMatthew Dillon 
191427e5fc6SMatthew Dillon 	/*
192427e5fc6SMatthew Dillon 	 * Interal mount data structure
193427e5fc6SMatthew Dillon 	 */
194195c19a1SMatthew Dillon 	if (mp->mnt_flag & MNT_UPDATE) {
195195c19a1SMatthew Dillon 		hmp = (void *)mp->mnt_data;
196195c19a1SMatthew Dillon 		KKASSERT(hmp != NULL);
197195c19a1SMatthew Dillon 	} else {
198427e5fc6SMatthew Dillon 		hmp = kmalloc(sizeof(*hmp), M_HAMMER, M_WAITOK | M_ZERO);
199427e5fc6SMatthew Dillon 		mp->mnt_data = (qaddr_t)hmp;
200427e5fc6SMatthew Dillon 		hmp->mp = mp;
201195c19a1SMatthew Dillon 		hmp->zbuf = kmalloc(HAMMER_BUFSIZE, M_HAMMER, M_WAITOK|M_ZERO);
202195c19a1SMatthew Dillon 		hmp->namekey_iterator = mycpu->gd_time_seconds;
20346fe7ae1SMatthew Dillon 		/*TAILQ_INIT(&hmp->recycle_list);*/
20447197d71SMatthew Dillon 
2052f85fa4dSMatthew Dillon 		hmp->root_btree_beg.localization = HAMMER_MIN_LOCALIZATION;
20647197d71SMatthew Dillon 		hmp->root_btree_beg.obj_id = -0x8000000000000000LL;
20747197d71SMatthew Dillon 		hmp->root_btree_beg.key = -0x8000000000000000LL;
20847197d71SMatthew Dillon 		hmp->root_btree_beg.create_tid = 1;
20947197d71SMatthew Dillon 		hmp->root_btree_beg.delete_tid = 1;
21047197d71SMatthew Dillon 		hmp->root_btree_beg.rec_type = 0;
21147197d71SMatthew Dillon 		hmp->root_btree_beg.obj_type = 0;
21247197d71SMatthew Dillon 
2132f85fa4dSMatthew Dillon 		hmp->root_btree_end.localization = HAMMER_MAX_LOCALIZATION;
21447197d71SMatthew Dillon 		hmp->root_btree_end.obj_id = 0x7FFFFFFFFFFFFFFFLL;
21547197d71SMatthew Dillon 		hmp->root_btree_end.key = 0x7FFFFFFFFFFFFFFFLL;
21647197d71SMatthew Dillon 		hmp->root_btree_end.create_tid = 0xFFFFFFFFFFFFFFFFULL;
21747197d71SMatthew Dillon 		hmp->root_btree_end.delete_tid = 0;   /* special case */
21847197d71SMatthew Dillon 		hmp->root_btree_end.rec_type = 0xFFFFU;
21947197d71SMatthew Dillon 		hmp->root_btree_end.obj_type = 0;
22040043e7fSMatthew Dillon 		lockinit(&hmp->blockmap_lock, "blkmap", 0, 0);
221f03c9cf4SMatthew Dillon 
2229480ff55SMatthew Dillon 		hmp->sync_lock.refs = 1;
223c9b9e29dSMatthew Dillon 		hmp->free_lock.refs = 1;
2249480ff55SMatthew Dillon 
225059819e3SMatthew Dillon 		TAILQ_INIT(&hmp->flush_list);
2260729c8c8SMatthew Dillon 		TAILQ_INIT(&hmp->objid_cache_list);
227e8599db1SMatthew Dillon 		TAILQ_INIT(&hmp->undo_lru_list);
228059819e3SMatthew Dillon 
2290729c8c8SMatthew Dillon 		/*
2300729c8c8SMatthew Dillon 		 * Set default zone limits.  This value can be reduced
2310729c8c8SMatthew Dillon 		 * further by the zone limit specified in the root volume.
2320729c8c8SMatthew Dillon 		 *
2330729c8c8SMatthew Dillon 		 * The sysctl can force a small zone limit for debugging
2340729c8c8SMatthew Dillon 		 * purposes.
2350729c8c8SMatthew Dillon 		 */
236f03c9cf4SMatthew Dillon 		for (i = 0; i < HAMMER_MAX_ZONES; ++i) {
237f03c9cf4SMatthew Dillon 			hmp->zone_limits[i] =
238f03c9cf4SMatthew Dillon 				HAMMER_ZONE_ENCODE(i, HAMMER_ZONE_LIMIT);
2390729c8c8SMatthew Dillon 
240f03c9cf4SMatthew Dillon 			if (hammer_zone_limit) {
241f03c9cf4SMatthew Dillon 				hmp->zone_limits[i] =
242f03c9cf4SMatthew Dillon 				    HAMMER_ZONE_ENCODE(i, hammer_zone_limit);
243f03c9cf4SMatthew Dillon 			}
244bf686dbeSMatthew Dillon 			hammer_init_holes(hmp, &hmp->holes[i]);
245f03c9cf4SMatthew Dillon 		}
246195c19a1SMatthew Dillon 	}
24751c35492SMatthew Dillon 	hmp->hflags &= ~HMNT_USERFLAGS;
24851c35492SMatthew Dillon 	hmp->hflags |= info.hflags & HMNT_USERFLAGS;
2497f7c1f84SMatthew Dillon 	if (info.asof) {
25051c35492SMatthew Dillon 		kprintf("ASOF\n");
2517f7c1f84SMatthew Dillon 		mp->mnt_flag |= MNT_RDONLY;
2527f7c1f84SMatthew Dillon 		hmp->asof = info.asof;
2537f7c1f84SMatthew Dillon 	} else {
2547f7c1f84SMatthew Dillon 		hmp->asof = HAMMER_MAX_TID;
2557f7c1f84SMatthew Dillon 	}
256195c19a1SMatthew Dillon 
257195c19a1SMatthew Dillon 	/*
25851c35492SMatthew Dillon 	 * Re-open read-write if originally read-only, or vise-versa.
259195c19a1SMatthew Dillon 	 */
260195c19a1SMatthew Dillon 	if (mp->mnt_flag & MNT_UPDATE) {
26151c35492SMatthew Dillon 		error = 0;
26251c35492SMatthew Dillon 		if (hmp->ronly && (mp->mnt_kern_flag & MNTK_WANTRDWR)) {
26351c35492SMatthew Dillon 			kprintf("HAMMER read-only -> read-write\n");
264195c19a1SMatthew Dillon 			hmp->ronly = 0;
26551c35492SMatthew Dillon 			RB_SCAN(hammer_vol_rb_tree, &hmp->rb_vols_root, NULL,
26651c35492SMatthew Dillon 				hammer_adjust_volume_mode, NULL);
26751c35492SMatthew Dillon 			rootvol = hammer_get_root_volume(hmp, &error);
26851c35492SMatthew Dillon 			if (rootvol) {
26951c35492SMatthew Dillon 				hammer_recover_flush_buffers(hmp, rootvol);
27051c35492SMatthew Dillon 				hammer_rel_volume(rootvol, 0);
271195c19a1SMatthew Dillon 			}
27251c35492SMatthew Dillon 			RB_SCAN(hammer_ino_rb_tree, &hmp->rb_inos_root, NULL,
27351c35492SMatthew Dillon 				hammer_reload_inode, NULL);
27451c35492SMatthew Dillon 			/* kernel clears MNT_RDONLY */
27551c35492SMatthew Dillon 		} else if (hmp->ronly == 0 && (mp->mnt_flag & MNT_RDONLY)) {
27651c35492SMatthew Dillon 			kprintf("HAMMER read-write -> read-only\n");
27751c35492SMatthew Dillon 			hmp->ronly = 1;	/* messy */
27851c35492SMatthew Dillon 			RB_SCAN(hammer_ino_rb_tree, &hmp->rb_inos_root, NULL,
27951c35492SMatthew Dillon 				hammer_reload_inode, NULL);
28051c35492SMatthew Dillon 			hmp->ronly = 0;
28151c35492SMatthew Dillon 			hammer_flusher_sync(hmp);
28251c35492SMatthew Dillon 			hammer_flusher_sync(hmp);
28351c35492SMatthew Dillon 			hammer_flusher_sync(hmp);
28451c35492SMatthew Dillon 			hmp->ronly = 1;
28551c35492SMatthew Dillon 			RB_SCAN(hammer_vol_rb_tree, &hmp->rb_vols_root, NULL,
28651c35492SMatthew Dillon 				hammer_adjust_volume_mode, NULL);
28751c35492SMatthew Dillon 		}
28851c35492SMatthew Dillon 		return(error);
289195c19a1SMatthew Dillon 	}
290195c19a1SMatthew Dillon 
291427e5fc6SMatthew Dillon 	RB_INIT(&hmp->rb_vols_root);
292427e5fc6SMatthew Dillon 	RB_INIT(&hmp->rb_inos_root);
29340043e7fSMatthew Dillon 	RB_INIT(&hmp->rb_nods_root);
294e8599db1SMatthew Dillon 	RB_INIT(&hmp->rb_undo_root);
295195c19a1SMatthew Dillon 	hmp->ronly = ((mp->mnt_flag & MNT_RDONLY) != 0);
296427e5fc6SMatthew Dillon 
29710a5d1baSMatthew Dillon 	TAILQ_INIT(&hmp->volu_list);
29810a5d1baSMatthew Dillon 	TAILQ_INIT(&hmp->undo_list);
29910a5d1baSMatthew Dillon 	TAILQ_INIT(&hmp->data_list);
30010a5d1baSMatthew Dillon 	TAILQ_INIT(&hmp->meta_list);
30110a5d1baSMatthew Dillon 	TAILQ_INIT(&hmp->lose_list);
30210a5d1baSMatthew Dillon 
303427e5fc6SMatthew Dillon 	/*
304427e5fc6SMatthew Dillon 	 * Load volumes
305427e5fc6SMatthew Dillon 	 */
306427e5fc6SMatthew Dillon 	path = objcache_get(namei_oc, M_WAITOK);
307d26d0ae9SMatthew Dillon 	hmp->nvolumes = info.nvolumes;
308427e5fc6SMatthew Dillon 	for (i = 0; i < info.nvolumes; ++i) {
309427e5fc6SMatthew Dillon 		error = copyin(&info.volumes[i], &upath, sizeof(char *));
310427e5fc6SMatthew Dillon 		if (error == 0)
311427e5fc6SMatthew Dillon 			error = copyinstr(upath, path, MAXPATHLEN, NULL);
312427e5fc6SMatthew Dillon 		if (error == 0)
3138cd0a023SMatthew Dillon 			error = hammer_install_volume(hmp, path);
314427e5fc6SMatthew Dillon 		if (error)
315427e5fc6SMatthew Dillon 			break;
316427e5fc6SMatthew Dillon 	}
317427e5fc6SMatthew Dillon 	objcache_put(namei_oc, path);
318427e5fc6SMatthew Dillon 
319427e5fc6SMatthew Dillon 	/*
320427e5fc6SMatthew Dillon 	 * Make sure we found a root volume
321427e5fc6SMatthew Dillon 	 */
322427e5fc6SMatthew Dillon 	if (error == 0 && hmp->rootvol == NULL) {
323427e5fc6SMatthew Dillon 		kprintf("hammer_mount: No root volume found!\n");
324427e5fc6SMatthew Dillon 		error = EINVAL;
325427e5fc6SMatthew Dillon 	}
326427e5fc6SMatthew Dillon 	if (error) {
327427e5fc6SMatthew Dillon 		hammer_free_hmp(mp);
328427e5fc6SMatthew Dillon 		return (error);
329427e5fc6SMatthew Dillon 	}
330427e5fc6SMatthew Dillon 
331427e5fc6SMatthew Dillon 	/*
33227ea2398SMatthew Dillon 	 * No errors, setup enough of the mount point so we can lookup the
33327ea2398SMatthew Dillon 	 * root vnode.
334427e5fc6SMatthew Dillon 	 */
335427e5fc6SMatthew Dillon 	mp->mnt_iosize_max = MAXPHYS;
336427e5fc6SMatthew Dillon 	mp->mnt_kern_flag |= MNTK_FSMID;
337c0ade690SMatthew Dillon 
338c0ade690SMatthew Dillon 	/*
339c0ade690SMatthew Dillon 	 * note: f_iosize is used by vnode_pager_haspage() when constructing
340c0ade690SMatthew Dillon 	 * its VOP_BMAP call.
341c0ade690SMatthew Dillon 	 */
342c0ade690SMatthew Dillon 	mp->mnt_stat.f_iosize = HAMMER_BUFSIZE;
343fbc6e32aSMatthew Dillon 	mp->mnt_stat.f_bsize = HAMMER_BUFSIZE;
3446f97fce3SMatthew Dillon 
3456f97fce3SMatthew Dillon 	mp->mnt_vstat.f_frsize = HAMMER_BUFSIZE;
3466f97fce3SMatthew Dillon 	mp->mnt_vstat.f_bsize = HAMMER_BUFSIZE;
3476f97fce3SMatthew Dillon 
348427e5fc6SMatthew Dillon 	mp->mnt_maxsymlinklen = 255;
349427e5fc6SMatthew Dillon 	mp->mnt_flag |= MNT_LOCAL;
350427e5fc6SMatthew Dillon 
351427e5fc6SMatthew Dillon 	vfs_add_vnodeops(mp, &hammer_vnode_vops, &mp->mnt_vn_norm_ops);
3527a04d74fSMatthew Dillon 	vfs_add_vnodeops(mp, &hammer_spec_vops, &mp->mnt_vn_spec_ops);
3537a04d74fSMatthew Dillon 	vfs_add_vnodeops(mp, &hammer_fifo_vops, &mp->mnt_vn_fifo_ops);
35427ea2398SMatthew Dillon 
35527ea2398SMatthew Dillon 	/*
356a89aec1bSMatthew Dillon 	 * The root volume's ondisk pointer is only valid if we hold a
357a89aec1bSMatthew Dillon 	 * reference to it.
358a89aec1bSMatthew Dillon 	 */
359a89aec1bSMatthew Dillon 	rootvol = hammer_get_root_volume(hmp, &error);
360a89aec1bSMatthew Dillon 	if (error)
361f90dde4cSMatthew Dillon 		goto failed;
362f90dde4cSMatthew Dillon 
363f90dde4cSMatthew Dillon 	/*
3640729c8c8SMatthew Dillon 	 * Perform any necessary UNDO operations.  The recover code does
3650729c8c8SMatthew Dillon 	 * call hammer_undo_lookup() so we have to pre-cache the blockmap,
3660729c8c8SMatthew Dillon 	 * and then re-copy it again after recovery is complete.
367c9b9e29dSMatthew Dillon 	 *
36851c35492SMatthew Dillon 	 * The recovery code will load hmp->flusher_undo_start.
36951c35492SMatthew Dillon 	 *
37051c35492SMatthew Dillon 	 * If this is a read-only mount the UNDO information is retained
37151c35492SMatthew Dillon 	 * in memory in the form of dirty buffer cache buffers, and not
37251c35492SMatthew Dillon 	 * written back to the media.
373f90dde4cSMatthew Dillon 	 */
3740729c8c8SMatthew Dillon 	bcopy(rootvol->ondisk->vol0_blockmap, hmp->blockmap,
3750729c8c8SMatthew Dillon 	      sizeof(hmp->blockmap));
376c9b9e29dSMatthew Dillon 
377f90dde4cSMatthew Dillon 	error = hammer_recover(hmp, rootvol);
378f90dde4cSMatthew Dillon 	if (error) {
379f90dde4cSMatthew Dillon 		kprintf("Failed to recover HAMMER filesystem on mount\n");
380a89aec1bSMatthew Dillon 		goto done;
381f90dde4cSMatthew Dillon 	}
382f90dde4cSMatthew Dillon 
383f90dde4cSMatthew Dillon 	/*
384f90dde4cSMatthew Dillon 	 * Finish setup now that we have a good root volume
385f90dde4cSMatthew Dillon 	 */
386a89aec1bSMatthew Dillon 	ksnprintf(mp->mnt_stat.f_mntfromname,
387a89aec1bSMatthew Dillon 		  sizeof(mp->mnt_stat.f_mntfromname), "%s",
388a89aec1bSMatthew Dillon 		  rootvol->ondisk->vol_name);
389513ca7d7SMatthew Dillon 	mp->mnt_stat.f_fsid.val[0] =
390513ca7d7SMatthew Dillon 		crc32((char *)&rootvol->ondisk->vol_fsid + 0, 8);
391513ca7d7SMatthew Dillon 	mp->mnt_stat.f_fsid.val[1] =
392513ca7d7SMatthew Dillon 		crc32((char *)&rootvol->ondisk->vol_fsid + 8, 8);
393b84de5afSMatthew Dillon 
3946f97fce3SMatthew Dillon 	mp->mnt_vstat.f_fsid_uuid = rootvol->ondisk->vol_fsid;
3956f97fce3SMatthew Dillon 	mp->mnt_vstat.f_fsid = crc32(&mp->mnt_vstat.f_fsid_uuid,
3966f97fce3SMatthew Dillon 				     sizeof(mp->mnt_vstat.f_fsid_uuid));
3976f97fce3SMatthew Dillon 
3980729c8c8SMatthew Dillon 	/*
3990729c8c8SMatthew Dillon 	 * Certain often-modified fields in the root volume are cached in
4000729c8c8SMatthew Dillon 	 * the hammer_mount structure so we do not have to generate lots
4010729c8c8SMatthew Dillon 	 * of little UNDO structures for them.
402c9b9e29dSMatthew Dillon 	 *
403c9b9e29dSMatthew Dillon 	 * Recopy after recovery.
4040729c8c8SMatthew Dillon 	 */
405b84de5afSMatthew Dillon 	hmp->next_tid = rootvol->ondisk->vol0_next_tid;
4060729c8c8SMatthew Dillon 	bcopy(rootvol->ondisk->vol0_blockmap, hmp->blockmap,
4070729c8c8SMatthew Dillon 	      sizeof(hmp->blockmap));
408e63644f0SMatthew Dillon 	hmp->copy_stat_freebigblocks = rootvol->ondisk->vol0_stat_freebigblocks;
4090729c8c8SMatthew Dillon 
4100729c8c8SMatthew Dillon 	/*
4110729c8c8SMatthew Dillon 	 * Use the zone limit set by newfs_hammer, or the zone limit set by
4120729c8c8SMatthew Dillon 	 * sysctl (for debugging), whichever is smaller.
4130729c8c8SMatthew Dillon 	 */
4140729c8c8SMatthew Dillon 	if (rootvol->ondisk->vol0_zone_limit) {
4150729c8c8SMatthew Dillon 		hammer_off_t vol0_zone_limit;
4160729c8c8SMatthew Dillon 
4170729c8c8SMatthew Dillon 		vol0_zone_limit = rootvol->ondisk->vol0_zone_limit;
4180729c8c8SMatthew Dillon 		for (i = 0; i < HAMMER_MAX_ZONES; ++i) {
4190729c8c8SMatthew Dillon 			if (hmp->zone_limits[i] > vol0_zone_limit)
4200729c8c8SMatthew Dillon 				hmp->zone_limits[i] = vol0_zone_limit;
4210729c8c8SMatthew Dillon 		}
4220729c8c8SMatthew Dillon 	}
423b84de5afSMatthew Dillon 
424059819e3SMatthew Dillon 	hammer_flusher_create(hmp);
425059819e3SMatthew Dillon 
426a89aec1bSMatthew Dillon 	/*
42727ea2398SMatthew Dillon 	 * Locate the root directory using the root cluster's B-Tree as a
42827ea2398SMatthew Dillon 	 * starting point.  The root directory uses an obj_id of 1.
42927ea2398SMatthew Dillon 	 *
43027ea2398SMatthew Dillon 	 * FUTURE: Leave the root directory cached referenced but unlocked
43127ea2398SMatthew Dillon 	 * in hmp->rootvp (need to flush it on unmount).
43227ea2398SMatthew Dillon 	 */
43327ea2398SMatthew Dillon 	error = hammer_vfs_vget(mp, 1, &rootvp);
434a89aec1bSMatthew Dillon 	if (error)
435a89aec1bSMatthew Dillon 		goto done;
43627ea2398SMatthew Dillon 	vput(rootvp);
43727ea2398SMatthew Dillon 	/*vn_unlock(hmp->rootvp);*/
43827ea2398SMatthew Dillon 
439a89aec1bSMatthew Dillon done:
440f90dde4cSMatthew Dillon 	hammer_rel_volume(rootvol, 0);
441f90dde4cSMatthew Dillon failed:
44227ea2398SMatthew Dillon 	/*
44327ea2398SMatthew Dillon 	 * Cleanup and return.
44427ea2398SMatthew Dillon 	 */
44527ea2398SMatthew Dillon 	if (error)
44627ea2398SMatthew Dillon 		hammer_free_hmp(mp);
447427e5fc6SMatthew Dillon 	return (error);
448427e5fc6SMatthew Dillon }
449427e5fc6SMatthew Dillon 
450427e5fc6SMatthew Dillon static int
451427e5fc6SMatthew Dillon hammer_vfs_unmount(struct mount *mp, int mntflags)
452427e5fc6SMatthew Dillon {
453427e5fc6SMatthew Dillon #if 0
454427e5fc6SMatthew Dillon 	struct hammer_mount *hmp = (void *)mp->mnt_data;
455427e5fc6SMatthew Dillon #endif
456427e5fc6SMatthew Dillon 	int flags;
45766325755SMatthew Dillon 	int error;
45827ea2398SMatthew Dillon 
45927ea2398SMatthew Dillon 	/*
460427e5fc6SMatthew Dillon 	 * Clean out the vnodes
461427e5fc6SMatthew Dillon 	 */
46266325755SMatthew Dillon 	flags = 0;
46366325755SMatthew Dillon 	if (mntflags & MNT_FORCE)
46466325755SMatthew Dillon 		flags |= FORCECLOSE;
46566325755SMatthew Dillon 	if ((error = vflush(mp, 0, flags)) != 0)
46666325755SMatthew Dillon 		return (error);
467427e5fc6SMatthew Dillon 
468427e5fc6SMatthew Dillon 	/*
469427e5fc6SMatthew Dillon 	 * Clean up the internal mount structure and related entities.  This
470427e5fc6SMatthew Dillon 	 * may issue I/O.
471427e5fc6SMatthew Dillon 	 */
472427e5fc6SMatthew Dillon 	hammer_free_hmp(mp);
473427e5fc6SMatthew Dillon 	return(0);
474427e5fc6SMatthew Dillon }
475427e5fc6SMatthew Dillon 
476427e5fc6SMatthew Dillon /*
477427e5fc6SMatthew Dillon  * Clean up the internal mount structure and disassociate it from the mount.
478427e5fc6SMatthew Dillon  * This may issue I/O.
479427e5fc6SMatthew Dillon  */
480427e5fc6SMatthew Dillon static void
481427e5fc6SMatthew Dillon hammer_free_hmp(struct mount *mp)
482427e5fc6SMatthew Dillon {
483427e5fc6SMatthew Dillon 	struct hammer_mount *hmp = (void *)mp->mnt_data;
484bf686dbeSMatthew Dillon 	int i;
485427e5fc6SMatthew Dillon 
48627ea2398SMatthew Dillon #if 0
487427e5fc6SMatthew Dillon 	/*
488427e5fc6SMatthew Dillon 	 * Clean up the root vnode
489427e5fc6SMatthew Dillon 	 */
490427e5fc6SMatthew Dillon 	if (hmp->rootvp) {
491427e5fc6SMatthew Dillon 		vrele(hmp->rootvp);
492427e5fc6SMatthew Dillon 		hmp->rootvp = NULL;
493427e5fc6SMatthew Dillon 	}
49427ea2398SMatthew Dillon #endif
495059819e3SMatthew Dillon 	hammer_flusher_sync(hmp);
496b84de5afSMatthew Dillon 	hammer_flusher_sync(hmp);
497059819e3SMatthew Dillon 	hammer_flusher_destroy(hmp);
498427e5fc6SMatthew Dillon 
499b84de5afSMatthew Dillon 	KKASSERT(RB_EMPTY(&hmp->rb_inos_root));
500b84de5afSMatthew Dillon 
501b84de5afSMatthew Dillon #if 0
502427e5fc6SMatthew Dillon 	/*
503427e5fc6SMatthew Dillon 	 * Unload & flush inodes
504b84de5afSMatthew Dillon 	 *
505b84de5afSMatthew Dillon 	 * XXX illegal to call this from here, it can only be done from
506b84de5afSMatthew Dillon 	 * the flusher.
507427e5fc6SMatthew Dillon 	 */
508427e5fc6SMatthew Dillon 	RB_SCAN(hammer_ino_rb_tree, &hmp->rb_inos_root, NULL,
509d113fda1SMatthew Dillon 		hammer_unload_inode, (void *)MNT_WAIT);
510427e5fc6SMatthew Dillon 
511427e5fc6SMatthew Dillon 	/*
512427e5fc6SMatthew Dillon 	 * Unload & flush volumes
513427e5fc6SMatthew Dillon 	 */
514b84de5afSMatthew Dillon #endif
515b84de5afSMatthew Dillon 	/*
516b84de5afSMatthew Dillon 	 * Unload the volumes
517b84de5afSMatthew Dillon 	 */
518427e5fc6SMatthew Dillon 	RB_SCAN(hammer_vol_rb_tree, &hmp->rb_vols_root, NULL,
519427e5fc6SMatthew Dillon 		hammer_unload_volume, NULL);
520427e5fc6SMatthew Dillon 
521427e5fc6SMatthew Dillon 	mp->mnt_data = NULL;
52266325755SMatthew Dillon 	mp->mnt_flag &= ~MNT_LOCAL;
523427e5fc6SMatthew Dillon 	hmp->mp = NULL;
5240729c8c8SMatthew Dillon 	hammer_destroy_objid_cache(hmp);
52566325755SMatthew Dillon 	kfree(hmp->zbuf, M_HAMMER);
52640043e7fSMatthew Dillon 	lockuninit(&hmp->blockmap_lock);
527bf686dbeSMatthew Dillon 
528bf686dbeSMatthew Dillon 	for (i = 0; i < HAMMER_MAX_ZONES; ++i)
529bf686dbeSMatthew Dillon 		hammer_free_holes(hmp, &hmp->holes[i]);
530bf686dbeSMatthew Dillon 
531427e5fc6SMatthew Dillon 	kfree(hmp, M_HAMMER);
532427e5fc6SMatthew Dillon }
533427e5fc6SMatthew Dillon 
534427e5fc6SMatthew Dillon /*
535513ca7d7SMatthew Dillon  * Obtain a vnode for the specified inode number.  An exclusively locked
536513ca7d7SMatthew Dillon  * vnode is returned.
537513ca7d7SMatthew Dillon  */
538513ca7d7SMatthew Dillon int
539513ca7d7SMatthew Dillon hammer_vfs_vget(struct mount *mp, ino_t ino, struct vnode **vpp)
540513ca7d7SMatthew Dillon {
54136f82b23SMatthew Dillon 	struct hammer_transaction trans;
542513ca7d7SMatthew Dillon 	struct hammer_mount *hmp = (void *)mp->mnt_data;
543513ca7d7SMatthew Dillon 	struct hammer_inode *ip;
544513ca7d7SMatthew Dillon 	int error;
545513ca7d7SMatthew Dillon 
54636f82b23SMatthew Dillon 	hammer_simple_transaction(&trans, hmp);
54736f82b23SMatthew Dillon 
548513ca7d7SMatthew Dillon 	/*
54936f82b23SMatthew Dillon 	 * Lookup the requested HAMMER inode.  The structure must be
55036f82b23SMatthew Dillon 	 * left unlocked while we manipulate the related vnode to avoid
55136f82b23SMatthew Dillon 	 * a deadlock.
552513ca7d7SMatthew Dillon 	 */
55336f82b23SMatthew Dillon 	ip = hammer_get_inode(&trans, NULL, ino, hmp->asof, 0, &error);
554513ca7d7SMatthew Dillon 	if (ip == NULL) {
555513ca7d7SMatthew Dillon 		*vpp = NULL;
556513ca7d7SMatthew Dillon 		return(error);
557513ca7d7SMatthew Dillon 	}
558e8599db1SMatthew Dillon 	error = hammer_get_vnode(ip, vpp);
559513ca7d7SMatthew Dillon 	hammer_rel_inode(ip, 0);
560b84de5afSMatthew Dillon 	hammer_done_transaction(&trans);
561513ca7d7SMatthew Dillon 	return (error);
562513ca7d7SMatthew Dillon }
563513ca7d7SMatthew Dillon 
564513ca7d7SMatthew Dillon /*
565427e5fc6SMatthew Dillon  * Return the root vnode for the filesystem.
566427e5fc6SMatthew Dillon  *
567427e5fc6SMatthew Dillon  * HAMMER stores the root vnode in the hammer_mount structure so
568427e5fc6SMatthew Dillon  * getting it is easy.
569427e5fc6SMatthew Dillon  */
570427e5fc6SMatthew Dillon static int
571427e5fc6SMatthew Dillon hammer_vfs_root(struct mount *mp, struct vnode **vpp)
572427e5fc6SMatthew Dillon {
57347197d71SMatthew Dillon #if 0
574427e5fc6SMatthew Dillon 	struct hammer_mount *hmp = (void *)mp->mnt_data;
57547197d71SMatthew Dillon #endif
57627ea2398SMatthew Dillon 	int error;
577427e5fc6SMatthew Dillon 
57827ea2398SMatthew Dillon 	error = hammer_vfs_vget(mp, 1, vpp);
57927ea2398SMatthew Dillon 	return (error);
580427e5fc6SMatthew Dillon }
581427e5fc6SMatthew Dillon 
582427e5fc6SMatthew Dillon static int
583427e5fc6SMatthew Dillon hammer_vfs_statfs(struct mount *mp, struct statfs *sbp, struct ucred *cred)
584427e5fc6SMatthew Dillon {
585fbc6e32aSMatthew Dillon 	struct hammer_mount *hmp = (void *)mp->mnt_data;
586fbc6e32aSMatthew Dillon 	hammer_volume_t volume;
587fbc6e32aSMatthew Dillon 	hammer_volume_ondisk_t ondisk;
588fbc6e32aSMatthew Dillon 	int error;
58947197d71SMatthew Dillon 	int64_t bfree;
590fbc6e32aSMatthew Dillon 
591fbc6e32aSMatthew Dillon 	volume = hammer_get_root_volume(hmp, &error);
592fbc6e32aSMatthew Dillon 	if (error)
593fbc6e32aSMatthew Dillon 		return(error);
594fbc6e32aSMatthew Dillon 	ondisk = volume->ondisk;
595fbc6e32aSMatthew Dillon 
59647197d71SMatthew Dillon 	/*
59747197d71SMatthew Dillon 	 * Basic stats
59847197d71SMatthew Dillon 	 */
599fbc6e32aSMatthew Dillon 	mp->mnt_stat.f_files = ondisk->vol0_stat_inodes;
600c3be93f2SMatthew Dillon 	bfree = ondisk->vol0_stat_freebigblocks * HAMMER_LARGEBLOCK_SIZE;
60140043e7fSMatthew Dillon 	hammer_rel_volume(volume, 0);
60247197d71SMatthew Dillon 
60347197d71SMatthew Dillon 	mp->mnt_stat.f_bfree = bfree / HAMMER_BUFSIZE;
60447197d71SMatthew Dillon 	mp->mnt_stat.f_bavail = mp->mnt_stat.f_bfree;
605fbc6e32aSMatthew Dillon 	if (mp->mnt_stat.f_files < 0)
606fbc6e32aSMatthew Dillon 		mp->mnt_stat.f_files = 0;
607fbc6e32aSMatthew Dillon 
60827ea2398SMatthew Dillon 	*sbp = mp->mnt_stat;
60927ea2398SMatthew Dillon 	return(0);
610427e5fc6SMatthew Dillon }
611427e5fc6SMatthew Dillon 
6126f97fce3SMatthew Dillon static int
6136f97fce3SMatthew Dillon hammer_vfs_statvfs(struct mount *mp, struct statvfs *sbp, struct ucred *cred)
6146f97fce3SMatthew Dillon {
6156f97fce3SMatthew Dillon 	struct hammer_mount *hmp = (void *)mp->mnt_data;
6166f97fce3SMatthew Dillon 	hammer_volume_t volume;
6176f97fce3SMatthew Dillon 	hammer_volume_ondisk_t ondisk;
6186f97fce3SMatthew Dillon 	int error;
6196f97fce3SMatthew Dillon 	int64_t bfree;
6206f97fce3SMatthew Dillon 
6216f97fce3SMatthew Dillon 	volume = hammer_get_root_volume(hmp, &error);
6226f97fce3SMatthew Dillon 	if (error)
6236f97fce3SMatthew Dillon 		return(error);
6246f97fce3SMatthew Dillon 	ondisk = volume->ondisk;
6256f97fce3SMatthew Dillon 
6266f97fce3SMatthew Dillon 	/*
6276f97fce3SMatthew Dillon 	 * Basic stats
6286f97fce3SMatthew Dillon 	 */
6296f97fce3SMatthew Dillon 	mp->mnt_vstat.f_files = ondisk->vol0_stat_inodes;
6306f97fce3SMatthew Dillon 	bfree = ondisk->vol0_stat_freebigblocks * HAMMER_LARGEBLOCK_SIZE;
6316f97fce3SMatthew Dillon 	hammer_rel_volume(volume, 0);
6326f97fce3SMatthew Dillon 
6336f97fce3SMatthew Dillon 	mp->mnt_vstat.f_bfree = bfree / HAMMER_BUFSIZE;
6346f97fce3SMatthew Dillon 	mp->mnt_vstat.f_bavail = mp->mnt_stat.f_bfree;
6356f97fce3SMatthew Dillon 	if (mp->mnt_vstat.f_files < 0)
6366f97fce3SMatthew Dillon 		mp->mnt_vstat.f_files = 0;
6376f97fce3SMatthew Dillon 	*sbp = mp->mnt_vstat;
6386f97fce3SMatthew Dillon 	return(0);
6396f97fce3SMatthew Dillon }
6406f97fce3SMatthew Dillon 
6410729c8c8SMatthew Dillon /*
6420729c8c8SMatthew Dillon  * Sync the filesystem.  Currently we have to run it twice, the second
6430729c8c8SMatthew Dillon  * one will advance the undo start index to the end index, so if a crash
6440729c8c8SMatthew Dillon  * occurs no undos will be run on mount.
64577062c8aSMatthew Dillon  *
64677062c8aSMatthew Dillon  * We do not sync the filesystem if we are called from a panic.  If we did
64777062c8aSMatthew Dillon  * we might end up blowing up a sync that was already in progress.
6480729c8c8SMatthew Dillon  */
649427e5fc6SMatthew Dillon static int
650427e5fc6SMatthew Dillon hammer_vfs_sync(struct mount *mp, int waitfor)
651427e5fc6SMatthew Dillon {
652fbc6e32aSMatthew Dillon 	struct hammer_mount *hmp = (void *)mp->mnt_data;
6530729c8c8SMatthew Dillon 	int error;
6540729c8c8SMatthew Dillon 
65577062c8aSMatthew Dillon 	if (panicstr == NULL) {
6560729c8c8SMatthew Dillon 		error = hammer_sync_hmp(hmp, waitfor);
6570729c8c8SMatthew Dillon 		if (error == 0)
6580729c8c8SMatthew Dillon 			error = hammer_sync_hmp(hmp, waitfor);
65977062c8aSMatthew Dillon 	} else {
66077062c8aSMatthew Dillon 		error = EIO;
66177062c8aSMatthew Dillon 		hkprintf("S");
66277062c8aSMatthew Dillon 	}
6630729c8c8SMatthew Dillon 	return (error);
664427e5fc6SMatthew Dillon }
665427e5fc6SMatthew Dillon 
666513ca7d7SMatthew Dillon /*
667513ca7d7SMatthew Dillon  * Convert a vnode to a file handle.
668513ca7d7SMatthew Dillon  */
669513ca7d7SMatthew Dillon static int
670513ca7d7SMatthew Dillon hammer_vfs_vptofh(struct vnode *vp, struct fid *fhp)
671513ca7d7SMatthew Dillon {
672513ca7d7SMatthew Dillon 	hammer_inode_t ip;
673513ca7d7SMatthew Dillon 
674513ca7d7SMatthew Dillon 	KKASSERT(MAXFIDSZ >= 16);
675513ca7d7SMatthew Dillon 	ip = VTOI(vp);
676513ca7d7SMatthew Dillon 	fhp->fid_len = offsetof(struct fid, fid_data[16]);
677513ca7d7SMatthew Dillon 	fhp->fid_reserved = 0;
678513ca7d7SMatthew Dillon 	bcopy(&ip->obj_id, fhp->fid_data + 0, sizeof(ip->obj_id));
679513ca7d7SMatthew Dillon 	bcopy(&ip->obj_asof, fhp->fid_data + 8, sizeof(ip->obj_asof));
680513ca7d7SMatthew Dillon 	return(0);
681513ca7d7SMatthew Dillon }
682513ca7d7SMatthew Dillon 
683513ca7d7SMatthew Dillon 
684513ca7d7SMatthew Dillon /*
685513ca7d7SMatthew Dillon  * Convert a file handle back to a vnode.
686513ca7d7SMatthew Dillon  */
687513ca7d7SMatthew Dillon static int
688513ca7d7SMatthew Dillon hammer_vfs_fhtovp(struct mount *mp, struct fid *fhp, struct vnode **vpp)
689513ca7d7SMatthew Dillon {
69036f82b23SMatthew Dillon 	struct hammer_transaction trans;
691513ca7d7SMatthew Dillon 	struct hammer_inode *ip;
692513ca7d7SMatthew Dillon 	struct hammer_inode_info info;
693513ca7d7SMatthew Dillon 	int error;
694513ca7d7SMatthew Dillon 
695513ca7d7SMatthew Dillon 	bcopy(fhp->fid_data + 0, &info.obj_id, sizeof(info.obj_id));
696513ca7d7SMatthew Dillon 	bcopy(fhp->fid_data + 8, &info.obj_asof, sizeof(info.obj_asof));
697513ca7d7SMatthew Dillon 
69836f82b23SMatthew Dillon 	hammer_simple_transaction(&trans, (void *)mp->mnt_data);
69936f82b23SMatthew Dillon 
700513ca7d7SMatthew Dillon 	/*
701513ca7d7SMatthew Dillon 	 * Get/allocate the hammer_inode structure.  The structure must be
702513ca7d7SMatthew Dillon 	 * unlocked while we manipulate the related vnode to avoid a
703513ca7d7SMatthew Dillon 	 * deadlock.
704513ca7d7SMatthew Dillon 	 */
70536f82b23SMatthew Dillon 	ip = hammer_get_inode(&trans, NULL, info.obj_id, info.obj_asof,
70636f82b23SMatthew Dillon 			      0, &error);
707513ca7d7SMatthew Dillon 	if (ip == NULL) {
708513ca7d7SMatthew Dillon 		*vpp = NULL;
709513ca7d7SMatthew Dillon 		return(error);
710513ca7d7SMatthew Dillon 	}
711e8599db1SMatthew Dillon 	error = hammer_get_vnode(ip, vpp);
712513ca7d7SMatthew Dillon 	hammer_rel_inode(ip, 0);
713b84de5afSMatthew Dillon 	hammer_done_transaction(&trans);
714513ca7d7SMatthew Dillon 	return (error);
715513ca7d7SMatthew Dillon }
716513ca7d7SMatthew Dillon 
717513ca7d7SMatthew Dillon static int
718513ca7d7SMatthew Dillon hammer_vfs_checkexp(struct mount *mp, struct sockaddr *nam,
719513ca7d7SMatthew Dillon 		    int *exflagsp, struct ucred **credanonp)
720513ca7d7SMatthew Dillon {
721513ca7d7SMatthew Dillon 	hammer_mount_t hmp = (void *)mp->mnt_data;
722513ca7d7SMatthew Dillon 	struct netcred *np;
723513ca7d7SMatthew Dillon 	int error;
724513ca7d7SMatthew Dillon 
725513ca7d7SMatthew Dillon 	np = vfs_export_lookup(mp, &hmp->export, nam);
726513ca7d7SMatthew Dillon 	if (np) {
727513ca7d7SMatthew Dillon 		*exflagsp = np->netc_exflags;
728513ca7d7SMatthew Dillon 		*credanonp = &np->netc_anon;
729513ca7d7SMatthew Dillon 		error = 0;
730513ca7d7SMatthew Dillon 	} else {
731513ca7d7SMatthew Dillon 		error = EACCES;
732513ca7d7SMatthew Dillon 	}
733513ca7d7SMatthew Dillon 	return (error);
734513ca7d7SMatthew Dillon 
735513ca7d7SMatthew Dillon }
736513ca7d7SMatthew Dillon 
737513ca7d7SMatthew Dillon int
738513ca7d7SMatthew Dillon hammer_vfs_export(struct mount *mp, int op, const struct export_args *export)
739513ca7d7SMatthew Dillon {
740513ca7d7SMatthew Dillon 	hammer_mount_t hmp = (void *)mp->mnt_data;
741513ca7d7SMatthew Dillon 	int error;
742513ca7d7SMatthew Dillon 
743513ca7d7SMatthew Dillon 	switch(op) {
744513ca7d7SMatthew Dillon 	case MOUNTCTL_SET_EXPORT:
745513ca7d7SMatthew Dillon 		error = vfs_export(mp, &hmp->export, export);
746513ca7d7SMatthew Dillon 		break;
747513ca7d7SMatthew Dillon 	default:
748513ca7d7SMatthew Dillon 		error = EOPNOTSUPP;
749513ca7d7SMatthew Dillon 		break;
750513ca7d7SMatthew Dillon 	}
751513ca7d7SMatthew Dillon 	return(error);
752513ca7d7SMatthew Dillon }
753513ca7d7SMatthew Dillon 
754