Home | History | Annotate | Line # | Download | only in puffs
puffs_msgif.c revision 1.72.12.1
      1  1.72.12.1   matt /*	$NetBSD: puffs_msgif.c,v 1.72.12.1 2010/04/21 00:28:13 matt Exp $	*/
      2        1.1  pooka 
      3        1.1  pooka /*
      4       1.16  pooka  * Copyright (c) 2005, 2006, 2007  Antti Kantee.  All Rights Reserved.
      5        1.1  pooka  *
      6        1.1  pooka  * Development of this software was supported by the
      7        1.1  pooka  * Google Summer of Code program and the Ulla Tuominen Foundation.
      8        1.1  pooka  * The Google SoC project was mentored by Bill Studenmund.
      9        1.1  pooka  *
     10        1.1  pooka  * Redistribution and use in source and binary forms, with or without
     11        1.1  pooka  * modification, are permitted provided that the following conditions
     12        1.1  pooka  * are met:
     13        1.1  pooka  * 1. Redistributions of source code must retain the above copyright
     14        1.1  pooka  *    notice, this list of conditions and the following disclaimer.
     15        1.1  pooka  * 2. Redistributions in binary form must reproduce the above copyright
     16        1.1  pooka  *    notice, this list of conditions and the following disclaimer in the
     17        1.1  pooka  *    documentation and/or other materials provided with the distribution.
     18        1.1  pooka  *
     19        1.1  pooka  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
     20        1.1  pooka  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
     21        1.1  pooka  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
     22        1.1  pooka  * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
     23        1.1  pooka  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     24        1.1  pooka  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
     25        1.1  pooka  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     26        1.1  pooka  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     27        1.1  pooka  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     28        1.1  pooka  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     29        1.1  pooka  * SUCH DAMAGE.
     30        1.1  pooka  */
     31        1.1  pooka 
     32        1.1  pooka #include <sys/cdefs.h>
     33  1.72.12.1   matt __KERNEL_RCSID(0, "$NetBSD: puffs_msgif.c,v 1.72.12.1 2010/04/21 00:28:13 matt Exp $");
     34        1.1  pooka 
     35        1.1  pooka #include <sys/param.h>
     36       1.68    tnn #include <sys/atomic.h>
     37       1.16  pooka #include <sys/fstrans.h>
     38       1.46  pooka #include <sys/kmem.h>
     39       1.53  pooka #include <sys/kthread.h>
     40       1.53  pooka #include <sys/lock.h>
     41        1.1  pooka #include <sys/malloc.h>
     42        1.1  pooka #include <sys/mount.h>
     43       1.53  pooka #include <sys/namei.h>
     44       1.53  pooka #include <sys/proc.h>
     45        1.1  pooka #include <sys/vnode.h>
     46       1.71     ad #include <sys/atomic.h>
     47       1.53  pooka 
     48       1.55  pooka #include <dev/putter/putter_sys.h>
     49        1.1  pooka 
     50        1.1  pooka #include <fs/puffs/puffs_msgif.h>
     51        1.1  pooka #include <fs/puffs/puffs_sys.h>
     52        1.1  pooka 
     53       1.53  pooka #include <miscfs/syncfs/syncfs.h> /* XXX: for syncer_mutex reference */
     54       1.53  pooka 
     55       1.22  pooka /*
     56       1.22  pooka  * waitq data structures
     57       1.22  pooka  */
     58       1.22  pooka 
     59       1.22  pooka /*
     60       1.22  pooka  * While a request is going to userspace, park the caller within the
     61       1.22  pooka  * kernel.  This is the kernel counterpart of "struct puffs_req".
     62       1.22  pooka  */
     63       1.46  pooka struct puffs_msgpark {
     64       1.22  pooka 	struct puffs_req	*park_preq;	/* req followed by buf	*/
     65       1.22  pooka 
     66       1.22  pooka 	size_t			park_copylen;	/* userspace copylength	*/
     67       1.22  pooka 	size_t			park_maxlen;	/* max size in comeback */
     68       1.24  pooka 
     69       1.46  pooka 	parkdone_fn		park_done;	/* "biodone" a'la puffs	*/
     70       1.24  pooka 	void			*park_donearg;
     71       1.22  pooka 
     72       1.22  pooka 	int			park_flags;
     73       1.26  pooka 	int			park_refcount;
     74       1.22  pooka 
     75       1.22  pooka 	kcondvar_t		park_cv;
     76       1.26  pooka 	kmutex_t		park_mtx;
     77       1.26  pooka 
     78       1.46  pooka 	TAILQ_ENTRY(puffs_msgpark) park_entries;
     79       1.22  pooka };
     80       1.22  pooka #define PARKFLAG_WAITERGONE	0x01
     81       1.26  pooka #define PARKFLAG_DONE		0x02
     82       1.26  pooka #define PARKFLAG_ONQUEUE1	0x04
     83       1.26  pooka #define PARKFLAG_ONQUEUE2	0x08
     84       1.26  pooka #define PARKFLAG_CALL		0x10
     85       1.31  pooka #define PARKFLAG_WANTREPLY	0x20
     86       1.57  pooka #define	PARKFLAG_HASERROR	0x40
     87       1.22  pooka 
     88       1.52     ad static pool_cache_t parkpc;
     89       1.57  pooka #ifdef PUFFSDEBUG
     90       1.57  pooka static int totalpark;
     91       1.57  pooka #endif
     92       1.22  pooka 
     93       1.22  pooka static int
     94       1.22  pooka makepark(void *arg, void *obj, int flags)
     95       1.22  pooka {
     96       1.46  pooka 	struct puffs_msgpark *park = obj;
     97       1.22  pooka 
     98       1.26  pooka 	mutex_init(&park->park_mtx, MUTEX_DEFAULT, IPL_NONE);
     99       1.22  pooka 	cv_init(&park->park_cv, "puffsrpl");
    100       1.22  pooka 
    101       1.22  pooka 	return 0;
    102       1.22  pooka }
    103       1.22  pooka 
    104       1.22  pooka static void
    105       1.22  pooka nukepark(void *arg, void *obj)
    106       1.22  pooka {
    107       1.46  pooka 	struct puffs_msgpark *park = obj;
    108       1.22  pooka 
    109       1.22  pooka 	cv_destroy(&park->park_cv);
    110       1.26  pooka 	mutex_destroy(&park->park_mtx);
    111       1.22  pooka }
    112       1.22  pooka 
    113       1.22  pooka void
    114       1.22  pooka puffs_msgif_init()
    115       1.22  pooka {
    116       1.22  pooka 
    117       1.52     ad 	parkpc = pool_cache_init(sizeof(struct puffs_msgpark), 0, 0, 0,
    118       1.52     ad 	    "puffprkl", NULL, IPL_NONE, makepark, nukepark, NULL);
    119       1.22  pooka }
    120       1.22  pooka 
    121       1.22  pooka void
    122       1.22  pooka puffs_msgif_destroy()
    123       1.22  pooka {
    124       1.22  pooka 
    125       1.52     ad 	pool_cache_destroy(parkpc);
    126       1.22  pooka }
    127       1.22  pooka 
    128       1.46  pooka static int alloced;
    129       1.46  pooka 
    130       1.46  pooka static struct puffs_msgpark *
    131       1.46  pooka puffs_msgpark_alloc(int waitok)
    132       1.26  pooka {
    133       1.46  pooka 	struct puffs_msgpark *park;
    134       1.26  pooka 
    135       1.52     ad 	park = pool_cache_get(parkpc, waitok ? PR_WAITOK : PR_NOWAIT);
    136       1.46  pooka 	if (park == NULL)
    137       1.46  pooka 		return park;
    138       1.46  pooka 
    139       1.46  pooka 	park->park_refcount = 1;
    140       1.46  pooka 	park->park_preq = NULL;
    141       1.46  pooka 	park->park_flags = PARKFLAG_WANTREPLY;
    142       1.26  pooka 
    143       1.57  pooka #ifdef PUFFSDEBUG
    144       1.57  pooka 	totalpark++;
    145       1.57  pooka #endif
    146       1.57  pooka 
    147       1.26  pooka 	return park;
    148       1.26  pooka }
    149       1.26  pooka 
    150       1.26  pooka static void
    151       1.46  pooka puffs_msgpark_reference(struct puffs_msgpark *park)
    152       1.22  pooka {
    153       1.22  pooka 
    154       1.46  pooka 	KASSERT(mutex_owned(&park->park_mtx));
    155       1.26  pooka 	park->park_refcount++;
    156       1.22  pooka }
    157       1.22  pooka 
    158       1.46  pooka /*
    159       1.46  pooka  * Release reference to park structure.
    160       1.46  pooka  */
    161       1.46  pooka static void
    162       1.46  pooka puffs_msgpark_release1(struct puffs_msgpark *park, int howmany)
    163       1.22  pooka {
    164       1.46  pooka 	struct puffs_req *preq = park->park_preq;
    165       1.46  pooka 	int refcnt;
    166       1.22  pooka 
    167       1.26  pooka 	KASSERT(mutex_owned(&park->park_mtx));
    168       1.46  pooka 	refcnt = park->park_refcount -= howmany;
    169       1.46  pooka 	mutex_exit(&park->park_mtx);
    170       1.46  pooka 
    171       1.46  pooka 	KASSERT(refcnt >= 0);
    172       1.26  pooka 
    173       1.46  pooka 	if (refcnt == 0) {
    174       1.46  pooka 		alloced--;
    175       1.46  pooka 		if (preq)
    176       1.46  pooka 			kmem_free(preq, park->park_maxlen);
    177       1.52     ad 		pool_cache_put(parkpc, park);
    178       1.57  pooka 
    179       1.57  pooka #ifdef PUFFSDEBUG
    180       1.57  pooka 		totalpark--;
    181       1.57  pooka #endif
    182       1.46  pooka 	}
    183       1.22  pooka }
    184       1.46  pooka #define puffs_msgpark_release(a) puffs_msgpark_release1(a, 1)
    185       1.22  pooka 
    186       1.26  pooka #ifdef PUFFSDEBUG
    187       1.26  pooka static void
    188       1.46  pooka parkdump(struct puffs_msgpark *park)
    189       1.26  pooka {
    190       1.26  pooka 
    191       1.26  pooka 	DPRINTF(("park %p, preq %p, id %" PRIu64 "\n"
    192       1.26  pooka 	    "\tcopy %zu, max %zu - done: %p/%p\n"
    193       1.26  pooka 	    "\tflags 0x%08x, refcount %d, cv/mtx: %p/%p\n",
    194       1.46  pooka 	    park, park->park_preq, park->park_preq->preq_id,
    195       1.26  pooka 	    park->park_copylen, park->park_maxlen,
    196       1.26  pooka 	    park->park_done, park->park_donearg,
    197       1.26  pooka 	    park->park_flags, park->park_refcount,
    198       1.26  pooka 	    &park->park_cv, &park->park_mtx));
    199       1.26  pooka }
    200       1.26  pooka 
    201       1.26  pooka static void
    202       1.26  pooka parkqdump(struct puffs_wq *q, int dumpall)
    203       1.26  pooka {
    204       1.46  pooka 	struct puffs_msgpark *park;
    205       1.26  pooka 	int total = 0;
    206       1.26  pooka 
    207       1.26  pooka 	TAILQ_FOREACH(park, q, park_entries) {
    208       1.26  pooka 		if (dumpall)
    209       1.26  pooka 			parkdump(park);
    210       1.26  pooka 		total++;
    211       1.26  pooka 	}
    212       1.29  pooka 	DPRINTF(("puffs waitqueue at %p dumped, %d total\n", q, total));
    213       1.26  pooka 
    214       1.26  pooka }
    215       1.26  pooka #endif /* PUFFSDEBUG */
    216       1.22  pooka 
    217       1.22  pooka /*
    218       1.46  pooka  * A word about locking in the park structures: the lock protects the
    219       1.46  pooka  * fields of the *park* structure (not preq) and acts as an interlock
    220       1.46  pooka  * in cv operations.  The lock is always internal to this module and
    221       1.46  pooka  * callers do not need to worry about it.
    222       1.22  pooka  */
    223       1.46  pooka 
    224       1.46  pooka int
    225       1.46  pooka puffs_msgmem_alloc(size_t len, struct puffs_msgpark **ppark, void **mem,
    226       1.46  pooka 	int cansleep)
    227       1.46  pooka {
    228       1.46  pooka 	struct puffs_msgpark *park;
    229       1.46  pooka 	void *m;
    230       1.46  pooka 
    231       1.46  pooka 	m = kmem_zalloc(len, cansleep ? KM_SLEEP : KM_NOSLEEP);
    232       1.46  pooka 	if (m == NULL) {
    233       1.46  pooka 		KASSERT(cansleep == 0);
    234       1.46  pooka 		return ENOMEM;
    235       1.46  pooka 	}
    236       1.46  pooka 
    237       1.46  pooka 	park = puffs_msgpark_alloc(cansleep);
    238       1.46  pooka 	if (park == NULL) {
    239       1.46  pooka 		KASSERT(cansleep == 0);
    240       1.46  pooka 		kmem_free(m, len);
    241       1.46  pooka 		return ENOMEM;
    242       1.46  pooka 	}
    243       1.46  pooka 
    244       1.46  pooka 	park->park_preq = m;
    245       1.57  pooka 	park->park_maxlen = park->park_copylen = len;
    246       1.46  pooka 
    247       1.46  pooka 	*ppark = park;
    248       1.46  pooka 	*mem = m;
    249       1.46  pooka 
    250       1.46  pooka 	return 0;
    251       1.46  pooka }
    252       1.46  pooka 
    253       1.46  pooka void
    254       1.46  pooka puffs_msgmem_release(struct puffs_msgpark *park)
    255       1.22  pooka {
    256       1.22  pooka 
    257       1.46  pooka 	if (park == NULL)
    258       1.46  pooka 		return;
    259       1.22  pooka 
    260       1.46  pooka 	mutex_enter(&park->park_mtx);
    261       1.46  pooka 	puffs_msgpark_release(park);
    262       1.46  pooka }
    263       1.22  pooka 
    264       1.46  pooka void
    265       1.46  pooka puffs_msg_setfaf(struct puffs_msgpark *park)
    266       1.46  pooka {
    267       1.22  pooka 
    268       1.57  pooka 	KASSERT((park->park_flags & PARKFLAG_CALL) == 0);
    269       1.36  pooka 	park->park_flags &= ~PARKFLAG_WANTREPLY;
    270       1.22  pooka }
    271       1.22  pooka 
    272       1.57  pooka void
    273       1.57  pooka puffs_msg_setdelta(struct puffs_msgpark *park, size_t delta)
    274        1.1  pooka {
    275        1.1  pooka 
    276       1.57  pooka 	KASSERT(delta < park->park_maxlen); /* "<=" wouldn't make sense */
    277       1.57  pooka 	park->park_copylen = park->park_maxlen - delta;
    278        1.1  pooka }
    279        1.1  pooka 
    280       1.57  pooka void
    281       1.64  pooka puffs_msg_setinfo(struct puffs_msgpark *park, int class, int type,
    282       1.64  pooka 	puffs_cookie_t ck)
    283        1.1  pooka {
    284        1.1  pooka 
    285       1.57  pooka 	park->park_preq->preq_opclass = PUFFSOP_OPCLASS(class);
    286       1.57  pooka 	park->park_preq->preq_optype = type;
    287       1.64  pooka 	park->park_preq->preq_cookie = ck;
    288        1.1  pooka }
    289        1.1  pooka 
    290       1.24  pooka void
    291       1.57  pooka puffs_msg_setcall(struct puffs_msgpark *park, parkdone_fn donefn, void *donearg)
    292        1.1  pooka {
    293       1.25  pooka 
    294       1.57  pooka 	KASSERT(park->park_flags & PARKFLAG_WANTREPLY);
    295       1.25  pooka 	park->park_done = donefn;
    296       1.25  pooka 	park->park_donearg = donearg;
    297       1.46  pooka 	park->park_flags |= PARKFLAG_CALL;
    298       1.20  pooka }
    299       1.20  pooka 
    300       1.57  pooka /*
    301       1.57  pooka  * kernel-user-kernel waitqueues
    302       1.57  pooka  */
    303        1.4  pooka 
    304       1.57  pooka static uint64_t
    305       1.57  pooka puffs_getmsgid(struct puffs_mount *pmp)
    306       1.41  pooka {
    307       1.57  pooka 	uint64_t rv;
    308       1.41  pooka 
    309       1.57  pooka 	mutex_enter(&pmp->pmp_lock);
    310       1.57  pooka 	rv = pmp->pmp_nextmsgid++;
    311       1.57  pooka 	mutex_exit(&pmp->pmp_lock);
    312       1.41  pooka 
    313       1.57  pooka 	return rv;
    314       1.41  pooka }
    315       1.41  pooka 
    316        1.4  pooka /*
    317       1.57  pooka  * A word about reference counting of parks.  A reference must be taken
    318       1.57  pooka  * when accessing a park and additionally when it is on a queue.  So
    319       1.57  pooka  * when taking it off a queue and releasing the access reference, the
    320       1.57  pooka  * reference count is generally decremented by 2.
    321        1.1  pooka  */
    322       1.57  pooka 
    323       1.57  pooka void
    324       1.57  pooka puffs_msg_enqueue(struct puffs_mount *pmp, struct puffs_msgpark *park)
    325        1.1  pooka {
    326       1.26  pooka 	struct lwp *l = curlwp;
    327       1.16  pooka 	struct mount *mp;
    328        1.9  pooka 	struct puffs_req *preq;
    329        1.1  pooka 
    330       1.16  pooka 	mp = PMPTOMP(pmp);
    331       1.25  pooka 	preq = park->park_preq;
    332       1.46  pooka 	preq->preq_buflen = park->park_maxlen;
    333       1.61  pooka 	KASSERT(preq->preq_id == 0
    334       1.61  pooka 	    || (preq->preq_opclass & PUFFSOPFLAG_ISRESPONSE));
    335       1.46  pooka 
    336       1.46  pooka 	if ((park->park_flags & PARKFLAG_WANTREPLY) == 0)
    337       1.46  pooka 		preq->preq_opclass |= PUFFSOPFLAG_FAF;
    338       1.46  pooka 	else
    339       1.46  pooka 		preq->preq_id = puffs_getmsgid(pmp);
    340       1.31  pooka 
    341       1.49  pooka 	/* fill in caller information */
    342       1.49  pooka 	preq->preq_pid = l->l_proc->p_pid;
    343       1.49  pooka 	preq->preq_lid = l->l_lid;
    344       1.49  pooka 
    345       1.19  pooka 	/*
    346       1.51  pooka 	 * To support cv_sig, yet another movie: check if there are signals
    347       1.19  pooka 	 * pending and we are issueing a non-FAF.  If so, return an error
    348       1.57  pooka 	 * directly UNLESS we are issueing INACTIVE/RECLAIM.  In that case,
    349       1.57  pooka 	 * convert it to a FAF, fire off to the file server and return
    350       1.57  pooka 	 * an error.  Yes, this is bordering disgusting.  Barfbags are on me.
    351       1.19  pooka 	 */
    352       1.57  pooka 	if (__predict_false((park->park_flags & PARKFLAG_WANTREPLY)
    353       1.25  pooka 	   && (park->park_flags & PARKFLAG_CALL) == 0
    354       1.57  pooka 	   && (l->l_flag & LW_PENDSIG) != 0 && sigispending(l, 0))) {
    355       1.57  pooka 		park->park_flags |= PARKFLAG_HASERROR;
    356       1.57  pooka 		preq->preq_rv = EINTR;
    357       1.19  pooka 		if (PUFFSOP_OPCLASS(preq->preq_opclass) == PUFFSOP_VN
    358       1.57  pooka 		    && (preq->preq_optype == PUFFS_VN_INACTIVE
    359       1.57  pooka 		     || preq->preq_optype == PUFFS_VN_RECLAIM)) {
    360       1.46  pooka 			park->park_preq->preq_opclass |= PUFFSOPFLAG_FAF;
    361       1.46  pooka 			park->park_flags &= ~PARKFLAG_WANTREPLY;
    362       1.57  pooka 			DPRINTF(("puffs_msg_enqueue: converted to FAF %p\n",
    363       1.57  pooka 			    park));
    364       1.19  pooka 		} else {
    365       1.57  pooka 			return;
    366       1.19  pooka 		}
    367       1.19  pooka 	}
    368       1.16  pooka 
    369       1.16  pooka 	/*
    370       1.16  pooka 	 * test for suspension lock.
    371       1.16  pooka 	 *
    372       1.16  pooka 	 * Note that we *DO NOT* keep the lock, since that might block
    373       1.16  pooka 	 * lock acquiring PLUS it would give userlandia control over
    374       1.16  pooka 	 * the lock.  The operation queue enforces a strict ordering:
    375       1.16  pooka 	 * when the fs server gets in the op stream, it knows things
    376       1.16  pooka 	 * are in order.  The kernel locks can't guarantee that for
    377       1.16  pooka 	 * userspace, in any case.
    378       1.16  pooka 	 *
    379       1.16  pooka 	 * BUT: this presents a problem for ops which have a consistency
    380       1.16  pooka 	 * clause based on more than one operation.  Unfortunately such
    381       1.16  pooka 	 * operations (read, write) do not reliably work yet.
    382       1.16  pooka 	 *
    383       1.16  pooka 	 * Ya, Ya, it's wrong wong wrong, me be fixink this someday.
    384       1.18  pooka 	 *
    385       1.18  pooka 	 * XXX: and there is one more problem.  We sometimes need to
    386       1.18  pooka 	 * take a lazy lock in case the fs is suspending and we are
    387       1.18  pooka 	 * executing as the fs server context.  This might happen
    388       1.18  pooka 	 * e.g. in the case that the user server triggers a reclaim
    389       1.18  pooka 	 * in the kernel while the fs is suspending.  It's not a very
    390       1.18  pooka 	 * likely event, but it needs to be fixed some day.
    391       1.16  pooka 	 */
    392       1.22  pooka 
    393       1.22  pooka 	/*
    394       1.22  pooka 	 * MOREXXX: once PUFFS_WCACHEINFO is enabled, we can't take
    395       1.22  pooka 	 * the mutex here, since getpages() might be called locked.
    396       1.22  pooka 	 */
    397       1.18  pooka 	fstrans_start(mp, FSTRANS_NORMAL);
    398       1.22  pooka 	mutex_enter(&pmp->pmp_lock);
    399       1.16  pooka 	fstrans_done(mp);
    400       1.16  pooka 
    401       1.13  pooka 	if (pmp->pmp_status != PUFFSTAT_RUNNING) {
    402       1.22  pooka 		mutex_exit(&pmp->pmp_lock);
    403       1.57  pooka 		park->park_flags |= PARKFLAG_HASERROR;
    404       1.57  pooka 		preq->preq_rv = ENXIO;
    405       1.57  pooka 		return;
    406        1.1  pooka 	}
    407        1.1  pooka 
    408       1.26  pooka #ifdef PUFFSDEBUG
    409       1.46  pooka 	parkqdump(&pmp->pmp_msg_touser, puffsdebug > 1);
    410       1.46  pooka 	parkqdump(&pmp->pmp_msg_replywait, puffsdebug > 1);
    411       1.26  pooka #endif
    412       1.26  pooka 
    413       1.57  pooka 	/*
    414       1.57  pooka 	 * Note: we don't need to lock park since we have the only
    415       1.57  pooka 	 * reference to it at this point.
    416       1.57  pooka 	 */
    417       1.46  pooka 	TAILQ_INSERT_TAIL(&pmp->pmp_msg_touser, park, park_entries);
    418       1.26  pooka 	park->park_flags |= PARKFLAG_ONQUEUE1;
    419       1.46  pooka 	pmp->pmp_msg_touser_count++;
    420       1.57  pooka 	park->park_refcount++;
    421       1.26  pooka 	mutex_exit(&pmp->pmp_lock);
    422        1.1  pooka 
    423       1.57  pooka 	cv_broadcast(&pmp->pmp_msg_waiter_cv);
    424       1.57  pooka 	putter_notify(pmp->pmp_pi);
    425       1.57  pooka 
    426       1.20  pooka 	DPRINTF(("touser: req %" PRIu64 ", preq: %p, park: %p, "
    427       1.25  pooka 	    "c/t: 0x%x/0x%x, f: 0x%x\n", preq->preq_id, preq, park,
    428       1.25  pooka 	    preq->preq_opclass, preq->preq_optype, park->park_flags));
    429       1.57  pooka }
    430       1.15  pooka 
    431       1.57  pooka int
    432       1.57  pooka puffs_msg_wait(struct puffs_mount *pmp, struct puffs_msgpark *park)
    433       1.57  pooka {
    434       1.57  pooka 	struct puffs_req *preq = park->park_preq; /* XXX: hmmm */
    435       1.57  pooka 	struct mount *mp = PMPTOMP(pmp);
    436       1.57  pooka 	int error = 0;
    437       1.57  pooka 	int rv;
    438        1.1  pooka 
    439       1.57  pooka 	mutex_enter(&pmp->pmp_lock);
    440       1.57  pooka 	puffs_mp_reference(pmp);
    441       1.57  pooka 	mutex_exit(&pmp->pmp_lock);
    442       1.46  pooka 
    443       1.57  pooka 	mutex_enter(&park->park_mtx);
    444       1.57  pooka 	if ((park->park_flags & PARKFLAG_WANTREPLY) == 0
    445       1.57  pooka 	    || (park->park_flags & PARKFLAG_CALL)) {
    446       1.57  pooka 		mutex_exit(&park->park_mtx);
    447       1.57  pooka 		rv = 0;
    448       1.57  pooka 		goto skipwait;
    449       1.57  pooka 	}
    450       1.46  pooka 
    451       1.57  pooka 	/* did the response beat us to the wait? */
    452       1.57  pooka 	if (__predict_false((park->park_flags & PARKFLAG_DONE)
    453       1.57  pooka 	    || (park->park_flags & PARKFLAG_HASERROR))) {
    454       1.57  pooka 		rv = park->park_preq->preq_rv;
    455       1.57  pooka 		mutex_exit(&park->park_mtx);
    456       1.57  pooka 		goto skipwait;
    457       1.57  pooka 	}
    458       1.26  pooka 
    459       1.57  pooka 	error = cv_wait_sig(&park->park_cv, &park->park_mtx);
    460       1.57  pooka 	DPRINTF(("puffs_touser: waiter for %p woke up with %d\n",
    461       1.57  pooka 	    park, error));
    462       1.57  pooka 	if (error) {
    463       1.57  pooka 		park->park_flags |= PARKFLAG_WAITERGONE;
    464       1.57  pooka 		if (park->park_flags & PARKFLAG_DONE) {
    465       1.57  pooka 			rv = preq->preq_rv;
    466       1.57  pooka 			mutex_exit(&park->park_mtx);
    467       1.57  pooka 		} else {
    468       1.57  pooka 			/*
    469       1.57  pooka 			 * ok, we marked it as going away, but
    470       1.57  pooka 			 * still need to do queue ops.  take locks
    471       1.57  pooka 			 * in correct order.
    472       1.57  pooka 			 *
    473       1.57  pooka 			 * We don't want to release our reference
    474       1.57  pooka 			 * if it's on replywait queue to avoid error
    475       1.57  pooka 			 * to file server.  putop() code will DTRT.
    476       1.57  pooka 			 */
    477       1.57  pooka 			mutex_exit(&park->park_mtx);
    478       1.57  pooka 			mutex_enter(&pmp->pmp_lock);
    479       1.57  pooka 			mutex_enter(&park->park_mtx);
    480       1.57  pooka 
    481       1.57  pooka 			/*
    482       1.57  pooka 			 * Still on queue1?  We can safely remove it
    483       1.57  pooka 			 * without any consequences since the file
    484       1.57  pooka 			 * server hasn't seen it.  "else" we need to
    485       1.57  pooka 			 * wait for the response and just ignore it
    486       1.57  pooka 			 * to avoid signalling an incorrect error to
    487       1.57  pooka 			 * the file server.
    488       1.57  pooka 			 */
    489       1.57  pooka 			if (park->park_flags & PARKFLAG_ONQUEUE1) {
    490       1.57  pooka 				TAILQ_REMOVE(&pmp->pmp_msg_touser,
    491       1.57  pooka 				    park, park_entries);
    492       1.57  pooka 				puffs_msgpark_release(park);
    493       1.57  pooka 				pmp->pmp_msg_touser_count--;
    494       1.57  pooka 				park->park_flags &= ~PARKFLAG_ONQUEUE1;
    495       1.57  pooka 			} else {
    496       1.57  pooka 				mutex_exit(&park->park_mtx);
    497       1.19  pooka 			}
    498       1.57  pooka 			mutex_exit(&pmp->pmp_lock);
    499       1.22  pooka 
    500       1.60  pooka 			rv = EINTR;
    501       1.16  pooka 		}
    502       1.22  pooka 	} else {
    503       1.57  pooka 		rv = preq->preq_rv;
    504       1.57  pooka 		mutex_exit(&park->park_mtx);
    505       1.16  pooka 	}
    506       1.16  pooka 
    507       1.57  pooka 	/*
    508       1.57  pooka 	 * retake the lock and release.  This makes sure (haha,
    509       1.57  pooka 	 * I'm humorous) that we don't process the same vnode in
    510       1.57  pooka 	 * multiple threads due to the locks hacks we have in
    511       1.57  pooka 	 * puffs_lock().  In reality this is well protected by
    512       1.57  pooka 	 * the biglock, but once that's gone, well, hopefully
    513       1.57  pooka 	 * this will be fixed for real.  (and when you read this
    514       1.57  pooka 	 * comment in 2017 and subsequently barf, my condolences ;).
    515       1.57  pooka 	 */
    516       1.57  pooka 	if (rv == 0 && !fstrans_is_owner(mp)) {
    517       1.57  pooka 		fstrans_start(mp, FSTRANS_NORMAL);
    518       1.57  pooka 		fstrans_done(mp);
    519       1.57  pooka 	}
    520       1.46  pooka 
    521       1.57  pooka  skipwait:
    522       1.22  pooka 	mutex_enter(&pmp->pmp_lock);
    523       1.34  pooka 	puffs_mp_release(pmp);
    524       1.22  pooka 	mutex_exit(&pmp->pmp_lock);
    525       1.16  pooka 
    526       1.19  pooka 	return rv;
    527        1.1  pooka }
    528        1.1  pooka 
    529        1.9  pooka /*
    530       1.57  pooka  * XXX: this suuuucks.  Hopefully I'll get rid of this lossage once
    531       1.57  pooka  * the whole setback-nonsense gets fixed.
    532       1.57  pooka  */
    533       1.57  pooka int
    534       1.57  pooka puffs_msg_wait2(struct puffs_mount *pmp, struct puffs_msgpark *park,
    535       1.57  pooka 	struct puffs_node *pn1, struct puffs_node *pn2)
    536       1.57  pooka {
    537       1.57  pooka 	struct puffs_req *preq;
    538       1.57  pooka 	int rv;
    539       1.57  pooka 
    540       1.57  pooka 	rv = puffs_msg_wait(pmp, park);
    541       1.57  pooka 
    542       1.57  pooka 	preq = park->park_preq;
    543       1.57  pooka 	if (pn1 && preq->preq_setbacks & PUFFS_SETBACK_INACT_N1)
    544       1.57  pooka 		pn1->pn_stat |= PNODE_DOINACT;
    545       1.57  pooka 	if (pn2 && preq->preq_setbacks & PUFFS_SETBACK_INACT_N2)
    546       1.57  pooka 		pn2->pn_stat |= PNODE_DOINACT;
    547       1.57  pooka 
    548       1.57  pooka 	if (pn1 && preq->preq_setbacks & PUFFS_SETBACK_NOREF_N1)
    549       1.57  pooka 		pn1->pn_stat |= PNODE_NOREFS;
    550       1.57  pooka 	if (pn2 && preq->preq_setbacks & PUFFS_SETBACK_NOREF_N2)
    551       1.57  pooka 		pn2->pn_stat |= PNODE_NOREFS;
    552       1.57  pooka 
    553       1.57  pooka 	return rv;
    554       1.57  pooka 
    555       1.57  pooka }
    556       1.57  pooka 
    557       1.57  pooka /*
    558       1.61  pooka  * XXX: lazy bum.  please, for the love of foie gras, fix me.
    559       1.61  pooka  * This should *NOT* depend on setfaf.  Also "memcpy" could
    560       1.61  pooka  * be done more nicely.
    561       1.61  pooka  */
    562       1.61  pooka void
    563       1.61  pooka puffs_msg_sendresp(struct puffs_mount *pmp, struct puffs_req *origpreq, int rv)
    564       1.61  pooka {
    565       1.61  pooka 	struct puffs_msgpark *park;
    566       1.61  pooka 	struct puffs_req *preq;
    567       1.61  pooka 
    568       1.63  pooka 	puffs_msgmem_alloc(sizeof(struct puffs_req), &park, (void *)&preq, 1);
    569       1.61  pooka 	puffs_msg_setfaf(park); /* XXXXXX: avoids reqid override */
    570       1.61  pooka 
    571       1.61  pooka 	memcpy(preq, origpreq, sizeof(struct puffs_req));
    572       1.61  pooka 	preq->preq_rv = rv;
    573       1.61  pooka 	preq->preq_opclass |= PUFFSOPFLAG_ISRESPONSE;
    574       1.61  pooka 
    575       1.61  pooka 	puffs_msg_enqueue(pmp, park);
    576       1.61  pooka 	puffs_msgmem_release(park);
    577       1.61  pooka }
    578       1.61  pooka 
    579       1.61  pooka /*
    580       1.46  pooka  * Get next request in the outgoing queue.  "maxsize" controls the
    581       1.46  pooka  * size the caller can accommodate and "nonblock" signals if this
    582       1.46  pooka  * should block while waiting for input.  Handles all locking internally.
    583        1.9  pooka  */
    584       1.10  pooka int
    585       1.46  pooka puffs_msgif_getout(void *this, size_t maxsize, int nonblock,
    586       1.46  pooka 	uint8_t **data, size_t *dlen, void **parkptr)
    587        1.1  pooka {
    588       1.46  pooka 	struct puffs_mount *pmp = this;
    589       1.46  pooka 	struct puffs_msgpark *park;
    590        1.9  pooka 	struct puffs_req *preq;
    591       1.46  pooka 	int error;
    592        1.1  pooka 
    593       1.46  pooka 	error = 0;
    594       1.22  pooka 	mutex_enter(&pmp->pmp_lock);
    595       1.50  pooka 	puffs_mp_reference(pmp);
    596       1.46  pooka 	for (;;) {
    597       1.46  pooka 		/* RIP? */
    598        1.9  pooka 		if (pmp->pmp_status != PUFFSTAT_RUNNING) {
    599        1.9  pooka 			error = ENXIO;
    600       1.46  pooka 			break;
    601        1.9  pooka 		}
    602       1.12  pooka 
    603       1.46  pooka 		/* need platinum yendorian express card? */
    604       1.46  pooka 		if (TAILQ_EMPTY(&pmp->pmp_msg_touser)) {
    605       1.46  pooka 			DPRINTF(("puffs_getout: no outgoing op, "));
    606       1.12  pooka 			if (nonblock) {
    607       1.46  pooka 				DPRINTF(("returning EWOULDBLOCK\n"));
    608       1.12  pooka 				error = EWOULDBLOCK;
    609       1.46  pooka 				break;
    610        1.9  pooka 			}
    611       1.46  pooka 			DPRINTF(("waiting ...\n"));
    612        1.9  pooka 
    613       1.46  pooka 			error = cv_wait_sig(&pmp->pmp_msg_waiter_cv,
    614       1.22  pooka 			    &pmp->pmp_lock);
    615       1.11  pooka 			if (error)
    616       1.46  pooka 				break;
    617       1.11  pooka 			else
    618       1.46  pooka 				continue;
    619        1.9  pooka 		}
    620        1.9  pooka 
    621       1.46  pooka 		park = TAILQ_FIRST(&pmp->pmp_msg_touser);
    622       1.50  pooka 		if (park == NULL)
    623       1.50  pooka 			continue;
    624       1.50  pooka 
    625       1.46  pooka 		mutex_enter(&park->park_mtx);
    626       1.46  pooka 		puffs_msgpark_reference(park);
    627       1.46  pooka 
    628       1.46  pooka 		DPRINTF(("puffs_getout: found park at %p, ", park));
    629       1.22  pooka 
    630       1.22  pooka 		/* If it's a goner, don't process any furher */
    631       1.22  pooka 		if (park->park_flags & PARKFLAG_WAITERGONE) {
    632       1.46  pooka 			DPRINTF(("waitergone!\n"));
    633       1.46  pooka 			puffs_msgpark_release(park);
    634       1.22  pooka 			continue;
    635       1.22  pooka 		}
    636       1.55  pooka 		preq = park->park_preq;
    637       1.22  pooka 
    638       1.55  pooka #if 0
    639       1.46  pooka 		/* check size */
    640       1.55  pooka 		/*
    641       1.55  pooka 		 * XXX: this check is not valid for now, we don't know
    642       1.55  pooka 		 * the size of the caller's input buffer.  i.e. this
    643       1.55  pooka 		 * will most likely go away
    644       1.55  pooka 		 */
    645       1.46  pooka 		if (maxsize < preq->preq_frhdr.pfr_len) {
    646       1.46  pooka 			DPRINTF(("buffer too small\n"));
    647       1.46  pooka 			puffs_msgpark_release(park);
    648       1.46  pooka 			error = E2BIG;
    649       1.46  pooka 			break;
    650       1.26  pooka 		}
    651       1.55  pooka #endif
    652       1.28  pooka 
    653       1.46  pooka 		DPRINTF(("returning\n"));
    654       1.46  pooka 
    655       1.46  pooka 		/*
    656       1.46  pooka 		 * Ok, we found what we came for.  Release it from the
    657       1.46  pooka 		 * outgoing queue but do not unlock.  We will unlock
    658       1.46  pooka 		 * only after we "releaseout" it to avoid complications:
    659       1.46  pooka 		 * otherwise it is (theoretically) possible for userland
    660       1.46  pooka 		 * to race us into "put" before we have a change to put
    661       1.46  pooka 		 * this baby on the receiving queue.
    662       1.46  pooka 		 */
    663       1.46  pooka 		TAILQ_REMOVE(&pmp->pmp_msg_touser, park, park_entries);
    664       1.28  pooka 		KASSERT(park->park_flags & PARKFLAG_ONQUEUE1);
    665       1.28  pooka 		park->park_flags &= ~PARKFLAG_ONQUEUE1;
    666       1.46  pooka 		mutex_exit(&park->park_mtx);
    667       1.46  pooka 
    668       1.46  pooka 		pmp->pmp_msg_touser_count--;
    669       1.46  pooka 		KASSERT(pmp->pmp_msg_touser_count >= 0);
    670       1.26  pooka 
    671       1.46  pooka 		break;
    672       1.46  pooka 	}
    673       1.50  pooka 	puffs_mp_release(pmp);
    674       1.46  pooka 	mutex_exit(&pmp->pmp_lock);
    675        1.9  pooka 
    676       1.46  pooka 	if (error == 0) {
    677       1.46  pooka 		*data = (uint8_t *)preq;
    678       1.55  pooka 		preq->preq_pth.pth_framelen = park->park_copylen;
    679       1.55  pooka 		*dlen = preq->preq_pth.pth_framelen;
    680       1.46  pooka 		*parkptr = park;
    681       1.46  pooka 	}
    682       1.51  pooka 
    683       1.46  pooka 	return error;
    684       1.46  pooka }
    685        1.9  pooka 
    686       1.46  pooka /*
    687       1.46  pooka  * Release outgoing structure.  Now, depending on the success of the
    688       1.46  pooka  * outgoing send, it is either going onto the result waiting queue
    689       1.46  pooka  * or the death chamber.
    690       1.46  pooka  */
    691       1.46  pooka void
    692       1.46  pooka puffs_msgif_releaseout(void *this, void *parkptr, int status)
    693       1.46  pooka {
    694       1.46  pooka 	struct puffs_mount *pmp = this;
    695       1.46  pooka 	struct puffs_msgpark *park = parkptr;
    696       1.32  pooka 
    697       1.46  pooka 	DPRINTF(("puffs_releaseout: returning park %p, errno %d: " ,
    698       1.46  pooka 	    park, status));
    699       1.46  pooka 	mutex_enter(&pmp->pmp_lock);
    700       1.46  pooka 	mutex_enter(&park->park_mtx);
    701       1.46  pooka 	if (park->park_flags & PARKFLAG_WANTREPLY) {
    702       1.46  pooka 		if (status == 0) {
    703       1.46  pooka 			DPRINTF(("enqueue replywait\n"));
    704       1.46  pooka 			TAILQ_INSERT_TAIL(&pmp->pmp_msg_replywait, park,
    705       1.22  pooka 			    park_entries);
    706       1.26  pooka 			park->park_flags |= PARKFLAG_ONQUEUE2;
    707        1.9  pooka 		} else {
    708       1.46  pooka 			DPRINTF(("error path!\n"));
    709       1.46  pooka 			park->park_preq->preq_rv = status;
    710       1.46  pooka 			park->park_flags |= PARKFLAG_DONE;
    711       1.46  pooka 			cv_signal(&park->park_cv);
    712        1.1  pooka 		}
    713       1.46  pooka 		puffs_msgpark_release(park);
    714       1.46  pooka 	} else {
    715       1.46  pooka 		DPRINTF(("release\n"));
    716       1.46  pooka 		puffs_msgpark_release1(park, 2);
    717        1.1  pooka 	}
    718       1.22  pooka 	mutex_exit(&pmp->pmp_lock);
    719        1.1  pooka }
    720        1.1  pooka 
    721       1.53  pooka size_t
    722       1.53  pooka puffs_msgif_waitcount(void *this)
    723       1.53  pooka {
    724       1.53  pooka 	struct puffs_mount *pmp = this;
    725       1.53  pooka 	size_t rv;
    726       1.53  pooka 
    727       1.53  pooka 	mutex_enter(&pmp->pmp_lock);
    728       1.53  pooka 	rv = pmp->pmp_msg_touser_count;
    729       1.53  pooka 	mutex_exit(&pmp->pmp_lock);
    730       1.53  pooka 
    731       1.53  pooka 	return rv;
    732       1.53  pooka }
    733       1.53  pooka 
    734       1.50  pooka /*
    735       1.50  pooka  * XXX: locking with this one?
    736       1.50  pooka  */
    737       1.53  pooka static void
    738       1.56  pooka puffsop_msg(void *this, struct puffs_req *preq)
    739        1.1  pooka {
    740       1.46  pooka 	struct puffs_mount *pmp = this;
    741       1.55  pooka 	struct putter_hdr *pth = &preq->preq_pth;
    742       1.46  pooka 	struct puffs_msgpark *park;
    743       1.57  pooka 	int wgone;
    744        1.1  pooka 
    745       1.22  pooka 	mutex_enter(&pmp->pmp_lock);
    746        1.9  pooka 
    747       1.46  pooka 	/* Locate waiter */
    748       1.46  pooka 	TAILQ_FOREACH(park, &pmp->pmp_msg_replywait, park_entries) {
    749       1.46  pooka 		if (park->park_preq->preq_id == preq->preq_id)
    750        1.1  pooka 			break;
    751       1.46  pooka 	}
    752       1.46  pooka 	if (park == NULL) {
    753       1.58  pooka 		DPRINTF(("puffsop_msg: no request: %" PRIu64 "\n",
    754       1.46  pooka 		    preq->preq_id));
    755       1.46  pooka 		mutex_exit(&pmp->pmp_lock);
    756       1.46  pooka 		return; /* XXX send error */
    757       1.46  pooka 	}
    758       1.26  pooka 
    759       1.46  pooka 	mutex_enter(&park->park_mtx);
    760       1.46  pooka 	puffs_msgpark_reference(park);
    761       1.55  pooka 	if (pth->pth_framelen > park->park_maxlen) {
    762       1.58  pooka 		DPRINTF(("puffsop_msg: invalid buffer length: "
    763       1.55  pooka 		    "%" PRIu64 " (req %" PRIu64 ", \n", pth->pth_framelen,
    764       1.55  pooka 		    preq->preq_id));
    765       1.46  pooka 		park->park_preq->preq_rv = EPROTO;
    766       1.46  pooka 		cv_signal(&park->park_cv);
    767       1.57  pooka 		puffs_msgpark_release1(park, 2);
    768       1.22  pooka 		mutex_exit(&pmp->pmp_lock);
    769       1.46  pooka 		return; /* XXX: error */
    770       1.46  pooka 	}
    771       1.46  pooka 	wgone = park->park_flags & PARKFLAG_WAITERGONE;
    772        1.9  pooka 
    773       1.46  pooka 	KASSERT(park->park_flags & PARKFLAG_ONQUEUE2);
    774       1.46  pooka 	TAILQ_REMOVE(&pmp->pmp_msg_replywait, park, park_entries);
    775       1.46  pooka 	park->park_flags &= ~PARKFLAG_ONQUEUE2;
    776       1.46  pooka 	mutex_exit(&pmp->pmp_lock);
    777       1.24  pooka 
    778       1.46  pooka 	if (wgone) {
    779       1.58  pooka 		DPRINTF(("puffsop_msg: bad service - waiter gone for "
    780       1.46  pooka 		    "park %p\n", park));
    781       1.46  pooka 	} else {
    782       1.24  pooka 		if (park->park_flags & PARKFLAG_CALL) {
    783       1.58  pooka 			DPRINTF(("puffsop_msg: call for %p, arg %p\n",
    784       1.40  pooka 			    park->park_preq, park->park_donearg));
    785       1.55  pooka 			park->park_done(pmp, preq, park->park_donearg);
    786       1.46  pooka 		} else {
    787       1.46  pooka 			/* XXX: yes, I know */
    788       1.55  pooka 			memcpy(park->park_preq, preq, pth->pth_framelen);
    789       1.20  pooka 		}
    790       1.46  pooka 	}
    791        1.1  pooka 
    792       1.46  pooka 	if (!wgone) {
    793       1.46  pooka 		DPRINTF(("puffs_putop: flagging done for "
    794       1.46  pooka 		    "park %p\n", park));
    795       1.46  pooka 		cv_signal(&park->park_cv);
    796        1.1  pooka 	}
    797        1.1  pooka 
    798       1.46  pooka 	park->park_flags |= PARKFLAG_DONE;
    799       1.57  pooka 	puffs_msgpark_release1(park, 2);
    800        1.1  pooka }
    801        1.1  pooka 
    802       1.22  pooka /*
    803       1.53  pooka  * helpers
    804       1.53  pooka  */
    805       1.53  pooka static void
    806       1.53  pooka dosuspendresume(void *arg)
    807       1.53  pooka {
    808       1.53  pooka 	struct puffs_mount *pmp = arg;
    809       1.53  pooka 	struct mount *mp;
    810       1.53  pooka 	int rv;
    811       1.53  pooka 
    812       1.53  pooka 	mp = PMPTOMP(pmp);
    813       1.53  pooka 	/*
    814       1.53  pooka 	 * XXX?  does this really do any good or is it just
    815       1.53  pooka 	 * paranoid stupidity?  or stupid paranoia?
    816       1.53  pooka 	 */
    817       1.53  pooka 	if (mp->mnt_iflag & IMNT_UNMOUNT) {
    818       1.53  pooka 		printf("puffs dosuspendresume(): detected suspend on "
    819       1.53  pooka 		    "unmounting fs\n");
    820       1.53  pooka 		goto out;
    821       1.53  pooka 	}
    822       1.53  pooka 
    823       1.53  pooka 	/* Do the dance.  Allow only one concurrent suspend */
    824       1.53  pooka 	rv = vfs_suspend(PMPTOMP(pmp), 1);
    825       1.53  pooka 	if (rv == 0)
    826       1.53  pooka 		vfs_resume(PMPTOMP(pmp));
    827       1.53  pooka 
    828       1.53  pooka  out:
    829       1.53  pooka 	mutex_enter(&pmp->pmp_lock);
    830       1.53  pooka 	KASSERT(pmp->pmp_suspend == 1);
    831       1.53  pooka 	pmp->pmp_suspend = 0;
    832       1.53  pooka 	puffs_mp_release(pmp);
    833       1.53  pooka 	mutex_exit(&pmp->pmp_lock);
    834       1.53  pooka 
    835       1.53  pooka 	kthread_exit(0);
    836       1.53  pooka }
    837       1.53  pooka 
    838       1.53  pooka static void
    839       1.53  pooka puffsop_suspend(struct puffs_mount *pmp)
    840       1.53  pooka {
    841       1.53  pooka 	int rv = 0;
    842       1.53  pooka 
    843       1.53  pooka 	mutex_enter(&pmp->pmp_lock);
    844       1.53  pooka 	if (pmp->pmp_suspend || pmp->pmp_status != PUFFSTAT_RUNNING) {
    845       1.53  pooka 		rv = EBUSY;
    846       1.53  pooka 	} else {
    847       1.53  pooka 		puffs_mp_reference(pmp);
    848       1.53  pooka 		pmp->pmp_suspend = 1;
    849       1.53  pooka 	}
    850       1.53  pooka 	mutex_exit(&pmp->pmp_lock);
    851       1.53  pooka 	if (rv)
    852       1.53  pooka 		return;
    853       1.53  pooka 	rv = kthread_create(PRI_NONE, 0, NULL, dosuspendresume,
    854       1.53  pooka 	    pmp, NULL, "puffsusp");
    855       1.53  pooka 
    856       1.53  pooka 	/* XXX: "return" rv */
    857       1.53  pooka }
    858       1.53  pooka 
    859       1.61  pooka static void
    860       1.53  pooka puffsop_flush(struct puffs_mount *pmp, struct puffs_flush *pf)
    861       1.53  pooka {
    862       1.53  pooka 	struct vnode *vp;
    863       1.53  pooka 	voff_t offlo, offhi;
    864       1.53  pooka 	int rv, flags = 0;
    865       1.53  pooka 
    866       1.61  pooka 	if (pf->pf_req.preq_pth.pth_framelen != sizeof(struct puffs_flush)) {
    867  1.72.12.1   matt 		puffs_msg_sendresp(pmp, &pf->pf_req, EINVAL); /* E2SMALL */
    868  1.72.12.1   matt 		return;
    869       1.61  pooka 	}
    870       1.61  pooka 
    871       1.53  pooka 	/* XXX: slurry */
    872       1.53  pooka 	if (pf->pf_op == PUFFS_INVAL_NAMECACHE_ALL) {
    873       1.53  pooka 		cache_purgevfs(PMPTOMP(pmp));
    874       1.61  pooka 		rv = 0;
    875       1.61  pooka 		goto out;
    876       1.53  pooka 	}
    877       1.53  pooka 
    878       1.53  pooka 	/*
    879       1.53  pooka 	 * Get vnode, don't lock it.  Namecache is protected by its own lock
    880       1.53  pooka 	 * and we have a reference to protect against premature harvesting.
    881       1.53  pooka 	 *
    882       1.53  pooka 	 * The node we want here might be locked and the op is in
    883       1.53  pooka 	 * userspace waiting for us to complete ==> deadlock.  Another
    884       1.53  pooka 	 * reason we need to eventually bump locking to userspace, as we
    885       1.53  pooka 	 * will need to lock the node if we wish to do flushes.
    886       1.53  pooka 	 */
    887       1.53  pooka 	rv = puffs_cookie2vnode(pmp, pf->pf_cookie, 0, 0, &vp);
    888       1.53  pooka 	if (rv) {
    889       1.53  pooka 		if (rv == PUFFS_NOSUCHCOOKIE)
    890       1.61  pooka 			rv = ENOENT;
    891       1.61  pooka 		goto out;
    892       1.53  pooka 	}
    893       1.53  pooka 
    894       1.53  pooka 	switch (pf->pf_op) {
    895       1.53  pooka #if 0
    896       1.53  pooka 	/* not quite ready, yet */
    897       1.53  pooka 	case PUFFS_INVAL_NAMECACHE_NODE:
    898       1.53  pooka 	struct componentname *pf_cn;
    899       1.53  pooka 	char *name;
    900       1.53  pooka 		/* get comfortab^Wcomponentname */
    901       1.59  pooka 		pf_cn = kmem_alloc(componentname);
    902       1.53  pooka 		memset(pf_cn, 0, sizeof(struct componentname));
    903       1.53  pooka 		break;
    904       1.53  pooka 
    905       1.53  pooka #endif
    906       1.53  pooka 	case PUFFS_INVAL_NAMECACHE_DIR:
    907       1.53  pooka 		if (vp->v_type != VDIR) {
    908       1.53  pooka 			rv = EINVAL;
    909       1.53  pooka 			break;
    910       1.53  pooka 		}
    911       1.53  pooka 		cache_purge1(vp, NULL, PURGE_CHILDREN);
    912       1.53  pooka 		break;
    913       1.53  pooka 
    914       1.53  pooka 	case PUFFS_INVAL_PAGECACHE_NODE_RANGE:
    915       1.53  pooka 		flags = PGO_FREE;
    916       1.53  pooka 		/*FALLTHROUGH*/
    917       1.53  pooka 	case PUFFS_FLUSH_PAGECACHE_NODE_RANGE:
    918       1.53  pooka 		if (flags == 0)
    919       1.53  pooka 			flags = PGO_CLEANIT;
    920       1.53  pooka 
    921       1.53  pooka 		if (pf->pf_end > vp->v_size || vp->v_type != VREG) {
    922       1.53  pooka 			rv = EINVAL;
    923       1.53  pooka 			break;
    924       1.53  pooka 		}
    925       1.53  pooka 
    926       1.53  pooka 		offlo = trunc_page(pf->pf_start);
    927       1.53  pooka 		offhi = round_page(pf->pf_end);
    928       1.53  pooka 		if (offhi != 0 && offlo >= offhi) {
    929       1.53  pooka 			rv = EINVAL;
    930       1.53  pooka 			break;
    931       1.53  pooka 		}
    932       1.53  pooka 
    933       1.62     ad 		mutex_enter(&vp->v_uobj.vmobjlock);
    934       1.53  pooka 		rv = VOP_PUTPAGES(vp, offlo, offhi, flags);
    935       1.53  pooka 		break;
    936       1.53  pooka 
    937       1.53  pooka 	default:
    938       1.53  pooka 		rv = EINVAL;
    939       1.53  pooka 	}
    940       1.53  pooka 
    941       1.53  pooka 	vrele(vp);
    942       1.53  pooka 
    943       1.61  pooka  out:
    944       1.61  pooka 	puffs_msg_sendresp(pmp, &pf->pf_req, rv);
    945       1.53  pooka }
    946       1.53  pooka 
    947       1.53  pooka int
    948       1.56  pooka puffs_msgif_dispatch(void *this, struct putter_hdr *pth)
    949       1.53  pooka {
    950       1.53  pooka 	struct puffs_mount *pmp = this;
    951       1.56  pooka 	struct puffs_req *preq = (struct puffs_req *)pth;
    952  1.72.12.1   matt 	struct puffs_sopreq *psopr;
    953       1.56  pooka 
    954       1.61  pooka 	if (pth->pth_framelen < sizeof(struct puffs_req)) {
    955       1.61  pooka 		puffs_msg_sendresp(pmp, preq, EINVAL); /* E2SMALL */
    956       1.61  pooka 		return 0;
    957       1.61  pooka 	}
    958       1.53  pooka 
    959       1.55  pooka 	switch (PUFFSOP_OPCLASS(preq->preq_opclass)) {
    960       1.53  pooka 	case PUFFSOP_VN:
    961       1.53  pooka 	case PUFFSOP_VFS:
    962       1.61  pooka 		DPRINTF(("dispatch: vn/vfs message 0x%x\n", preq->preq_optype));
    963       1.56  pooka 		puffsop_msg(pmp, preq);
    964       1.53  pooka 		break;
    965  1.72.12.1   matt 	case PUFFSOP_FLUSH: /* process in sop thread */
    966  1.72.12.1   matt 	{
    967  1.72.12.1   matt 		struct puffs_flush *pf;
    968  1.72.12.1   matt 
    969  1.72.12.1   matt  		DPRINTF(("dispatch: flush 0x%x\n", preq->preq_optype));
    970  1.72.12.1   matt 
    971  1.72.12.1   matt 		if (preq->preq_pth.pth_framelen != sizeof(struct puffs_flush)) {
    972  1.72.12.1   matt 			puffs_msg_sendresp(pmp, preq, EINVAL); /* E2SMALL */
    973  1.72.12.1   matt 			break;
    974  1.72.12.1   matt 		}
    975  1.72.12.1   matt 		pf = (struct puffs_flush *)preq;
    976  1.72.12.1   matt 
    977  1.72.12.1   matt 		psopr = kmem_alloc(sizeof(*psopr), KM_SLEEP);
    978  1.72.12.1   matt 		memcpy(&psopr->psopr_pf, pf, sizeof(*pf));
    979  1.72.12.1   matt 		psopr->psopr_sopreq = PUFFS_SOPREQ_FLUSH;
    980  1.72.12.1   matt 
    981  1.72.12.1   matt 		mutex_enter(&pmp->pmp_sopmtx);
    982  1.72.12.1   matt 		TAILQ_INSERT_TAIL(&pmp->pmp_sopreqs, psopr, psopr_entries);
    983  1.72.12.1   matt 		cv_signal(&pmp->pmp_sopcv);
    984  1.72.12.1   matt 		mutex_exit(&pmp->pmp_sopmtx);
    985  1.72.12.1   matt  		break;
    986  1.72.12.1   matt 	}
    987       1.53  pooka 	case PUFFSOP_SUSPEND:
    988       1.61  pooka 		DPRINTF(("dispatch: suspend\n"));
    989       1.53  pooka 		puffsop_suspend(pmp);
    990       1.53  pooka 		break;
    991       1.53  pooka 	default:
    992       1.61  pooka 		DPRINTF(("dispatch: invalid class 0x%x\n", preq->preq_opclass));
    993       1.61  pooka 		puffs_msg_sendresp(pmp, preq, EINVAL);
    994       1.53  pooka 		break;
    995       1.53  pooka 	}
    996       1.53  pooka 
    997       1.53  pooka 	return 0;
    998       1.53  pooka }
    999  1.72.12.1   matt 
   1000  1.72.12.1   matt /*
   1001  1.72.12.1   matt  * Work loop for thread processing all ops from server which
   1002  1.72.12.1   matt  * cannot safely be handled in caller context.  This includes
   1003  1.72.12.1   matt  * everything which might need a lock currently "held" by the file
   1004  1.72.12.1   matt  * server, i.e. a long-term kernel lock which will be released only
   1005  1.72.12.1   matt  * once the file server acknowledges a request
   1006  1.72.12.1   matt  */
   1007  1.72.12.1   matt void
   1008  1.72.12.1   matt puffs_sop_thread(void *arg)
   1009  1.72.12.1   matt {
   1010  1.72.12.1   matt 	struct puffs_mount *pmp = arg;
   1011  1.72.12.1   matt 	struct puffs_sopreq *psopr;
   1012  1.72.12.1   matt 	struct puffs_req *preq;
   1013  1.72.12.1   matt 	bool keeprunning = true;
   1014  1.72.12.1   matt 
   1015  1.72.12.1   matt 	mutex_enter(&pmp->pmp_sopmtx);
   1016  1.72.12.1   matt 	while (keeprunning) {
   1017  1.72.12.1   matt 		while ((psopr = TAILQ_FIRST(&pmp->pmp_sopreqs)) == NULL)
   1018  1.72.12.1   matt 			cv_wait(&pmp->pmp_sopcv, &pmp->pmp_sopmtx);
   1019  1.72.12.1   matt 		TAILQ_REMOVE(&pmp->pmp_sopreqs, psopr, psopr_entries);
   1020  1.72.12.1   matt 		mutex_exit(&pmp->pmp_sopmtx);
   1021  1.72.12.1   matt 
   1022  1.72.12.1   matt 		preq = &psopr->psopr_preq;
   1023  1.72.12.1   matt 		switch (psopr->psopr_sopreq) {
   1024  1.72.12.1   matt 		case PUFFS_SOPREQ_EXIT:
   1025  1.72.12.1   matt 			keeprunning = false;
   1026  1.72.12.1   matt 			break;
   1027  1.72.12.1   matt 		case PUFFS_SOPREQ_FLUSH:
   1028  1.72.12.1   matt 			puffsop_flush(pmp, (struct puffs_flush *)preq);
   1029  1.72.12.1   matt 			break;
   1030  1.72.12.1   matt 		}
   1031  1.72.12.1   matt 
   1032  1.72.12.1   matt 		kmem_free(psopr, sizeof(*psopr));
   1033  1.72.12.1   matt 		mutex_enter(&pmp->pmp_sopmtx);
   1034  1.72.12.1   matt 	}
   1035  1.72.12.1   matt 
   1036  1.72.12.1   matt 	/*
   1037  1.72.12.1   matt 	 * Purge remaining ops.  could send error, but that is highly
   1038  1.72.12.1   matt 	 * unlikely to reach the caller.
   1039  1.72.12.1   matt 	 */
   1040  1.72.12.1   matt 	while ((psopr = TAILQ_FIRST(&pmp->pmp_sopreqs)) != NULL) {
   1041  1.72.12.1   matt 		TAILQ_REMOVE(&pmp->pmp_sopreqs, psopr, psopr_entries);
   1042  1.72.12.1   matt 		mutex_exit(&pmp->pmp_sopmtx);
   1043  1.72.12.1   matt 		kmem_free(psopr, sizeof(*psopr));
   1044  1.72.12.1   matt 		mutex_enter(&pmp->pmp_sopmtx);
   1045  1.72.12.1   matt 	}
   1046  1.72.12.1   matt 
   1047  1.72.12.1   matt 	pmp->pmp_sopthrcount--;
   1048  1.72.12.1   matt 	cv_signal(&pmp->pmp_sopcv);
   1049  1.72.12.1   matt 	mutex_exit(&pmp->pmp_sopmtx); /* not allowed to access fs after this */
   1050  1.72.12.1   matt 
   1051  1.72.12.1   matt 	kthread_exit(0);
   1052  1.72.12.1   matt }
   1053       1.53  pooka 
   1054       1.53  pooka int
   1055       1.53  pooka puffs_msgif_close(void *this)
   1056       1.53  pooka {
   1057       1.53  pooka 	struct puffs_mount *pmp = this;
   1058       1.53  pooka 	struct mount *mp = PMPTOMP(pmp);
   1059       1.53  pooka 
   1060       1.53  pooka 	mutex_enter(&pmp->pmp_lock);
   1061       1.53  pooka 	puffs_mp_reference(pmp);
   1062       1.53  pooka 
   1063       1.53  pooka 	/*
   1064       1.53  pooka 	 * Free the waiting callers before proceeding any further.
   1065       1.53  pooka 	 * The syncer might be jogging around in this file system
   1066       1.53  pooka 	 * currently.  If we allow it to go to the userspace of no
   1067       1.53  pooka 	 * return while trying to get the syncer lock, well ...
   1068       1.53  pooka 	 */
   1069       1.53  pooka 	puffs_userdead(pmp);
   1070       1.53  pooka 
   1071       1.53  pooka 	/*
   1072       1.53  pooka 	 * Make sure someone from puffs_unmount() isn't currently in
   1073       1.53  pooka 	 * userspace.  If we don't take this precautionary step,
   1074       1.53  pooka 	 * they might notice that the mountpoint has disappeared
   1075       1.53  pooka 	 * from under them once they return.  Especially note that we
   1076       1.53  pooka 	 * cannot simply test for an unmounter before calling
   1077       1.53  pooka 	 * dounmount(), since it might be possible that that particular
   1078       1.53  pooka 	 * invocation of unmount was called without MNT_FORCE.  Here we
   1079       1.53  pooka 	 * *must* make sure unmount succeeds.  Also, restart is necessary
   1080       1.53  pooka 	 * since pmp isn't locked.  We might end up with PUTTER_DEAD after
   1081       1.53  pooka 	 * restart and exit from there.
   1082       1.53  pooka 	 */
   1083       1.53  pooka 	if (pmp->pmp_unmounting) {
   1084       1.53  pooka 		cv_wait(&pmp->pmp_unmounting_cv, &pmp->pmp_lock);
   1085       1.53  pooka 		puffs_mp_release(pmp);
   1086       1.53  pooka 		mutex_exit(&pmp->pmp_lock);
   1087       1.53  pooka 		DPRINTF(("puffs_fop_close: unmount was in progress for pmp %p, "
   1088       1.53  pooka 		    "restart\n", pmp));
   1089       1.53  pooka 		return ERESTART;
   1090       1.53  pooka 	}
   1091       1.53  pooka 
   1092       1.53  pooka 	/* Won't access pmp from here anymore */
   1093       1.72     ad 	atomic_inc_uint((unsigned int*)&mp->mnt_refcnt);
   1094       1.53  pooka 	puffs_mp_release(pmp);
   1095       1.53  pooka 	mutex_exit(&pmp->pmp_lock);
   1096       1.53  pooka 
   1097       1.72     ad 	/* Detach from VFS. */
   1098       1.71     ad 	(void)dounmount(mp, MNT_FORCE, curlwp);
   1099       1.72     ad 	vfs_destroy(mp);
   1100       1.53  pooka 
   1101       1.53  pooka 	return 0;
   1102       1.53  pooka }
   1103       1.53  pooka 
   1104       1.53  pooka /*
   1105       1.22  pooka  * We're dead, kaput, RIP, slightly more than merely pining for the
   1106       1.22  pooka  * fjords, belly-up, fallen, lifeless, finished, expired, gone to meet
   1107       1.22  pooka  * our maker, ceased to be, etcetc.  YASD.  It's a dead FS!
   1108       1.22  pooka  *
   1109       1.22  pooka  * Caller must hold puffs mutex.
   1110       1.22  pooka  */
   1111       1.22  pooka void
   1112       1.22  pooka puffs_userdead(struct puffs_mount *pmp)
   1113       1.22  pooka {
   1114       1.46  pooka 	struct puffs_msgpark *park, *park_next;
   1115       1.22  pooka 
   1116       1.22  pooka 	/*
   1117       1.22  pooka 	 * Mark filesystem status as dying so that operations don't
   1118       1.22  pooka 	 * attempt to march to userspace any longer.
   1119       1.22  pooka 	 */
   1120       1.22  pooka 	pmp->pmp_status = PUFFSTAT_DYING;
   1121       1.22  pooka 
   1122       1.22  pooka 	/* signal waiters on REQUEST TO file server queue */
   1123       1.46  pooka 	for (park = TAILQ_FIRST(&pmp->pmp_msg_touser); park; park = park_next) {
   1124       1.24  pooka 		uint8_t opclass;
   1125       1.24  pooka 
   1126       1.46  pooka 		mutex_enter(&park->park_mtx);
   1127       1.46  pooka 		puffs_msgpark_reference(park);
   1128       1.32  pooka 		park_next = TAILQ_NEXT(park, park_entries);
   1129       1.26  pooka 
   1130       1.26  pooka 		KASSERT(park->park_flags & PARKFLAG_ONQUEUE1);
   1131       1.46  pooka 		TAILQ_REMOVE(&pmp->pmp_msg_touser, park, park_entries);
   1132       1.26  pooka 		park->park_flags &= ~PARKFLAG_ONQUEUE1;
   1133       1.46  pooka 		pmp->pmp_msg_touser_count--;
   1134       1.22  pooka 
   1135       1.31  pooka 		/*
   1136       1.51  pooka 		 * Even though waiters on QUEUE1 are removed in touser()
   1137       1.51  pooka 		 * in case of WAITERGONE, it is still possible for us to
   1138       1.51  pooka 		 * get raced here due to having to retake locks in said
   1139       1.51  pooka 		 * touser().  In the race case simply "ignore" the item
   1140       1.51  pooka 		 * on the queue and move on to the next one.
   1141       1.31  pooka 		 */
   1142       1.31  pooka 		if (park->park_flags & PARKFLAG_WAITERGONE) {
   1143       1.31  pooka 			KASSERT((park->park_flags & PARKFLAG_CALL) == 0);
   1144       1.31  pooka 			KASSERT(park->park_flags & PARKFLAG_WANTREPLY);
   1145       1.46  pooka 			puffs_msgpark_release(park);
   1146       1.51  pooka 
   1147       1.22  pooka 		} else {
   1148       1.31  pooka 			opclass = park->park_preq->preq_opclass;
   1149       1.23  pooka 			park->park_preq->preq_rv = ENXIO;
   1150       1.31  pooka 
   1151       1.31  pooka 			if (park->park_flags & PARKFLAG_CALL) {
   1152       1.42  pooka 				park->park_done(pmp, park->park_preq,
   1153       1.31  pooka 				    park->park_donearg);
   1154       1.46  pooka 				puffs_msgpark_release1(park, 2);
   1155       1.31  pooka 			} else if ((park->park_flags & PARKFLAG_WANTREPLY)==0) {
   1156       1.46  pooka 				puffs_msgpark_release1(park, 2);
   1157       1.31  pooka 			} else {
   1158       1.31  pooka 				park->park_preq->preq_rv = ENXIO;
   1159       1.31  pooka 				cv_signal(&park->park_cv);
   1160       1.46  pooka 				puffs_msgpark_release(park);
   1161       1.31  pooka 			}
   1162       1.22  pooka 		}
   1163       1.22  pooka 	}
   1164       1.22  pooka 
   1165       1.22  pooka 	/* signal waiters on RESPONSE FROM file server queue */
   1166       1.46  pooka 	for (park=TAILQ_FIRST(&pmp->pmp_msg_replywait); park; park=park_next) {
   1167       1.46  pooka 		mutex_enter(&park->park_mtx);
   1168       1.46  pooka 		puffs_msgpark_reference(park);
   1169       1.32  pooka 		park_next = TAILQ_NEXT(park, park_entries);
   1170       1.26  pooka 
   1171       1.26  pooka 		KASSERT(park->park_flags & PARKFLAG_ONQUEUE2);
   1172       1.31  pooka 		KASSERT(park->park_flags & PARKFLAG_WANTREPLY);
   1173       1.26  pooka 
   1174       1.46  pooka 		TAILQ_REMOVE(&pmp->pmp_msg_replywait, park, park_entries);
   1175       1.26  pooka 		park->park_flags &= ~PARKFLAG_ONQUEUE2;
   1176       1.26  pooka 
   1177       1.31  pooka 		if (park->park_flags & PARKFLAG_WAITERGONE) {
   1178       1.31  pooka 			KASSERT((park->park_flags & PARKFLAG_CALL) == 0);
   1179       1.46  pooka 			puffs_msgpark_release(park);
   1180       1.22  pooka 		} else {
   1181       1.31  pooka 			park->park_preq->preq_rv = ENXIO;
   1182       1.31  pooka 			if (park->park_flags & PARKFLAG_CALL) {
   1183       1.42  pooka 				park->park_done(pmp, park->park_preq,
   1184       1.31  pooka 				    park->park_donearg);
   1185       1.46  pooka 				puffs_msgpark_release1(park, 2);
   1186       1.31  pooka 			} else {
   1187       1.31  pooka 				cv_signal(&park->park_cv);
   1188       1.46  pooka 				puffs_msgpark_release(park);
   1189       1.31  pooka 			}
   1190       1.22  pooka 		}
   1191       1.22  pooka 	}
   1192       1.50  pooka 
   1193       1.50  pooka 	cv_broadcast(&pmp->pmp_msg_waiter_cv);
   1194       1.22  pooka }
   1195