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.9 2007/12/14 08:05:39 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 hammer_mount_t hmp; 91 hammer_volume_t rootvol; 92 struct vnode *rootvp; 93 const char *upath; /* volume name in userspace */ 94 char *path; /* volume name in system space */ 95 int error; 96 int i; 97 98 if ((error = copyin(data, &info, sizeof(info))) != 0) 99 return (error); 100 if (info.nvolumes <= 0 || info.nvolumes >= 32768) 101 return (EINVAL); 102 103 /* 104 * Interal mount data structure 105 */ 106 if (mp->mnt_flag & MNT_UPDATE) { 107 hmp = (void *)mp->mnt_data; 108 KKASSERT(hmp != NULL); 109 } else { 110 hmp = kmalloc(sizeof(*hmp), M_HAMMER, M_WAITOK | M_ZERO); 111 mp->mnt_data = (qaddr_t)hmp; 112 hmp->mp = mp; 113 hmp->zbuf = kmalloc(HAMMER_BUFSIZE, M_HAMMER, M_WAITOK|M_ZERO); 114 hmp->namekey_iterator = mycpu->gd_time_seconds; 115 } 116 hmp->hflags = info.hflags; 117 if (info.asof) { 118 mp->mnt_flag |= MNT_RDONLY; 119 hmp->asof = info.asof; 120 } else { 121 hmp->asof = HAMMER_MAX_TID; 122 } 123 124 /* 125 * Re-open read-write if originally read-only, or vise-versa XXX 126 */ 127 if (mp->mnt_flag & MNT_UPDATE) { 128 if (hmp->ronly == 0 && (mp->mnt_flag & MNT_RDONLY)) { 129 kprintf("HAMMER read-write -> read-only XXX\n"); 130 hmp->ronly = 1; 131 } else if (hmp->ronly && (mp->mnt_flag & MNT_RDONLY) == 0) { 132 kprintf("HAMMER read-only -> read-write XXX\n"); 133 hmp->ronly = 0; 134 } 135 return(0); 136 } 137 138 RB_INIT(&hmp->rb_vols_root); 139 RB_INIT(&hmp->rb_inos_root); 140 hmp->ronly = ((mp->mnt_flag & MNT_RDONLY) != 0); 141 142 /* 143 * Load volumes 144 */ 145 path = objcache_get(namei_oc, M_WAITOK); 146 for (i = 0; i < info.nvolumes; ++i) { 147 error = copyin(&info.volumes[i], &upath, sizeof(char *)); 148 if (error == 0) 149 error = copyinstr(upath, path, MAXPATHLEN, NULL); 150 if (error == 0) 151 error = hammer_install_volume(hmp, path); 152 if (error) 153 break; 154 } 155 objcache_put(namei_oc, path); 156 157 /* 158 * Make sure we found a root volume 159 */ 160 if (error == 0 && hmp->rootvol == NULL) { 161 kprintf("hammer_mount: No root volume found!\n"); 162 error = EINVAL; 163 } 164 if (error == 0 && hmp->rootcl == NULL) { 165 kprintf("hammer_mount: No root cluster found!\n"); 166 error = EINVAL; 167 } 168 if (error) { 169 hammer_free_hmp(mp); 170 return (error); 171 } 172 173 /* 174 * No errors, setup enough of the mount point so we can lookup the 175 * root vnode. 176 */ 177 mp->mnt_iosize_max = MAXPHYS; 178 mp->mnt_kern_flag |= MNTK_FSMID; 179 mp->mnt_stat.f_fsid.val[0] = 0; /* XXX */ 180 mp->mnt_stat.f_fsid.val[1] = 0; /* XXX */ 181 182 /* 183 * note: f_iosize is used by vnode_pager_haspage() when constructing 184 * its VOP_BMAP call. 185 */ 186 mp->mnt_stat.f_iosize = HAMMER_BUFSIZE; 187 mp->mnt_stat.f_bsize = HAMMER_BUFSIZE; 188 vfs_getnewfsid(mp); /* XXX */ 189 mp->mnt_maxsymlinklen = 255; 190 mp->mnt_flag |= MNT_LOCAL; 191 192 vfs_add_vnodeops(mp, &hammer_vnode_vops, &mp->mnt_vn_norm_ops); 193 194 /* 195 * The root volume's ondisk pointer is only valid if we hold a 196 * reference to it. 197 */ 198 rootvol = hammer_get_root_volume(hmp, &error); 199 if (error) 200 goto done; 201 ksnprintf(mp->mnt_stat.f_mntfromname, 202 sizeof(mp->mnt_stat.f_mntfromname), "%s", 203 rootvol->ondisk->vol_name); 204 hammer_rel_volume(rootvol, 0); 205 206 /* 207 * Locate the root directory using the root cluster's B-Tree as a 208 * starting point. The root directory uses an obj_id of 1. 209 * 210 * FUTURE: Leave the root directory cached referenced but unlocked 211 * in hmp->rootvp (need to flush it on unmount). 212 */ 213 error = hammer_vfs_vget(mp, 1, &rootvp); 214 if (error) 215 goto done; 216 vput(rootvp); 217 /*vn_unlock(hmp->rootvp);*/ 218 219 done: 220 /* 221 * Cleanup and return. 222 */ 223 if (error) 224 hammer_free_hmp(mp); 225 return (error); 226 } 227 228 static int 229 hammer_vfs_unmount(struct mount *mp, int mntflags) 230 { 231 #if 0 232 struct hammer_mount *hmp = (void *)mp->mnt_data; 233 #endif 234 int flags; 235 int error; 236 237 /* 238 * Clean out the vnodes 239 */ 240 flags = 0; 241 if (mntflags & MNT_FORCE) 242 flags |= FORCECLOSE; 243 if ((error = vflush(mp, 0, flags)) != 0) 244 return (error); 245 246 /* 247 * Clean up the internal mount structure and related entities. This 248 * may issue I/O. 249 */ 250 hammer_free_hmp(mp); 251 return(0); 252 } 253 254 /* 255 * Clean up the internal mount structure and disassociate it from the mount. 256 * This may issue I/O. 257 */ 258 static void 259 hammer_free_hmp(struct mount *mp) 260 { 261 struct hammer_mount *hmp = (void *)mp->mnt_data; 262 263 #if 0 264 /* 265 * Clean up the root vnode 266 */ 267 if (hmp->rootvp) { 268 vrele(hmp->rootvp); 269 hmp->rootvp = NULL; 270 } 271 #endif 272 273 /* 274 * Unload & flush inodes 275 */ 276 RB_SCAN(hammer_ino_rb_tree, &hmp->rb_inos_root, NULL, 277 hammer_unload_inode, NULL); 278 279 /* 280 * Unload & flush volumes 281 */ 282 RB_SCAN(hammer_vol_rb_tree, &hmp->rb_vols_root, NULL, 283 hammer_unload_volume, NULL); 284 285 mp->mnt_data = NULL; 286 mp->mnt_flag &= ~MNT_LOCAL; 287 hmp->mp = NULL; 288 kfree(hmp->zbuf, M_HAMMER); 289 kfree(hmp, M_HAMMER); 290 } 291 292 /* 293 * Return the root vnode for the filesystem. 294 * 295 * HAMMER stores the root vnode in the hammer_mount structure so 296 * getting it is easy. 297 */ 298 static int 299 hammer_vfs_root(struct mount *mp, struct vnode **vpp) 300 { 301 struct hammer_mount *hmp = (void *)mp->mnt_data; 302 int error; 303 304 if (hmp->rootcl == NULL) 305 error = EIO; 306 else 307 error = hammer_vfs_vget(mp, 1, vpp); 308 return (error); 309 #if 0 310 /* FUTURE - cached root vnode */ 311 if ((vp = hmp->rootvp) != NULL) { 312 vref(vp); 313 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 314 *vpp = vp; 315 return (0); 316 } else { 317 *vpp = NULL; 318 return (EIO); 319 } 320 #endif 321 } 322 323 static int 324 hammer_vfs_statfs(struct mount *mp, struct statfs *sbp, struct ucred *cred) 325 { 326 struct hammer_mount *hmp = (void *)mp->mnt_data; 327 hammer_volume_t volume; 328 hammer_volume_ondisk_t ondisk; 329 int error; 330 331 volume = hammer_get_root_volume(hmp, &error); 332 if (error) 333 return(error); 334 335 ondisk = volume->ondisk; 336 337 mp->mnt_stat.f_bfree = mp->mnt_stat.f_blocks - 338 ondisk->vol0_stat_idx_bufs - 339 ondisk->vol0_stat_rec_bufs - 340 ondisk->vol0_stat_data_bufs; 341 if (mp->mnt_stat.f_bfree < 0) 342 mp->mnt_stat.f_bfree = 0; 343 mp->mnt_stat.f_bavail = mp->mnt_stat.f_bfree; 344 mp->mnt_stat.f_files = ondisk->vol0_stat_inodes; 345 if (mp->mnt_stat.f_files < 0) 346 mp->mnt_stat.f_files = 0; 347 348 hammer_rel_volume(volume, 0); 349 *sbp = mp->mnt_stat; 350 return(0); 351 } 352 353 static int 354 hammer_vfs_sync(struct mount *mp, int waitfor) 355 { 356 struct hammer_mount *hmp = (void *)mp->mnt_data; 357 int error; 358 359 error = hammer_sync_hmp(hmp, waitfor); 360 return(error); 361 } 362 363