Home | History | Annotate | Line # | Download | only in puffs
puffs_msgif.c revision 1.48
      1 /*	$NetBSD: puffs_msgif.c,v 1.48 2007/10/19 14:38:45 pooka Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 2005, 2006, 2007  Antti Kantee.  All Rights Reserved.
      5  *
      6  * Development of this software was supported by the
      7  * Google Summer of Code program and the Ulla Tuominen Foundation.
      8  * The Google SoC project was mentored by Bill Studenmund.
      9  *
     10  * Redistribution and use in source and binary forms, with or without
     11  * modification, are permitted provided that the following conditions
     12  * are met:
     13  * 1. Redistributions of source code must retain the above copyright
     14  *    notice, this list of conditions and the following disclaimer.
     15  * 2. Redistributions in binary form must reproduce the above copyright
     16  *    notice, this list of conditions and the following disclaimer in the
     17  *    documentation and/or other materials provided with the distribution.
     18  *
     19  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
     20  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
     21  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
     22  * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
     23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
     25  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     29  * SUCH DAMAGE.
     30  */
     31 
     32 #include <sys/cdefs.h>
     33 __KERNEL_RCSID(0, "$NetBSD: puffs_msgif.c,v 1.48 2007/10/19 14:38:45 pooka Exp $");
     34 
     35 #include <sys/param.h>
     36 #include <sys/fstrans.h>
     37 #include <sys/kmem.h>
     38 #include <sys/malloc.h>
     39 #include <sys/mount.h>
     40 #include <sys/vnode.h>
     41 #include <sys/lock.h>
     42 #include <sys/proc.h>
     43 
     44 #include <fs/puffs/puffs_msgif.h>
     45 #include <fs/puffs/puffs_sys.h>
     46 
     47 /*
     48  * waitq data structures
     49  */
     50 
     51 /*
     52  * While a request is going to userspace, park the caller within the
     53  * kernel.  This is the kernel counterpart of "struct puffs_req".
     54  */
     55 struct puffs_msgpark {
     56 	struct puffs_req	*park_preq;	/* req followed by buf	*/
     57 
     58 	size_t			park_copylen;	/* userspace copylength	*/
     59 	size_t			park_maxlen;	/* max size in comeback */
     60 
     61 	parkdone_fn		park_done;	/* "biodone" a'la puffs	*/
     62 	void			*park_donearg;
     63 
     64 	int			park_flags;
     65 	int			park_refcount;
     66 
     67 	kcondvar_t		park_cv;
     68 	kmutex_t		park_mtx;
     69 
     70 	TAILQ_ENTRY(puffs_msgpark) park_entries;
     71 };
     72 #define PARKFLAG_WAITERGONE	0x01
     73 #define PARKFLAG_DONE		0x02
     74 #define PARKFLAG_ONQUEUE1	0x04
     75 #define PARKFLAG_ONQUEUE2	0x08
     76 #define PARKFLAG_CALL		0x10
     77 #define PARKFLAG_WANTREPLY	0x20
     78 
     79 static struct pool_cache parkpc;
     80 static struct pool parkpool;
     81 
     82 static int
     83 makepark(void *arg, void *obj, int flags)
     84 {
     85 	struct puffs_msgpark *park = obj;
     86 
     87 	mutex_init(&park->park_mtx, MUTEX_DEFAULT, IPL_NONE);
     88 	cv_init(&park->park_cv, "puffsrpl");
     89 
     90 	return 0;
     91 }
     92 
     93 static void
     94 nukepark(void *arg, void *obj)
     95 {
     96 	struct puffs_msgpark *park = obj;
     97 
     98 	cv_destroy(&park->park_cv);
     99 	mutex_destroy(&park->park_mtx);
    100 }
    101 
    102 void
    103 puffs_msgif_init()
    104 {
    105 
    106 	pool_init(&parkpool, sizeof(struct puffs_msgpark), 0, 0, 0,
    107 	    "puffprkl", &pool_allocator_nointr, IPL_NONE);
    108 	pool_cache_init(&parkpc, &parkpool, makepark, nukepark, NULL);
    109 }
    110 
    111 void
    112 puffs_msgif_destroy()
    113 {
    114 
    115 	pool_cache_destroy(&parkpc);
    116 	pool_destroy(&parkpool);
    117 }
    118 
    119 static int alloced;
    120 
    121 static struct puffs_msgpark *
    122 puffs_msgpark_alloc(int waitok)
    123 {
    124 	struct puffs_msgpark *park;
    125 
    126 	park = pool_cache_get(&parkpc, waitok ? PR_WAITOK : PR_NOWAIT);
    127 	if (park == NULL)
    128 		return park;
    129 
    130 	park->park_refcount = 1;
    131 	park->park_preq = NULL;
    132 	park->park_flags = PARKFLAG_WANTREPLY;
    133 
    134 	return park;
    135 }
    136 
    137 static void
    138 puffs_msgpark_reference(struct puffs_msgpark *park)
    139 {
    140 
    141 	KASSERT(mutex_owned(&park->park_mtx));
    142 	park->park_refcount++;
    143 }
    144 
    145 /*
    146  * Release reference to park structure.
    147  */
    148 static void
    149 puffs_msgpark_release1(struct puffs_msgpark *park, int howmany)
    150 {
    151 	struct puffs_req *preq = park->park_preq;
    152 	int refcnt;
    153 
    154 	KASSERT(mutex_owned(&park->park_mtx));
    155 	refcnt = park->park_refcount -= howmany;
    156 	mutex_exit(&park->park_mtx);
    157 
    158 	KASSERT(refcnt >= 0);
    159 
    160 	if (refcnt == 0) {
    161 		alloced--;
    162 		if (preq)
    163 			kmem_free(preq, park->park_maxlen);
    164 		pool_cache_put(&parkpc, park);
    165 	}
    166 }
    167 #define puffs_msgpark_release(a) puffs_msgpark_release1(a, 1)
    168 
    169 #ifdef PUFFSDEBUG
    170 static void
    171 parkdump(struct puffs_msgpark *park)
    172 {
    173 
    174 	DPRINTF(("park %p, preq %p, id %" PRIu64 "\n"
    175 	    "\tcopy %zu, max %zu - done: %p/%p\n"
    176 	    "\tflags 0x%08x, refcount %d, cv/mtx: %p/%p\n",
    177 	    park, park->park_preq, park->park_preq->preq_id,
    178 	    park->park_copylen, park->park_maxlen,
    179 	    park->park_done, park->park_donearg,
    180 	    park->park_flags, park->park_refcount,
    181 	    &park->park_cv, &park->park_mtx));
    182 }
    183 
    184 static void
    185 parkqdump(struct puffs_wq *q, int dumpall)
    186 {
    187 	struct puffs_msgpark *park;
    188 	int total = 0;
    189 
    190 	TAILQ_FOREACH(park, q, park_entries) {
    191 		if (dumpall)
    192 			parkdump(park);
    193 		total++;
    194 	}
    195 	DPRINTF(("puffs waitqueue at %p dumped, %d total\n", q, total));
    196 
    197 }
    198 #endif /* PUFFSDEBUG */
    199 
    200 /*
    201  * A word about locking in the park structures: the lock protects the
    202  * fields of the *park* structure (not preq) and acts as an interlock
    203  * in cv operations.  The lock is always internal to this module and
    204  * callers do not need to worry about it.
    205  */
    206 
    207 int
    208 puffs_msgmem_alloc(size_t len, struct puffs_msgpark **ppark, void **mem,
    209 	int cansleep)
    210 {
    211 	struct puffs_msgpark *park;
    212 	void *m;
    213 
    214 	m = kmem_zalloc(len, cansleep ? KM_SLEEP : KM_NOSLEEP);
    215 	if (m == NULL) {
    216 		KASSERT(cansleep == 0);
    217 		return ENOMEM;
    218 	}
    219 
    220 	park = puffs_msgpark_alloc(cansleep);
    221 	if (park == NULL) {
    222 		KASSERT(cansleep == 0);
    223 		kmem_free(m, len);
    224 		return ENOMEM;
    225 	}
    226 
    227 	park->park_preq = m;
    228 	park->park_maxlen = len;
    229 
    230 	*ppark = park;
    231 	*mem = m;
    232 
    233 	return 0;
    234 }
    235 
    236 void
    237 puffs_msgmem_release(struct puffs_msgpark *park)
    238 {
    239 
    240 	if (park == NULL)
    241 		return;
    242 
    243 	mutex_enter(&park->park_mtx);
    244 	puffs_msgpark_release(park);
    245 }
    246 
    247 void
    248 puffs_msg_setfaf(struct puffs_msgpark *park)
    249 {
    250 
    251 	park->park_flags &= ~PARKFLAG_WANTREPLY;
    252 }
    253 
    254 /*
    255  * kernel-user-kernel waitqueues
    256  */
    257 
    258 static int touser(struct puffs_mount *, struct puffs_msgpark *);
    259 
    260 static uint64_t
    261 puffs_getmsgid(struct puffs_mount *pmp)
    262 {
    263 	uint64_t rv;
    264 
    265 	mutex_enter(&pmp->pmp_lock);
    266 	rv = pmp->pmp_nextmsgid++;
    267 	mutex_exit(&pmp->pmp_lock);
    268 
    269 	return rv;
    270 }
    271 
    272 /* vfs request */
    273 int
    274 puffs_msg_vfs(struct puffs_mount *pmp, struct puffs_msgpark *park, int optype)
    275 {
    276 
    277 	park->park_preq->preq_opclass = PUFFSOP_VFS;
    278 	park->park_preq->preq_optype = optype;
    279 
    280 	park->park_copylen = park->park_maxlen;
    281 
    282 	return touser(pmp, park);
    283 }
    284 
    285 /*
    286  * vnode level request
    287  */
    288 int
    289 puffs_msg_vn(struct puffs_mount *pmp, struct puffs_msgpark *park,
    290 	int optype, size_t delta, struct vnode *vp_opc, struct vnode *vp_aux)
    291 {
    292 	struct puffs_req *preq;
    293 	void *cookie = VPTOPNC(vp_opc);
    294 	struct puffs_node *pnode;
    295 	int rv;
    296 
    297 	park->park_preq->preq_opclass = PUFFSOP_VN;
    298 	park->park_preq->preq_optype = optype;
    299 	park->park_preq->preq_cookie = cookie;
    300 
    301 	KASSERT(delta < park->park_maxlen); /* "<=" wouldn't make sense */
    302 	park->park_copylen = park->park_maxlen - delta;
    303 
    304 	rv = touser(pmp, park);
    305 
    306 	/*
    307 	 * Check if the user server requests that inactive be called
    308 	 * when the time is right.
    309 	 */
    310 	preq = park->park_preq;
    311 	if (preq->preq_setbacks & PUFFS_SETBACK_INACT_N1) {
    312 		pnode = vp_opc->v_data;
    313 		pnode->pn_stat |= PNODE_DOINACT;
    314 	}
    315 	if (preq->preq_setbacks & PUFFS_SETBACK_INACT_N2) {
    316 		/* if no vp_aux, just ignore */
    317 		if (vp_aux) {
    318 			pnode = vp_aux->v_data;
    319 			pnode->pn_stat |= PNODE_DOINACT;
    320 		}
    321 	}
    322 	if (preq->preq_setbacks & PUFFS_SETBACK_NOREF_N1) {
    323 		pnode = vp_opc->v_data;
    324 		pnode->pn_stat |= PNODE_NOREFS;
    325 	}
    326 	if (preq->preq_setbacks & PUFFS_SETBACK_NOREF_N2) {
    327 		/* if no vp_aux, just ignore */
    328 		if (vp_aux) {
    329 			pnode = vp_aux->v_data;
    330 			pnode->pn_stat |= PNODE_NOREFS;
    331 		}
    332 	}
    333 
    334 	return rv;
    335 }
    336 
    337 void
    338 puffs_msg_vncall(struct puffs_mount *pmp, struct puffs_msgpark *park,
    339 	int optype, size_t delta, parkdone_fn donefn, void *donearg,
    340 	struct vnode *vp_opc)
    341 {
    342 	void *cookie = VPTOPNC(vp_opc);
    343 
    344 	park->park_preq->preq_opclass = PUFFSOP_VN;
    345 	park->park_preq->preq_optype = optype;
    346 	park->park_preq->preq_cookie = cookie;
    347 
    348 	KASSERT(delta < park->park_maxlen);
    349 	park->park_copylen = park->park_maxlen - delta;
    350 	park->park_done = donefn;
    351 	park->park_donearg = donearg;
    352 	park->park_flags |= PARKFLAG_CALL;
    353 
    354 	(void) touser(pmp, park);
    355 }
    356 
    357 int
    358 puffs_msg_raw(struct puffs_mount *pmp, struct puffs_msgpark *park)
    359 {
    360 
    361 	park->park_copylen = park->park_maxlen;
    362 
    363 	return touser(pmp, park);
    364 }
    365 
    366 void
    367 puffs_msg_errnotify(struct puffs_mount *pmp, uint8_t type, int error,
    368 	const char *str, void *cookie)
    369 {
    370 	struct puffs_msgpark *park;
    371 	struct puffs_error *perr;
    372 
    373 	puffs_msgmem_alloc(sizeof(struct puffs_error), &park, (void **)&perr,1);
    374 
    375 	perr->perr_error = error;
    376 	strlcpy(perr->perr_str, str, sizeof(perr->perr_str));
    377 
    378 	park->park_preq->preq_opclass |= PUFFSOP_ERROR | PUFFSOPFLAG_FAF;
    379 	park->park_preq->preq_optype = type;
    380 	park->park_preq->preq_cookie = cookie;
    381 
    382 	park->park_copylen = park->park_maxlen;
    383 
    384 	(void)touser(pmp, park);
    385 }
    386 
    387 /*
    388  * Wait for the userspace ping-pong game in calling process context.
    389  *
    390  * This unlocks vnodes if they are supplied.  vp1 is the vnode
    391  * before in the locking order, i.e. the one which must be locked
    392  * before accessing vp2.  This is done here so that operations are
    393  * already ordered in the queue when vnodes are unlocked (I'm not
    394  * sure if that's really necessary, but it can't hurt).  Okok, maybe
    395  * there's a slight ugly-factor also, but let's not worry about that.
    396  */
    397 static int
    398 touser(struct puffs_mount *pmp, struct puffs_msgpark *park)
    399 {
    400 	struct lwp *l = curlwp;
    401 	struct mount *mp;
    402 	struct puffs_req *preq;
    403 	int rv = 0;
    404 
    405 	mp = PMPTOMP(pmp);
    406 	preq = park->park_preq;
    407 	preq->preq_buflen = park->park_maxlen;
    408 	KASSERT(preq->preq_id == 0);
    409 
    410 	if ((park->park_flags & PARKFLAG_WANTREPLY) == 0)
    411 		preq->preq_opclass |= PUFFSOPFLAG_FAF;
    412 	else
    413 		preq->preq_id = puffs_getmsgid(pmp);
    414 
    415 	/*
    416 	 * To support PCATCH, yet another movie: check if there are signals
    417 	 * pending and we are issueing a non-FAF.  If so, return an error
    418 	 * directly UNLESS we are issueing INACTIVE.  In that case, convert
    419 	 * it to a FAF, fire off to the file server and return an error.
    420 	 * Yes, this is bordering disgusting.  Barfbags are on me.
    421 	 */
    422 	if ((park->park_flags & PARKFLAG_WANTREPLY)
    423 	   && (park->park_flags & PARKFLAG_CALL) == 0
    424 	   && (l->l_flag & LW_PENDSIG) != 0 && sigispending(l, 0)) {
    425 		if (PUFFSOP_OPCLASS(preq->preq_opclass) == PUFFSOP_VN
    426 		    && preq->preq_optype == PUFFS_VN_INACTIVE) {
    427 			park->park_preq->preq_opclass |= PUFFSOPFLAG_FAF;
    428 			park->park_flags &= ~PARKFLAG_WANTREPLY;
    429 			DPRINTF(("puffs touser: converted to FAF %p\n", park));
    430 			rv = EINTR;
    431 		} else {
    432 			return EINTR;
    433 		}
    434 	}
    435 
    436 	/*
    437 	 * test for suspension lock.
    438 	 *
    439 	 * Note that we *DO NOT* keep the lock, since that might block
    440 	 * lock acquiring PLUS it would give userlandia control over
    441 	 * the lock.  The operation queue enforces a strict ordering:
    442 	 * when the fs server gets in the op stream, it knows things
    443 	 * are in order.  The kernel locks can't guarantee that for
    444 	 * userspace, in any case.
    445 	 *
    446 	 * BUT: this presents a problem for ops which have a consistency
    447 	 * clause based on more than one operation.  Unfortunately such
    448 	 * operations (read, write) do not reliably work yet.
    449 	 *
    450 	 * Ya, Ya, it's wrong wong wrong, me be fixink this someday.
    451 	 *
    452 	 * XXX: and there is one more problem.  We sometimes need to
    453 	 * take a lazy lock in case the fs is suspending and we are
    454 	 * executing as the fs server context.  This might happen
    455 	 * e.g. in the case that the user server triggers a reclaim
    456 	 * in the kernel while the fs is suspending.  It's not a very
    457 	 * likely event, but it needs to be fixed some day.
    458 	 */
    459 
    460 	/*
    461 	 * MOREXXX: once PUFFS_WCACHEINFO is enabled, we can't take
    462 	 * the mutex here, since getpages() might be called locked.
    463 	 */
    464 	fstrans_start(mp, FSTRANS_NORMAL);
    465 	mutex_enter(&pmp->pmp_lock);
    466 	fstrans_done(mp);
    467 
    468 	if (pmp->pmp_status != PUFFSTAT_RUNNING) {
    469 		mutex_exit(&pmp->pmp_lock);
    470 		return ENXIO;
    471 	}
    472 
    473 #ifdef PUFFSDEBUG
    474 	parkqdump(&pmp->pmp_msg_touser, puffsdebug > 1);
    475 	parkqdump(&pmp->pmp_msg_replywait, puffsdebug > 1);
    476 #endif
    477 
    478 	mutex_enter(&park->park_mtx);
    479 	TAILQ_INSERT_TAIL(&pmp->pmp_msg_touser, park, park_entries);
    480 	park->park_flags |= PARKFLAG_ONQUEUE1;
    481 	puffs_mp_reference(pmp);
    482 	pmp->pmp_msg_touser_count++;
    483 	mutex_exit(&pmp->pmp_lock);
    484 
    485 	DPRINTF(("touser: req %" PRIu64 ", preq: %p, park: %p, "
    486 	    "c/t: 0x%x/0x%x, f: 0x%x\n", preq->preq_id, preq, park,
    487 	    preq->preq_opclass, preq->preq_optype, park->park_flags));
    488 
    489 	cv_broadcast(&pmp->pmp_msg_waiter_cv);
    490 	selnotify(pmp->pmp_sel, 0);
    491 
    492 	if ((park->park_flags & PARKFLAG_WANTREPLY)
    493 	    && (park->park_flags & PARKFLAG_CALL) == 0) {
    494 		int error;
    495 
    496 		error = cv_wait_sig(&park->park_cv, &park->park_mtx);
    497 		DPRINTF(("puffs_touser: waiter for %p woke up with %d\n",
    498 		    park, error));
    499 		if (error) {
    500 			park->park_flags |= PARKFLAG_WAITERGONE;
    501 			if (park->park_flags & PARKFLAG_DONE) {
    502 				rv = preq->preq_rv;
    503 			} else {
    504 				/*
    505 				 * ok, we marked it as going away, but
    506 				 * still need to do queue ops.  take locks
    507 				 * in correct order.
    508 				 *
    509 				 * We don't want to release our reference
    510 				 * if it's on replywait queue to avoid error
    511 				 * to file server.  putop() code will DTRT.
    512 				 */
    513 				mutex_exit(&park->park_mtx);
    514 				mutex_enter(&pmp->pmp_lock);
    515 				mutex_enter(&park->park_mtx);
    516 
    517 				/* remove from queue1 */
    518 				if (park->park_flags & PARKFLAG_ONQUEUE1) {
    519 					TAILQ_REMOVE(&pmp->pmp_msg_touser,
    520 					    park, park_entries);
    521 					pmp->pmp_msg_touser_count--;
    522 					park->park_flags &= ~PARKFLAG_ONQUEUE1;
    523 				}
    524 
    525 				/*
    526 				 * If it's waiting for a response already,
    527 				 * boost reference count.  Park will get
    528 				 * nuked once the response arrives from
    529 				 * the file server.
    530 				 */
    531 				if (park->park_flags & PARKFLAG_ONQUEUE2)
    532 					puffs_msgpark_reference(park);
    533 
    534 				mutex_exit(&pmp->pmp_lock);
    535 
    536 				rv = error;
    537 			}
    538 		} else {
    539 			rv = preq->preq_rv;
    540 		}
    541 
    542 		/*
    543 		 * retake the lock and release.  This makes sure (haha,
    544 		 * I'm humorous) that we don't process the same vnode in
    545 		 * multiple threads due to the locks hacks we have in
    546 		 * puffs_lock().  In reality this is well protected by
    547 		 * the biglock, but once that's gone, well, hopefully
    548 		 * this will be fixed for real.  (and when you read this
    549 		 * comment in 2017 and subsequently barf, my condolences ;).
    550 		 */
    551 		if (rv == 0 && !fstrans_is_owner(mp)) {
    552 			fstrans_start(mp, FSTRANS_NORMAL);
    553 			fstrans_done(mp);
    554 		}
    555 	} else {
    556 		/*
    557 		 * Take extra reference for FAF, i.e. don't free us
    558 		 * immediately upon return to the caller, but rather
    559 		 * only when the message has been transported.
    560 		 */
    561 		puffs_msgpark_reference(park);
    562 	}
    563 
    564 	mutex_exit(&park->park_mtx);
    565 
    566 	mutex_enter(&pmp->pmp_lock);
    567 	puffs_mp_release(pmp);
    568 	mutex_exit(&pmp->pmp_lock);
    569 
    570 	return rv;
    571 }
    572 
    573 /*
    574  * Get next request in the outgoing queue.  "maxsize" controls the
    575  * size the caller can accommodate and "nonblock" signals if this
    576  * should block while waiting for input.  Handles all locking internally.
    577  */
    578 int
    579 puffs_msgif_getout(void *this, size_t maxsize, int nonblock,
    580 	uint8_t **data, size_t *dlen, void **parkptr)
    581 {
    582 	struct puffs_mount *pmp = this;
    583 	struct puffs_msgpark *park;
    584 	struct puffs_req *preq;
    585 	int error;
    586 
    587 	error = 0;
    588 	mutex_enter(&pmp->pmp_lock);
    589 	for (;;) {
    590 		/* RIP? */
    591 		if (pmp->pmp_status != PUFFSTAT_RUNNING) {
    592 			error = ENXIO;
    593 			break;
    594 		}
    595 
    596 		/* need platinum yendorian express card? */
    597 		if (TAILQ_EMPTY(&pmp->pmp_msg_touser)) {
    598 			DPRINTF(("puffs_getout: no outgoing op, "));
    599 			if (nonblock) {
    600 				DPRINTF(("returning EWOULDBLOCK\n"));
    601 				error = EWOULDBLOCK;
    602 				break;
    603 			}
    604 			DPRINTF(("waiting ...\n"));
    605 
    606 			error = cv_wait_sig(&pmp->pmp_msg_waiter_cv,
    607 			    &pmp->pmp_lock);
    608 			if (error)
    609 				break;
    610 			else
    611 				continue;
    612 		}
    613 
    614 		park = TAILQ_FIRST(&pmp->pmp_msg_touser);
    615 		mutex_enter(&park->park_mtx);
    616 		puffs_msgpark_reference(park);
    617 
    618 		DPRINTF(("puffs_getout: found park at %p, ", park));
    619 
    620 		/* If it's a goner, don't process any furher */
    621 		if (park->park_flags & PARKFLAG_WAITERGONE) {
    622 			DPRINTF(("waitergone!\n"));
    623 			puffs_msgpark_release(park);
    624 			continue;
    625 		}
    626 
    627 		/* check size */
    628 		preq = park->park_preq;
    629 		if (maxsize < preq->preq_frhdr.pfr_len) {
    630 			DPRINTF(("buffer too small\n"));
    631 			puffs_msgpark_release(park);
    632 			error = E2BIG;
    633 			break;
    634 		}
    635 
    636 		DPRINTF(("returning\n"));
    637 
    638 		/*
    639 		 * Ok, we found what we came for.  Release it from the
    640 		 * outgoing queue but do not unlock.  We will unlock
    641 		 * only after we "releaseout" it to avoid complications:
    642 		 * otherwise it is (theoretically) possible for userland
    643 		 * to race us into "put" before we have a change to put
    644 		 * this baby on the receiving queue.
    645 		 */
    646 		TAILQ_REMOVE(&pmp->pmp_msg_touser, park, park_entries);
    647 		KASSERT(park->park_flags & PARKFLAG_ONQUEUE1);
    648 		park->park_flags &= ~PARKFLAG_ONQUEUE1;
    649 		mutex_exit(&park->park_mtx);
    650 
    651 		pmp->pmp_msg_touser_count--;
    652 		KASSERT(pmp->pmp_msg_touser_count >= 0);
    653 
    654 		break;
    655 	}
    656 	mutex_exit(&pmp->pmp_lock);
    657 
    658 	if (error == 0) {
    659 		*data = (uint8_t *)preq;
    660 		preq->preq_frhdr.pfr_len = park->park_copylen;
    661 		preq->preq_frhdr.pfr_alloclen = park->park_maxlen;
    662 		preq->preq_frhdr.pfr_type = preq->preq_opclass; /* yay! */
    663 		*dlen = preq->preq_frhdr.pfr_len;
    664 		*parkptr = park;
    665 	}
    666 
    667 	return error;
    668 }
    669 
    670 /*
    671  * Release outgoing structure.  Now, depending on the success of the
    672  * outgoing send, it is either going onto the result waiting queue
    673  * or the death chamber.
    674  */
    675 void
    676 puffs_msgif_releaseout(void *this, void *parkptr, int status)
    677 {
    678 	struct puffs_mount *pmp = this;
    679 	struct puffs_msgpark *park = parkptr;
    680 
    681 	DPRINTF(("puffs_releaseout: returning park %p, errno %d: " ,
    682 	    park, status));
    683 	mutex_enter(&pmp->pmp_lock);
    684 	mutex_enter(&park->park_mtx);
    685 	if (park->park_flags & PARKFLAG_WANTREPLY) {
    686 		if (status == 0) {
    687 			DPRINTF(("enqueue replywait\n"));
    688 			TAILQ_INSERT_TAIL(&pmp->pmp_msg_replywait, park,
    689 			    park_entries);
    690 			park->park_flags |= PARKFLAG_ONQUEUE2;
    691 		} else {
    692 			DPRINTF(("error path!\n"));
    693 			park->park_preq->preq_rv = status;
    694 			park->park_flags |= PARKFLAG_DONE;
    695 			cv_signal(&park->park_cv);
    696 		}
    697 		puffs_msgpark_release(park);
    698 	} else {
    699 		DPRINTF(("release\n"));
    700 		puffs_msgpark_release1(park, 2);
    701 	}
    702 	mutex_exit(&pmp->pmp_lock);
    703 }
    704 
    705 void
    706 puffs_msgif_incoming(void *this, void *buf)
    707 {
    708 	struct puffs_mount *pmp = this;
    709 	struct puffs_req *preq = buf;
    710 	struct puffs_frame *pfr = &preq->preq_frhdr;
    711 	struct puffs_msgpark *park;
    712 	int release, wgone;
    713 
    714 	/* XXX */
    715 	if (PUFFSOP_OPCLASS(preq->preq_opclass) != PUFFSOP_VN
    716 	    && PUFFSOP_OPCLASS(preq->preq_opclass) != PUFFSOP_VFS)
    717 		return;
    718 
    719 	mutex_enter(&pmp->pmp_lock);
    720 
    721 	/* Locate waiter */
    722 	TAILQ_FOREACH(park, &pmp->pmp_msg_replywait, park_entries) {
    723 		if (park->park_preq->preq_id == preq->preq_id)
    724 			break;
    725 	}
    726 	if (park == NULL) {
    727 		DPRINTF(("puffs_msgif_income: no request: %" PRIu64 "\n",
    728 		    preq->preq_id));
    729 		mutex_exit(&pmp->pmp_lock);
    730 		return; /* XXX send error */
    731 	}
    732 
    733 	mutex_enter(&park->park_mtx);
    734 	puffs_msgpark_reference(park);
    735 	if (pfr->pfr_len > park->park_maxlen) {
    736 		DPRINTF(("puffs_msgif_income: invalid buffer length: "
    737 		    "%zu (req %" PRIu64 ", \n", pfr->pfr_len, preq->preq_id));
    738 		park->park_preq->preq_rv = EPROTO;
    739 		cv_signal(&park->park_cv);
    740 		puffs_msgpark_release(park);
    741 		mutex_exit(&pmp->pmp_lock);
    742 		return; /* XXX: error */
    743 	}
    744 	wgone = park->park_flags & PARKFLAG_WAITERGONE;
    745 
    746 	KASSERT(park->park_flags & PARKFLAG_ONQUEUE2);
    747 	TAILQ_REMOVE(&pmp->pmp_msg_replywait, park, park_entries);
    748 	park->park_flags &= ~PARKFLAG_ONQUEUE2;
    749 	mutex_exit(&pmp->pmp_lock);
    750 
    751 	if (wgone) {
    752 		DPRINTF(("puffs_putop: bad service - waiter gone for "
    753 		    "park %p\n", park));
    754 		release = 2;
    755 	} else {
    756 		if (park->park_flags & PARKFLAG_CALL) {
    757 			DPRINTF(("puffs_msgif_income: call for %p, arg %p\n",
    758 			    park->park_preq, park->park_donearg));
    759 			park->park_done(pmp, buf, park->park_donearg);
    760 			release = 2;
    761 		} else {
    762 			/* XXX: yes, I know */
    763 			memcpy(park->park_preq, buf, pfr->pfr_len);
    764 			release = 1;
    765 		}
    766 	}
    767 
    768 	if (!wgone) {
    769 		DPRINTF(("puffs_putop: flagging done for "
    770 		    "park %p\n", park));
    771 		cv_signal(&park->park_cv);
    772 	}
    773 
    774 	park->park_flags |= PARKFLAG_DONE;
    775 	puffs_msgpark_release1(park, release);
    776 }
    777 
    778 /*
    779  * We're dead, kaput, RIP, slightly more than merely pining for the
    780  * fjords, belly-up, fallen, lifeless, finished, expired, gone to meet
    781  * our maker, ceased to be, etcetc.  YASD.  It's a dead FS!
    782  *
    783  * Caller must hold puffs mutex.
    784  */
    785 void
    786 puffs_userdead(struct puffs_mount *pmp)
    787 {
    788 	struct puffs_msgpark *park, *park_next;
    789 
    790 	/*
    791 	 * Mark filesystem status as dying so that operations don't
    792 	 * attempt to march to userspace any longer.
    793 	 */
    794 	pmp->pmp_status = PUFFSTAT_DYING;
    795 
    796 	/* signal waiters on REQUEST TO file server queue */
    797 	for (park = TAILQ_FIRST(&pmp->pmp_msg_touser); park; park = park_next) {
    798 		uint8_t opclass;
    799 
    800 		mutex_enter(&park->park_mtx);
    801 		puffs_msgpark_reference(park);
    802 		park_next = TAILQ_NEXT(park, park_entries);
    803 
    804 		KASSERT(park->park_flags & PARKFLAG_ONQUEUE1);
    805 		TAILQ_REMOVE(&pmp->pmp_msg_touser, park, park_entries);
    806 		park->park_flags &= ~PARKFLAG_ONQUEUE1;
    807 		pmp->pmp_msg_touser_count--;
    808 
    809 		/*
    810 		 * If the waiter is gone, we may *NOT* access preq anymore.
    811 		 */
    812 		if (park->park_flags & PARKFLAG_WAITERGONE) {
    813 			KASSERT((park->park_flags & PARKFLAG_CALL) == 0);
    814 			KASSERT(park->park_flags & PARKFLAG_WANTREPLY);
    815 			puffs_msgpark_release(park);
    816 		} else {
    817 			opclass = park->park_preq->preq_opclass;
    818 			park->park_preq->preq_rv = ENXIO;
    819 
    820 			if (park->park_flags & PARKFLAG_CALL) {
    821 				park->park_done(pmp, park->park_preq,
    822 				    park->park_donearg);
    823 				puffs_msgpark_release1(park, 2);
    824 			} else if ((park->park_flags & PARKFLAG_WANTREPLY)==0) {
    825 				puffs_msgpark_release1(park, 2);
    826 			} else {
    827 				park->park_preq->preq_rv = ENXIO;
    828 				cv_signal(&park->park_cv);
    829 				puffs_msgpark_release(park);
    830 			}
    831 		}
    832 	}
    833 
    834 	/* signal waiters on RESPONSE FROM file server queue */
    835 	for (park=TAILQ_FIRST(&pmp->pmp_msg_replywait); park; park=park_next) {
    836 		mutex_enter(&park->park_mtx);
    837 		puffs_msgpark_reference(park);
    838 		park_next = TAILQ_NEXT(park, park_entries);
    839 
    840 		KASSERT(park->park_flags & PARKFLAG_ONQUEUE2);
    841 		KASSERT(park->park_flags & PARKFLAG_WANTREPLY);
    842 
    843 		TAILQ_REMOVE(&pmp->pmp_msg_replywait, park, park_entries);
    844 		park->park_flags &= ~PARKFLAG_ONQUEUE2;
    845 
    846 		/*
    847 		 * If the waiter is gone, we may *NOT* access preq anymore.
    848 		 */
    849 		if (park->park_flags & PARKFLAG_WAITERGONE) {
    850 			KASSERT((park->park_flags & PARKFLAG_CALL) == 0);
    851 			puffs_msgpark_release(park);
    852 		} else {
    853 			park->park_preq->preq_rv = ENXIO;
    854 			if (park->park_flags & PARKFLAG_CALL) {
    855 				park->park_done(pmp, park->park_preq,
    856 				    park->park_donearg);
    857 				puffs_msgpark_release1(park, 2);
    858 			} else {
    859 				cv_signal(&park->park_cv);
    860 				puffs_msgpark_release(park);
    861 			}
    862 		}
    863 	}
    864 }
    865