xref: /netbsd-src/lib/libp2k/p2k.c (revision cdc507f0d27576e5c4f30629a5cfe9e1f5271dbe)
1*cdc507f0Sandvar /*	$NetBSD: p2k.c,v 1.75 2022/05/24 20:50:17 andvar Exp $	*/
2bdf6e0b0Spooka 
3bdf6e0b0Spooka /*
40605ce2bSpooka  * Copyright (c) 2007, 2008, 2009  Antti Kantee.  All Rights Reserved.
5bdf6e0b0Spooka  *
60605ce2bSpooka  * Development of this software was supported by the
70605ce2bSpooka  * Finnish Cultural Foundation.
8bdf6e0b0Spooka  *
9bdf6e0b0Spooka  * Redistribution and use in source and binary forms, with or without
10bdf6e0b0Spooka  * modification, are permitted provided that the following conditions
11bdf6e0b0Spooka  * are met:
12bdf6e0b0Spooka  * 1. Redistributions of source code must retain the above copyright
13bdf6e0b0Spooka  *    notice, this list of conditions and the following disclaimer.
14bdf6e0b0Spooka  * 2. Redistributions in binary form must reproduce the above copyright
15bdf6e0b0Spooka  *    notice, this list of conditions and the following disclaimer in the
16bdf6e0b0Spooka  *    documentation and/or other materials provided with the distribution.
17bdf6e0b0Spooka  *
18bdf6e0b0Spooka  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
19bdf6e0b0Spooka  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20bdf6e0b0Spooka  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21bdf6e0b0Spooka  * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22bdf6e0b0Spooka  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23bdf6e0b0Spooka  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24bdf6e0b0Spooka  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25bdf6e0b0Spooka  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26bdf6e0b0Spooka  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27bdf6e0b0Spooka  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28bdf6e0b0Spooka  * SUCH DAMAGE.
29bdf6e0b0Spooka  */
30bdf6e0b0Spooka 
31bdf6e0b0Spooka /*
32bdf6e0b0Spooka  * puffs 2k, i.e. puffs 2 kernel.  Converts the puffs protocol to
33bdf6e0b0Spooka  * the kernel vfs protocol and vice versa.
34bdf6e0b0Spooka  *
35bdf6e0b0Spooka  * A word about reference counting: puffs in the kernel is the king of
36bdf6e0b0Spooka  * reference counting.  We must maintain a vnode alive and kicking
37bdf6e0b0Spooka  * until the kernel tells us to reclaim it.  Therefore we make sure
38bdf6e0b0Spooka  * we never accidentally lose a vnode.  Before calling operations which
39bdf6e0b0Spooka  * decrease the refcount we always bump the refcount up to compensate.
40bdf6e0b0Spooka  * Come inactive, if the file system thinks that the vnode should be
41bdf6e0b0Spooka  * put out of its misery, it will set the recycle flag.  We use this
42bdf6e0b0Spooka  * to tell the kernel to reclaim the vnode.  Only in reclaim do we
43bdf6e0b0Spooka  * really nuke the last reference.
44bdf6e0b0Spooka  */
45bdf6e0b0Spooka 
4649d75a28Spooka #include <sys/cdefs.h>
47bdf6e0b0Spooka #include <sys/mount.h>
48bdf6e0b0Spooka #include <sys/param.h>
49bdf6e0b0Spooka #include <sys/lock.h>
50bdf6e0b0Spooka #include <sys/namei.h>
51bdf6e0b0Spooka #include <sys/dirent.h>
525290e6c8Spooka #include <sys/hash.h>
53bdf6e0b0Spooka 
54bdf6e0b0Spooka #include <assert.h>
55bdf6e0b0Spooka #include <errno.h>
56bdf6e0b0Spooka #include <puffs.h>
57bdf6e0b0Spooka #include <stdlib.h>
58c67ff293Spooka #include <stdio.h>
59bdf6e0b0Spooka 
60bdf6e0b0Spooka #include <rump/rump.h>
61d35b86acSpooka #include <rump/rumpvnode_if.h>
62bdf6e0b0Spooka #include <rump/p2k.h>
63bdf6e0b0Spooka #include <rump/ukfs.h>
64bdf6e0b0Spooka 
65421f4561Schristos #include <uvm/uvm_pager.h>
66421f4561Schristos 
6730df4c9fSpooka /* NetBSD-5 compat */
6830df4c9fSpooka #ifndef MOUNT_RUMPFS
6930df4c9fSpooka #define MOUNT_RUMPFS    "rumpfs"
7030df4c9fSpooka #endif
7130df4c9fSpooka 
72bdf6e0b0Spooka PUFFSOP_PROTOS(p2k)
73bdf6e0b0Spooka 
745290e6c8Spooka LIST_HEAD(p2k_vp_hash, p2k_node);
755290e6c8Spooka #define NHASHBUCK (1<<16)
765290e6c8Spooka struct p2k_mount {
775290e6c8Spooka 	struct vnode *p2m_rvp;
78476b5ba6Spooka 	struct puffs_usermount *p2m_pu;
79476b5ba6Spooka 	struct ukfs *p2m_ukfs;
805290e6c8Spooka 	struct p2k_vp_hash p2m_vphash[NHASHBUCK];
8130df4c9fSpooka 	struct mount *p2m_mp;
825290e6c8Spooka 	int p2m_nvnodes;
8313777d56Spooka 	int p2m_imtmpfsman;
84d16346a2Spooka 	bool p2m_hasdebug;
855290e6c8Spooka };
865290e6c8Spooka 
875290e6c8Spooka struct p2k_node {
88519089c8Smanu 	struct puffs_node p2n_pn;
895290e6c8Spooka 	struct vnode *p2n_vp;
905290e6c8Spooka 
915290e6c8Spooka 	LIST_ENTRY(p2k_node) p2n_entries;
925290e6c8Spooka };
935290e6c8Spooka 
945290e6c8Spooka #define OPC2VP(opc) (((struct p2k_node *)opc)->p2n_vp)
955290e6c8Spooka 
9696ae77caSpooka static int haswizard;
9796ae77caSpooka static uid_t wizarduid;
9896ae77caSpooka 
992734e549Spooka static struct kauth_cred *
cred_create(const struct puffs_cred * pcr)100bdf6e0b0Spooka cred_create(const struct puffs_cred *pcr)
101bdf6e0b0Spooka {
102bdf6e0b0Spooka 	gid_t groups[NGROUPS];
103bdf6e0b0Spooka 	uid_t uid;
104bdf6e0b0Spooka 	gid_t gid;
105251fbb35Spooka 	short ngroups = __arraycount(groups);
106bdf6e0b0Spooka 
10796ae77caSpooka 	if (haswizard) {
10896ae77caSpooka 		uid = wizarduid;
10996ae77caSpooka 	} else {
110bdf6e0b0Spooka 		if (puffs_cred_getuid(pcr, &uid) == -1)
111bdf6e0b0Spooka 			uid = 0;
11296ae77caSpooka 	}
113bdf6e0b0Spooka 	if (puffs_cred_getgid(pcr, &gid) == -1)
114bdf6e0b0Spooka 		gid = 0;
115bdf6e0b0Spooka 	puffs_cred_getgroups(pcr, groups, &ngroups);
116bdf6e0b0Spooka 
117bdf6e0b0Spooka 	/* LINTED: ngroups is ok */
118bf3992afSpooka 	return rump_pub_cred_create(uid, gid, ngroups, groups);
119bdf6e0b0Spooka }
120bdf6e0b0Spooka 
121bdf6e0b0Spooka static __inline void
cred_destroy(struct kauth_cred * cred)1222734e549Spooka cred_destroy(struct kauth_cred *cred)
123bdf6e0b0Spooka {
124bdf6e0b0Spooka 
125bf3992afSpooka 	rump_pub_cred_put(cred);
126bdf6e0b0Spooka }
127bdf6e0b0Spooka 
128bdf6e0b0Spooka static struct componentname *
makecn(const struct puffs_cn * pcn)1299670fcafSpooka makecn(const struct puffs_cn *pcn)
130bdf6e0b0Spooka {
1312734e549Spooka 	struct kauth_cred *cred;
132bdf6e0b0Spooka 
133bdf6e0b0Spooka 	cred = cred_create(pcn->pcn_cred);
134bdf6e0b0Spooka 	/* LINTED: prehistoric types in first two args */
1359670fcafSpooka 	return rump_pub_makecn(pcn->pcn_nameiop, pcn->pcn_flags,
136cd52561aSpooka 	    pcn->pcn_name, pcn->pcn_namelen, cred, rump_pub_lwproc_curlwp());
137bdf6e0b0Spooka }
138bdf6e0b0Spooka 
139bdf6e0b0Spooka static __inline void
freecn(struct componentname * cnp)1409670fcafSpooka freecn(struct componentname *cnp)
141bdf6e0b0Spooka {
142bdf6e0b0Spooka 
1439670fcafSpooka 	rump_pub_freecn(cnp, RUMPCN_FREECRED);
144bdf6e0b0Spooka }
145bdf6e0b0Spooka 
146bdf6e0b0Spooka static void
makelwp(struct puffs_usermount * pu)147bdf6e0b0Spooka makelwp(struct puffs_usermount *pu)
148bdf6e0b0Spooka {
149bdf6e0b0Spooka 	pid_t pid;
150bdf6e0b0Spooka 	lwpid_t lid;
151bdf6e0b0Spooka 
152bdf6e0b0Spooka 	puffs_cc_getcaller(puffs_cc_getcc(pu), &pid, &lid);
153cd52561aSpooka 	rump_pub_allbetsareoff_setid(pid, lid);
154bdf6e0b0Spooka }
155bdf6e0b0Spooka 
15627daa694Spooka static volatile sig_atomic_t dodump;
15727daa694Spooka static void
dumpmp(struct puffs_usermount * pu)15827daa694Spooka dumpmp(struct puffs_usermount *pu)
15927daa694Spooka {
16038a0431bSchristos 	struct puffs_statvfs svfsb;
16127daa694Spooka 
16227daa694Spooka 	if (dodump && p2k_fs_statvfs(pu, &svfsb) == 0) {
16327daa694Spooka 		rump_pub_vfs_mount_print(svfsb.f_mntonname, dodump-1);
16427daa694Spooka 	}
16527daa694Spooka 
16627daa694Spooka 	dodump = 0;
16727daa694Spooka }
16827daa694Spooka 
16927daa694Spooka static void
sighand(int sig)17027daa694Spooka sighand(int sig)
17127daa694Spooka {
17227daa694Spooka 
17327daa694Spooka 	if (sig == SIGINFO)
17427daa694Spooka 		dodump = 1;
17527daa694Spooka 	else if (sig == SIGUSR1)
17627daa694Spooka 		dodump = 2;
17727daa694Spooka }
17827daa694Spooka 
1795290e6c8Spooka static __inline struct p2k_vp_hash *
gethash(struct p2k_mount * p2m,struct vnode * vp)1805290e6c8Spooka gethash(struct p2k_mount *p2m, struct vnode *vp)
1815290e6c8Spooka {
1825290e6c8Spooka 	uint32_t hash;
1835290e6c8Spooka 
1845290e6c8Spooka 	hash = hash32_buf(&vp, sizeof(vp), HASH32_BUF_INIT);
1855290e6c8Spooka 	return &p2m->p2m_vphash[hash % NHASHBUCK];
1865290e6c8Spooka }
1875290e6c8Spooka 
1885290e6c8Spooka /*
1895290e6c8Spooka  * Find node based on hash of vnode pointer.  If vnode is found,
1905290e6c8Spooka  * releases one reference to vnode based on the fact that we just
1915290e6c8Spooka  * performed a lookup for it.
1925290e6c8Spooka  *
1935290e6c8Spooka  * If the optinal p2n_storage parameter is passed, it is used instead
1945290e6c8Spooka  * of allocating more memory.  This allows for easier error recovery.
1955290e6c8Spooka  */
1965290e6c8Spooka static struct p2k_node *
getp2n(struct p2k_mount * p2m,struct vnode * vp,bool initial,struct p2k_node * p2n_storage)1975290e6c8Spooka getp2n(struct p2k_mount *p2m, struct vnode *vp, bool initial,
1985290e6c8Spooka 	struct p2k_node *p2n_storage)
1995290e6c8Spooka {
2005290e6c8Spooka 	struct p2k_vp_hash *hl;
2015290e6c8Spooka 	struct p2k_node *p2n = NULL;
2025290e6c8Spooka 
2035290e6c8Spooka 	/* p2n_storage => initial */
2045290e6c8Spooka 	assert(!p2n_storage || initial);
2055290e6c8Spooka 
2065290e6c8Spooka 	hl = gethash(p2m, vp);
2075290e6c8Spooka 	if (!initial)
2085290e6c8Spooka 		LIST_FOREACH(p2n, hl, p2n_entries)
2095290e6c8Spooka 			if (p2n->p2n_vp == vp)
2105290e6c8Spooka 				break;
2115290e6c8Spooka 
2125290e6c8Spooka 	hl = gethash(p2m, vp);
2135290e6c8Spooka 	if (p2n) {
214bf3992afSpooka 		rump_pub_vp_rele(vp);
2155290e6c8Spooka 	} else {
2165290e6c8Spooka 		if (p2n_storage)
2175290e6c8Spooka 			p2n = p2n_storage;
2185290e6c8Spooka 		else
2195290e6c8Spooka 			p2n = malloc(sizeof(*p2n));
2205290e6c8Spooka 		if (!p2n) {
221bf3992afSpooka 			rump_pub_vp_rele(vp);
2225290e6c8Spooka 			return NULL;
2235290e6c8Spooka 		}
2245290e6c8Spooka 		memset(p2n, 0, sizeof(*p2n));
2255290e6c8Spooka 		LIST_INSERT_HEAD(hl, p2n, p2n_entries);
2265290e6c8Spooka 		p2n->p2n_vp = vp;
2275290e6c8Spooka 	}
2285290e6c8Spooka 	return p2n;
2295290e6c8Spooka }
2305290e6c8Spooka 
2315290e6c8Spooka static void
freep2n(struct p2k_node * p2n)2325290e6c8Spooka freep2n(struct p2k_node *p2n)
2335290e6c8Spooka {
2345290e6c8Spooka 
2355290e6c8Spooka 	assert(p2n->p2n_vp == NULL);
2365290e6c8Spooka 	LIST_REMOVE(p2n, p2n_entries);
2375290e6c8Spooka 	free(p2n);
2385290e6c8Spooka }
2395290e6c8Spooka 
240c69ace3cSpooka /*ARGSUSED*/
241c67ff293Spooka static void
p2k_errcatcher(struct puffs_usermount * pu,uint8_t type,int error,const char * str,puffs_cookie_t cook)242c67ff293Spooka p2k_errcatcher(struct puffs_usermount *pu, uint8_t type, int error,
243c67ff293Spooka 	const char *str, puffs_cookie_t cook)
244c67ff293Spooka {
245c67ff293Spooka 
246c67ff293Spooka 	fprintf(stderr, "type %d, error %d, cookie %p (%s)\n",
247c67ff293Spooka 	    type, error, cook, str);
248c67ff293Spooka 
249c67ff293Spooka 	/*
250c67ff293Spooka 	 * Trap all EINVAL responses to lookup.  It most likely means
251c67ff293Spooka 	 * that we supplied VNON/VBAD as the type.  The real kernel
252c67ff293Spooka 	 * doesn't panic from this either, but just handles it.
253c67ff293Spooka 	 */
254c67ff293Spooka 	if (type != PUFFS_VN_LOOKUP && error == EINVAL)
255c67ff293Spooka 		abort();
256c67ff293Spooka }
257c67ff293Spooka 
2585290e6c8Spooka /* just to avoid annoying loop when singlestepping */
25938a8ac9cSpooka static struct p2k_mount *
allocp2m(void)26038a8ac9cSpooka allocp2m(void)
2615290e6c8Spooka {
2625290e6c8Spooka 	struct p2k_mount *p2m;
2635290e6c8Spooka 	int i;
2645290e6c8Spooka 
2655290e6c8Spooka 	p2m = malloc(sizeof(*p2m));
26638a8ac9cSpooka 	if (p2m == NULL)
26738a8ac9cSpooka 		return NULL;
268476b5ba6Spooka 	memset(p2m, 0, sizeof(*p2m));
269476b5ba6Spooka 
2705290e6c8Spooka 	for (i = 0; i < NHASHBUCK; i++)
2715290e6c8Spooka 		LIST_INIT(&p2m->p2m_vphash[i]);
27238a8ac9cSpooka 
27338a8ac9cSpooka 	return p2m;
2745290e6c8Spooka }
2755290e6c8Spooka 
27638a8ac9cSpooka struct p2k_mount *
p2k_init(uint32_t puffs_flags)27738a8ac9cSpooka p2k_init(uint32_t puffs_flags)
278bdf6e0b0Spooka {
279bdf6e0b0Spooka 	struct puffs_ops *pops;
28038a8ac9cSpooka 	struct p2k_mount *p2m;
28196ae77caSpooka 	char *envbuf;
28202d2ab30Spooka 	bool dodaemon;
283d16346a2Spooka 	bool hasdebug;
284bdf6e0b0Spooka 
285bdf6e0b0Spooka 	PUFFSOP_INIT(pops);
286bdf6e0b0Spooka 
287bdf6e0b0Spooka 	PUFFSOP_SET(pops, p2k, fs, statvfs);
288bdf6e0b0Spooka 	PUFFSOP_SET(pops, p2k, fs, unmount);
289bdf6e0b0Spooka 	PUFFSOP_SET(pops, p2k, fs, sync);
290bdf6e0b0Spooka 	PUFFSOP_SET(pops, p2k, fs, fhtonode);
291bdf6e0b0Spooka 	PUFFSOP_SET(pops, p2k, fs, nodetofh);
29255a23816Spooka 	PUFFSOP_SET(pops, p2k, fs, extattrctl);
293bdf6e0b0Spooka 
294bdf6e0b0Spooka 	PUFFSOP_SET(pops, p2k, node, lookup);
295bdf6e0b0Spooka 	PUFFSOP_SET(pops, p2k, node, create);
296bdf6e0b0Spooka 	PUFFSOP_SET(pops, p2k, node, mknod);
297bdf6e0b0Spooka 	PUFFSOP_SET(pops, p2k, node, open);
298bdf6e0b0Spooka 	PUFFSOP_SET(pops, p2k, node, close);
299bdf6e0b0Spooka 	PUFFSOP_SET(pops, p2k, node, access);
300bdf6e0b0Spooka 	PUFFSOP_SET(pops, p2k, node, getattr);
301bdf6e0b0Spooka 	PUFFSOP_SET(pops, p2k, node, setattr);
302bdf6e0b0Spooka #if 0
303bdf6e0b0Spooka 	PUFFSOP_SET(pops, p2k, node, poll);
304bdf6e0b0Spooka #endif
305bdf6e0b0Spooka 	PUFFSOP_SET(pops, p2k, node, mmap);
306bdf6e0b0Spooka 	PUFFSOP_SET(pops, p2k, node, fsync);
307bdf6e0b0Spooka 	PUFFSOP_SET(pops, p2k, node, seek);
308bdf6e0b0Spooka 	PUFFSOP_SET(pops, p2k, node, remove);
309bdf6e0b0Spooka 	PUFFSOP_SET(pops, p2k, node, link);
310bdf6e0b0Spooka 	PUFFSOP_SET(pops, p2k, node, rename);
311bdf6e0b0Spooka 	PUFFSOP_SET(pops, p2k, node, mkdir);
312bdf6e0b0Spooka 	PUFFSOP_SET(pops, p2k, node, rmdir);
313bdf6e0b0Spooka 	PUFFSOP_SET(pops, p2k, node, symlink);
314bdf6e0b0Spooka 	PUFFSOP_SET(pops, p2k, node, readdir);
315bdf6e0b0Spooka 	PUFFSOP_SET(pops, p2k, node, readlink);
316bdf6e0b0Spooka 	PUFFSOP_SET(pops, p2k, node, read);
317bdf6e0b0Spooka 	PUFFSOP_SET(pops, p2k, node, write);
318bdf6e0b0Spooka 
3191cfb9937Spooka 	PUFFSOP_SET(pops, p2k, node, pathconf);
3201cfb9937Spooka 
321bdf6e0b0Spooka 	PUFFSOP_SET(pops, p2k, node, inactive);
322bdf6e0b0Spooka 	PUFFSOP_SET(pops, p2k, node, reclaim);
323bdf6e0b0Spooka 
32455a23816Spooka 	PUFFSOP_SET(pops, p2k, node, getextattr);
32555a23816Spooka 	PUFFSOP_SET(pops, p2k, node, setextattr);
32655a23816Spooka 	PUFFSOP_SET(pops, p2k, node, listextattr);
32755a23816Spooka 	PUFFSOP_SET(pops, p2k, node, deleteextattr);
32855a23816Spooka 
32902d2ab30Spooka 	dodaemon = true;
3309a9b93d4Spooka 	hasdebug = false;
3319a9b93d4Spooka 
33202d2ab30Spooka 	if (getenv("P2K_DEBUG") != NULL) {
33302d2ab30Spooka 		puffs_flags |= PUFFS_FLAG_OPDUMP;
33402d2ab30Spooka 		dodaemon = false;
335d16346a2Spooka 		hasdebug = true;
33602d2ab30Spooka 	}
33753b8d598Spooka 	if (getenv("P2K_NODETACH") != NULL) {
33853b8d598Spooka 		dodaemon = false;
33953b8d598Spooka 	}
34055a30cc8Spooka 	if (getenv("P2K_NOCACHE_PAGE") != NULL) {
34155a30cc8Spooka 		puffs_flags |= PUFFS_KFLAG_NOCACHE_PAGE;
34255a30cc8Spooka 	}
34355a30cc8Spooka 	if (getenv("P2K_NOCACHE_NAME") != NULL) {
34455a30cc8Spooka 		puffs_flags |= PUFFS_KFLAG_NOCACHE_NAME;
34555a30cc8Spooka 	}
34655a30cc8Spooka 	if (getenv("P2K_NOCACHE") != NULL) {
34755a30cc8Spooka 		puffs_flags |= PUFFS_KFLAG_NOCACHE;
34855a30cc8Spooka 	}
34996ae77caSpooka 	if ((envbuf = getenv("P2K_WIZARDUID")) != NULL) {
350357983ccSpooka 		char *ep;
351357983ccSpooka 
352357983ccSpooka 		wizarduid = strtoul(envbuf, &ep, 10);
353357983ccSpooka 		if (envbuf[0] == '\0' || *ep != '\0') {
354357983ccSpooka 			printf("P2K_WIZARDUID: invalid uid %s\n", envbuf);
355357983ccSpooka 		} else if (wizarduid > UID_MAX) {
356357983ccSpooka 			printf("P2K_WIZARDUID: uid %s out-of-range\n", envbuf);
357357983ccSpooka 		} else {
35896ae77caSpooka 			haswizard = 1;
35996ae77caSpooka 			printf("P2K WIZARD MODE: using uid %d\n", wizarduid);
36096ae77caSpooka 		}
361357983ccSpooka 	}
36202d2ab30Spooka 
363d256e384Smanu 	/*
364*cdc507f0Sandvar 	 * Explicitly tell that our cookies can be treated as
365d256e384Smanu 	 * puffs_node, since we never let libpuffs know by
366d256e384Smanu 	 * calling  call puffs_pn_new()
367d256e384Smanu 	 */
368d256e384Smanu 	puffs_flags |= PUFFS_FLAG_PNCOOKIE;
369d256e384Smanu 
37038a8ac9cSpooka 	p2m = allocp2m();
37138a8ac9cSpooka 	if (p2m == NULL)
37238a8ac9cSpooka 		return NULL;
37338a8ac9cSpooka 	p2m->p2m_pu = puffs_init(pops, PUFFS_DEFER, PUFFS_DEFER,
37438a8ac9cSpooka 	    PUFFS_DEFER, puffs_flags);
37538a8ac9cSpooka 	if (p2m->p2m_pu == NULL) {
37638a8ac9cSpooka 		int sverrno = errno;
37738a8ac9cSpooka 		free(p2m);
37838a8ac9cSpooka 		errno = sverrno;
37938a8ac9cSpooka 		return NULL;
38038a8ac9cSpooka 	}
381d16346a2Spooka 	p2m->p2m_hasdebug = hasdebug;
38238a8ac9cSpooka 
38338a8ac9cSpooka 	if (dodaemon) {
38438a8ac9cSpooka 		if (puffs_daemon(p2m->p2m_pu, 1, 1) == -1) {
38538a8ac9cSpooka 			int sverrno = errno;
38638a8ac9cSpooka 			p2k_cancel(p2m, sverrno);
38738a8ac9cSpooka 			errno = sverrno;
38838a8ac9cSpooka 			p2m = NULL;
38938a8ac9cSpooka 		}
39038a8ac9cSpooka 	}
39138a8ac9cSpooka 	if (p2m)
39238a8ac9cSpooka 		rump_init();
39338a8ac9cSpooka 
3943daddc03Spooka 	rump_pub_lwproc_rfork(RUMP_RFCFDG);
395cd52561aSpooka 
39638a8ac9cSpooka 	return p2m;
39738a8ac9cSpooka }
39838a8ac9cSpooka 
39938a8ac9cSpooka void
p2k_cancel(struct p2k_mount * p2m,int error)40038a8ac9cSpooka p2k_cancel(struct p2k_mount *p2m, int error)
40138a8ac9cSpooka {
40238a8ac9cSpooka 
40338a8ac9cSpooka 	puffs_cancel(p2m->p2m_pu, error);
40438a8ac9cSpooka 	free(p2m);
40538a8ac9cSpooka }
40638a8ac9cSpooka 
40738a8ac9cSpooka static int
setupfs(struct p2k_mount * p2m,const char * vfsname,const char * devpath,struct ukfs_part * part,const char * mountpath,int mntflags,void * arg,size_t alen)40838a8ac9cSpooka setupfs(struct p2k_mount *p2m, const char *vfsname, const char *devpath,
409a1c46739Spooka 	struct ukfs_part *part, const char *mountpath, int mntflags,
41038a8ac9cSpooka 	void *arg, size_t alen)
41138a8ac9cSpooka {
412a1c46739Spooka 	char partpath[UKFS_DEVICE_MAXPATHLEN];
413a1c46739Spooka 	char partbuf[UKFS_DEVICE_MAXSTR];
41438a8ac9cSpooka 	char typebuf[PUFFS_TYPELEN];
41538a8ac9cSpooka 	struct puffs_usermount *pu = p2m->p2m_pu;
41638a8ac9cSpooka 	struct p2k_node *p2n_root;
41738a8ac9cSpooka 	struct ukfs *ukfs = NULL;
41838a8ac9cSpooka 	extern int puffs_fakecc;
41938a8ac9cSpooka 	int rv = -1, sverrno;
42038a8ac9cSpooka 
421bdf6e0b0Spooka 	strcpy(typebuf, "p2k|");
422bdf6e0b0Spooka 	if (strcmp(vfsname, "puffs") == 0) { /* XXX */
423bdf6e0b0Spooka 		struct puffs_kargs *args = arg;
424bdf6e0b0Spooka 		strlcat(typebuf, args->pa_typename, sizeof(typebuf));
425bdf6e0b0Spooka 	} else {
426bdf6e0b0Spooka 		strlcat(typebuf, vfsname, sizeof(typebuf));
427bdf6e0b0Spooka 	}
428bdf6e0b0Spooka 
4290605ce2bSpooka 	strlcpy(partpath, devpath, sizeof(partpath));
430a1c46739Spooka 	if (ukfs_part_tostring(part, partbuf, sizeof(partbuf))) {
4310605ce2bSpooka 		strlcat(partpath, partbuf, sizeof(partpath));
4320605ce2bSpooka 	}
43338a8ac9cSpooka 	puffs_setmntinfo(pu, partpath, typebuf);
434710e4c1aSpooka 
435710e4c1aSpooka 	if (ukfs_init() == -1)
436476b5ba6Spooka 		goto out;
43730df4c9fSpooka 
43830df4c9fSpooka 	/*
43930df4c9fSpooka 	 * If we're mounting rumpfs, actually do no mount and redirect
44030df4c9fSpooka 	 * requests to rump fs namespace root.  Strictly speaking, this
441404fa78cSpooka 	 * is not correct, but I don't think anyone will notice.
442404fa78cSpooka 	 * After all, we're mostly interested in things which reside
443404fa78cSpooka 	 * specifically on the rootfs, namely the contents of /dev
44430df4c9fSpooka 	 */
44530df4c9fSpooka 	if (strcmp(vfsname, MOUNT_RUMPFS) == 0) {
44630df4c9fSpooka 		if ((rv = rump_pub_vfs_getmp("/", &p2m->p2m_mp)) != 0) {
44730df4c9fSpooka 			errno = rv;
44830df4c9fSpooka 			rv = -1;
44930df4c9fSpooka 			goto out;
45030df4c9fSpooka 		}
45130df4c9fSpooka 	} else {
452a1c46739Spooka 		if (part != ukfs_part_na)
453a1c46739Spooka 			ukfs = ukfs_mount_disk(vfsname, devpath, part,
4540605ce2bSpooka 			    mountpath, mntflags, arg, alen);
4550605ce2bSpooka 		else
4560605ce2bSpooka 			ukfs = ukfs_mount(vfsname, devpath, mountpath, mntflags,
4570605ce2bSpooka 			    arg, alen);
458710e4c1aSpooka 		if (ukfs == NULL)
459710e4c1aSpooka 			goto out;
46038a8ac9cSpooka 		ukfs_setspecific(ukfs, p2m);
461476b5ba6Spooka 		p2m->p2m_ukfs = ukfs;
46230df4c9fSpooka 		p2m->p2m_mp = ukfs_getmp(ukfs);
463607d9b61Spooka 	}
464607d9b61Spooka 	if ((rv = rump_pub_vfs_root(p2m->p2m_mp, &p2m->p2m_rvp, 0)) != 0) {
465607d9b61Spooka 		errno = rv;
466607d9b61Spooka 		rv = -1;
467607d9b61Spooka 		goto out;
46830df4c9fSpooka 	}
46930df4c9fSpooka 
470476b5ba6Spooka 	p2m->p2m_pu = pu;
471710e4c1aSpooka 
47213777d56Spooka 	/*
47313777d56Spooka 	 * Detect tmpfs.  XXX: this is a kludge.  See inactive().
47413777d56Spooka 	 *
47513777d56Spooka 	 * In reality we'd want "does file system use anon objects
47613777d56Spooka 	 * for storage?".  But since tmpfs hides the anon object from
47713777d56Spooka 	 * the public interface, we can't actually detect it sanely.
47813777d56Spooka 	 * Therefore, use this kludge.
47913777d56Spooka 	 */
48013777d56Spooka 	p2m->p2m_imtmpfsman = strcmp(vfsname, MOUNT_TMPFS) == 0;
48113777d56Spooka 
4825290e6c8Spooka 	p2n_root = getp2n(p2m, p2m->p2m_rvp, true, NULL);
483bdf6e0b0Spooka 	puffs_setfhsize(pu, 0, PUFFS_FHFLAG_PASSTHROUGH);
484bdf6e0b0Spooka 	puffs_setstacksize(pu, PUFFS_STACKSIZE_MIN);
485bdf6e0b0Spooka 	puffs_fakecc = 1;
486cd52561aSpooka 	puffs_set_prepost(pu, makelwp, NULL);
48727daa694Spooka 
48827daa694Spooka 	if (p2m->p2m_hasdebug) {
48927daa694Spooka 		struct timespec ts;
49027daa694Spooka 
49127daa694Spooka 		signal(SIGINFO, sighand);
49227daa694Spooka 		signal(SIGUSR1, sighand);
49327daa694Spooka 
49427daa694Spooka 		ts.tv_sec = 0;
49527daa694Spooka 		ts.tv_nsec = 1000*1000*10; /* 10ms */
49627daa694Spooka 		puffs_ml_setloopfn(pu, dumpmp);
49727daa694Spooka 		puffs_ml_settimeout(pu, &ts);
49827daa694Spooka 	}
499c67ff293Spooka 	puffs_set_errnotify(pu, p2k_errcatcher);
500bdf6e0b0Spooka 
50130df4c9fSpooka 	puffs_setspecific(pu, p2m);
50238a8ac9cSpooka 	rv = puffs_mount(pu, mountpath, mntflags, p2n_root);
503bdf6e0b0Spooka 
504bdf6e0b0Spooka  out:
50538a8ac9cSpooka 	if (rv == -1) {
506bdf6e0b0Spooka 		sverrno = errno;
50738a8ac9cSpooka 		puffs_cancel(pu, sverrno);
508710e4c1aSpooka 		if (ukfs)
509476b5ba6Spooka 			ukfs_release(p2m->p2m_ukfs, UKFS_RELFLAG_FORCE);
510476b5ba6Spooka 		free(p2m);
511bdf6e0b0Spooka 		errno = sverrno;
512bdf6e0b0Spooka 	}
513bdf6e0b0Spooka 
51438a8ac9cSpooka 	return rv;
515476b5ba6Spooka }
516476b5ba6Spooka 
517476b5ba6Spooka int
p2k_mainloop(struct p2k_mount * p2m)518476b5ba6Spooka p2k_mainloop(struct p2k_mount *p2m)
519476b5ba6Spooka {
520476b5ba6Spooka 	int rv, sverrno;
521476b5ba6Spooka 
522476b5ba6Spooka 	rv = puffs_mainloop(p2m->p2m_pu);
523476b5ba6Spooka 	sverrno = errno;
524476b5ba6Spooka 	puffs_exit(p2m->p2m_pu, 1);
525476b5ba6Spooka 	if (p2m->p2m_ukfs)
526476b5ba6Spooka 		ukfs_release(p2m->p2m_ukfs, UKFS_RELFLAG_FORCE);
527476b5ba6Spooka 	free(p2m);
528476b5ba6Spooka 
529476b5ba6Spooka 	if (rv == -1)
530476b5ba6Spooka 		errno = sverrno;
531bdf6e0b0Spooka 	return rv;
532bdf6e0b0Spooka }
533bdf6e0b0Spooka 
5340605ce2bSpooka int
p2k_run_fs(const char * vfsname,const char * devpath,const char * mountpath,int mntflags,void * arg,size_t alen,uint32_t puffs_flags)5350605ce2bSpooka p2k_run_fs(const char *vfsname, const char *devpath, const char *mountpath,
5360605ce2bSpooka 	int mntflags, void *arg, size_t alen, uint32_t puffs_flags)
5370605ce2bSpooka {
538476b5ba6Spooka 	struct p2k_mount *p2m;
53938a8ac9cSpooka 	int rv;
5400605ce2bSpooka 
54138a8ac9cSpooka 	p2m = p2k_init(puffs_flags);
542476b5ba6Spooka 	if (p2m == NULL)
543476b5ba6Spooka 		return -1;
544a1c46739Spooka 	rv = setupfs(p2m, vfsname, devpath, ukfs_part_na, mountpath,
54538a8ac9cSpooka 	    mntflags, arg, alen);
54638a8ac9cSpooka 	if (rv == -1)
54738a8ac9cSpooka 		return rv;
548476b5ba6Spooka 	return p2k_mainloop(p2m);
5490605ce2bSpooka }
5500605ce2bSpooka 
5510605ce2bSpooka int
p2k_run_diskfs(const char * vfsname,const char * devpath,struct ukfs_part * part,const char * mountpath,int mntflags,void * arg,size_t alen,uint32_t puffs_flags)552a1c46739Spooka p2k_run_diskfs(const char *vfsname, const char *devpath, struct ukfs_part *part,
5530605ce2bSpooka 	const char *mountpath, int mntflags, void *arg, size_t alen,
5540605ce2bSpooka 	uint32_t puffs_flags)
5550605ce2bSpooka {
556476b5ba6Spooka 	struct p2k_mount *p2m;
55738a8ac9cSpooka 	int rv;
5580605ce2bSpooka 
55938a8ac9cSpooka 	p2m = p2k_init(puffs_flags);
560476b5ba6Spooka 	if (p2m == NULL)
561476b5ba6Spooka 		return -1;
562a1c46739Spooka 	rv = setupfs(p2m, vfsname, devpath, part, mountpath, mntflags,
56338a8ac9cSpooka 	    arg, alen);
56438a8ac9cSpooka 	if (rv == -1)
56538a8ac9cSpooka 		return rv;
566476b5ba6Spooka 	return p2k_mainloop(p2m);
567476b5ba6Spooka }
568476b5ba6Spooka 
56938a8ac9cSpooka int
p2k_setup_fs(struct p2k_mount * p2m,const char * vfsname,const char * devpath,const char * mountpath,int mntflags,void * arg,size_t alen)57038a8ac9cSpooka p2k_setup_fs(struct p2k_mount *p2m, const char *vfsname, const char *devpath,
57138a8ac9cSpooka 	const char *mountpath, int mntflags, void *arg, size_t alen)
572476b5ba6Spooka {
573476b5ba6Spooka 
574a1c46739Spooka 	return setupfs(p2m, vfsname, devpath, ukfs_part_na, mountpath,
57538a8ac9cSpooka 	    mntflags, arg, alen);
576476b5ba6Spooka }
577476b5ba6Spooka 
57838a8ac9cSpooka int
p2k_setup_diskfs(struct p2k_mount * p2m,const char * vfsname,const char * devpath,struct ukfs_part * part,const char * mountpath,int mntflags,void * arg,size_t alen)57938a8ac9cSpooka p2k_setup_diskfs(struct p2k_mount *p2m, const char *vfsname,
580a1c46739Spooka 	const char *devpath, struct ukfs_part *part, const char *mountpath,
58138a8ac9cSpooka 	int mntflags, void *arg, size_t alen)
582476b5ba6Spooka {
583476b5ba6Spooka 
584a1c46739Spooka 	return setupfs(p2m, vfsname, devpath, part, mountpath, mntflags,
58538a8ac9cSpooka 	    arg, alen);
5860605ce2bSpooka }
5870605ce2bSpooka 
588bdf6e0b0Spooka int
p2k_fs_statvfs(struct puffs_usermount * pu,struct puffs_statvfs * sbp)58938a0431bSchristos p2k_fs_statvfs(struct puffs_usermount *pu, struct puffs_statvfs *sbp)
590bdf6e0b0Spooka {
59130df4c9fSpooka 	struct p2k_mount *p2m = puffs_getspecific(pu);
59230df4c9fSpooka 	struct mount *mp = p2m->p2m_mp;
59338a0431bSchristos 	struct statvfs sb;
59438a0431bSchristos 	puffs_statvfs_to_statvfs(sbp, &sb);
595bdf6e0b0Spooka 
59638a0431bSchristos 	return rump_pub_vfs_statvfs(mp, &sb);
597bdf6e0b0Spooka }
598bdf6e0b0Spooka 
599d51d08a7Spooka /*ARGSUSED*/
600bdf6e0b0Spooka int
p2k_fs_unmount(struct puffs_usermount * pu,int flags)601bdf6e0b0Spooka p2k_fs_unmount(struct puffs_usermount *pu, int flags)
602bdf6e0b0Spooka {
60330df4c9fSpooka 	struct p2k_mount *p2m = puffs_getspecific(pu);
60430df4c9fSpooka 	struct ukfs *fs = p2m->p2m_ukfs;
6055290e6c8Spooka 	int error = 0;
606bdf6e0b0Spooka 
607bf3992afSpooka 	rump_pub_vp_rele(p2m->p2m_rvp);
608cd52561aSpooka 
60930df4c9fSpooka 	if (fs) {
6105290e6c8Spooka 		if (ukfs_release(fs, 0) != 0) {
61138a0431bSchristos 			struct puffs_statvfs svfsb;
612d32ef440Spooka 
613d32ef440Spooka 			if (p2m->p2m_hasdebug
614d32ef440Spooka 			    && p2k_fs_statvfs(pu, &svfsb) == 0) {
615d32ef440Spooka 				printf("\nSOFT UNMOUNT FAILED, MP INFO DUMP\n");
616d32ef440Spooka 				rump_pub_vfs_mount_print(svfsb.f_mntonname, 1);
617d32ef440Spooka 			}
618d51d08a7Spooka 			ukfs_release(fs, UKFS_RELFLAG_FORCE);
6195290e6c8Spooka 			error = 0;
6205290e6c8Spooka 		}
62130df4c9fSpooka 	}
622476b5ba6Spooka 	p2m->p2m_ukfs = NULL;
623bdf6e0b0Spooka 
624d16346a2Spooka 	if (p2m->p2m_hasdebug) {
625d16346a2Spooka 		printf("-- rump kernel event counters --\n");
626d16346a2Spooka 		rump_printevcnts();
627d16346a2Spooka 		printf("-- end of event counters --\n");
628d16346a2Spooka 	}
629d16346a2Spooka 
6305290e6c8Spooka 	return error;
631bdf6e0b0Spooka }
632bdf6e0b0Spooka 
633bdf6e0b0Spooka int
p2k_fs_sync(struct puffs_usermount * pu,int waitfor,const struct puffs_cred * pcr)634bdf6e0b0Spooka p2k_fs_sync(struct puffs_usermount *pu, int waitfor,
635bdf6e0b0Spooka 	const struct puffs_cred *pcr)
636bdf6e0b0Spooka {
63730df4c9fSpooka 	struct p2k_mount *p2m = puffs_getspecific(pu);
63830df4c9fSpooka 	struct mount *mp = p2m->p2m_mp;
6392734e549Spooka 	struct kauth_cred *cred;
640bdf6e0b0Spooka 	int rv;
641bdf6e0b0Spooka 
642bdf6e0b0Spooka 	cred = cred_create(pcr);
6432734e549Spooka 	rv = rump_pub_vfs_sync(mp, waitfor, cred);
644bdf6e0b0Spooka 	cred_destroy(cred);
645bdf6e0b0Spooka 
646bdf6e0b0Spooka 	return rv;
647bdf6e0b0Spooka }
648bdf6e0b0Spooka 
649bdf6e0b0Spooka /*ARGSUSED*/
650bdf6e0b0Spooka int
p2k_fs_fhtonode(struct puffs_usermount * pu,void * fid,size_t fidsize,struct puffs_newinfo * pni)651bdf6e0b0Spooka p2k_fs_fhtonode(struct puffs_usermount *pu, void *fid, size_t fidsize,
652bdf6e0b0Spooka 	struct puffs_newinfo *pni)
653bdf6e0b0Spooka {
65430df4c9fSpooka 	struct p2k_mount *p2m = puffs_getspecific(pu);
65530df4c9fSpooka 	struct mount *mp = p2m->p2m_mp;
6565290e6c8Spooka 	struct p2k_node *p2n;
657bdf6e0b0Spooka 	struct vnode *vp;
658005755d8Spooka 	enum rump_vtype vtype;
659bdf6e0b0Spooka 	voff_t vsize;
6605290e6c8Spooka 	uint64_t rdev; /* XXX: allows running this on NetBSD 5.0 */
661bdf6e0b0Spooka 	int rv;
662bdf6e0b0Spooka 
663bf3992afSpooka 	rv = rump_pub_vfs_fhtovp(mp, fid, &vp);
664bdf6e0b0Spooka 	if (rv)
665bdf6e0b0Spooka 		return rv;
6661423e65bShannken 	RUMP_VOP_UNLOCK(vp);
667bdf6e0b0Spooka 
6685290e6c8Spooka 	p2n = getp2n(p2m, vp, false, NULL);
6695290e6c8Spooka 	if (p2n == NULL)
6705290e6c8Spooka 		return ENOMEM;
6715290e6c8Spooka 
6725290e6c8Spooka 	puffs_newinfo_setcookie(pni, p2n);
673bf3992afSpooka 	rump_pub_getvninfo(vp, &vtype, &vsize, (void *)&rdev);
674d3095eb5Sjoerg 	puffs_newinfo_setvtype(pni, (enum vtype)vtype);
675bdf6e0b0Spooka 	puffs_newinfo_setsize(pni, vsize);
6765290e6c8Spooka 	/* LINTED: yea, it'll lose accuracy, but that's life */
677bdf6e0b0Spooka 	puffs_newinfo_setrdev(pni, rdev);
678bdf6e0b0Spooka 
679bdf6e0b0Spooka 	return 0;
680bdf6e0b0Spooka }
681bdf6e0b0Spooka 
682bdf6e0b0Spooka /*ARGSUSED*/
683bdf6e0b0Spooka int
p2k_fs_nodetofh(struct puffs_usermount * pu,puffs_cookie_t cookie,void * fid,size_t * fidsize)6843fd391abSpooka p2k_fs_nodetofh(struct puffs_usermount *pu, puffs_cookie_t cookie, void *fid,
685bdf6e0b0Spooka 	size_t *fidsize)
686bdf6e0b0Spooka {
6874063bc51Spooka 	struct vnode *vp = OPC2VP(cookie);
688bdf6e0b0Spooka 
689bf3992afSpooka 	return rump_pub_vfs_vptofh(vp, fid, fidsize);
690bdf6e0b0Spooka }
691bdf6e0b0Spooka 
69255a23816Spooka int
p2k_fs_extattrctl(struct puffs_usermount * pu,int cmd,puffs_cookie_t cookie,int flags,int attrnamespace,const char * attrname)69355a23816Spooka p2k_fs_extattrctl(struct puffs_usermount *pu, int cmd,
69455a23816Spooka 	puffs_cookie_t cookie, int flags,
69555a23816Spooka 	int attrnamespace, const char *attrname)
69655a23816Spooka {
69755a23816Spooka 	struct p2k_mount *p2m = puffs_getspecific(pu);
69855a23816Spooka 	struct mount *mp = p2m->p2m_mp;
69955a23816Spooka 	struct vnode *vp;
70055a23816Spooka 
70155a23816Spooka 	if (flags & PUFFS_EXTATTRCTL_HASNODE) {
70255a23816Spooka 		vp = OPC2VP(cookie);
70355a23816Spooka 		RUMP_VOP_LOCK(vp, LK_EXCLUSIVE | LK_RETRY);
70455a23816Spooka 	} else {
70555a23816Spooka 		vp = NULL;
70655a23816Spooka 	}
70755a23816Spooka 
70855a23816Spooka 	/* vfsop unlocks (but doesn't release) vnode, so we're done here */
70955a23816Spooka 	return rump_pub_vfs_extattrctl(mp, cmd, vp, attrnamespace, attrname);
71055a23816Spooka }
71155a23816Spooka 
712bdf6e0b0Spooka /*ARGSUSED*/
713bdf6e0b0Spooka int
p2k_node_lookup(struct puffs_usermount * pu,puffs_cookie_t opc,struct puffs_newinfo * pni,const struct puffs_cn * pcn)7143fd391abSpooka p2k_node_lookup(struct puffs_usermount *pu, puffs_cookie_t opc,
715bdf6e0b0Spooka 	struct puffs_newinfo *pni, const struct puffs_cn *pcn)
716bdf6e0b0Spooka {
71730df4c9fSpooka 	struct p2k_mount *p2m = puffs_getspecific(pu);
7185290e6c8Spooka 	struct p2k_node *p2n_dir = opc, *p2n;
719bdf6e0b0Spooka 	struct componentname *cn;
7205290e6c8Spooka 	struct vnode *dvp = p2n_dir->p2n_vp, *vp;
721005755d8Spooka 	enum rump_vtype vtype;
722bdf6e0b0Spooka 	voff_t vsize;
72325c08576Spooka 	uint64_t rdev; /* XXX: uint64_t because of stack overwrite in compat */
724bdf6e0b0Spooka 	int rv;
725bdf6e0b0Spooka 
7269670fcafSpooka 	cn = makecn(pcn);
7275290e6c8Spooka 	RUMP_VOP_LOCK(dvp, LK_EXCLUSIVE);
7285290e6c8Spooka 	rv = RUMP_VOP_LOOKUP(dvp, &vp, cn);
7291423e65bShannken 	RUMP_VOP_UNLOCK(dvp);
7309670fcafSpooka 	freecn(cn);
7319670fcafSpooka 
732bdf6e0b0Spooka 	if (rv) {
733e6d33ac9Spooka 		if (rv == RUMP_EJUSTRETURN) {
734bdf6e0b0Spooka 			rv = ENOENT;
7355290e6c8Spooka 		}
736bdf6e0b0Spooka 		return rv;
737bdf6e0b0Spooka 	}
738bdf6e0b0Spooka 
7395290e6c8Spooka 	p2n = getp2n(p2m, vp, false, NULL);
7405290e6c8Spooka 	if (p2n == NULL) {
7415290e6c8Spooka 		return ENOMEM;
7425290e6c8Spooka 	}
7435290e6c8Spooka 
7445290e6c8Spooka 	puffs_newinfo_setcookie(pni, p2n);
745bf3992afSpooka 	rump_pub_getvninfo(vp, &vtype, &vsize, (void *)&rdev);
746d3095eb5Sjoerg 	puffs_newinfo_setvtype(pni, (enum vtype)vtype);
747bdf6e0b0Spooka 	puffs_newinfo_setsize(pni, vsize);
7485290e6c8Spooka 	/* LINTED: yea, it'll lose accuracy, but that's life */
749bdf6e0b0Spooka 	puffs_newinfo_setrdev(pni, rdev);
750bdf6e0b0Spooka 
751bdf6e0b0Spooka 	return 0;
752bdf6e0b0Spooka }
753bdf6e0b0Spooka 
75425c08576Spooka #define VERS_TIMECHANGE 599000700
75525c08576Spooka static int
needcompat(void)75625c08576Spooka needcompat(void)
75725c08576Spooka {
75825c08576Spooka 
759d51d08a7Spooka 	/*LINTED*/
76025c08576Spooka 	return __NetBSD_Version__ < VERS_TIMECHANGE
76143925050Spooka 	    && rump_getversion() >= VERS_TIMECHANGE;
76225c08576Spooka }
76325c08576Spooka 
76425c08576Spooka #define DOCOMPAT(va, va_compat)						\
76525c08576Spooka do {									\
76625c08576Spooka 	if (needcompat()) {						\
767bf3992afSpooka 		va_compat = rump_pub_vattr_init();			\
768bf3992afSpooka 		rump_pub_vattr50_to_vattr(va, va_compat);		\
76925c08576Spooka 	} else {							\
77025c08576Spooka 		va_compat = __UNCONST(va);				\
77125c08576Spooka 	}								\
772388550b0Srillig } while (0)
77325c08576Spooka 
77425c08576Spooka #define UNDOCOMPAT(va_compat)						\
77525c08576Spooka do {									\
77625c08576Spooka 	if (needcompat())						\
777bf3992afSpooka 		rump_pub_vattr_free(va_compat);				\
778388550b0Srillig } while (0)
77925c08576Spooka 
7805290e6c8Spooka static int
do_makenode(struct puffs_usermount * pu,struct p2k_node * p2n_dir,struct puffs_newinfo * pni,const struct puffs_cn * pcn,const struct vattr * vap,char * link_target,int (* makefn)(struct vnode *,struct vnode **,struct componentname *,struct vattr *),int (* symfn)(struct vnode *,struct vnode **,struct componentname *,struct vattr *,char *))7815290e6c8Spooka do_makenode(struct puffs_usermount *pu, struct p2k_node *p2n_dir,
7825290e6c8Spooka 	struct puffs_newinfo *pni, const struct puffs_cn *pcn,
7835290e6c8Spooka 	const struct vattr *vap, char *link_target,
7845290e6c8Spooka 	int (*makefn)(struct vnode *, struct vnode **, struct componentname *,
7855290e6c8Spooka 		      struct vattr *),
7865290e6c8Spooka 	int (*symfn)(struct vnode *, struct vnode **, struct componentname *,
7875290e6c8Spooka 		      struct vattr *, char *))
7885290e6c8Spooka {
78930df4c9fSpooka 	struct p2k_mount *p2m = puffs_getspecific(pu);
7905290e6c8Spooka 	struct vnode *dvp = p2n_dir->p2n_vp;
7915290e6c8Spooka 	struct p2k_node *p2n;
7925290e6c8Spooka 	struct componentname *cn;
7935290e6c8Spooka 	struct vattr *va_x;
794f638f19cSriastradh 	struct vnode *vp = NULL;
7955290e6c8Spooka 	int rv;
7965290e6c8Spooka 
7975290e6c8Spooka 	p2n = malloc(sizeof(*p2n));
7985290e6c8Spooka 	if (p2n == NULL)
7995290e6c8Spooka 		return ENOMEM;
8005290e6c8Spooka 	DOCOMPAT(vap, va_x);
8015290e6c8Spooka 
8029670fcafSpooka 	cn = makecn(pcn);
8035290e6c8Spooka 	RUMP_VOP_LOCK(dvp, LK_EXCLUSIVE);
804bf3992afSpooka 	rump_pub_vp_incref(dvp);
8055290e6c8Spooka 	if (makefn) {
8065290e6c8Spooka 		rv = makefn(dvp, &vp, cn, va_x);
8075290e6c8Spooka 	} else {
8085290e6c8Spooka 		rv = symfn(dvp, &vp, cn, va_x, link_target);
8095290e6c8Spooka 	}
810c89a5913Sriastradh 	rump_pub_vp_rele(dvp);
81111392744Shannken 	RUMP_VOP_UNLOCK(dvp);
8129670fcafSpooka 	freecn(cn);
8135290e6c8Spooka 
8145290e6c8Spooka 	if (rv == 0) {
8155290e6c8Spooka 		p2n = getp2n(p2m, vp, true, p2n);
8165290e6c8Spooka 		puffs_newinfo_setcookie(pni, p2n);
8175290e6c8Spooka 	} else {
8185290e6c8Spooka 		free(p2n);
8195290e6c8Spooka 	}
8205290e6c8Spooka 
8215290e6c8Spooka 	UNDOCOMPAT(va_x);
8225290e6c8Spooka 
8235290e6c8Spooka 	return rv;
8245290e6c8Spooka 
8255290e6c8Spooka }
8265290e6c8Spooka 
827bdf6e0b0Spooka /*ARGSUSED*/
828bdf6e0b0Spooka int
p2k_node_create(struct puffs_usermount * pu,puffs_cookie_t opc,struct puffs_newinfo * pni,const struct puffs_cn * pcn,const struct vattr * vap)8293fd391abSpooka p2k_node_create(struct puffs_usermount *pu, puffs_cookie_t opc,
830bdf6e0b0Spooka 	struct puffs_newinfo *pni, const struct puffs_cn *pcn,
831bdf6e0b0Spooka 	const struct vattr *vap)
832bdf6e0b0Spooka {
833bdf6e0b0Spooka 
8345290e6c8Spooka 	return do_makenode(pu, opc, pni, pcn, vap, NULL, RUMP_VOP_CREATE, NULL);
835bdf6e0b0Spooka }
836bdf6e0b0Spooka 
837bdf6e0b0Spooka /*ARGSUSED*/
838bdf6e0b0Spooka int
p2k_node_mknod(struct puffs_usermount * pu,puffs_cookie_t opc,struct puffs_newinfo * pni,const struct puffs_cn * pcn,const struct vattr * vap)8393fd391abSpooka p2k_node_mknod(struct puffs_usermount *pu, puffs_cookie_t opc,
8403fd391abSpooka 	struct puffs_newinfo *pni, const struct puffs_cn *pcn,
8413fd391abSpooka 	const struct vattr *vap)
842bdf6e0b0Spooka {
843bdf6e0b0Spooka 
8445290e6c8Spooka 	return do_makenode(pu, opc, pni, pcn, vap, NULL, RUMP_VOP_MKNOD, NULL);
845bdf6e0b0Spooka }
846bdf6e0b0Spooka 
847bdf6e0b0Spooka /*ARGSUSED*/
848bdf6e0b0Spooka int
p2k_node_open(struct puffs_usermount * pu,puffs_cookie_t opc,int mode,const struct puffs_cred * pcr)8493fd391abSpooka p2k_node_open(struct puffs_usermount *pu, puffs_cookie_t opc, int mode,
850bdf6e0b0Spooka 	const struct puffs_cred *pcr)
851bdf6e0b0Spooka {
8525290e6c8Spooka 	struct vnode *vp = OPC2VP(opc);
8532734e549Spooka 	struct kauth_cred *cred;
854bdf6e0b0Spooka 	int rv;
855bdf6e0b0Spooka 
856bdf6e0b0Spooka 	cred = cred_create(pcr);
8575290e6c8Spooka 	RUMP_VOP_LOCK(vp, LK_EXCLUSIVE);
8585290e6c8Spooka 	rv = RUMP_VOP_OPEN(vp, mode, cred);
8591423e65bShannken 	RUMP_VOP_UNLOCK(vp);
860bdf6e0b0Spooka 	cred_destroy(cred);
861bdf6e0b0Spooka 
862bdf6e0b0Spooka 	return rv;
863bdf6e0b0Spooka }
864bdf6e0b0Spooka 
865bdf6e0b0Spooka /*ARGSUSED*/
866bdf6e0b0Spooka int
p2k_node_close(struct puffs_usermount * pu,puffs_cookie_t opc,int flags,const struct puffs_cred * pcr)8673fd391abSpooka p2k_node_close(struct puffs_usermount *pu, puffs_cookie_t opc, int flags,
868bdf6e0b0Spooka 	const struct puffs_cred *pcr)
869bdf6e0b0Spooka {
8705290e6c8Spooka 	struct vnode *vp = OPC2VP(opc);
8712734e549Spooka 	struct kauth_cred *cred;
872bdf6e0b0Spooka 
873bdf6e0b0Spooka 	cred = cred_create(pcr);
8745290e6c8Spooka 	RUMP_VOP_LOCK(vp, LK_EXCLUSIVE);
8755290e6c8Spooka 	RUMP_VOP_CLOSE(vp, flags, cred);
8761423e65bShannken 	RUMP_VOP_UNLOCK(vp);
877bdf6e0b0Spooka 	cred_destroy(cred);
878bdf6e0b0Spooka 
879bdf6e0b0Spooka 	return 0;
880bdf6e0b0Spooka }
881bdf6e0b0Spooka 
882bdf6e0b0Spooka /*ARGSUSED*/
883bdf6e0b0Spooka int
p2k_node_access(struct puffs_usermount * pu,puffs_cookie_t opc,int mode,const struct puffs_cred * pcr)8843fd391abSpooka p2k_node_access(struct puffs_usermount *pu, puffs_cookie_t opc, int mode,
885bdf6e0b0Spooka 	const struct puffs_cred *pcr)
886bdf6e0b0Spooka {
8875290e6c8Spooka 	struct vnode *vp = OPC2VP(opc);
8882734e549Spooka 	struct kauth_cred *cred;
889bdf6e0b0Spooka 	int rv;
890bdf6e0b0Spooka 
891bdf6e0b0Spooka 	cred = cred_create(pcr);
8925290e6c8Spooka 	RUMP_VOP_LOCK(vp, LK_EXCLUSIVE);
8935290e6c8Spooka 	rv = RUMP_VOP_ACCESS(vp, mode, cred);
8941423e65bShannken 	RUMP_VOP_UNLOCK(vp);
895bdf6e0b0Spooka 	cred_destroy(cred);
896bdf6e0b0Spooka 
897bdf6e0b0Spooka 	return rv;
898bdf6e0b0Spooka }
899bdf6e0b0Spooka 
900bdf6e0b0Spooka /*ARGSUSED*/
901bdf6e0b0Spooka int
p2k_node_getattr(struct puffs_usermount * pu,puffs_cookie_t opc,struct vattr * vap,const struct puffs_cred * pcr)9023fd391abSpooka p2k_node_getattr(struct puffs_usermount *pu, puffs_cookie_t opc,
9033fd391abSpooka 	struct vattr *vap, const struct puffs_cred *pcr)
904bdf6e0b0Spooka {
9055290e6c8Spooka 	struct vnode *vp = OPC2VP(opc);
9062734e549Spooka 	struct kauth_cred *cred;
90725c08576Spooka 	struct vattr *va_x;
908bdf6e0b0Spooka 	int rv;
909bdf6e0b0Spooka 
910a06931dbSpooka 	/* "deadfs" */
911a06931dbSpooka 	if (!vp)
912a06931dbSpooka 		return 0;
913a06931dbSpooka 
91425c08576Spooka 	if (needcompat()) {
915bf3992afSpooka 		va_x = rump_pub_vattr_init();
91625c08576Spooka 	} else {
91725c08576Spooka 		va_x = vap;
91825c08576Spooka 	}
91925c08576Spooka 
920bdf6e0b0Spooka 	cred = cred_create(pcr);
9215290e6c8Spooka 	RUMP_VOP_LOCK(vp, LK_EXCLUSIVE);
9225290e6c8Spooka 	rv = RUMP_VOP_GETATTR(vp, va_x, cred);
9231423e65bShannken 	RUMP_VOP_UNLOCK(vp);
924bdf6e0b0Spooka 	cred_destroy(cred);
925bdf6e0b0Spooka 
92625c08576Spooka 	if (needcompat()) {
927bf3992afSpooka 		rump_pub_vattr_to_vattr50(va_x, vap);
928bf3992afSpooka 		rump_pub_vattr_free(va_x);
92925c08576Spooka 	}
93025c08576Spooka 
931bdf6e0b0Spooka 	return rv;
932bdf6e0b0Spooka }
933bdf6e0b0Spooka 
934bdf6e0b0Spooka /*ARGSUSED*/
935bdf6e0b0Spooka int
p2k_node_setattr(struct puffs_usermount * pu,puffs_cookie_t opc,const struct vattr * vap,const struct puffs_cred * pcr)9363fd391abSpooka p2k_node_setattr(struct puffs_usermount *pu, puffs_cookie_t opc,
9373fd391abSpooka 	const struct vattr *vap, const struct puffs_cred *pcr)
938bdf6e0b0Spooka {
9395290e6c8Spooka 	struct vnode *vp = OPC2VP(opc);
9402734e549Spooka 	struct kauth_cred *cred;
94125c08576Spooka 	struct vattr *va_x;
942bdf6e0b0Spooka 	int rv;
943bdf6e0b0Spooka 
9445290e6c8Spooka 	/* "deadfs" */
9455290e6c8Spooka 	if (!vp)
9465290e6c8Spooka 		return 0;
9475290e6c8Spooka 
94825c08576Spooka 	DOCOMPAT(vap, va_x);
94925c08576Spooka 
950bdf6e0b0Spooka 	cred = cred_create(pcr);
9515290e6c8Spooka 	RUMP_VOP_LOCK(vp, LK_EXCLUSIVE);
9525290e6c8Spooka 	rv = RUMP_VOP_SETATTR(vp, va_x, cred);
9531423e65bShannken 	RUMP_VOP_UNLOCK(vp);
954bdf6e0b0Spooka 	cred_destroy(cred);
955bdf6e0b0Spooka 
95625c08576Spooka 	UNDOCOMPAT(va_x);
95725c08576Spooka 
958bdf6e0b0Spooka 	return rv;
959bdf6e0b0Spooka }
960bdf6e0b0Spooka 
961bdf6e0b0Spooka /*ARGSUSED*/
962bdf6e0b0Spooka int
p2k_node_fsync(struct puffs_usermount * pu,puffs_cookie_t opc,const struct puffs_cred * pcr,int flags,off_t offlo,off_t offhi)9633fd391abSpooka p2k_node_fsync(struct puffs_usermount *pu, puffs_cookie_t opc,
964bdf6e0b0Spooka 	const struct puffs_cred *pcr, int flags, off_t offlo, off_t offhi)
965bdf6e0b0Spooka {
9665290e6c8Spooka 	struct vnode *vp = OPC2VP(opc);
9672734e549Spooka 	struct kauth_cred *cred;
968bdf6e0b0Spooka 	int rv;
969bdf6e0b0Spooka 
9705290e6c8Spooka 	/* "deadfs" */
9715290e6c8Spooka 	if (!vp)
9725290e6c8Spooka 		return 0;
9735290e6c8Spooka 
974bdf6e0b0Spooka 	cred = cred_create(pcr);
9755290e6c8Spooka 	RUMP_VOP_LOCK(vp, LK_EXCLUSIVE);
9765290e6c8Spooka 	rv = RUMP_VOP_FSYNC(vp, cred, flags, offlo, offhi);
9771423e65bShannken 	RUMP_VOP_UNLOCK(vp);
978bdf6e0b0Spooka 	cred_destroy(cred);
979bdf6e0b0Spooka 
980bdf6e0b0Spooka 	return rv;
981bdf6e0b0Spooka }
982bdf6e0b0Spooka 
983bdf6e0b0Spooka /*ARGSUSED*/
984bdf6e0b0Spooka int
p2k_node_mmap(struct puffs_usermount * pu,puffs_cookie_t opc,vm_prot_t flags,const struct puffs_cred * pcr)9853fd391abSpooka p2k_node_mmap(struct puffs_usermount *pu, puffs_cookie_t opc, vm_prot_t flags,
986bdf6e0b0Spooka 	const struct puffs_cred *pcr)
987bdf6e0b0Spooka {
9882734e549Spooka 	struct kauth_cred *cred;
989bdf6e0b0Spooka 	int rv;
990bdf6e0b0Spooka 
991bdf6e0b0Spooka 	cred = cred_create(pcr);
9925290e6c8Spooka 	rv = RUMP_VOP_MMAP(OPC2VP(opc), flags, cred);
993bdf6e0b0Spooka 	cred_destroy(cred);
994bdf6e0b0Spooka 
995bdf6e0b0Spooka 	return rv;
996bdf6e0b0Spooka }
997bdf6e0b0Spooka 
998bdf6e0b0Spooka /*ARGSUSED*/
999bdf6e0b0Spooka int
p2k_node_seek(struct puffs_usermount * pu,puffs_cookie_t opc,off_t oldoff,off_t newoff,const struct puffs_cred * pcr)10003fd391abSpooka p2k_node_seek(struct puffs_usermount *pu, puffs_cookie_t opc,
10013fd391abSpooka 	off_t oldoff, off_t newoff, const struct puffs_cred *pcr)
1002bdf6e0b0Spooka {
10035290e6c8Spooka 	struct vnode *vp = OPC2VP(opc);
10042734e549Spooka 	struct kauth_cred *cred;
1005bdf6e0b0Spooka 	int rv;
1006bdf6e0b0Spooka 
1007bdf6e0b0Spooka 	cred = cred_create(pcr);
10085290e6c8Spooka 	RUMP_VOP_LOCK(vp, LK_EXCLUSIVE);
10095290e6c8Spooka 	rv = RUMP_VOP_SEEK(vp, oldoff, newoff, cred);
10101423e65bShannken 	RUMP_VOP_UNLOCK(vp);
1011bdf6e0b0Spooka 	cred_destroy(cred);
1012bdf6e0b0Spooka 
1013bdf6e0b0Spooka 	return rv;
1014bdf6e0b0Spooka }
1015bdf6e0b0Spooka 
10165290e6c8Spooka static int
do_nukenode(struct p2k_node * p2n_dir,struct p2k_node * p2n,const struct puffs_cn * pcn,int (* nukefn)(struct vnode *,struct vnode *,struct componentname *))10175290e6c8Spooka do_nukenode(struct p2k_node *p2n_dir, struct p2k_node *p2n,
10185290e6c8Spooka 	const struct puffs_cn *pcn,
10195290e6c8Spooka 	int (*nukefn)(struct vnode *, struct vnode *, struct componentname *))
10205290e6c8Spooka {
10215290e6c8Spooka 	struct vnode *dvp = p2n_dir->p2n_vp, *vp = p2n->p2n_vp;
10225290e6c8Spooka 	struct componentname *cn;
10235290e6c8Spooka 	int rv;
10245290e6c8Spooka 
10259670fcafSpooka 	cn = makecn(pcn);
10265290e6c8Spooka 	RUMP_VOP_LOCK(dvp, LK_EXCLUSIVE);
1027bf3992afSpooka 	rump_pub_vp_incref(dvp);
10285290e6c8Spooka 	RUMP_VOP_LOCK(vp, LK_EXCLUSIVE);
1029bf3992afSpooka 	rump_pub_vp_incref(vp);
10305290e6c8Spooka 	rv = nukefn(dvp, vp, cn);
10316fa7b158Sriastradh 	assert(dvp != vp);
10326fa7b158Sriastradh 	assert(RUMP_VOP_ISLOCKED(dvp) == LK_EXCLUSIVE);
10335290e6c8Spooka 	assert(RUMP_VOP_ISLOCKED(vp) == 0);
10346fa7b158Sriastradh 	rump_pub_vp_rele(dvp);
10356fa7b158Sriastradh 	RUMP_VOP_UNLOCK(dvp);
10369670fcafSpooka 	freecn(cn);
10375290e6c8Spooka 
10385290e6c8Spooka 	return rv;
10395290e6c8Spooka 
10405290e6c8Spooka }
10415290e6c8Spooka 
1042bdf6e0b0Spooka /*ARGSUSED*/
1043bdf6e0b0Spooka int
p2k_node_remove(struct puffs_usermount * pu,puffs_cookie_t opc,puffs_cookie_t targ,const struct puffs_cn * pcn)10443fd391abSpooka p2k_node_remove(struct puffs_usermount *pu, puffs_cookie_t opc,
10453fd391abSpooka 	puffs_cookie_t targ, const struct puffs_cn *pcn)
1046bdf6e0b0Spooka {
1047bdf6e0b0Spooka 
10485290e6c8Spooka 	return do_nukenode(opc, targ, pcn, RUMP_VOP_REMOVE);
1049bdf6e0b0Spooka }
1050bdf6e0b0Spooka 
1051bdf6e0b0Spooka /*ARGSUSED*/
1052bdf6e0b0Spooka int
p2k_node_link(struct puffs_usermount * pu,puffs_cookie_t opc,puffs_cookie_t targ,const struct puffs_cn * pcn)10533fd391abSpooka p2k_node_link(struct puffs_usermount *pu, puffs_cookie_t opc,
10543fd391abSpooka 	puffs_cookie_t targ, const struct puffs_cn *pcn)
1055bdf6e0b0Spooka {
10565290e6c8Spooka 	struct vnode *dvp = OPC2VP(opc);
1057bdf6e0b0Spooka 	struct componentname *cn;
1058bdf6e0b0Spooka 	int rv;
1059bdf6e0b0Spooka 
10609670fcafSpooka 	cn = makecn(pcn);
10615290e6c8Spooka 	RUMP_VOP_LOCK(dvp, LK_EXCLUSIVE);
1062bf3992afSpooka 	rump_pub_vp_incref(dvp);
10635290e6c8Spooka 	rv = RUMP_VOP_LINK(dvp, OPC2VP(targ), cn);
106446e71c7dSriastradh 	rump_pub_vp_rele(dvp);
106546e71c7dSriastradh 	RUMP_VOP_UNLOCK(dvp);
10669670fcafSpooka 	freecn(cn);
1067bdf6e0b0Spooka 
1068bdf6e0b0Spooka 	return rv;
1069bdf6e0b0Spooka }
1070bdf6e0b0Spooka 
1071bdf6e0b0Spooka /*ARGSUSED*/
1072bdf6e0b0Spooka int
p2k_node_rename(struct puffs_usermount * pu,puffs_cookie_t src_dir,puffs_cookie_t src,const struct puffs_cn * pcn_src,puffs_cookie_t targ_dir,puffs_cookie_t targ,const struct puffs_cn * pcn_targ)10733fd391abSpooka p2k_node_rename(struct puffs_usermount *pu,
10743fd391abSpooka 	puffs_cookie_t src_dir, puffs_cookie_t src,
10753fd391abSpooka 	const struct puffs_cn *pcn_src,
10763fd391abSpooka 	puffs_cookie_t targ_dir, puffs_cookie_t targ,
1077bdf6e0b0Spooka 	const struct puffs_cn *pcn_targ)
1078bdf6e0b0Spooka {
10795290e6c8Spooka 	struct vnode *dvp, *vp, *tdvp, *tvp = NULL;
1080bdf6e0b0Spooka 	struct componentname *cn_src, *cn_targ;
1081bdf6e0b0Spooka 	int rv;
1082bdf6e0b0Spooka 
10839670fcafSpooka 	cn_src = makecn(pcn_src);
10849670fcafSpooka 	cn_targ = makecn(pcn_targ);
10855290e6c8Spooka 
10865290e6c8Spooka 	dvp = OPC2VP(src_dir);
10875290e6c8Spooka 	vp = OPC2VP(src);
10885290e6c8Spooka 	tdvp = OPC2VP(targ_dir);
10895290e6c8Spooka 	if (targ) {
10905290e6c8Spooka 		tvp = OPC2VP(targ);
10915290e6c8Spooka 	}
10925290e6c8Spooka 
1093bf3992afSpooka 	rump_pub_vp_incref(dvp);
1094bf3992afSpooka 	rump_pub_vp_incref(vp);
10955290e6c8Spooka 	RUMP_VOP_LOCK(tdvp, LK_EXCLUSIVE);
1096bf3992afSpooka 	rump_pub_vp_incref(tdvp);
10975290e6c8Spooka 	if (tvp) {
10985290e6c8Spooka 		RUMP_VOP_LOCK(tvp, LK_EXCLUSIVE);
1099bf3992afSpooka 		rump_pub_vp_incref(tvp);
11005290e6c8Spooka 	}
11015290e6c8Spooka 	rv = RUMP_VOP_RENAME(dvp, vp, cn_src, tdvp, tvp, cn_targ);
11025290e6c8Spooka 	assert(RUMP_VOP_ISLOCKED(tdvp) == 0);
11035290e6c8Spooka 	if (tvp) {
11045290e6c8Spooka 		assert(RUMP_VOP_ISLOCKED(tvp) == 0);
11055290e6c8Spooka 	}
11069670fcafSpooka 	freecn(cn_src);
11079670fcafSpooka 	freecn(cn_targ);
1108bdf6e0b0Spooka 
1109bdf6e0b0Spooka 	return rv;
1110bdf6e0b0Spooka }
1111bdf6e0b0Spooka 
1112bdf6e0b0Spooka /*ARGSUSED*/
1113bdf6e0b0Spooka int
p2k_node_mkdir(struct puffs_usermount * pu,puffs_cookie_t opc,struct puffs_newinfo * pni,const struct puffs_cn * pcn,const struct vattr * vap)11143fd391abSpooka p2k_node_mkdir(struct puffs_usermount *pu, puffs_cookie_t opc,
11153fd391abSpooka 	struct puffs_newinfo *pni, const struct puffs_cn *pcn,
11163fd391abSpooka 	const struct vattr *vap)
1117bdf6e0b0Spooka {
1118bdf6e0b0Spooka 
11195290e6c8Spooka 	return do_makenode(pu, opc, pni, pcn, vap, NULL, RUMP_VOP_MKDIR, NULL);
1120bdf6e0b0Spooka }
1121bdf6e0b0Spooka 
1122bdf6e0b0Spooka /*ARGSUSED*/
1123bdf6e0b0Spooka int
p2k_node_rmdir(struct puffs_usermount * pu,puffs_cookie_t opc,puffs_cookie_t targ,const struct puffs_cn * pcn)11243fd391abSpooka p2k_node_rmdir(struct puffs_usermount *pu, puffs_cookie_t opc,
11253fd391abSpooka 	puffs_cookie_t targ, const struct puffs_cn *pcn)
1126bdf6e0b0Spooka {
1127bdf6e0b0Spooka 
11285290e6c8Spooka 	return do_nukenode(opc, targ, pcn, RUMP_VOP_RMDIR);
1129bdf6e0b0Spooka }
1130bdf6e0b0Spooka 
1131bdf6e0b0Spooka /*ARGSUSED*/
1132bdf6e0b0Spooka int
p2k_node_symlink(struct puffs_usermount * pu,puffs_cookie_t opc,struct puffs_newinfo * pni,const struct puffs_cn * pcn,const struct vattr * vap,const char * link_target)11333fd391abSpooka p2k_node_symlink(struct puffs_usermount *pu, puffs_cookie_t opc,
11345290e6c8Spooka 	struct puffs_newinfo *pni, const struct puffs_cn *pcn,
1135bdf6e0b0Spooka 	const struct vattr *vap, const char *link_target)
1136bdf6e0b0Spooka {
1137bdf6e0b0Spooka 
11385290e6c8Spooka 	return do_makenode(pu, opc, pni, pcn, vap,
11395290e6c8Spooka 	    __UNCONST(link_target), NULL, RUMP_VOP_SYMLINK);
1140bdf6e0b0Spooka }
1141bdf6e0b0Spooka 
1142bdf6e0b0Spooka /*ARGSUSED*/
1143bdf6e0b0Spooka int
p2k_node_readdir(struct puffs_usermount * pu,puffs_cookie_t opc,struct dirent * dent,off_t * readoff,size_t * reslen,const struct puffs_cred * pcr,int * eofflag,off_t * cookies,size_t * ncookies)11443fd391abSpooka p2k_node_readdir(struct puffs_usermount *pu, puffs_cookie_t opc,
11453fd391abSpooka 	struct dirent *dent, off_t *readoff, size_t *reslen,
11463fd391abSpooka 	const struct puffs_cred *pcr, int *eofflag,
11473fd391abSpooka 	off_t *cookies, size_t *ncookies)
1148bdf6e0b0Spooka {
11495290e6c8Spooka 	struct vnode *vp = OPC2VP(opc);
11502734e549Spooka 	struct kauth_cred *cred;
1151bdf6e0b0Spooka 	struct uio *uio;
1152bdf6e0b0Spooka 	off_t *vop_cookies;
1153bdf6e0b0Spooka 	int vop_ncookies;
1154bdf6e0b0Spooka 	int rv;
1155bdf6e0b0Spooka 
1156bdf6e0b0Spooka 	cred = cred_create(pcr);
1157bf3992afSpooka 	uio = rump_pub_uio_setup(dent, *reslen, *readoff, RUMPUIO_READ);
11585290e6c8Spooka 	RUMP_VOP_LOCK(vp, LK_SHARED);
1159bdf6e0b0Spooka 	if (cookies) {
11605290e6c8Spooka 		rv = RUMP_VOP_READDIR(vp, uio, cred, eofflag,
1161bdf6e0b0Spooka 		    &vop_cookies, &vop_ncookies);
1162bdf6e0b0Spooka 		memcpy(cookies, vop_cookies, vop_ncookies * sizeof(*cookies));
1163bdf6e0b0Spooka 		*ncookies = vop_ncookies;
1164bdf6e0b0Spooka 		free(vop_cookies);
1165bdf6e0b0Spooka 	} else {
11665290e6c8Spooka 		rv = RUMP_VOP_READDIR(vp, uio, cred, eofflag, NULL, NULL);
1167bdf6e0b0Spooka 	}
11681423e65bShannken 	RUMP_VOP_UNLOCK(vp);
1169bdf6e0b0Spooka 	if (rv == 0) {
1170bf3992afSpooka 		*reslen = rump_pub_uio_getresid(uio);
1171bf3992afSpooka 		*readoff = rump_pub_uio_getoff(uio);
1172bdf6e0b0Spooka 	}
1173bf3992afSpooka 	rump_pub_uio_free(uio);
1174bdf6e0b0Spooka 	cred_destroy(cred);
1175bdf6e0b0Spooka 
1176bdf6e0b0Spooka 	return rv;
1177bdf6e0b0Spooka }
1178bdf6e0b0Spooka 
1179bdf6e0b0Spooka /*ARGSUSED*/
1180bdf6e0b0Spooka int
p2k_node_readlink(struct puffs_usermount * pu,puffs_cookie_t opc,const struct puffs_cred * pcr,char * linkname,size_t * linklen)11813fd391abSpooka p2k_node_readlink(struct puffs_usermount *pu, puffs_cookie_t opc,
1182bdf6e0b0Spooka 	const struct puffs_cred *pcr, char *linkname, size_t *linklen)
1183bdf6e0b0Spooka {
11845290e6c8Spooka 	struct vnode *vp = OPC2VP(opc);
11852734e549Spooka 	struct kauth_cred *cred;
1186bdf6e0b0Spooka 	struct uio *uio;
1187bdf6e0b0Spooka 	int rv;
1188bdf6e0b0Spooka 
1189bdf6e0b0Spooka 	cred = cred_create(pcr);
1190bf3992afSpooka 	uio = rump_pub_uio_setup(linkname, *linklen, 0, RUMPUIO_READ);
11915290e6c8Spooka 	RUMP_VOP_LOCK(vp, LK_EXCLUSIVE);
11925290e6c8Spooka 	rv = RUMP_VOP_READLINK(vp, uio, cred);
11931423e65bShannken 	RUMP_VOP_UNLOCK(vp);
1194bf3992afSpooka 	*linklen -= rump_pub_uio_free(uio);
1195bdf6e0b0Spooka 	cred_destroy(cred);
1196bdf6e0b0Spooka 
1197bdf6e0b0Spooka 	return rv;
1198bdf6e0b0Spooka }
1199bdf6e0b0Spooka 
1200bdf6e0b0Spooka /*ARGSUSED*/
1201bdf6e0b0Spooka int
p2k_node_read(struct puffs_usermount * pu,puffs_cookie_t opc,uint8_t * buf,off_t offset,size_t * resid,const struct puffs_cred * pcr,int ioflag)12023fd391abSpooka p2k_node_read(struct puffs_usermount *pu, puffs_cookie_t opc,
1203bdf6e0b0Spooka 	uint8_t *buf, off_t offset, size_t *resid,
1204bdf6e0b0Spooka 	const struct puffs_cred *pcr, int ioflag)
1205bdf6e0b0Spooka {
12065290e6c8Spooka 	struct vnode *vp = OPC2VP(opc);
12072734e549Spooka 	struct kauth_cred *cred;
1208bdf6e0b0Spooka 	struct uio *uio;
1209bdf6e0b0Spooka 	int rv;
1210bdf6e0b0Spooka 
1211bdf6e0b0Spooka 	cred = cred_create(pcr);
1212bf3992afSpooka 	uio = rump_pub_uio_setup(buf, *resid, offset, RUMPUIO_READ);
12135290e6c8Spooka 	RUMP_VOP_LOCK(vp, LK_SHARED);
12145290e6c8Spooka 	rv = RUMP_VOP_READ(vp, uio, ioflag, cred);
12151423e65bShannken 	RUMP_VOP_UNLOCK(vp);
1216bf3992afSpooka 	*resid = rump_pub_uio_free(uio);
1217bdf6e0b0Spooka 	cred_destroy(cred);
1218bdf6e0b0Spooka 
1219bdf6e0b0Spooka 	return rv;
1220bdf6e0b0Spooka }
1221bdf6e0b0Spooka 
1222bdf6e0b0Spooka /*ARGSUSED*/
1223bdf6e0b0Spooka int
p2k_node_write(struct puffs_usermount * pu,puffs_cookie_t opc,uint8_t * buf,off_t offset,size_t * resid,const struct puffs_cred * pcr,int ioflag)12243fd391abSpooka p2k_node_write(struct puffs_usermount *pu, puffs_cookie_t opc,
1225bdf6e0b0Spooka 	uint8_t *buf, off_t offset, size_t *resid,
1226bdf6e0b0Spooka 	const struct puffs_cred *pcr, int ioflag)
1227bdf6e0b0Spooka {
12285290e6c8Spooka 	struct vnode *vp = OPC2VP(opc);
12292734e549Spooka 	struct kauth_cred *cred;
1230bdf6e0b0Spooka 	struct uio *uio;
1231bdf6e0b0Spooka 	int rv;
1232bdf6e0b0Spooka 
12335290e6c8Spooka 	/* "deadfs" */
12345290e6c8Spooka 	if (!vp)
12355290e6c8Spooka 		return 0;
12365290e6c8Spooka 
1237bdf6e0b0Spooka 	cred = cred_create(pcr);
1238bf3992afSpooka 	uio = rump_pub_uio_setup(buf, *resid, offset, RUMPUIO_WRITE);
12395290e6c8Spooka 	RUMP_VOP_LOCK(vp, LK_EXCLUSIVE);
12405290e6c8Spooka 	rv = RUMP_VOP_WRITE(vp, uio, ioflag, cred);
12411423e65bShannken 	RUMP_VOP_UNLOCK(vp);
1242bf3992afSpooka 	*resid = rump_pub_uio_free(uio);
1243bdf6e0b0Spooka 	cred_destroy(cred);
1244bdf6e0b0Spooka 
1245bdf6e0b0Spooka 	return rv;
1246bdf6e0b0Spooka }
1247bdf6e0b0Spooka 
124855a23816Spooka /*ARGSUSED*/
124955a23816Spooka int
p2k_node_pathconf(struct puffs_usermount * pu,puffs_cookie_t opc,int name,register_t * retval)12501cfb9937Spooka p2k_node_pathconf(struct puffs_usermount *pu, puffs_cookie_t opc,
1251388dad17Spooka 	int name, register_t *retval)
12521cfb9937Spooka {
12531cfb9937Spooka 	struct vnode *vp = OPC2VP(opc);
12541cfb9937Spooka 	int rv;
12551cfb9937Spooka 
12561cfb9937Spooka 	RUMP_VOP_LOCK(vp, LK_EXCLUSIVE);
1257388dad17Spooka 	rv = RUMP_VOP_PATHCONF(vp, name, retval);
12581423e65bShannken 	RUMP_VOP_UNLOCK(vp);
12591cfb9937Spooka 
12601cfb9937Spooka 	return rv;
12611cfb9937Spooka }
12621cfb9937Spooka 
12631cfb9937Spooka /*ARGSUSED*/
12641cfb9937Spooka int
p2k_node_getextattr(struct puffs_usermount * pu,puffs_cookie_t opc,int attrnamespace,const char * attrname,size_t * attrsize,uint8_t * attr,size_t * resid,const struct puffs_cred * pcr)126555a23816Spooka p2k_node_getextattr(struct puffs_usermount *pu, puffs_cookie_t opc,
126655a23816Spooka 	int attrnamespace, const char *attrname, size_t *attrsize,
126755a23816Spooka 	uint8_t *attr, size_t *resid, const struct puffs_cred *pcr)
126855a23816Spooka {
126955a23816Spooka 	struct vnode *vp = OPC2VP(opc);
127055a23816Spooka 	struct kauth_cred *cred;
127155a23816Spooka 	struct uio *uio;
127255a23816Spooka 	int rv;
127355a23816Spooka 
127455a23816Spooka 	if (attr)
127555a23816Spooka 		uio = rump_pub_uio_setup(attr, *resid, 0, RUMPUIO_READ);
127655a23816Spooka 	else
127755a23816Spooka 		uio = NULL;
127855a23816Spooka 
127955a23816Spooka 	cred = cred_create(pcr);
128055a23816Spooka 	RUMP_VOP_LOCK(vp, LK_EXCLUSIVE);
128155a23816Spooka 	rv = RUMP_VOP_GETEXTATTR(vp, attrnamespace, attrname, uio,
128255a23816Spooka 	    attrsize, cred);
12831423e65bShannken 	RUMP_VOP_UNLOCK(vp);
128455a23816Spooka 	cred_destroy(cred);
128555a23816Spooka 
128655a23816Spooka 	if (uio)
128755a23816Spooka 		*resid = rump_pub_uio_free(uio);
128855a23816Spooka 
128955a23816Spooka 	return rv;
129055a23816Spooka }
129155a23816Spooka 
129255a23816Spooka /*ARGSUSED*/
129355a23816Spooka int
p2k_node_setextattr(struct puffs_usermount * pu,puffs_cookie_t opc,int attrnamespace,const char * attrname,uint8_t * attr,size_t * resid,const struct puffs_cred * pcr)129455a23816Spooka p2k_node_setextattr(struct puffs_usermount *pu, puffs_cookie_t opc,
129555a23816Spooka 	int attrnamespace, const char *attrname,
129655a23816Spooka 	uint8_t *attr, size_t *resid, const struct puffs_cred *pcr)
129755a23816Spooka {
129855a23816Spooka 	struct vnode *vp = OPC2VP(opc);
129955a23816Spooka 	struct kauth_cred *cred;
130055a23816Spooka 	struct uio *uio;
130155a23816Spooka 	int rv;
130255a23816Spooka 
130355a23816Spooka 	if (attr)
130455a23816Spooka 		uio = rump_pub_uio_setup(attr, *resid, 0, RUMPUIO_READ);
130555a23816Spooka 	else
130655a23816Spooka 		uio = NULL;
130755a23816Spooka 
130855a23816Spooka 	cred = cred_create(pcr);
130955a23816Spooka 	RUMP_VOP_LOCK(vp, LK_EXCLUSIVE);
131055a23816Spooka 	rv = RUMP_VOP_SETEXTATTR(vp, attrnamespace, attrname, uio, cred);
13111423e65bShannken 	RUMP_VOP_UNLOCK(vp);
131255a23816Spooka 	cred_destroy(cred);
131355a23816Spooka 
131455a23816Spooka 	if (uio)
131555a23816Spooka 		*resid = rump_pub_uio_free(uio);
131655a23816Spooka 
131755a23816Spooka 	return rv;
131855a23816Spooka }
131955a23816Spooka 
132055a23816Spooka /*ARGSUSED*/
132155a23816Spooka int
p2k_node_listextattr(struct puffs_usermount * pu,puffs_cookie_t opc,int attrnamespace,size_t * attrsize,uint8_t * attrs,size_t * resid,int flags,const struct puffs_cred * pcr)132255a23816Spooka p2k_node_listextattr(struct puffs_usermount *pu, puffs_cookie_t opc,
1323be95d607Smanu 	int attrnamespace, size_t *attrsize, uint8_t *attrs,
1324be95d607Smanu 	size_t *resid, int flags, const struct puffs_cred *pcr)
132555a23816Spooka {
132655a23816Spooka 	struct vnode *vp = OPC2VP(opc);
132755a23816Spooka 	struct kauth_cred *cred;
132855a23816Spooka 	struct uio *uio;
132955a23816Spooka 	int rv;
133055a23816Spooka 
133155a23816Spooka 	if (attrs)
133255a23816Spooka 		uio = rump_pub_uio_setup(attrs, *resid, 0, RUMPUIO_READ);
133355a23816Spooka 	else
133455a23816Spooka 		uio = NULL;
133555a23816Spooka 
133655a23816Spooka 	cred = cred_create(pcr);
133755a23816Spooka 	RUMP_VOP_LOCK(vp, LK_EXCLUSIVE);
1338be95d607Smanu 	rv = RUMP_VOP_LISTEXTATTR(vp, attrnamespace, uio, attrsize,
1339be95d607Smanu 	    flags, cred);
13401423e65bShannken 	RUMP_VOP_UNLOCK(vp);
134155a23816Spooka 	cred_destroy(cred);
134255a23816Spooka 
134355a23816Spooka 	if (uio)
134455a23816Spooka 		*resid = rump_pub_uio_free(uio);
134555a23816Spooka 
134655a23816Spooka 	return rv;
134755a23816Spooka }
134855a23816Spooka 
134955a23816Spooka /*ARGSUSED*/
135055a23816Spooka int
p2k_node_deleteextattr(struct puffs_usermount * pu,puffs_cookie_t opc,int attrnamespace,const char * attrname,const struct puffs_cred * pcr)135155a23816Spooka p2k_node_deleteextattr(struct puffs_usermount *pu, puffs_cookie_t opc,
135255a23816Spooka 	int attrnamespace, const char *attrname, const struct puffs_cred *pcr)
135355a23816Spooka {
135455a23816Spooka 	struct vnode *vp = OPC2VP(opc);
135555a23816Spooka 	struct kauth_cred *cred;
135655a23816Spooka 	int rv;
135755a23816Spooka 
135855a23816Spooka 	cred = cred_create(pcr);
135955a23816Spooka 	RUMP_VOP_LOCK(vp, LK_EXCLUSIVE);
136055a23816Spooka 	rv = RUMP_VOP_DELETEEXTATTR(vp, attrnamespace, attrname, cred);
13611423e65bShannken 	RUMP_VOP_UNLOCK(vp);
136255a23816Spooka 	cred_destroy(cred);
136355a23816Spooka 
136455a23816Spooka 	return rv;
136555a23816Spooka }
136655a23816Spooka 
13675290e6c8Spooka /* the kernel releases its last reference here */
1368bdf6e0b0Spooka int
p2k_node_inactive(struct puffs_usermount * pu,puffs_cookie_t opc)13693fd391abSpooka p2k_node_inactive(struct puffs_usermount *pu, puffs_cookie_t opc)
1370bdf6e0b0Spooka {
137130df4c9fSpooka 	struct p2k_mount *p2m = puffs_getspecific(pu);
13725290e6c8Spooka 	struct p2k_node *p2n = opc;
13735290e6c8Spooka 	struct vnode *vp = OPC2VP(opc);
1374a37ccec1Spooka 	bool recycle = false;
1375bdf6e0b0Spooka 	int rv;
1376bdf6e0b0Spooka 
13775290e6c8Spooka 	/* deadfs */
13785290e6c8Spooka 	if (!vp)
13795290e6c8Spooka 		return 0;
13805290e6c8Spooka 
13815290e6c8Spooka 	/*
13825290e6c8Spooka 	 * Flush all cached vnode pages from the rump kernel -- they
138313777d56Spooka 	 * are kept in puffs for all things that matter.  However,
138413777d56Spooka 	 * don't do this for tmpfs (vnodes are backed by an aobj), since that
138513777d56Spooka 	 * would cause us to clear the backing storage leaving us without
138613777d56Spooka 	 * a way to regain the data from "stable storage".
13875290e6c8Spooka 	 */
138813777d56Spooka 	if (!p2m->p2m_imtmpfsman) {
1389d2a0ebb6Sad 		rump_pub_vp_vmobjlock(vp, 1);
139013777d56Spooka 		RUMP_VOP_PUTPAGES(vp, 0, 0,
139113777d56Spooka 		    PGO_ALLPAGES|PGO_CLEANIT|PGO_FREE);
139213777d56Spooka 	}
13935290e6c8Spooka 
13945290e6c8Spooka 	/*
13955290e6c8Spooka 	 * Ok, this is where we get nasty.  We pretend the vnode is
13965290e6c8Spooka 	 * inactive and already tell the file system that.  However,
13975290e6c8Spooka 	 * we are allowed to pretend it also grows a reference immediately
13985290e6c8Spooka 	 * after per vget(), so this does not do harm.  Cheap trick, but ...
13995290e6c8Spooka 	 *
14005290e6c8Spooka 	 * If the file system thinks the inode is done for, we release
14015290e6c8Spooka 	 * our reference and clear all knowledge of the vnode.  If,
14025290e6c8Spooka 	 * however, the inode is still active, we retain our reference
14035290e6c8Spooka 	 * until reclaim, since puffs might be flushing out some data
14045290e6c8Spooka 	 * later.
14055290e6c8Spooka 	 */
14065290e6c8Spooka 	RUMP_VOP_LOCK(vp, LK_EXCLUSIVE);
1407bdf6e0b0Spooka 	rv = RUMP_VOP_INACTIVE(vp, &recycle);
140887fb3229Sriastradh 	RUMP_VOP_UNLOCK(vp);
14095290e6c8Spooka 	if (recycle) {
1410bdf6e0b0Spooka 		puffs_setback(puffs_cc_getcc(pu), PUFFS_SETBACK_NOREF_N1);
1411bf3992afSpooka 		rump_pub_vp_rele(p2n->p2n_vp);
14125290e6c8Spooka 		p2n->p2n_vp = NULL;
14135290e6c8Spooka 	}
1414bdf6e0b0Spooka 
1415bdf6e0b0Spooka 	return rv;
1416bdf6e0b0Spooka }
1417bdf6e0b0Spooka 
1418bdf6e0b0Spooka /*ARGSUSED*/
1419bdf6e0b0Spooka int
p2k_node_reclaim(struct puffs_usermount * pu,puffs_croissant_t opc)14203fd391abSpooka p2k_node_reclaim(struct puffs_usermount *pu, puffs_croissant_t opc)
1421bdf6e0b0Spooka {
14225290e6c8Spooka 	struct p2k_node *p2n = opc;
1423bdf6e0b0Spooka 
14245290e6c8Spooka 	if (p2n->p2n_vp) {
1425bf3992afSpooka 		rump_pub_vp_rele(p2n->p2n_vp);
14265290e6c8Spooka 		p2n->p2n_vp = NULL;
14275290e6c8Spooka 	}
14285290e6c8Spooka 
14295290e6c8Spooka 	freep2n(p2n);
1430bdf6e0b0Spooka 	return 0;
1431bdf6e0b0Spooka }
1432