Home | History | Annotate | Line # | Download | only in rumpvfs
rumpfs.c revision 1.37.2.6
      1  1.37.2.6  rmind /*	$NetBSD: rumpfs.c,v 1.37.2.6 2011/05/19 03:43:04 rmind Exp $	*/
      2       1.1  pooka 
      3       1.1  pooka /*
      4  1.37.2.5  rmind  * Copyright (c) 2009, 2010, 2011 Antti Kantee.  All Rights Reserved.
      5       1.1  pooka  *
      6       1.1  pooka  * Redistribution and use in source and binary forms, with or without
      7       1.1  pooka  * modification, are permitted provided that the following conditions
      8       1.1  pooka  * are met:
      9       1.1  pooka  * 1. Redistributions of source code must retain the above copyright
     10       1.1  pooka  *    notice, this list of conditions and the following disclaimer.
     11       1.1  pooka  * 2. Redistributions in binary form must reproduce the above copyright
     12       1.1  pooka  *    notice, this list of conditions and the following disclaimer in the
     13       1.1  pooka  *    documentation and/or other materials provided with the distribution.
     14       1.1  pooka  *
     15       1.1  pooka  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
     16       1.1  pooka  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
     17       1.1  pooka  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
     18       1.1  pooka  * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
     19       1.1  pooka  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     20       1.1  pooka  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
     21       1.1  pooka  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     22       1.1  pooka  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     23       1.1  pooka  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     24       1.1  pooka  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     25       1.1  pooka  * SUCH DAMAGE.
     26       1.1  pooka  */
     27       1.1  pooka 
     28       1.3  pooka #include <sys/cdefs.h>
     29  1.37.2.6  rmind __KERNEL_RCSID(0, "$NetBSD: rumpfs.c,v 1.37.2.6 2011/05/19 03:43:04 rmind Exp $");
     30       1.3  pooka 
     31       1.1  pooka #include <sys/param.h>
     32      1.24  pooka #include <sys/atomic.h>
     33  1.37.2.4  rmind #include <sys/buf.h>
     34      1.33  pooka #include <sys/dirent.h>
     35      1.33  pooka #include <sys/errno.h>
     36      1.24  pooka #include <sys/filedesc.h>
     37      1.24  pooka #include <sys/fcntl.h>
     38       1.1  pooka #include <sys/kauth.h>
     39      1.24  pooka #include <sys/malloc.h>
     40      1.30  pooka #include <sys/module.h>
     41      1.24  pooka #include <sys/mount.h>
     42      1.24  pooka #include <sys/namei.h>
     43       1.1  pooka #include <sys/lock.h>
     44       1.1  pooka #include <sys/lockf.h>
     45      1.24  pooka #include <sys/queue.h>
     46       1.1  pooka #include <sys/stat.h>
     47       1.1  pooka #include <sys/syscallargs.h>
     48      1.24  pooka #include <sys/vnode.h>
     49  1.37.2.4  rmind #include <sys/unistd.h>
     50       1.1  pooka 
     51       1.1  pooka #include <miscfs/fifofs/fifo.h>
     52       1.1  pooka #include <miscfs/specfs/specdev.h>
     53       1.1  pooka #include <miscfs/genfs/genfs.h>
     54  1.37.2.4  rmind #include <miscfs/genfs/genfs_node.h>
     55  1.37.2.4  rmind 
     56  1.37.2.4  rmind #include <uvm/uvm_extern.h>
     57       1.1  pooka 
     58       1.1  pooka #include <rump/rumpuser.h>
     59       1.1  pooka 
     60       1.1  pooka #include "rump_private.h"
     61       1.1  pooka #include "rump_vfs_private.h"
     62       1.1  pooka 
     63       1.1  pooka static int rump_vop_lookup(void *);
     64       1.9  pooka static int rump_vop_getattr(void *);
     65  1.37.2.4  rmind static int rump_vop_setattr(void *);
     66      1.14  pooka static int rump_vop_mkdir(void *);
     67  1.37.2.3  rmind static int rump_vop_rmdir(void *);
     68  1.37.2.4  rmind static int rump_vop_remove(void *);
     69      1.19  pooka static int rump_vop_mknod(void *);
     70      1.26  pooka static int rump_vop_create(void *);
     71      1.14  pooka static int rump_vop_inactive(void *);
     72      1.12  pooka static int rump_vop_reclaim(void *);
     73       1.9  pooka static int rump_vop_success(void *);
     74  1.37.2.2  rmind static int rump_vop_readdir(void *);
     75      1.19  pooka static int rump_vop_spec(void *);
     76      1.24  pooka static int rump_vop_read(void *);
     77      1.24  pooka static int rump_vop_write(void *);
     78      1.24  pooka static int rump_vop_open(void *);
     79  1.37.2.3  rmind static int rump_vop_symlink(void *);
     80  1.37.2.3  rmind static int rump_vop_readlink(void *);
     81  1.37.2.4  rmind static int rump_vop_whiteout(void *);
     82  1.37.2.4  rmind static int rump_vop_pathconf(void *);
     83  1.37.2.4  rmind static int rump_vop_bmap(void *);
     84  1.37.2.4  rmind static int rump_vop_strategy(void *);
     85  1.37.2.4  rmind static int rump_vop_advlock(void *);
     86  1.37.2.4  rmind static int rump_vop_access(void *);
     87       1.1  pooka 
     88       1.1  pooka int (**fifo_vnodeop_p)(void *);
     89       1.1  pooka const struct vnodeopv_entry_desc fifo_vnodeop_entries[] = {
     90       1.1  pooka 	{ &vop_default_desc, vn_default_error },
     91       1.1  pooka 	{ NULL, NULL }
     92       1.1  pooka };
     93       1.1  pooka const struct vnodeopv_desc fifo_vnodeop_opv_desc =
     94       1.1  pooka 	{ &fifo_vnodeop_p, fifo_vnodeop_entries };
     95       1.1  pooka 
     96       1.1  pooka int (**rump_vnodeop_p)(void *);
     97       1.1  pooka const struct vnodeopv_entry_desc rump_vnodeop_entries[] = {
     98       1.1  pooka 	{ &vop_default_desc, vn_default_error },
     99       1.1  pooka 	{ &vop_lookup_desc, rump_vop_lookup },
    100       1.9  pooka 	{ &vop_getattr_desc, rump_vop_getattr },
    101  1.37.2.4  rmind 	{ &vop_setattr_desc, rump_vop_setattr },
    102      1.14  pooka 	{ &vop_mkdir_desc, rump_vop_mkdir },
    103  1.37.2.3  rmind 	{ &vop_rmdir_desc, rump_vop_rmdir },
    104  1.37.2.4  rmind 	{ &vop_remove_desc, rump_vop_remove },
    105      1.19  pooka 	{ &vop_mknod_desc, rump_vop_mknod },
    106      1.26  pooka 	{ &vop_create_desc, rump_vop_create },
    107  1.37.2.3  rmind 	{ &vop_symlink_desc, rump_vop_symlink },
    108  1.37.2.3  rmind 	{ &vop_readlink_desc, rump_vop_readlink },
    109  1.37.2.4  rmind 	{ &vop_access_desc, rump_vop_access },
    110  1.37.2.2  rmind 	{ &vop_readdir_desc, rump_vop_readdir },
    111      1.24  pooka 	{ &vop_read_desc, rump_vop_read },
    112      1.24  pooka 	{ &vop_write_desc, rump_vop_write },
    113      1.24  pooka 	{ &vop_open_desc, rump_vop_open },
    114  1.37.2.4  rmind 	{ &vop_close_desc, genfs_nullop },
    115  1.37.2.3  rmind 	{ &vop_seek_desc, genfs_seek },
    116  1.37.2.4  rmind 	{ &vop_getpages_desc, genfs_getpages },
    117  1.37.2.4  rmind 	{ &vop_putpages_desc, genfs_putpages },
    118  1.37.2.4  rmind 	{ &vop_whiteout_desc, rump_vop_whiteout },
    119       1.9  pooka 	{ &vop_fsync_desc, rump_vop_success },
    120       1.1  pooka 	{ &vop_lock_desc, genfs_lock },
    121       1.1  pooka 	{ &vop_unlock_desc, genfs_unlock },
    122  1.37.2.2  rmind 	{ &vop_islocked_desc, genfs_islocked },
    123      1.14  pooka 	{ &vop_inactive_desc, rump_vop_inactive },
    124      1.12  pooka 	{ &vop_reclaim_desc, rump_vop_reclaim },
    125  1.37.2.4  rmind 	{ &vop_link_desc, genfs_eopnotsupp },
    126  1.37.2.4  rmind 	{ &vop_pathconf_desc, rump_vop_pathconf },
    127  1.37.2.4  rmind 	{ &vop_bmap_desc, rump_vop_bmap },
    128  1.37.2.4  rmind 	{ &vop_strategy_desc, rump_vop_strategy },
    129  1.37.2.4  rmind 	{ &vop_advlock_desc, rump_vop_advlock },
    130       1.1  pooka 	{ NULL, NULL }
    131       1.1  pooka };
    132       1.1  pooka const struct vnodeopv_desc rump_vnodeop_opv_desc =
    133       1.1  pooka 	{ &rump_vnodeop_p, rump_vnodeop_entries };
    134      1.19  pooka 
    135      1.19  pooka int (**rump_specop_p)(void *);
    136      1.19  pooka const struct vnodeopv_entry_desc rump_specop_entries[] = {
    137      1.19  pooka 	{ &vop_default_desc, rump_vop_spec },
    138      1.19  pooka 	{ NULL, NULL }
    139      1.19  pooka };
    140      1.19  pooka const struct vnodeopv_desc rump_specop_opv_desc =
    141      1.19  pooka 	{ &rump_specop_p, rump_specop_entries };
    142      1.19  pooka 
    143       1.1  pooka const struct vnodeopv_desc * const rump_opv_descs[] = {
    144       1.1  pooka 	&rump_vnodeop_opv_desc,
    145      1.19  pooka 	&rump_specop_opv_desc,
    146       1.1  pooka 	NULL
    147       1.1  pooka };
    148       1.1  pooka 
    149  1.37.2.4  rmind #define RUMPFS_WHITEOUT ((void *)-1)
    150  1.37.2.4  rmind #define RDENT_ISWHITEOUT(rdp) (rdp->rd_node == RUMPFS_WHITEOUT)
    151      1.14  pooka struct rumpfs_dent {
    152      1.14  pooka 	char *rd_name;
    153  1.37.2.2  rmind 	int rd_namelen;
    154      1.14  pooka 	struct rumpfs_node *rd_node;
    155      1.14  pooka 
    156      1.14  pooka 	LIST_ENTRY(rumpfs_dent) rd_entries;
    157      1.14  pooka };
    158      1.14  pooka 
    159  1.37.2.4  rmind struct genfs_ops rumpfs_genfsops = {
    160  1.37.2.4  rmind 	.gop_size = genfs_size,
    161  1.37.2.4  rmind 	.gop_write = genfs_gop_write,
    162  1.37.2.4  rmind 
    163  1.37.2.4  rmind 	/* optional */
    164  1.37.2.4  rmind 	.gop_alloc = NULL,
    165  1.37.2.4  rmind 	.gop_markupdate = NULL,
    166  1.37.2.4  rmind };
    167  1.37.2.4  rmind 
    168      1.14  pooka struct rumpfs_node {
    169  1.37.2.4  rmind 	struct genfs_node rn_gn;
    170      1.14  pooka 	struct vattr rn_va;
    171      1.14  pooka 	struct vnode *rn_vp;
    172  1.37.2.2  rmind 	char *rn_hostpath;
    173  1.37.2.2  rmind 	int rn_flags;
    174  1.37.2.4  rmind 	struct lockf *rn_lockf;
    175      1.14  pooka 
    176      1.24  pooka 	union {
    177  1.37.2.2  rmind 		struct {		/* VREG */
    178      1.24  pooka 			int readfd;
    179      1.24  pooka 			int writefd;
    180      1.27  pooka 			uint64_t offset;
    181      1.24  pooka 		} reg;
    182  1.37.2.4  rmind 		struct {
    183  1.37.2.4  rmind 			void *data;
    184  1.37.2.4  rmind 			size_t dlen;
    185  1.37.2.4  rmind 		} reg_noet;
    186  1.37.2.2  rmind 		struct {		/* VDIR */
    187  1.37.2.2  rmind 			LIST_HEAD(, rumpfs_dent) dents;
    188  1.37.2.4  rmind 			struct rumpfs_node *parent;
    189  1.37.2.2  rmind 			int flags;
    190  1.37.2.2  rmind 		} dir;
    191  1.37.2.3  rmind 		struct {
    192  1.37.2.3  rmind 			char *target;
    193  1.37.2.3  rmind 			size_t len;
    194  1.37.2.3  rmind 		} link;
    195      1.24  pooka 	} rn_u;
    196      1.14  pooka };
    197      1.24  pooka #define rn_readfd	rn_u.reg.readfd
    198      1.24  pooka #define rn_writefd	rn_u.reg.writefd
    199      1.27  pooka #define rn_offset	rn_u.reg.offset
    200  1.37.2.4  rmind #define rn_data		rn_u.reg_noet.data
    201  1.37.2.4  rmind #define rn_dlen		rn_u.reg_noet.dlen
    202  1.37.2.2  rmind #define rn_dir		rn_u.dir.dents
    203  1.37.2.4  rmind #define rn_parent	rn_u.dir.parent
    204  1.37.2.3  rmind #define rn_linktarg	rn_u.link.target
    205  1.37.2.3  rmind #define rn_linklen	rn_u.link.len
    206  1.37.2.2  rmind 
    207  1.37.2.2  rmind #define RUMPNODE_CANRECLAIM	0x01
    208  1.37.2.2  rmind #define RUMPNODE_DIR_ET		0x02
    209  1.37.2.2  rmind #define RUMPNODE_DIR_ETSUBS	0x04
    210  1.37.2.4  rmind #define RUMPNODE_ET_PHONE_HOST	0x10
    211      1.14  pooka 
    212      1.30  pooka struct rumpfs_mount {
    213      1.30  pooka 	struct vnode *rfsmp_rvp;
    214      1.30  pooka };
    215      1.30  pooka 
    216  1.37.2.4  rmind #define INO_WHITEOUT 1
    217  1.37.2.4  rmind static int lastino = 2;
    218  1.37.2.4  rmind static kmutex_t reclock;
    219  1.37.2.4  rmind 
    220  1.37.2.4  rmind static struct rumpfs_node *makeprivate(enum vtype, dev_t, off_t, bool);
    221      1.21  pooka 
    222      1.21  pooka /*
    223      1.21  pooka  * Extra Terrestrial stuff.  We map a given key (pathname) to a file on
    224      1.21  pooka  * the host FS.  ET phones home only from the root node of rumpfs.
    225      1.21  pooka  *
    226      1.21  pooka  * When an etfs node is removed, a vnode potentially behind it is not
    227      1.21  pooka  * immediately recycled.
    228      1.21  pooka  */
    229      1.21  pooka 
    230      1.21  pooka struct etfs {
    231      1.21  pooka 	char et_key[MAXPATHLEN];
    232      1.24  pooka 	size_t et_keylen;
    233  1.37.2.2  rmind 	bool et_prefixkey;
    234  1.37.2.3  rmind 	bool et_removing;
    235  1.37.2.3  rmind 	devminor_t et_blkmin;
    236      1.24  pooka 
    237      1.21  pooka 	LIST_ENTRY(etfs) et_entries;
    238      1.21  pooka 
    239      1.21  pooka 	struct rumpfs_node *et_rn;
    240      1.21  pooka };
    241      1.21  pooka static kmutex_t etfs_lock;
    242      1.21  pooka static LIST_HEAD(, etfs) etfs_list = LIST_HEAD_INITIALIZER(etfs_list);
    243      1.21  pooka 
    244      1.21  pooka static enum vtype
    245      1.21  pooka ettype_to_vtype(enum rump_etfs_type et)
    246      1.21  pooka {
    247      1.21  pooka 	enum vtype vt;
    248      1.21  pooka 
    249      1.21  pooka 	switch (et) {
    250      1.21  pooka 	case RUMP_ETFS_REG:
    251      1.21  pooka 		vt = VREG;
    252      1.21  pooka 		break;
    253      1.21  pooka 	case RUMP_ETFS_BLK:
    254      1.21  pooka 		vt = VBLK;
    255      1.21  pooka 		break;
    256      1.21  pooka 	case RUMP_ETFS_CHR:
    257      1.21  pooka 		vt = VCHR;
    258      1.21  pooka 		break;
    259  1.37.2.2  rmind 	case RUMP_ETFS_DIR:
    260  1.37.2.2  rmind 		vt = VDIR;
    261  1.37.2.2  rmind 		break;
    262  1.37.2.2  rmind 	case RUMP_ETFS_DIR_SUBDIRS:
    263  1.37.2.2  rmind 		vt = VDIR;
    264  1.37.2.2  rmind 		break;
    265      1.21  pooka 	default:
    266      1.21  pooka 		panic("invalid et type: %d", et);
    267      1.21  pooka 	}
    268      1.21  pooka 
    269      1.21  pooka 	return vt;
    270      1.21  pooka }
    271      1.21  pooka 
    272  1.37.2.2  rmind static enum vtype
    273  1.37.2.2  rmind hft_to_vtype(int hft)
    274  1.37.2.2  rmind {
    275  1.37.2.2  rmind 	enum vtype vt;
    276  1.37.2.2  rmind 
    277  1.37.2.2  rmind 	switch (hft) {
    278  1.37.2.2  rmind 	case RUMPUSER_FT_OTHER:
    279  1.37.2.2  rmind 		vt = VNON;
    280  1.37.2.2  rmind 		break;
    281  1.37.2.2  rmind 	case RUMPUSER_FT_DIR:
    282  1.37.2.2  rmind 		vt = VDIR;
    283  1.37.2.2  rmind 		break;
    284  1.37.2.2  rmind 	case RUMPUSER_FT_REG:
    285  1.37.2.2  rmind 		vt = VREG;
    286  1.37.2.2  rmind 		break;
    287  1.37.2.2  rmind 	case RUMPUSER_FT_BLK:
    288  1.37.2.2  rmind 		vt = VBLK;
    289  1.37.2.2  rmind 		break;
    290  1.37.2.2  rmind 	case RUMPUSER_FT_CHR:
    291  1.37.2.2  rmind 		vt = VCHR;
    292  1.37.2.2  rmind 		break;
    293  1.37.2.2  rmind 	default:
    294  1.37.2.2  rmind 		vt = VNON;
    295  1.37.2.2  rmind 		break;
    296  1.37.2.2  rmind 	}
    297  1.37.2.2  rmind 
    298  1.37.2.2  rmind 	return vt;
    299  1.37.2.2  rmind }
    300  1.37.2.2  rmind 
    301      1.21  pooka static bool
    302  1.37.2.2  rmind etfs_find(const char *key, struct etfs **etp, bool forceprefix)
    303      1.21  pooka {
    304      1.21  pooka 	struct etfs *et;
    305      1.24  pooka 	size_t keylen = strlen(key);
    306      1.21  pooka 
    307      1.21  pooka 	KASSERT(mutex_owned(&etfs_lock));
    308      1.21  pooka 
    309      1.21  pooka 	LIST_FOREACH(et, &etfs_list, et_entries) {
    310  1.37.2.2  rmind 		if ((keylen == et->et_keylen || et->et_prefixkey || forceprefix)
    311  1.37.2.2  rmind 		    && strncmp(key, et->et_key, et->et_keylen) == 0) {
    312  1.37.2.2  rmind 			if (etp)
    313  1.37.2.2  rmind 				*etp = et;
    314  1.37.2.2  rmind 			return true;
    315      1.21  pooka 		}
    316      1.21  pooka 	}
    317      1.21  pooka 
    318  1.37.2.2  rmind 	return false;
    319      1.21  pooka }
    320      1.21  pooka 
    321  1.37.2.2  rmind #define REGDIR(ftype) \
    322  1.37.2.2  rmind     ((ftype) == RUMP_ETFS_DIR || (ftype) == RUMP_ETFS_DIR_SUBDIRS)
    323      1.25  pooka static int
    324      1.25  pooka doregister(const char *key, const char *hostpath,
    325      1.25  pooka 	enum rump_etfs_type ftype, uint64_t begin, uint64_t size)
    326      1.21  pooka {
    327  1.37.2.4  rmind 	char buf[9];
    328      1.21  pooka 	struct etfs *et;
    329  1.37.2.2  rmind 	struct rumpfs_node *rn;
    330      1.21  pooka 	uint64_t fsize;
    331      1.24  pooka 	dev_t rdev = NODEV;
    332  1.37.2.3  rmind 	devminor_t dmin = -1;
    333      1.21  pooka 	int hft, error;
    334      1.21  pooka 
    335  1.37.2.4  rmind 	if (key[0] != '/') {
    336  1.37.2.4  rmind 		return EINVAL;
    337  1.37.2.4  rmind 	}
    338  1.37.2.4  rmind 	while (key[0] == '/') {
    339  1.37.2.4  rmind 		key++;
    340  1.37.2.4  rmind 	}
    341  1.37.2.4  rmind 
    342      1.21  pooka 	if (rumpuser_getfileinfo(hostpath, &fsize, &hft, &error))
    343      1.21  pooka 		return error;
    344      1.21  pooka 
    345  1.37.2.2  rmind 	/* etfs directory requires a directory on the host */
    346  1.37.2.2  rmind 	if (REGDIR(ftype)) {
    347  1.37.2.2  rmind 		if (hft != RUMPUSER_FT_DIR)
    348  1.37.2.2  rmind 			return ENOTDIR;
    349  1.37.2.2  rmind 		if (begin != 0)
    350  1.37.2.2  rmind 			return EISDIR;
    351  1.37.2.2  rmind 		if (size != RUMP_ETFS_SIZE_ENDOFF)
    352  1.37.2.2  rmind 			return EISDIR;
    353  1.37.2.2  rmind 		size = fsize;
    354  1.37.2.2  rmind 	} else {
    355  1.37.2.2  rmind 		if (begin > fsize)
    356  1.37.2.2  rmind 			return EINVAL;
    357  1.37.2.2  rmind 		if (size == RUMP_ETFS_SIZE_ENDOFF)
    358  1.37.2.2  rmind 			size = fsize - begin;
    359  1.37.2.2  rmind 		if (begin + size > fsize)
    360  1.37.2.2  rmind 			return EINVAL;
    361  1.37.2.2  rmind 	}
    362      1.25  pooka 
    363      1.24  pooka 	if (ftype == RUMP_ETFS_BLK || ftype == RUMP_ETFS_CHR) {
    364      1.25  pooka 		error = rumpblk_register(hostpath, &dmin, begin, size);
    365      1.24  pooka 		if (error != 0) {
    366      1.24  pooka 			return error;
    367      1.24  pooka 		}
    368  1.37.2.2  rmind 		rdev = makedev(RUMPBLK_DEVMAJOR, dmin);
    369      1.21  pooka 	}
    370      1.21  pooka 
    371      1.21  pooka 	et = kmem_alloc(sizeof(*et), KM_SLEEP);
    372      1.21  pooka 	strcpy(et->et_key, key);
    373      1.24  pooka 	et->et_keylen = strlen(et->et_key);
    374  1.37.2.4  rmind 	et->et_rn = rn = makeprivate(ettype_to_vtype(ftype), rdev, size, true);
    375  1.37.2.3  rmind 	et->et_removing = false;
    376  1.37.2.3  rmind 	et->et_blkmin = dmin;
    377  1.37.2.2  rmind 
    378  1.37.2.4  rmind 	rn->rn_flags |= RUMPNODE_ET_PHONE_HOST;
    379  1.37.2.4  rmind 
    380  1.37.2.3  rmind 	if (ftype == RUMP_ETFS_REG || REGDIR(ftype) || et->et_blkmin != -1) {
    381      1.27  pooka 		size_t len = strlen(hostpath)+1;
    382      1.27  pooka 
    383      1.27  pooka 		rn->rn_hostpath = malloc(len, M_TEMP, M_WAITOK | M_ZERO);
    384      1.27  pooka 		memcpy(rn->rn_hostpath, hostpath, len);
    385      1.27  pooka 		rn->rn_offset = begin;
    386      1.27  pooka 	}
    387      1.21  pooka 
    388  1.37.2.2  rmind 	if (REGDIR(ftype)) {
    389  1.37.2.2  rmind 		rn->rn_flags |= RUMPNODE_DIR_ET;
    390  1.37.2.2  rmind 		et->et_prefixkey = true;
    391  1.37.2.2  rmind 	} else {
    392  1.37.2.2  rmind 		et->et_prefixkey = false;
    393  1.37.2.2  rmind 	}
    394  1.37.2.2  rmind 
    395  1.37.2.2  rmind 	if (ftype == RUMP_ETFS_DIR_SUBDIRS)
    396  1.37.2.2  rmind 		rn->rn_flags |= RUMPNODE_DIR_ETSUBS;
    397  1.37.2.2  rmind 
    398      1.21  pooka 	mutex_enter(&etfs_lock);
    399  1.37.2.2  rmind 	if (etfs_find(key, NULL, REGDIR(ftype))) {
    400      1.21  pooka 		mutex_exit(&etfs_lock);
    401  1.37.2.3  rmind 		if (et->et_blkmin != -1)
    402  1.37.2.3  rmind 			rumpblk_deregister(hostpath);
    403  1.37.2.3  rmind 		if (et->et_rn->rn_hostpath != NULL)
    404  1.37.2.3  rmind 			free(et->et_rn->rn_hostpath, M_TEMP);
    405  1.37.2.3  rmind 		kmem_free(et->et_rn, sizeof(*et->et_rn));
    406      1.21  pooka 		kmem_free(et, sizeof(*et));
    407      1.21  pooka 		return EEXIST;
    408      1.21  pooka 	}
    409      1.21  pooka 	LIST_INSERT_HEAD(&etfs_list, et, et_entries);
    410      1.21  pooka 	mutex_exit(&etfs_lock);
    411      1.21  pooka 
    412  1.37.2.4  rmind 	if (ftype == RUMP_ETFS_BLK) {
    413  1.37.2.4  rmind 		format_bytes(buf, sizeof(buf), size);
    414  1.37.2.4  rmind 		aprint_verbose("/%s: hostpath %s (%s)\n", key, hostpath, buf);
    415  1.37.2.4  rmind 	}
    416  1.37.2.4  rmind 
    417      1.21  pooka 	return 0;
    418      1.21  pooka }
    419  1.37.2.2  rmind #undef REGDIR
    420      1.21  pooka 
    421      1.21  pooka int
    422      1.29  pooka rump_etfs_register(const char *key, const char *hostpath,
    423      1.25  pooka 	enum rump_etfs_type ftype)
    424      1.25  pooka {
    425      1.25  pooka 
    426      1.25  pooka 	return doregister(key, hostpath, ftype, 0, RUMP_ETFS_SIZE_ENDOFF);
    427      1.25  pooka }
    428      1.25  pooka 
    429      1.25  pooka int
    430      1.29  pooka rump_etfs_register_withsize(const char *key, const char *hostpath,
    431      1.25  pooka 	enum rump_etfs_type ftype, uint64_t begin, uint64_t size)
    432      1.25  pooka {
    433      1.25  pooka 
    434      1.25  pooka 	return doregister(key, hostpath, ftype, begin, size);
    435      1.25  pooka }
    436      1.25  pooka 
    437  1.37.2.3  rmind /* remove etfs mapping.  caller's responsibility to make sure it's not in use */
    438      1.25  pooka int
    439      1.29  pooka rump_etfs_remove(const char *key)
    440      1.21  pooka {
    441      1.21  pooka 	struct etfs *et;
    442  1.37.2.4  rmind 	size_t keylen;
    443  1.37.2.3  rmind 	int rv;
    444      1.21  pooka 
    445  1.37.2.4  rmind 	if (key[0] != '/') {
    446  1.37.2.4  rmind 		return EINVAL;
    447  1.37.2.4  rmind 	}
    448  1.37.2.4  rmind 	while (key[0] == '/') {
    449  1.37.2.4  rmind 		key++;
    450  1.37.2.4  rmind 	}
    451  1.37.2.4  rmind 
    452  1.37.2.4  rmind 	keylen = strlen(key);
    453  1.37.2.4  rmind 
    454      1.21  pooka 	mutex_enter(&etfs_lock);
    455      1.21  pooka 	LIST_FOREACH(et, &etfs_list, et_entries) {
    456      1.24  pooka 		if (keylen == et->et_keylen && strcmp(et->et_key, key) == 0) {
    457  1.37.2.3  rmind 			if (et->et_removing)
    458  1.37.2.3  rmind 				et = NULL;
    459  1.37.2.3  rmind 			else
    460  1.37.2.3  rmind 				et->et_removing = true;
    461      1.21  pooka 			break;
    462      1.21  pooka 		}
    463      1.21  pooka 	}
    464      1.21  pooka 	mutex_exit(&etfs_lock);
    465      1.21  pooka 	if (!et)
    466      1.21  pooka 		return ENOENT;
    467  1.37.2.3  rmind 
    468  1.37.2.3  rmind 	/*
    469  1.37.2.3  rmind 	 * ok, we know what we want to remove and have signalled there
    470  1.37.2.3  rmind 	 * actually are men at work.  first, unregister from rumpblk
    471  1.37.2.3  rmind 	 */
    472  1.37.2.3  rmind 	if (et->et_blkmin != -1) {
    473  1.37.2.3  rmind 		rv = rumpblk_deregister(et->et_rn->rn_hostpath);
    474  1.37.2.3  rmind 	} else {
    475  1.37.2.3  rmind 		rv = 0;
    476  1.37.2.3  rmind 	}
    477  1.37.2.3  rmind 	KASSERT(rv == 0);
    478  1.37.2.3  rmind 
    479  1.37.2.3  rmind 	/* then do the actual removal */
    480  1.37.2.3  rmind 	mutex_enter(&etfs_lock);
    481  1.37.2.3  rmind 	LIST_REMOVE(et, et_entries);
    482  1.37.2.3  rmind 	mutex_exit(&etfs_lock);
    483  1.37.2.3  rmind 
    484  1.37.2.3  rmind 	/* node is unreachable, safe to nuke all device copies */
    485  1.37.2.4  rmind 	if (et->et_blkmin != -1) {
    486  1.37.2.3  rmind 		vdevgone(RUMPBLK_DEVMAJOR, et->et_blkmin, et->et_blkmin, VBLK);
    487  1.37.2.4  rmind 	} else {
    488  1.37.2.4  rmind 		struct vnode *vp;
    489  1.37.2.4  rmind 
    490  1.37.2.4  rmind 		mutex_enter(&reclock);
    491  1.37.2.4  rmind 		if ((vp = et->et_rn->rn_vp) != NULL)
    492  1.37.2.4  rmind 			mutex_enter(&vp->v_interlock);
    493  1.37.2.4  rmind 		mutex_exit(&reclock);
    494  1.37.2.4  rmind 		if (vp && vget(vp, 0) == 0)
    495  1.37.2.4  rmind 			vgone(vp);
    496  1.37.2.4  rmind 	}
    497  1.37.2.3  rmind 
    498  1.37.2.3  rmind 	if (et->et_rn->rn_hostpath != NULL)
    499  1.37.2.3  rmind 		free(et->et_rn->rn_hostpath, M_TEMP);
    500  1.37.2.3  rmind 	kmem_free(et->et_rn, sizeof(*et->et_rn));
    501  1.37.2.3  rmind 	kmem_free(et, sizeof(*et));
    502  1.37.2.3  rmind 
    503      1.21  pooka 	return 0;
    504      1.21  pooka }
    505      1.21  pooka 
    506      1.21  pooka /*
    507      1.21  pooka  * rumpfs
    508      1.21  pooka  */
    509      1.21  pooka 
    510      1.14  pooka static struct rumpfs_node *
    511  1.37.2.4  rmind makeprivate(enum vtype vt, dev_t rdev, off_t size, bool et)
    512       1.9  pooka {
    513      1.14  pooka 	struct rumpfs_node *rn;
    514       1.9  pooka 	struct vattr *va;
    515       1.9  pooka 	struct timespec ts;
    516       1.9  pooka 
    517      1.23  pooka 	rn = kmem_zalloc(sizeof(*rn), KM_SLEEP);
    518      1.24  pooka 
    519      1.24  pooka 	switch (vt) {
    520      1.24  pooka 	case VDIR:
    521      1.24  pooka 		LIST_INIT(&rn->rn_dir);
    522      1.24  pooka 		break;
    523      1.24  pooka 	case VREG:
    524  1.37.2.4  rmind 		if (et) {
    525  1.37.2.4  rmind 			rn->rn_readfd = -1;
    526  1.37.2.4  rmind 			rn->rn_writefd = -1;
    527  1.37.2.4  rmind 		}
    528      1.24  pooka 		break;
    529      1.24  pooka 	default:
    530      1.24  pooka 		break;
    531      1.24  pooka 	}
    532      1.24  pooka 
    533       1.9  pooka 	nanotime(&ts);
    534       1.9  pooka 
    535      1.14  pooka 	va = &rn->rn_va;
    536       1.9  pooka 	va->va_type = vt;
    537       1.9  pooka 	va->va_mode = 0755;
    538      1.14  pooka 	if (vt == VDIR)
    539      1.14  pooka 		va->va_nlink = 2;
    540      1.14  pooka 	else
    541      1.14  pooka 		va->va_nlink = 1;
    542       1.9  pooka 	va->va_uid = 0;
    543       1.9  pooka 	va->va_gid = 0;
    544       1.9  pooka 	va->va_fsid =
    545       1.9  pooka 	va->va_fileid = atomic_inc_uint_nv(&lastino);
    546      1.19  pooka 	va->va_size = size;
    547       1.9  pooka 	va->va_blocksize = 512;
    548       1.9  pooka 	va->va_atime = ts;
    549       1.9  pooka 	va->va_mtime = ts;
    550       1.9  pooka 	va->va_ctime = ts;
    551       1.9  pooka 	va->va_birthtime = ts;
    552       1.9  pooka 	va->va_gen = 0;
    553       1.9  pooka 	va->va_flags = 0;
    554      1.19  pooka 	va->va_rdev = rdev;
    555       1.9  pooka 	va->va_bytes = 512;
    556       1.9  pooka 	va->va_filerev = 0;
    557       1.9  pooka 	va->va_vaflags = 0;
    558       1.9  pooka 
    559      1.14  pooka 	return rn;
    560       1.9  pooka }
    561       1.1  pooka 
    562       1.6  pooka static int
    563      1.30  pooka makevnode(struct mount *mp, struct rumpfs_node *rn, struct vnode **vpp)
    564       1.1  pooka {
    565       1.1  pooka 	struct vnode *vp;
    566      1.12  pooka 	int (**vpops)(void *);
    567      1.21  pooka 	struct vattr *va = &rn->rn_va;
    568       1.6  pooka 	int rv;
    569       1.1  pooka 
    570  1.37.2.2  rmind 	KASSERT(!mutex_owned(&reclock));
    571      1.21  pooka 
    572      1.21  pooka 	if (va->va_type == VCHR || va->va_type == VBLK) {
    573      1.19  pooka 		vpops = rump_specop_p;
    574      1.12  pooka 	} else {
    575      1.12  pooka 		vpops = rump_vnodeop_p;
    576      1.12  pooka 	}
    577      1.12  pooka 
    578  1.37.2.6  rmind 	rv = getnewvnode(VT_RUMP, mp, vpops, NULL, &vp);
    579      1.12  pooka 	if (rv)
    580      1.12  pooka 		return rv;
    581      1.12  pooka 
    582      1.21  pooka 	vp->v_size = vp->v_writesize = va->va_size;
    583      1.21  pooka 	vp->v_type = va->va_type;
    584       1.1  pooka 
    585      1.21  pooka 	if (vpops == rump_specop_p) {
    586      1.21  pooka 		spec_node_init(vp, va->va_rdev);
    587      1.14  pooka 	}
    588      1.19  pooka 	vp->v_data = rn;
    589      1.14  pooka 
    590  1.37.2.4  rmind 	genfs_node_init(vp, &rumpfs_genfsops);
    591      1.14  pooka 	vn_lock(vp, LK_RETRY | LK_EXCLUSIVE);
    592  1.37.2.2  rmind 	mutex_enter(&reclock);
    593      1.21  pooka 	rn->rn_vp = vp;
    594  1.37.2.2  rmind 	mutex_exit(&reclock);
    595  1.37.2.2  rmind 
    596       1.6  pooka 	*vpp = vp;
    597       1.6  pooka 
    598       1.6  pooka 	return 0;
    599       1.1  pooka }
    600       1.1  pooka 
    601  1.37.2.2  rmind 
    602  1.37.2.2  rmind static void
    603  1.37.2.2  rmind makedir(struct rumpfs_node *rnd,
    604  1.37.2.2  rmind 	struct componentname *cnp, struct rumpfs_node *rn)
    605  1.37.2.2  rmind {
    606  1.37.2.2  rmind 	struct rumpfs_dent *rdent;
    607  1.37.2.2  rmind 
    608  1.37.2.2  rmind 	rdent = kmem_alloc(sizeof(*rdent), KM_SLEEP);
    609  1.37.2.2  rmind 	rdent->rd_name = kmem_alloc(cnp->cn_namelen+1, KM_SLEEP);
    610  1.37.2.2  rmind 	rdent->rd_node = rn;
    611  1.37.2.2  rmind 	strlcpy(rdent->rd_name, cnp->cn_nameptr, cnp->cn_namelen+1);
    612  1.37.2.2  rmind 	rdent->rd_namelen = strlen(rdent->rd_name);
    613  1.37.2.2  rmind 
    614  1.37.2.2  rmind 	LIST_INSERT_HEAD(&rnd->rn_dir, rdent, rd_entries);
    615  1.37.2.2  rmind }
    616  1.37.2.2  rmind 
    617  1.37.2.3  rmind static void
    618  1.37.2.3  rmind freedir(struct rumpfs_node *rnd, struct componentname *cnp)
    619  1.37.2.3  rmind {
    620  1.37.2.3  rmind 	struct rumpfs_dent *rd = NULL;
    621  1.37.2.3  rmind 
    622  1.37.2.3  rmind 	LIST_FOREACH(rd, &rnd->rn_dir, rd_entries) {
    623  1.37.2.3  rmind 		if (rd->rd_namelen == cnp->cn_namelen &&
    624  1.37.2.3  rmind 		    strncmp(rd->rd_name, cnp->cn_nameptr,
    625  1.37.2.3  rmind 		            cnp->cn_namelen) == 0)
    626  1.37.2.3  rmind 			break;
    627  1.37.2.3  rmind 	}
    628  1.37.2.3  rmind 	if (rd == NULL)
    629  1.37.2.3  rmind 		panic("could not find directory entry: %s", cnp->cn_nameptr);
    630  1.37.2.3  rmind 
    631  1.37.2.4  rmind 	if (cnp->cn_flags & DOWHITEOUT) {
    632  1.37.2.4  rmind 		rd->rd_node = RUMPFS_WHITEOUT;
    633  1.37.2.4  rmind 	} else {
    634  1.37.2.4  rmind 		LIST_REMOVE(rd, rd_entries);
    635  1.37.2.4  rmind 		kmem_free(rd->rd_name, rd->rd_namelen+1);
    636  1.37.2.4  rmind 		kmem_free(rd, sizeof(*rd));
    637  1.37.2.4  rmind 	}
    638  1.37.2.3  rmind }
    639  1.37.2.3  rmind 
    640       1.1  pooka /*
    641  1.37.2.3  rmind  * Simple lookup for rump file systems.
    642      1.21  pooka  *
    643      1.21  pooka  * uhm, this is twisted.  C F C C, hope of C C F C looming
    644       1.1  pooka  */
    645       1.1  pooka static int
    646       1.1  pooka rump_vop_lookup(void *v)
    647       1.1  pooka {
    648       1.1  pooka 	struct vop_lookup_args /* {
    649       1.1  pooka 		struct vnode *a_dvp;
    650       1.1  pooka 		struct vnode **a_vpp;
    651       1.1  pooka 		struct componentname *a_cnp;
    652       1.1  pooka 	}; */ *ap = v;
    653       1.1  pooka 	struct componentname *cnp = ap->a_cnp;
    654      1.14  pooka 	struct vnode *dvp = ap->a_dvp;
    655      1.14  pooka 	struct vnode **vpp = ap->a_vpp;
    656      1.14  pooka 	struct vnode *vp;
    657      1.21  pooka 	struct rumpfs_node *rnd = dvp->v_data, *rn;
    658      1.21  pooka 	struct rumpfs_dent *rd = NULL;
    659  1.37.2.2  rmind 	struct etfs *et;
    660  1.37.2.4  rmind 	bool dotdot = (cnp->cn_flags & ISDOTDOT) != 0;
    661  1.37.2.4  rmind 	int rv = 0;
    662       1.1  pooka 
    663  1.37.2.4  rmind 	*vpp = NULL;
    664  1.37.2.4  rmind 
    665  1.37.2.4  rmind 	if ((cnp->cn_flags & ISLASTCN)
    666  1.37.2.4  rmind 	    && (dvp->v_mount->mnt_flag & MNT_RDONLY)
    667  1.37.2.4  rmind 	    && (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME))
    668  1.37.2.4  rmind 		return EROFS;
    669      1.32  pooka 
    670      1.32  pooka 	/* check for dot, return directly if the case */
    671      1.32  pooka 	if (cnp->cn_namelen == 1 && cnp->cn_nameptr[0] == '.') {
    672      1.32  pooka 		vref(dvp);
    673      1.32  pooka 		*vpp = dvp;
    674  1.37.2.2  rmind 		return 0;
    675      1.32  pooka 	}
    676       1.1  pooka 
    677  1.37.2.4  rmind 	/* we don't do rename */
    678  1.37.2.4  rmind 	if (!(((cnp->cn_flags & ISLASTCN) == 0) || (cnp->cn_nameiop != RENAME)))
    679  1.37.2.4  rmind 		return EOPNOTSUPP;
    680  1.37.2.4  rmind 
    681  1.37.2.2  rmind 	/* check for etfs */
    682  1.37.2.4  rmind 	if (dvp == rootvnode &&
    683  1.37.2.4  rmind 	    (cnp->cn_nameiop == LOOKUP || cnp->cn_nameiop == CREATE)) {
    684  1.37.2.2  rmind 		bool found;
    685      1.21  pooka 		mutex_enter(&etfs_lock);
    686  1.37.2.4  rmind 		found = etfs_find(cnp->cn_nameptr, &et, false);
    687  1.37.2.2  rmind 		mutex_exit(&etfs_lock);
    688  1.37.2.2  rmind 
    689  1.37.2.2  rmind 		if (found) {
    690  1.37.2.2  rmind 			rn = et->et_rn;
    691  1.37.2.4  rmind 			cnp->cn_consume += et->et_keylen - cnp->cn_namelen;
    692  1.37.2.2  rmind 			if (rn->rn_va.va_type != VDIR)
    693  1.37.2.2  rmind 				cnp->cn_flags &= ~REQUIREDIR;
    694      1.21  pooka 			goto getvnode;
    695      1.14  pooka 		}
    696      1.14  pooka 	}
    697      1.14  pooka 
    698  1.37.2.2  rmind 	if (rnd->rn_flags & RUMPNODE_DIR_ET) {
    699  1.37.2.2  rmind 		uint64_t fsize;
    700  1.37.2.2  rmind 		char *newpath;
    701  1.37.2.2  rmind 		size_t newpathlen;
    702  1.37.2.2  rmind 		int hft, error;
    703  1.37.2.2  rmind 
    704  1.37.2.4  rmind 		if (dotdot)
    705  1.37.2.4  rmind 			return EOPNOTSUPP;
    706  1.37.2.4  rmind 
    707  1.37.2.2  rmind 		newpathlen = strlen(rnd->rn_hostpath) + 1 + cnp->cn_namelen + 1;
    708  1.37.2.2  rmind 		newpath = malloc(newpathlen, M_TEMP, M_WAITOK);
    709  1.37.2.2  rmind 
    710  1.37.2.2  rmind 		strlcpy(newpath, rnd->rn_hostpath, newpathlen);
    711  1.37.2.2  rmind 		strlcat(newpath, "/", newpathlen);
    712  1.37.2.2  rmind 		strlcat(newpath, cnp->cn_nameptr, newpathlen);
    713  1.37.2.2  rmind 
    714  1.37.2.2  rmind 		if (rumpuser_getfileinfo(newpath, &fsize, &hft, &error)) {
    715  1.37.2.2  rmind 			free(newpath, M_TEMP);
    716  1.37.2.2  rmind 			return error;
    717  1.37.2.2  rmind 		}
    718  1.37.2.2  rmind 
    719  1.37.2.2  rmind 		/* allow only dirs and regular files */
    720  1.37.2.2  rmind 		if (hft != RUMPUSER_FT_REG && hft != RUMPUSER_FT_DIR) {
    721  1.37.2.2  rmind 			free(newpath, M_TEMP);
    722  1.37.2.2  rmind 			return ENOENT;
    723  1.37.2.2  rmind 		}
    724  1.37.2.2  rmind 
    725  1.37.2.4  rmind 		rn = makeprivate(hft_to_vtype(hft), NODEV, fsize, true);
    726  1.37.2.2  rmind 		rn->rn_flags |= RUMPNODE_CANRECLAIM;
    727  1.37.2.2  rmind 		if (rnd->rn_flags & RUMPNODE_DIR_ETSUBS) {
    728  1.37.2.2  rmind 			rn->rn_flags |= RUMPNODE_DIR_ET | RUMPNODE_DIR_ETSUBS;
    729  1.37.2.4  rmind 			rn->rn_flags |= RUMPNODE_ET_PHONE_HOST;
    730  1.37.2.2  rmind 		}
    731  1.37.2.2  rmind 		rn->rn_hostpath = newpath;
    732  1.37.2.2  rmind 
    733  1.37.2.2  rmind 		goto getvnode;
    734  1.37.2.2  rmind 	} else {
    735  1.37.2.4  rmind 		if (dotdot) {
    736  1.37.2.4  rmind 			if ((rn = rnd->rn_parent) != NULL)
    737  1.37.2.4  rmind 				goto getvnode;
    738  1.37.2.4  rmind 		} else {
    739  1.37.2.4  rmind 			LIST_FOREACH(rd, &rnd->rn_dir, rd_entries) {
    740  1.37.2.4  rmind 				if (rd->rd_namelen == cnp->cn_namelen &&
    741  1.37.2.4  rmind 				    strncmp(rd->rd_name, cnp->cn_nameptr,
    742  1.37.2.4  rmind 				      cnp->cn_namelen) == 0)
    743  1.37.2.4  rmind 					break;
    744  1.37.2.4  rmind 			}
    745      1.21  pooka 		}
    746      1.14  pooka 	}
    747      1.14  pooka 
    748      1.14  pooka 	if (!rd && ((cnp->cn_flags & ISLASTCN) == 0||cnp->cn_nameiop != CREATE))
    749      1.14  pooka 		return ENOENT;
    750      1.14  pooka 
    751      1.14  pooka 	if (!rd && (cnp->cn_flags & ISLASTCN) && cnp->cn_nameiop == CREATE) {
    752  1.37.2.4  rmind 		if (dvp->v_mount->mnt_flag & MNT_RDONLY)
    753  1.37.2.4  rmind 			return EROFS;
    754      1.14  pooka 		return EJUSTRETURN;
    755       1.7  pooka 	}
    756  1.37.2.4  rmind 
    757  1.37.2.4  rmind 	if (RDENT_ISWHITEOUT(rd)) {
    758  1.37.2.4  rmind 		cnp->cn_flags |= ISWHITEOUT;
    759  1.37.2.4  rmind 		return ENOENT;
    760  1.37.2.4  rmind 	}
    761  1.37.2.3  rmind 
    762      1.21  pooka 	rn = rd->rd_node;
    763       1.1  pooka 
    764      1.21  pooka  getvnode:
    765      1.21  pooka 	KASSERT(rn);
    766  1.37.2.4  rmind 	if (dotdot)
    767  1.37.2.4  rmind 		VOP_UNLOCK(dvp);
    768      1.14  pooka 	mutex_enter(&reclock);
    769      1.21  pooka 	if ((vp = rn->rn_vp)) {
    770  1.37.2.1  rmind 		mutex_enter(vp->v_interlock);
    771      1.14  pooka 		mutex_exit(&reclock);
    772  1.37.2.4  rmind 		if (vget(vp, LK_EXCLUSIVE)) {
    773  1.37.2.4  rmind 			vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY);
    774      1.21  pooka 			goto getvnode;
    775  1.37.2.4  rmind 		}
    776      1.14  pooka 		*vpp = vp;
    777      1.14  pooka 	} else {
    778      1.21  pooka 		mutex_exit(&reclock);
    779  1.37.2.2  rmind 		rv = makevnode(dvp->v_mount, rn, vpp);
    780  1.37.2.4  rmind 	}
    781  1.37.2.4  rmind 	if (dotdot)
    782  1.37.2.4  rmind 		vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY);
    783  1.37.2.4  rmind 
    784  1.37.2.4  rmind 	return rv;
    785  1.37.2.4  rmind }
    786  1.37.2.4  rmind 
    787  1.37.2.4  rmind int
    788  1.37.2.4  rmind rump_vop_access(void *v)
    789  1.37.2.4  rmind {
    790  1.37.2.4  rmind 	struct vop_access_args /* {
    791  1.37.2.4  rmind 		const struct vnodeop_desc *a_desc;
    792  1.37.2.4  rmind 		struct vnode *a_vp;
    793  1.37.2.4  rmind 		int a_mode;
    794  1.37.2.4  rmind 		kauth_cred_t a_cred;
    795  1.37.2.4  rmind 	} */ *ap = v;
    796  1.37.2.4  rmind 	struct vnode *vp = ap->a_vp;
    797  1.37.2.4  rmind 	int mode = ap->a_mode;
    798  1.37.2.4  rmind 
    799  1.37.2.4  rmind 	if (mode & VWRITE) {
    800  1.37.2.4  rmind 		switch (vp->v_type) {
    801  1.37.2.4  rmind 		case VDIR:
    802  1.37.2.4  rmind 		case VLNK:
    803  1.37.2.4  rmind 		case VREG:
    804  1.37.2.4  rmind 			if ((vp->v_mount->mnt_flag & MNT_RDONLY))
    805  1.37.2.4  rmind 				return EROFS;
    806  1.37.2.4  rmind 			break;
    807  1.37.2.4  rmind 		default:
    808  1.37.2.4  rmind 			break;
    809  1.37.2.4  rmind 		}
    810      1.14  pooka 	}
    811       1.1  pooka 
    812       1.1  pooka 	return 0;
    813       1.1  pooka }
    814       1.1  pooka 
    815       1.9  pooka static int
    816       1.9  pooka rump_vop_getattr(void *v)
    817       1.9  pooka {
    818       1.9  pooka 	struct vop_getattr_args /* {
    819       1.9  pooka 		struct vnode *a_vp;
    820       1.9  pooka 		struct vattr *a_vap;
    821       1.9  pooka 		kauth_cred_t a_cred;
    822       1.9  pooka 	} */ *ap = v;
    823  1.37.2.4  rmind 	struct vnode *vp = ap->a_vp;
    824  1.37.2.4  rmind 	struct rumpfs_node *rn = vp->v_data;
    825  1.37.2.4  rmind 	struct vattr *vap = ap->a_vap;
    826       1.9  pooka 
    827  1.37.2.4  rmind 	memcpy(vap, &rn->rn_va, sizeof(struct vattr));
    828  1.37.2.4  rmind 	vap->va_size = vp->v_size;
    829  1.37.2.4  rmind 	return 0;
    830  1.37.2.4  rmind }
    831  1.37.2.4  rmind 
    832  1.37.2.4  rmind static int
    833  1.37.2.4  rmind rump_vop_setattr(void *v)
    834  1.37.2.4  rmind {
    835  1.37.2.4  rmind 	struct vop_getattr_args /* {
    836  1.37.2.4  rmind 		struct vnode *a_vp;
    837  1.37.2.4  rmind 		struct vattr *a_vap;
    838  1.37.2.4  rmind 		kauth_cred_t a_cred;
    839  1.37.2.4  rmind 	} */ *ap = v;
    840  1.37.2.4  rmind 	struct vnode *vp = ap->a_vp;
    841  1.37.2.4  rmind 	struct vattr *vap = ap->a_vap;
    842  1.37.2.4  rmind 	struct rumpfs_node *rn = vp->v_data;
    843  1.37.2.4  rmind 
    844  1.37.2.4  rmind #define SETIFVAL(a,t) if (vap->a != (t)VNOVAL) rn->rn_va.a = vap->a
    845  1.37.2.4  rmind 	SETIFVAL(va_mode, mode_t);
    846  1.37.2.4  rmind 	SETIFVAL(va_uid, uid_t);
    847  1.37.2.4  rmind 	SETIFVAL(va_gid, gid_t);
    848  1.37.2.4  rmind 	SETIFVAL(va_atime.tv_sec, time_t);
    849  1.37.2.4  rmind 	SETIFVAL(va_ctime.tv_sec, time_t);
    850  1.37.2.4  rmind 	SETIFVAL(va_mtime.tv_sec, time_t);
    851  1.37.2.4  rmind 	SETIFVAL(va_birthtime.tv_sec, time_t);
    852  1.37.2.4  rmind 	SETIFVAL(va_atime.tv_nsec, long);
    853  1.37.2.4  rmind 	SETIFVAL(va_ctime.tv_nsec, long);
    854  1.37.2.4  rmind 	SETIFVAL(va_mtime.tv_nsec, long);
    855  1.37.2.4  rmind 	SETIFVAL(va_birthtime.tv_nsec, long);
    856  1.37.2.4  rmind 	SETIFVAL(va_flags, u_long);
    857  1.37.2.4  rmind #undef  SETIFVAL
    858  1.37.2.4  rmind 
    859  1.37.2.4  rmind 	if (vp->v_type == VREG &&
    860  1.37.2.4  rmind 	    vap->va_size != VSIZENOTSET &&
    861  1.37.2.4  rmind 	    vap->va_size != rn->rn_dlen) {
    862  1.37.2.4  rmind 		void *newdata;
    863  1.37.2.4  rmind 		size_t copylen, newlen;
    864  1.37.2.4  rmind 
    865  1.37.2.4  rmind 		newlen = vap->va_size;
    866  1.37.2.4  rmind 		newdata = rump_hypermalloc(newlen, 0, true, "rumpfs");
    867  1.37.2.4  rmind 
    868  1.37.2.4  rmind 		copylen = MIN(rn->rn_dlen, newlen);
    869  1.37.2.4  rmind 		memset(newdata, 0, newlen);
    870  1.37.2.4  rmind 		memcpy(newdata, rn->rn_data, copylen);
    871  1.37.2.4  rmind 		rump_hyperfree(rn->rn_data, rn->rn_dlen);
    872  1.37.2.4  rmind 
    873  1.37.2.4  rmind 		rn->rn_data = newdata;
    874  1.37.2.4  rmind 		rn->rn_dlen = newlen;
    875  1.37.2.4  rmind 		uvm_vnp_setsize(vp, newlen);
    876  1.37.2.4  rmind 	}
    877       1.9  pooka 	return 0;
    878       1.9  pooka }
    879       1.9  pooka 
    880       1.9  pooka static int
    881      1.14  pooka rump_vop_mkdir(void *v)
    882      1.14  pooka {
    883      1.14  pooka 	struct vop_mkdir_args /* {
    884      1.14  pooka 		struct vnode *a_dvp;
    885      1.14  pooka 		struct vnode **a_vpp;
    886      1.14  pooka 		struct componentname *a_cnp;
    887      1.14  pooka 		struct vattr *a_vap;
    888      1.14  pooka 	}; */ *ap = v;
    889      1.14  pooka 	struct vnode *dvp = ap->a_dvp;
    890      1.14  pooka 	struct vnode **vpp = ap->a_vpp;
    891      1.14  pooka 	struct componentname *cnp = ap->a_cnp;
    892      1.21  pooka 	struct rumpfs_node *rnd = dvp->v_data, *rn;
    893      1.14  pooka 	int rv = 0;
    894      1.14  pooka 
    895  1.37.2.4  rmind 	rn = makeprivate(VDIR, NODEV, DEV_BSIZE, false);
    896  1.37.2.4  rmind 	rn->rn_parent = rnd;
    897      1.30  pooka 	rv = makevnode(dvp->v_mount, rn, vpp);
    898      1.21  pooka 	if (rv)
    899      1.14  pooka 		goto out;
    900      1.14  pooka 
    901  1.37.2.2  rmind 	makedir(rnd, cnp, rn);
    902      1.14  pooka 
    903      1.14  pooka  out:
    904      1.14  pooka 	vput(dvp);
    905      1.14  pooka 	return rv;
    906      1.14  pooka }
    907      1.14  pooka 
    908      1.14  pooka static int
    909  1.37.2.3  rmind rump_vop_rmdir(void *v)
    910  1.37.2.3  rmind {
    911  1.37.2.3  rmind         struct vop_rmdir_args /* {
    912  1.37.2.3  rmind                 struct vnode *a_dvp;
    913  1.37.2.3  rmind                 struct vnode *a_vp;
    914  1.37.2.3  rmind                 struct componentname *a_cnp;
    915  1.37.2.3  rmind         }; */ *ap = v;
    916  1.37.2.3  rmind 	struct vnode *dvp = ap->a_dvp;
    917  1.37.2.3  rmind 	struct vnode *vp = ap->a_vp;
    918  1.37.2.3  rmind 	struct componentname *cnp = ap->a_cnp;
    919  1.37.2.3  rmind 	struct rumpfs_node *rnd = dvp->v_data;
    920  1.37.2.3  rmind 	struct rumpfs_node *rn = vp->v_data;
    921  1.37.2.3  rmind 	int rv = 0;
    922  1.37.2.3  rmind 
    923  1.37.2.3  rmind 	if (!LIST_EMPTY(&rn->rn_dir)) {
    924  1.37.2.3  rmind 		rv = ENOTEMPTY;
    925  1.37.2.3  rmind 		goto out;
    926  1.37.2.3  rmind 	}
    927  1.37.2.3  rmind 
    928  1.37.2.3  rmind 	freedir(rnd, cnp);
    929  1.37.2.3  rmind 	rn->rn_flags |= RUMPNODE_CANRECLAIM;
    930  1.37.2.4  rmind 	rn->rn_parent = NULL;
    931  1.37.2.3  rmind 
    932  1.37.2.3  rmind out:
    933  1.37.2.4  rmind 	vput(dvp);
    934  1.37.2.4  rmind 	vput(vp);
    935  1.37.2.4  rmind 
    936  1.37.2.4  rmind 	return rv;
    937  1.37.2.4  rmind }
    938  1.37.2.4  rmind 
    939  1.37.2.4  rmind static int
    940  1.37.2.4  rmind rump_vop_remove(void *v)
    941  1.37.2.4  rmind {
    942  1.37.2.4  rmind         struct vop_rmdir_args /* {
    943  1.37.2.4  rmind                 struct vnode *a_dvp;
    944  1.37.2.4  rmind                 struct vnode *a_vp;
    945  1.37.2.4  rmind                 struct componentname *a_cnp;
    946  1.37.2.4  rmind         }; */ *ap = v;
    947  1.37.2.4  rmind 	struct vnode *dvp = ap->a_dvp;
    948  1.37.2.4  rmind 	struct vnode *vp = ap->a_vp;
    949  1.37.2.4  rmind 	struct componentname *cnp = ap->a_cnp;
    950  1.37.2.4  rmind 	struct rumpfs_node *rnd = dvp->v_data;
    951  1.37.2.4  rmind 	struct rumpfs_node *rn = vp->v_data;
    952  1.37.2.4  rmind 	int rv = 0;
    953  1.37.2.4  rmind 
    954  1.37.2.4  rmind 	if (rn->rn_flags & RUMPNODE_ET_PHONE_HOST)
    955  1.37.2.4  rmind 		return EOPNOTSUPP;
    956  1.37.2.4  rmind 
    957  1.37.2.4  rmind 	if (vp->v_type == VREG) {
    958  1.37.2.4  rmind 		rump_hyperfree(rn->rn_data, rn->rn_dlen);
    959  1.37.2.4  rmind 	}
    960  1.37.2.4  rmind 
    961  1.37.2.4  rmind 	freedir(rnd, cnp);
    962  1.37.2.4  rmind 	rn->rn_flags |= RUMPNODE_CANRECLAIM;
    963  1.37.2.4  rmind 
    964  1.37.2.3  rmind 	vput(dvp);
    965  1.37.2.3  rmind 	vput(vp);
    966  1.37.2.3  rmind 
    967  1.37.2.3  rmind 	return rv;
    968  1.37.2.3  rmind }
    969  1.37.2.3  rmind 
    970  1.37.2.3  rmind static int
    971      1.19  pooka rump_vop_mknod(void *v)
    972      1.19  pooka {
    973      1.19  pooka 	struct vop_mknod_args /* {
    974      1.19  pooka 		struct vnode *a_dvp;
    975      1.19  pooka 		struct vnode **a_vpp;
    976      1.19  pooka 		struct componentname *a_cnp;
    977      1.19  pooka 		struct vattr *a_vap;
    978      1.19  pooka 	}; */ *ap = v;
    979      1.19  pooka 	struct vnode *dvp = ap->a_dvp;
    980      1.19  pooka 	struct vnode **vpp = ap->a_vpp;
    981      1.19  pooka 	struct componentname *cnp = ap->a_cnp;
    982      1.19  pooka 	struct vattr *va = ap->a_vap;
    983      1.21  pooka 	struct rumpfs_node *rnd = dvp->v_data, *rn;
    984      1.19  pooka 	int rv;
    985      1.19  pooka 
    986  1.37.2.4  rmind 	rn = makeprivate(va->va_type, va->va_rdev, DEV_BSIZE, false);
    987      1.30  pooka 	rv = makevnode(dvp->v_mount, rn, vpp);
    988      1.21  pooka 	if (rv)
    989      1.19  pooka 		goto out;
    990      1.19  pooka 
    991  1.37.2.2  rmind 	makedir(rnd, cnp, rn);
    992      1.19  pooka 
    993      1.19  pooka  out:
    994      1.19  pooka 	vput(dvp);
    995      1.19  pooka 	return rv;
    996      1.19  pooka }
    997      1.19  pooka 
    998      1.19  pooka static int
    999      1.26  pooka rump_vop_create(void *v)
   1000      1.26  pooka {
   1001      1.26  pooka 	struct vop_create_args /* {
   1002      1.26  pooka 		struct vnode *a_dvp;
   1003      1.26  pooka 		struct vnode **a_vpp;
   1004      1.26  pooka 		struct componentname *a_cnp;
   1005      1.26  pooka 		struct vattr *a_vap;
   1006      1.26  pooka 	}; */ *ap = v;
   1007      1.26  pooka 	struct vnode *dvp = ap->a_dvp;
   1008      1.26  pooka 	struct vnode **vpp = ap->a_vpp;
   1009      1.26  pooka 	struct componentname *cnp = ap->a_cnp;
   1010      1.26  pooka 	struct vattr *va = ap->a_vap;
   1011      1.26  pooka 	struct rumpfs_node *rnd = dvp->v_data, *rn;
   1012  1.37.2.4  rmind 	off_t newsize;
   1013      1.26  pooka 	int rv;
   1014      1.26  pooka 
   1015  1.37.2.4  rmind 	newsize = va->va_type == VSOCK ? DEV_BSIZE : 0;
   1016  1.37.2.4  rmind 	rn = makeprivate(va->va_type, NODEV, newsize, false);
   1017      1.30  pooka 	rv = makevnode(dvp->v_mount, rn, vpp);
   1018      1.26  pooka 	if (rv)
   1019      1.26  pooka 		goto out;
   1020      1.26  pooka 
   1021  1.37.2.2  rmind 	makedir(rnd, cnp, rn);
   1022      1.26  pooka 
   1023      1.26  pooka  out:
   1024      1.26  pooka 	vput(dvp);
   1025      1.26  pooka 	return rv;
   1026      1.26  pooka }
   1027      1.26  pooka 
   1028      1.26  pooka static int
   1029  1.37.2.3  rmind rump_vop_symlink(void *v)
   1030  1.37.2.3  rmind {
   1031  1.37.2.3  rmind 	struct vop_symlink_args /* {
   1032  1.37.2.3  rmind 		struct vnode *a_dvp;
   1033  1.37.2.3  rmind 		struct vnode **a_vpp;
   1034  1.37.2.3  rmind 		struct componentname *a_cnp;
   1035  1.37.2.3  rmind 		struct vattr *a_vap;
   1036  1.37.2.3  rmind 		char *a_target;
   1037  1.37.2.3  rmind 	}; */ *ap = v;
   1038  1.37.2.3  rmind 	struct vnode *dvp = ap->a_dvp;
   1039  1.37.2.3  rmind 	struct vnode **vpp = ap->a_vpp;
   1040  1.37.2.3  rmind 	struct componentname *cnp = ap->a_cnp;
   1041  1.37.2.3  rmind 	struct rumpfs_node *rnd = dvp->v_data, *rn;
   1042  1.37.2.3  rmind 	const char *target = ap->a_target;
   1043  1.37.2.3  rmind 	size_t linklen;
   1044  1.37.2.3  rmind 	int rv;
   1045  1.37.2.3  rmind 
   1046  1.37.2.3  rmind 	linklen = strlen(target);
   1047  1.37.2.3  rmind 	KASSERT(linklen < MAXPATHLEN);
   1048  1.37.2.4  rmind 	rn = makeprivate(VLNK, NODEV, linklen, false);
   1049  1.37.2.3  rmind 	rv = makevnode(dvp->v_mount, rn, vpp);
   1050  1.37.2.3  rmind 	if (rv)
   1051  1.37.2.3  rmind 		goto out;
   1052  1.37.2.3  rmind 
   1053  1.37.2.3  rmind 	makedir(rnd, cnp, rn);
   1054  1.37.2.3  rmind 
   1055  1.37.2.3  rmind 	KASSERT(linklen < MAXPATHLEN);
   1056  1.37.2.3  rmind 	rn->rn_linktarg = PNBUF_GET();
   1057  1.37.2.3  rmind 	rn->rn_linklen = linklen;
   1058  1.37.2.3  rmind 	strcpy(rn->rn_linktarg, target);
   1059  1.37.2.3  rmind 
   1060  1.37.2.3  rmind  out:
   1061  1.37.2.3  rmind 	vput(dvp);
   1062  1.37.2.3  rmind 	return rv;
   1063  1.37.2.3  rmind }
   1064  1.37.2.3  rmind 
   1065  1.37.2.3  rmind static int
   1066  1.37.2.3  rmind rump_vop_readlink(void *v)
   1067  1.37.2.3  rmind {
   1068  1.37.2.3  rmind 	struct vop_readlink_args /* {
   1069  1.37.2.3  rmind 		struct vnode *a_vp;
   1070  1.37.2.3  rmind 		struct uio *a_uio;
   1071  1.37.2.3  rmind 		kauth_cred_t a_cred;
   1072  1.37.2.3  rmind 	}; */ *ap = v;
   1073  1.37.2.3  rmind 	struct vnode *vp = ap->a_vp;
   1074  1.37.2.3  rmind 	struct rumpfs_node *rn = vp->v_data;
   1075  1.37.2.3  rmind 	struct uio *uio = ap->a_uio;
   1076  1.37.2.3  rmind 
   1077  1.37.2.3  rmind 	return uiomove(rn->rn_linktarg, rn->rn_linklen, uio);
   1078  1.37.2.3  rmind }
   1079  1.37.2.3  rmind 
   1080  1.37.2.3  rmind static int
   1081  1.37.2.4  rmind rump_vop_whiteout(void *v)
   1082  1.37.2.4  rmind {
   1083  1.37.2.4  rmind 	struct vop_whiteout_args /* {
   1084  1.37.2.4  rmind 		struct vnode            *a_dvp;
   1085  1.37.2.4  rmind 		struct componentname    *a_cnp;
   1086  1.37.2.4  rmind 		int                     a_flags;
   1087  1.37.2.4  rmind 	} */ *ap = v;
   1088  1.37.2.4  rmind 	struct vnode *dvp = ap->a_dvp;
   1089  1.37.2.4  rmind 	struct rumpfs_node *rnd = dvp->v_data;
   1090  1.37.2.4  rmind 	struct componentname *cnp = ap->a_cnp;
   1091  1.37.2.4  rmind 	int flags = ap->a_flags;
   1092  1.37.2.4  rmind 
   1093  1.37.2.4  rmind 	switch (flags) {
   1094  1.37.2.4  rmind 	case LOOKUP:
   1095  1.37.2.4  rmind 		break;
   1096  1.37.2.4  rmind 	case CREATE:
   1097  1.37.2.4  rmind 		makedir(rnd, cnp, RUMPFS_WHITEOUT);
   1098  1.37.2.4  rmind 		break;
   1099  1.37.2.4  rmind 	case DELETE:
   1100  1.37.2.4  rmind 		cnp->cn_flags &= ~DOWHITEOUT; /* cargo culting never fails ? */
   1101  1.37.2.4  rmind 		freedir(rnd, cnp);
   1102  1.37.2.4  rmind 		break;
   1103  1.37.2.4  rmind 	default:
   1104  1.37.2.4  rmind 		panic("unknown whiteout op %d", flags);
   1105  1.37.2.4  rmind 	}
   1106  1.37.2.4  rmind 
   1107  1.37.2.4  rmind 	return 0;
   1108  1.37.2.4  rmind }
   1109  1.37.2.4  rmind 
   1110  1.37.2.4  rmind static int
   1111      1.24  pooka rump_vop_open(void *v)
   1112      1.24  pooka {
   1113      1.24  pooka 	struct vop_open_args /* {
   1114      1.24  pooka 		struct vnode *a_vp;
   1115      1.24  pooka 		int a_mode;
   1116      1.24  pooka 		kauth_cred_t a_cred;
   1117      1.24  pooka 	} */ *ap = v;
   1118      1.24  pooka 	struct vnode *vp = ap->a_vp;
   1119      1.24  pooka 	struct rumpfs_node *rn = vp->v_data;
   1120      1.24  pooka 	int mode = ap->a_mode;
   1121      1.24  pooka 	int error = EINVAL;
   1122      1.24  pooka 
   1123  1.37.2.4  rmind 	if (vp->v_type != VREG || (rn->rn_flags & RUMPNODE_ET_PHONE_HOST) == 0)
   1124      1.24  pooka 		return 0;
   1125      1.24  pooka 
   1126      1.24  pooka 	if (mode & FREAD) {
   1127      1.24  pooka 		if (rn->rn_readfd != -1)
   1128      1.24  pooka 			return 0;
   1129      1.24  pooka 		rn->rn_readfd = rumpuser_open(rn->rn_hostpath,
   1130      1.24  pooka 		    O_RDONLY, &error);
   1131  1.37.2.3  rmind 	}
   1132  1.37.2.3  rmind 
   1133  1.37.2.3  rmind 	if (mode & FWRITE) {
   1134      1.24  pooka 		if (rn->rn_writefd != -1)
   1135      1.24  pooka 			return 0;
   1136      1.24  pooka 		rn->rn_writefd = rumpuser_open(rn->rn_hostpath,
   1137      1.24  pooka 		    O_WRONLY, &error);
   1138      1.24  pooka 	}
   1139      1.24  pooka 
   1140      1.24  pooka 	return error;
   1141      1.24  pooka }
   1142      1.24  pooka 
   1143  1.37.2.2  rmind /* simple readdir.  event omits dotstuff and periods */
   1144  1.37.2.2  rmind static int
   1145  1.37.2.2  rmind rump_vop_readdir(void *v)
   1146  1.37.2.2  rmind {
   1147  1.37.2.2  rmind 	struct vop_readdir_args /* {
   1148  1.37.2.2  rmind 		struct vnode *a_vp;
   1149  1.37.2.2  rmind 		struct uio *a_uio;
   1150  1.37.2.2  rmind 		kauth_cred_t a_cred;
   1151  1.37.2.2  rmind 		int *a_eofflag;
   1152  1.37.2.2  rmind 		off_t **a_cookies;
   1153  1.37.2.2  rmind 		int *a_ncookies;
   1154  1.37.2.2  rmind 	} */ *ap = v;
   1155  1.37.2.2  rmind 	struct vnode *vp = ap->a_vp;
   1156  1.37.2.2  rmind 	struct uio *uio = ap->a_uio;
   1157  1.37.2.2  rmind 	struct rumpfs_node *rnd = vp->v_data;
   1158  1.37.2.2  rmind 	struct rumpfs_dent *rdent;
   1159  1.37.2.2  rmind 	unsigned i;
   1160  1.37.2.2  rmind 	int rv = 0;
   1161  1.37.2.2  rmind 
   1162  1.37.2.2  rmind 	/* seek to current entry */
   1163  1.37.2.2  rmind 	for (i = 0, rdent = LIST_FIRST(&rnd->rn_dir);
   1164  1.37.2.2  rmind 	    (i < uio->uio_offset) && rdent;
   1165  1.37.2.2  rmind 	    i++, rdent = LIST_NEXT(rdent, rd_entries))
   1166  1.37.2.2  rmind 		continue;
   1167  1.37.2.2  rmind 	if (!rdent)
   1168  1.37.2.2  rmind 		goto out;
   1169  1.37.2.2  rmind 
   1170  1.37.2.2  rmind 	/* copy entries */
   1171  1.37.2.2  rmind 	for (; rdent && uio->uio_resid > 0;
   1172  1.37.2.2  rmind 	    rdent = LIST_NEXT(rdent, rd_entries), i++) {
   1173  1.37.2.2  rmind 		struct dirent dent;
   1174  1.37.2.2  rmind 
   1175  1.37.2.2  rmind 		strlcpy(dent.d_name, rdent->rd_name, sizeof(dent.d_name));
   1176  1.37.2.2  rmind 		dent.d_namlen = strlen(dent.d_name);
   1177  1.37.2.2  rmind 		dent.d_reclen = _DIRENT_RECLEN(&dent, dent.d_namlen);
   1178  1.37.2.2  rmind 
   1179  1.37.2.4  rmind 		if (__predict_false(RDENT_ISWHITEOUT(rdent))) {
   1180  1.37.2.4  rmind 			dent.d_fileno = INO_WHITEOUT;
   1181  1.37.2.4  rmind 			dent.d_type = DT_WHT;
   1182  1.37.2.4  rmind 		} else {
   1183  1.37.2.4  rmind 			dent.d_fileno = rdent->rd_node->rn_va.va_fileid;
   1184  1.37.2.4  rmind 			dent.d_type = vtype2dt(rdent->rd_node->rn_va.va_type);
   1185  1.37.2.4  rmind 		}
   1186  1.37.2.4  rmind 
   1187  1.37.2.2  rmind 		if (uio->uio_resid < dent.d_reclen) {
   1188  1.37.2.2  rmind 			i--;
   1189  1.37.2.2  rmind 			break;
   1190  1.37.2.2  rmind 		}
   1191  1.37.2.2  rmind 
   1192  1.37.2.2  rmind 		rv = uiomove(&dent, dent.d_reclen, uio);
   1193  1.37.2.2  rmind 		if (rv) {
   1194  1.37.2.2  rmind 			i--;
   1195  1.37.2.2  rmind 			break;
   1196  1.37.2.2  rmind 		}
   1197  1.37.2.2  rmind 	}
   1198  1.37.2.2  rmind 
   1199  1.37.2.2  rmind  out:
   1200  1.37.2.2  rmind 	if (ap->a_cookies) {
   1201  1.37.2.2  rmind 		*ap->a_ncookies = 0;
   1202  1.37.2.2  rmind 		*ap->a_cookies = NULL;
   1203  1.37.2.2  rmind 	}
   1204  1.37.2.2  rmind 	if (rdent)
   1205  1.37.2.2  rmind 		*ap->a_eofflag = 0;
   1206  1.37.2.2  rmind 	else
   1207  1.37.2.2  rmind 		*ap->a_eofflag = 1;
   1208  1.37.2.2  rmind 	uio->uio_offset = i;
   1209  1.37.2.2  rmind 
   1210  1.37.2.2  rmind 	return rv;
   1211  1.37.2.2  rmind }
   1212  1.37.2.2  rmind 
   1213      1.24  pooka static int
   1214  1.37.2.4  rmind etread(struct rumpfs_node *rn, struct uio *uio)
   1215      1.24  pooka {
   1216      1.24  pooka 	uint8_t *buf;
   1217      1.24  pooka 	size_t bufsize;
   1218  1.37.2.3  rmind 	ssize_t n;
   1219      1.24  pooka 	int error = 0;
   1220      1.24  pooka 
   1221      1.24  pooka 	bufsize = uio->uio_resid;
   1222  1.37.2.5  rmind 	if (bufsize == 0)
   1223  1.37.2.5  rmind 		return 0;
   1224      1.24  pooka 	buf = kmem_alloc(bufsize, KM_SLEEP);
   1225  1.37.2.3  rmind 	if ((n = rumpuser_pread(rn->rn_readfd, buf, bufsize,
   1226  1.37.2.3  rmind 	    uio->uio_offset + rn->rn_offset, &error)) == -1)
   1227      1.24  pooka 		goto out;
   1228  1.37.2.3  rmind 	KASSERT(n <= bufsize);
   1229  1.37.2.3  rmind 	error = uiomove(buf, n, uio);
   1230      1.24  pooka 
   1231      1.24  pooka  out:
   1232      1.24  pooka 	kmem_free(buf, bufsize);
   1233      1.24  pooka 	return error;
   1234  1.37.2.4  rmind 
   1235      1.24  pooka }
   1236      1.24  pooka 
   1237      1.24  pooka static int
   1238  1.37.2.4  rmind rump_vop_read(void *v)
   1239      1.24  pooka {
   1240      1.24  pooka 	struct vop_read_args /* {
   1241      1.24  pooka 		struct vnode *a_vp;
   1242      1.24  pooka 		struct uio *a_uio;
   1243      1.24  pooka 		int ioflags a_ioflag;
   1244      1.24  pooka 		kauth_cred_t a_cred;
   1245      1.24  pooka 	}; */ *ap = v;
   1246      1.24  pooka 	struct vnode *vp = ap->a_vp;
   1247      1.24  pooka 	struct rumpfs_node *rn = vp->v_data;
   1248      1.24  pooka 	struct uio *uio = ap->a_uio;
   1249  1.37.2.4  rmind 	const int advice = IO_ADV_DECODE(ap->a_ioflag);
   1250  1.37.2.4  rmind 	off_t chunk;
   1251  1.37.2.4  rmind 	int error = 0;
   1252  1.37.2.4  rmind 
   1253  1.37.2.4  rmind 	/* et op? */
   1254  1.37.2.4  rmind 	if (rn->rn_flags & RUMPNODE_ET_PHONE_HOST)
   1255  1.37.2.4  rmind 		return etread(rn, uio);
   1256  1.37.2.4  rmind 
   1257  1.37.2.4  rmind 	/* otherwise, it's off to ubc with us */
   1258  1.37.2.4  rmind 	while (uio->uio_resid > 0) {
   1259  1.37.2.4  rmind 		chunk = MIN(uio->uio_resid, (off_t)rn->rn_dlen-uio->uio_offset);
   1260  1.37.2.4  rmind 		if (chunk == 0)
   1261  1.37.2.4  rmind 			break;
   1262  1.37.2.4  rmind 		error = ubc_uiomove(&vp->v_uobj, uio, chunk, advice,
   1263  1.37.2.4  rmind 		    UBC_READ | UBC_PARTIALOK | UBC_WANT_UNMAP(vp)?UBC_UNMAP:0);
   1264  1.37.2.4  rmind 		if (error)
   1265  1.37.2.4  rmind 			break;
   1266  1.37.2.4  rmind 	}
   1267  1.37.2.4  rmind 
   1268  1.37.2.4  rmind 	return error;
   1269  1.37.2.4  rmind }
   1270  1.37.2.4  rmind 
   1271  1.37.2.4  rmind static int
   1272  1.37.2.4  rmind etwrite(struct rumpfs_node *rn, struct uio *uio)
   1273  1.37.2.4  rmind {
   1274      1.24  pooka 	uint8_t *buf;
   1275      1.24  pooka 	size_t bufsize;
   1276  1.37.2.3  rmind 	ssize_t n;
   1277      1.24  pooka 	int error = 0;
   1278      1.24  pooka 
   1279      1.24  pooka 	bufsize = uio->uio_resid;
   1280  1.37.2.5  rmind 	if (bufsize == 0)
   1281  1.37.2.5  rmind 		return 0;
   1282      1.24  pooka 	buf = kmem_alloc(bufsize, KM_SLEEP);
   1283      1.24  pooka 	error = uiomove(buf, bufsize, uio);
   1284      1.24  pooka 	if (error)
   1285      1.24  pooka 		goto out;
   1286      1.24  pooka 	KASSERT(uio->uio_resid == 0);
   1287  1.37.2.3  rmind 	n = rumpuser_pwrite(rn->rn_writefd, buf, bufsize,
   1288  1.37.2.3  rmind 	    (uio->uio_offset-bufsize) + rn->rn_offset, &error);
   1289  1.37.2.3  rmind 	if (n >= 0) {
   1290  1.37.2.3  rmind 		KASSERT(n <= bufsize);
   1291  1.37.2.3  rmind 		uio->uio_resid = bufsize - n;
   1292  1.37.2.3  rmind 	}
   1293      1.24  pooka 
   1294      1.24  pooka  out:
   1295      1.24  pooka 	kmem_free(buf, bufsize);
   1296      1.24  pooka 	return error;
   1297      1.24  pooka }
   1298      1.24  pooka 
   1299      1.24  pooka static int
   1300  1.37.2.4  rmind rump_vop_write(void *v)
   1301  1.37.2.4  rmind {
   1302  1.37.2.4  rmind 	struct vop_read_args /* {
   1303  1.37.2.4  rmind 		struct vnode *a_vp;
   1304  1.37.2.4  rmind 		struct uio *a_uio;
   1305  1.37.2.4  rmind 		int ioflags a_ioflag;
   1306  1.37.2.4  rmind 		kauth_cred_t a_cred;
   1307  1.37.2.4  rmind 	}; */ *ap = v;
   1308  1.37.2.4  rmind 	struct vnode *vp = ap->a_vp;
   1309  1.37.2.4  rmind 	struct rumpfs_node *rn = vp->v_data;
   1310  1.37.2.4  rmind 	struct uio *uio = ap->a_uio;
   1311  1.37.2.4  rmind 	const int advice = IO_ADV_DECODE(ap->a_ioflag);
   1312  1.37.2.4  rmind 	void *olddata;
   1313  1.37.2.4  rmind 	size_t oldlen, newlen;
   1314  1.37.2.4  rmind 	off_t chunk;
   1315  1.37.2.4  rmind 	int error = 0;
   1316  1.37.2.4  rmind 	bool allocd = false;
   1317  1.37.2.4  rmind 
   1318  1.37.2.4  rmind 	if (ap->a_ioflag & IO_APPEND)
   1319  1.37.2.4  rmind 		uio->uio_offset = vp->v_size;
   1320  1.37.2.4  rmind 
   1321  1.37.2.4  rmind 	/* consult et? */
   1322  1.37.2.4  rmind 	if (rn->rn_flags & RUMPNODE_ET_PHONE_HOST)
   1323  1.37.2.4  rmind 		return etwrite(rn, uio);
   1324  1.37.2.4  rmind 
   1325  1.37.2.4  rmind 	/*
   1326  1.37.2.4  rmind 	 * Otherwise, it's a case of ubcmove.
   1327  1.37.2.4  rmind 	 */
   1328  1.37.2.4  rmind 
   1329  1.37.2.4  rmind 	/*
   1330  1.37.2.4  rmind 	 * First, make sure we have enough storage.
   1331  1.37.2.4  rmind 	 *
   1332  1.37.2.4  rmind 	 * No, you don't need to tell me it's not very efficient.
   1333  1.37.2.4  rmind 	 * No, it doesn't really support sparse files, just fakes it.
   1334  1.37.2.4  rmind 	 */
   1335  1.37.2.4  rmind 	newlen = uio->uio_offset + uio->uio_resid;
   1336  1.37.2.4  rmind 	oldlen = 0; /* XXXgcc */
   1337  1.37.2.4  rmind 	olddata = NULL;
   1338  1.37.2.4  rmind 	if (rn->rn_dlen < newlen) {
   1339  1.37.2.4  rmind 		oldlen = rn->rn_dlen;
   1340  1.37.2.4  rmind 		olddata = rn->rn_data;
   1341  1.37.2.4  rmind 
   1342  1.37.2.4  rmind 		rn->rn_data = rump_hypermalloc(newlen, 0, true, "rumpfs");
   1343  1.37.2.4  rmind 		rn->rn_dlen = newlen;
   1344  1.37.2.4  rmind 		memset(rn->rn_data, 0, newlen);
   1345  1.37.2.4  rmind 		memcpy(rn->rn_data, olddata, oldlen);
   1346  1.37.2.4  rmind 		allocd = true;
   1347  1.37.2.4  rmind 		uvm_vnp_setsize(vp, newlen);
   1348  1.37.2.4  rmind 	}
   1349  1.37.2.4  rmind 
   1350  1.37.2.4  rmind 	/* ok, we have enough stooorage.  write */
   1351  1.37.2.4  rmind 	while (uio->uio_resid > 0) {
   1352  1.37.2.4  rmind 		chunk = MIN(uio->uio_resid, (off_t)rn->rn_dlen-uio->uio_offset);
   1353  1.37.2.4  rmind 		if (chunk == 0)
   1354  1.37.2.4  rmind 			break;
   1355  1.37.2.4  rmind 		error = ubc_uiomove(&vp->v_uobj, uio, chunk, advice,
   1356  1.37.2.4  rmind 		    UBC_WRITE | UBC_PARTIALOK | UBC_WANT_UNMAP(vp)?UBC_UNMAP:0);
   1357  1.37.2.4  rmind 		if (error)
   1358  1.37.2.4  rmind 			break;
   1359  1.37.2.4  rmind 	}
   1360  1.37.2.4  rmind 
   1361  1.37.2.4  rmind 	if (allocd) {
   1362  1.37.2.4  rmind 		if (error) {
   1363  1.37.2.4  rmind 			rump_hyperfree(rn->rn_data, newlen);
   1364  1.37.2.4  rmind 			rn->rn_data = olddata;
   1365  1.37.2.4  rmind 			rn->rn_dlen = oldlen;
   1366  1.37.2.4  rmind 			uvm_vnp_setsize(vp, oldlen);
   1367  1.37.2.4  rmind 		} else {
   1368  1.37.2.4  rmind 			rump_hyperfree(olddata, oldlen);
   1369  1.37.2.4  rmind 		}
   1370  1.37.2.4  rmind 	}
   1371  1.37.2.4  rmind 
   1372  1.37.2.4  rmind 	return error;
   1373  1.37.2.4  rmind }
   1374  1.37.2.4  rmind 
   1375  1.37.2.4  rmind static int
   1376  1.37.2.4  rmind rump_vop_bmap(void *v)
   1377  1.37.2.4  rmind {
   1378  1.37.2.4  rmind 	struct vop_bmap_args /* {
   1379  1.37.2.4  rmind 		struct vnode *a_vp;
   1380  1.37.2.4  rmind 		daddr_t a_bn;
   1381  1.37.2.4  rmind 		struct vnode **a_vpp;
   1382  1.37.2.4  rmind 		daddr_t *a_bnp;
   1383  1.37.2.4  rmind 		int *a_runp;
   1384  1.37.2.4  rmind 	} */ *ap = v;
   1385  1.37.2.4  rmind 
   1386  1.37.2.4  rmind 	/* 1:1 mapping */
   1387  1.37.2.4  rmind 	if (ap->a_vpp)
   1388  1.37.2.4  rmind 		*ap->a_vpp = ap->a_vp;
   1389  1.37.2.4  rmind 	if (ap->a_bnp)
   1390  1.37.2.4  rmind 		*ap->a_bnp = ap->a_bn;
   1391  1.37.2.4  rmind 	if (ap->a_runp)
   1392  1.37.2.4  rmind 		*ap->a_runp = 16;
   1393  1.37.2.4  rmind 
   1394  1.37.2.4  rmind 	return 0;
   1395  1.37.2.4  rmind }
   1396  1.37.2.4  rmind 
   1397  1.37.2.4  rmind static int
   1398  1.37.2.4  rmind rump_vop_strategy(void *v)
   1399  1.37.2.4  rmind {
   1400  1.37.2.4  rmind 	struct vop_strategy_args /* {
   1401  1.37.2.4  rmind 		struct vnode *a_vp;
   1402  1.37.2.4  rmind 		struct buf *a_bp;
   1403  1.37.2.4  rmind 	} */ *ap = v;
   1404  1.37.2.4  rmind 	struct vnode *vp = ap->a_vp;
   1405  1.37.2.4  rmind 	struct rumpfs_node *rn = vp->v_data;
   1406  1.37.2.4  rmind 	struct buf *bp = ap->a_bp;
   1407  1.37.2.4  rmind 	off_t copylen, copyoff;
   1408  1.37.2.4  rmind 	int error;
   1409  1.37.2.4  rmind 
   1410  1.37.2.4  rmind 	if (vp->v_type != VREG || rn->rn_flags & RUMPNODE_ET_PHONE_HOST) {
   1411  1.37.2.4  rmind 		error = EINVAL;
   1412  1.37.2.4  rmind 		goto out;
   1413  1.37.2.4  rmind 	}
   1414  1.37.2.4  rmind 
   1415  1.37.2.4  rmind 	copyoff = bp->b_blkno << DEV_BSHIFT;
   1416  1.37.2.4  rmind 	copylen = MIN(rn->rn_dlen - copyoff, bp->b_bcount);
   1417  1.37.2.4  rmind 	if (BUF_ISWRITE(bp)) {
   1418  1.37.2.4  rmind 		memcpy((uint8_t *)rn->rn_data + copyoff, bp->b_data, copylen);
   1419  1.37.2.4  rmind 	} else {
   1420  1.37.2.4  rmind 		memset((uint8_t*)bp->b_data + copylen, 0, bp->b_bcount-copylen);
   1421  1.37.2.4  rmind 		memcpy(bp->b_data, (uint8_t *)rn->rn_data + copyoff, copylen);
   1422  1.37.2.4  rmind 	}
   1423  1.37.2.4  rmind 	bp->b_resid = 0;
   1424  1.37.2.4  rmind 	error = 0;
   1425  1.37.2.4  rmind 
   1426  1.37.2.4  rmind  out:
   1427  1.37.2.4  rmind 	bp->b_error = error;
   1428  1.37.2.4  rmind 	biodone(bp);
   1429  1.37.2.4  rmind 	return 0;
   1430  1.37.2.4  rmind }
   1431  1.37.2.4  rmind 
   1432  1.37.2.4  rmind static int
   1433  1.37.2.4  rmind rump_vop_pathconf(void *v)
   1434  1.37.2.4  rmind {
   1435  1.37.2.4  rmind 	struct vop_pathconf_args /* {
   1436  1.37.2.4  rmind 		struct vnode *a_vp;
   1437  1.37.2.4  rmind 		int a_name;
   1438  1.37.2.4  rmind 		register_t *a_retval;
   1439  1.37.2.4  rmind 	}; */ *ap = v;
   1440  1.37.2.4  rmind 	int name = ap->a_name;
   1441  1.37.2.4  rmind 	register_t *retval = ap->a_retval;
   1442  1.37.2.4  rmind 
   1443  1.37.2.4  rmind 	switch (name) {
   1444  1.37.2.4  rmind 	case _PC_LINK_MAX:
   1445  1.37.2.4  rmind 		*retval = LINK_MAX;
   1446  1.37.2.4  rmind 		return 0;
   1447  1.37.2.4  rmind 	case _PC_NAME_MAX:
   1448  1.37.2.4  rmind 		*retval = NAME_MAX;
   1449  1.37.2.4  rmind 		return 0;
   1450  1.37.2.4  rmind 	case _PC_PATH_MAX:
   1451  1.37.2.4  rmind 		*retval = PATH_MAX;
   1452  1.37.2.4  rmind 		return 0;
   1453  1.37.2.4  rmind 	case _PC_PIPE_BUF:
   1454  1.37.2.4  rmind 		*retval = PIPE_BUF;
   1455  1.37.2.4  rmind 		return 0;
   1456  1.37.2.4  rmind 	case _PC_CHOWN_RESTRICTED:
   1457  1.37.2.4  rmind 		*retval = 1;
   1458  1.37.2.4  rmind 		return 0;
   1459  1.37.2.4  rmind 	case _PC_NO_TRUNC:
   1460  1.37.2.4  rmind 		*retval = 1;
   1461  1.37.2.4  rmind 		return 0;
   1462  1.37.2.4  rmind 	case _PC_SYNC_IO:
   1463  1.37.2.4  rmind 		*retval = 1;
   1464  1.37.2.4  rmind 		return 0;
   1465  1.37.2.4  rmind 	case _PC_FILESIZEBITS:
   1466  1.37.2.4  rmind 		*retval = 43; /* this one goes to 11 */
   1467  1.37.2.4  rmind 		return 0;
   1468  1.37.2.4  rmind 	case _PC_SYMLINK_MAX:
   1469  1.37.2.4  rmind 		*retval = MAXPATHLEN;
   1470  1.37.2.4  rmind 		return 0;
   1471  1.37.2.4  rmind 	case _PC_2_SYMLINKS:
   1472  1.37.2.4  rmind 		*retval = 1;
   1473  1.37.2.4  rmind 		return 0;
   1474  1.37.2.4  rmind 	default:
   1475  1.37.2.4  rmind 		return EINVAL;
   1476  1.37.2.4  rmind 	}
   1477  1.37.2.4  rmind }
   1478  1.37.2.4  rmind 
   1479  1.37.2.4  rmind static int
   1480       1.9  pooka rump_vop_success(void *v)
   1481       1.9  pooka {
   1482       1.9  pooka 
   1483       1.9  pooka 	return 0;
   1484       1.9  pooka }
   1485       1.9  pooka 
   1486      1.12  pooka static int
   1487      1.14  pooka rump_vop_inactive(void *v)
   1488      1.14  pooka {
   1489  1.37.2.3  rmind 	struct vop_inactive_args /* {
   1490  1.37.2.3  rmind 		struct vnode *a_vp;
   1491  1.37.2.3  rmind 		bool *a_recycle;
   1492  1.37.2.3  rmind 	} */ *ap = v;
   1493      1.24  pooka 	struct vnode *vp = ap->a_vp;
   1494      1.24  pooka 	struct rumpfs_node *rn = vp->v_data;
   1495      1.24  pooka 	int error;
   1496      1.14  pooka 
   1497  1.37.2.4  rmind 	if (rn->rn_flags & RUMPNODE_ET_PHONE_HOST && vp->v_type == VREG) {
   1498      1.24  pooka 		if (rn->rn_readfd != -1) {
   1499      1.24  pooka 			rumpuser_close(rn->rn_readfd, &error);
   1500      1.24  pooka 			rn->rn_readfd = -1;
   1501      1.24  pooka 		}
   1502      1.24  pooka 		if (rn->rn_writefd != -1) {
   1503      1.24  pooka 			rumpuser_close(rn->rn_writefd, &error);
   1504      1.24  pooka 			rn->rn_writefd = -1;
   1505      1.24  pooka 		}
   1506      1.24  pooka 	}
   1507  1.37.2.3  rmind 	*ap->a_recycle = (rn->rn_flags & RUMPNODE_CANRECLAIM) ? true : false;
   1508  1.37.2.4  rmind 
   1509  1.37.2.3  rmind 	VOP_UNLOCK(vp);
   1510      1.14  pooka 	return 0;
   1511      1.14  pooka }
   1512      1.14  pooka 
   1513      1.14  pooka static int
   1514      1.12  pooka rump_vop_reclaim(void *v)
   1515      1.12  pooka {
   1516      1.12  pooka 	struct vop_reclaim_args /* {
   1517      1.12  pooka 		struct vnode *a_vp;
   1518      1.12  pooka 	} */ *ap = v;
   1519      1.12  pooka 	struct vnode *vp = ap->a_vp;
   1520      1.14  pooka 	struct rumpfs_node *rn = vp->v_data;
   1521      1.12  pooka 
   1522      1.14  pooka 	mutex_enter(&reclock);
   1523      1.14  pooka 	rn->rn_vp = NULL;
   1524      1.14  pooka 	mutex_exit(&reclock);
   1525  1.37.2.4  rmind 	genfs_node_destroy(vp);
   1526      1.12  pooka 	vp->v_data = NULL;
   1527      1.12  pooka 
   1528  1.37.2.2  rmind 	if (rn->rn_flags & RUMPNODE_CANRECLAIM) {
   1529  1.37.2.3  rmind 		if (vp->v_type == VLNK)
   1530  1.37.2.3  rmind 			PNBUF_PUT(rn->rn_linktarg);
   1531  1.37.2.2  rmind 		if (rn->rn_hostpath)
   1532  1.37.2.2  rmind 			free(rn->rn_hostpath, M_TEMP);
   1533  1.37.2.2  rmind 		kmem_free(rn, sizeof(*rn));
   1534  1.37.2.2  rmind 	}
   1535  1.37.2.2  rmind 
   1536      1.12  pooka 	return 0;
   1537      1.12  pooka }
   1538      1.12  pooka 
   1539      1.19  pooka static int
   1540      1.19  pooka rump_vop_spec(void *v)
   1541      1.19  pooka {
   1542      1.19  pooka 	struct vop_generic_args *ap = v;
   1543      1.19  pooka 	int (**opvec)(void *);
   1544      1.19  pooka 
   1545      1.19  pooka 	switch (ap->a_desc->vdesc_offset) {
   1546      1.19  pooka 	case VOP_ACCESS_DESCOFFSET:
   1547      1.19  pooka 	case VOP_GETATTR_DESCOFFSET:
   1548  1.37.2.4  rmind 	case VOP_SETATTR_DESCOFFSET:
   1549      1.22  pooka 	case VOP_LOCK_DESCOFFSET:
   1550      1.22  pooka 	case VOP_UNLOCK_DESCOFFSET:
   1551  1.37.2.4  rmind 	case VOP_ISLOCKED_DESCOFFSET:
   1552  1.37.2.2  rmind 	case VOP_RECLAIM_DESCOFFSET:
   1553      1.19  pooka 		opvec = rump_vnodeop_p;
   1554      1.19  pooka 		break;
   1555      1.19  pooka 	default:
   1556      1.19  pooka 		opvec = spec_vnodeop_p;
   1557      1.19  pooka 		break;
   1558      1.19  pooka 	}
   1559      1.19  pooka 
   1560      1.19  pooka 	return VOCALL(opvec, ap->a_desc->vdesc_offset, v);
   1561      1.19  pooka }
   1562      1.19  pooka 
   1563  1.37.2.4  rmind static int
   1564  1.37.2.4  rmind rump_vop_advlock(void *v)
   1565  1.37.2.4  rmind {
   1566  1.37.2.4  rmind 	struct vop_advlock_args /* {
   1567  1.37.2.4  rmind 		const struct vnodeop_desc *a_desc;
   1568  1.37.2.4  rmind 		struct vnode *a_vp;
   1569  1.37.2.4  rmind 		void *a_id;
   1570  1.37.2.4  rmind 		int a_op;
   1571  1.37.2.4  rmind 		struct flock *a_fl;
   1572  1.37.2.4  rmind 		int a_flags;
   1573  1.37.2.4  rmind 	} */ *ap = v;
   1574  1.37.2.4  rmind 	struct vnode *vp = ap->a_vp;
   1575  1.37.2.4  rmind 	struct rumpfs_node *rn = vp->v_data;
   1576  1.37.2.4  rmind 
   1577  1.37.2.4  rmind 	return lf_advlock(ap, &rn->rn_lockf, vp->v_size);
   1578  1.37.2.4  rmind }
   1579  1.37.2.4  rmind 
   1580      1.30  pooka /*
   1581      1.30  pooka  * Begin vfs-level stuff
   1582      1.30  pooka  */
   1583      1.30  pooka 
   1584      1.30  pooka VFS_PROTOS(rumpfs);
   1585      1.30  pooka struct vfsops rumpfs_vfsops = {
   1586      1.30  pooka 	.vfs_name =		MOUNT_RUMPFS,
   1587      1.30  pooka 	.vfs_min_mount_data = 	0,
   1588      1.30  pooka 	.vfs_mount =		rumpfs_mount,
   1589      1.30  pooka 	.vfs_start =		(void *)nullop,
   1590      1.30  pooka 	.vfs_unmount = 		rumpfs_unmount,
   1591      1.30  pooka 	.vfs_root =		rumpfs_root,
   1592      1.30  pooka 	.vfs_quotactl =		(void *)eopnotsupp,
   1593      1.33  pooka 	.vfs_statvfs =		genfs_statvfs,
   1594      1.30  pooka 	.vfs_sync =		(void *)nullop,
   1595      1.30  pooka 	.vfs_vget =		rumpfs_vget,
   1596      1.30  pooka 	.vfs_fhtovp =		(void *)eopnotsupp,
   1597      1.30  pooka 	.vfs_vptofh =		(void *)eopnotsupp,
   1598      1.30  pooka 	.vfs_init =		rumpfs_init,
   1599      1.30  pooka 	.vfs_reinit =		NULL,
   1600      1.30  pooka 	.vfs_done =		rumpfs_done,
   1601      1.30  pooka 	.vfs_mountroot =	rumpfs_mountroot,
   1602      1.30  pooka 	.vfs_snapshot =		(void *)eopnotsupp,
   1603      1.30  pooka 	.vfs_extattrctl =	(void *)eopnotsupp,
   1604      1.30  pooka 	.vfs_suspendctl =	(void *)eopnotsupp,
   1605  1.37.2.4  rmind 	.vfs_renamelock_enter =	genfs_renamelock_enter,
   1606  1.37.2.4  rmind 	.vfs_renamelock_exit =	genfs_renamelock_exit,
   1607      1.30  pooka 	.vfs_opv_descs =	rump_opv_descs,
   1608      1.30  pooka 	/* vfs_refcount */
   1609      1.30  pooka 	/* vfs_list */
   1610      1.30  pooka };
   1611      1.30  pooka 
   1612  1.37.2.4  rmind static int
   1613  1.37.2.4  rmind rumpfs_mountfs(struct mount *mp)
   1614  1.37.2.4  rmind {
   1615  1.37.2.4  rmind 	struct rumpfs_mount *rfsmp;
   1616  1.37.2.4  rmind 	struct rumpfs_node *rn;
   1617  1.37.2.4  rmind 	int error;
   1618  1.37.2.4  rmind 
   1619  1.37.2.4  rmind 	rfsmp = kmem_alloc(sizeof(*rfsmp), KM_SLEEP);
   1620  1.37.2.4  rmind 
   1621  1.37.2.4  rmind 	rn = makeprivate(VDIR, NODEV, DEV_BSIZE, false);
   1622  1.37.2.4  rmind 	rn->rn_parent = rn;
   1623  1.37.2.4  rmind 	if ((error = makevnode(mp, rn, &rfsmp->rfsmp_rvp)) != 0)
   1624  1.37.2.4  rmind 		return error;
   1625  1.37.2.4  rmind 
   1626  1.37.2.4  rmind 	rfsmp->rfsmp_rvp->v_vflag |= VV_ROOT;
   1627  1.37.2.4  rmind 	VOP_UNLOCK(rfsmp->rfsmp_rvp);
   1628  1.37.2.4  rmind 
   1629  1.37.2.4  rmind 	mp->mnt_data = rfsmp;
   1630  1.37.2.4  rmind 	mp->mnt_stat.f_namemax = MAXNAMLEN;
   1631  1.37.2.4  rmind 	mp->mnt_stat.f_iosize = 512;
   1632  1.37.2.4  rmind 	mp->mnt_flag |= MNT_LOCAL;
   1633  1.37.2.4  rmind 	mp->mnt_iflag |= IMNT_MPSAFE | IMNT_CAN_RWTORO;
   1634  1.37.2.4  rmind 	mp->mnt_fs_bshift = DEV_BSHIFT;
   1635  1.37.2.4  rmind 	vfs_getnewfsid(mp);
   1636  1.37.2.4  rmind 
   1637  1.37.2.4  rmind 	return 0;
   1638  1.37.2.4  rmind }
   1639  1.37.2.4  rmind 
   1640      1.30  pooka int
   1641      1.30  pooka rumpfs_mount(struct mount *mp, const char *mntpath, void *arg, size_t *alen)
   1642      1.30  pooka {
   1643  1.37.2.4  rmind 	int error;
   1644      1.30  pooka 
   1645  1.37.2.4  rmind 	if (mp->mnt_flag & MNT_UPDATE) {
   1646  1.37.2.4  rmind 		return 0;
   1647  1.37.2.4  rmind 	}
   1648  1.37.2.4  rmind 
   1649  1.37.2.4  rmind 	error = set_statvfs_info(mntpath, UIO_USERSPACE, "rumpfs", UIO_SYSSPACE,
   1650  1.37.2.4  rmind 	    mp->mnt_op->vfs_name, mp, curlwp);
   1651  1.37.2.4  rmind 	if (error)
   1652  1.37.2.4  rmind 		return error;
   1653  1.37.2.4  rmind 
   1654  1.37.2.4  rmind 	return rumpfs_mountfs(mp);
   1655      1.30  pooka }
   1656      1.30  pooka 
   1657      1.30  pooka int
   1658  1.37.2.4  rmind rumpfs_unmount(struct mount *mp, int mntflags)
   1659      1.30  pooka {
   1660  1.37.2.4  rmind 	struct rumpfs_mount *rfsmp = mp->mnt_data;
   1661  1.37.2.4  rmind 	int flags = 0, error;
   1662      1.30  pooka 
   1663  1.37.2.4  rmind 	if (panicstr || mntflags & MNT_FORCE)
   1664  1.37.2.4  rmind 		flags |= FORCECLOSE;
   1665  1.37.2.4  rmind 
   1666  1.37.2.4  rmind 	if ((error = vflush(mp, rfsmp->rfsmp_rvp, flags)) != 0)
   1667  1.37.2.4  rmind 		return error;
   1668  1.37.2.4  rmind 	vgone(rfsmp->rfsmp_rvp); /* XXX */
   1669      1.37  pooka 
   1670  1.37.2.4  rmind 	kmem_free(rfsmp, sizeof(*rfsmp));
   1671  1.37.2.4  rmind 
   1672  1.37.2.4  rmind 	return 0;
   1673      1.30  pooka }
   1674      1.30  pooka 
   1675      1.30  pooka int
   1676      1.30  pooka rumpfs_root(struct mount *mp, struct vnode **vpp)
   1677      1.30  pooka {
   1678      1.30  pooka 	struct rumpfs_mount *rfsmp = mp->mnt_data;
   1679      1.30  pooka 
   1680  1.37.2.4  rmind 	vref(rfsmp->rfsmp_rvp);
   1681  1.37.2.4  rmind 	vn_lock(rfsmp->rfsmp_rvp, LK_EXCLUSIVE | LK_RETRY);
   1682      1.30  pooka 	*vpp = rfsmp->rfsmp_rvp;
   1683      1.30  pooka 	return 0;
   1684      1.30  pooka }
   1685      1.30  pooka 
   1686      1.30  pooka int
   1687      1.30  pooka rumpfs_vget(struct mount *mp, ino_t ino, struct vnode **vpp)
   1688      1.30  pooka {
   1689      1.30  pooka 
   1690      1.30  pooka 	return EOPNOTSUPP;
   1691      1.30  pooka }
   1692      1.30  pooka 
   1693       1.1  pooka void
   1694      1.30  pooka rumpfs_init()
   1695       1.1  pooka {
   1696       1.1  pooka 
   1697      1.25  pooka 	CTASSERT(RUMP_ETFS_SIZE_ENDOFF == RUMPBLK_SIZENOTSET);
   1698      1.25  pooka 
   1699      1.14  pooka 	mutex_init(&reclock, MUTEX_DEFAULT, IPL_NONE);
   1700      1.21  pooka 	mutex_init(&etfs_lock, MUTEX_DEFAULT, IPL_NONE);
   1701      1.30  pooka }
   1702      1.30  pooka 
   1703      1.30  pooka void
   1704      1.30  pooka rumpfs_done()
   1705      1.30  pooka {
   1706      1.30  pooka 
   1707      1.30  pooka 	mutex_destroy(&reclock);
   1708      1.30  pooka 	mutex_destroy(&etfs_lock);
   1709      1.30  pooka }
   1710      1.14  pooka 
   1711      1.30  pooka int
   1712      1.30  pooka rumpfs_mountroot()
   1713      1.30  pooka {
   1714      1.30  pooka 	struct mount *mp;
   1715      1.30  pooka 	int error;
   1716      1.30  pooka 
   1717      1.30  pooka 	if ((error = vfs_rootmountalloc(MOUNT_RUMPFS, "rootdev", &mp)) != 0) {
   1718      1.30  pooka 		vrele(rootvp);
   1719      1.30  pooka 		return error;
   1720      1.30  pooka 	}
   1721      1.30  pooka 
   1722  1.37.2.4  rmind 	if ((error = rumpfs_mountfs(mp)) != 0)
   1723  1.37.2.4  rmind 		panic("mounting rootfs failed: %d", error);
   1724      1.30  pooka 
   1725      1.30  pooka 	mutex_enter(&mountlist_lock);
   1726      1.30  pooka 	CIRCLEQ_INSERT_TAIL(&mountlist, mp, mnt_list);
   1727      1.30  pooka 	mutex_exit(&mountlist_lock);
   1728      1.30  pooka 
   1729      1.33  pooka 	error = set_statvfs_info("/", UIO_SYSSPACE, "rumpfs", UIO_SYSSPACE,
   1730      1.33  pooka 	    mp->mnt_op->vfs_name, mp, curlwp);
   1731      1.33  pooka 	if (error)
   1732  1.37.2.4  rmind 		panic("set_statvfs_info failed for rootfs: %d", error);
   1733      1.33  pooka 
   1734  1.37.2.4  rmind 	mp->mnt_flag &= ~MNT_RDONLY;
   1735      1.30  pooka 	vfs_unbusy(mp, false, NULL);
   1736      1.30  pooka 
   1737      1.30  pooka 	return 0;
   1738      1.30  pooka }
   1739