1 /* $NetBSD: rump.c,v 1.23 2007/12/08 19:29:52 pooka Exp $ */ 2 3 /* 4 * Copyright (c) 2007 Antti Kantee. All Rights Reserved. 5 * 6 * Development of this software was supported by Google Summer of Code. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 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 the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS 18 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 23 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 */ 29 30 #include <sys/param.h> 31 #include <sys/filedesc.h> 32 #include <sys/kauth.h> 33 #include <sys/kmem.h> 34 #include <sys/mount.h> 35 #include <sys/namei.h> 36 #include <sys/queue.h> 37 #include <sys/resourcevar.h> 38 #include <sys/vnode.h> 39 #include <sys/cpu.h> 40 41 #include <miscfs/specfs/specdev.h> 42 43 #include "rump_private.h" 44 #include "rumpuser.h" 45 46 struct proc rump_proc; 47 struct cwdinfo rump_cwdi; 48 struct pstats rump_stats; 49 struct plimit rump_limits; 50 kauth_cred_t rump_cred; 51 struct cpu_info rump_cpu; 52 53 kmutex_t rump_giantlock; 54 55 struct fakeblk { 56 char path[MAXPATHLEN]; 57 LIST_ENTRY(fakeblk) entries; 58 }; 59 60 static LIST_HEAD(, fakeblk) fakeblks = LIST_HEAD_INITIALIZER(fakeblks); 61 62 static void 63 rump_aiodone_worker(struct work *wk, void *dummy) 64 { 65 struct buf *bp = (struct buf *)wk; 66 67 KASSERT(&bp->b_work == wk); 68 bp->b_iodone(bp); 69 } 70 71 void 72 rump_init() 73 { 74 extern char hostname[]; 75 extern size_t hostnamelen; 76 struct proc *p; 77 struct lwp *l; 78 int error; 79 80 l = &lwp0; 81 p = &rump_proc; 82 p->p_stats = &rump_stats; 83 p->p_cwdi = &rump_cwdi; 84 p->p_limit = &rump_limits; 85 p->p_pid = 0; 86 l->l_cred = rump_cred; 87 l->l_proc = p; 88 l->l_lid = 1; 89 90 rumpvm_init(); 91 92 rump_limits.pl_rlimit[RLIMIT_FSIZE].rlim_cur = RLIM_INFINITY; 93 94 /* should be "enough" */ 95 syncdelay = 0; 96 97 vfsinit(); 98 bufinit(); 99 100 rump_sleepers_init(); 101 rumpuser_thrinit(); 102 103 rumpuser_mutex_recursive_init(&rump_giantlock.kmtx_mtx); 104 105 /* aieeeedondest */ 106 if (workqueue_create(&uvm.aiodone_queue, "aiodoned", 107 rump_aiodone_worker, NULL, 0, 0, 0)) 108 panic("aiodoned"); 109 110 rumpuser_gethostname(hostname, MAXHOSTNAMELEN, &error); 111 hostnamelen = strlen(hostname); 112 } 113 114 struct mount * 115 rump_mnt_init(struct vfsops *vfsops, int mntflags) 116 { 117 struct mount *mp; 118 119 mp = rumpuser_malloc(sizeof(struct mount), 0); 120 memset(mp, 0, sizeof(struct mount)); 121 122 mp->mnt_op = vfsops; 123 mp->mnt_flag = mntflags; 124 TAILQ_INIT(&mp->mnt_vnodelist); 125 126 mount_initspecific(mp); 127 128 return mp; 129 } 130 131 int 132 rump_mnt_mount(struct mount *mp, const char *path, void *data, size_t *dlen) 133 { 134 int rv; 135 136 rv = VFS_MOUNT(mp, path, data, dlen); 137 if (rv) 138 return rv; 139 140 rv = VFS_STATVFS(mp, &mp->mnt_stat); 141 if (rv) { 142 VFS_UNMOUNT(mp, MNT_FORCE); 143 return rv; 144 } 145 146 rv = VFS_START(mp, 0); 147 if (rv) 148 VFS_UNMOUNT(mp, MNT_FORCE); 149 150 return rv; 151 } 152 153 void 154 rump_mnt_destroy(struct mount *mp) 155 { 156 157 mount_finispecific(mp); 158 rumpuser_free(mp); 159 } 160 161 struct componentname * 162 rump_makecn(u_long nameiop, u_long flags, const char *name, size_t namelen, 163 kauth_cred_t creds, struct lwp *l) 164 { 165 struct componentname *cnp; 166 167 cnp = rumpuser_malloc(sizeof(struct componentname), 0); 168 memset(cnp, 0, sizeof(struct componentname)); 169 170 cnp->cn_nameiop = nameiop; 171 cnp->cn_flags = flags; 172 173 cnp->cn_pnbuf = PNBUF_GET(); 174 strcpy(cnp->cn_pnbuf, name); 175 cnp->cn_nameptr = cnp->cn_pnbuf; 176 cnp->cn_namelen = namelen; 177 178 cnp->cn_cred = creds; 179 180 return cnp; 181 } 182 183 void 184 rump_freecn(struct componentname *cnp, int flags) 185 { 186 187 if (flags & RUMPCN_FREECRED) 188 rump_cred_destroy(cnp->cn_cred); 189 190 if (cnp->cn_flags & SAVENAME) { 191 if (flags & RUMPCN_ISLOOKUP || cnp->cn_flags & SAVESTART) 192 PNBUF_PUT(cnp->cn_pnbuf); 193 } else { 194 PNBUF_PUT(cnp->cn_pnbuf); 195 } 196 rumpuser_free(cnp); 197 } 198 199 int 200 rump_recyclenode(struct vnode *vp) 201 { 202 203 return vrecycle(vp, NULL, curlwp); 204 } 205 206 static struct fakeblk * 207 _rump_fakeblk_find(const char *path) 208 { 209 char buf[MAXPATHLEN]; 210 struct fakeblk *fblk; 211 int error; 212 213 if (rumpuser_realpath(path, buf, &error) == NULL) 214 return NULL; 215 216 LIST_FOREACH(fblk, &fakeblks, entries) 217 if (strcmp(fblk->path, buf) == 0) 218 return fblk; 219 220 return NULL; 221 } 222 223 int 224 rump_fakeblk_register(const char *path) 225 { 226 char buf[MAXPATHLEN]; 227 struct fakeblk *fblk; 228 int error; 229 230 if (_rump_fakeblk_find(path)) 231 return EEXIST; 232 233 if (rumpuser_realpath(path, buf, &error) == NULL) 234 return error; 235 236 fblk = rumpuser_malloc(sizeof(struct fakeblk), 1); 237 if (fblk == NULL) 238 return ENOMEM; 239 240 strlcpy(fblk->path, buf, MAXPATHLEN); 241 LIST_INSERT_HEAD(&fakeblks, fblk, entries); 242 243 return 0; 244 } 245 246 int 247 rump_fakeblk_find(const char *path) 248 { 249 250 return _rump_fakeblk_find(path) != NULL; 251 } 252 253 void 254 rump_fakeblk_deregister(const char *path) 255 { 256 struct fakeblk *fblk; 257 258 fblk = _rump_fakeblk_find(path); 259 if (fblk == NULL) 260 return; 261 262 LIST_REMOVE(fblk, entries); 263 rumpuser_free(fblk); 264 } 265 266 void 267 rump_getvninfo(struct vnode *vp, enum vtype *vtype, voff_t *vsize, dev_t *vdev) 268 { 269 270 *vtype = vp->v_type; 271 *vsize = vp->v_size; 272 if (vp->v_specinfo) 273 *vdev = vp->v_rdev; 274 else 275 *vdev = 0; 276 } 277 278 struct vfsops * 279 rump_vfslist_iterate(struct vfsops *ops) 280 { 281 282 if (ops == NULL) 283 return LIST_FIRST(&vfs_list); 284 else 285 return LIST_NEXT(ops, vfs_list); 286 } 287 288 struct vfsops * 289 rump_vfs_getopsbyname(const char *name) 290 { 291 292 return vfs_getopsbyname(name); 293 } 294 295 struct vattr* 296 rump_vattr_init() 297 { 298 struct vattr *vap; 299 300 vap = rumpuser_malloc(sizeof(struct vattr), 0); 301 vattr_null(vap); 302 303 return vap; 304 } 305 306 void 307 rump_vattr_settype(struct vattr *vap, enum vtype vt) 308 { 309 310 vap->va_type = vt; 311 } 312 313 void 314 rump_vattr_setmode(struct vattr *vap, mode_t mode) 315 { 316 317 vap->va_mode = mode; 318 } 319 320 void 321 rump_vattr_setrdev(struct vattr *vap, dev_t dev) 322 { 323 324 vap->va_rdev = dev; 325 } 326 327 void 328 rump_vattr_free(struct vattr *vap) 329 { 330 331 rumpuser_free(vap); 332 } 333 334 void 335 rump_vp_incref(struct vnode *vp) 336 { 337 338 ++vp->v_usecount; 339 } 340 341 int 342 rump_vp_getref(struct vnode *vp) 343 { 344 345 return vp->v_usecount; 346 } 347 348 void 349 rump_vp_decref(struct vnode *vp) 350 { 351 352 --vp->v_usecount; 353 } 354 355 struct uio * 356 rump_uio_setup(void *buf, size_t bufsize, off_t offset, enum rump_uiorw rw) 357 { 358 struct uio *uio; 359 enum uio_rw uiorw; 360 361 switch (rw) { 362 case RUMPUIO_READ: 363 uiorw = UIO_READ; 364 break; 365 case RUMPUIO_WRITE: 366 uiorw = UIO_WRITE; 367 break; 368 default: 369 panic("%s: invalid rw %d", __func__, rw); 370 } 371 372 uio = rumpuser_malloc(sizeof(struct uio), 0); 373 uio->uio_iov = rumpuser_malloc(sizeof(struct iovec), 0); 374 375 uio->uio_iov->iov_base = buf; 376 uio->uio_iov->iov_len = bufsize; 377 378 uio->uio_iovcnt = 1; 379 uio->uio_offset = offset; 380 uio->uio_resid = bufsize; 381 uio->uio_rw = uiorw; 382 uio->uio_vmspace = UIO_VMSPACE_SYS; 383 384 return uio; 385 } 386 387 size_t 388 rump_uio_getresid(struct uio *uio) 389 { 390 391 return uio->uio_resid; 392 } 393 394 off_t 395 rump_uio_getoff(struct uio *uio) 396 { 397 398 return uio->uio_offset; 399 } 400 401 size_t 402 rump_uio_free(struct uio *uio) 403 { 404 size_t resid; 405 406 resid = uio->uio_resid; 407 rumpuser_free(uio->uio_iov); 408 rumpuser_free(uio); 409 410 return resid; 411 } 412 413 void 414 rump_vp_lock_exclusive(struct vnode *vp) 415 { 416 417 /* we can skip vn_lock() */ 418 VOP_LOCK(vp, LK_EXCLUSIVE); 419 } 420 421 void 422 rump_vp_lock_shared(struct vnode *vp) 423 { 424 425 VOP_LOCK(vp, LK_SHARED); 426 } 427 428 void 429 rump_vp_unlock(struct vnode *vp) 430 { 431 432 VOP_UNLOCK(vp, 0); 433 } 434 435 int 436 rump_vp_islocked(struct vnode *vp) 437 { 438 439 return VOP_ISLOCKED(vp); 440 } 441 442 int 443 rump_vfs_unmount(struct mount *mp, int mntflags) 444 { 445 446 return VFS_UNMOUNT(mp, mntflags); 447 } 448 449 int 450 rump_vfs_root(struct mount *mp, struct vnode **vpp, int lock) 451 { 452 int rv; 453 454 rv = VFS_ROOT(mp, vpp); 455 if (rv) 456 return rv; 457 458 if (!lock) 459 VOP_UNLOCK(*vpp, 0); 460 461 return 0; 462 } 463 464 /* XXX: statvfs is different from system to system */ 465 #if 0 466 int 467 rump_vfs_statvfs(struct mount *mp, struct statvfs *sbp) 468 { 469 470 return VFS_STATVFS(mp, sbp); 471 } 472 #endif 473 474 int 475 rump_vfs_sync(struct mount *mp, int wait, kauth_cred_t cred) 476 { 477 478 return VFS_SYNC(mp, wait ? MNT_WAIT : MNT_NOWAIT, cred); 479 } 480 481 int 482 rump_vfs_fhtovp(struct mount *mp, struct fid *fid, struct vnode **vpp) 483 { 484 485 return VFS_FHTOVP(mp, fid, vpp); 486 } 487 488 int 489 rump_vfs_vptofh(struct vnode *vp, struct fid *fid, size_t *fidsize) 490 { 491 492 return VFS_VPTOFH(vp, fid, fidsize); 493 } 494 495 /*ARGSUSED*/ 496 void 497 rump_vfs_syncwait(struct mount *mp) 498 { 499 int n; 500 501 n = buf_syncwait(); 502 if (n) 503 printf("syncwait: unsynced buffers: %d\n", n); 504 } 505 506 void 507 rump_bioops_sync() 508 { 509 510 if (bioopsp) 511 bioopsp->io_sync(NULL); 512 } 513 514 struct lwp * 515 rump_setup_curlwp(pid_t pid, lwpid_t lid, int set) 516 { 517 struct lwp *l; 518 struct proc *p; 519 520 l = kmem_alloc(sizeof(struct lwp), KM_SLEEP); 521 p = kmem_alloc(sizeof(struct proc), KM_SLEEP); 522 p->p_stats = &rump_stats; 523 p->p_cwdi = &rump_cwdi; 524 p->p_limit = &rump_limits; 525 p->p_pid = pid; 526 l->l_cred = rump_cred; 527 l->l_proc = p; 528 l->l_lid = lid; 529 530 if (set) 531 rumpuser_set_curlwp(l); 532 533 return l; 534 } 535 536 void 537 rump_clear_curlwp() 538 { 539 struct lwp *l; 540 541 l = rumpuser_get_curlwp(); 542 kmem_free(l->l_proc, sizeof(struct proc)); 543 kmem_free(l, sizeof(struct lwp)); 544 rumpuser_set_curlwp(NULL); 545 } 546 547 struct lwp * 548 rump_get_curlwp() 549 { 550 struct lwp *l; 551 552 l = rumpuser_get_curlwp(); 553 if (l == NULL) 554 l = &lwp0; 555 556 return l; 557 } 558 559 int 560 rump_splfoo() 561 { 562 563 if (rumpuser_whatis_ipl() != RUMPUSER_IPL_INTR) { 564 rumpuser_rw_enter(&rumpspl, 0); 565 rumpuser_set_ipl(RUMPUSER_IPL_SPLFOO); 566 } 567 568 return 0; 569 } 570 571 static void 572 rump_intr_enter(void) 573 { 574 575 rumpuser_set_ipl(RUMPUSER_IPL_INTR); 576 rumpuser_rw_enter(&rumpspl, 1); 577 } 578 579 static void 580 rump_intr_exit(void) 581 { 582 583 rumpuser_rw_exit(&rumpspl); 584 rumpuser_clear_ipl(RUMPUSER_IPL_INTR); 585 } 586 587 void 588 rump_splx(int dummy) 589 { 590 591 if (rumpuser_whatis_ipl() != RUMPUSER_IPL_INTR) { 592 rumpuser_clear_ipl(RUMPUSER_IPL_SPLFOO); 593 rumpuser_rw_exit(&rumpspl); 594 } 595 } 596 597 void 598 rump_biodone(void *arg, size_t count, int error) 599 { 600 struct buf *bp = arg; 601 602 bp->b_resid = bp->b_bcount - count; 603 KASSERT(bp->b_resid >= 0); 604 bp->b_error = error; 605 606 rump_intr_enter(); 607 biodone(bp); 608 rump_intr_exit(); 609 } 610