1 /* $NetBSD: rump_vfs.c,v 1.77 2013/06/10 19:48:22 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.77 2013/06/10 19:48:22 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 extern 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 static void 77 fini(void) 78 { 79 80 vfs_shutdown(); 81 } 82 83 static void 84 drainbufs(int npages) 85 { 86 87 mutex_enter(&bufcache_lock); 88 buf_drain(npages); 89 mutex_exit(&bufcache_lock); 90 } 91 92 RUMP_COMPONENT(RUMP__FACTION_VFS) 93 { 94 extern struct vfsops rumpfs_vfsops; 95 char buf[64]; 96 int rv, i; 97 98 /* initialize indirect interfaces */ 99 rump_vfs_fini = fini; 100 rump_vfs_drainbufs = drainbufs; 101 102 if (rumpuser_getparam("RUMP_NVNODES", buf, sizeof(buf)) == 0) { 103 desiredvnodes = strtoul(buf, NULL, 10); 104 } else { 105 desiredvnodes = 1<<10; 106 } 107 108 rumpblk_init(); 109 110 for (i = 0; i < ncpu; i++) { 111 struct cpu_info *ci = cpu_lookup(i); 112 cache_cpu_init(ci); 113 } 114 115 /* make number of bufpages 5% of total memory limit */ 116 if (rump_physmemlimit != RUMPMEM_UNLIMITED) { 117 extern u_int bufpages; 118 bufpages = rump_physmemlimit / (20 * PAGE_SIZE); 119 } 120 121 vfsinit(); 122 bufinit(); 123 cwd_sys_init(); 124 lf_init(); 125 spec_init(); 126 fstrans_init(); 127 128 root_device = &rump_rootdev; 129 130 /* bootstrap cwdi (rest done in vfs_mountroot() */ 131 proc0.p_cwdi = &cwdi0; 132 proc0.p_cwdi = cwdinit(); 133 134 vfs_attach(&rumpfs_vfsops); 135 vfs_mountroot(); 136 137 /* "mtree": create /dev */ 138 do_sys_mkdir("/dev", 0755, UIO_SYSSPACE); 139 140 rump_proc_vfs_init = pvfs_init; 141 rump_proc_vfs_release = pvfs_rele; 142 143 if (rump_threads) { 144 if ((rv = kthread_create(PRI_IOFLUSH, KTHREAD_MPSAFE, NULL, 145 sched_sync, NULL, NULL, "ioflush")) != 0) 146 panic("syncer thread create failed: %d", rv); 147 } else { 148 syncdelay = 0; 149 } 150 151 /* 152 * On archs where the native kernel ABI is supported, map 153 * host module directory to rump. This means that kernel 154 * modules from the host will be autoloaded to rump kernels. 155 */ 156 #ifdef _RUMP_NATIVE_ABI 157 { 158 char *mbase; 159 160 if (rumpuser_getparam("RUMP_MODULEBASE", buf, sizeof(buf)) == 0) 161 mbase = buf; 162 else 163 mbase = module_base; 164 165 if (strlen(mbase) != 0 && *mbase != '0') { 166 rump_etfs_register(module_base, mbase, RUMP_ETFS_DIR_SUBDIRS); 167 } 168 } 169 #endif 170 171 module_init_class(MODULE_CLASS_VFS); 172 173 /* 174 * Don't build device names for a large set of devices by 175 * default. While the pseudo-devfs is a fun experiment, 176 * creating many many device nodes may increase rump kernel 177 * bootstrap time by ~40%. Device nodes should be created 178 * per-demand in the component constructors. 179 */ 180 #if 0 181 { 182 extern struct devsw_conv devsw_conv0[]; 183 extern int max_devsw_convs; 184 rump_vfs_builddevs(devsw_conv0, max_devsw_convs); 185 } 186 #else 187 rump_vfs_builddevs(NULL, 0); 188 #endif 189 190 /* attach null device and create /dev/{null,zero} */ 191 rump_devnull_init(); 192 193 rump_component_init(RUMP_COMPONENT_VFS); 194 } 195 196 struct rumpcn { 197 struct componentname rcn_cn; 198 char *rcn_path; 199 }; 200 201 struct componentname * 202 rump_makecn(u_long nameiop, u_long flags, const char *name, size_t namelen, 203 kauth_cred_t creds, struct lwp *l) 204 { 205 struct rumpcn *rcn; 206 struct componentname *cnp; 207 208 rcn = kmem_zalloc(sizeof(*rcn), KM_SLEEP); 209 cnp = &rcn->rcn_cn; 210 211 rcn->rcn_path = PNBUF_GET(); 212 strlcpy(rcn->rcn_path, name, MAXPATHLEN); 213 cnp->cn_nameptr = rcn->rcn_path; 214 215 cnp->cn_nameiop = nameiop; 216 cnp->cn_flags = flags & (MODMASK | PARAMASK); 217 218 cnp->cn_namelen = namelen; 219 220 cnp->cn_cred = creds; 221 222 return cnp; 223 } 224 225 void 226 rump_freecn(struct componentname *cnp, int flags) 227 { 228 struct rumpcn *rcn = (void *)cnp; 229 230 if (flags & RUMPCN_FREECRED) 231 rump_cred_put(cnp->cn_cred); 232 233 PNBUF_PUT(rcn->rcn_path); 234 kmem_free(rcn, sizeof(*rcn)); 235 } 236 237 /* hey baby, what's your namei? */ 238 int 239 rump_namei(uint32_t op, uint32_t flags, const char *namep, 240 struct vnode **dvpp, struct vnode **vpp, struct componentname **cnpp) 241 { 242 struct pathbuf *pb; 243 struct nameidata nd; 244 int rv; 245 246 pb = pathbuf_create(namep); 247 if (pb == NULL) { 248 return ENOMEM; 249 } 250 NDINIT(&nd, op, flags, pb); 251 rv = namei(&nd); 252 if (rv) { 253 pathbuf_destroy(pb); 254 return rv; 255 } 256 257 if (dvpp) { 258 KASSERT(flags & LOCKPARENT); 259 *dvpp = nd.ni_dvp; 260 } else { 261 KASSERT((flags & LOCKPARENT) == 0); 262 } 263 264 if (vpp) { 265 *vpp = nd.ni_vp; 266 } else { 267 if (nd.ni_vp) { 268 if (flags & LOCKLEAF) 269 vput(nd.ni_vp); 270 else 271 vrele(nd.ni_vp); 272 } 273 } 274 275 if (cnpp) { 276 struct componentname *cnp; 277 278 cnp = kmem_alloc(sizeof(*cnp), KM_SLEEP); 279 memcpy(cnp, &nd.ni_cnd, sizeof(*cnp)); 280 *cnpp = cnp; 281 } 282 pathbuf_destroy(pb); 283 284 return rv; 285 } 286 287 void 288 rump_getvninfo(struct vnode *vp, enum rump_vtype *vtype, 289 voff_t *vsize, dev_t *vdev) 290 { 291 292 *vtype = (enum rump_vtype)vp->v_type; 293 *vsize = vp->v_size; 294 if (vp->v_specnode) 295 *vdev = vp->v_rdev; 296 else 297 *vdev = 0; 298 } 299 300 struct vfsops * 301 rump_vfslist_iterate(struct vfsops *ops) 302 { 303 304 if (ops == NULL) 305 return LIST_FIRST(&vfs_list); 306 else 307 return LIST_NEXT(ops, vfs_list); 308 } 309 310 struct vfsops * 311 rump_vfs_getopsbyname(const char *name) 312 { 313 314 return vfs_getopsbyname(name); 315 } 316 317 int 318 rump_vfs_getmp(const char *path, struct mount **mpp) 319 { 320 struct vnode *vp; 321 int rv; 322 323 if ((rv = namei_simple_user(path, NSM_FOLLOW_TRYEMULROOT, &vp)) != 0) 324 return rv; 325 326 *mpp = vp->v_mount; 327 vrele(vp); 328 return 0; 329 } 330 331 struct vattr* 332 rump_vattr_init(void) 333 { 334 struct vattr *vap; 335 336 vap = kmem_alloc(sizeof(struct vattr), KM_SLEEP); 337 vattr_null(vap); 338 339 return vap; 340 } 341 342 void 343 rump_vattr_settype(struct vattr *vap, enum rump_vtype vt) 344 { 345 346 vap->va_type = (enum vtype)vt; 347 } 348 349 void 350 rump_vattr_setmode(struct vattr *vap, mode_t mode) 351 { 352 353 vap->va_mode = mode; 354 } 355 356 void 357 rump_vattr_setrdev(struct vattr *vap, dev_t dev) 358 { 359 360 vap->va_rdev = dev; 361 } 362 363 void 364 rump_vattr_free(struct vattr *vap) 365 { 366 367 kmem_free(vap, sizeof(*vap)); 368 } 369 370 void 371 rump_vp_incref(struct vnode *vp) 372 { 373 374 vref(vp); 375 } 376 377 int 378 rump_vp_getref(struct vnode *vp) 379 { 380 381 return vp->v_usecount; 382 } 383 384 void 385 rump_vp_rele(struct vnode *vp) 386 { 387 388 vrele(vp); 389 } 390 391 void 392 rump_vp_interlock(struct vnode *vp) 393 { 394 395 mutex_enter(vp->v_interlock); 396 } 397 398 int 399 rump_vfs_unmount(struct mount *mp, int mntflags) 400 { 401 402 return VFS_UNMOUNT(mp, mntflags); 403 } 404 405 int 406 rump_vfs_root(struct mount *mp, struct vnode **vpp, int lock) 407 { 408 int rv; 409 410 rv = VFS_ROOT(mp, vpp); 411 if (rv) 412 return rv; 413 414 if (!lock) 415 VOP_UNLOCK(*vpp); 416 417 return 0; 418 } 419 420 int 421 rump_vfs_statvfs(struct mount *mp, struct statvfs *sbp) 422 { 423 424 return VFS_STATVFS(mp, sbp); 425 } 426 427 int 428 rump_vfs_sync(struct mount *mp, int wait, kauth_cred_t cred) 429 { 430 431 return VFS_SYNC(mp, wait ? MNT_WAIT : MNT_NOWAIT, cred); 432 } 433 434 int 435 rump_vfs_fhtovp(struct mount *mp, struct fid *fid, struct vnode **vpp) 436 { 437 438 return VFS_FHTOVP(mp, fid, vpp); 439 } 440 441 int 442 rump_vfs_vptofh(struct vnode *vp, struct fid *fid, size_t *fidsize) 443 { 444 445 return VFS_VPTOFH(vp, fid, fidsize); 446 } 447 448 int 449 rump_vfs_extattrctl(struct mount *mp, int cmd, struct vnode *vp, 450 int attrnamespace, const char *attrname) 451 { 452 453 return VFS_EXTATTRCTL(mp, cmd, vp, attrnamespace, attrname); 454 } 455 456 /*ARGSUSED*/ 457 void 458 rump_vfs_syncwait(struct mount *mp) 459 { 460 int n; 461 462 n = buf_syncwait(); 463 if (n) 464 printf("syncwait: unsynced buffers: %d\n", n); 465 } 466 467 /* 468 * Dump info about mount point. No locking. 469 */ 470 void 471 rump_vfs_mount_print(const char *path, int full) 472 { 473 #ifdef DEBUGPRINT 474 struct vnode *mvp; 475 struct vnode *vp; 476 int error; 477 478 rumpuser_dprintf("\n==== dumping mountpoint at ``%s'' ====\n\n", path); 479 if ((error = namei_simple_user(path, NSM_FOLLOW_NOEMULROOT, &mvp))!=0) { 480 rumpuser_dprintf("==== lookup error %d ====\n\n", error); 481 return; 482 } 483 vfs_mount_print(mvp->v_mount, full, (void *)rumpuser_dprintf); 484 if (full) { 485 rumpuser_dprintf("\n== dumping vnodes ==\n\n"); 486 TAILQ_FOREACH(vp, &mvp->v_mount->mnt_vnodelist, v_mntvnodes) { 487 vfs_vnode_print(vp, full, (void *)rumpuser_dprintf); 488 } 489 } 490 vrele(mvp); 491 rumpuser_dprintf("\n==== done ====\n\n"); 492 #else 493 rumpuser_dprintf("mount dump not supported without DEBUGPRINT\n"); 494 #endif 495 } 496 497 void 498 rump_biodone(void *arg, size_t count, int error) 499 { 500 struct buf *bp = arg; 501 502 bp->b_resid = bp->b_bcount - count; 503 KASSERT(bp->b_resid >= 0); 504 bp->b_error = error; 505 506 biodone(bp); 507 } 508