Home | History | Annotate | Line # | Download | only in rumpkern
rump.c revision 1.22
      1 /*	$NetBSD: rump.c,v 1.22 2007/11/26 19:02:23 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 	cnp->cn_lwp = l;
    180 
    181 	return cnp;
    182 }
    183 
    184 void
    185 rump_freecn(struct componentname *cnp, int flags)
    186 {
    187 
    188 	if (flags & RUMPCN_FREECRED)
    189 		rump_cred_destroy(cnp->cn_cred);
    190 
    191 	if (cnp->cn_flags & SAVENAME) {
    192 		if (flags & RUMPCN_ISLOOKUP || cnp->cn_flags & SAVESTART)
    193 			PNBUF_PUT(cnp->cn_pnbuf);
    194 	} else {
    195 		PNBUF_PUT(cnp->cn_pnbuf);
    196 	}
    197 	rumpuser_free(cnp);
    198 }
    199 
    200 int
    201 rump_recyclenode(struct vnode *vp)
    202 {
    203 
    204 	return vrecycle(vp, NULL, curlwp);
    205 }
    206 
    207 static struct fakeblk *
    208 _rump_fakeblk_find(const char *path)
    209 {
    210 	char buf[MAXPATHLEN];
    211 	struct fakeblk *fblk;
    212 	int error;
    213 
    214 	if (rumpuser_realpath(path, buf, &error) == NULL)
    215 		return NULL;
    216 
    217 	LIST_FOREACH(fblk, &fakeblks, entries)
    218 		if (strcmp(fblk->path, buf) == 0)
    219 			return fblk;
    220 
    221 	return NULL;
    222 }
    223 
    224 int
    225 rump_fakeblk_register(const char *path)
    226 {
    227 	char buf[MAXPATHLEN];
    228 	struct fakeblk *fblk;
    229 	int error;
    230 
    231 	if (_rump_fakeblk_find(path))
    232 		return EEXIST;
    233 
    234 	if (rumpuser_realpath(path, buf, &error) == NULL)
    235 		return error;
    236 
    237 	fblk = rumpuser_malloc(sizeof(struct fakeblk), 1);
    238 	if (fblk == NULL)
    239 		return ENOMEM;
    240 
    241 	strlcpy(fblk->path, buf, MAXPATHLEN);
    242 	LIST_INSERT_HEAD(&fakeblks, fblk, entries);
    243 
    244 	return 0;
    245 }
    246 
    247 int
    248 rump_fakeblk_find(const char *path)
    249 {
    250 
    251 	return _rump_fakeblk_find(path) != NULL;
    252 }
    253 
    254 void
    255 rump_fakeblk_deregister(const char *path)
    256 {
    257 	struct fakeblk *fblk;
    258 
    259 	fblk = _rump_fakeblk_find(path);
    260 	if (fblk == NULL)
    261 		return;
    262 
    263 	LIST_REMOVE(fblk, entries);
    264 	rumpuser_free(fblk);
    265 }
    266 
    267 void
    268 rump_getvninfo(struct vnode *vp, enum vtype *vtype, voff_t *vsize, dev_t *vdev)
    269 {
    270 
    271 	*vtype = vp->v_type;
    272 	*vsize = vp->v_size;
    273 	if (vp->v_specinfo)
    274 		*vdev = vp->v_rdev;
    275 	else
    276 		*vdev = 0;
    277 }
    278 
    279 struct vfsops *
    280 rump_vfslist_iterate(struct vfsops *ops)
    281 {
    282 
    283 	if (ops == NULL)
    284 		return LIST_FIRST(&vfs_list);
    285 	else
    286 		return LIST_NEXT(ops, vfs_list);
    287 }
    288 
    289 struct vfsops *
    290 rump_vfs_getopsbyname(const char *name)
    291 {
    292 
    293 	return vfs_getopsbyname(name);
    294 }
    295 
    296 struct vattr*
    297 rump_vattr_init()
    298 {
    299 	struct vattr *vap;
    300 
    301 	vap = rumpuser_malloc(sizeof(struct vattr), 0);
    302 	vattr_null(vap);
    303 
    304 	return vap;
    305 }
    306 
    307 void
    308 rump_vattr_settype(struct vattr *vap, enum vtype vt)
    309 {
    310 
    311 	vap->va_type = vt;
    312 }
    313 
    314 void
    315 rump_vattr_setmode(struct vattr *vap, mode_t mode)
    316 {
    317 
    318 	vap->va_mode = mode;
    319 }
    320 
    321 void
    322 rump_vattr_setrdev(struct vattr *vap, dev_t dev)
    323 {
    324 
    325 	vap->va_rdev = dev;
    326 }
    327 
    328 void
    329 rump_vattr_free(struct vattr *vap)
    330 {
    331 
    332 	rumpuser_free(vap);
    333 }
    334 
    335 void
    336 rump_vp_incref(struct vnode *vp)
    337 {
    338 
    339 	++vp->v_usecount;
    340 }
    341 
    342 int
    343 rump_vp_getref(struct vnode *vp)
    344 {
    345 
    346 	return vp->v_usecount;
    347 }
    348 
    349 void
    350 rump_vp_decref(struct vnode *vp)
    351 {
    352 
    353 	--vp->v_usecount;
    354 }
    355 
    356 struct uio *
    357 rump_uio_setup(void *buf, size_t bufsize, off_t offset, enum rump_uiorw rw)
    358 {
    359 	struct uio *uio;
    360 	enum uio_rw uiorw;
    361 
    362 	switch (rw) {
    363 	case RUMPUIO_READ:
    364 		uiorw = UIO_READ;
    365 		break;
    366 	case RUMPUIO_WRITE:
    367 		uiorw = UIO_WRITE;
    368 		break;
    369 	default:
    370 		panic("%s: invalid rw %d", __func__, rw);
    371 	}
    372 
    373 	uio = rumpuser_malloc(sizeof(struct uio), 0);
    374 	uio->uio_iov = rumpuser_malloc(sizeof(struct iovec), 0);
    375 
    376 	uio->uio_iov->iov_base = buf;
    377 	uio->uio_iov->iov_len = bufsize;
    378 
    379 	uio->uio_iovcnt = 1;
    380 	uio->uio_offset = offset;
    381 	uio->uio_resid = bufsize;
    382 	uio->uio_rw = uiorw;
    383 	uio->uio_vmspace = UIO_VMSPACE_SYS;
    384 
    385 	return uio;
    386 }
    387 
    388 size_t
    389 rump_uio_getresid(struct uio *uio)
    390 {
    391 
    392 	return uio->uio_resid;
    393 }
    394 
    395 off_t
    396 rump_uio_getoff(struct uio *uio)
    397 {
    398 
    399 	return uio->uio_offset;
    400 }
    401 
    402 size_t
    403 rump_uio_free(struct uio *uio)
    404 {
    405 	size_t resid;
    406 
    407 	resid = uio->uio_resid;
    408 	rumpuser_free(uio->uio_iov);
    409 	rumpuser_free(uio);
    410 
    411 	return resid;
    412 }
    413 
    414 void
    415 rump_vp_lock_exclusive(struct vnode *vp)
    416 {
    417 
    418 	/* we can skip vn_lock() */
    419 	VOP_LOCK(vp, LK_EXCLUSIVE);
    420 }
    421 
    422 void
    423 rump_vp_lock_shared(struct vnode *vp)
    424 {
    425 
    426 	VOP_LOCK(vp, LK_SHARED);
    427 }
    428 
    429 void
    430 rump_vp_unlock(struct vnode *vp)
    431 {
    432 
    433 	VOP_UNLOCK(vp, 0);
    434 }
    435 
    436 int
    437 rump_vp_islocked(struct vnode *vp)
    438 {
    439 
    440 	return VOP_ISLOCKED(vp);
    441 }
    442 
    443 int
    444 rump_vfs_unmount(struct mount *mp, int mntflags)
    445 {
    446 
    447 	return VFS_UNMOUNT(mp, mntflags);
    448 }
    449 
    450 int
    451 rump_vfs_root(struct mount *mp, struct vnode **vpp, int lock)
    452 {
    453 	int rv;
    454 
    455 	rv = VFS_ROOT(mp, vpp);
    456 	if (rv)
    457 		return rv;
    458 
    459 	if (!lock)
    460 		VOP_UNLOCK(*vpp, 0);
    461 
    462 	return 0;
    463 }
    464 
    465 /* XXX: statvfs is different from system to system */
    466 #if 0
    467 int
    468 rump_vfs_statvfs(struct mount *mp, struct statvfs *sbp)
    469 {
    470 
    471 	return VFS_STATVFS(mp, sbp);
    472 }
    473 #endif
    474 
    475 int
    476 rump_vfs_sync(struct mount *mp, int wait, kauth_cred_t cred)
    477 {
    478 
    479 	return VFS_SYNC(mp, wait ? MNT_WAIT : MNT_NOWAIT, cred);
    480 }
    481 
    482 int
    483 rump_vfs_fhtovp(struct mount *mp, struct fid *fid, struct vnode **vpp)
    484 {
    485 
    486 	return VFS_FHTOVP(mp, fid, vpp);
    487 }
    488 
    489 int
    490 rump_vfs_vptofh(struct vnode *vp, struct fid *fid, size_t *fidsize)
    491 {
    492 
    493 	return VFS_VPTOFH(vp, fid, fidsize);
    494 }
    495 
    496 /*ARGSUSED*/
    497 void
    498 rump_vfs_syncwait(struct mount *mp)
    499 {
    500 	int n;
    501 
    502 	n = buf_syncwait();
    503 	if (n)
    504 		printf("syncwait: unsynced buffers: %d\n", n);
    505 }
    506 
    507 void
    508 rump_bioops_sync()
    509 {
    510 
    511 	if (bioopsp)
    512 		bioopsp->io_sync(NULL);
    513 }
    514 
    515 struct lwp *
    516 rump_setup_curlwp(pid_t pid, lwpid_t lid, int set)
    517 {
    518 	struct lwp *l;
    519 	struct proc *p;
    520 
    521 	l = kmem_alloc(sizeof(struct lwp), KM_SLEEP);
    522 	p = kmem_alloc(sizeof(struct proc), KM_SLEEP);
    523 	p->p_stats = &rump_stats;
    524 	p->p_cwdi = &rump_cwdi;
    525 	p->p_limit = &rump_limits;
    526         p->p_pid = pid;
    527 	l->l_cred = rump_cred;
    528 	l->l_proc = p;
    529         l->l_lid = lid;
    530 
    531 	if (set)
    532 		rumpuser_set_curlwp(l);
    533 
    534 	return l;
    535 }
    536 
    537 void
    538 rump_clear_curlwp()
    539 {
    540 	struct lwp *l;
    541 
    542 	l = rumpuser_get_curlwp();
    543 	kmem_free(l->l_proc, sizeof(struct proc));
    544 	kmem_free(l, sizeof(struct lwp));
    545 	rumpuser_set_curlwp(NULL);
    546 }
    547 
    548 struct lwp *
    549 rump_get_curlwp()
    550 {
    551 	struct lwp *l;
    552 
    553 	l = rumpuser_get_curlwp();
    554 	if (l == NULL)
    555 		l = &lwp0;
    556 
    557 	return l;
    558 }
    559 
    560 int
    561 rump_splfoo()
    562 {
    563 
    564 	if (rumpuser_whatis_ipl() != RUMPUSER_IPL_INTR) {
    565 		rumpuser_rw_enter(&rumpspl, 0);
    566 		rumpuser_set_ipl(RUMPUSER_IPL_SPLFOO);
    567 	}
    568 
    569 	return 0;
    570 }
    571 
    572 static void
    573 rump_intr_enter(void)
    574 {
    575 
    576 	rumpuser_set_ipl(RUMPUSER_IPL_INTR);
    577 	rumpuser_rw_enter(&rumpspl, 1);
    578 }
    579 
    580 static void
    581 rump_intr_exit(void)
    582 {
    583 
    584 	rumpuser_rw_exit(&rumpspl);
    585 	rumpuser_clear_ipl(RUMPUSER_IPL_INTR);
    586 }
    587 
    588 void
    589 rump_splx(int dummy)
    590 {
    591 
    592 	if (rumpuser_whatis_ipl() != RUMPUSER_IPL_INTR) {
    593 		rumpuser_clear_ipl(RUMPUSER_IPL_SPLFOO);
    594 		rumpuser_rw_exit(&rumpspl);
    595 	}
    596 }
    597 
    598 void
    599 rump_biodone(void *arg, size_t count, int error)
    600 {
    601 	struct buf *bp = arg;
    602 
    603 	bp->b_resid = bp->b_bcount - count;
    604 	KASSERT(bp->b_resid >= 0);
    605 	bp->b_error = error;
    606 
    607 	rump_intr_enter();
    608 	biodone(bp);
    609 	rump_intr_exit();
    610 }
    611