1427e5fc6SMatthew Dillon /* 2427e5fc6SMatthew Dillon * Copyright (c) 2007 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*a89aec1bSMatthew Dillon * $DragonFly: src/sys/vfs/hammer/hammer_vfsops.c,v 1.5 2007/11/20 07:16:28 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> 45427e5fc6SMatthew Dillon #include <sys/buf.h> 46427e5fc6SMatthew Dillon #include <sys/buf2.h> 47427e5fc6SMatthew Dillon #include "hammer.h" 48427e5fc6SMatthew Dillon 49427e5fc6SMatthew Dillon /* 50427e5fc6SMatthew Dillon * VFS ABI 51427e5fc6SMatthew Dillon */ 52427e5fc6SMatthew Dillon static void hammer_free_hmp(struct mount *mp); 53427e5fc6SMatthew Dillon 54427e5fc6SMatthew Dillon static int hammer_vfs_mount(struct mount *mp, char *path, caddr_t data, 55427e5fc6SMatthew Dillon struct ucred *cred); 56427e5fc6SMatthew Dillon static int hammer_vfs_unmount(struct mount *mp, int mntflags); 57427e5fc6SMatthew Dillon static int hammer_vfs_root(struct mount *mp, struct vnode **vpp); 58427e5fc6SMatthew Dillon static int hammer_vfs_statfs(struct mount *mp, struct statfs *sbp, 59427e5fc6SMatthew Dillon struct ucred *cred); 60427e5fc6SMatthew Dillon static int hammer_vfs_sync(struct mount *mp, int waitfor); 61427e5fc6SMatthew Dillon static int hammer_vfs_init(struct vfsconf *conf); 62427e5fc6SMatthew Dillon 63427e5fc6SMatthew Dillon static struct vfsops hammer_vfsops = { 64427e5fc6SMatthew Dillon .vfs_mount = hammer_vfs_mount, 65427e5fc6SMatthew Dillon .vfs_unmount = hammer_vfs_unmount, 66427e5fc6SMatthew Dillon .vfs_root = hammer_vfs_root, 67427e5fc6SMatthew Dillon .vfs_statfs = hammer_vfs_statfs, 68427e5fc6SMatthew Dillon .vfs_sync = hammer_vfs_sync, 69427e5fc6SMatthew Dillon .vfs_vget = hammer_vfs_vget, 70427e5fc6SMatthew Dillon .vfs_init = hammer_vfs_init 71427e5fc6SMatthew Dillon }; 72427e5fc6SMatthew Dillon 73427e5fc6SMatthew Dillon MALLOC_DEFINE(M_HAMMER, "hammer-mount", "hammer mount"); 74427e5fc6SMatthew Dillon 75427e5fc6SMatthew Dillon VFS_SET(hammer_vfsops, hammer, 0); 76427e5fc6SMatthew Dillon MODULE_VERSION(hammer, 1); 77427e5fc6SMatthew Dillon 78427e5fc6SMatthew Dillon static int 79427e5fc6SMatthew Dillon hammer_vfs_init(struct vfsconf *conf) 80427e5fc6SMatthew Dillon { 81427e5fc6SMatthew Dillon hammer_init_alist_config(); 82427e5fc6SMatthew Dillon return(0); 83427e5fc6SMatthew Dillon } 84427e5fc6SMatthew Dillon 85427e5fc6SMatthew Dillon static int 86427e5fc6SMatthew Dillon hammer_vfs_mount(struct mount *mp, char *mntpt, caddr_t data, 87427e5fc6SMatthew Dillon struct ucred *cred) 88427e5fc6SMatthew Dillon { 89427e5fc6SMatthew Dillon struct hammer_mount_info info; 90*a89aec1bSMatthew Dillon hammer_mount_t hmp; 91*a89aec1bSMatthew Dillon hammer_volume_t rootvol; 9227ea2398SMatthew Dillon struct vnode *rootvp; 93427e5fc6SMatthew Dillon const char *upath; /* volume name in userspace */ 94427e5fc6SMatthew Dillon char *path; /* volume name in system space */ 95427e5fc6SMatthew Dillon int error; 96427e5fc6SMatthew Dillon int i; 97427e5fc6SMatthew Dillon 98427e5fc6SMatthew Dillon if ((error = copyin(data, &info, sizeof(info))) != 0) 99427e5fc6SMatthew Dillon return (error); 100427e5fc6SMatthew Dillon if (info.nvolumes <= 0 || info.nvolumes >= 32768) 101427e5fc6SMatthew Dillon return (EINVAL); 102427e5fc6SMatthew Dillon 103427e5fc6SMatthew Dillon /* 104427e5fc6SMatthew Dillon * Interal mount data structure 105427e5fc6SMatthew Dillon */ 106427e5fc6SMatthew Dillon hmp = kmalloc(sizeof(*hmp), M_HAMMER, M_WAITOK | M_ZERO); 107427e5fc6SMatthew Dillon mp->mnt_data = (qaddr_t)hmp; 108427e5fc6SMatthew Dillon hmp->mp = mp; 10966325755SMatthew Dillon hmp->zbuf = kmalloc(HAMMER_BUFSIZE, M_HAMMER, M_WAITOK | M_ZERO); 110*a89aec1bSMatthew Dillon hmp->namekey_iterator = mycpu->gd_time_seconds; 111427e5fc6SMatthew Dillon RB_INIT(&hmp->rb_vols_root); 112427e5fc6SMatthew Dillon RB_INIT(&hmp->rb_inos_root); 113427e5fc6SMatthew Dillon 114427e5fc6SMatthew Dillon /* 115427e5fc6SMatthew Dillon * Load volumes 116427e5fc6SMatthew Dillon */ 117427e5fc6SMatthew Dillon path = objcache_get(namei_oc, M_WAITOK); 118427e5fc6SMatthew Dillon for (i = 0; i < info.nvolumes; ++i) { 119427e5fc6SMatthew Dillon error = copyin(&info.volumes[i], &upath, sizeof(char *)); 120427e5fc6SMatthew Dillon if (error == 0) 121427e5fc6SMatthew Dillon error = copyinstr(upath, path, MAXPATHLEN, NULL); 122427e5fc6SMatthew Dillon if (error == 0) 1238cd0a023SMatthew Dillon error = hammer_install_volume(hmp, path); 124427e5fc6SMatthew Dillon if (error) 125427e5fc6SMatthew Dillon break; 126427e5fc6SMatthew Dillon } 127427e5fc6SMatthew Dillon objcache_put(namei_oc, path); 128427e5fc6SMatthew Dillon 129427e5fc6SMatthew Dillon /* 130427e5fc6SMatthew Dillon * Make sure we found a root volume 131427e5fc6SMatthew Dillon */ 132427e5fc6SMatthew Dillon if (error == 0 && hmp->rootvol == NULL) { 133427e5fc6SMatthew Dillon kprintf("hammer_mount: No root volume found!\n"); 134427e5fc6SMatthew Dillon error = EINVAL; 135427e5fc6SMatthew Dillon } 136427e5fc6SMatthew Dillon if (error == 0 && hmp->rootcl == NULL) { 137427e5fc6SMatthew Dillon kprintf("hammer_mount: No root cluster found!\n"); 138427e5fc6SMatthew Dillon error = EINVAL; 139427e5fc6SMatthew Dillon } 140427e5fc6SMatthew Dillon if (error) { 141427e5fc6SMatthew Dillon hammer_free_hmp(mp); 142427e5fc6SMatthew Dillon return (error); 143427e5fc6SMatthew Dillon } 144427e5fc6SMatthew Dillon 145427e5fc6SMatthew Dillon /* 14627ea2398SMatthew Dillon * No errors, setup enough of the mount point so we can lookup the 14727ea2398SMatthew Dillon * root vnode. 148427e5fc6SMatthew Dillon */ 149427e5fc6SMatthew Dillon mp->mnt_iosize_max = MAXPHYS; 150427e5fc6SMatthew Dillon mp->mnt_kern_flag |= MNTK_FSMID; 151427e5fc6SMatthew Dillon mp->mnt_stat.f_fsid.val[0] = 0; /* XXX */ 152427e5fc6SMatthew Dillon mp->mnt_stat.f_fsid.val[1] = 0; /* XXX */ 153427e5fc6SMatthew Dillon vfs_getnewfsid(mp); /* XXX */ 154427e5fc6SMatthew Dillon mp->mnt_maxsymlinklen = 255; 155427e5fc6SMatthew Dillon mp->mnt_flag |= MNT_LOCAL; 156427e5fc6SMatthew Dillon 157427e5fc6SMatthew Dillon vfs_add_vnodeops(mp, &hammer_vnode_vops, &mp->mnt_vn_norm_ops); 15827ea2398SMatthew Dillon 15927ea2398SMatthew Dillon /* 160*a89aec1bSMatthew Dillon * The root volume's ondisk pointer is only valid if we hold a 161*a89aec1bSMatthew Dillon * reference to it. 162*a89aec1bSMatthew Dillon */ 163*a89aec1bSMatthew Dillon rootvol = hammer_get_root_volume(hmp, &error); 164*a89aec1bSMatthew Dillon if (error) 165*a89aec1bSMatthew Dillon goto done; 166*a89aec1bSMatthew Dillon ksnprintf(mp->mnt_stat.f_mntfromname, 167*a89aec1bSMatthew Dillon sizeof(mp->mnt_stat.f_mntfromname), "%s", 168*a89aec1bSMatthew Dillon rootvol->ondisk->vol_name); 169*a89aec1bSMatthew Dillon hammer_rel_volume(rootvol, 0); 170*a89aec1bSMatthew Dillon 171*a89aec1bSMatthew Dillon /* 17227ea2398SMatthew Dillon * Locate the root directory using the root cluster's B-Tree as a 17327ea2398SMatthew Dillon * starting point. The root directory uses an obj_id of 1. 17427ea2398SMatthew Dillon * 17527ea2398SMatthew Dillon * FUTURE: Leave the root directory cached referenced but unlocked 17627ea2398SMatthew Dillon * in hmp->rootvp (need to flush it on unmount). 17727ea2398SMatthew Dillon */ 17827ea2398SMatthew Dillon error = hammer_vfs_vget(mp, 1, &rootvp); 179*a89aec1bSMatthew Dillon if (error) 180*a89aec1bSMatthew Dillon goto done; 18127ea2398SMatthew Dillon vput(rootvp); 18227ea2398SMatthew Dillon /*vn_unlock(hmp->rootvp);*/ 18327ea2398SMatthew Dillon 184*a89aec1bSMatthew Dillon done: 18527ea2398SMatthew Dillon /* 18627ea2398SMatthew Dillon * Cleanup and return. 18727ea2398SMatthew Dillon */ 18827ea2398SMatthew Dillon if (error) 18927ea2398SMatthew Dillon hammer_free_hmp(mp); 190427e5fc6SMatthew Dillon return (error); 191427e5fc6SMatthew Dillon } 192427e5fc6SMatthew Dillon 193427e5fc6SMatthew Dillon static int 194427e5fc6SMatthew Dillon hammer_vfs_unmount(struct mount *mp, int mntflags) 195427e5fc6SMatthew Dillon { 196427e5fc6SMatthew Dillon #if 0 197427e5fc6SMatthew Dillon struct hammer_mount *hmp = (void *)mp->mnt_data; 198427e5fc6SMatthew Dillon #endif 199427e5fc6SMatthew Dillon int flags; 20066325755SMatthew Dillon int error; 20127ea2398SMatthew Dillon 20227ea2398SMatthew Dillon /* 203427e5fc6SMatthew Dillon * Clean out the vnodes 204427e5fc6SMatthew Dillon */ 20566325755SMatthew Dillon flags = 0; 20666325755SMatthew Dillon if (mntflags & MNT_FORCE) 20766325755SMatthew Dillon flags |= FORCECLOSE; 20866325755SMatthew Dillon if ((error = vflush(mp, 0, flags)) != 0) 20966325755SMatthew Dillon return (error); 210427e5fc6SMatthew Dillon 211427e5fc6SMatthew Dillon /* 212427e5fc6SMatthew Dillon * Clean up the internal mount structure and related entities. This 213427e5fc6SMatthew Dillon * may issue I/O. 214427e5fc6SMatthew Dillon */ 215427e5fc6SMatthew Dillon hammer_free_hmp(mp); 216427e5fc6SMatthew Dillon return(0); 217427e5fc6SMatthew Dillon } 218427e5fc6SMatthew Dillon 219427e5fc6SMatthew Dillon /* 220427e5fc6SMatthew Dillon * Clean up the internal mount structure and disassociate it from the mount. 221427e5fc6SMatthew Dillon * This may issue I/O. 222427e5fc6SMatthew Dillon */ 223427e5fc6SMatthew Dillon static void 224427e5fc6SMatthew Dillon hammer_free_hmp(struct mount *mp) 225427e5fc6SMatthew Dillon { 226427e5fc6SMatthew Dillon struct hammer_mount *hmp = (void *)mp->mnt_data; 227427e5fc6SMatthew Dillon 22827ea2398SMatthew Dillon #if 0 229427e5fc6SMatthew Dillon /* 230427e5fc6SMatthew Dillon * Clean up the root vnode 231427e5fc6SMatthew Dillon */ 232427e5fc6SMatthew Dillon if (hmp->rootvp) { 233427e5fc6SMatthew Dillon vrele(hmp->rootvp); 234427e5fc6SMatthew Dillon hmp->rootvp = NULL; 235427e5fc6SMatthew Dillon } 23627ea2398SMatthew Dillon #endif 237427e5fc6SMatthew Dillon 238427e5fc6SMatthew Dillon /* 239427e5fc6SMatthew Dillon * Unload & flush inodes 240427e5fc6SMatthew Dillon */ 241427e5fc6SMatthew Dillon RB_SCAN(hammer_ino_rb_tree, &hmp->rb_inos_root, NULL, 24266325755SMatthew Dillon hammer_unload_inode, NULL); 243427e5fc6SMatthew Dillon 244427e5fc6SMatthew Dillon /* 245427e5fc6SMatthew Dillon * Unload & flush volumes 246427e5fc6SMatthew Dillon */ 247427e5fc6SMatthew Dillon RB_SCAN(hammer_vol_rb_tree, &hmp->rb_vols_root, NULL, 248427e5fc6SMatthew Dillon hammer_unload_volume, NULL); 249427e5fc6SMatthew Dillon 250427e5fc6SMatthew Dillon mp->mnt_data = NULL; 25166325755SMatthew Dillon mp->mnt_flag &= ~MNT_LOCAL; 252427e5fc6SMatthew Dillon hmp->mp = NULL; 25366325755SMatthew Dillon kfree(hmp->zbuf, M_HAMMER); 254427e5fc6SMatthew Dillon kfree(hmp, M_HAMMER); 255427e5fc6SMatthew Dillon } 256427e5fc6SMatthew Dillon 257427e5fc6SMatthew Dillon /* 258427e5fc6SMatthew Dillon * Return the root vnode for the filesystem. 259427e5fc6SMatthew Dillon * 260427e5fc6SMatthew Dillon * HAMMER stores the root vnode in the hammer_mount structure so 261427e5fc6SMatthew Dillon * getting it is easy. 262427e5fc6SMatthew Dillon */ 263427e5fc6SMatthew Dillon static int 264427e5fc6SMatthew Dillon hammer_vfs_root(struct mount *mp, struct vnode **vpp) 265427e5fc6SMatthew Dillon { 266427e5fc6SMatthew Dillon struct hammer_mount *hmp = (void *)mp->mnt_data; 26727ea2398SMatthew Dillon int error; 268427e5fc6SMatthew Dillon 26927ea2398SMatthew Dillon if (hmp->rootcl == NULL) 27027ea2398SMatthew Dillon error = EIO; 27127ea2398SMatthew Dillon else 27227ea2398SMatthew Dillon error = hammer_vfs_vget(mp, 1, vpp); 27327ea2398SMatthew Dillon return (error); 27427ea2398SMatthew Dillon #if 0 27527ea2398SMatthew Dillon /* FUTURE - cached root vnode */ 276427e5fc6SMatthew Dillon if ((vp = hmp->rootvp) != NULL) { 277427e5fc6SMatthew Dillon vref(vp); 278427e5fc6SMatthew Dillon vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 279427e5fc6SMatthew Dillon *vpp = vp; 280427e5fc6SMatthew Dillon return (0); 281427e5fc6SMatthew Dillon } else { 282427e5fc6SMatthew Dillon *vpp = NULL; 283427e5fc6SMatthew Dillon return (EIO); 284427e5fc6SMatthew Dillon } 28527ea2398SMatthew Dillon #endif 286427e5fc6SMatthew Dillon } 287427e5fc6SMatthew Dillon 288427e5fc6SMatthew Dillon static int 289427e5fc6SMatthew Dillon hammer_vfs_statfs(struct mount *mp, struct statfs *sbp, struct ucred *cred) 290427e5fc6SMatthew Dillon { 29127ea2398SMatthew Dillon *sbp = mp->mnt_stat; 29227ea2398SMatthew Dillon return(0); 293427e5fc6SMatthew Dillon } 294427e5fc6SMatthew Dillon 295427e5fc6SMatthew Dillon static int 296427e5fc6SMatthew Dillon hammer_vfs_sync(struct mount *mp, int waitfor) 297427e5fc6SMatthew Dillon { 298427e5fc6SMatthew Dillon return(0); 299427e5fc6SMatthew Dillon } 300427e5fc6SMatthew Dillon 301