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