Home | History | Annotate | Line # | Download | only in puffs
puffs_msgif.c revision 1.50
      1 /*	$NetBSD: puffs_msgif.c,v 1.50 2007/10/25 15:22:25 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.50 2007/10/25 15:22:25 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 	/* fill in caller information */
    416 	preq->preq_pid = l->l_proc->p_pid;
    417 	preq->preq_lid = l->l_lid;
    418 
    419 	/*
    420 	 * To support PCATCH, yet another movie: check if there are signals
    421 	 * pending and we are issueing a non-FAF.  If so, return an error
    422 	 * directly UNLESS we are issueing INACTIVE.  In that case, convert
    423 	 * it to a FAF, fire off to the file server and return an error.
    424 	 * Yes, this is bordering disgusting.  Barfbags are on me.
    425 	 */
    426 	if ((park->park_flags & PARKFLAG_WANTREPLY)
    427 	   && (park->park_flags & PARKFLAG_CALL) == 0
    428 	   && (l->l_flag & LW_PENDSIG) != 0 && sigispending(l, 0)) {
    429 		if (PUFFSOP_OPCLASS(preq->preq_opclass) == PUFFSOP_VN
    430 		    && preq->preq_optype == PUFFS_VN_INACTIVE) {
    431 			park->park_preq->preq_opclass |= PUFFSOPFLAG_FAF;
    432 			park->park_flags &= ~PARKFLAG_WANTREPLY;
    433 			DPRINTF(("puffs touser: converted to FAF %p\n", park));
    434 			rv = EINTR;
    435 		} else {
    436 			return EINTR;
    437 		}
    438 	}
    439 
    440 	/*
    441 	 * test for suspension lock.
    442 	 *
    443 	 * Note that we *DO NOT* keep the lock, since that might block
    444 	 * lock acquiring PLUS it would give userlandia control over
    445 	 * the lock.  The operation queue enforces a strict ordering:
    446 	 * when the fs server gets in the op stream, it knows things
    447 	 * are in order.  The kernel locks can't guarantee that for
    448 	 * userspace, in any case.
    449 	 *
    450 	 * BUT: this presents a problem for ops which have a consistency
    451 	 * clause based on more than one operation.  Unfortunately such
    452 	 * operations (read, write) do not reliably work yet.
    453 	 *
    454 	 * Ya, Ya, it's wrong wong wrong, me be fixink this someday.
    455 	 *
    456 	 * XXX: and there is one more problem.  We sometimes need to
    457 	 * take a lazy lock in case the fs is suspending and we are
    458 	 * executing as the fs server context.  This might happen
    459 	 * e.g. in the case that the user server triggers a reclaim
    460 	 * in the kernel while the fs is suspending.  It's not a very
    461 	 * likely event, but it needs to be fixed some day.
    462 	 */
    463 
    464 	/*
    465 	 * MOREXXX: once PUFFS_WCACHEINFO is enabled, we can't take
    466 	 * the mutex here, since getpages() might be called locked.
    467 	 */
    468 	fstrans_start(mp, FSTRANS_NORMAL);
    469 	mutex_enter(&pmp->pmp_lock);
    470 	fstrans_done(mp);
    471 
    472 	if (pmp->pmp_status != PUFFSTAT_RUNNING) {
    473 		mutex_exit(&pmp->pmp_lock);
    474 		return ENXIO;
    475 	}
    476 
    477 #ifdef PUFFSDEBUG
    478 	parkqdump(&pmp->pmp_msg_touser, puffsdebug > 1);
    479 	parkqdump(&pmp->pmp_msg_replywait, puffsdebug > 1);
    480 #endif
    481 
    482 	mutex_enter(&park->park_mtx);
    483 	TAILQ_INSERT_TAIL(&pmp->pmp_msg_touser, park, park_entries);
    484 	park->park_flags |= PARKFLAG_ONQUEUE1;
    485 	puffs_mp_reference(pmp);
    486 	pmp->pmp_msg_touser_count++;
    487 	mutex_exit(&pmp->pmp_lock);
    488 
    489 	DPRINTF(("touser: req %" PRIu64 ", preq: %p, park: %p, "
    490 	    "c/t: 0x%x/0x%x, f: 0x%x\n", preq->preq_id, preq, park,
    491 	    preq->preq_opclass, preq->preq_optype, park->park_flags));
    492 
    493 	cv_broadcast(&pmp->pmp_msg_waiter_cv);
    494 	selnotify(pmp->pmp_sel, 0);
    495 
    496 	if ((park->park_flags & PARKFLAG_WANTREPLY)
    497 	    && (park->park_flags & PARKFLAG_CALL) == 0) {
    498 		int error;
    499 
    500 		error = cv_wait_sig(&park->park_cv, &park->park_mtx);
    501 		DPRINTF(("puffs_touser: waiter for %p woke up with %d\n",
    502 		    park, error));
    503 		if (error) {
    504 			park->park_flags |= PARKFLAG_WAITERGONE;
    505 			if (park->park_flags & PARKFLAG_DONE) {
    506 				rv = preq->preq_rv;
    507 			} else {
    508 				/*
    509 				 * ok, we marked it as going away, but
    510 				 * still need to do queue ops.  take locks
    511 				 * in correct order.
    512 				 *
    513 				 * We don't want to release our reference
    514 				 * if it's on replywait queue to avoid error
    515 				 * to file server.  putop() code will DTRT.
    516 				 */
    517 				mutex_exit(&park->park_mtx);
    518 				mutex_enter(&pmp->pmp_lock);
    519 				mutex_enter(&park->park_mtx);
    520 
    521 				/* remove from queue1 */
    522 				if (park->park_flags & PARKFLAG_ONQUEUE1) {
    523 					TAILQ_REMOVE(&pmp->pmp_msg_touser,
    524 					    park, park_entries);
    525 					pmp->pmp_msg_touser_count--;
    526 					park->park_flags &= ~PARKFLAG_ONQUEUE1;
    527 				}
    528 
    529 				/*
    530 				 * If it's waiting for a response already,
    531 				 * boost reference count.  Park will get
    532 				 * nuked once the response arrives from
    533 				 * the file server.
    534 				 */
    535 				if (park->park_flags & PARKFLAG_ONQUEUE2)
    536 					puffs_msgpark_reference(park);
    537 
    538 				mutex_exit(&pmp->pmp_lock);
    539 
    540 				rv = error;
    541 			}
    542 		} else {
    543 			rv = preq->preq_rv;
    544 		}
    545 
    546 		/*
    547 		 * retake the lock and release.  This makes sure (haha,
    548 		 * I'm humorous) that we don't process the same vnode in
    549 		 * multiple threads due to the locks hacks we have in
    550 		 * puffs_lock().  In reality this is well protected by
    551 		 * the biglock, but once that's gone, well, hopefully
    552 		 * this will be fixed for real.  (and when you read this
    553 		 * comment in 2017 and subsequently barf, my condolences ;).
    554 		 */
    555 		if (rv == 0 && !fstrans_is_owner(mp)) {
    556 			fstrans_start(mp, FSTRANS_NORMAL);
    557 			fstrans_done(mp);
    558 		}
    559 	} else {
    560 		/*
    561 		 * Take extra reference for FAF, i.e. don't free us
    562 		 * immediately upon return to the caller, but rather
    563 		 * only when the message has been transported.
    564 		 */
    565 		puffs_msgpark_reference(park);
    566 	}
    567 
    568 	mutex_exit(&park->park_mtx);
    569 
    570 	mutex_enter(&pmp->pmp_lock);
    571 	puffs_mp_release(pmp);
    572 	mutex_exit(&pmp->pmp_lock);
    573 
    574 	return rv;
    575 }
    576 
    577 /*
    578  * Get next request in the outgoing queue.  "maxsize" controls the
    579  * size the caller can accommodate and "nonblock" signals if this
    580  * should block while waiting for input.  Handles all locking internally.
    581  */
    582 int
    583 puffs_msgif_getout(void *this, size_t maxsize, int nonblock,
    584 	uint8_t **data, size_t *dlen, void **parkptr)
    585 {
    586 	struct puffs_mount *pmp = this;
    587 	struct puffs_msgpark *park;
    588 	struct puffs_req *preq;
    589 	int error;
    590 
    591 	error = 0;
    592 	mutex_enter(&pmp->pmp_lock);
    593 	puffs_mp_reference(pmp);
    594 	for (;;) {
    595 		/* RIP? */
    596 		if (pmp->pmp_status != PUFFSTAT_RUNNING) {
    597 			error = ENXIO;
    598 			break;
    599 		}
    600 
    601 		/* need platinum yendorian express card? */
    602 		if (TAILQ_EMPTY(&pmp->pmp_msg_touser)) {
    603 			DPRINTF(("puffs_getout: no outgoing op, "));
    604 			if (nonblock) {
    605 				DPRINTF(("returning EWOULDBLOCK\n"));
    606 				error = EWOULDBLOCK;
    607 				break;
    608 			}
    609 			DPRINTF(("waiting ...\n"));
    610 
    611 			error = cv_wait_sig(&pmp->pmp_msg_waiter_cv,
    612 			    &pmp->pmp_lock);
    613 			if (error)
    614 				break;
    615 			else
    616 				continue;
    617 		}
    618 
    619 		park = TAILQ_FIRST(&pmp->pmp_msg_touser);
    620 		if (park == NULL)
    621 			continue;
    622 
    623 		mutex_enter(&park->park_mtx);
    624 		puffs_msgpark_reference(park);
    625 
    626 		DPRINTF(("puffs_getout: found park at %p, ", park));
    627 
    628 		/* If it's a goner, don't process any furher */
    629 		if (park->park_flags & PARKFLAG_WAITERGONE) {
    630 			DPRINTF(("waitergone!\n"));
    631 			puffs_msgpark_release(park);
    632 			continue;
    633 		}
    634 
    635 		/* check size */
    636 		preq = park->park_preq;
    637 		if (maxsize < preq->preq_frhdr.pfr_len) {
    638 			DPRINTF(("buffer too small\n"));
    639 			puffs_msgpark_release(park);
    640 			error = E2BIG;
    641 			break;
    642 		}
    643 
    644 		DPRINTF(("returning\n"));
    645 
    646 		/*
    647 		 * Ok, we found what we came for.  Release it from the
    648 		 * outgoing queue but do not unlock.  We will unlock
    649 		 * only after we "releaseout" it to avoid complications:
    650 		 * otherwise it is (theoretically) possible for userland
    651 		 * to race us into "put" before we have a change to put
    652 		 * this baby on the receiving queue.
    653 		 */
    654 		TAILQ_REMOVE(&pmp->pmp_msg_touser, park, park_entries);
    655 		KASSERT(park->park_flags & PARKFLAG_ONQUEUE1);
    656 		park->park_flags &= ~PARKFLAG_ONQUEUE1;
    657 		mutex_exit(&park->park_mtx);
    658 
    659 		pmp->pmp_msg_touser_count--;
    660 		KASSERT(pmp->pmp_msg_touser_count >= 0);
    661 
    662 		break;
    663 	}
    664 	puffs_mp_release(pmp);
    665 	mutex_exit(&pmp->pmp_lock);
    666 
    667 	if (error == 0) {
    668 		*data = (uint8_t *)preq;
    669 		preq->preq_frhdr.pfr_len = park->park_copylen;
    670 		preq->preq_frhdr.pfr_alloclen = park->park_maxlen;
    671 		preq->preq_frhdr.pfr_type = preq->preq_opclass; /* yay! */
    672 		*dlen = preq->preq_frhdr.pfr_len;
    673 		*parkptr = park;
    674 	}
    675 
    676 	return error;
    677 }
    678 
    679 /*
    680  * Release outgoing structure.  Now, depending on the success of the
    681  * outgoing send, it is either going onto the result waiting queue
    682  * or the death chamber.
    683  */
    684 void
    685 puffs_msgif_releaseout(void *this, void *parkptr, int status)
    686 {
    687 	struct puffs_mount *pmp = this;
    688 	struct puffs_msgpark *park = parkptr;
    689 
    690 	DPRINTF(("puffs_releaseout: returning park %p, errno %d: " ,
    691 	    park, status));
    692 	mutex_enter(&pmp->pmp_lock);
    693 	mutex_enter(&park->park_mtx);
    694 	if (park->park_flags & PARKFLAG_WANTREPLY) {
    695 		if (status == 0) {
    696 			DPRINTF(("enqueue replywait\n"));
    697 			TAILQ_INSERT_TAIL(&pmp->pmp_msg_replywait, park,
    698 			    park_entries);
    699 			park->park_flags |= PARKFLAG_ONQUEUE2;
    700 		} else {
    701 			DPRINTF(("error path!\n"));
    702 			park->park_preq->preq_rv = status;
    703 			park->park_flags |= PARKFLAG_DONE;
    704 			cv_signal(&park->park_cv);
    705 		}
    706 		puffs_msgpark_release(park);
    707 	} else {
    708 		DPRINTF(("release\n"));
    709 		puffs_msgpark_release1(park, 2);
    710 	}
    711 	mutex_exit(&pmp->pmp_lock);
    712 }
    713 
    714 /*
    715  * XXX: locking with this one?
    716  */
    717 void
    718 puffs_msgif_incoming(void *this, void *buf)
    719 {
    720 	struct puffs_mount *pmp = this;
    721 	struct puffs_req *preq = buf;
    722 	struct puffs_frame *pfr = &preq->preq_frhdr;
    723 	struct puffs_msgpark *park;
    724 	int release, wgone;
    725 
    726 	/* XXX */
    727 	if (PUFFSOP_OPCLASS(preq->preq_opclass) != PUFFSOP_VN
    728 	    && PUFFSOP_OPCLASS(preq->preq_opclass) != PUFFSOP_VFS)
    729 		return;
    730 
    731 	mutex_enter(&pmp->pmp_lock);
    732 
    733 	/* Locate waiter */
    734 	TAILQ_FOREACH(park, &pmp->pmp_msg_replywait, park_entries) {
    735 		if (park->park_preq->preq_id == preq->preq_id)
    736 			break;
    737 	}
    738 	if (park == NULL) {
    739 		DPRINTF(("puffs_msgif_income: no request: %" PRIu64 "\n",
    740 		    preq->preq_id));
    741 		mutex_exit(&pmp->pmp_lock);
    742 		return; /* XXX send error */
    743 	}
    744 
    745 	mutex_enter(&park->park_mtx);
    746 	puffs_msgpark_reference(park);
    747 	if (pfr->pfr_len > park->park_maxlen) {
    748 		DPRINTF(("puffs_msgif_income: invalid buffer length: "
    749 		    "%zu (req %" PRIu64 ", \n", pfr->pfr_len, preq->preq_id));
    750 		park->park_preq->preq_rv = EPROTO;
    751 		cv_signal(&park->park_cv);
    752 		puffs_msgpark_release(park);
    753 		mutex_exit(&pmp->pmp_lock);
    754 		return; /* XXX: error */
    755 	}
    756 	wgone = park->park_flags & PARKFLAG_WAITERGONE;
    757 
    758 	KASSERT(park->park_flags & PARKFLAG_ONQUEUE2);
    759 	TAILQ_REMOVE(&pmp->pmp_msg_replywait, park, park_entries);
    760 	park->park_flags &= ~PARKFLAG_ONQUEUE2;
    761 	mutex_exit(&pmp->pmp_lock);
    762 
    763 	if (wgone) {
    764 		DPRINTF(("puffs_putop: bad service - waiter gone for "
    765 		    "park %p\n", park));
    766 		release = 2;
    767 	} else {
    768 		if (park->park_flags & PARKFLAG_CALL) {
    769 			DPRINTF(("puffs_msgif_income: call for %p, arg %p\n",
    770 			    park->park_preq, park->park_donearg));
    771 			park->park_done(pmp, buf, park->park_donearg);
    772 			release = 2;
    773 		} else {
    774 			/* XXX: yes, I know */
    775 			memcpy(park->park_preq, buf, pfr->pfr_len);
    776 			release = 1;
    777 		}
    778 	}
    779 
    780 	if (!wgone) {
    781 		DPRINTF(("puffs_putop: flagging done for "
    782 		    "park %p\n", park));
    783 		cv_signal(&park->park_cv);
    784 	}
    785 
    786 	park->park_flags |= PARKFLAG_DONE;
    787 	puffs_msgpark_release1(park, release);
    788 }
    789 
    790 /*
    791  * We're dead, kaput, RIP, slightly more than merely pining for the
    792  * fjords, belly-up, fallen, lifeless, finished, expired, gone to meet
    793  * our maker, ceased to be, etcetc.  YASD.  It's a dead FS!
    794  *
    795  * Caller must hold puffs mutex.
    796  */
    797 void
    798 puffs_userdead(struct puffs_mount *pmp)
    799 {
    800 	struct puffs_msgpark *park, *park_next;
    801 
    802 	/*
    803 	 * Mark filesystem status as dying so that operations don't
    804 	 * attempt to march to userspace any longer.
    805 	 */
    806 	pmp->pmp_status = PUFFSTAT_DYING;
    807 
    808 	/* signal waiters on REQUEST TO file server queue */
    809 	for (park = TAILQ_FIRST(&pmp->pmp_msg_touser); park; park = park_next) {
    810 		uint8_t opclass;
    811 
    812 		mutex_enter(&park->park_mtx);
    813 		puffs_msgpark_reference(park);
    814 		park_next = TAILQ_NEXT(park, park_entries);
    815 
    816 		KASSERT(park->park_flags & PARKFLAG_ONQUEUE1);
    817 		TAILQ_REMOVE(&pmp->pmp_msg_touser, park, park_entries);
    818 		park->park_flags &= ~PARKFLAG_ONQUEUE1;
    819 		pmp->pmp_msg_touser_count--;
    820 
    821 		/*
    822 		 * If the waiter is gone, we may *NOT* access preq anymore.
    823 		 */
    824 		if (park->park_flags & PARKFLAG_WAITERGONE) {
    825 			KASSERT((park->park_flags & PARKFLAG_CALL) == 0);
    826 			KASSERT(park->park_flags & PARKFLAG_WANTREPLY);
    827 			puffs_msgpark_release(park);
    828 		} else {
    829 			opclass = park->park_preq->preq_opclass;
    830 			park->park_preq->preq_rv = ENXIO;
    831 
    832 			if (park->park_flags & PARKFLAG_CALL) {
    833 				park->park_done(pmp, park->park_preq,
    834 				    park->park_donearg);
    835 				puffs_msgpark_release1(park, 2);
    836 			} else if ((park->park_flags & PARKFLAG_WANTREPLY)==0) {
    837 				puffs_msgpark_release1(park, 2);
    838 			} else {
    839 				park->park_preq->preq_rv = ENXIO;
    840 				cv_signal(&park->park_cv);
    841 				puffs_msgpark_release(park);
    842 			}
    843 		}
    844 	}
    845 
    846 	/* signal waiters on RESPONSE FROM file server queue */
    847 	for (park=TAILQ_FIRST(&pmp->pmp_msg_replywait); park; park=park_next) {
    848 		mutex_enter(&park->park_mtx);
    849 		puffs_msgpark_reference(park);
    850 		park_next = TAILQ_NEXT(park, park_entries);
    851 
    852 		KASSERT(park->park_flags & PARKFLAG_ONQUEUE2);
    853 		KASSERT(park->park_flags & PARKFLAG_WANTREPLY);
    854 
    855 		TAILQ_REMOVE(&pmp->pmp_msg_replywait, park, park_entries);
    856 		park->park_flags &= ~PARKFLAG_ONQUEUE2;
    857 
    858 		/*
    859 		 * If the waiter is gone, we may *NOT* access preq anymore.
    860 		 */
    861 		if (park->park_flags & PARKFLAG_WAITERGONE) {
    862 			KASSERT((park->park_flags & PARKFLAG_CALL) == 0);
    863 			puffs_msgpark_release(park);
    864 		} else {
    865 			park->park_preq->preq_rv = ENXIO;
    866 			if (park->park_flags & PARKFLAG_CALL) {
    867 				park->park_done(pmp, park->park_preq,
    868 				    park->park_donearg);
    869 				puffs_msgpark_release1(park, 2);
    870 			} else {
    871 				cv_signal(&park->park_cv);
    872 				puffs_msgpark_release(park);
    873 			}
    874 		}
    875 	}
    876 
    877 	cv_broadcast(&pmp->pmp_msg_waiter_cv);
    878 }
    879