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