Home | History | Annotate | Line # | Download | only in rumpvfs
rumpfs.c revision 1.26
      1 /*	$NetBSD: rumpfs.c,v 1.26 2009/10/11 17:54:22 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/cdefs.h>
     31 __KERNEL_RCSID(0, "$NetBSD: rumpfs.c,v 1.26 2009/10/11 17:54:22 pooka Exp $");
     32 
     33 #include <sys/param.h>
     34 #include <sys/atomic.h>
     35 #include <sys/filedesc.h>
     36 #include <sys/errno.h>
     37 #include <sys/fcntl.h>
     38 #include <sys/kauth.h>
     39 #include <sys/malloc.h>
     40 #include <sys/mount.h>
     41 #include <sys/namei.h>
     42 #include <sys/lock.h>
     43 #include <sys/lockf.h>
     44 #include <sys/queue.h>
     45 #include <sys/stat.h>
     46 #include <sys/syscallargs.h>
     47 #include <sys/vnode.h>
     48 
     49 #include <miscfs/fifofs/fifo.h>
     50 #include <miscfs/specfs/specdev.h>
     51 #include <miscfs/genfs/genfs.h>
     52 
     53 #include <rump/rumpuser.h>
     54 
     55 #include "rump_private.h"
     56 #include "rump_vfs_private.h"
     57 
     58 static int rump_vop_lookup(void *);
     59 static int rump_vop_getattr(void *);
     60 static int rump_vop_mkdir(void *);
     61 static int rump_vop_mknod(void *);
     62 static int rump_vop_create(void *);
     63 static int rump_vop_inactive(void *);
     64 static int rump_vop_reclaim(void *);
     65 static int rump_vop_success(void *);
     66 static int rump_vop_spec(void *);
     67 static int rump_vop_read(void *);
     68 static int rump_vop_write(void *);
     69 static int rump_vop_open(void *);
     70 
     71 int (**fifo_vnodeop_p)(void *);
     72 const struct vnodeopv_entry_desc fifo_vnodeop_entries[] = {
     73 	{ &vop_default_desc, vn_default_error },
     74 	{ NULL, NULL }
     75 };
     76 const struct vnodeopv_desc fifo_vnodeop_opv_desc =
     77 	{ &fifo_vnodeop_p, fifo_vnodeop_entries };
     78 
     79 int (**rump_vnodeop_p)(void *);
     80 const struct vnodeopv_entry_desc rump_vnodeop_entries[] = {
     81 	{ &vop_default_desc, vn_default_error },
     82 	{ &vop_lookup_desc, rump_vop_lookup },
     83 	{ &vop_getattr_desc, rump_vop_getattr },
     84 	{ &vop_mkdir_desc, rump_vop_mkdir },
     85 	{ &vop_mknod_desc, rump_vop_mknod },
     86 	{ &vop_create_desc, rump_vop_create },
     87 	{ &vop_access_desc, rump_vop_success },
     88 	{ &vop_read_desc, rump_vop_read },
     89 	{ &vop_write_desc, rump_vop_write },
     90 	{ &vop_open_desc, rump_vop_open },
     91 	{ &vop_putpages_desc, genfs_null_putpages },
     92 	{ &vop_fsync_desc, rump_vop_success },
     93 	{ &vop_lock_desc, genfs_lock },
     94 	{ &vop_unlock_desc, genfs_unlock },
     95 	{ &vop_inactive_desc, rump_vop_inactive },
     96 	{ &vop_reclaim_desc, rump_vop_reclaim },
     97 	{ NULL, NULL }
     98 };
     99 const struct vnodeopv_desc rump_vnodeop_opv_desc =
    100 	{ &rump_vnodeop_p, rump_vnodeop_entries };
    101 
    102 int (**rump_specop_p)(void *);
    103 const struct vnodeopv_entry_desc rump_specop_entries[] = {
    104 	{ &vop_default_desc, rump_vop_spec },
    105 	{ NULL, NULL }
    106 };
    107 const struct vnodeopv_desc rump_specop_opv_desc =
    108 	{ &rump_specop_p, rump_specop_entries };
    109 
    110 const struct vnodeopv_desc * const rump_opv_descs[] = {
    111 	&rump_vnodeop_opv_desc,
    112 	&rump_specop_opv_desc,
    113 	NULL
    114 };
    115 
    116 struct rumpfs_dent {
    117 	char *rd_name;
    118 	struct rumpfs_node *rd_node;
    119 
    120 	LIST_ENTRY(rumpfs_dent) rd_entries;
    121 };
    122 
    123 struct rumpfs_node {
    124 	struct vattr rn_va;
    125 	struct vnode *rn_vp;
    126 
    127 	union {
    128 		struct {
    129 			char *hostpath;		/* VREG */
    130 			int readfd;
    131 			int writefd;
    132 		} reg;
    133 		LIST_HEAD(, rumpfs_dent) dir;	/* VDIR */
    134 	} rn_u;
    135 };
    136 #define rn_hostpath	rn_u.reg.hostpath
    137 #define rn_readfd	rn_u.reg.readfd
    138 #define rn_writefd	rn_u.reg.writefd
    139 #define rn_dir		rn_u.dir
    140 
    141 static struct rumpfs_node *makeprivate(enum vtype, dev_t, off_t, const char *);
    142 
    143 /*
    144  * Extra Terrestrial stuff.  We map a given key (pathname) to a file on
    145  * the host FS.  ET phones home only from the root node of rumpfs.
    146  *
    147  * When an etfs node is removed, a vnode potentially behind it is not
    148  * immediately recycled.
    149  */
    150 
    151 struct etfs {
    152 	char et_key[MAXPATHLEN];
    153 	size_t et_keylen;
    154 
    155 	LIST_ENTRY(etfs) et_entries;
    156 
    157 	struct rumpfs_node *et_rn;
    158 };
    159 static kmutex_t etfs_lock;
    160 static LIST_HEAD(, etfs) etfs_list = LIST_HEAD_INITIALIZER(etfs_list);
    161 
    162 static enum vtype
    163 ettype_to_vtype(enum rump_etfs_type et)
    164 {
    165 	enum vtype vt;
    166 
    167 	switch (et) {
    168 	case RUMP_ETFS_REG:
    169 		vt = VREG;
    170 		break;
    171 	case RUMP_ETFS_BLK:
    172 		vt = VBLK;
    173 		break;
    174 	case RUMP_ETFS_CHR:
    175 		vt = VCHR;
    176 		break;
    177 	default:
    178 		panic("invalid et type: %d", et);
    179 	}
    180 
    181 	return vt;
    182 }
    183 
    184 static bool
    185 etfs_find(const char *key, struct rumpfs_node **rnp)
    186 {
    187 	struct etfs *et;
    188 	size_t keylen = strlen(key);
    189 	bool rv = false;
    190 
    191 	KASSERT(mutex_owned(&etfs_lock));
    192 
    193 	LIST_FOREACH(et, &etfs_list, et_entries) {
    194 		if (keylen == et->et_keylen && strcmp(key, et->et_key) == 0) {
    195 			*rnp = et->et_rn;
    196 			rv = true;
    197 			break;
    198 		}
    199 	}
    200 
    201 	return rv;
    202 }
    203 
    204 static int
    205 doregister(const char *key, const char *hostpath,
    206 	enum rump_etfs_type ftype, uint64_t begin, uint64_t size)
    207 {
    208 	struct etfs *et;
    209 	struct rumpfs_node *rn_dummy;
    210 	uint64_t fsize;
    211 	dev_t rdev = NODEV;
    212 	devminor_t dmin;
    213 	int hft, error;
    214 
    215 	if (rumpuser_getfileinfo(hostpath, &fsize, &hft, &error))
    216 		return error;
    217 
    218 	/* check that we give sensible arguments */
    219 	if (begin > fsize)
    220 		return EINVAL;
    221 	if (size == RUMP_ETFS_SIZE_ENDOFF)
    222 		size = fsize - begin;
    223 	if (begin + size > fsize)
    224 		return EINVAL;
    225 
    226 	if (ftype == RUMP_ETFS_BLK || ftype == RUMP_ETFS_CHR) {
    227 		error = rumpblk_register(hostpath, &dmin, begin, size);
    228 		if (error != 0) {
    229 			return error;
    230 		}
    231 		rdev = makedev(RUMPBLK, dmin);
    232 	}
    233 
    234 	et = kmem_alloc(sizeof(*et), KM_SLEEP);
    235 	strcpy(et->et_key, key);
    236 	et->et_keylen = strlen(et->et_key);
    237 	et->et_rn = makeprivate(ettype_to_vtype(ftype), rdev, size, hostpath);
    238 
    239 	mutex_enter(&etfs_lock);
    240 	if (etfs_find(key, &rn_dummy)) {
    241 		mutex_exit(&etfs_lock);
    242 		kmem_free(et, sizeof(*et));
    243 		/* XXX: rumpblk_deregister(hostpath); */
    244 		return EEXIST;
    245 	}
    246 	LIST_INSERT_HEAD(&etfs_list, et, et_entries);
    247 	mutex_exit(&etfs_lock);
    248 
    249 	return 0;
    250 }
    251 
    252 int
    253 rump_etfs_register(const char *key, const char *hostpath,
    254 	enum rump_etfs_type ftype)
    255 {
    256 
    257 	return doregister(key, hostpath, ftype, 0, RUMP_ETFS_SIZE_ENDOFF);
    258 }
    259 
    260 int
    261 rump_etfs_register_withsize(const char *key, const char *hostpath,
    262 	enum rump_etfs_type ftype, uint64_t begin, uint64_t size)
    263 {
    264 
    265 	/*
    266 	 * Check that we're mapping at block offsets.  I guess this
    267 	 * is not technically necessary except for BLK/CHR backends
    268 	 * (i.e. what getfileinfo() returns, not ftype) and can be
    269 	 * removed later if there are problems.
    270 	 */
    271 	if ((begin & (DEV_BSIZE-1)) != 0)
    272 		return EINVAL;
    273 	if (size != RUMP_ETFS_SIZE_ENDOFF && (size & (DEV_BSIZE-1)) != 0)
    274 		return EINVAL;
    275 
    276 	return doregister(key, hostpath, ftype, begin, size);
    277 }
    278 
    279 int
    280 rump_etfs_remove(const char *key)
    281 {
    282 	struct etfs *et;
    283 	size_t keylen = strlen(key);
    284 
    285 	mutex_enter(&etfs_lock);
    286 	LIST_FOREACH(et, &etfs_list, et_entries) {
    287 		if (keylen == et->et_keylen && strcmp(et->et_key, key) == 0) {
    288 			LIST_REMOVE(et, et_entries);
    289 			kmem_free(et, sizeof(*et));
    290 			break;
    291 		}
    292 	}
    293 	mutex_exit(&etfs_lock);
    294 
    295 	if (!et)
    296 		return ENOENT;
    297 	return 0;
    298 }
    299 
    300 /*
    301  * rumpfs
    302  */
    303 
    304 static struct mount rump_mnt;
    305 static int lastino = 1;
    306 static kmutex_t reclock;
    307 
    308 static struct rumpfs_node *
    309 makeprivate(enum vtype vt, dev_t rdev, off_t size, const char *hostpath)
    310 {
    311 	struct rumpfs_node *rn;
    312 	struct vattr *va;
    313 	struct timespec ts;
    314 
    315 	rn = kmem_zalloc(sizeof(*rn), KM_SLEEP);
    316 
    317 	switch (vt) {
    318 	case VDIR:
    319 		LIST_INIT(&rn->rn_dir);
    320 		break;
    321 	case VREG:
    322 		rn->rn_readfd = -1;
    323 		rn->rn_writefd = -1;
    324 		rn->rn_hostpath = malloc(strlen(hostpath)+1, M_TEMP, M_WAITOK);
    325 		strcpy(rn->rn_hostpath, hostpath);
    326 		break;
    327 	default:
    328 		break;
    329 	}
    330 
    331 	nanotime(&ts);
    332 
    333 	va = &rn->rn_va;
    334 	va->va_type = vt;
    335 	va->va_mode = 0755;
    336 	if (vt == VDIR)
    337 		va->va_nlink = 2;
    338 	else
    339 		va->va_nlink = 1;
    340 	va->va_uid = 0;
    341 	va->va_gid = 0;
    342 	va->va_fsid =
    343 	va->va_fileid = atomic_inc_uint_nv(&lastino);
    344 	va->va_size = size;
    345 	va->va_blocksize = 512;
    346 	va->va_atime = ts;
    347 	va->va_mtime = ts;
    348 	va->va_ctime = ts;
    349 	va->va_birthtime = ts;
    350 	va->va_gen = 0;
    351 	va->va_flags = 0;
    352 	va->va_rdev = rdev;
    353 	va->va_bytes = 512;
    354 	va->va_filerev = 0;
    355 	va->va_vaflags = 0;
    356 
    357 	return rn;
    358 }
    359 
    360 static int
    361 makevnode(struct rumpfs_node *rn, struct vnode **vpp)
    362 {
    363 	struct vnode *vp;
    364 	int (**vpops)(void *);
    365 	struct vattr *va = &rn->rn_va;
    366 	int rv;
    367 
    368 	KASSERT(mutex_owned(&reclock));
    369 
    370 	if (va->va_type == VCHR || va->va_type == VBLK) {
    371 		vpops = rump_specop_p;
    372 	} else {
    373 		vpops = rump_vnodeop_p;
    374 	}
    375 	if (vpops != rump_specop_p && va->va_type != VDIR
    376 	    && !(va->va_type == VREG && rn->rn_hostpath != NULL)
    377 	    && va->va_type != VSOCK)
    378 		return EOPNOTSUPP;
    379 
    380 	rv = getnewvnode(VT_RUMP, &rump_mnt, vpops, &vp);
    381 	if (rv)
    382 		return rv;
    383 
    384 	vp->v_size = vp->v_writesize = va->va_size;
    385 	vp->v_type = va->va_type;
    386 
    387 	if (vpops == rump_specop_p) {
    388 		spec_node_init(vp, va->va_rdev);
    389 	}
    390 	vp->v_data = rn;
    391 
    392 	vn_lock(vp, LK_RETRY | LK_EXCLUSIVE);
    393 	rn->rn_vp = vp;
    394 	*vpp = vp;
    395 
    396 	return 0;
    397 }
    398 
    399 /*
    400  * Simple lookup for faking lookup of device entry for rump file systems
    401  * and for locating/creating directories.  Yes, this will panic if you
    402  * call it with the wrong arguments.
    403  *
    404  * uhm, this is twisted.  C F C C, hope of C C F C looming
    405  */
    406 static int
    407 rump_vop_lookup(void *v)
    408 {
    409 	struct vop_lookup_args /* {
    410 		struct vnode *a_dvp;
    411 		struct vnode **a_vpp;
    412 		struct componentname *a_cnp;
    413 	}; */ *ap = v;
    414 	struct componentname *cnp = ap->a_cnp;
    415 	struct vnode *dvp = ap->a_dvp;
    416 	struct vnode **vpp = ap->a_vpp;
    417 	struct vnode *vp;
    418 	struct rumpfs_node *rnd = dvp->v_data, *rn;
    419 	struct rumpfs_dent *rd = NULL;
    420 	int rv;
    421 
    422 	/* we handle only some "non-special" cases */
    423 	if (!(((cnp->cn_flags & ISLASTCN) == 0)
    424 	    || (cnp->cn_nameiop == LOOKUP || cnp->cn_nameiop == CREATE)))
    425 		return EOPNOTSUPP;
    426 	if (!((cnp->cn_flags & ISDOTDOT) == 0))
    427 		return EOPNOTSUPP;
    428 	if (!(cnp->cn_namelen != 0 && cnp->cn_pnbuf[0] != '.'))
    429 		return EOPNOTSUPP;
    430 
    431 	/* check if we are returning a faked block device */
    432 	if (dvp == rootvnode && cnp->cn_nameiop == LOOKUP) {
    433 		mutex_enter(&etfs_lock);
    434 		if (etfs_find(cnp->cn_pnbuf, &rn)) {
    435 			mutex_exit(&etfs_lock);
    436 			cnp->cn_consume = strlen(cnp->cn_nameptr
    437 			    + cnp->cn_namelen);
    438 			cnp->cn_flags &= ~REQUIREDIR;
    439 			goto getvnode;
    440 		}
    441 		mutex_exit(&etfs_lock);
    442 	}
    443 
    444 	if (!rd) {
    445 		LIST_FOREACH(rd, &rnd->rn_dir, rd_entries) {
    446 			if (strncmp(rd->rd_name, cnp->cn_nameptr,
    447 			    cnp->cn_namelen) == 0)
    448 				break;
    449 		}
    450 	}
    451 
    452 	if (!rd && ((cnp->cn_flags & ISLASTCN) == 0||cnp->cn_nameiop != CREATE))
    453 		return ENOENT;
    454 
    455 	if (!rd && (cnp->cn_flags & ISLASTCN) && cnp->cn_nameiop == CREATE) {
    456 		cnp->cn_flags |= SAVENAME;
    457 		return EJUSTRETURN;
    458 	}
    459 	rn = rd->rd_node;
    460 	rd = NULL;
    461 
    462  getvnode:
    463 	KASSERT(rn);
    464 	mutex_enter(&reclock);
    465 	if ((vp = rn->rn_vp)) {
    466 		mutex_enter(&vp->v_interlock);
    467 		mutex_exit(&reclock);
    468 		if (vget(vp, LK_EXCLUSIVE | LK_INTERLOCK))
    469 			goto getvnode;
    470 		*vpp = vp;
    471 	} else {
    472 		rv = makevnode(rn, vpp);
    473 		rn->rn_vp = *vpp;
    474 		mutex_exit(&reclock);
    475 		if (rv)
    476 			return rv;
    477 	}
    478 
    479 	return 0;
    480 }
    481 
    482 static int
    483 rump_vop_getattr(void *v)
    484 {
    485 	struct vop_getattr_args /* {
    486 		struct vnode *a_vp;
    487 		struct vattr *a_vap;
    488 		kauth_cred_t a_cred;
    489 	} */ *ap = v;
    490 	struct rumpfs_node *rn = ap->a_vp->v_data;
    491 
    492 	memcpy(ap->a_vap, &rn->rn_va, sizeof(struct vattr));
    493 	return 0;
    494 }
    495 
    496 static int
    497 rump_vop_mkdir(void *v)
    498 {
    499 	struct vop_mkdir_args /* {
    500 		struct vnode *a_dvp;
    501 		struct vnode **a_vpp;
    502 		struct componentname *a_cnp;
    503 		struct vattr *a_vap;
    504 	}; */ *ap = v;
    505 	struct vnode *dvp = ap->a_dvp;
    506 	struct vnode **vpp = ap->a_vpp;
    507 	struct componentname *cnp = ap->a_cnp;
    508 	struct rumpfs_node *rnd = dvp->v_data, *rn;
    509 	struct rumpfs_dent *rdent;
    510 	int rv = 0;
    511 
    512 	rn = makeprivate(VDIR, NODEV, DEV_BSIZE, NULL);
    513 	mutex_enter(&reclock);
    514 	rv = makevnode(rn, vpp);
    515 	mutex_exit(&reclock);
    516 	if (rv)
    517 		goto out;
    518 
    519 	rdent = kmem_alloc(sizeof(*rdent), KM_SLEEP);
    520 	rdent->rd_name = kmem_alloc(cnp->cn_namelen+1, KM_SLEEP);
    521 	rdent->rd_node = (*vpp)->v_data;
    522 	strlcpy(rdent->rd_name, cnp->cn_nameptr, cnp->cn_namelen+1);
    523 
    524 	LIST_INSERT_HEAD(&rnd->rn_dir, rdent, rd_entries);
    525 
    526  out:
    527 	vput(dvp);
    528 	return rv;
    529 }
    530 
    531 static int
    532 rump_vop_mknod(void *v)
    533 {
    534 	struct vop_mknod_args /* {
    535 		struct vnode *a_dvp;
    536 		struct vnode **a_vpp;
    537 		struct componentname *a_cnp;
    538 		struct vattr *a_vap;
    539 	}; */ *ap = v;
    540 	struct vnode *dvp = ap->a_dvp;
    541 	struct vnode **vpp = ap->a_vpp;
    542 	struct componentname *cnp = ap->a_cnp;
    543 	struct vattr *va = ap->a_vap;
    544 	struct rumpfs_node *rnd = dvp->v_data, *rn;
    545 	struct rumpfs_dent *rdent;
    546 	int rv;
    547 
    548 	rn = makeprivate(va->va_type, va->va_rdev, DEV_BSIZE, NULL);
    549 	mutex_enter(&reclock);
    550 	rv = makevnode(rn, vpp);
    551 	mutex_exit(&reclock);
    552 	if (rv)
    553 		goto out;
    554 
    555 	rdent = kmem_alloc(sizeof(*rdent), KM_SLEEP);
    556 	rdent->rd_name = kmem_alloc(cnp->cn_namelen+1, KM_SLEEP);
    557 	rdent->rd_node = (*vpp)->v_data;
    558 	rdent->rd_node->rn_va.va_rdev = va->va_rdev;
    559 	strlcpy(rdent->rd_name, cnp->cn_nameptr, cnp->cn_namelen+1);
    560 
    561 	LIST_INSERT_HEAD(&rnd->rn_dir, rdent, rd_entries);
    562 
    563  out:
    564 	vput(dvp);
    565 	return rv;
    566 }
    567 
    568 static int
    569 rump_vop_create(void *v)
    570 {
    571 	struct vop_create_args /* {
    572 		struct vnode *a_dvp;
    573 		struct vnode **a_vpp;
    574 		struct componentname *a_cnp;
    575 		struct vattr *a_vap;
    576 	}; */ *ap = v;
    577 	struct vnode *dvp = ap->a_dvp;
    578 	struct vnode **vpp = ap->a_vpp;
    579 	struct componentname *cnp = ap->a_cnp;
    580 	struct vattr *va = ap->a_vap;
    581 	struct rumpfs_node *rnd = dvp->v_data, *rn;
    582 	struct rumpfs_dent *rdent;
    583 	int rv;
    584 
    585 	if (va->va_type != VSOCK) {
    586 		rv = EOPNOTSUPP;
    587 		goto out;
    588 	}
    589 	rn = makeprivate(VSOCK, NODEV, DEV_BSIZE, NULL);
    590 	mutex_enter(&reclock);
    591 	rv = makevnode(rn, vpp);
    592 	mutex_exit(&reclock);
    593 	if (rv)
    594 		goto out;
    595 
    596 	rdent = kmem_alloc(sizeof(*rdent), KM_SLEEP);
    597 	rdent->rd_name = kmem_alloc(cnp->cn_namelen+1, KM_SLEEP);
    598 	rdent->rd_node = (*vpp)->v_data;
    599 	rdent->rd_node->rn_va.va_rdev = NODEV;
    600 	strlcpy(rdent->rd_name, cnp->cn_nameptr, cnp->cn_namelen+1);
    601 
    602 	LIST_INSERT_HEAD(&rnd->rn_dir, rdent, rd_entries);
    603 
    604  out:
    605 	vput(dvp);
    606 	return rv;
    607 }
    608 
    609 static int
    610 rump_vop_open(void *v)
    611 {
    612 	struct vop_open_args /* {
    613 		struct vnode *a_vp;
    614 		int a_mode;
    615 		kauth_cred_t a_cred;
    616 	} */ *ap = v;
    617 	struct vnode *vp = ap->a_vp;
    618 	struct rumpfs_node *rn = vp->v_data;
    619 	int mode = ap->a_mode;
    620 	int error = EINVAL;
    621 
    622 	if (vp->v_type != VREG)
    623 		return 0;
    624 
    625 	if (mode & FREAD) {
    626 		if (rn->rn_readfd != -1)
    627 			return 0;
    628 		rn->rn_readfd = rumpuser_open(rn->rn_hostpath,
    629 		    O_RDONLY, &error);
    630 	} else if (mode & FWRITE) {
    631 		if (rn->rn_writefd != -1)
    632 			return 0;
    633 		rn->rn_writefd = rumpuser_open(rn->rn_hostpath,
    634 		    O_WRONLY, &error);
    635 	}
    636 
    637 	return error;
    638 }
    639 
    640 static int
    641 rump_vop_read(void *v)
    642 {
    643 	struct vop_read_args /* {
    644 		struct vnode *a_vp;
    645 		struct uio *a_uio;
    646 		int ioflags a_ioflag;
    647 		kauth_cred_t a_cred;
    648 	}; */ *ap = v;
    649 	struct vnode *vp = ap->a_vp;
    650 	struct rumpfs_node *rn = vp->v_data;
    651 	struct uio *uio = ap->a_uio;
    652 	uint8_t *buf;
    653 	size_t bufsize;
    654 	int error = 0;
    655 
    656 	bufsize = uio->uio_resid;
    657 	buf = kmem_alloc(bufsize, KM_SLEEP);
    658 	if (rumpuser_read(rn->rn_readfd, buf, bufsize, &error) == -1)
    659 		goto out;
    660 	error = uiomove(buf, bufsize, uio);
    661 
    662  out:
    663 	kmem_free(buf, bufsize);
    664 	return error;
    665 }
    666 
    667 static int
    668 rump_vop_write(void *v)
    669 {
    670 	struct vop_read_args /* {
    671 		struct vnode *a_vp;
    672 		struct uio *a_uio;
    673 		int ioflags a_ioflag;
    674 		kauth_cred_t a_cred;
    675 	}; */ *ap = v;
    676 	struct vnode *vp = ap->a_vp;
    677 	struct rumpfs_node *rn = vp->v_data;
    678 	struct uio *uio = ap->a_uio;
    679 	uint8_t *buf;
    680 	size_t bufsize;
    681 	int error = 0;
    682 
    683 	bufsize = uio->uio_resid;
    684 	buf = kmem_alloc(bufsize, KM_SLEEP);
    685 	error = uiomove(buf, bufsize, uio);
    686 	if (error)
    687 		goto out;
    688 	KASSERT(uio->uio_resid == 0);
    689 	rumpuser_write(rn->rn_writefd, buf, bufsize, &error);
    690 
    691  out:
    692 	kmem_free(buf, bufsize);
    693 	return error;
    694 }
    695 
    696 static int
    697 rump_vop_success(void *v)
    698 {
    699 
    700 	return 0;
    701 }
    702 
    703 static int
    704 rump_vop_inactive(void *v)
    705 {
    706 	struct vop_inactive_args *ap = v;
    707 	struct vnode *vp = ap->a_vp;
    708 	struct rumpfs_node *rn = vp->v_data;
    709 	int error;
    710 
    711 	if (vp->v_type == VREG) {
    712 		if (rn->rn_readfd != -1) {
    713 			rumpuser_close(rn->rn_readfd, &error);
    714 			rn->rn_readfd = -1;
    715 		}
    716 		if (rn->rn_writefd != -1) {
    717 			rumpuser_close(rn->rn_writefd, &error);
    718 			rn->rn_writefd = -1;
    719 		}
    720 	}
    721 
    722 	VOP_UNLOCK(vp, 0);
    723 	return 0;
    724 }
    725 
    726 static int
    727 rump_vop_reclaim(void *v)
    728 {
    729 	struct vop_reclaim_args /* {
    730 		struct vnode *a_vp;
    731 	} */ *ap = v;
    732 	struct vnode *vp = ap->a_vp;
    733 	struct rumpfs_node *rn = vp->v_data;
    734 
    735 	mutex_enter(&reclock);
    736 	rn->rn_vp = NULL;
    737 	mutex_exit(&reclock);
    738 	vp->v_data = NULL;
    739 
    740 	return 0;
    741 }
    742 
    743 static int
    744 rump_vop_spec(void *v)
    745 {
    746 	struct vop_generic_args *ap = v;
    747 	int (**opvec)(void *);
    748 
    749 	switch (ap->a_desc->vdesc_offset) {
    750 	case VOP_ACCESS_DESCOFFSET:
    751 	case VOP_GETATTR_DESCOFFSET:
    752 	case VOP_LOCK_DESCOFFSET:
    753 	case VOP_UNLOCK_DESCOFFSET:
    754 		opvec = rump_vnodeop_p;
    755 		break;
    756 	default:
    757 		opvec = spec_vnodeop_p;
    758 		break;
    759 	}
    760 
    761 	return VOCALL(opvec, ap->a_desc->vdesc_offset, v);
    762 }
    763 
    764 void
    765 rumpfs_init(void)
    766 {
    767 	struct rumpfs_node *rn;
    768 	int rv;
    769 
    770 	CTASSERT(RUMP_ETFS_SIZE_ENDOFF == RUMPBLK_SIZENOTSET);
    771 
    772 	mutex_init(&reclock, MUTEX_DEFAULT, IPL_NONE);
    773 	mutex_init(&etfs_lock, MUTEX_DEFAULT, IPL_NONE);
    774 
    775 	/* XXX: init properly instead of this crap */
    776 	rump_mnt.mnt_refcnt = 1;
    777 	rump_mnt.mnt_flag = MNT_ROOTFS;
    778 	rw_init(&rump_mnt.mnt_unmounting);
    779 	TAILQ_INIT(&rump_mnt.mnt_vnodelist);
    780 
    781 	vfs_opv_init(rump_opv_descs);
    782 	rn = makeprivate(VDIR, NODEV, DEV_BSIZE, NULL);
    783 	mutex_enter(&reclock);
    784 	rv = makevnode(rn, &rootvnode);
    785 	mutex_exit(&reclock);
    786 	if (rv)
    787 		panic("could not create root vnode: %d", rv);
    788 	rootvnode->v_vflag |= VV_ROOT;
    789 	VOP_UNLOCK(rootvnode, 0);
    790 }
    791