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*d99d6bf5SMatthew Dillon * $DragonFly: src/sys/vfs/hammer/hammer_vfsops.c,v 1.46 2008/06/12 00:16:10 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; 59cebe9493SMatthew Dillon int hammer_debug_write_release; /* if 1 release buffer on strategy */ 60a99b9ea2SMatthew Dillon int hammer_debug_cluster_enable = 1; /* enable read clustering by default */ 61b3deaf57SMatthew Dillon int hammer_count_inodes; 62af209b0fSMatthew Dillon int hammer_count_iqueued; 639f5097dcSMatthew Dillon int hammer_count_reclaiming; 64b3deaf57SMatthew Dillon int hammer_count_records; 65b3deaf57SMatthew Dillon int hammer_count_record_datas; 66b3deaf57SMatthew Dillon int hammer_count_volumes; 67b3deaf57SMatthew Dillon int hammer_count_buffers; 68b3deaf57SMatthew Dillon int hammer_count_nodes; 699480ff55SMatthew Dillon int hammer_count_dirtybufs; /* global */ 70a99b9ea2SMatthew Dillon int hammer_count_refedbufs; /* global */ 710832c9bbSMatthew Dillon int hammer_count_reservations; 72a99b9ea2SMatthew Dillon int hammer_count_io_running_read; 73a99b9ea2SMatthew Dillon int hammer_count_io_running_write; 74a99b9ea2SMatthew Dillon int hammer_count_io_locked; 7547637bffSMatthew Dillon int hammer_stats_btree_iterations; 7647637bffSMatthew Dillon int hammer_stats_record_iterations; 779f5097dcSMatthew Dillon int hammer_limit_dirtybufs; /* per-mount */ 780832c9bbSMatthew Dillon int hammer_limit_irecs; /* per-inode */ 790832c9bbSMatthew Dillon int hammer_limit_recs; /* as a whole XXX */ 80af209b0fSMatthew Dillon int hammer_limit_iqueued; /* per-mount */ 811f07f686SMatthew Dillon int hammer_bio_count; 827d683b0fSMatthew Dillon int64_t hammer_contention_count; 83f03c9cf4SMatthew Dillon int64_t hammer_zone_limit; 84b3deaf57SMatthew Dillon 85b3deaf57SMatthew Dillon SYSCTL_NODE(_vfs, OID_AUTO, hammer, CTLFLAG_RW, 0, "HAMMER filesystem"); 86d5ef456eSMatthew Dillon SYSCTL_INT(_vfs_hammer, OID_AUTO, debug_general, CTLFLAG_RW, 87d5ef456eSMatthew Dillon &hammer_debug_general, 0, ""); 882f85fa4dSMatthew Dillon SYSCTL_INT(_vfs_hammer, OID_AUTO, debug_io, CTLFLAG_RW, 892f85fa4dSMatthew Dillon &hammer_debug_io, 0, ""); 9077062c8aSMatthew Dillon SYSCTL_INT(_vfs_hammer, OID_AUTO, debug_debug, CTLFLAG_RW, 9177062c8aSMatthew Dillon &hammer_debug_debug, 0, ""); 92e8599db1SMatthew Dillon SYSCTL_INT(_vfs_hammer, OID_AUTO, debug_inode, CTLFLAG_RW, 93e8599db1SMatthew Dillon &hammer_debug_inode, 0, ""); 947d683b0fSMatthew Dillon SYSCTL_INT(_vfs_hammer, OID_AUTO, debug_locks, CTLFLAG_RW, 957d683b0fSMatthew Dillon &hammer_debug_locks, 0, ""); 96b3deaf57SMatthew Dillon SYSCTL_INT(_vfs_hammer, OID_AUTO, debug_btree, CTLFLAG_RW, 97b3deaf57SMatthew Dillon &hammer_debug_btree, 0, ""); 98d113fda1SMatthew Dillon SYSCTL_INT(_vfs_hammer, OID_AUTO, debug_tid, CTLFLAG_RW, 99d113fda1SMatthew Dillon &hammer_debug_tid, 0, ""); 100b33e2cc0SMatthew Dillon SYSCTL_INT(_vfs_hammer, OID_AUTO, debug_recover, CTLFLAG_RW, 101b33e2cc0SMatthew Dillon &hammer_debug_recover, 0, ""); 10246fe7ae1SMatthew Dillon SYSCTL_INT(_vfs_hammer, OID_AUTO, debug_recover_faults, CTLFLAG_RW, 10346fe7ae1SMatthew Dillon &hammer_debug_recover_faults, 0, ""); 104cebe9493SMatthew Dillon SYSCTL_INT(_vfs_hammer, OID_AUTO, debug_write_release, CTLFLAG_RW, 105cebe9493SMatthew Dillon &hammer_debug_write_release, 0, ""); 106a99b9ea2SMatthew Dillon SYSCTL_INT(_vfs_hammer, OID_AUTO, debug_cluster_enable, CTLFLAG_RW, 107a99b9ea2SMatthew Dillon &hammer_debug_cluster_enable, 0, ""); 1089480ff55SMatthew Dillon 1099480ff55SMatthew Dillon SYSCTL_INT(_vfs_hammer, OID_AUTO, limit_dirtybufs, CTLFLAG_RW, 1109480ff55SMatthew Dillon &hammer_limit_dirtybufs, 0, ""); 11147637bffSMatthew Dillon SYSCTL_INT(_vfs_hammer, OID_AUTO, limit_irecs, CTLFLAG_RW, 11247637bffSMatthew Dillon &hammer_limit_irecs, 0, ""); 11347637bffSMatthew Dillon SYSCTL_INT(_vfs_hammer, OID_AUTO, limit_recs, CTLFLAG_RW, 11447637bffSMatthew Dillon &hammer_limit_recs, 0, ""); 115af209b0fSMatthew Dillon SYSCTL_INT(_vfs_hammer, OID_AUTO, limit_iqueued, CTLFLAG_RW, 116af209b0fSMatthew Dillon &hammer_limit_iqueued, 0, ""); 1179480ff55SMatthew Dillon 118b3deaf57SMatthew Dillon SYSCTL_INT(_vfs_hammer, OID_AUTO, count_inodes, CTLFLAG_RD, 119b3deaf57SMatthew Dillon &hammer_count_inodes, 0, ""); 120af209b0fSMatthew Dillon SYSCTL_INT(_vfs_hammer, OID_AUTO, count_iqueued, CTLFLAG_RD, 121af209b0fSMatthew Dillon &hammer_count_iqueued, 0, ""); 1229f5097dcSMatthew Dillon SYSCTL_INT(_vfs_hammer, OID_AUTO, count_reclaiming, CTLFLAG_RD, 1239f5097dcSMatthew Dillon &hammer_count_reclaiming, 0, ""); 124b3deaf57SMatthew Dillon SYSCTL_INT(_vfs_hammer, OID_AUTO, count_records, CTLFLAG_RD, 125b3deaf57SMatthew Dillon &hammer_count_records, 0, ""); 126b3deaf57SMatthew Dillon SYSCTL_INT(_vfs_hammer, OID_AUTO, count_record_datas, CTLFLAG_RD, 127b3deaf57SMatthew Dillon &hammer_count_record_datas, 0, ""); 128b3deaf57SMatthew Dillon SYSCTL_INT(_vfs_hammer, OID_AUTO, count_volumes, CTLFLAG_RD, 129b3deaf57SMatthew Dillon &hammer_count_volumes, 0, ""); 130b3deaf57SMatthew Dillon SYSCTL_INT(_vfs_hammer, OID_AUTO, count_buffers, CTLFLAG_RD, 131b3deaf57SMatthew Dillon &hammer_count_buffers, 0, ""); 132b3deaf57SMatthew Dillon SYSCTL_INT(_vfs_hammer, OID_AUTO, count_nodes, CTLFLAG_RD, 133b3deaf57SMatthew Dillon &hammer_count_nodes, 0, ""); 1349480ff55SMatthew Dillon SYSCTL_INT(_vfs_hammer, OID_AUTO, count_dirtybufs, CTLFLAG_RD, 1359480ff55SMatthew Dillon &hammer_count_dirtybufs, 0, ""); 136a99b9ea2SMatthew Dillon SYSCTL_INT(_vfs_hammer, OID_AUTO, count_refedbufs, CTLFLAG_RD, 137a99b9ea2SMatthew Dillon &hammer_count_refedbufs, 0, ""); 1380832c9bbSMatthew Dillon SYSCTL_INT(_vfs_hammer, OID_AUTO, count_reservations, CTLFLAG_RD, 1390832c9bbSMatthew Dillon &hammer_count_reservations, 0, ""); 140a99b9ea2SMatthew Dillon SYSCTL_INT(_vfs_hammer, OID_AUTO, count_io_running_read, CTLFLAG_RD, 141a99b9ea2SMatthew Dillon &hammer_count_io_running_read, 0, ""); 142a99b9ea2SMatthew Dillon SYSCTL_INT(_vfs_hammer, OID_AUTO, count_io_locked, CTLFLAG_RD, 143a99b9ea2SMatthew Dillon &hammer_count_io_locked, 0, ""); 144a99b9ea2SMatthew Dillon SYSCTL_INT(_vfs_hammer, OID_AUTO, count_io_running_write, CTLFLAG_RD, 145a99b9ea2SMatthew Dillon &hammer_count_io_running_write, 0, ""); 146f03c9cf4SMatthew Dillon SYSCTL_QUAD(_vfs_hammer, OID_AUTO, zone_limit, CTLFLAG_RW, 147f03c9cf4SMatthew Dillon &hammer_zone_limit, 0, ""); 1487d683b0fSMatthew Dillon SYSCTL_QUAD(_vfs_hammer, OID_AUTO, contention_count, CTLFLAG_RW, 1497d683b0fSMatthew Dillon &hammer_contention_count, 0, ""); 150b3deaf57SMatthew Dillon 151427e5fc6SMatthew Dillon /* 152427e5fc6SMatthew Dillon * VFS ABI 153427e5fc6SMatthew Dillon */ 154427e5fc6SMatthew Dillon static void hammer_free_hmp(struct mount *mp); 155427e5fc6SMatthew Dillon 156427e5fc6SMatthew Dillon static int hammer_vfs_mount(struct mount *mp, char *path, caddr_t data, 157427e5fc6SMatthew Dillon struct ucred *cred); 158427e5fc6SMatthew Dillon static int hammer_vfs_unmount(struct mount *mp, int mntflags); 159427e5fc6SMatthew Dillon static int hammer_vfs_root(struct mount *mp, struct vnode **vpp); 160427e5fc6SMatthew Dillon static int hammer_vfs_statfs(struct mount *mp, struct statfs *sbp, 161427e5fc6SMatthew Dillon struct ucred *cred); 1626f97fce3SMatthew Dillon static int hammer_vfs_statvfs(struct mount *mp, struct statvfs *sbp, 1636f97fce3SMatthew Dillon struct ucred *cred); 164427e5fc6SMatthew Dillon static int hammer_vfs_sync(struct mount *mp, int waitfor); 165513ca7d7SMatthew Dillon static int hammer_vfs_vget(struct mount *mp, ino_t ino, 166513ca7d7SMatthew Dillon struct vnode **vpp); 167427e5fc6SMatthew Dillon static int hammer_vfs_init(struct vfsconf *conf); 168513ca7d7SMatthew Dillon static int hammer_vfs_fhtovp(struct mount *mp, struct fid *fhp, 169513ca7d7SMatthew Dillon struct vnode **vpp); 170513ca7d7SMatthew Dillon static int hammer_vfs_vptofh(struct vnode *vp, struct fid *fhp); 171513ca7d7SMatthew Dillon static int hammer_vfs_checkexp(struct mount *mp, struct sockaddr *nam, 172513ca7d7SMatthew Dillon int *exflagsp, struct ucred **credanonp); 173513ca7d7SMatthew Dillon 174427e5fc6SMatthew Dillon 175427e5fc6SMatthew Dillon static struct vfsops hammer_vfsops = { 176427e5fc6SMatthew Dillon .vfs_mount = hammer_vfs_mount, 177427e5fc6SMatthew Dillon .vfs_unmount = hammer_vfs_unmount, 178427e5fc6SMatthew Dillon .vfs_root = hammer_vfs_root, 179427e5fc6SMatthew Dillon .vfs_statfs = hammer_vfs_statfs, 1806f97fce3SMatthew Dillon .vfs_statvfs = hammer_vfs_statvfs, 181427e5fc6SMatthew Dillon .vfs_sync = hammer_vfs_sync, 182427e5fc6SMatthew Dillon .vfs_vget = hammer_vfs_vget, 183513ca7d7SMatthew Dillon .vfs_init = hammer_vfs_init, 184513ca7d7SMatthew Dillon .vfs_vptofh = hammer_vfs_vptofh, 185513ca7d7SMatthew Dillon .vfs_fhtovp = hammer_vfs_fhtovp, 186513ca7d7SMatthew Dillon .vfs_checkexp = hammer_vfs_checkexp 187427e5fc6SMatthew Dillon }; 188427e5fc6SMatthew Dillon 189427e5fc6SMatthew Dillon MALLOC_DEFINE(M_HAMMER, "hammer-mount", "hammer mount"); 190427e5fc6SMatthew Dillon 191427e5fc6SMatthew Dillon VFS_SET(hammer_vfsops, hammer, 0); 192427e5fc6SMatthew Dillon MODULE_VERSION(hammer, 1); 193427e5fc6SMatthew Dillon 194427e5fc6SMatthew Dillon static int 195427e5fc6SMatthew Dillon hammer_vfs_init(struct vfsconf *conf) 196427e5fc6SMatthew Dillon { 1970832c9bbSMatthew Dillon if (hammer_limit_irecs == 0) 198a99b9ea2SMatthew Dillon hammer_limit_irecs = nbuf * 8; 1990832c9bbSMatthew Dillon if (hammer_limit_recs == 0) /* XXX TODO */ 200a99b9ea2SMatthew Dillon hammer_limit_recs = nbuf * 25; 2019f5097dcSMatthew Dillon if (hammer_limit_dirtybufs == 0) { 2029f5097dcSMatthew Dillon hammer_limit_dirtybufs = hidirtybuffers / 2; 2039f5097dcSMatthew Dillon if (hammer_limit_dirtybufs < 100) 2049f5097dcSMatthew Dillon hammer_limit_dirtybufs = 100; 2059f5097dcSMatthew Dillon } 206af209b0fSMatthew Dillon if (hammer_limit_iqueued == 0) 207af209b0fSMatthew Dillon hammer_limit_iqueued = desiredvnodes / 5; 208427e5fc6SMatthew Dillon return(0); 209427e5fc6SMatthew Dillon } 210427e5fc6SMatthew Dillon 211427e5fc6SMatthew Dillon static int 212427e5fc6SMatthew Dillon hammer_vfs_mount(struct mount *mp, char *mntpt, caddr_t data, 213427e5fc6SMatthew Dillon struct ucred *cred) 214427e5fc6SMatthew Dillon { 215427e5fc6SMatthew Dillon struct hammer_mount_info info; 216a89aec1bSMatthew Dillon hammer_mount_t hmp; 217a89aec1bSMatthew Dillon hammer_volume_t rootvol; 21827ea2398SMatthew Dillon struct vnode *rootvp; 219427e5fc6SMatthew Dillon const char *upath; /* volume name in userspace */ 220427e5fc6SMatthew Dillon char *path; /* volume name in system space */ 221427e5fc6SMatthew Dillon int error; 222427e5fc6SMatthew Dillon int i; 223427e5fc6SMatthew Dillon 224427e5fc6SMatthew Dillon if ((error = copyin(data, &info, sizeof(info))) != 0) 225427e5fc6SMatthew Dillon return (error); 22651c35492SMatthew Dillon if ((mp->mnt_flag & MNT_UPDATE) == 0) { 227427e5fc6SMatthew Dillon if (info.nvolumes <= 0 || info.nvolumes >= 32768) 228427e5fc6SMatthew Dillon return (EINVAL); 22951c35492SMatthew Dillon } 230427e5fc6SMatthew Dillon 231427e5fc6SMatthew Dillon /* 232427e5fc6SMatthew Dillon * Interal mount data structure 233427e5fc6SMatthew Dillon */ 234195c19a1SMatthew Dillon if (mp->mnt_flag & MNT_UPDATE) { 235195c19a1SMatthew Dillon hmp = (void *)mp->mnt_data; 236195c19a1SMatthew Dillon KKASSERT(hmp != NULL); 237195c19a1SMatthew Dillon } else { 238427e5fc6SMatthew Dillon hmp = kmalloc(sizeof(*hmp), M_HAMMER, M_WAITOK | M_ZERO); 239427e5fc6SMatthew Dillon mp->mnt_data = (qaddr_t)hmp; 240427e5fc6SMatthew Dillon hmp->mp = mp; 241195c19a1SMatthew Dillon hmp->zbuf = kmalloc(HAMMER_BUFSIZE, M_HAMMER, M_WAITOK|M_ZERO); 242195c19a1SMatthew Dillon hmp->namekey_iterator = mycpu->gd_time_seconds; 24346fe7ae1SMatthew Dillon /*TAILQ_INIT(&hmp->recycle_list);*/ 24447197d71SMatthew Dillon 2452f85fa4dSMatthew Dillon hmp->root_btree_beg.localization = HAMMER_MIN_LOCALIZATION; 24647197d71SMatthew Dillon hmp->root_btree_beg.obj_id = -0x8000000000000000LL; 24747197d71SMatthew Dillon hmp->root_btree_beg.key = -0x8000000000000000LL; 24847197d71SMatthew Dillon hmp->root_btree_beg.create_tid = 1; 24947197d71SMatthew Dillon hmp->root_btree_beg.delete_tid = 1; 25047197d71SMatthew Dillon hmp->root_btree_beg.rec_type = 0; 25147197d71SMatthew Dillon hmp->root_btree_beg.obj_type = 0; 25247197d71SMatthew Dillon 2532f85fa4dSMatthew Dillon hmp->root_btree_end.localization = HAMMER_MAX_LOCALIZATION; 25447197d71SMatthew Dillon hmp->root_btree_end.obj_id = 0x7FFFFFFFFFFFFFFFLL; 25547197d71SMatthew Dillon hmp->root_btree_end.key = 0x7FFFFFFFFFFFFFFFLL; 25647197d71SMatthew Dillon hmp->root_btree_end.create_tid = 0xFFFFFFFFFFFFFFFFULL; 25747197d71SMatthew Dillon hmp->root_btree_end.delete_tid = 0; /* special case */ 25847197d71SMatthew Dillon hmp->root_btree_end.rec_type = 0xFFFFU; 25947197d71SMatthew Dillon hmp->root_btree_end.obj_type = 0; 260f03c9cf4SMatthew Dillon 2619480ff55SMatthew Dillon hmp->sync_lock.refs = 1; 262c9b9e29dSMatthew Dillon hmp->free_lock.refs = 1; 263*d99d6bf5SMatthew Dillon hmp->undo_lock.refs = 1; 264*d99d6bf5SMatthew Dillon hmp->blkmap_lock.refs = 1; 2659480ff55SMatthew Dillon 266059819e3SMatthew Dillon TAILQ_INIT(&hmp->flush_list); 267cebe9493SMatthew Dillon TAILQ_INIT(&hmp->delay_list); 2680729c8c8SMatthew Dillon TAILQ_INIT(&hmp->objid_cache_list); 269e8599db1SMatthew Dillon TAILQ_INIT(&hmp->undo_lru_list); 270059819e3SMatthew Dillon 2710729c8c8SMatthew Dillon /* 2720729c8c8SMatthew Dillon * Set default zone limits. This value can be reduced 2730729c8c8SMatthew Dillon * further by the zone limit specified in the root volume. 2740729c8c8SMatthew Dillon * 2750729c8c8SMatthew Dillon * The sysctl can force a small zone limit for debugging 2760729c8c8SMatthew Dillon * purposes. 2770729c8c8SMatthew Dillon */ 278f03c9cf4SMatthew Dillon for (i = 0; i < HAMMER_MAX_ZONES; ++i) { 279f03c9cf4SMatthew Dillon hmp->zone_limits[i] = 280f03c9cf4SMatthew Dillon HAMMER_ZONE_ENCODE(i, HAMMER_ZONE_LIMIT); 2810729c8c8SMatthew Dillon 282f03c9cf4SMatthew Dillon if (hammer_zone_limit) { 283f03c9cf4SMatthew Dillon hmp->zone_limits[i] = 284f03c9cf4SMatthew Dillon HAMMER_ZONE_ENCODE(i, hammer_zone_limit); 285f03c9cf4SMatthew Dillon } 286bf686dbeSMatthew Dillon hammer_init_holes(hmp, &hmp->holes[i]); 287f03c9cf4SMatthew Dillon } 288195c19a1SMatthew Dillon } 28951c35492SMatthew Dillon hmp->hflags &= ~HMNT_USERFLAGS; 29051c35492SMatthew Dillon hmp->hflags |= info.hflags & HMNT_USERFLAGS; 2917f7c1f84SMatthew Dillon if (info.asof) { 29251c35492SMatthew Dillon kprintf("ASOF\n"); 2937f7c1f84SMatthew Dillon mp->mnt_flag |= MNT_RDONLY; 2947f7c1f84SMatthew Dillon hmp->asof = info.asof; 2957f7c1f84SMatthew Dillon } else { 2967f7c1f84SMatthew Dillon hmp->asof = HAMMER_MAX_TID; 2977f7c1f84SMatthew Dillon } 298195c19a1SMatthew Dillon 299195c19a1SMatthew Dillon /* 30051c35492SMatthew Dillon * Re-open read-write if originally read-only, or vise-versa. 301195c19a1SMatthew Dillon */ 302195c19a1SMatthew Dillon if (mp->mnt_flag & MNT_UPDATE) { 30351c35492SMatthew Dillon error = 0; 30451c35492SMatthew Dillon if (hmp->ronly && (mp->mnt_kern_flag & MNTK_WANTRDWR)) { 30551c35492SMatthew Dillon kprintf("HAMMER read-only -> read-write\n"); 306195c19a1SMatthew Dillon hmp->ronly = 0; 30751c35492SMatthew Dillon RB_SCAN(hammer_vol_rb_tree, &hmp->rb_vols_root, NULL, 30851c35492SMatthew Dillon hammer_adjust_volume_mode, NULL); 30951c35492SMatthew Dillon rootvol = hammer_get_root_volume(hmp, &error); 31051c35492SMatthew Dillon if (rootvol) { 31151c35492SMatthew Dillon hammer_recover_flush_buffers(hmp, rootvol); 3129f5097dcSMatthew Dillon bcopy(rootvol->ondisk->vol0_blockmap, 3139f5097dcSMatthew Dillon hmp->blockmap, 3149f5097dcSMatthew Dillon sizeof(hmp->blockmap)); 31551c35492SMatthew Dillon hammer_rel_volume(rootvol, 0); 316195c19a1SMatthew Dillon } 31751c35492SMatthew Dillon RB_SCAN(hammer_ino_rb_tree, &hmp->rb_inos_root, NULL, 31851c35492SMatthew Dillon hammer_reload_inode, NULL); 31951c35492SMatthew Dillon /* kernel clears MNT_RDONLY */ 32051c35492SMatthew Dillon } else if (hmp->ronly == 0 && (mp->mnt_flag & MNT_RDONLY)) { 32151c35492SMatthew Dillon kprintf("HAMMER read-write -> read-only\n"); 32251c35492SMatthew Dillon hmp->ronly = 1; /* messy */ 32351c35492SMatthew Dillon RB_SCAN(hammer_ino_rb_tree, &hmp->rb_inos_root, NULL, 32451c35492SMatthew Dillon hammer_reload_inode, NULL); 32551c35492SMatthew Dillon hmp->ronly = 0; 32651c35492SMatthew Dillon hammer_flusher_sync(hmp); 32751c35492SMatthew Dillon hammer_flusher_sync(hmp); 32851c35492SMatthew Dillon hammer_flusher_sync(hmp); 32951c35492SMatthew Dillon hmp->ronly = 1; 33051c35492SMatthew Dillon RB_SCAN(hammer_vol_rb_tree, &hmp->rb_vols_root, NULL, 33151c35492SMatthew Dillon hammer_adjust_volume_mode, NULL); 33251c35492SMatthew Dillon } 33351c35492SMatthew Dillon return(error); 334195c19a1SMatthew Dillon } 335195c19a1SMatthew Dillon 336427e5fc6SMatthew Dillon RB_INIT(&hmp->rb_vols_root); 337427e5fc6SMatthew Dillon RB_INIT(&hmp->rb_inos_root); 33840043e7fSMatthew Dillon RB_INIT(&hmp->rb_nods_root); 339e8599db1SMatthew Dillon RB_INIT(&hmp->rb_undo_root); 3400832c9bbSMatthew Dillon RB_INIT(&hmp->rb_resv_root); 3410832c9bbSMatthew Dillon RB_INIT(&hmp->rb_bufs_root); 3420832c9bbSMatthew Dillon 343195c19a1SMatthew Dillon hmp->ronly = ((mp->mnt_flag & MNT_RDONLY) != 0); 344427e5fc6SMatthew Dillon 34510a5d1baSMatthew Dillon TAILQ_INIT(&hmp->volu_list); 34610a5d1baSMatthew Dillon TAILQ_INIT(&hmp->undo_list); 34710a5d1baSMatthew Dillon TAILQ_INIT(&hmp->data_list); 34810a5d1baSMatthew Dillon TAILQ_INIT(&hmp->meta_list); 34910a5d1baSMatthew Dillon TAILQ_INIT(&hmp->lose_list); 35010a5d1baSMatthew Dillon 351427e5fc6SMatthew Dillon /* 352427e5fc6SMatthew Dillon * Load volumes 353427e5fc6SMatthew Dillon */ 354427e5fc6SMatthew Dillon path = objcache_get(namei_oc, M_WAITOK); 355d26d0ae9SMatthew Dillon hmp->nvolumes = info.nvolumes; 356427e5fc6SMatthew Dillon for (i = 0; i < info.nvolumes; ++i) { 357427e5fc6SMatthew Dillon error = copyin(&info.volumes[i], &upath, sizeof(char *)); 358427e5fc6SMatthew Dillon if (error == 0) 359427e5fc6SMatthew Dillon error = copyinstr(upath, path, MAXPATHLEN, NULL); 360427e5fc6SMatthew Dillon if (error == 0) 3618cd0a023SMatthew Dillon error = hammer_install_volume(hmp, path); 362427e5fc6SMatthew Dillon if (error) 363427e5fc6SMatthew Dillon break; 364427e5fc6SMatthew Dillon } 365427e5fc6SMatthew Dillon objcache_put(namei_oc, path); 366427e5fc6SMatthew Dillon 367427e5fc6SMatthew Dillon /* 368427e5fc6SMatthew Dillon * Make sure we found a root volume 369427e5fc6SMatthew Dillon */ 370427e5fc6SMatthew Dillon if (error == 0 && hmp->rootvol == NULL) { 371427e5fc6SMatthew Dillon kprintf("hammer_mount: No root volume found!\n"); 372427e5fc6SMatthew Dillon error = EINVAL; 373427e5fc6SMatthew Dillon } 374427e5fc6SMatthew Dillon if (error) { 375427e5fc6SMatthew Dillon hammer_free_hmp(mp); 376427e5fc6SMatthew Dillon return (error); 377427e5fc6SMatthew Dillon } 378427e5fc6SMatthew Dillon 379427e5fc6SMatthew Dillon /* 38027ea2398SMatthew Dillon * No errors, setup enough of the mount point so we can lookup the 38127ea2398SMatthew Dillon * root vnode. 382427e5fc6SMatthew Dillon */ 383427e5fc6SMatthew Dillon mp->mnt_iosize_max = MAXPHYS; 384427e5fc6SMatthew Dillon mp->mnt_kern_flag |= MNTK_FSMID; 385c0ade690SMatthew Dillon 386c0ade690SMatthew Dillon /* 387c0ade690SMatthew Dillon * note: f_iosize is used by vnode_pager_haspage() when constructing 388c0ade690SMatthew Dillon * its VOP_BMAP call. 389c0ade690SMatthew Dillon */ 390c0ade690SMatthew Dillon mp->mnt_stat.f_iosize = HAMMER_BUFSIZE; 391fbc6e32aSMatthew Dillon mp->mnt_stat.f_bsize = HAMMER_BUFSIZE; 3926f97fce3SMatthew Dillon 3936f97fce3SMatthew Dillon mp->mnt_vstat.f_frsize = HAMMER_BUFSIZE; 3946f97fce3SMatthew Dillon mp->mnt_vstat.f_bsize = HAMMER_BUFSIZE; 3956f97fce3SMatthew Dillon 396427e5fc6SMatthew Dillon mp->mnt_maxsymlinklen = 255; 397427e5fc6SMatthew Dillon mp->mnt_flag |= MNT_LOCAL; 398427e5fc6SMatthew Dillon 399427e5fc6SMatthew Dillon vfs_add_vnodeops(mp, &hammer_vnode_vops, &mp->mnt_vn_norm_ops); 4007a04d74fSMatthew Dillon vfs_add_vnodeops(mp, &hammer_spec_vops, &mp->mnt_vn_spec_ops); 4017a04d74fSMatthew Dillon vfs_add_vnodeops(mp, &hammer_fifo_vops, &mp->mnt_vn_fifo_ops); 40227ea2398SMatthew Dillon 40327ea2398SMatthew Dillon /* 404a89aec1bSMatthew Dillon * The root volume's ondisk pointer is only valid if we hold a 405a89aec1bSMatthew Dillon * reference to it. 406a89aec1bSMatthew Dillon */ 407a89aec1bSMatthew Dillon rootvol = hammer_get_root_volume(hmp, &error); 408a89aec1bSMatthew Dillon if (error) 409f90dde4cSMatthew Dillon goto failed; 410f90dde4cSMatthew Dillon 411f90dde4cSMatthew Dillon /* 4129f5097dcSMatthew Dillon * Perform any necessary UNDO operations. The recovery code does 4130729c8c8SMatthew Dillon * call hammer_undo_lookup() so we have to pre-cache the blockmap, 4140729c8c8SMatthew Dillon * and then re-copy it again after recovery is complete. 415c9b9e29dSMatthew Dillon * 41651c35492SMatthew Dillon * If this is a read-only mount the UNDO information is retained 41751c35492SMatthew Dillon * in memory in the form of dirty buffer cache buffers, and not 41851c35492SMatthew Dillon * written back to the media. 419f90dde4cSMatthew Dillon */ 4200729c8c8SMatthew Dillon bcopy(rootvol->ondisk->vol0_blockmap, hmp->blockmap, 4210729c8c8SMatthew Dillon sizeof(hmp->blockmap)); 422c9b9e29dSMatthew Dillon 423f90dde4cSMatthew Dillon error = hammer_recover(hmp, rootvol); 424f90dde4cSMatthew Dillon if (error) { 425f90dde4cSMatthew Dillon kprintf("Failed to recover HAMMER filesystem on mount\n"); 426a89aec1bSMatthew Dillon goto done; 427f90dde4cSMatthew Dillon } 428f90dde4cSMatthew Dillon 429f90dde4cSMatthew Dillon /* 430f90dde4cSMatthew Dillon * Finish setup now that we have a good root volume 431f90dde4cSMatthew Dillon */ 432a89aec1bSMatthew Dillon ksnprintf(mp->mnt_stat.f_mntfromname, 433a89aec1bSMatthew Dillon sizeof(mp->mnt_stat.f_mntfromname), "%s", 434a89aec1bSMatthew Dillon rootvol->ondisk->vol_name); 435513ca7d7SMatthew Dillon mp->mnt_stat.f_fsid.val[0] = 436513ca7d7SMatthew Dillon crc32((char *)&rootvol->ondisk->vol_fsid + 0, 8); 437513ca7d7SMatthew Dillon mp->mnt_stat.f_fsid.val[1] = 438513ca7d7SMatthew Dillon crc32((char *)&rootvol->ondisk->vol_fsid + 8, 8); 439b84de5afSMatthew Dillon 4406f97fce3SMatthew Dillon mp->mnt_vstat.f_fsid_uuid = rootvol->ondisk->vol_fsid; 4416f97fce3SMatthew Dillon mp->mnt_vstat.f_fsid = crc32(&mp->mnt_vstat.f_fsid_uuid, 4426f97fce3SMatthew Dillon sizeof(mp->mnt_vstat.f_fsid_uuid)); 4436f97fce3SMatthew Dillon 4440729c8c8SMatthew Dillon /* 4450729c8c8SMatthew Dillon * Certain often-modified fields in the root volume are cached in 4460729c8c8SMatthew Dillon * the hammer_mount structure so we do not have to generate lots 4470729c8c8SMatthew Dillon * of little UNDO structures for them. 448c9b9e29dSMatthew Dillon * 4499f5097dcSMatthew Dillon * Recopy after recovery. This also has the side effect of 4509f5097dcSMatthew Dillon * setting our cached undo FIFO's first_offset, which serves to 4519f5097dcSMatthew Dillon * placemark the FIFO start for the NEXT flush cycle while the 4529f5097dcSMatthew Dillon * on-disk first_offset represents the LAST flush cycle. 4530729c8c8SMatthew Dillon */ 454b84de5afSMatthew Dillon hmp->next_tid = rootvol->ondisk->vol0_next_tid; 4550729c8c8SMatthew Dillon bcopy(rootvol->ondisk->vol0_blockmap, hmp->blockmap, 4560729c8c8SMatthew Dillon sizeof(hmp->blockmap)); 457e63644f0SMatthew Dillon hmp->copy_stat_freebigblocks = rootvol->ondisk->vol0_stat_freebigblocks; 4580729c8c8SMatthew Dillon 4590729c8c8SMatthew Dillon /* 4600729c8c8SMatthew Dillon * Use the zone limit set by newfs_hammer, or the zone limit set by 4610729c8c8SMatthew Dillon * sysctl (for debugging), whichever is smaller. 4620729c8c8SMatthew Dillon */ 4630729c8c8SMatthew Dillon if (rootvol->ondisk->vol0_zone_limit) { 4640729c8c8SMatthew Dillon hammer_off_t vol0_zone_limit; 4650729c8c8SMatthew Dillon 4660729c8c8SMatthew Dillon vol0_zone_limit = rootvol->ondisk->vol0_zone_limit; 4670729c8c8SMatthew Dillon for (i = 0; i < HAMMER_MAX_ZONES; ++i) { 4680729c8c8SMatthew Dillon if (hmp->zone_limits[i] > vol0_zone_limit) 4690729c8c8SMatthew Dillon hmp->zone_limits[i] = vol0_zone_limit; 4700729c8c8SMatthew Dillon } 4710729c8c8SMatthew Dillon } 472b84de5afSMatthew Dillon 473059819e3SMatthew Dillon hammer_flusher_create(hmp); 474059819e3SMatthew Dillon 475a89aec1bSMatthew Dillon /* 47627ea2398SMatthew Dillon * Locate the root directory using the root cluster's B-Tree as a 47727ea2398SMatthew Dillon * starting point. The root directory uses an obj_id of 1. 47827ea2398SMatthew Dillon * 47927ea2398SMatthew Dillon * FUTURE: Leave the root directory cached referenced but unlocked 48027ea2398SMatthew Dillon * in hmp->rootvp (need to flush it on unmount). 48127ea2398SMatthew Dillon */ 48227ea2398SMatthew Dillon error = hammer_vfs_vget(mp, 1, &rootvp); 483a89aec1bSMatthew Dillon if (error) 484a89aec1bSMatthew Dillon goto done; 48527ea2398SMatthew Dillon vput(rootvp); 48627ea2398SMatthew Dillon /*vn_unlock(hmp->rootvp);*/ 48727ea2398SMatthew Dillon 488a89aec1bSMatthew Dillon done: 489f90dde4cSMatthew Dillon hammer_rel_volume(rootvol, 0); 490f90dde4cSMatthew Dillon failed: 49127ea2398SMatthew Dillon /* 49227ea2398SMatthew Dillon * Cleanup and return. 49327ea2398SMatthew Dillon */ 49427ea2398SMatthew Dillon if (error) 49527ea2398SMatthew Dillon hammer_free_hmp(mp); 496427e5fc6SMatthew Dillon return (error); 497427e5fc6SMatthew Dillon } 498427e5fc6SMatthew Dillon 499427e5fc6SMatthew Dillon static int 500427e5fc6SMatthew Dillon hammer_vfs_unmount(struct mount *mp, int mntflags) 501427e5fc6SMatthew Dillon { 502427e5fc6SMatthew Dillon #if 0 503427e5fc6SMatthew Dillon struct hammer_mount *hmp = (void *)mp->mnt_data; 504427e5fc6SMatthew Dillon #endif 505427e5fc6SMatthew Dillon int flags; 50666325755SMatthew Dillon int error; 50727ea2398SMatthew Dillon 50827ea2398SMatthew Dillon /* 509427e5fc6SMatthew Dillon * Clean out the vnodes 510427e5fc6SMatthew Dillon */ 51166325755SMatthew Dillon flags = 0; 51266325755SMatthew Dillon if (mntflags & MNT_FORCE) 51366325755SMatthew Dillon flags |= FORCECLOSE; 51466325755SMatthew Dillon if ((error = vflush(mp, 0, flags)) != 0) 51566325755SMatthew Dillon return (error); 516427e5fc6SMatthew Dillon 517427e5fc6SMatthew Dillon /* 518427e5fc6SMatthew Dillon * Clean up the internal mount structure and related entities. This 519427e5fc6SMatthew Dillon * may issue I/O. 520427e5fc6SMatthew Dillon */ 521427e5fc6SMatthew Dillon hammer_free_hmp(mp); 522427e5fc6SMatthew Dillon return(0); 523427e5fc6SMatthew Dillon } 524427e5fc6SMatthew Dillon 525427e5fc6SMatthew Dillon /* 526427e5fc6SMatthew Dillon * Clean up the internal mount structure and disassociate it from the mount. 527427e5fc6SMatthew Dillon * This may issue I/O. 528427e5fc6SMatthew Dillon */ 529427e5fc6SMatthew Dillon static void 530427e5fc6SMatthew Dillon hammer_free_hmp(struct mount *mp) 531427e5fc6SMatthew Dillon { 532427e5fc6SMatthew Dillon struct hammer_mount *hmp = (void *)mp->mnt_data; 533bf686dbeSMatthew Dillon int i; 534427e5fc6SMatthew Dillon 53527ea2398SMatthew Dillon #if 0 536427e5fc6SMatthew Dillon /* 537427e5fc6SMatthew Dillon * Clean up the root vnode 538427e5fc6SMatthew Dillon */ 539427e5fc6SMatthew Dillon if (hmp->rootvp) { 540427e5fc6SMatthew Dillon vrele(hmp->rootvp); 541427e5fc6SMatthew Dillon hmp->rootvp = NULL; 542427e5fc6SMatthew Dillon } 54327ea2398SMatthew Dillon #endif 5443897d7e9SMatthew Dillon kprintf("X1"); 545059819e3SMatthew Dillon hammer_flusher_sync(hmp); 5463897d7e9SMatthew Dillon kprintf("X2"); 547b84de5afSMatthew Dillon hammer_flusher_sync(hmp); 5483897d7e9SMatthew Dillon kprintf("X3"); 549059819e3SMatthew Dillon hammer_flusher_destroy(hmp); 5503897d7e9SMatthew Dillon kprintf("X4"); 551427e5fc6SMatthew Dillon 552b84de5afSMatthew Dillon KKASSERT(RB_EMPTY(&hmp->rb_inos_root)); 553b84de5afSMatthew Dillon 554b84de5afSMatthew Dillon #if 0 555427e5fc6SMatthew Dillon /* 556427e5fc6SMatthew Dillon * Unload & flush inodes 557b84de5afSMatthew Dillon * 558b84de5afSMatthew Dillon * XXX illegal to call this from here, it can only be done from 559b84de5afSMatthew Dillon * the flusher. 560427e5fc6SMatthew Dillon */ 561427e5fc6SMatthew Dillon RB_SCAN(hammer_ino_rb_tree, &hmp->rb_inos_root, NULL, 562d113fda1SMatthew Dillon hammer_unload_inode, (void *)MNT_WAIT); 563427e5fc6SMatthew Dillon 564427e5fc6SMatthew Dillon /* 565427e5fc6SMatthew Dillon * Unload & flush volumes 566427e5fc6SMatthew Dillon */ 567b84de5afSMatthew Dillon #endif 568b84de5afSMatthew Dillon /* 5690832c9bbSMatthew Dillon * Unload buffers and then volumes 570b84de5afSMatthew Dillon */ 5710832c9bbSMatthew Dillon RB_SCAN(hammer_buf_rb_tree, &hmp->rb_bufs_root, NULL, 5720832c9bbSMatthew Dillon hammer_unload_buffer, NULL); 5733897d7e9SMatthew Dillon kprintf("X5"); 574427e5fc6SMatthew Dillon RB_SCAN(hammer_vol_rb_tree, &hmp->rb_vols_root, NULL, 575427e5fc6SMatthew Dillon hammer_unload_volume, NULL); 5763897d7e9SMatthew Dillon kprintf("X6"); 577427e5fc6SMatthew Dillon 578427e5fc6SMatthew Dillon mp->mnt_data = NULL; 57966325755SMatthew Dillon mp->mnt_flag &= ~MNT_LOCAL; 580427e5fc6SMatthew Dillon hmp->mp = NULL; 5813897d7e9SMatthew Dillon kprintf("X7"); 5820729c8c8SMatthew Dillon hammer_destroy_objid_cache(hmp); 5833897d7e9SMatthew Dillon kprintf("X8"); 58466325755SMatthew Dillon kfree(hmp->zbuf, M_HAMMER); 5853897d7e9SMatthew Dillon kprintf("X9"); 5863897d7e9SMatthew Dillon kprintf("X10"); 587bf686dbeSMatthew Dillon 588bf686dbeSMatthew Dillon for (i = 0; i < HAMMER_MAX_ZONES; ++i) 589bf686dbeSMatthew Dillon hammer_free_holes(hmp, &hmp->holes[i]); 5903897d7e9SMatthew Dillon kprintf("X11"); 591bf686dbeSMatthew Dillon 592427e5fc6SMatthew Dillon kfree(hmp, M_HAMMER); 5933897d7e9SMatthew Dillon kprintf("X12"); 594427e5fc6SMatthew Dillon } 595427e5fc6SMatthew Dillon 596427e5fc6SMatthew Dillon /* 597513ca7d7SMatthew Dillon * Obtain a vnode for the specified inode number. An exclusively locked 598513ca7d7SMatthew Dillon * vnode is returned. 599513ca7d7SMatthew Dillon */ 600513ca7d7SMatthew Dillon int 601513ca7d7SMatthew Dillon hammer_vfs_vget(struct mount *mp, ino_t ino, struct vnode **vpp) 602513ca7d7SMatthew Dillon { 60336f82b23SMatthew Dillon struct hammer_transaction trans; 604513ca7d7SMatthew Dillon struct hammer_mount *hmp = (void *)mp->mnt_data; 605513ca7d7SMatthew Dillon struct hammer_inode *ip; 606513ca7d7SMatthew Dillon int error; 607513ca7d7SMatthew Dillon 60836f82b23SMatthew Dillon hammer_simple_transaction(&trans, hmp); 60936f82b23SMatthew Dillon 610513ca7d7SMatthew Dillon /* 61136f82b23SMatthew Dillon * Lookup the requested HAMMER inode. The structure must be 61236f82b23SMatthew Dillon * left unlocked while we manipulate the related vnode to avoid 61336f82b23SMatthew Dillon * a deadlock. 614513ca7d7SMatthew Dillon */ 61536f82b23SMatthew Dillon ip = hammer_get_inode(&trans, NULL, ino, hmp->asof, 0, &error); 616513ca7d7SMatthew Dillon if (ip == NULL) { 617513ca7d7SMatthew Dillon *vpp = NULL; 618513ca7d7SMatthew Dillon return(error); 619513ca7d7SMatthew Dillon } 620e8599db1SMatthew Dillon error = hammer_get_vnode(ip, vpp); 621513ca7d7SMatthew Dillon hammer_rel_inode(ip, 0); 622b84de5afSMatthew Dillon hammer_done_transaction(&trans); 623513ca7d7SMatthew Dillon return (error); 624513ca7d7SMatthew Dillon } 625513ca7d7SMatthew Dillon 626513ca7d7SMatthew Dillon /* 627427e5fc6SMatthew Dillon * Return the root vnode for the filesystem. 628427e5fc6SMatthew Dillon * 629427e5fc6SMatthew Dillon * HAMMER stores the root vnode in the hammer_mount structure so 630427e5fc6SMatthew Dillon * getting it is easy. 631427e5fc6SMatthew Dillon */ 632427e5fc6SMatthew Dillon static int 633427e5fc6SMatthew Dillon hammer_vfs_root(struct mount *mp, struct vnode **vpp) 634427e5fc6SMatthew Dillon { 63547197d71SMatthew Dillon #if 0 636427e5fc6SMatthew Dillon struct hammer_mount *hmp = (void *)mp->mnt_data; 63747197d71SMatthew Dillon #endif 63827ea2398SMatthew Dillon int error; 639427e5fc6SMatthew Dillon 64027ea2398SMatthew Dillon error = hammer_vfs_vget(mp, 1, vpp); 64127ea2398SMatthew Dillon return (error); 642427e5fc6SMatthew Dillon } 643427e5fc6SMatthew Dillon 644427e5fc6SMatthew Dillon static int 645427e5fc6SMatthew Dillon hammer_vfs_statfs(struct mount *mp, struct statfs *sbp, struct ucred *cred) 646427e5fc6SMatthew Dillon { 647fbc6e32aSMatthew Dillon struct hammer_mount *hmp = (void *)mp->mnt_data; 648fbc6e32aSMatthew Dillon hammer_volume_t volume; 649fbc6e32aSMatthew Dillon hammer_volume_ondisk_t ondisk; 650fbc6e32aSMatthew Dillon int error; 65147197d71SMatthew Dillon int64_t bfree; 652fbc6e32aSMatthew Dillon 653fbc6e32aSMatthew Dillon volume = hammer_get_root_volume(hmp, &error); 654fbc6e32aSMatthew Dillon if (error) 655fbc6e32aSMatthew Dillon return(error); 656fbc6e32aSMatthew Dillon ondisk = volume->ondisk; 657fbc6e32aSMatthew Dillon 65847197d71SMatthew Dillon /* 65947197d71SMatthew Dillon * Basic stats 66047197d71SMatthew Dillon */ 661fbc6e32aSMatthew Dillon mp->mnt_stat.f_files = ondisk->vol0_stat_inodes; 662c3be93f2SMatthew Dillon bfree = ondisk->vol0_stat_freebigblocks * HAMMER_LARGEBLOCK_SIZE; 66340043e7fSMatthew Dillon hammer_rel_volume(volume, 0); 66447197d71SMatthew Dillon 66547197d71SMatthew Dillon mp->mnt_stat.f_bfree = bfree / HAMMER_BUFSIZE; 66647197d71SMatthew Dillon mp->mnt_stat.f_bavail = mp->mnt_stat.f_bfree; 667fbc6e32aSMatthew Dillon if (mp->mnt_stat.f_files < 0) 668fbc6e32aSMatthew Dillon mp->mnt_stat.f_files = 0; 669fbc6e32aSMatthew Dillon 67027ea2398SMatthew Dillon *sbp = mp->mnt_stat; 67127ea2398SMatthew Dillon return(0); 672427e5fc6SMatthew Dillon } 673427e5fc6SMatthew Dillon 6746f97fce3SMatthew Dillon static int 6756f97fce3SMatthew Dillon hammer_vfs_statvfs(struct mount *mp, struct statvfs *sbp, struct ucred *cred) 6766f97fce3SMatthew Dillon { 6776f97fce3SMatthew Dillon struct hammer_mount *hmp = (void *)mp->mnt_data; 6786f97fce3SMatthew Dillon hammer_volume_t volume; 6796f97fce3SMatthew Dillon hammer_volume_ondisk_t ondisk; 6806f97fce3SMatthew Dillon int error; 6816f97fce3SMatthew Dillon int64_t bfree; 6826f97fce3SMatthew Dillon 6836f97fce3SMatthew Dillon volume = hammer_get_root_volume(hmp, &error); 6846f97fce3SMatthew Dillon if (error) 6856f97fce3SMatthew Dillon return(error); 6866f97fce3SMatthew Dillon ondisk = volume->ondisk; 6876f97fce3SMatthew Dillon 6886f97fce3SMatthew Dillon /* 6896f97fce3SMatthew Dillon * Basic stats 6906f97fce3SMatthew Dillon */ 6916f97fce3SMatthew Dillon mp->mnt_vstat.f_files = ondisk->vol0_stat_inodes; 6926f97fce3SMatthew Dillon bfree = ondisk->vol0_stat_freebigblocks * HAMMER_LARGEBLOCK_SIZE; 6936f97fce3SMatthew Dillon hammer_rel_volume(volume, 0); 6946f97fce3SMatthew Dillon 6956f97fce3SMatthew Dillon mp->mnt_vstat.f_bfree = bfree / HAMMER_BUFSIZE; 6966f97fce3SMatthew Dillon mp->mnt_vstat.f_bavail = mp->mnt_stat.f_bfree; 6976f97fce3SMatthew Dillon if (mp->mnt_vstat.f_files < 0) 6986f97fce3SMatthew Dillon mp->mnt_vstat.f_files = 0; 6996f97fce3SMatthew Dillon *sbp = mp->mnt_vstat; 7006f97fce3SMatthew Dillon return(0); 7016f97fce3SMatthew Dillon } 7026f97fce3SMatthew Dillon 7030729c8c8SMatthew Dillon /* 7040729c8c8SMatthew Dillon * Sync the filesystem. Currently we have to run it twice, the second 7050729c8c8SMatthew Dillon * one will advance the undo start index to the end index, so if a crash 7060729c8c8SMatthew Dillon * occurs no undos will be run on mount. 70777062c8aSMatthew Dillon * 70877062c8aSMatthew Dillon * We do not sync the filesystem if we are called from a panic. If we did 70977062c8aSMatthew Dillon * we might end up blowing up a sync that was already in progress. 7100729c8c8SMatthew Dillon */ 711427e5fc6SMatthew Dillon static int 712427e5fc6SMatthew Dillon hammer_vfs_sync(struct mount *mp, int waitfor) 713427e5fc6SMatthew Dillon { 714fbc6e32aSMatthew Dillon struct hammer_mount *hmp = (void *)mp->mnt_data; 7150729c8c8SMatthew Dillon int error; 7160729c8c8SMatthew Dillon 71777062c8aSMatthew Dillon if (panicstr == NULL) { 7180729c8c8SMatthew Dillon error = hammer_sync_hmp(hmp, waitfor); 7190729c8c8SMatthew Dillon if (error == 0) 7200729c8c8SMatthew Dillon error = hammer_sync_hmp(hmp, waitfor); 72177062c8aSMatthew Dillon } else { 72277062c8aSMatthew Dillon error = EIO; 72377062c8aSMatthew Dillon } 7240729c8c8SMatthew Dillon return (error); 725427e5fc6SMatthew Dillon } 726427e5fc6SMatthew Dillon 727513ca7d7SMatthew Dillon /* 728513ca7d7SMatthew Dillon * Convert a vnode to a file handle. 729513ca7d7SMatthew Dillon */ 730513ca7d7SMatthew Dillon static int 731513ca7d7SMatthew Dillon hammer_vfs_vptofh(struct vnode *vp, struct fid *fhp) 732513ca7d7SMatthew Dillon { 733513ca7d7SMatthew Dillon hammer_inode_t ip; 734513ca7d7SMatthew Dillon 735513ca7d7SMatthew Dillon KKASSERT(MAXFIDSZ >= 16); 736513ca7d7SMatthew Dillon ip = VTOI(vp); 737513ca7d7SMatthew Dillon fhp->fid_len = offsetof(struct fid, fid_data[16]); 738513ca7d7SMatthew Dillon fhp->fid_reserved = 0; 739513ca7d7SMatthew Dillon bcopy(&ip->obj_id, fhp->fid_data + 0, sizeof(ip->obj_id)); 740513ca7d7SMatthew Dillon bcopy(&ip->obj_asof, fhp->fid_data + 8, sizeof(ip->obj_asof)); 741513ca7d7SMatthew Dillon return(0); 742513ca7d7SMatthew Dillon } 743513ca7d7SMatthew Dillon 744513ca7d7SMatthew Dillon 745513ca7d7SMatthew Dillon /* 746513ca7d7SMatthew Dillon * Convert a file handle back to a vnode. 747513ca7d7SMatthew Dillon */ 748513ca7d7SMatthew Dillon static int 749513ca7d7SMatthew Dillon hammer_vfs_fhtovp(struct mount *mp, struct fid *fhp, struct vnode **vpp) 750513ca7d7SMatthew Dillon { 75136f82b23SMatthew Dillon struct hammer_transaction trans; 752513ca7d7SMatthew Dillon struct hammer_inode *ip; 753513ca7d7SMatthew Dillon struct hammer_inode_info info; 754513ca7d7SMatthew Dillon int error; 755513ca7d7SMatthew Dillon 756513ca7d7SMatthew Dillon bcopy(fhp->fid_data + 0, &info.obj_id, sizeof(info.obj_id)); 757513ca7d7SMatthew Dillon bcopy(fhp->fid_data + 8, &info.obj_asof, sizeof(info.obj_asof)); 758513ca7d7SMatthew Dillon 75936f82b23SMatthew Dillon hammer_simple_transaction(&trans, (void *)mp->mnt_data); 76036f82b23SMatthew Dillon 761513ca7d7SMatthew Dillon /* 762513ca7d7SMatthew Dillon * Get/allocate the hammer_inode structure. The structure must be 763513ca7d7SMatthew Dillon * unlocked while we manipulate the related vnode to avoid a 764513ca7d7SMatthew Dillon * deadlock. 765513ca7d7SMatthew Dillon */ 76636f82b23SMatthew Dillon ip = hammer_get_inode(&trans, NULL, info.obj_id, info.obj_asof, 76736f82b23SMatthew Dillon 0, &error); 768513ca7d7SMatthew Dillon if (ip == NULL) { 769513ca7d7SMatthew Dillon *vpp = NULL; 770513ca7d7SMatthew Dillon return(error); 771513ca7d7SMatthew Dillon } 772e8599db1SMatthew Dillon error = hammer_get_vnode(ip, vpp); 773513ca7d7SMatthew Dillon hammer_rel_inode(ip, 0); 774b84de5afSMatthew Dillon hammer_done_transaction(&trans); 775513ca7d7SMatthew Dillon return (error); 776513ca7d7SMatthew Dillon } 777513ca7d7SMatthew Dillon 778513ca7d7SMatthew Dillon static int 779513ca7d7SMatthew Dillon hammer_vfs_checkexp(struct mount *mp, struct sockaddr *nam, 780513ca7d7SMatthew Dillon int *exflagsp, struct ucred **credanonp) 781513ca7d7SMatthew Dillon { 782513ca7d7SMatthew Dillon hammer_mount_t hmp = (void *)mp->mnt_data; 783513ca7d7SMatthew Dillon struct netcred *np; 784513ca7d7SMatthew Dillon int error; 785513ca7d7SMatthew Dillon 786513ca7d7SMatthew Dillon np = vfs_export_lookup(mp, &hmp->export, nam); 787513ca7d7SMatthew Dillon if (np) { 788513ca7d7SMatthew Dillon *exflagsp = np->netc_exflags; 789513ca7d7SMatthew Dillon *credanonp = &np->netc_anon; 790513ca7d7SMatthew Dillon error = 0; 791513ca7d7SMatthew Dillon } else { 792513ca7d7SMatthew Dillon error = EACCES; 793513ca7d7SMatthew Dillon } 794513ca7d7SMatthew Dillon return (error); 795513ca7d7SMatthew Dillon 796513ca7d7SMatthew Dillon } 797513ca7d7SMatthew Dillon 798513ca7d7SMatthew Dillon int 799513ca7d7SMatthew Dillon hammer_vfs_export(struct mount *mp, int op, const struct export_args *export) 800513ca7d7SMatthew Dillon { 801513ca7d7SMatthew Dillon hammer_mount_t hmp = (void *)mp->mnt_data; 802513ca7d7SMatthew Dillon int error; 803513ca7d7SMatthew Dillon 804513ca7d7SMatthew Dillon switch(op) { 805513ca7d7SMatthew Dillon case MOUNTCTL_SET_EXPORT: 806513ca7d7SMatthew Dillon error = vfs_export(mp, &hmp->export, export); 807513ca7d7SMatthew Dillon break; 808513ca7d7SMatthew Dillon default: 809513ca7d7SMatthew Dillon error = EOPNOTSUPP; 810513ca7d7SMatthew Dillon break; 811513ca7d7SMatthew Dillon } 812513ca7d7SMatthew Dillon return(error); 813513ca7d7SMatthew Dillon } 814513ca7d7SMatthew Dillon 815