1 /* $NetBSD: rump_vfs.c,v 1.65 2011/01/07 11:27:53 pooka Exp $ */ 2 3 /* 4 * Copyright (c) 2008 Antti Kantee. All Rights Reserved. 5 * 6 * Development of this software was supported by the 7 * Finnish Cultural Foundation. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS 19 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 20 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 * SUCH DAMAGE. 29 */ 30 31 #include <sys/cdefs.h> 32 __KERNEL_RCSID(0, "$NetBSD: rump_vfs.c,v 1.65 2011/01/07 11:27:53 pooka Exp $"); 33 34 #include <sys/param.h> 35 #include <sys/buf.h> 36 #include <sys/conf.h> 37 #include <sys/evcnt.h> 38 #include <sys/filedesc.h> 39 #include <sys/fstrans.h> 40 #include <sys/lockf.h> 41 #include <sys/kthread.h> 42 #include <sys/module.h> 43 #include <sys/namei.h> 44 #include <sys/queue.h> 45 #include <sys/stat.h> 46 #include <sys/vfs_syscalls.h> 47 #include <sys/vnode.h> 48 #include <sys/wapbl.h> 49 50 #include <miscfs/specfs/specdev.h> 51 #include <miscfs/syncfs/syncfs.h> 52 53 #include <rump/rump.h> 54 #include <rump/rumpuser.h> 55 56 #include "rump_private.h" 57 #include "rump_vfs_private.h" 58 59 struct cwdinfo cwdi0; 60 const char *rootfstype = ROOT_FSTYPE_ANY; 61 62 static void 63 pvfs_init(struct proc *p) 64 { 65 66 p->p_cwdi = cwdinit(); 67 } 68 69 static void 70 pvfs_rele(struct proc *p) 71 { 72 73 cwdfree(p->p_cwdi); 74 } 75 76 void 77 rump_vfs_init(void) 78 { 79 extern struct devsw_conv devsw_conv0[]; 80 extern int max_devsw_convs; 81 extern struct vfsops rumpfs_vfsops; 82 char buf[64]; 83 int error; 84 int rv, i; 85 86 if (rumpuser_getenv("RUMP_NVNODES", buf, sizeof(buf), &error) == 0) { 87 desiredvnodes = strtoul(buf, NULL, 10); 88 } else { 89 desiredvnodes = 1<<10; 90 } 91 92 rumpblk_init(); 93 94 for (i = 0; i < ncpu; i++) { 95 struct cpu_info *ci = cpu_lookup(i); 96 cache_cpu_init(ci); 97 } 98 99 /* make number of bufpages 5% of total memory limit */ 100 if (rump_physmemlimit != RUMPMEM_UNLIMITED) { 101 extern u_int bufpages; 102 bufpages = rump_physmemlimit / (20 * PAGE_SIZE); 103 } 104 105 vfsinit(); 106 bufinit(); 107 cwd_sys_init(); 108 lf_init(); 109 spec_init(); 110 fstrans_init(); 111 112 if (rump_threads) { 113 if ((rv = kthread_create(PRI_BIO, KTHREAD_MPSAFE, NULL, 114 rumpuser_biothread, rump_biodone, NULL, "rmpabio")) != 0) 115 panic("syncer thread create failed: %d", rv); 116 } 117 118 root_device = &rump_rootdev; 119 120 /* bootstrap cwdi (rest done in vfs_mountroot() */ 121 proc0.p_cwdi = &cwdi0; 122 proc0.p_cwdi = cwdinit(); 123 124 vfs_attach(&rumpfs_vfsops); 125 vfs_mountroot(); 126 127 /* "mtree": create /dev */ 128 do_sys_mkdir("/dev", 0777, UIO_SYSSPACE); 129 rump_devnull_init(); 130 131 rump_proc_vfs_init = pvfs_init; 132 rump_proc_vfs_release = pvfs_rele; 133 134 if (rump_threads) { 135 if ((rv = kthread_create(PRI_IOFLUSH, KTHREAD_MPSAFE, NULL, 136 sched_sync, NULL, NULL, "ioflush")) != 0) 137 panic("syncer thread create failed: %d", rv); 138 } else { 139 syncdelay = 0; 140 } 141 142 /* 143 * On archs where the native kernel ABI is supported, map 144 * host module directory to rump. This means that kernel 145 * modules from the host will be autoloaded to rump kernels. 146 */ 147 #ifdef _RUMP_NATIVE_ABI 148 { 149 char *mbase; 150 151 if (rumpuser_getenv("RUMP_MODULEBASE", buf, sizeof(buf), &error) == 0) 152 mbase = buf; 153 else 154 mbase = module_base; 155 156 if (strlen(mbase) != 0 && *mbase != '0') { 157 rump_etfs_register(module_base, mbase, RUMP_ETFS_DIR_SUBDIRS); 158 } 159 } 160 #endif 161 162 module_init_class(MODULE_CLASS_VFS); 163 164 rump_vfs_builddevs(devsw_conv0, max_devsw_convs); 165 166 rump_component_init(RUMP_COMPONENT_VFS); 167 } 168 169 void 170 rump_vfs_fini(void) 171 { 172 173 vfs_shutdown(); 174 } 175 176 struct rumpcn { 177 struct componentname rcn_cn; 178 char *rcn_path; 179 }; 180 181 struct componentname * 182 rump_makecn(u_long nameiop, u_long flags, const char *name, size_t namelen, 183 kauth_cred_t creds, struct lwp *l) 184 { 185 struct rumpcn *rcn; 186 struct componentname *cnp; 187 const char *cp = NULL; 188 189 rcn = kmem_zalloc(sizeof(*rcn), KM_SLEEP); 190 cnp = &rcn->rcn_cn; 191 192 rcn->rcn_path = PNBUF_GET(); 193 strlcpy(rcn->rcn_path, name, MAXPATHLEN); 194 cnp->cn_nameptr = rcn->rcn_path; 195 196 cnp->cn_nameiop = nameiop; 197 cnp->cn_flags = flags & (MODMASK | PARAMASK); 198 199 cnp->cn_namelen = namelen; 200 cnp->cn_hash = namei_hash(name, &cp); 201 202 cnp->cn_cred = creds; 203 204 return cnp; 205 } 206 207 void 208 rump_freecn(struct componentname *cnp, int flags) 209 { 210 struct rumpcn *rcn = (void *)cnp; 211 212 if (flags & RUMPCN_FREECRED) 213 rump_cred_put(cnp->cn_cred); 214 215 PNBUF_PUT(rcn->rcn_path); 216 kmem_free(rcn, sizeof(*rcn)); 217 } 218 219 /* hey baby, what's your namei? */ 220 int 221 rump_namei(uint32_t op, uint32_t flags, const char *namep, 222 struct vnode **dvpp, struct vnode **vpp, struct componentname **cnpp) 223 { 224 struct pathbuf *pb; 225 struct nameidata nd; 226 int rv; 227 228 pb = pathbuf_create(namep); 229 if (pb == NULL) { 230 return ENOMEM; 231 } 232 NDINIT(&nd, op, flags, pb); 233 rv = namei(&nd); 234 if (rv) { 235 pathbuf_destroy(pb); 236 return rv; 237 } 238 239 if (dvpp) { 240 KASSERT(flags & LOCKPARENT); 241 *dvpp = nd.ni_dvp; 242 } else { 243 KASSERT((flags & LOCKPARENT) == 0); 244 } 245 246 if (vpp) { 247 *vpp = nd.ni_vp; 248 } else { 249 if (nd.ni_vp) { 250 if (flags & LOCKLEAF) 251 vput(nd.ni_vp); 252 else 253 vrele(nd.ni_vp); 254 } 255 } 256 257 if (cnpp) { 258 struct componentname *cnp; 259 260 cnp = kmem_alloc(sizeof(*cnp), KM_SLEEP); 261 memcpy(cnp, &nd.ni_cnd, sizeof(*cnp)); 262 *cnpp = cnp; 263 } 264 pathbuf_destroy(pb); 265 266 return rv; 267 } 268 269 void 270 rump_getvninfo(struct vnode *vp, enum vtype *vtype, 271 voff_t *vsize, dev_t *vdev) 272 { 273 274 *vtype = vp->v_type; 275 *vsize = vp->v_size; 276 if (vp->v_specnode) 277 *vdev = vp->v_rdev; 278 else 279 *vdev = 0; 280 } 281 282 struct vfsops * 283 rump_vfslist_iterate(struct vfsops *ops) 284 { 285 286 if (ops == NULL) 287 return LIST_FIRST(&vfs_list); 288 else 289 return LIST_NEXT(ops, vfs_list); 290 } 291 292 struct vfsops * 293 rump_vfs_getopsbyname(const char *name) 294 { 295 296 return vfs_getopsbyname(name); 297 } 298 299 int 300 rump_vfs_getmp(const char *path, struct mount **mpp) 301 { 302 struct vnode *vp; 303 int rv; 304 305 if ((rv = namei_simple_user(path, NSM_FOLLOW_TRYEMULROOT, &vp)) != 0) 306 return rv; 307 308 *mpp = vp->v_mount; 309 vrele(vp); 310 return 0; 311 } 312 313 struct vattr* 314 rump_vattr_init(void) 315 { 316 struct vattr *vap; 317 318 vap = kmem_alloc(sizeof(struct vattr), KM_SLEEP); 319 vattr_null(vap); 320 321 return vap; 322 } 323 324 void 325 rump_vattr_settype(struct vattr *vap, enum vtype vt) 326 { 327 328 vap->va_type = vt; 329 } 330 331 void 332 rump_vattr_setmode(struct vattr *vap, mode_t mode) 333 { 334 335 vap->va_mode = mode; 336 } 337 338 void 339 rump_vattr_setrdev(struct vattr *vap, dev_t dev) 340 { 341 342 vap->va_rdev = dev; 343 } 344 345 void 346 rump_vattr_free(struct vattr *vap) 347 { 348 349 kmem_free(vap, sizeof(*vap)); 350 } 351 352 void 353 rump_vp_incref(struct vnode *vp) 354 { 355 356 vref(vp); 357 } 358 359 int 360 rump_vp_getref(struct vnode *vp) 361 { 362 363 return vp->v_usecount; 364 } 365 366 void 367 rump_vp_rele(struct vnode *vp) 368 { 369 370 vrele(vp); 371 } 372 373 void 374 rump_vp_interlock(struct vnode *vp) 375 { 376 377 mutex_enter(&vp->v_interlock); 378 } 379 380 int 381 rump_vfs_unmount(struct mount *mp, int mntflags) 382 { 383 384 return VFS_UNMOUNT(mp, mntflags); 385 } 386 387 int 388 rump_vfs_root(struct mount *mp, struct vnode **vpp, int lock) 389 { 390 int rv; 391 392 rv = VFS_ROOT(mp, vpp); 393 if (rv) 394 return rv; 395 396 if (!lock) 397 VOP_UNLOCK(*vpp); 398 399 return 0; 400 } 401 402 int 403 rump_vfs_statvfs(struct mount *mp, struct statvfs *sbp) 404 { 405 406 return VFS_STATVFS(mp, sbp); 407 } 408 409 int 410 rump_vfs_sync(struct mount *mp, int wait, kauth_cred_t cred) 411 { 412 413 return VFS_SYNC(mp, wait ? MNT_WAIT : MNT_NOWAIT, cred); 414 } 415 416 int 417 rump_vfs_fhtovp(struct mount *mp, struct fid *fid, struct vnode **vpp) 418 { 419 420 return VFS_FHTOVP(mp, fid, vpp); 421 } 422 423 int 424 rump_vfs_vptofh(struct vnode *vp, struct fid *fid, size_t *fidsize) 425 { 426 427 return VFS_VPTOFH(vp, fid, fidsize); 428 } 429 430 int 431 rump_vfs_extattrctl(struct mount *mp, int cmd, struct vnode *vp, 432 int attrnamespace, const char *attrname) 433 { 434 435 return VFS_EXTATTRCTL(mp, cmd, vp, attrnamespace, attrname); 436 } 437 438 /*ARGSUSED*/ 439 void 440 rump_vfs_syncwait(struct mount *mp) 441 { 442 int n; 443 444 n = buf_syncwait(); 445 if (n) 446 printf("syncwait: unsynced buffers: %d\n", n); 447 } 448 449 /* 450 * Dump info about mount point. No locking. 451 */ 452 void 453 rump_vfs_mount_print(const char *path, int full) 454 { 455 #ifdef DEBUGPRINT 456 struct vnode *mvp; 457 struct vnode *vp; 458 int error; 459 460 rumpuser_dprintf("\n==== dumping mountpoint at ``%s'' ====\n\n", path); 461 if ((error = namei_simple_user(path, NSM_FOLLOW_NOEMULROOT, &mvp))!=0) { 462 rumpuser_dprintf("==== lookup error %d ====\n\n", error); 463 return; 464 } 465 vfs_mount_print(mvp->v_mount, full, (void *)rumpuser_dprintf); 466 if (full) { 467 rumpuser_dprintf("\n== dumping vnodes ==\n\n"); 468 TAILQ_FOREACH(vp, &mvp->v_mount->mnt_vnodelist, v_mntvnodes) { 469 vfs_vnode_print(vp, full, (void *)rumpuser_dprintf); 470 } 471 } 472 vrele(mvp); 473 rumpuser_dprintf("\n==== done ====\n\n"); 474 #else 475 rumpuser_dprintf("mount dump not supported without DEBUGPRINT\n"); 476 #endif 477 } 478 479 void 480 rump_biodone(void *arg, size_t count, int error) 481 { 482 struct buf *bp = arg; 483 484 bp->b_resid = bp->b_bcount - count; 485 KASSERT(bp->b_resid >= 0); 486 bp->b_error = error; 487 488 biodone(bp); 489 } 490 491 void 492 rump_vfs_drainbufs(int npages) 493 { 494 495 mutex_enter(&bufcache_lock); 496 buf_drain(npages); 497 mutex_exit(&bufcache_lock); 498 } 499