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