Home | History | Annotate | Line # | Download | only in rumpvfs
rumpfs.c revision 1.60
      1 /*	$NetBSD: rumpfs.c,v 1.60 2010/07/03 10:55:47 pooka Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 2009  Antti Kantee.  All Rights Reserved.
      5  *
      6  * Redistribution and use in source and binary forms, with or without
      7  * modification, are permitted provided that the following conditions
      8  * are met:
      9  * 1. Redistributions of source code must retain the above copyright
     10  *    notice, this list of conditions and the following disclaimer.
     11  * 2. Redistributions in binary form must reproduce the above copyright
     12  *    notice, this list of conditions and the following disclaimer in the
     13  *    documentation and/or other materials provided with the distribution.
     14  *
     15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
     16  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
     17  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
     18  * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
     19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
     21  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     25  * SUCH DAMAGE.
     26  */
     27 
     28 #include <sys/cdefs.h>
     29 __KERNEL_RCSID(0, "$NetBSD: rumpfs.c,v 1.60 2010/07/03 10:55:47 pooka Exp $");
     30 
     31 #include <sys/param.h>
     32 #include <sys/atomic.h>
     33 #include <sys/dirent.h>
     34 #include <sys/errno.h>
     35 #include <sys/filedesc.h>
     36 #include <sys/fcntl.h>
     37 #include <sys/kauth.h>
     38 #include <sys/malloc.h>
     39 #include <sys/module.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_rmdir(void *);
     62 static int rump_vop_mknod(void *);
     63 static int rump_vop_create(void *);
     64 static int rump_vop_inactive(void *);
     65 static int rump_vop_reclaim(void *);
     66 static int rump_vop_success(void *);
     67 static int rump_vop_readdir(void *);
     68 static int rump_vop_spec(void *);
     69 static int rump_vop_read(void *);
     70 static int rump_vop_write(void *);
     71 static int rump_vop_open(void *);
     72 static int rump_vop_symlink(void *);
     73 static int rump_vop_readlink(void *);
     74 static int rump_vop_whiteout(void *);
     75 
     76 int (**fifo_vnodeop_p)(void *);
     77 const struct vnodeopv_entry_desc fifo_vnodeop_entries[] = {
     78 	{ &vop_default_desc, vn_default_error },
     79 	{ NULL, NULL }
     80 };
     81 const struct vnodeopv_desc fifo_vnodeop_opv_desc =
     82 	{ &fifo_vnodeop_p, fifo_vnodeop_entries };
     83 
     84 int (**rump_vnodeop_p)(void *);
     85 const struct vnodeopv_entry_desc rump_vnodeop_entries[] = {
     86 	{ &vop_default_desc, vn_default_error },
     87 	{ &vop_lookup_desc, rump_vop_lookup },
     88 	{ &vop_getattr_desc, rump_vop_getattr },
     89 	{ &vop_mkdir_desc, rump_vop_mkdir },
     90 	{ &vop_rmdir_desc, rump_vop_rmdir },
     91 	{ &vop_mknod_desc, rump_vop_mknod },
     92 	{ &vop_create_desc, rump_vop_create },
     93 	{ &vop_symlink_desc, rump_vop_symlink },
     94 	{ &vop_readlink_desc, rump_vop_readlink },
     95 	{ &vop_access_desc, rump_vop_success },
     96 	{ &vop_readdir_desc, rump_vop_readdir },
     97 	{ &vop_read_desc, rump_vop_read },
     98 	{ &vop_write_desc, rump_vop_write },
     99 	{ &vop_open_desc, rump_vop_open },
    100 	{ &vop_seek_desc, genfs_seek },
    101 	{ &vop_putpages_desc, genfs_null_putpages },
    102 	{ &vop_whiteout_desc, rump_vop_whiteout },
    103 	{ &vop_fsync_desc, rump_vop_success },
    104 	{ &vop_lock_desc, genfs_lock },
    105 	{ &vop_unlock_desc, genfs_unlock },
    106 	{ &vop_islocked_desc, genfs_islocked },
    107 	{ &vop_inactive_desc, rump_vop_inactive },
    108 	{ &vop_reclaim_desc, rump_vop_reclaim },
    109 	{ NULL, NULL }
    110 };
    111 const struct vnodeopv_desc rump_vnodeop_opv_desc =
    112 	{ &rump_vnodeop_p, rump_vnodeop_entries };
    113 
    114 int (**rump_specop_p)(void *);
    115 const struct vnodeopv_entry_desc rump_specop_entries[] = {
    116 	{ &vop_default_desc, rump_vop_spec },
    117 	{ NULL, NULL }
    118 };
    119 const struct vnodeopv_desc rump_specop_opv_desc =
    120 	{ &rump_specop_p, rump_specop_entries };
    121 
    122 const struct vnodeopv_desc * const rump_opv_descs[] = {
    123 	&rump_vnodeop_opv_desc,
    124 	&rump_specop_opv_desc,
    125 	NULL
    126 };
    127 
    128 #define RUMPFS_WHITEOUT NULL
    129 #define RDENT_ISWHITEOUT(rdp) (rdp->rd_node == RUMPFS_WHITEOUT)
    130 struct rumpfs_dent {
    131 	char *rd_name;
    132 	int rd_namelen;
    133 	struct rumpfs_node *rd_node;
    134 
    135 	LIST_ENTRY(rumpfs_dent) rd_entries;
    136 };
    137 
    138 struct rumpfs_node {
    139 	struct vattr rn_va;
    140 	struct vnode *rn_vp;
    141 	char *rn_hostpath;
    142 	int rn_flags;
    143 
    144 	union {
    145 		struct {		/* VREG */
    146 			int readfd;
    147 			int writefd;
    148 			uint64_t offset;
    149 		} reg;
    150 		struct {		/* VDIR */
    151 			LIST_HEAD(, rumpfs_dent) dents;
    152 			int flags;
    153 		} dir;
    154 		struct {
    155 			char *target;
    156 			size_t len;
    157 		} link;
    158 	} rn_u;
    159 };
    160 #define rn_readfd	rn_u.reg.readfd
    161 #define rn_writefd	rn_u.reg.writefd
    162 #define rn_offset	rn_u.reg.offset
    163 #define rn_dir		rn_u.dir.dents
    164 #define rn_linktarg	rn_u.link.target
    165 #define rn_linklen	rn_u.link.len
    166 
    167 #define RUMPNODE_CANRECLAIM	0x01
    168 #define RUMPNODE_DIR_ET		0x02
    169 #define RUMPNODE_DIR_ETSUBS	0x04
    170 
    171 struct rumpfs_mount {
    172 	struct vnode *rfsmp_rvp;
    173 };
    174 
    175 static struct rumpfs_node *makeprivate(enum vtype, dev_t, off_t);
    176 
    177 /*
    178  * Extra Terrestrial stuff.  We map a given key (pathname) to a file on
    179  * the host FS.  ET phones home only from the root node of rumpfs.
    180  *
    181  * When an etfs node is removed, a vnode potentially behind it is not
    182  * immediately recycled.
    183  */
    184 
    185 struct etfs {
    186 	char et_key[MAXPATHLEN];
    187 	size_t et_keylen;
    188 	bool et_prefixkey;
    189 	bool et_removing;
    190 	devminor_t et_blkmin;
    191 
    192 	LIST_ENTRY(etfs) et_entries;
    193 
    194 	struct rumpfs_node *et_rn;
    195 };
    196 static kmutex_t etfs_lock;
    197 static LIST_HEAD(, etfs) etfs_list = LIST_HEAD_INITIALIZER(etfs_list);
    198 
    199 static enum vtype
    200 ettype_to_vtype(enum rump_etfs_type et)
    201 {
    202 	enum vtype vt;
    203 
    204 	switch (et) {
    205 	case RUMP_ETFS_REG:
    206 		vt = VREG;
    207 		break;
    208 	case RUMP_ETFS_BLK:
    209 		vt = VBLK;
    210 		break;
    211 	case RUMP_ETFS_CHR:
    212 		vt = VCHR;
    213 		break;
    214 	case RUMP_ETFS_DIR:
    215 		vt = VDIR;
    216 		break;
    217 	case RUMP_ETFS_DIR_SUBDIRS:
    218 		vt = VDIR;
    219 		break;
    220 	default:
    221 		panic("invalid et type: %d", et);
    222 	}
    223 
    224 	return vt;
    225 }
    226 
    227 static enum vtype
    228 hft_to_vtype(int hft)
    229 {
    230 	enum vtype vt;
    231 
    232 	switch (hft) {
    233 	case RUMPUSER_FT_OTHER:
    234 		vt = VNON;
    235 		break;
    236 	case RUMPUSER_FT_DIR:
    237 		vt = VDIR;
    238 		break;
    239 	case RUMPUSER_FT_REG:
    240 		vt = VREG;
    241 		break;
    242 	case RUMPUSER_FT_BLK:
    243 		vt = VBLK;
    244 		break;
    245 	case RUMPUSER_FT_CHR:
    246 		vt = VCHR;
    247 		break;
    248 	default:
    249 		vt = VNON;
    250 		break;
    251 	}
    252 
    253 	return vt;
    254 }
    255 
    256 static bool
    257 etfs_find(const char *key, struct etfs **etp, bool forceprefix)
    258 {
    259 	struct etfs *et;
    260 	size_t keylen = strlen(key);
    261 
    262 	KASSERT(mutex_owned(&etfs_lock));
    263 
    264 	LIST_FOREACH(et, &etfs_list, et_entries) {
    265 		if ((keylen == et->et_keylen || et->et_prefixkey || forceprefix)
    266 		    && strncmp(key, et->et_key, et->et_keylen) == 0) {
    267 			if (etp)
    268 				*etp = et;
    269 			return true;
    270 		}
    271 	}
    272 
    273 	return false;
    274 }
    275 
    276 #define REGDIR(ftype) \
    277     ((ftype) == RUMP_ETFS_DIR || (ftype) == RUMP_ETFS_DIR_SUBDIRS)
    278 static int
    279 doregister(const char *key, const char *hostpath,
    280 	enum rump_etfs_type ftype, uint64_t begin, uint64_t size)
    281 {
    282 	struct etfs *et;
    283 	struct rumpfs_node *rn;
    284 	uint64_t fsize;
    285 	dev_t rdev = NODEV;
    286 	devminor_t dmin = -1;
    287 	int hft, error;
    288 
    289 	if (rumpuser_getfileinfo(hostpath, &fsize, &hft, &error))
    290 		return error;
    291 
    292 	/* etfs directory requires a directory on the host */
    293 	if (REGDIR(ftype)) {
    294 		if (hft != RUMPUSER_FT_DIR)
    295 			return ENOTDIR;
    296 		if (begin != 0)
    297 			return EISDIR;
    298 		if (size != RUMP_ETFS_SIZE_ENDOFF)
    299 			return EISDIR;
    300 		size = fsize;
    301 	} else {
    302 		if (begin > fsize)
    303 			return EINVAL;
    304 		if (size == RUMP_ETFS_SIZE_ENDOFF)
    305 			size = fsize - begin;
    306 		if (begin + size > fsize)
    307 			return EINVAL;
    308 	}
    309 
    310 	if (ftype == RUMP_ETFS_BLK || ftype == RUMP_ETFS_CHR) {
    311 		error = rumpblk_register(hostpath, &dmin, begin, size);
    312 		if (error != 0) {
    313 			return error;
    314 		}
    315 		rdev = makedev(RUMPBLK_DEVMAJOR, dmin);
    316 	}
    317 
    318 	et = kmem_alloc(sizeof(*et), KM_SLEEP);
    319 	strcpy(et->et_key, key);
    320 	et->et_keylen = strlen(et->et_key);
    321 	et->et_rn = rn = makeprivate(ettype_to_vtype(ftype), rdev, size);
    322 	et->et_removing = false;
    323 	et->et_blkmin = dmin;
    324 
    325 	if (ftype == RUMP_ETFS_REG || REGDIR(ftype) || et->et_blkmin != -1) {
    326 		size_t len = strlen(hostpath)+1;
    327 
    328 		rn->rn_hostpath = malloc(len, M_TEMP, M_WAITOK | M_ZERO);
    329 		memcpy(rn->rn_hostpath, hostpath, len);
    330 		rn->rn_offset = begin;
    331 	}
    332 
    333 	if (REGDIR(ftype)) {
    334 		rn->rn_flags |= RUMPNODE_DIR_ET;
    335 		et->et_prefixkey = true;
    336 	} else {
    337 		et->et_prefixkey = false;
    338 	}
    339 
    340 	if (ftype == RUMP_ETFS_DIR_SUBDIRS)
    341 		rn->rn_flags |= RUMPNODE_DIR_ETSUBS;
    342 
    343 	mutex_enter(&etfs_lock);
    344 	if (etfs_find(key, NULL, REGDIR(ftype))) {
    345 		mutex_exit(&etfs_lock);
    346 		if (et->et_blkmin != -1)
    347 			rumpblk_deregister(hostpath);
    348 		if (et->et_rn->rn_hostpath != NULL)
    349 			free(et->et_rn->rn_hostpath, M_TEMP);
    350 		kmem_free(et->et_rn, sizeof(*et->et_rn));
    351 		kmem_free(et, sizeof(*et));
    352 		return EEXIST;
    353 	}
    354 	LIST_INSERT_HEAD(&etfs_list, et, et_entries);
    355 	mutex_exit(&etfs_lock);
    356 
    357 	return 0;
    358 }
    359 #undef REGDIR
    360 
    361 int
    362 rump_etfs_register(const char *key, const char *hostpath,
    363 	enum rump_etfs_type ftype)
    364 {
    365 
    366 	return doregister(key, hostpath, ftype, 0, RUMP_ETFS_SIZE_ENDOFF);
    367 }
    368 
    369 int
    370 rump_etfs_register_withsize(const char *key, const char *hostpath,
    371 	enum rump_etfs_type ftype, uint64_t begin, uint64_t size)
    372 {
    373 
    374 	return doregister(key, hostpath, ftype, begin, size);
    375 }
    376 
    377 /* remove etfs mapping.  caller's responsibility to make sure it's not in use */
    378 int
    379 rump_etfs_remove(const char *key)
    380 {
    381 	struct etfs *et;
    382 	size_t keylen = strlen(key);
    383 	int rv;
    384 
    385 	mutex_enter(&etfs_lock);
    386 	LIST_FOREACH(et, &etfs_list, et_entries) {
    387 		if (keylen == et->et_keylen && strcmp(et->et_key, key) == 0) {
    388 			if (et->et_removing)
    389 				et = NULL;
    390 			else
    391 				et->et_removing = true;
    392 			break;
    393 		}
    394 	}
    395 	mutex_exit(&etfs_lock);
    396 	if (!et)
    397 		return ENOENT;
    398 
    399 	/*
    400 	 * ok, we know what we want to remove and have signalled there
    401 	 * actually are men at work.  first, unregister from rumpblk
    402 	 */
    403 	if (et->et_blkmin != -1) {
    404 		rv = rumpblk_deregister(et->et_rn->rn_hostpath);
    405 	} else {
    406 		rv = 0;
    407 	}
    408 	KASSERT(rv == 0);
    409 
    410 	/* then do the actual removal */
    411 	mutex_enter(&etfs_lock);
    412 	LIST_REMOVE(et, et_entries);
    413 	mutex_exit(&etfs_lock);
    414 
    415 	/* node is unreachable, safe to nuke all device copies */
    416 	if (et->et_blkmin != -1)
    417 		vdevgone(RUMPBLK_DEVMAJOR, et->et_blkmin, et->et_blkmin, VBLK);
    418 
    419 	if (et->et_rn->rn_hostpath != NULL)
    420 		free(et->et_rn->rn_hostpath, M_TEMP);
    421 	kmem_free(et->et_rn, sizeof(*et->et_rn));
    422 	kmem_free(et, sizeof(*et));
    423 
    424 	return 0;
    425 }
    426 
    427 /*
    428  * rumpfs
    429  */
    430 
    431 #define INO_WHITEOUT 1
    432 static int lastino = 2;
    433 static kmutex_t reclock;
    434 
    435 static struct rumpfs_node *
    436 makeprivate(enum vtype vt, dev_t rdev, off_t size)
    437 {
    438 	struct rumpfs_node *rn;
    439 	struct vattr *va;
    440 	struct timespec ts;
    441 
    442 	rn = kmem_zalloc(sizeof(*rn), KM_SLEEP);
    443 
    444 	switch (vt) {
    445 	case VDIR:
    446 		LIST_INIT(&rn->rn_dir);
    447 		break;
    448 	case VREG:
    449 		rn->rn_readfd = -1;
    450 		rn->rn_writefd = -1;
    451 		break;
    452 	default:
    453 		break;
    454 	}
    455 
    456 	nanotime(&ts);
    457 
    458 	va = &rn->rn_va;
    459 	va->va_type = vt;
    460 	va->va_mode = 0755;
    461 	if (vt == VDIR)
    462 		va->va_nlink = 2;
    463 	else
    464 		va->va_nlink = 1;
    465 	va->va_uid = 0;
    466 	va->va_gid = 0;
    467 	va->va_fsid =
    468 	va->va_fileid = atomic_inc_uint_nv(&lastino);
    469 	va->va_size = size;
    470 	va->va_blocksize = 512;
    471 	va->va_atime = ts;
    472 	va->va_mtime = ts;
    473 	va->va_ctime = ts;
    474 	va->va_birthtime = ts;
    475 	va->va_gen = 0;
    476 	va->va_flags = 0;
    477 	va->va_rdev = rdev;
    478 	va->va_bytes = 512;
    479 	va->va_filerev = 0;
    480 	va->va_vaflags = 0;
    481 
    482 	return rn;
    483 }
    484 
    485 static int
    486 makevnode(struct mount *mp, struct rumpfs_node *rn, struct vnode **vpp)
    487 {
    488 	struct vnode *vp;
    489 	int (**vpops)(void *);
    490 	struct vattr *va = &rn->rn_va;
    491 	int rv;
    492 
    493 	KASSERT(!mutex_owned(&reclock));
    494 
    495 	if (va->va_type == VCHR || va->va_type == VBLK) {
    496 		vpops = rump_specop_p;
    497 	} else {
    498 		vpops = rump_vnodeop_p;
    499 	}
    500 	if (vpops != rump_specop_p && va->va_type != VDIR
    501 	    && !(va->va_type == VREG && rn->rn_hostpath != NULL)
    502 	    && va->va_type != VSOCK && va->va_type != VLNK)
    503 		return EOPNOTSUPP;
    504 
    505 	rv = getnewvnode(VT_RUMP, mp, vpops, &vp);
    506 	if (rv)
    507 		return rv;
    508 
    509 	vp->v_size = vp->v_writesize = va->va_size;
    510 	vp->v_type = va->va_type;
    511 
    512 	if (vpops == rump_specop_p) {
    513 		spec_node_init(vp, va->va_rdev);
    514 	}
    515 	vp->v_data = rn;
    516 
    517 	vn_lock(vp, LK_RETRY | LK_EXCLUSIVE);
    518 	mutex_enter(&reclock);
    519 	rn->rn_vp = vp;
    520 	mutex_exit(&reclock);
    521 
    522 	*vpp = vp;
    523 
    524 	return 0;
    525 }
    526 
    527 
    528 static void
    529 makedir(struct rumpfs_node *rnd,
    530 	struct componentname *cnp, struct rumpfs_node *rn)
    531 {
    532 	struct rumpfs_dent *rdent;
    533 
    534 	rdent = kmem_alloc(sizeof(*rdent), KM_SLEEP);
    535 	rdent->rd_name = kmem_alloc(cnp->cn_namelen+1, KM_SLEEP);
    536 	rdent->rd_node = rn;
    537 	strlcpy(rdent->rd_name, cnp->cn_nameptr, cnp->cn_namelen+1);
    538 	rdent->rd_namelen = strlen(rdent->rd_name);
    539 
    540 	LIST_INSERT_HEAD(&rnd->rn_dir, rdent, rd_entries);
    541 }
    542 
    543 static void
    544 freedir(struct rumpfs_node *rnd, struct componentname *cnp)
    545 {
    546 	struct rumpfs_dent *rd = NULL;
    547 
    548 	LIST_FOREACH(rd, &rnd->rn_dir, rd_entries) {
    549 		if (rd->rd_namelen == cnp->cn_namelen &&
    550 		    strncmp(rd->rd_name, cnp->cn_nameptr,
    551 		            cnp->cn_namelen) == 0)
    552 			break;
    553 	}
    554 	if (rd == NULL)
    555 		panic("could not find directory entry: %s", cnp->cn_nameptr);
    556 
    557 	LIST_REMOVE(rd, rd_entries);
    558 	kmem_free(rd->rd_name, rd->rd_namelen+1);
    559 	kmem_free(rd, sizeof(*rd));
    560 }
    561 
    562 /*
    563  * Simple lookup for rump file systems.
    564  *
    565  * uhm, this is twisted.  C F C C, hope of C C F C looming
    566  */
    567 static int
    568 rump_vop_lookup(void *v)
    569 {
    570 	struct vop_lookup_args /* {
    571 		struct vnode *a_dvp;
    572 		struct vnode **a_vpp;
    573 		struct componentname *a_cnp;
    574 	}; */ *ap = v;
    575 	struct componentname *cnp = ap->a_cnp;
    576 	struct vnode *dvp = ap->a_dvp;
    577 	struct vnode **vpp = ap->a_vpp;
    578 	struct vnode *vp;
    579 	struct rumpfs_node *rnd = dvp->v_data, *rn;
    580 	struct rumpfs_dent *rd = NULL;
    581 	struct etfs *et;
    582 	int rv;
    583 
    584 	/* we handle only some "non-special" cases */
    585 	if (!(((cnp->cn_flags & ISLASTCN) == 0) || (cnp->cn_nameiop != RENAME)))
    586 		return EOPNOTSUPP;
    587 	if (!((cnp->cn_flags & ISDOTDOT) == 0))
    588 		return EOPNOTSUPP;
    589 
    590 	/* check for dot, return directly if the case */
    591 	if (cnp->cn_namelen == 1 && cnp->cn_nameptr[0] == '.') {
    592 		vref(dvp);
    593 		*vpp = dvp;
    594 		return 0;
    595 	}
    596 
    597 	/* check for etfs */
    598 	if (dvp == rootvnode && cnp->cn_nameiop == LOOKUP) {
    599 		bool found;
    600 		mutex_enter(&etfs_lock);
    601 		found = etfs_find(cnp->cn_pnbuf, &et, false);
    602 		mutex_exit(&etfs_lock);
    603 
    604 		if (found) {
    605 			char *offset;
    606 
    607 			offset = strstr(cnp->cn_pnbuf, et->et_key);
    608 			KASSERT(offset);
    609 
    610 			rn = et->et_rn;
    611 			cnp->cn_consume += et->et_keylen
    612 			    - (cnp->cn_nameptr - offset) - cnp->cn_namelen;
    613 			if (rn->rn_va.va_type != VDIR)
    614 				cnp->cn_flags &= ~REQUIREDIR;
    615 			goto getvnode;
    616 		}
    617 	}
    618 
    619 	if (rnd->rn_flags & RUMPNODE_DIR_ET) {
    620 		uint64_t fsize;
    621 		char *newpath;
    622 		size_t newpathlen;
    623 		int hft, error;
    624 
    625 		newpathlen = strlen(rnd->rn_hostpath) + 1 + cnp->cn_namelen + 1;
    626 		newpath = malloc(newpathlen, M_TEMP, M_WAITOK);
    627 
    628 		strlcpy(newpath, rnd->rn_hostpath, newpathlen);
    629 		strlcat(newpath, "/", newpathlen);
    630 		strlcat(newpath, cnp->cn_nameptr, newpathlen);
    631 
    632 		if (rumpuser_getfileinfo(newpath, &fsize, &hft, &error)) {
    633 			free(newpath, M_TEMP);
    634 			return error;
    635 		}
    636 
    637 		/* allow only dirs and regular files */
    638 		if (hft != RUMPUSER_FT_REG && hft != RUMPUSER_FT_DIR) {
    639 			free(newpath, M_TEMP);
    640 			return ENOENT;
    641 		}
    642 
    643 		rn = makeprivate(hft_to_vtype(hft), NODEV, fsize);
    644 		rn->rn_flags |= RUMPNODE_CANRECLAIM;
    645 		if (rnd->rn_flags & RUMPNODE_DIR_ETSUBS) {
    646 			rn->rn_flags |= RUMPNODE_DIR_ET | RUMPNODE_DIR_ETSUBS;
    647 		}
    648 		rn->rn_hostpath = newpath;
    649 
    650 		goto getvnode;
    651 	} else {
    652 		LIST_FOREACH(rd, &rnd->rn_dir, rd_entries) {
    653 			if (rd->rd_namelen == cnp->cn_namelen &&
    654 			    strncmp(rd->rd_name, cnp->cn_nameptr,
    655 			      cnp->cn_namelen) == 0)
    656 				break;
    657 		}
    658 	}
    659 
    660 	if (!rd && ((cnp->cn_flags & ISLASTCN) == 0||cnp->cn_nameiop != CREATE))
    661 		return ENOENT;
    662 
    663 	if (!rd && (cnp->cn_flags & ISLASTCN) && cnp->cn_nameiop == CREATE) {
    664 		cnp->cn_flags |= SAVENAME;
    665 		return EJUSTRETURN;
    666 	}
    667 	if ((cnp->cn_flags & ISLASTCN) && cnp->cn_nameiop == DELETE)
    668 		cnp->cn_flags |= SAVENAME;
    669 
    670 	rn = rd->rd_node;
    671 
    672  getvnode:
    673 	KASSERT(rn);
    674 	mutex_enter(&reclock);
    675 	if ((vp = rn->rn_vp)) {
    676 		mutex_enter(&vp->v_interlock);
    677 		mutex_exit(&reclock);
    678 		if (vget(vp, LK_EXCLUSIVE | LK_INTERLOCK))
    679 			goto getvnode;
    680 		*vpp = vp;
    681 	} else {
    682 		mutex_exit(&reclock);
    683 		rv = makevnode(dvp->v_mount, rn, vpp);
    684 		if (rv)
    685 			return rv;
    686 	}
    687 
    688 	return 0;
    689 }
    690 
    691 static int
    692 rump_vop_getattr(void *v)
    693 {
    694 	struct vop_getattr_args /* {
    695 		struct vnode *a_vp;
    696 		struct vattr *a_vap;
    697 		kauth_cred_t a_cred;
    698 	} */ *ap = v;
    699 	struct rumpfs_node *rn = ap->a_vp->v_data;
    700 
    701 	memcpy(ap->a_vap, &rn->rn_va, sizeof(struct vattr));
    702 	return 0;
    703 }
    704 
    705 static int
    706 rump_vop_mkdir(void *v)
    707 {
    708 	struct vop_mkdir_args /* {
    709 		struct vnode *a_dvp;
    710 		struct vnode **a_vpp;
    711 		struct componentname *a_cnp;
    712 		struct vattr *a_vap;
    713 	}; */ *ap = v;
    714 	struct vnode *dvp = ap->a_dvp;
    715 	struct vnode **vpp = ap->a_vpp;
    716 	struct componentname *cnp = ap->a_cnp;
    717 	struct rumpfs_node *rnd = dvp->v_data, *rn;
    718 	int rv = 0;
    719 
    720 	rn = makeprivate(VDIR, NODEV, DEV_BSIZE);
    721 	rv = makevnode(dvp->v_mount, rn, vpp);
    722 	if (rv)
    723 		goto out;
    724 
    725 	makedir(rnd, cnp, rn);
    726 
    727  out:
    728 	PNBUF_PUT(cnp->cn_pnbuf);
    729 	vput(dvp);
    730 	return rv;
    731 }
    732 
    733 static int
    734 rump_vop_rmdir(void *v)
    735 {
    736         struct vop_rmdir_args /* {
    737                 struct vnode *a_dvp;
    738                 struct vnode *a_vp;
    739                 struct componentname *a_cnp;
    740         }; */ *ap = v;
    741 	struct vnode *dvp = ap->a_dvp;
    742 	struct vnode *vp = ap->a_vp;
    743 	struct componentname *cnp = ap->a_cnp;
    744 	struct rumpfs_node *rnd = dvp->v_data;
    745 	struct rumpfs_node *rn = vp->v_data;
    746 	int rv = 0;
    747 
    748 	if (!LIST_EMPTY(&rn->rn_dir)) {
    749 		rv = ENOTEMPTY;
    750 		goto out;
    751 	}
    752 
    753 	freedir(rnd, cnp);
    754 	rn->rn_flags |= RUMPNODE_CANRECLAIM;
    755 
    756 out:
    757 	PNBUF_PUT(cnp->cn_pnbuf);
    758 	vput(dvp);
    759 	vput(vp);
    760 
    761 	return rv;
    762 }
    763 
    764 static int
    765 rump_vop_mknod(void *v)
    766 {
    767 	struct vop_mknod_args /* {
    768 		struct vnode *a_dvp;
    769 		struct vnode **a_vpp;
    770 		struct componentname *a_cnp;
    771 		struct vattr *a_vap;
    772 	}; */ *ap = v;
    773 	struct vnode *dvp = ap->a_dvp;
    774 	struct vnode **vpp = ap->a_vpp;
    775 	struct componentname *cnp = ap->a_cnp;
    776 	struct vattr *va = ap->a_vap;
    777 	struct rumpfs_node *rnd = dvp->v_data, *rn;
    778 	int rv;
    779 
    780 	rn = makeprivate(va->va_type, va->va_rdev, DEV_BSIZE);
    781 	rv = makevnode(dvp->v_mount, rn, vpp);
    782 	if (rv)
    783 		goto out;
    784 
    785 	makedir(rnd, cnp, rn);
    786 
    787  out:
    788 	PNBUF_PUT(cnp->cn_pnbuf);
    789 	vput(dvp);
    790 	return rv;
    791 }
    792 
    793 static int
    794 rump_vop_create(void *v)
    795 {
    796 	struct vop_create_args /* {
    797 		struct vnode *a_dvp;
    798 		struct vnode **a_vpp;
    799 		struct componentname *a_cnp;
    800 		struct vattr *a_vap;
    801 	}; */ *ap = v;
    802 	struct vnode *dvp = ap->a_dvp;
    803 	struct vnode **vpp = ap->a_vpp;
    804 	struct componentname *cnp = ap->a_cnp;
    805 	struct vattr *va = ap->a_vap;
    806 	struct rumpfs_node *rnd = dvp->v_data, *rn;
    807 	int rv;
    808 
    809 	if (va->va_type != VSOCK) {
    810 		rv = EOPNOTSUPP;
    811 		goto out;
    812 	}
    813 	rn = makeprivate(VSOCK, NODEV, DEV_BSIZE);
    814 	rv = makevnode(dvp->v_mount, rn, vpp);
    815 	if (rv)
    816 		goto out;
    817 
    818 	makedir(rnd, cnp, rn);
    819 
    820  out:
    821 	PNBUF_PUT(cnp->cn_pnbuf);
    822 	vput(dvp);
    823 	return rv;
    824 }
    825 
    826 static int
    827 rump_vop_symlink(void *v)
    828 {
    829 	struct vop_symlink_args /* {
    830 		struct vnode *a_dvp;
    831 		struct vnode **a_vpp;
    832 		struct componentname *a_cnp;
    833 		struct vattr *a_vap;
    834 		char *a_target;
    835 	}; */ *ap = v;
    836 	struct vnode *dvp = ap->a_dvp;
    837 	struct vnode **vpp = ap->a_vpp;
    838 	struct componentname *cnp = ap->a_cnp;
    839 	struct rumpfs_node *rnd = dvp->v_data, *rn;
    840 	const char *target = ap->a_target;
    841 	size_t linklen;
    842 	int rv;
    843 
    844 	linklen = strlen(target);
    845 	KASSERT(linklen < MAXPATHLEN);
    846 	rn = makeprivate(VLNK, NODEV, linklen);
    847 	rv = makevnode(dvp->v_mount, rn, vpp);
    848 	if (rv)
    849 		goto out;
    850 
    851 	makedir(rnd, cnp, rn);
    852 
    853 	KASSERT(linklen < MAXPATHLEN);
    854 	rn->rn_linktarg = PNBUF_GET();
    855 	rn->rn_linklen = linklen;
    856 	strcpy(rn->rn_linktarg, target);
    857 
    858  out:
    859 	vput(dvp);
    860 	return rv;
    861 }
    862 
    863 static int
    864 rump_vop_readlink(void *v)
    865 {
    866 	struct vop_readlink_args /* {
    867 		struct vnode *a_vp;
    868 		struct uio *a_uio;
    869 		kauth_cred_t a_cred;
    870 	}; */ *ap = v;
    871 	struct vnode *vp = ap->a_vp;
    872 	struct rumpfs_node *rn = vp->v_data;
    873 	struct uio *uio = ap->a_uio;
    874 
    875 	return uiomove(rn->rn_linktarg, rn->rn_linklen, uio);
    876 }
    877 
    878 static int
    879 rump_vop_whiteout(void *v)
    880 {
    881 	struct vop_whiteout_args /* {
    882 		struct vnode            *a_dvp;
    883 		struct componentname    *a_cnp;
    884 		int                     a_flags;
    885 	} */ *ap = v;
    886 	struct vnode *dvp = ap->a_dvp;
    887 	struct rumpfs_node *rnd = dvp->v_data;
    888 	struct componentname *cnp = ap->a_cnp;
    889 	int flags = ap->a_flags;
    890 
    891 	switch (flags) {
    892 	case LOOKUP:
    893 		break;
    894 	case CREATE:
    895 		makedir(rnd, cnp, RUMPFS_WHITEOUT);
    896 		break;
    897 	case DELETE:
    898 		cnp->cn_flags &= ~DOWHITEOUT; /* cargo culting never fails ? */
    899 		freedir(rnd, cnp);
    900 		break;
    901 	default:
    902 		panic("unknown whiteout op %d", flags);
    903 	}
    904 
    905 	return 0;
    906 }
    907 
    908 static int
    909 rump_vop_open(void *v)
    910 {
    911 	struct vop_open_args /* {
    912 		struct vnode *a_vp;
    913 		int a_mode;
    914 		kauth_cred_t a_cred;
    915 	} */ *ap = v;
    916 	struct vnode *vp = ap->a_vp;
    917 	struct rumpfs_node *rn = vp->v_data;
    918 	int mode = ap->a_mode;
    919 	int error = EINVAL;
    920 
    921 	if (vp->v_type != VREG)
    922 		return 0;
    923 
    924 	if (mode & FREAD) {
    925 		if (rn->rn_readfd != -1)
    926 			return 0;
    927 		rn->rn_readfd = rumpuser_open(rn->rn_hostpath,
    928 		    O_RDONLY, &error);
    929 	}
    930 
    931 	if (mode & FWRITE) {
    932 		if (rn->rn_writefd != -1)
    933 			return 0;
    934 		rn->rn_writefd = rumpuser_open(rn->rn_hostpath,
    935 		    O_WRONLY, &error);
    936 	}
    937 
    938 	return error;
    939 }
    940 
    941 /* simple readdir.  event omits dotstuff and periods */
    942 static int
    943 rump_vop_readdir(void *v)
    944 {
    945 	struct vop_readdir_args /* {
    946 		struct vnode *a_vp;
    947 		struct uio *a_uio;
    948 		kauth_cred_t a_cred;
    949 		int *a_eofflag;
    950 		off_t **a_cookies;
    951 		int *a_ncookies;
    952 	} */ *ap = v;
    953 	struct vnode *vp = ap->a_vp;
    954 	struct uio *uio = ap->a_uio;
    955 	struct rumpfs_node *rnd = vp->v_data;
    956 	struct rumpfs_dent *rdent;
    957 	unsigned i;
    958 	int rv = 0;
    959 
    960 	/* seek to current entry */
    961 	for (i = 0, rdent = LIST_FIRST(&rnd->rn_dir);
    962 	    (i < uio->uio_offset) && rdent;
    963 	    i++, rdent = LIST_NEXT(rdent, rd_entries))
    964 		continue;
    965 	if (!rdent)
    966 		goto out;
    967 
    968 	/* copy entries */
    969 	for (; rdent && uio->uio_resid > 0;
    970 	    rdent = LIST_NEXT(rdent, rd_entries), i++) {
    971 		struct dirent dent;
    972 
    973 		strlcpy(dent.d_name, rdent->rd_name, sizeof(dent.d_name));
    974 		dent.d_namlen = strlen(dent.d_name);
    975 		dent.d_reclen = _DIRENT_RECLEN(&dent, dent.d_namlen);
    976 
    977 		if (__predict_false(RDENT_ISWHITEOUT(rdent))) {
    978 			dent.d_fileno = INO_WHITEOUT;
    979 			dent.d_type = DT_WHT;
    980 		} else {
    981 			dent.d_fileno = rdent->rd_node->rn_va.va_fileid;
    982 			dent.d_type = vtype2dt(rdent->rd_node->rn_va.va_type);
    983 		}
    984 
    985 		if (uio->uio_resid < dent.d_reclen) {
    986 			i--;
    987 			break;
    988 		}
    989 
    990 		rv = uiomove(&dent, dent.d_reclen, uio);
    991 		if (rv) {
    992 			i--;
    993 			break;
    994 		}
    995 	}
    996 
    997  out:
    998 	if (ap->a_cookies) {
    999 		*ap->a_ncookies = 0;
   1000 		*ap->a_cookies = NULL;
   1001 	}
   1002 	if (rdent)
   1003 		*ap->a_eofflag = 0;
   1004 	else
   1005 		*ap->a_eofflag = 1;
   1006 	uio->uio_offset = i;
   1007 
   1008 	return rv;
   1009 }
   1010 
   1011 static int
   1012 rump_vop_read(void *v)
   1013 {
   1014 	struct vop_read_args /* {
   1015 		struct vnode *a_vp;
   1016 		struct uio *a_uio;
   1017 		int ioflags a_ioflag;
   1018 		kauth_cred_t a_cred;
   1019 	}; */ *ap = v;
   1020 	struct vnode *vp = ap->a_vp;
   1021 	struct rumpfs_node *rn = vp->v_data;
   1022 	struct uio *uio = ap->a_uio;
   1023 	uint8_t *buf;
   1024 	size_t bufsize;
   1025 	ssize_t n;
   1026 	int error = 0;
   1027 
   1028 	bufsize = uio->uio_resid;
   1029 	buf = kmem_alloc(bufsize, KM_SLEEP);
   1030 	if ((n = rumpuser_pread(rn->rn_readfd, buf, bufsize,
   1031 	    uio->uio_offset + rn->rn_offset, &error)) == -1)
   1032 		goto out;
   1033 	KASSERT(n <= bufsize);
   1034 	error = uiomove(buf, n, uio);
   1035 
   1036  out:
   1037 	kmem_free(buf, bufsize);
   1038 	return error;
   1039 }
   1040 
   1041 static int
   1042 rump_vop_write(void *v)
   1043 {
   1044 	struct vop_read_args /* {
   1045 		struct vnode *a_vp;
   1046 		struct uio *a_uio;
   1047 		int ioflags a_ioflag;
   1048 		kauth_cred_t a_cred;
   1049 	}; */ *ap = v;
   1050 	struct vnode *vp = ap->a_vp;
   1051 	struct rumpfs_node *rn = vp->v_data;
   1052 	struct uio *uio = ap->a_uio;
   1053 	uint8_t *buf;
   1054 	size_t bufsize;
   1055 	ssize_t n;
   1056 	int error = 0;
   1057 
   1058 	bufsize = uio->uio_resid;
   1059 	buf = kmem_alloc(bufsize, KM_SLEEP);
   1060 	error = uiomove(buf, bufsize, uio);
   1061 	if (error)
   1062 		goto out;
   1063 	KASSERT(uio->uio_resid == 0);
   1064 	n = rumpuser_pwrite(rn->rn_writefd, buf, bufsize,
   1065 	    (uio->uio_offset-bufsize) + rn->rn_offset, &error);
   1066 	if (n >= 0) {
   1067 		KASSERT(n <= bufsize);
   1068 		uio->uio_resid = bufsize - n;
   1069 	}
   1070 
   1071  out:
   1072 	kmem_free(buf, bufsize);
   1073 	return error;
   1074 }
   1075 
   1076 static int
   1077 rump_vop_success(void *v)
   1078 {
   1079 
   1080 	return 0;
   1081 }
   1082 
   1083 static int
   1084 rump_vop_inactive(void *v)
   1085 {
   1086 	struct vop_inactive_args /* {
   1087 		struct vnode *a_vp;
   1088 		bool *a_recycle;
   1089 	} */ *ap = v;
   1090 	struct vnode *vp = ap->a_vp;
   1091 	struct rumpfs_node *rn = vp->v_data;
   1092 	int error;
   1093 
   1094 	if (vp->v_type == VREG) {
   1095 		if (rn->rn_readfd != -1) {
   1096 			rumpuser_close(rn->rn_readfd, &error);
   1097 			rn->rn_readfd = -1;
   1098 		}
   1099 		if (rn->rn_writefd != -1) {
   1100 			rumpuser_close(rn->rn_writefd, &error);
   1101 			rn->rn_writefd = -1;
   1102 		}
   1103 	}
   1104 	*ap->a_recycle = (rn->rn_flags & RUMPNODE_CANRECLAIM) ? true : false;
   1105 
   1106 	VOP_UNLOCK(vp);
   1107 	return 0;
   1108 }
   1109 
   1110 static int
   1111 rump_vop_reclaim(void *v)
   1112 {
   1113 	struct vop_reclaim_args /* {
   1114 		struct vnode *a_vp;
   1115 	} */ *ap = v;
   1116 	struct vnode *vp = ap->a_vp;
   1117 	struct rumpfs_node *rn = vp->v_data;
   1118 
   1119 	mutex_enter(&reclock);
   1120 	rn->rn_vp = NULL;
   1121 	mutex_exit(&reclock);
   1122 	vp->v_data = NULL;
   1123 
   1124 	if (rn->rn_flags & RUMPNODE_CANRECLAIM) {
   1125 		if (vp->v_type == VLNK)
   1126 			PNBUF_PUT(rn->rn_linktarg);
   1127 		if (rn->rn_hostpath)
   1128 			free(rn->rn_hostpath, M_TEMP);
   1129 		kmem_free(rn, sizeof(*rn));
   1130 	}
   1131 
   1132 	return 0;
   1133 }
   1134 
   1135 static int
   1136 rump_vop_spec(void *v)
   1137 {
   1138 	struct vop_generic_args *ap = v;
   1139 	int (**opvec)(void *);
   1140 
   1141 	switch (ap->a_desc->vdesc_offset) {
   1142 	case VOP_ACCESS_DESCOFFSET:
   1143 	case VOP_GETATTR_DESCOFFSET:
   1144 	case VOP_LOCK_DESCOFFSET:
   1145 	case VOP_UNLOCK_DESCOFFSET:
   1146 	case VOP_RECLAIM_DESCOFFSET:
   1147 		opvec = rump_vnodeop_p;
   1148 		break;
   1149 	default:
   1150 		opvec = spec_vnodeop_p;
   1151 		break;
   1152 	}
   1153 
   1154 	return VOCALL(opvec, ap->a_desc->vdesc_offset, v);
   1155 }
   1156 
   1157 /*
   1158  * Begin vfs-level stuff
   1159  */
   1160 
   1161 VFS_PROTOS(rumpfs);
   1162 struct vfsops rumpfs_vfsops = {
   1163 	.vfs_name =		MOUNT_RUMPFS,
   1164 	.vfs_min_mount_data = 	0,
   1165 	.vfs_mount =		rumpfs_mount,
   1166 	.vfs_start =		(void *)nullop,
   1167 	.vfs_unmount = 		rumpfs_unmount,
   1168 	.vfs_root =		rumpfs_root,
   1169 	.vfs_quotactl =		(void *)eopnotsupp,
   1170 	.vfs_statvfs =		genfs_statvfs,
   1171 	.vfs_sync =		(void *)nullop,
   1172 	.vfs_vget =		rumpfs_vget,
   1173 	.vfs_fhtovp =		(void *)eopnotsupp,
   1174 	.vfs_vptofh =		(void *)eopnotsupp,
   1175 	.vfs_init =		rumpfs_init,
   1176 	.vfs_reinit =		NULL,
   1177 	.vfs_done =		rumpfs_done,
   1178 	.vfs_mountroot =	rumpfs_mountroot,
   1179 	.vfs_snapshot =		(void *)eopnotsupp,
   1180 	.vfs_extattrctl =	(void *)eopnotsupp,
   1181 	.vfs_suspendctl =	(void *)eopnotsupp,
   1182 	.vfs_opv_descs =	rump_opv_descs,
   1183 	/* vfs_refcount */
   1184 	/* vfs_list */
   1185 };
   1186 
   1187 int
   1188 rumpfs_mount(struct mount *mp, const char *mntpath, void *arg, size_t *alen)
   1189 {
   1190 
   1191 	return EOPNOTSUPP;
   1192 }
   1193 
   1194 int
   1195 rumpfs_unmount(struct mount *mp, int flags)
   1196 {
   1197 
   1198 	/* if going for it, just lie about it */
   1199 	if (panicstr)
   1200 		return 0;
   1201 
   1202 	return EOPNOTSUPP; /* ;) */
   1203 }
   1204 
   1205 int
   1206 rumpfs_root(struct mount *mp, struct vnode **vpp)
   1207 {
   1208 	struct rumpfs_mount *rfsmp = mp->mnt_data;
   1209 
   1210 	vget(rfsmp->rfsmp_rvp, LK_EXCLUSIVE | LK_RETRY);
   1211 	*vpp = rfsmp->rfsmp_rvp;
   1212 	return 0;
   1213 }
   1214 
   1215 int
   1216 rumpfs_vget(struct mount *mp, ino_t ino, struct vnode **vpp)
   1217 {
   1218 
   1219 	return EOPNOTSUPP;
   1220 }
   1221 
   1222 void
   1223 rumpfs_init()
   1224 {
   1225 
   1226 	CTASSERT(RUMP_ETFS_SIZE_ENDOFF == RUMPBLK_SIZENOTSET);
   1227 
   1228 	mutex_init(&reclock, MUTEX_DEFAULT, IPL_NONE);
   1229 	mutex_init(&etfs_lock, MUTEX_DEFAULT, IPL_NONE);
   1230 }
   1231 
   1232 void
   1233 rumpfs_done()
   1234 {
   1235 
   1236 	mutex_destroy(&reclock);
   1237 	mutex_destroy(&etfs_lock);
   1238 }
   1239 
   1240 int
   1241 rumpfs_mountroot()
   1242 {
   1243 	struct mount *mp;
   1244 	struct rumpfs_mount *rfsmp;
   1245 	struct rumpfs_node *rn;
   1246 	int error;
   1247 
   1248 	if ((error = vfs_rootmountalloc(MOUNT_RUMPFS, "rootdev", &mp)) != 0) {
   1249 		vrele(rootvp);
   1250 		return error;
   1251 	}
   1252 
   1253 	rfsmp = kmem_alloc(sizeof(*rfsmp), KM_SLEEP);
   1254 
   1255 	rn = makeprivate(VDIR, NODEV, DEV_BSIZE);
   1256 	error = makevnode(mp, rn, &rfsmp->rfsmp_rvp);
   1257 	if (error)
   1258 		panic("could not create root vnode: %d", error);
   1259 	rfsmp->rfsmp_rvp->v_vflag |= VV_ROOT;
   1260 	VOP_UNLOCK(rfsmp->rfsmp_rvp);
   1261 
   1262 	mutex_enter(&mountlist_lock);
   1263 	CIRCLEQ_INSERT_TAIL(&mountlist, mp, mnt_list);
   1264 	mutex_exit(&mountlist_lock);
   1265 
   1266 	mp->mnt_data = rfsmp;
   1267 	mp->mnt_stat.f_namemax = MAXNAMLEN;
   1268 	mp->mnt_stat.f_iosize = 512;
   1269 	mp->mnt_flag |= MNT_LOCAL;
   1270 	mp->mnt_iflag |= IMNT_MPSAFE;
   1271 	vfs_getnewfsid(mp);
   1272 
   1273 	error = set_statvfs_info("/", UIO_SYSSPACE, "rumpfs", UIO_SYSSPACE,
   1274 	    mp->mnt_op->vfs_name, mp, curlwp);
   1275 	if (error)
   1276 		panic("set statvfsinfo for rootfs failed");
   1277 
   1278 	vfs_unbusy(mp, false, NULL);
   1279 
   1280 	return 0;
   1281 }
   1282