xref: /netbsd-src/lib/libp2k/p2k.c (revision 4d5abbe83f525258eb479e5fca29f25cb943f379)
1 /*	$NetBSD: p2k.c,v 1.67 2016/01/23 16:39:31 christos Exp $	*/
2 
3 /*
4  * Copyright (c) 2007, 2008, 2009  Antti Kantee.  All Rights Reserved.
5  *
6  * Development of this software was supported by the
7  * Finnish Cultural Foundation.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
19  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21  * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28  * SUCH DAMAGE.
29  */
30 
31 /*
32  * puffs 2k, i.e. puffs 2 kernel.  Converts the puffs protocol to
33  * the kernel vfs protocol and vice versa.
34  *
35  * A word about reference counting: puffs in the kernel is the king of
36  * reference counting.  We must maintain a vnode alive and kicking
37  * until the kernel tells us to reclaim it.  Therefore we make sure
38  * we never accidentally lose a vnode.  Before calling operations which
39  * decrease the refcount we always bump the refcount up to compensate.
40  * Come inactive, if the file system thinks that the vnode should be
41  * put out of its misery, it will set the recycle flag.  We use this
42  * to tell the kernel to reclaim the vnode.  Only in reclaim do we
43  * really nuke the last reference.
44  */
45 
46 #include <sys/cdefs.h>
47 #include <sys/mount.h>
48 #include <sys/param.h>
49 #include <sys/lock.h>
50 #include <sys/namei.h>
51 #include <sys/dirent.h>
52 #include <sys/hash.h>
53 
54 #include <assert.h>
55 #include <errno.h>
56 #include <puffs.h>
57 #include <stdlib.h>
58 #include <stdio.h>
59 
60 #include <rump/rump.h>
61 #include <rump/p2k.h>
62 #include <rump/ukfs.h>
63 
64 #include <uvm/uvm_pager.h>
65 
66 /* NetBSD-5 compat */
67 #ifndef MOUNT_RUMPFS
68 #define MOUNT_RUMPFS    "rumpfs"
69 #endif
70 
71 PUFFSOP_PROTOS(p2k)
72 
73 LIST_HEAD(p2k_vp_hash, p2k_node);
74 #define NHASHBUCK (1<<16)
75 struct p2k_mount {
76 	struct vnode *p2m_rvp;
77 	struct puffs_usermount *p2m_pu;
78 	struct ukfs *p2m_ukfs;
79 	struct p2k_vp_hash p2m_vphash[NHASHBUCK];
80 	struct mount *p2m_mp;
81 	int p2m_nvnodes;
82 	int p2m_imtmpfsman;
83 	bool p2m_hasdebug;
84 };
85 
86 struct p2k_node {
87 	struct puffs_node p2n_pn;
88 	struct vnode *p2n_vp;
89 
90 	LIST_ENTRY(p2k_node) p2n_entries;
91 };
92 
93 #define OPC2VP(opc) (((struct p2k_node *)opc)->p2n_vp)
94 
95 static int haswizard;
96 static uid_t wizarduid;
97 
98 static struct kauth_cred *
99 cred_create(const struct puffs_cred *pcr)
100 {
101 	gid_t groups[NGROUPS];
102 	uid_t uid;
103 	gid_t gid;
104 	short ngroups = __arraycount(groups);
105 
106 	if (haswizard) {
107 		uid = wizarduid;
108 	} else {
109 		if (puffs_cred_getuid(pcr, &uid) == -1)
110 			uid = 0;
111 	}
112 	if (puffs_cred_getgid(pcr, &gid) == -1)
113 		gid = 0;
114 	puffs_cred_getgroups(pcr, groups, &ngroups);
115 
116 	/* LINTED: ngroups is ok */
117 	return rump_pub_cred_create(uid, gid, ngroups, groups);
118 }
119 
120 static __inline void
121 cred_destroy(struct kauth_cred *cred)
122 {
123 
124 	rump_pub_cred_put(cred);
125 }
126 
127 static struct componentname *
128 makecn(const struct puffs_cn *pcn)
129 {
130 	struct kauth_cred *cred;
131 
132 	cred = cred_create(pcn->pcn_cred);
133 	/* LINTED: prehistoric types in first two args */
134 	return rump_pub_makecn(pcn->pcn_nameiop, pcn->pcn_flags,
135 	    pcn->pcn_name, pcn->pcn_namelen, cred, rump_pub_lwproc_curlwp());
136 }
137 
138 static __inline void
139 freecn(struct componentname *cnp)
140 {
141 
142 	rump_pub_freecn(cnp, RUMPCN_FREECRED);
143 }
144 
145 static void
146 makelwp(struct puffs_usermount *pu)
147 {
148 	pid_t pid;
149 	lwpid_t lid;
150 
151 	puffs_cc_getcaller(puffs_cc_getcc(pu), &pid, &lid);
152 	rump_pub_allbetsareoff_setid(pid, lid);
153 }
154 
155 static volatile sig_atomic_t dodump;
156 static void
157 dumpmp(struct puffs_usermount *pu)
158 {
159 	struct statvfs svfsb;
160 
161 	if (dodump && p2k_fs_statvfs(pu, &svfsb) == 0) {
162 		rump_pub_vfs_mount_print(svfsb.f_mntonname, dodump-1);
163 	}
164 
165 	dodump = 0;
166 }
167 
168 static void
169 sighand(int sig)
170 {
171 
172 	if (sig == SIGINFO)
173 		dodump = 1;
174 	else if (sig == SIGUSR1)
175 		dodump = 2;
176 }
177 
178 static __inline struct p2k_vp_hash *
179 gethash(struct p2k_mount *p2m, struct vnode *vp)
180 {
181 	uint32_t hash;
182 
183 	hash = hash32_buf(&vp, sizeof(vp), HASH32_BUF_INIT);
184 	return &p2m->p2m_vphash[hash % NHASHBUCK];
185 }
186 
187 /*
188  * Find node based on hash of vnode pointer.  If vnode is found,
189  * releases one reference to vnode based on the fact that we just
190  * performed a lookup for it.
191  *
192  * If the optinal p2n_storage parameter is passed, it is used instead
193  * of allocating more memory.  This allows for easier error recovery.
194  */
195 static struct p2k_node *
196 getp2n(struct p2k_mount *p2m, struct vnode *vp, bool initial,
197 	struct p2k_node *p2n_storage)
198 {
199 	struct p2k_vp_hash *hl;
200 	struct p2k_node *p2n = NULL;
201 
202 	/* p2n_storage => initial */
203 	assert(!p2n_storage || initial);
204 
205 	hl = gethash(p2m, vp);
206 	if (!initial)
207 		LIST_FOREACH(p2n, hl, p2n_entries)
208 			if (p2n->p2n_vp == vp)
209 				break;
210 
211 	hl = gethash(p2m, vp);
212 	if (p2n) {
213 		rump_pub_vp_rele(vp);
214 	} else {
215 		if (p2n_storage)
216 			p2n = p2n_storage;
217 		else
218 			p2n = malloc(sizeof(*p2n));
219 		if (!p2n) {
220 			rump_pub_vp_rele(vp);
221 			return NULL;
222 		}
223 		memset(p2n, 0, sizeof(*p2n));
224 		LIST_INSERT_HEAD(hl, p2n, p2n_entries);
225 		p2n->p2n_vp = vp;
226 	}
227 	return p2n;
228 }
229 
230 static void
231 freep2n(struct p2k_node *p2n)
232 {
233 
234 	assert(p2n->p2n_vp == NULL);
235 	LIST_REMOVE(p2n, p2n_entries);
236 	free(p2n);
237 }
238 
239 /*ARGSUSED*/
240 static void
241 p2k_errcatcher(struct puffs_usermount *pu, uint8_t type, int error,
242 	const char *str, puffs_cookie_t cook)
243 {
244 
245 	fprintf(stderr, "type %d, error %d, cookie %p (%s)\n",
246 	    type, error, cook, str);
247 
248 	/*
249 	 * Trap all EINVAL responses to lookup.  It most likely means
250 	 * that we supplied VNON/VBAD as the type.  The real kernel
251 	 * doesn't panic from this either, but just handles it.
252 	 */
253 	if (type != PUFFS_VN_LOOKUP && error == EINVAL)
254 		abort();
255 }
256 
257 /* just to avoid annoying loop when singlestepping */
258 static struct p2k_mount *
259 allocp2m(void)
260 {
261 	struct p2k_mount *p2m;
262 	int i;
263 
264 	p2m = malloc(sizeof(*p2m));
265 	if (p2m == NULL)
266 		return NULL;
267 	memset(p2m, 0, sizeof(*p2m));
268 
269 	for (i = 0; i < NHASHBUCK; i++)
270 		LIST_INIT(&p2m->p2m_vphash[i]);
271 
272 	return p2m;
273 }
274 
275 struct p2k_mount *
276 p2k_init(uint32_t puffs_flags)
277 {
278 	struct puffs_ops *pops;
279 	struct p2k_mount *p2m;
280 	char *envbuf;
281 	bool dodaemon;
282 	bool hasdebug;
283 
284 	PUFFSOP_INIT(pops);
285 
286 	PUFFSOP_SET(pops, p2k, fs, statvfs);
287 	PUFFSOP_SET(pops, p2k, fs, unmount);
288 	PUFFSOP_SET(pops, p2k, fs, sync);
289 	PUFFSOP_SET(pops, p2k, fs, fhtonode);
290 	PUFFSOP_SET(pops, p2k, fs, nodetofh);
291 	PUFFSOP_SET(pops, p2k, fs, extattrctl);
292 
293 	PUFFSOP_SET(pops, p2k, node, lookup);
294 	PUFFSOP_SET(pops, p2k, node, create);
295 	PUFFSOP_SET(pops, p2k, node, mknod);
296 	PUFFSOP_SET(pops, p2k, node, open);
297 	PUFFSOP_SET(pops, p2k, node, close);
298 	PUFFSOP_SET(pops, p2k, node, access);
299 	PUFFSOP_SET(pops, p2k, node, getattr);
300 	PUFFSOP_SET(pops, p2k, node, setattr);
301 #if 0
302 	PUFFSOP_SET(pops, p2k, node, poll);
303 #endif
304 	PUFFSOP_SET(pops, p2k, node, mmap);
305 	PUFFSOP_SET(pops, p2k, node, fsync);
306 	PUFFSOP_SET(pops, p2k, node, seek);
307 	PUFFSOP_SET(pops, p2k, node, remove);
308 	PUFFSOP_SET(pops, p2k, node, link);
309 	PUFFSOP_SET(pops, p2k, node, rename);
310 	PUFFSOP_SET(pops, p2k, node, mkdir);
311 	PUFFSOP_SET(pops, p2k, node, rmdir);
312 	PUFFSOP_SET(pops, p2k, node, symlink);
313 	PUFFSOP_SET(pops, p2k, node, readdir);
314 	PUFFSOP_SET(pops, p2k, node, readlink);
315 	PUFFSOP_SET(pops, p2k, node, read);
316 	PUFFSOP_SET(pops, p2k, node, write);
317 
318 	PUFFSOP_SET(pops, p2k, node, pathconf);
319 
320 	PUFFSOP_SET(pops, p2k, node, inactive);
321 	PUFFSOP_SET(pops, p2k, node, reclaim);
322 
323 	PUFFSOP_SET(pops, p2k, node, getextattr);
324 	PUFFSOP_SET(pops, p2k, node, setextattr);
325 	PUFFSOP_SET(pops, p2k, node, listextattr);
326 	PUFFSOP_SET(pops, p2k, node, deleteextattr);
327 
328 	dodaemon = true;
329 	hasdebug = false;
330 
331 	if (getenv("P2K_DEBUG") != NULL) {
332 		puffs_flags |= PUFFS_FLAG_OPDUMP;
333 		dodaemon = false;
334 		hasdebug = true;
335 	}
336 	if (getenv("P2K_NODETACH") != NULL) {
337 		dodaemon = false;
338 	}
339 	if (getenv("P2K_NOCACHE_PAGE") != NULL) {
340 		puffs_flags |= PUFFS_KFLAG_NOCACHE_PAGE;
341 	}
342 	if (getenv("P2K_NOCACHE_NAME") != NULL) {
343 		puffs_flags |= PUFFS_KFLAG_NOCACHE_NAME;
344 	}
345 	if (getenv("P2K_NOCACHE") != NULL) {
346 		puffs_flags |= PUFFS_KFLAG_NOCACHE;
347 	}
348 	if ((envbuf = getenv("P2K_WIZARDUID")) != NULL) {
349 		char *ep;
350 
351 		wizarduid = strtoul(envbuf, &ep, 10);
352 		if (envbuf[0] == '\0' || *ep != '\0') {
353 			printf("P2K_WIZARDUID: invalid uid %s\n", envbuf);
354 		} else if (wizarduid > UID_MAX) {
355 			printf("P2K_WIZARDUID: uid %s out-of-range\n", envbuf);
356 		} else {
357 			haswizard = 1;
358 			printf("P2K WIZARD MODE: using uid %d\n", wizarduid);
359 		}
360 	}
361 
362 	/*
363 	 * Explicitely tell that our cookies can be treated as
364 	 * puffs_node, since we never let libpuffs know by
365 	 * calling  call puffs_pn_new()
366 	 */
367 	puffs_flags |= PUFFS_FLAG_PNCOOKIE;
368 
369 	p2m = allocp2m();
370 	if (p2m == NULL)
371 		return NULL;
372 	p2m->p2m_pu = puffs_init(pops, PUFFS_DEFER, PUFFS_DEFER,
373 	    PUFFS_DEFER, puffs_flags);
374 	if (p2m->p2m_pu == NULL) {
375 		int sverrno = errno;
376 		free(p2m);
377 		errno = sverrno;
378 		return NULL;
379 	}
380 	p2m->p2m_hasdebug = hasdebug;
381 
382 	if (dodaemon) {
383 		if (puffs_daemon(p2m->p2m_pu, 1, 1) == -1) {
384 			int sverrno = errno;
385 			p2k_cancel(p2m, sverrno);
386 			errno = sverrno;
387 			p2m = NULL;
388 		}
389 	}
390 	if (p2m)
391 		rump_init();
392 
393 	rump_pub_lwproc_rfork(RUMP_RFCFDG);
394 
395 	return p2m;
396 }
397 
398 void
399 p2k_cancel(struct p2k_mount *p2m, int error)
400 {
401 
402 	puffs_cancel(p2m->p2m_pu, error);
403 	free(p2m);
404 }
405 
406 static int
407 setupfs(struct p2k_mount *p2m, const char *vfsname, const char *devpath,
408 	struct ukfs_part *part, const char *mountpath, int mntflags,
409 	void *arg, size_t alen)
410 {
411 	char partpath[UKFS_DEVICE_MAXPATHLEN];
412 	char partbuf[UKFS_DEVICE_MAXSTR];
413 	char typebuf[PUFFS_TYPELEN];
414 	struct puffs_usermount *pu = p2m->p2m_pu;
415 	struct p2k_node *p2n_root;
416 	struct ukfs *ukfs = NULL;
417 	extern int puffs_fakecc;
418 	int rv = -1, sverrno;
419 
420 	strcpy(typebuf, "p2k|");
421 	if (strcmp(vfsname, "puffs") == 0) { /* XXX */
422 		struct puffs_kargs *args = arg;
423 		strlcat(typebuf, args->pa_typename, sizeof(typebuf));
424 	} else {
425 		strlcat(typebuf, vfsname, sizeof(typebuf));
426 	}
427 
428 	strlcpy(partpath, devpath, sizeof(partpath));
429 	if (ukfs_part_tostring(part, partbuf, sizeof(partbuf))) {
430 		strlcat(partpath, partbuf, sizeof(partpath));
431 	}
432 	puffs_setmntinfo(pu, partpath, typebuf);
433 
434 	if (ukfs_init() == -1)
435 		goto out;
436 
437 	/*
438 	 * If we're mounting rumpfs, actually do no mount and redirect
439 	 * requests to rump fs namespace root.  Strictly speaking, this
440 	 * is not correct, but I don't think anyone will notice.
441 	 * After all, we're mostly interested in things which reside
442 	 * specifically on the rootfs, namely the contents of /dev
443 	 */
444 	if (strcmp(vfsname, MOUNT_RUMPFS) == 0) {
445 		if ((rv = rump_pub_vfs_getmp("/", &p2m->p2m_mp)) != 0) {
446 			errno = rv;
447 			rv = -1;
448 			goto out;
449 		}
450 	} else {
451 		if (part != ukfs_part_na)
452 			ukfs = ukfs_mount_disk(vfsname, devpath, part,
453 			    mountpath, mntflags, arg, alen);
454 		else
455 			ukfs = ukfs_mount(vfsname, devpath, mountpath, mntflags,
456 			    arg, alen);
457 		if (ukfs == NULL)
458 			goto out;
459 		ukfs_setspecific(ukfs, p2m);
460 		p2m->p2m_ukfs = ukfs;
461 		p2m->p2m_mp = ukfs_getmp(ukfs);
462 	}
463 	if ((rv = rump_pub_vfs_root(p2m->p2m_mp, &p2m->p2m_rvp, 0)) != 0) {
464 		errno = rv;
465 		rv = -1;
466 		goto out;
467 	}
468 
469 	p2m->p2m_pu = pu;
470 
471 	/*
472 	 * Detect tmpfs.  XXX: this is a kludge.  See inactive().
473 	 *
474 	 * In reality we'd want "does file system use anon objects
475 	 * for storage?".  But since tmpfs hides the anon object from
476 	 * the public interface, we can't actually detect it sanely.
477 	 * Therefore, use this kludge.
478 	 */
479 	p2m->p2m_imtmpfsman = strcmp(vfsname, MOUNT_TMPFS) == 0;
480 
481 	p2n_root = getp2n(p2m, p2m->p2m_rvp, true, NULL);
482 	puffs_setfhsize(pu, 0, PUFFS_FHFLAG_PASSTHROUGH);
483 	puffs_setstacksize(pu, PUFFS_STACKSIZE_MIN);
484 	puffs_fakecc = 1;
485 	puffs_set_prepost(pu, makelwp, NULL);
486 
487 	if (p2m->p2m_hasdebug) {
488 		struct timespec ts;
489 
490 		signal(SIGINFO, sighand);
491 		signal(SIGUSR1, sighand);
492 
493 		ts.tv_sec = 0;
494 		ts.tv_nsec = 1000*1000*10; /* 10ms */
495 		puffs_ml_setloopfn(pu, dumpmp);
496 		puffs_ml_settimeout(pu, &ts);
497 	}
498 	puffs_set_errnotify(pu, p2k_errcatcher);
499 
500 	puffs_setspecific(pu, p2m);
501 	rv = puffs_mount(pu, mountpath, mntflags, p2n_root);
502 
503  out:
504 	if (rv == -1) {
505 		sverrno = errno;
506 		puffs_cancel(pu, sverrno);
507 		if (ukfs)
508 			ukfs_release(p2m->p2m_ukfs, UKFS_RELFLAG_FORCE);
509 		free(p2m);
510 		errno = sverrno;
511 	}
512 
513 	return rv;
514 }
515 
516 int
517 p2k_mainloop(struct p2k_mount *p2m)
518 {
519 	int rv, sverrno;
520 
521 	rv = puffs_mainloop(p2m->p2m_pu);
522 	sverrno = errno;
523 	puffs_exit(p2m->p2m_pu, 1);
524 	if (p2m->p2m_ukfs)
525 		ukfs_release(p2m->p2m_ukfs, UKFS_RELFLAG_FORCE);
526 	free(p2m);
527 
528 	if (rv == -1)
529 		errno = sverrno;
530 	return rv;
531 }
532 
533 int
534 p2k_run_fs(const char *vfsname, const char *devpath, const char *mountpath,
535 	int mntflags, void *arg, size_t alen, uint32_t puffs_flags)
536 {
537 	struct p2k_mount *p2m;
538 	int rv;
539 
540 	p2m = p2k_init(puffs_flags);
541 	if (p2m == NULL)
542 		return -1;
543 	rv = setupfs(p2m, vfsname, devpath, ukfs_part_na, mountpath,
544 	    mntflags, arg, alen);
545 	if (rv == -1)
546 		return rv;
547 	return p2k_mainloop(p2m);
548 }
549 
550 int
551 p2k_run_diskfs(const char *vfsname, const char *devpath, struct ukfs_part *part,
552 	const char *mountpath, int mntflags, void *arg, size_t alen,
553 	uint32_t puffs_flags)
554 {
555 	struct p2k_mount *p2m;
556 	int rv;
557 
558 	p2m = p2k_init(puffs_flags);
559 	if (p2m == NULL)
560 		return -1;
561 	rv = setupfs(p2m, vfsname, devpath, part, mountpath, mntflags,
562 	    arg, alen);
563 	if (rv == -1)
564 		return rv;
565 	return p2k_mainloop(p2m);
566 }
567 
568 int
569 p2k_setup_fs(struct p2k_mount *p2m, const char *vfsname, const char *devpath,
570 	const char *mountpath, int mntflags, void *arg, size_t alen)
571 {
572 
573 	return setupfs(p2m, vfsname, devpath, ukfs_part_na, mountpath,
574 	    mntflags, arg, alen);
575 }
576 
577 int
578 p2k_setup_diskfs(struct p2k_mount *p2m, const char *vfsname,
579 	const char *devpath, struct ukfs_part *part, const char *mountpath,
580 	int mntflags, void *arg, size_t alen)
581 {
582 
583 	return setupfs(p2m, vfsname, devpath, part, mountpath, mntflags,
584 	    arg, alen);
585 }
586 
587 int
588 p2k_fs_statvfs(struct puffs_usermount *pu, struct statvfs *sbp)
589 {
590 	struct p2k_mount *p2m = puffs_getspecific(pu);
591 	struct mount *mp = p2m->p2m_mp;
592 
593 	return rump_pub_vfs_statvfs(mp, sbp);
594 }
595 
596 /*ARGSUSED*/
597 int
598 p2k_fs_unmount(struct puffs_usermount *pu, int flags)
599 {
600 	struct p2k_mount *p2m = puffs_getspecific(pu);
601 	struct ukfs *fs = p2m->p2m_ukfs;
602 	int error = 0;
603 
604 	rump_pub_vp_rele(p2m->p2m_rvp);
605 
606 	if (fs) {
607 		if (ukfs_release(fs, 0) != 0) {
608 			struct statvfs svfsb;
609 
610 			if (p2m->p2m_hasdebug
611 			    && p2k_fs_statvfs(pu, &svfsb) == 0) {
612 				printf("\nSOFT UNMOUNT FAILED, MP INFO DUMP\n");
613 				rump_pub_vfs_mount_print(svfsb.f_mntonname, 1);
614 			}
615 			ukfs_release(fs, UKFS_RELFLAG_FORCE);
616 			error = 0;
617 		}
618 	}
619 	p2m->p2m_ukfs = NULL;
620 
621 	if (p2m->p2m_hasdebug) {
622 		printf("-- rump kernel event counters --\n");
623 		rump_printevcnts();
624 		printf("-- end of event counters --\n");
625 	}
626 
627 	return error;
628 }
629 
630 int
631 p2k_fs_sync(struct puffs_usermount *pu, int waitfor,
632 	const struct puffs_cred *pcr)
633 {
634 	struct p2k_mount *p2m = puffs_getspecific(pu);
635 	struct mount *mp = p2m->p2m_mp;
636 	struct kauth_cred *cred;
637 	int rv;
638 
639 	cred = cred_create(pcr);
640 	rv = rump_pub_vfs_sync(mp, waitfor, cred);
641 	cred_destroy(cred);
642 
643 	return rv;
644 }
645 
646 /*ARGSUSED*/
647 int
648 p2k_fs_fhtonode(struct puffs_usermount *pu, void *fid, size_t fidsize,
649 	struct puffs_newinfo *pni)
650 {
651 	struct p2k_mount *p2m = puffs_getspecific(pu);
652 	struct mount *mp = p2m->p2m_mp;
653 	struct p2k_node *p2n;
654 	struct vnode *vp;
655 	enum rump_vtype vtype;
656 	voff_t vsize;
657 	uint64_t rdev; /* XXX: allows running this on NetBSD 5.0 */
658 	int rv;
659 
660 	rv = rump_pub_vfs_fhtovp(mp, fid, &vp);
661 	if (rv)
662 		return rv;
663 	RUMP_VOP_UNLOCK(vp);
664 
665 	p2n = getp2n(p2m, vp, false, NULL);
666 	if (p2n == NULL)
667 		return ENOMEM;
668 
669 	puffs_newinfo_setcookie(pni, p2n);
670 	rump_pub_getvninfo(vp, &vtype, &vsize, (void *)&rdev);
671 	puffs_newinfo_setvtype(pni, (enum vtype)vtype);
672 	puffs_newinfo_setsize(pni, vsize);
673 	/* LINTED: yea, it'll lose accuracy, but that's life */
674 	puffs_newinfo_setrdev(pni, rdev);
675 
676 	return 0;
677 }
678 
679 /*ARGSUSED*/
680 int
681 p2k_fs_nodetofh(struct puffs_usermount *pu, puffs_cookie_t cookie, void *fid,
682 	size_t *fidsize)
683 {
684 	struct vnode *vp = OPC2VP(cookie);
685 
686 	return rump_pub_vfs_vptofh(vp, fid, fidsize);
687 }
688 
689 int
690 p2k_fs_extattrctl(struct puffs_usermount *pu, int cmd,
691 	puffs_cookie_t cookie, int flags,
692 	int attrnamespace, const char *attrname)
693 {
694 	struct p2k_mount *p2m = puffs_getspecific(pu);
695 	struct mount *mp = p2m->p2m_mp;
696 	struct vnode *vp;
697 
698 	if (flags & PUFFS_EXTATTRCTL_HASNODE) {
699 		vp = OPC2VP(cookie);
700 		RUMP_VOP_LOCK(vp, LK_EXCLUSIVE | LK_RETRY);
701 	} else {
702 		vp = NULL;
703 	}
704 
705 	/* vfsop unlocks (but doesn't release) vnode, so we're done here */
706 	return rump_pub_vfs_extattrctl(mp, cmd, vp, attrnamespace, attrname);
707 }
708 
709 /*ARGSUSED*/
710 int
711 p2k_node_lookup(struct puffs_usermount *pu, puffs_cookie_t opc,
712 	struct puffs_newinfo *pni, const struct puffs_cn *pcn)
713 {
714 	struct p2k_mount *p2m = puffs_getspecific(pu);
715 	struct p2k_node *p2n_dir = opc, *p2n;
716 	struct componentname *cn;
717 	struct vnode *dvp = p2n_dir->p2n_vp, *vp;
718 	enum rump_vtype vtype;
719 	voff_t vsize;
720 	uint64_t rdev; /* XXX: uint64_t because of stack overwrite in compat */
721 	int rv;
722 
723 	cn = makecn(pcn);
724 	RUMP_VOP_LOCK(dvp, LK_EXCLUSIVE);
725 	rv = RUMP_VOP_LOOKUP(dvp, &vp, cn);
726 	RUMP_VOP_UNLOCK(dvp);
727 	freecn(cn);
728 
729 	if (rv) {
730 		if (rv == RUMP_EJUSTRETURN) {
731 			rv = ENOENT;
732 		}
733 		return rv;
734 	}
735 
736 	p2n = getp2n(p2m, vp, false, NULL);
737 	if (p2n == NULL) {
738 		return ENOMEM;
739 	}
740 
741 	puffs_newinfo_setcookie(pni, p2n);
742 	rump_pub_getvninfo(vp, &vtype, &vsize, (void *)&rdev);
743 	puffs_newinfo_setvtype(pni, (enum vtype)vtype);
744 	puffs_newinfo_setsize(pni, vsize);
745 	/* LINTED: yea, it'll lose accuracy, but that's life */
746 	puffs_newinfo_setrdev(pni, rdev);
747 
748 	return 0;
749 }
750 
751 #define VERS_TIMECHANGE 599000700
752 static int
753 needcompat(void)
754 {
755 
756 	/*LINTED*/
757 	return __NetBSD_Version__ < VERS_TIMECHANGE
758 	    && rump_getversion() >= VERS_TIMECHANGE;
759 }
760 
761 #define DOCOMPAT(va, va_compat)						\
762 do {									\
763 	if (needcompat()) {						\
764 		va_compat = rump_pub_vattr_init();			\
765 		rump_pub_vattr50_to_vattr(va, va_compat);		\
766 	} else {							\
767 		va_compat = __UNCONST(va);				\
768 	}								\
769 } while (/*CONSTCOND*/0)
770 
771 #define UNDOCOMPAT(va_compat)						\
772 do {									\
773 	if (needcompat())						\
774 		rump_pub_vattr_free(va_compat);				\
775 } while (/*CONSTCOND*/0)
776 
777 static int
778 do_makenode(struct puffs_usermount *pu, struct p2k_node *p2n_dir,
779 	struct puffs_newinfo *pni, const struct puffs_cn *pcn,
780 	const struct vattr *vap, char *link_target,
781 	int (*makefn)(struct vnode *, struct vnode **, struct componentname *,
782 		      struct vattr *),
783 	int (*symfn)(struct vnode *, struct vnode **, struct componentname *,
784 		      struct vattr *, char *))
785 {
786 	struct p2k_mount *p2m = puffs_getspecific(pu);
787 	struct vnode *dvp = p2n_dir->p2n_vp;
788 	struct p2k_node *p2n;
789 	struct componentname *cn;
790 	struct vattr *va_x;
791 	struct vnode *vp;
792 	int rv;
793 
794 	p2n = malloc(sizeof(*p2n));
795 	if (p2n == NULL)
796 		return ENOMEM;
797 	DOCOMPAT(vap, va_x);
798 
799 	cn = makecn(pcn);
800 	RUMP_VOP_LOCK(dvp, LK_EXCLUSIVE);
801 	rump_pub_vp_incref(dvp);
802 	if (makefn) {
803 		rv = makefn(dvp, &vp, cn, va_x);
804 	} else {
805 		rv = symfn(dvp, &vp, cn, va_x, link_target);
806 	}
807 	rump_pub_vp_rele(dvp);
808 	RUMP_VOP_UNLOCK(dvp);
809 	freecn(cn);
810 
811 	if (rv == 0) {
812 		p2n = getp2n(p2m, vp, true, p2n);
813 		puffs_newinfo_setcookie(pni, p2n);
814 	} else {
815 		free(p2n);
816 	}
817 
818 	UNDOCOMPAT(va_x);
819 
820 	return rv;
821 
822 }
823 
824 /*ARGSUSED*/
825 int
826 p2k_node_create(struct puffs_usermount *pu, puffs_cookie_t opc,
827 	struct puffs_newinfo *pni, const struct puffs_cn *pcn,
828 	const struct vattr *vap)
829 {
830 
831 	return do_makenode(pu, opc, pni, pcn, vap, NULL, RUMP_VOP_CREATE, NULL);
832 }
833 
834 /*ARGSUSED*/
835 int
836 p2k_node_mknod(struct puffs_usermount *pu, puffs_cookie_t opc,
837 	struct puffs_newinfo *pni, const struct puffs_cn *pcn,
838 	const struct vattr *vap)
839 {
840 
841 	return do_makenode(pu, opc, pni, pcn, vap, NULL, RUMP_VOP_MKNOD, NULL);
842 }
843 
844 /*ARGSUSED*/
845 int
846 p2k_node_open(struct puffs_usermount *pu, puffs_cookie_t opc, int mode,
847 	const struct puffs_cred *pcr)
848 {
849 	struct vnode *vp = OPC2VP(opc);
850 	struct kauth_cred *cred;
851 	int rv;
852 
853 	cred = cred_create(pcr);
854 	RUMP_VOP_LOCK(vp, LK_EXCLUSIVE);
855 	rv = RUMP_VOP_OPEN(vp, mode, cred);
856 	RUMP_VOP_UNLOCK(vp);
857 	cred_destroy(cred);
858 
859 	return rv;
860 }
861 
862 /*ARGSUSED*/
863 int
864 p2k_node_close(struct puffs_usermount *pu, puffs_cookie_t opc, int flags,
865 	const struct puffs_cred *pcr)
866 {
867 	struct vnode *vp = OPC2VP(opc);
868 	struct kauth_cred *cred;
869 
870 	cred = cred_create(pcr);
871 	RUMP_VOP_LOCK(vp, LK_EXCLUSIVE);
872 	RUMP_VOP_CLOSE(vp, flags, cred);
873 	RUMP_VOP_UNLOCK(vp);
874 	cred_destroy(cred);
875 
876 	return 0;
877 }
878 
879 /*ARGSUSED*/
880 int
881 p2k_node_access(struct puffs_usermount *pu, puffs_cookie_t opc, int mode,
882 	const struct puffs_cred *pcr)
883 {
884 	struct vnode *vp = OPC2VP(opc);
885 	struct kauth_cred *cred;
886 	int rv;
887 
888 	cred = cred_create(pcr);
889 	RUMP_VOP_LOCK(vp, LK_EXCLUSIVE);
890 	rv = RUMP_VOP_ACCESS(vp, mode, cred);
891 	RUMP_VOP_UNLOCK(vp);
892 	cred_destroy(cred);
893 
894 	return rv;
895 }
896 
897 /*ARGSUSED*/
898 int
899 p2k_node_getattr(struct puffs_usermount *pu, puffs_cookie_t opc,
900 	struct vattr *vap, const struct puffs_cred *pcr)
901 {
902 	struct vnode *vp = OPC2VP(opc);
903 	struct kauth_cred *cred;
904 	struct vattr *va_x;
905 	int rv;
906 
907 	/* "deadfs" */
908 	if (!vp)
909 		return 0;
910 
911 	if (needcompat()) {
912 		va_x = rump_pub_vattr_init();
913 	} else {
914 		va_x = vap;
915 	}
916 
917 	cred = cred_create(pcr);
918 	RUMP_VOP_LOCK(vp, LK_EXCLUSIVE);
919 	rv = RUMP_VOP_GETATTR(vp, va_x, cred);
920 	RUMP_VOP_UNLOCK(vp);
921 	cred_destroy(cred);
922 
923 	if (needcompat()) {
924 		rump_pub_vattr_to_vattr50(va_x, vap);
925 		rump_pub_vattr_free(va_x);
926 	}
927 
928 	return rv;
929 }
930 
931 /*ARGSUSED*/
932 int
933 p2k_node_setattr(struct puffs_usermount *pu, puffs_cookie_t opc,
934 	const struct vattr *vap, const struct puffs_cred *pcr)
935 {
936 	struct vnode *vp = OPC2VP(opc);
937 	struct kauth_cred *cred;
938 	struct vattr *va_x;
939 	int rv;
940 
941 	/* "deadfs" */
942 	if (!vp)
943 		return 0;
944 
945 	DOCOMPAT(vap, va_x);
946 
947 	cred = cred_create(pcr);
948 	RUMP_VOP_LOCK(vp, LK_EXCLUSIVE);
949 	rv = RUMP_VOP_SETATTR(vp, va_x, cred);
950 	RUMP_VOP_UNLOCK(vp);
951 	cred_destroy(cred);
952 
953 	UNDOCOMPAT(va_x);
954 
955 	return rv;
956 }
957 
958 /*ARGSUSED*/
959 int
960 p2k_node_fsync(struct puffs_usermount *pu, puffs_cookie_t opc,
961 	const struct puffs_cred *pcr, int flags, off_t offlo, off_t offhi)
962 {
963 	struct vnode *vp = OPC2VP(opc);
964 	struct kauth_cred *cred;
965 	int rv;
966 
967 	/* "deadfs" */
968 	if (!vp)
969 		return 0;
970 
971 	cred = cred_create(pcr);
972 	RUMP_VOP_LOCK(vp, LK_EXCLUSIVE);
973 	rv = RUMP_VOP_FSYNC(vp, cred, flags, offlo, offhi);
974 	RUMP_VOP_UNLOCK(vp);
975 	cred_destroy(cred);
976 
977 	return rv;
978 }
979 
980 /*ARGSUSED*/
981 int
982 p2k_node_mmap(struct puffs_usermount *pu, puffs_cookie_t opc, vm_prot_t flags,
983 	const struct puffs_cred *pcr)
984 {
985 	struct kauth_cred *cred;
986 	int rv;
987 
988 	cred = cred_create(pcr);
989 	rv = RUMP_VOP_MMAP(OPC2VP(opc), flags, cred);
990 	cred_destroy(cred);
991 
992 	return rv;
993 }
994 
995 /*ARGSUSED*/
996 int
997 p2k_node_seek(struct puffs_usermount *pu, puffs_cookie_t opc,
998 	off_t oldoff, off_t newoff, const struct puffs_cred *pcr)
999 {
1000 	struct vnode *vp = OPC2VP(opc);
1001 	struct kauth_cred *cred;
1002 	int rv;
1003 
1004 	cred = cred_create(pcr);
1005 	RUMP_VOP_LOCK(vp, LK_EXCLUSIVE);
1006 	rv = RUMP_VOP_SEEK(vp, oldoff, newoff, cred);
1007 	RUMP_VOP_UNLOCK(vp);
1008 	cred_destroy(cred);
1009 
1010 	return rv;
1011 }
1012 
1013 static int
1014 do_nukenode(struct p2k_node *p2n_dir, struct p2k_node *p2n,
1015 	const struct puffs_cn *pcn,
1016 	int (*nukefn)(struct vnode *, struct vnode *, struct componentname *))
1017 {
1018 	struct vnode *dvp = p2n_dir->p2n_vp, *vp = p2n->p2n_vp;
1019 	struct componentname *cn;
1020 	int rv;
1021 
1022 	cn = makecn(pcn);
1023 	RUMP_VOP_LOCK(dvp, LK_EXCLUSIVE);
1024 	rump_pub_vp_incref(dvp);
1025 	RUMP_VOP_LOCK(vp, LK_EXCLUSIVE);
1026 	rump_pub_vp_incref(vp);
1027 	rv = nukefn(dvp, vp, cn);
1028 	assert(RUMP_VOP_ISLOCKED(dvp) == 0);
1029 	assert(RUMP_VOP_ISLOCKED(vp) == 0);
1030 	freecn(cn);
1031 
1032 	return rv;
1033 
1034 }
1035 
1036 /*ARGSUSED*/
1037 int
1038 p2k_node_remove(struct puffs_usermount *pu, puffs_cookie_t opc,
1039 	puffs_cookie_t targ, const struct puffs_cn *pcn)
1040 {
1041 
1042 	return do_nukenode(opc, targ, pcn, RUMP_VOP_REMOVE);
1043 }
1044 
1045 /*ARGSUSED*/
1046 int
1047 p2k_node_link(struct puffs_usermount *pu, puffs_cookie_t opc,
1048 	puffs_cookie_t targ, const struct puffs_cn *pcn)
1049 {
1050 	struct vnode *dvp = OPC2VP(opc);
1051 	struct componentname *cn;
1052 	int rv;
1053 
1054 	cn = makecn(pcn);
1055 	RUMP_VOP_LOCK(dvp, LK_EXCLUSIVE);
1056 	rump_pub_vp_incref(dvp);
1057 	rv = RUMP_VOP_LINK(dvp, OPC2VP(targ), cn);
1058 	rump_pub_vp_rele(dvp);
1059 	RUMP_VOP_UNLOCK(dvp);
1060 	freecn(cn);
1061 
1062 	return rv;
1063 }
1064 
1065 /*ARGSUSED*/
1066 int
1067 p2k_node_rename(struct puffs_usermount *pu,
1068 	puffs_cookie_t src_dir, puffs_cookie_t src,
1069 	const struct puffs_cn *pcn_src,
1070 	puffs_cookie_t targ_dir, puffs_cookie_t targ,
1071 	const struct puffs_cn *pcn_targ)
1072 {
1073 	struct vnode *dvp, *vp, *tdvp, *tvp = NULL;
1074 	struct componentname *cn_src, *cn_targ;
1075 	int rv;
1076 
1077 	cn_src = makecn(pcn_src);
1078 	cn_targ = makecn(pcn_targ);
1079 
1080 	dvp = OPC2VP(src_dir);
1081 	vp = OPC2VP(src);
1082 	tdvp = OPC2VP(targ_dir);
1083 	if (targ) {
1084 		tvp = OPC2VP(targ);
1085 	}
1086 
1087 	rump_pub_vp_incref(dvp);
1088 	rump_pub_vp_incref(vp);
1089 	RUMP_VOP_LOCK(tdvp, LK_EXCLUSIVE);
1090 	rump_pub_vp_incref(tdvp);
1091 	if (tvp) {
1092 		RUMP_VOP_LOCK(tvp, LK_EXCLUSIVE);
1093 		rump_pub_vp_incref(tvp);
1094 	}
1095 	rv = RUMP_VOP_RENAME(dvp, vp, cn_src, tdvp, tvp, cn_targ);
1096 	assert(RUMP_VOP_ISLOCKED(tdvp) == 0);
1097 	if (tvp) {
1098 		assert(RUMP_VOP_ISLOCKED(tvp) == 0);
1099 	}
1100 	freecn(cn_src);
1101 	freecn(cn_targ);
1102 
1103 	return rv;
1104 }
1105 
1106 /*ARGSUSED*/
1107 int
1108 p2k_node_mkdir(struct puffs_usermount *pu, puffs_cookie_t opc,
1109 	struct puffs_newinfo *pni, const struct puffs_cn *pcn,
1110 	const struct vattr *vap)
1111 {
1112 
1113 	return do_makenode(pu, opc, pni, pcn, vap, NULL, RUMP_VOP_MKDIR, NULL);
1114 }
1115 
1116 /*ARGSUSED*/
1117 int
1118 p2k_node_rmdir(struct puffs_usermount *pu, puffs_cookie_t opc,
1119 	puffs_cookie_t targ, const struct puffs_cn *pcn)
1120 {
1121 
1122 	return do_nukenode(opc, targ, pcn, RUMP_VOP_RMDIR);
1123 }
1124 
1125 /*ARGSUSED*/
1126 int
1127 p2k_node_symlink(struct puffs_usermount *pu, puffs_cookie_t opc,
1128 	struct puffs_newinfo *pni, const struct puffs_cn *pcn,
1129 	const struct vattr *vap, const char *link_target)
1130 {
1131 
1132 	return do_makenode(pu, opc, pni, pcn, vap,
1133 	    __UNCONST(link_target), NULL, RUMP_VOP_SYMLINK);
1134 }
1135 
1136 /*ARGSUSED*/
1137 int
1138 p2k_node_readdir(struct puffs_usermount *pu, puffs_cookie_t opc,
1139 	struct dirent *dent, off_t *readoff, size_t *reslen,
1140 	const struct puffs_cred *pcr, int *eofflag,
1141 	off_t *cookies, size_t *ncookies)
1142 {
1143 	struct vnode *vp = OPC2VP(opc);
1144 	struct kauth_cred *cred;
1145 	struct uio *uio;
1146 	off_t *vop_cookies;
1147 	int vop_ncookies;
1148 	int rv;
1149 
1150 	cred = cred_create(pcr);
1151 	uio = rump_pub_uio_setup(dent, *reslen, *readoff, RUMPUIO_READ);
1152 	RUMP_VOP_LOCK(vp, LK_SHARED);
1153 	if (cookies) {
1154 		rv = RUMP_VOP_READDIR(vp, uio, cred, eofflag,
1155 		    &vop_cookies, &vop_ncookies);
1156 		memcpy(cookies, vop_cookies, vop_ncookies * sizeof(*cookies));
1157 		*ncookies = vop_ncookies;
1158 		free(vop_cookies);
1159 	} else {
1160 		rv = RUMP_VOP_READDIR(vp, uio, cred, eofflag, NULL, NULL);
1161 	}
1162 	RUMP_VOP_UNLOCK(vp);
1163 	if (rv == 0) {
1164 		*reslen = rump_pub_uio_getresid(uio);
1165 		*readoff = rump_pub_uio_getoff(uio);
1166 	}
1167 	rump_pub_uio_free(uio);
1168 	cred_destroy(cred);
1169 
1170 	return rv;
1171 }
1172 
1173 /*ARGSUSED*/
1174 int
1175 p2k_node_readlink(struct puffs_usermount *pu, puffs_cookie_t opc,
1176 	const struct puffs_cred *pcr, char *linkname, size_t *linklen)
1177 {
1178 	struct vnode *vp = OPC2VP(opc);
1179 	struct kauth_cred *cred;
1180 	struct uio *uio;
1181 	int rv;
1182 
1183 	cred = cred_create(pcr);
1184 	uio = rump_pub_uio_setup(linkname, *linklen, 0, RUMPUIO_READ);
1185 	RUMP_VOP_LOCK(vp, LK_EXCLUSIVE);
1186 	rv = RUMP_VOP_READLINK(vp, uio, cred);
1187 	RUMP_VOP_UNLOCK(vp);
1188 	*linklen -= rump_pub_uio_free(uio);
1189 	cred_destroy(cred);
1190 
1191 	return rv;
1192 }
1193 
1194 /*ARGSUSED*/
1195 int
1196 p2k_node_read(struct puffs_usermount *pu, puffs_cookie_t opc,
1197 	uint8_t *buf, off_t offset, size_t *resid,
1198 	const struct puffs_cred *pcr, int ioflag)
1199 {
1200 	struct vnode *vp = OPC2VP(opc);
1201 	struct kauth_cred *cred;
1202 	struct uio *uio;
1203 	int rv;
1204 
1205 	cred = cred_create(pcr);
1206 	uio = rump_pub_uio_setup(buf, *resid, offset, RUMPUIO_READ);
1207 	RUMP_VOP_LOCK(vp, LK_SHARED);
1208 	rv = RUMP_VOP_READ(vp, uio, ioflag, cred);
1209 	RUMP_VOP_UNLOCK(vp);
1210 	*resid = rump_pub_uio_free(uio);
1211 	cred_destroy(cred);
1212 
1213 	return rv;
1214 }
1215 
1216 /*ARGSUSED*/
1217 int
1218 p2k_node_write(struct puffs_usermount *pu, puffs_cookie_t opc,
1219 	uint8_t *buf, off_t offset, size_t *resid,
1220 	const struct puffs_cred *pcr, int ioflag)
1221 {
1222 	struct vnode *vp = OPC2VP(opc);
1223 	struct kauth_cred *cred;
1224 	struct uio *uio;
1225 	int rv;
1226 
1227 	/* "deadfs" */
1228 	if (!vp)
1229 		return 0;
1230 
1231 	cred = cred_create(pcr);
1232 	uio = rump_pub_uio_setup(buf, *resid, offset, RUMPUIO_WRITE);
1233 	RUMP_VOP_LOCK(vp, LK_EXCLUSIVE);
1234 	rv = RUMP_VOP_WRITE(vp, uio, ioflag, cred);
1235 	RUMP_VOP_UNLOCK(vp);
1236 	*resid = rump_pub_uio_free(uio);
1237 	cred_destroy(cred);
1238 
1239 	return rv;
1240 }
1241 
1242 /*ARGSUSED*/
1243 int
1244 p2k_node_pathconf(struct puffs_usermount *pu, puffs_cookie_t opc,
1245 	int name, register_t *retval)
1246 {
1247 	struct vnode *vp = OPC2VP(opc);
1248 	int rv;
1249 
1250 	RUMP_VOP_LOCK(vp, LK_EXCLUSIVE);
1251 	rv = RUMP_VOP_PATHCONF(vp, name, retval);
1252 	RUMP_VOP_UNLOCK(vp);
1253 
1254 	return rv;
1255 }
1256 
1257 /*ARGSUSED*/
1258 int
1259 p2k_node_getextattr(struct puffs_usermount *pu, puffs_cookie_t opc,
1260 	int attrnamespace, const char *attrname, size_t *attrsize,
1261 	uint8_t *attr, size_t *resid, const struct puffs_cred *pcr)
1262 {
1263 	struct vnode *vp = OPC2VP(opc);
1264 	struct kauth_cred *cred;
1265 	struct uio *uio;
1266 	int rv;
1267 
1268 	if (attr)
1269 		uio = rump_pub_uio_setup(attr, *resid, 0, RUMPUIO_READ);
1270 	else
1271 		uio = NULL;
1272 
1273 	cred = cred_create(pcr);
1274 	RUMP_VOP_LOCK(vp, LK_EXCLUSIVE);
1275 	rv = RUMP_VOP_GETEXTATTR(vp, attrnamespace, attrname, uio,
1276 	    attrsize, cred);
1277 	RUMP_VOP_UNLOCK(vp);
1278 	cred_destroy(cred);
1279 
1280 	if (uio)
1281 		*resid = rump_pub_uio_free(uio);
1282 
1283 	return rv;
1284 }
1285 
1286 /*ARGSUSED*/
1287 int
1288 p2k_node_setextattr(struct puffs_usermount *pu, puffs_cookie_t opc,
1289 	int attrnamespace, const char *attrname,
1290 	uint8_t *attr, size_t *resid, const struct puffs_cred *pcr)
1291 {
1292 	struct vnode *vp = OPC2VP(opc);
1293 	struct kauth_cred *cred;
1294 	struct uio *uio;
1295 	int rv;
1296 
1297 	if (attr)
1298 		uio = rump_pub_uio_setup(attr, *resid, 0, RUMPUIO_READ);
1299 	else
1300 		uio = NULL;
1301 
1302 	cred = cred_create(pcr);
1303 	RUMP_VOP_LOCK(vp, LK_EXCLUSIVE);
1304 	rv = RUMP_VOP_SETEXTATTR(vp, attrnamespace, attrname, uio, cred);
1305 	RUMP_VOP_UNLOCK(vp);
1306 	cred_destroy(cred);
1307 
1308 	if (uio)
1309 		*resid = rump_pub_uio_free(uio);
1310 
1311 	return rv;
1312 }
1313 
1314 /*ARGSUSED*/
1315 int
1316 p2k_node_listextattr(struct puffs_usermount *pu, puffs_cookie_t opc,
1317 	int attrnamespace, size_t *attrsize, uint8_t *attrs,
1318 	size_t *resid, int flags, const struct puffs_cred *pcr)
1319 {
1320 	struct vnode *vp = OPC2VP(opc);
1321 	struct kauth_cred *cred;
1322 	struct uio *uio;
1323 	int rv;
1324 
1325 	if (attrs)
1326 		uio = rump_pub_uio_setup(attrs, *resid, 0, RUMPUIO_READ);
1327 	else
1328 		uio = NULL;
1329 
1330 	cred = cred_create(pcr);
1331 	RUMP_VOP_LOCK(vp, LK_EXCLUSIVE);
1332 	rv = RUMP_VOP_LISTEXTATTR(vp, attrnamespace, uio, attrsize,
1333 	    flags, cred);
1334 	RUMP_VOP_UNLOCK(vp);
1335 	cred_destroy(cred);
1336 
1337 	if (uio)
1338 		*resid = rump_pub_uio_free(uio);
1339 
1340 	return rv;
1341 }
1342 
1343 /*ARGSUSED*/
1344 int
1345 p2k_node_deleteextattr(struct puffs_usermount *pu, puffs_cookie_t opc,
1346 	int attrnamespace, const char *attrname, const struct puffs_cred *pcr)
1347 {
1348 	struct vnode *vp = OPC2VP(opc);
1349 	struct kauth_cred *cred;
1350 	int rv;
1351 
1352 	cred = cred_create(pcr);
1353 	RUMP_VOP_LOCK(vp, LK_EXCLUSIVE);
1354 	rv = RUMP_VOP_DELETEEXTATTR(vp, attrnamespace, attrname, cred);
1355 	RUMP_VOP_UNLOCK(vp);
1356 	cred_destroy(cred);
1357 
1358 	return rv;
1359 }
1360 
1361 /* the kernel releases its last reference here */
1362 int
1363 p2k_node_inactive(struct puffs_usermount *pu, puffs_cookie_t opc)
1364 {
1365 	struct p2k_mount *p2m = puffs_getspecific(pu);
1366 	struct p2k_node *p2n = opc;
1367 	struct vnode *vp = OPC2VP(opc);
1368 	bool recycle = false;
1369 	int rv;
1370 
1371 	/* deadfs */
1372 	if (!vp)
1373 		return 0;
1374 
1375 	/*
1376 	 * Flush all cached vnode pages from the rump kernel -- they
1377 	 * are kept in puffs for all things that matter.  However,
1378 	 * don't do this for tmpfs (vnodes are backed by an aobj), since that
1379 	 * would cause us to clear the backing storage leaving us without
1380 	 * a way to regain the data from "stable storage".
1381 	 */
1382 	if (!p2m->p2m_imtmpfsman) {
1383 		rump_pub_vp_interlock(vp);
1384 		RUMP_VOP_PUTPAGES(vp, 0, 0,
1385 		    PGO_ALLPAGES|PGO_CLEANIT|PGO_FREE);
1386 	}
1387 
1388 	/*
1389 	 * Ok, this is where we get nasty.  We pretend the vnode is
1390 	 * inactive and already tell the file system that.  However,
1391 	 * we are allowed to pretend it also grows a reference immediately
1392 	 * after per vget(), so this does not do harm.  Cheap trick, but ...
1393 	 *
1394 	 * If the file system thinks the inode is done for, we release
1395 	 * our reference and clear all knowledge of the vnode.  If,
1396 	 * however, the inode is still active, we retain our reference
1397 	 * until reclaim, since puffs might be flushing out some data
1398 	 * later.
1399 	 */
1400 	RUMP_VOP_LOCK(vp, LK_EXCLUSIVE);
1401 	rv = RUMP_VOP_INACTIVE(vp, &recycle);
1402 	if (recycle) {
1403 		puffs_setback(puffs_cc_getcc(pu), PUFFS_SETBACK_NOREF_N1);
1404 		rump_pub_vp_rele(p2n->p2n_vp);
1405 		p2n->p2n_vp = NULL;
1406 	}
1407 
1408 	return rv;
1409 }
1410 
1411 /*ARGSUSED*/
1412 int
1413 p2k_node_reclaim(struct puffs_usermount *pu, puffs_croissant_t opc)
1414 {
1415 	struct p2k_node *p2n = opc;
1416 
1417 	if (p2n->p2n_vp) {
1418 		rump_pub_vp_rele(p2n->p2n_vp);
1419 		p2n->p2n_vp = NULL;
1420 	}
1421 
1422 	freep2n(p2n);
1423 	return 0;
1424 }
1425