1 /* 2 * Copyright (c) 2007 The DragonFly Project. All rights reserved. 3 * 4 * This code is derived from software contributed to The DragonFly Project 5 * by Matthew Dillon <dillon@backplane.com> 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in 15 * the documentation and/or other materials provided with the 16 * distribution. 17 * 3. Neither the name of The DragonFly Project nor the names of its 18 * contributors may be used to endorse or promote products derived 19 * from this software without specific, prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 24 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 25 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 26 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, 27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 29 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 30 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 31 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 * 34 * $DragonFly: src/sys/vfs/hammer/hammer_vfsops.c,v 1.4 2007/11/19 00:53:40 dillon Exp $ 35 */ 36 37 #include <sys/param.h> 38 #include <sys/systm.h> 39 #include <sys/kernel.h> 40 #include <sys/vnode.h> 41 #include <sys/mount.h> 42 #include <sys/malloc.h> 43 #include <sys/nlookup.h> 44 #include <sys/fcntl.h> 45 #include <sys/buf.h> 46 #include <sys/buf2.h> 47 #include "hammer.h" 48 49 /* 50 * VFS ABI 51 */ 52 static void hammer_free_hmp(struct mount *mp); 53 54 static int hammer_vfs_mount(struct mount *mp, char *path, caddr_t data, 55 struct ucred *cred); 56 static int hammer_vfs_unmount(struct mount *mp, int mntflags); 57 static int hammer_vfs_root(struct mount *mp, struct vnode **vpp); 58 static int hammer_vfs_statfs(struct mount *mp, struct statfs *sbp, 59 struct ucred *cred); 60 static int hammer_vfs_sync(struct mount *mp, int waitfor); 61 static int hammer_vfs_init(struct vfsconf *conf); 62 63 static struct vfsops hammer_vfsops = { 64 .vfs_mount = hammer_vfs_mount, 65 .vfs_unmount = hammer_vfs_unmount, 66 .vfs_root = hammer_vfs_root, 67 .vfs_statfs = hammer_vfs_statfs, 68 .vfs_sync = hammer_vfs_sync, 69 .vfs_vget = hammer_vfs_vget, 70 .vfs_init = hammer_vfs_init 71 }; 72 73 MALLOC_DEFINE(M_HAMMER, "hammer-mount", "hammer mount"); 74 75 VFS_SET(hammer_vfsops, hammer, 0); 76 MODULE_VERSION(hammer, 1); 77 78 static int 79 hammer_vfs_init(struct vfsconf *conf) 80 { 81 hammer_init_alist_config(); 82 return(0); 83 } 84 85 static int 86 hammer_vfs_mount(struct mount *mp, char *mntpt, caddr_t data, 87 struct ucred *cred) 88 { 89 struct hammer_mount_info info; 90 struct hammer_mount *hmp; 91 struct vnode *rootvp; 92 const char *upath; /* volume name in userspace */ 93 char *path; /* volume name in system space */ 94 int error; 95 int i; 96 97 if ((error = copyin(data, &info, sizeof(info))) != 0) 98 return (error); 99 if (info.nvolumes <= 0 || info.nvolumes >= 32768) 100 return (EINVAL); 101 102 /* 103 * Interal mount data structure 104 */ 105 hmp = kmalloc(sizeof(*hmp), M_HAMMER, M_WAITOK | M_ZERO); 106 mp->mnt_data = (qaddr_t)hmp; 107 hmp->mp = mp; 108 hmp->zbuf = kmalloc(HAMMER_BUFSIZE, M_HAMMER, M_WAITOK | M_ZERO); 109 RB_INIT(&hmp->rb_vols_root); 110 RB_INIT(&hmp->rb_inos_root); 111 112 /* 113 * Load volumes 114 */ 115 path = objcache_get(namei_oc, M_WAITOK); 116 for (i = 0; i < info.nvolumes; ++i) { 117 error = copyin(&info.volumes[i], &upath, sizeof(char *)); 118 if (error == 0) 119 error = copyinstr(upath, path, MAXPATHLEN, NULL); 120 if (error == 0) 121 error = hammer_install_volume(hmp, path); 122 if (error) 123 break; 124 } 125 objcache_put(namei_oc, path); 126 127 /* 128 * Make sure we found a root volume 129 */ 130 if (error == 0 && hmp->rootvol == NULL) { 131 kprintf("hammer_mount: No root volume found!\n"); 132 error = EINVAL; 133 } 134 if (error == 0 && hmp->rootcl == NULL) { 135 kprintf("hammer_mount: No root cluster found!\n"); 136 error = EINVAL; 137 } 138 if (error) { 139 hammer_free_hmp(mp); 140 return (error); 141 } 142 143 /* 144 * No errors, setup enough of the mount point so we can lookup the 145 * root vnode. 146 */ 147 mp->mnt_iosize_max = MAXPHYS; 148 mp->mnt_kern_flag |= MNTK_FSMID; 149 mp->mnt_stat.f_fsid.val[0] = 0; /* XXX */ 150 mp->mnt_stat.f_fsid.val[1] = 0; /* XXX */ 151 vfs_getnewfsid(mp); /* XXX */ 152 mp->mnt_maxsymlinklen = 255; 153 mp->mnt_flag |= MNT_LOCAL; 154 155 vfs_add_vnodeops(mp, &hammer_vnode_vops, &mp->mnt_vn_norm_ops); 156 157 /* 158 * Locate the root directory using the root cluster's B-Tree as a 159 * starting point. The root directory uses an obj_id of 1. 160 * 161 * FUTURE: Leave the root directory cached referenced but unlocked 162 * in hmp->rootvp (need to flush it on unmount). 163 */ 164 error = hammer_vfs_vget(mp, 1, &rootvp); 165 if (error == 0) 166 vput(rootvp); 167 /*vn_unlock(hmp->rootvp);*/ 168 169 /* 170 * Cleanup and return. 171 */ 172 if (error) 173 hammer_free_hmp(mp); 174 return (error); 175 } 176 177 static int 178 hammer_vfs_unmount(struct mount *mp, int mntflags) 179 { 180 #if 0 181 struct hammer_mount *hmp = (void *)mp->mnt_data; 182 #endif 183 int flags; 184 int error; 185 186 /* 187 * Clean out the vnodes 188 */ 189 flags = 0; 190 if (mntflags & MNT_FORCE) 191 flags |= FORCECLOSE; 192 if ((error = vflush(mp, 0, flags)) != 0) 193 return (error); 194 195 /* 196 * Clean up the internal mount structure and related entities. This 197 * may issue I/O. 198 */ 199 hammer_free_hmp(mp); 200 return(0); 201 } 202 203 /* 204 * Clean up the internal mount structure and disassociate it from the mount. 205 * This may issue I/O. 206 */ 207 static void 208 hammer_free_hmp(struct mount *mp) 209 { 210 struct hammer_mount *hmp = (void *)mp->mnt_data; 211 212 #if 0 213 /* 214 * Clean up the root vnode 215 */ 216 if (hmp->rootvp) { 217 vrele(hmp->rootvp); 218 hmp->rootvp = NULL; 219 } 220 #endif 221 222 /* 223 * Unload & flush inodes 224 */ 225 RB_SCAN(hammer_ino_rb_tree, &hmp->rb_inos_root, NULL, 226 hammer_unload_inode, NULL); 227 228 /* 229 * Unload & flush volumes 230 */ 231 RB_SCAN(hammer_vol_rb_tree, &hmp->rb_vols_root, NULL, 232 hammer_unload_volume, NULL); 233 234 mp->mnt_data = NULL; 235 mp->mnt_flag &= ~MNT_LOCAL; 236 hmp->mp = NULL; 237 kfree(hmp->zbuf, M_HAMMER); 238 kfree(hmp, M_HAMMER); 239 } 240 241 /* 242 * Return the root vnode for the filesystem. 243 * 244 * HAMMER stores the root vnode in the hammer_mount structure so 245 * getting it is easy. 246 */ 247 static int 248 hammer_vfs_root(struct mount *mp, struct vnode **vpp) 249 { 250 struct hammer_mount *hmp = (void *)mp->mnt_data; 251 int error; 252 253 if (hmp->rootcl == NULL) 254 error = EIO; 255 else 256 error = hammer_vfs_vget(mp, 1, vpp); 257 return (error); 258 #if 0 259 /* FUTURE - cached root vnode */ 260 if ((vp = hmp->rootvp) != NULL) { 261 vref(vp); 262 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 263 *vpp = vp; 264 return (0); 265 } else { 266 *vpp = NULL; 267 return (EIO); 268 } 269 #endif 270 } 271 272 static int 273 hammer_vfs_statfs(struct mount *mp, struct statfs *sbp, struct ucred *cred) 274 { 275 *sbp = mp->mnt_stat; 276 return(0); 277 } 278 279 static int 280 hammer_vfs_sync(struct mount *mp, int waitfor) 281 { 282 return(0); 283 } 284 285