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.2 2007/11/02 00:57:16 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 RB_INIT(&hmp->rb_vols_root); 109 RB_INIT(&hmp->rb_inos_root); 110 111 /* 112 * Load volumes 113 */ 114 path = objcache_get(namei_oc, M_WAITOK); 115 for (i = 0; i < info.nvolumes; ++i) { 116 error = copyin(&info.volumes[i], &upath, sizeof(char *)); 117 if (error == 0) 118 error = copyinstr(upath, path, MAXPATHLEN, NULL); 119 if (error == 0) 120 error = hammer_load_volume(hmp, path); 121 if (error) 122 break; 123 } 124 objcache_put(namei_oc, path); 125 126 /* 127 * Make sure we found a root volume 128 */ 129 if (error == 0 && hmp->rootvol == NULL) { 130 kprintf("hammer_mount: No root volume found!\n"); 131 error = EINVAL; 132 } 133 if (error == 0 && hmp->rootcl == NULL) { 134 kprintf("hammer_mount: No root cluster found!\n"); 135 error = EINVAL; 136 } 137 if (error) { 138 hammer_free_hmp(mp); 139 return (error); 140 } 141 142 /* 143 * No errors, setup enough of the mount point so we can lookup the 144 * root vnode. 145 */ 146 mp->mnt_iosize_max = MAXPHYS; 147 mp->mnt_kern_flag |= MNTK_FSMID; 148 mp->mnt_stat.f_fsid.val[0] = 0; /* XXX */ 149 mp->mnt_stat.f_fsid.val[1] = 0; /* XXX */ 150 vfs_getnewfsid(mp); /* XXX */ 151 mp->mnt_maxsymlinklen = 255; 152 mp->mnt_flag |= MNT_LOCAL; 153 154 vfs_add_vnodeops(mp, &hammer_vnode_vops, &mp->mnt_vn_norm_ops); 155 156 /* 157 * Locate the root directory using the root cluster's B-Tree as a 158 * starting point. The root directory uses an obj_id of 1. 159 * 160 * FUTURE: Leave the root directory cached referenced but unlocked 161 * in hmp->rootvp (need to flush it on unmount). 162 */ 163 error = hammer_vfs_vget(mp, 1, &rootvp); 164 if (error == 0) 165 vput(rootvp); 166 /*vn_unlock(hmp->rootvp);*/ 167 168 /* 169 * Cleanup and return. 170 */ 171 if (error) 172 hammer_free_hmp(mp); 173 return (error); 174 } 175 176 static int 177 hammer_vfs_unmount(struct mount *mp, int mntflags) 178 { 179 #if 0 180 struct hammer_mount *hmp = (void *)mp->mnt_data; 181 #endif 182 int flags; 183 184 /* 185 * 186 */ 187 188 /* 189 * Clean out the vnodes 190 */ 191 flags = WRITECLOSE | ((mntflags & MNT_FORCE) ? FORCECLOSE : 0); 192 vflush(mp, 0, flags); 193 194 /* 195 * Clean up the internal mount structure and related entities. This 196 * may issue I/O. 197 */ 198 hammer_free_hmp(mp); 199 return(0); 200 } 201 202 /* 203 * Clean up the internal mount structure and disassociate it from the mount. 204 * This may issue I/O. 205 */ 206 static void 207 hammer_free_hmp(struct mount *mp) 208 { 209 struct hammer_mount *hmp = (void *)mp->mnt_data; 210 211 #if 0 212 /* 213 * Clean up the root vnode 214 */ 215 if (hmp->rootvp) { 216 vrele(hmp->rootvp); 217 hmp->rootvp = NULL; 218 } 219 #endif 220 221 /* 222 * Unload & flush inodes 223 */ 224 RB_SCAN(hammer_ino_rb_tree, &hmp->rb_inos_root, NULL, 225 hammer_unload_inode, hmp); 226 227 /* 228 * Unload & flush volumes 229 */ 230 RB_SCAN(hammer_vol_rb_tree, &hmp->rb_vols_root, NULL, 231 hammer_unload_volume, NULL); 232 233 mp->mnt_data = NULL; 234 hmp->mp = NULL; 235 kfree(hmp, M_HAMMER); 236 } 237 238 /* 239 * Return the root vnode for the filesystem. 240 * 241 * HAMMER stores the root vnode in the hammer_mount structure so 242 * getting it is easy. 243 */ 244 static int 245 hammer_vfs_root(struct mount *mp, struct vnode **vpp) 246 { 247 struct hammer_mount *hmp = (void *)mp->mnt_data; 248 int error; 249 250 if (hmp->rootcl == NULL) 251 error = EIO; 252 else 253 error = hammer_vfs_vget(mp, 1, vpp); 254 return (error); 255 #if 0 256 /* FUTURE - cached root vnode */ 257 if ((vp = hmp->rootvp) != NULL) { 258 vref(vp); 259 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 260 *vpp = vp; 261 return (0); 262 } else { 263 *vpp = NULL; 264 return (EIO); 265 } 266 #endif 267 } 268 269 static int 270 hammer_vfs_statfs(struct mount *mp, struct statfs *sbp, struct ucred *cred) 271 { 272 *sbp = mp->mnt_stat; 273 return(0); 274 } 275 276 static int 277 hammer_vfs_sync(struct mount *mp, int waitfor) 278 { 279 return(0); 280 } 281 282