1*0a6a1f1dSLionel Sambuc /* $NetBSD: puffs_msgif.c,v 1.98 2015/05/06 15:57:08 hannken Exp $ */
284d9c625SLionel Sambuc
384d9c625SLionel Sambuc /*
484d9c625SLionel Sambuc * Copyright (c) 2005, 2006, 2007 Antti Kantee. All Rights Reserved.
584d9c625SLionel Sambuc *
684d9c625SLionel Sambuc * Development of this software was supported by the
784d9c625SLionel Sambuc * Google Summer of Code program and the Ulla Tuominen Foundation.
884d9c625SLionel Sambuc * The Google SoC project was mentored by Bill Studenmund.
984d9c625SLionel Sambuc *
1084d9c625SLionel Sambuc * Redistribution and use in source and binary forms, with or without
1184d9c625SLionel Sambuc * modification, are permitted provided that the following conditions
1284d9c625SLionel Sambuc * are met:
1384d9c625SLionel Sambuc * 1. Redistributions of source code must retain the above copyright
1484d9c625SLionel Sambuc * notice, this list of conditions and the following disclaimer.
1584d9c625SLionel Sambuc * 2. Redistributions in binary form must reproduce the above copyright
1684d9c625SLionel Sambuc * notice, this list of conditions and the following disclaimer in the
1784d9c625SLionel Sambuc * documentation and/or other materials provided with the distribution.
1884d9c625SLionel Sambuc *
1984d9c625SLionel Sambuc * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
2084d9c625SLionel Sambuc * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
2184d9c625SLionel Sambuc * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
2284d9c625SLionel Sambuc * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2384d9c625SLionel Sambuc * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2484d9c625SLionel Sambuc * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
2584d9c625SLionel Sambuc * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2684d9c625SLionel Sambuc * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2784d9c625SLionel Sambuc * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2884d9c625SLionel Sambuc * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2984d9c625SLionel Sambuc * SUCH DAMAGE.
3084d9c625SLionel Sambuc */
3184d9c625SLionel Sambuc
3284d9c625SLionel Sambuc #include <sys/cdefs.h>
33*0a6a1f1dSLionel Sambuc __KERNEL_RCSID(0, "$NetBSD: puffs_msgif.c,v 1.98 2015/05/06 15:57:08 hannken Exp $");
3484d9c625SLionel Sambuc
3584d9c625SLionel Sambuc #include <sys/param.h>
3684d9c625SLionel Sambuc #include <sys/kernel.h>
3784d9c625SLionel Sambuc #include <sys/atomic.h>
3884d9c625SLionel Sambuc #include <sys/kmem.h>
3984d9c625SLionel Sambuc #include <sys/kthread.h>
4084d9c625SLionel Sambuc #include <sys/lock.h>
4184d9c625SLionel Sambuc #include <sys/mount.h>
4284d9c625SLionel Sambuc #include <sys/namei.h>
4384d9c625SLionel Sambuc #include <sys/proc.h>
4484d9c625SLionel Sambuc #include <sys/vnode.h>
4584d9c625SLionel Sambuc #include <sys/atomic.h>
4684d9c625SLionel Sambuc
4784d9c625SLionel Sambuc #include <uvm/uvm.h>
4884d9c625SLionel Sambuc
4984d9c625SLionel Sambuc #include <dev/putter/putter_sys.h>
5084d9c625SLionel Sambuc
5184d9c625SLionel Sambuc #include <fs/puffs/puffs_msgif.h>
5284d9c625SLionel Sambuc #include <fs/puffs/puffs_sys.h>
5384d9c625SLionel Sambuc
5484d9c625SLionel Sambuc /*
5584d9c625SLionel Sambuc * waitq data structures
5684d9c625SLionel Sambuc */
5784d9c625SLionel Sambuc
5884d9c625SLionel Sambuc /*
5984d9c625SLionel Sambuc * While a request is going to userspace, park the caller within the
6084d9c625SLionel Sambuc * kernel. This is the kernel counterpart of "struct puffs_req".
6184d9c625SLionel Sambuc */
6284d9c625SLionel Sambuc struct puffs_msgpark {
6384d9c625SLionel Sambuc struct puffs_req *park_preq; /* req followed by buf */
6484d9c625SLionel Sambuc
6584d9c625SLionel Sambuc size_t park_copylen; /* userspace copylength */
6684d9c625SLionel Sambuc size_t park_maxlen; /* max size in comeback */
6784d9c625SLionel Sambuc
6884d9c625SLionel Sambuc struct puffs_req *park_creq; /* non-compat preq */
6984d9c625SLionel Sambuc size_t park_creqlen; /* non-compat preq len */
7084d9c625SLionel Sambuc
7184d9c625SLionel Sambuc parkdone_fn park_done; /* "biodone" a'la puffs */
7284d9c625SLionel Sambuc void *park_donearg;
7384d9c625SLionel Sambuc
7484d9c625SLionel Sambuc int park_flags;
7584d9c625SLionel Sambuc int park_refcount;
7684d9c625SLionel Sambuc
7784d9c625SLionel Sambuc kcondvar_t park_cv;
7884d9c625SLionel Sambuc kmutex_t park_mtx;
7984d9c625SLionel Sambuc
8084d9c625SLionel Sambuc TAILQ_ENTRY(puffs_msgpark) park_entries;
8184d9c625SLionel Sambuc };
8284d9c625SLionel Sambuc #define PARKFLAG_WAITERGONE 0x01
8384d9c625SLionel Sambuc #define PARKFLAG_DONE 0x02
8484d9c625SLionel Sambuc #define PARKFLAG_ONQUEUE1 0x04
8584d9c625SLionel Sambuc #define PARKFLAG_ONQUEUE2 0x08
8684d9c625SLionel Sambuc #define PARKFLAG_CALL 0x10
8784d9c625SLionel Sambuc #define PARKFLAG_WANTREPLY 0x20
8884d9c625SLionel Sambuc #define PARKFLAG_HASERROR 0x40
8984d9c625SLionel Sambuc
9084d9c625SLionel Sambuc static pool_cache_t parkpc;
9184d9c625SLionel Sambuc #ifdef PUFFSDEBUG
9284d9c625SLionel Sambuc static int totalpark;
9384d9c625SLionel Sambuc #endif
9484d9c625SLionel Sambuc
9584d9c625SLionel Sambuc int puffs_sopreq_expire_timeout = PUFFS_SOPREQ_EXPIRE_TIMEOUT;
9684d9c625SLionel Sambuc
9784d9c625SLionel Sambuc static int
makepark(void * arg,void * obj,int flags)9884d9c625SLionel Sambuc makepark(void *arg, void *obj, int flags)
9984d9c625SLionel Sambuc {
10084d9c625SLionel Sambuc struct puffs_msgpark *park = obj;
10184d9c625SLionel Sambuc
10284d9c625SLionel Sambuc mutex_init(&park->park_mtx, MUTEX_DEFAULT, IPL_NONE);
10384d9c625SLionel Sambuc cv_init(&park->park_cv, "puffsrpl");
10484d9c625SLionel Sambuc
10584d9c625SLionel Sambuc return 0;
10684d9c625SLionel Sambuc }
10784d9c625SLionel Sambuc
10884d9c625SLionel Sambuc static void
nukepark(void * arg,void * obj)10984d9c625SLionel Sambuc nukepark(void *arg, void *obj)
11084d9c625SLionel Sambuc {
11184d9c625SLionel Sambuc struct puffs_msgpark *park = obj;
11284d9c625SLionel Sambuc
11384d9c625SLionel Sambuc cv_destroy(&park->park_cv);
11484d9c625SLionel Sambuc mutex_destroy(&park->park_mtx);
11584d9c625SLionel Sambuc }
11684d9c625SLionel Sambuc
11784d9c625SLionel Sambuc void
puffs_msgif_init(void)11884d9c625SLionel Sambuc puffs_msgif_init(void)
11984d9c625SLionel Sambuc {
12084d9c625SLionel Sambuc
12184d9c625SLionel Sambuc parkpc = pool_cache_init(sizeof(struct puffs_msgpark), 0, 0, 0,
12284d9c625SLionel Sambuc "puffprkl", NULL, IPL_NONE, makepark, nukepark, NULL);
12384d9c625SLionel Sambuc }
12484d9c625SLionel Sambuc
12584d9c625SLionel Sambuc void
puffs_msgif_destroy(void)12684d9c625SLionel Sambuc puffs_msgif_destroy(void)
12784d9c625SLionel Sambuc {
12884d9c625SLionel Sambuc
12984d9c625SLionel Sambuc pool_cache_destroy(parkpc);
13084d9c625SLionel Sambuc }
13184d9c625SLionel Sambuc
13284d9c625SLionel Sambuc static struct puffs_msgpark *
puffs_msgpark_alloc(int waitok)13384d9c625SLionel Sambuc puffs_msgpark_alloc(int waitok)
13484d9c625SLionel Sambuc {
13584d9c625SLionel Sambuc struct puffs_msgpark *park;
13684d9c625SLionel Sambuc
13784d9c625SLionel Sambuc KASSERT(curlwp != uvm.pagedaemon_lwp || !waitok);
13884d9c625SLionel Sambuc
13984d9c625SLionel Sambuc park = pool_cache_get(parkpc, waitok ? PR_WAITOK : PR_NOWAIT);
14084d9c625SLionel Sambuc if (park == NULL)
14184d9c625SLionel Sambuc return park;
14284d9c625SLionel Sambuc
14384d9c625SLionel Sambuc park->park_refcount = 1;
14484d9c625SLionel Sambuc park->park_preq = park->park_creq = NULL;
14584d9c625SLionel Sambuc park->park_flags = PARKFLAG_WANTREPLY;
14684d9c625SLionel Sambuc
14784d9c625SLionel Sambuc #ifdef PUFFSDEBUG
14884d9c625SLionel Sambuc totalpark++;
14984d9c625SLionel Sambuc #endif
15084d9c625SLionel Sambuc
15184d9c625SLionel Sambuc return park;
15284d9c625SLionel Sambuc }
15384d9c625SLionel Sambuc
15484d9c625SLionel Sambuc static void
puffs_msgpark_reference(struct puffs_msgpark * park)15584d9c625SLionel Sambuc puffs_msgpark_reference(struct puffs_msgpark *park)
15684d9c625SLionel Sambuc {
15784d9c625SLionel Sambuc
15884d9c625SLionel Sambuc KASSERT(mutex_owned(&park->park_mtx));
15984d9c625SLionel Sambuc park->park_refcount++;
16084d9c625SLionel Sambuc }
16184d9c625SLionel Sambuc
16284d9c625SLionel Sambuc /*
16384d9c625SLionel Sambuc * Release reference to park structure.
16484d9c625SLionel Sambuc */
16584d9c625SLionel Sambuc static void
puffs_msgpark_release1(struct puffs_msgpark * park,int howmany)16684d9c625SLionel Sambuc puffs_msgpark_release1(struct puffs_msgpark *park, int howmany)
16784d9c625SLionel Sambuc {
16884d9c625SLionel Sambuc struct puffs_req *preq = park->park_preq;
16984d9c625SLionel Sambuc struct puffs_req *creq = park->park_creq;
17084d9c625SLionel Sambuc int refcnt;
17184d9c625SLionel Sambuc
17284d9c625SLionel Sambuc KASSERT(mutex_owned(&park->park_mtx));
17384d9c625SLionel Sambuc refcnt = park->park_refcount -= howmany;
17484d9c625SLionel Sambuc mutex_exit(&park->park_mtx);
17584d9c625SLionel Sambuc
17684d9c625SLionel Sambuc KASSERT(refcnt >= 0);
17784d9c625SLionel Sambuc
17884d9c625SLionel Sambuc if (refcnt == 0) {
17984d9c625SLionel Sambuc if (preq)
18084d9c625SLionel Sambuc kmem_free(preq, park->park_maxlen);
18184d9c625SLionel Sambuc #if 1
18284d9c625SLionel Sambuc if (creq)
18384d9c625SLionel Sambuc kmem_free(creq, park->park_creqlen);
18484d9c625SLionel Sambuc #endif
18584d9c625SLionel Sambuc pool_cache_put(parkpc, park);
18684d9c625SLionel Sambuc
18784d9c625SLionel Sambuc #ifdef PUFFSDEBUG
18884d9c625SLionel Sambuc totalpark--;
18984d9c625SLionel Sambuc #endif
19084d9c625SLionel Sambuc }
19184d9c625SLionel Sambuc }
19284d9c625SLionel Sambuc #define puffs_msgpark_release(a) puffs_msgpark_release1(a, 1)
19384d9c625SLionel Sambuc
19484d9c625SLionel Sambuc #ifdef PUFFSDEBUG
19584d9c625SLionel Sambuc static void
parkdump(struct puffs_msgpark * park)19684d9c625SLionel Sambuc parkdump(struct puffs_msgpark *park)
19784d9c625SLionel Sambuc {
19884d9c625SLionel Sambuc
19984d9c625SLionel Sambuc DPRINTF(("park %p, preq %p, id %" PRIu64 "\n"
20084d9c625SLionel Sambuc "\tcopy %zu, max %zu - done: %p/%p\n"
20184d9c625SLionel Sambuc "\tflags 0x%08x, refcount %d, cv/mtx: %p/%p\n",
20284d9c625SLionel Sambuc park, park->park_preq, park->park_preq->preq_id,
20384d9c625SLionel Sambuc park->park_copylen, park->park_maxlen,
20484d9c625SLionel Sambuc park->park_done, park->park_donearg,
20584d9c625SLionel Sambuc park->park_flags, park->park_refcount,
20684d9c625SLionel Sambuc &park->park_cv, &park->park_mtx));
20784d9c625SLionel Sambuc }
20884d9c625SLionel Sambuc
20984d9c625SLionel Sambuc static void
parkqdump(struct puffs_wq * q,int dumpall)21084d9c625SLionel Sambuc parkqdump(struct puffs_wq *q, int dumpall)
21184d9c625SLionel Sambuc {
21284d9c625SLionel Sambuc struct puffs_msgpark *park;
21384d9c625SLionel Sambuc int total = 0;
21484d9c625SLionel Sambuc
21584d9c625SLionel Sambuc TAILQ_FOREACH(park, q, park_entries) {
21684d9c625SLionel Sambuc if (dumpall)
21784d9c625SLionel Sambuc parkdump(park);
21884d9c625SLionel Sambuc total++;
21984d9c625SLionel Sambuc }
22084d9c625SLionel Sambuc DPRINTF(("puffs waitqueue at %p dumped, %d total\n", q, total));
22184d9c625SLionel Sambuc
22284d9c625SLionel Sambuc }
22384d9c625SLionel Sambuc #endif /* PUFFSDEBUG */
22484d9c625SLionel Sambuc
22584d9c625SLionel Sambuc /*
22684d9c625SLionel Sambuc * A word about locking in the park structures: the lock protects the
22784d9c625SLionel Sambuc * fields of the *park* structure (not preq) and acts as an interlock
22884d9c625SLionel Sambuc * in cv operations. The lock is always internal to this module and
22984d9c625SLionel Sambuc * callers do not need to worry about it.
23084d9c625SLionel Sambuc */
23184d9c625SLionel Sambuc
23284d9c625SLionel Sambuc int
puffs_msgmem_alloc(size_t len,struct puffs_msgpark ** ppark,void ** mem,int cansleep)23384d9c625SLionel Sambuc puffs_msgmem_alloc(size_t len, struct puffs_msgpark **ppark, void **mem,
23484d9c625SLionel Sambuc int cansleep)
23584d9c625SLionel Sambuc {
23684d9c625SLionel Sambuc struct puffs_msgpark *park;
23784d9c625SLionel Sambuc void *m;
23884d9c625SLionel Sambuc
23984d9c625SLionel Sambuc KASSERT(curlwp != uvm.pagedaemon_lwp || !cansleep);
24084d9c625SLionel Sambuc m = kmem_zalloc(len, cansleep ? KM_SLEEP : KM_NOSLEEP);
24184d9c625SLionel Sambuc if (m == NULL) {
24284d9c625SLionel Sambuc KASSERT(cansleep == 0);
24384d9c625SLionel Sambuc return ENOMEM;
24484d9c625SLionel Sambuc }
24584d9c625SLionel Sambuc
24684d9c625SLionel Sambuc park = puffs_msgpark_alloc(cansleep);
24784d9c625SLionel Sambuc if (park == NULL) {
24884d9c625SLionel Sambuc KASSERT(cansleep == 0);
24984d9c625SLionel Sambuc kmem_free(m, len);
25084d9c625SLionel Sambuc return ENOMEM;
25184d9c625SLionel Sambuc }
25284d9c625SLionel Sambuc
25384d9c625SLionel Sambuc park->park_preq = m;
25484d9c625SLionel Sambuc park->park_maxlen = park->park_copylen = len;
25584d9c625SLionel Sambuc
25684d9c625SLionel Sambuc *ppark = park;
25784d9c625SLionel Sambuc *mem = m;
25884d9c625SLionel Sambuc
25984d9c625SLionel Sambuc return 0;
26084d9c625SLionel Sambuc }
26184d9c625SLionel Sambuc
26284d9c625SLionel Sambuc void
puffs_msgmem_release(struct puffs_msgpark * park)26384d9c625SLionel Sambuc puffs_msgmem_release(struct puffs_msgpark *park)
26484d9c625SLionel Sambuc {
26584d9c625SLionel Sambuc
26684d9c625SLionel Sambuc if (park == NULL)
26784d9c625SLionel Sambuc return;
26884d9c625SLionel Sambuc
26984d9c625SLionel Sambuc mutex_enter(&park->park_mtx);
27084d9c625SLionel Sambuc puffs_msgpark_release(park);
27184d9c625SLionel Sambuc }
27284d9c625SLionel Sambuc
27384d9c625SLionel Sambuc void
puffs_msg_setfaf(struct puffs_msgpark * park)27484d9c625SLionel Sambuc puffs_msg_setfaf(struct puffs_msgpark *park)
27584d9c625SLionel Sambuc {
27684d9c625SLionel Sambuc
27784d9c625SLionel Sambuc KASSERT((park->park_flags & PARKFLAG_CALL) == 0);
27884d9c625SLionel Sambuc park->park_flags &= ~PARKFLAG_WANTREPLY;
27984d9c625SLionel Sambuc }
28084d9c625SLionel Sambuc
28184d9c625SLionel Sambuc void
puffs_msg_setdelta(struct puffs_msgpark * park,size_t delta)28284d9c625SLionel Sambuc puffs_msg_setdelta(struct puffs_msgpark *park, size_t delta)
28384d9c625SLionel Sambuc {
28484d9c625SLionel Sambuc
28584d9c625SLionel Sambuc KASSERT(delta < park->park_maxlen); /* "<=" wouldn't make sense */
28684d9c625SLionel Sambuc park->park_copylen = park->park_maxlen - delta;
28784d9c625SLionel Sambuc }
28884d9c625SLionel Sambuc
28984d9c625SLionel Sambuc void
puffs_msg_setinfo(struct puffs_msgpark * park,int opclass,int type,puffs_cookie_t ck)290*0a6a1f1dSLionel Sambuc puffs_msg_setinfo(struct puffs_msgpark *park, int opclass, int type,
29184d9c625SLionel Sambuc puffs_cookie_t ck)
29284d9c625SLionel Sambuc {
29384d9c625SLionel Sambuc
294*0a6a1f1dSLionel Sambuc park->park_preq->preq_opclass = PUFFSOP_OPCLASS(opclass);
29584d9c625SLionel Sambuc park->park_preq->preq_optype = type;
29684d9c625SLionel Sambuc park->park_preq->preq_cookie = ck;
29784d9c625SLionel Sambuc }
29884d9c625SLionel Sambuc
29984d9c625SLionel Sambuc void
puffs_msg_setcall(struct puffs_msgpark * park,parkdone_fn donefn,void * donearg)30084d9c625SLionel Sambuc puffs_msg_setcall(struct puffs_msgpark *park, parkdone_fn donefn, void *donearg)
30184d9c625SLionel Sambuc {
30284d9c625SLionel Sambuc
30384d9c625SLionel Sambuc KASSERT(park->park_flags & PARKFLAG_WANTREPLY);
30484d9c625SLionel Sambuc park->park_done = donefn;
30584d9c625SLionel Sambuc park->park_donearg = donearg;
30684d9c625SLionel Sambuc park->park_flags |= PARKFLAG_CALL;
30784d9c625SLionel Sambuc }
30884d9c625SLionel Sambuc
30984d9c625SLionel Sambuc /*
31084d9c625SLionel Sambuc * kernel-user-kernel waitqueues
31184d9c625SLionel Sambuc */
31284d9c625SLionel Sambuc
31384d9c625SLionel Sambuc static uint64_t
puffs_getmsgid(struct puffs_mount * pmp)31484d9c625SLionel Sambuc puffs_getmsgid(struct puffs_mount *pmp)
31584d9c625SLionel Sambuc {
31684d9c625SLionel Sambuc uint64_t rv;
31784d9c625SLionel Sambuc
31884d9c625SLionel Sambuc mutex_enter(&pmp->pmp_lock);
31984d9c625SLionel Sambuc rv = pmp->pmp_nextmsgid++;
32084d9c625SLionel Sambuc mutex_exit(&pmp->pmp_lock);
32184d9c625SLionel Sambuc
32284d9c625SLionel Sambuc return rv;
32384d9c625SLionel Sambuc }
32484d9c625SLionel Sambuc
32584d9c625SLionel Sambuc /*
32684d9c625SLionel Sambuc * A word about reference counting of parks. A reference must be taken
32784d9c625SLionel Sambuc * when accessing a park and additionally when it is on a queue. So
32884d9c625SLionel Sambuc * when taking it off a queue and releasing the access reference, the
32984d9c625SLionel Sambuc * reference count is generally decremented by 2.
33084d9c625SLionel Sambuc */
33184d9c625SLionel Sambuc
33284d9c625SLionel Sambuc void
puffs_msg_enqueue(struct puffs_mount * pmp,struct puffs_msgpark * park)33384d9c625SLionel Sambuc puffs_msg_enqueue(struct puffs_mount *pmp, struct puffs_msgpark *park)
33484d9c625SLionel Sambuc {
33584d9c625SLionel Sambuc struct lwp *l = curlwp;
33684d9c625SLionel Sambuc struct puffs_req *preq, *creq;
33784d9c625SLionel Sambuc ssize_t delta;
33884d9c625SLionel Sambuc
33984d9c625SLionel Sambuc /*
34084d9c625SLionel Sambuc * Some clients reuse a park, so reset some flags. We might
34184d9c625SLionel Sambuc * want to provide a caller-side interface for this and add
34284d9c625SLionel Sambuc * a few more invariant checks here, but this will do for now.
34384d9c625SLionel Sambuc */
34484d9c625SLionel Sambuc park->park_flags &= ~(PARKFLAG_DONE | PARKFLAG_HASERROR);
34584d9c625SLionel Sambuc KASSERT((park->park_flags & PARKFLAG_WAITERGONE) == 0);
34684d9c625SLionel Sambuc
34784d9c625SLionel Sambuc preq = park->park_preq;
34884d9c625SLionel Sambuc
34984d9c625SLionel Sambuc #if 1
35084d9c625SLionel Sambuc /* check if we do compat adjustments */
35184d9c625SLionel Sambuc if (pmp->pmp_docompat && puffs_compat_outgoing(preq, &creq, &delta)) {
35284d9c625SLionel Sambuc park->park_creq = park->park_preq;
35384d9c625SLionel Sambuc park->park_creqlen = park->park_maxlen;
35484d9c625SLionel Sambuc
35584d9c625SLionel Sambuc park->park_maxlen += delta;
35684d9c625SLionel Sambuc park->park_copylen += delta;
35784d9c625SLionel Sambuc park->park_preq = preq = creq;
35884d9c625SLionel Sambuc }
35984d9c625SLionel Sambuc #endif
36084d9c625SLionel Sambuc
36184d9c625SLionel Sambuc preq->preq_buflen = park->park_maxlen;
36284d9c625SLionel Sambuc KASSERT(preq->preq_id == 0
36384d9c625SLionel Sambuc || (preq->preq_opclass & PUFFSOPFLAG_ISRESPONSE));
36484d9c625SLionel Sambuc
36584d9c625SLionel Sambuc if ((park->park_flags & PARKFLAG_WANTREPLY) == 0)
36684d9c625SLionel Sambuc preq->preq_opclass |= PUFFSOPFLAG_FAF;
36784d9c625SLionel Sambuc else
36884d9c625SLionel Sambuc preq->preq_id = puffs_getmsgid(pmp);
36984d9c625SLionel Sambuc
37084d9c625SLionel Sambuc /* fill in caller information */
37184d9c625SLionel Sambuc preq->preq_pid = l->l_proc->p_pid;
37284d9c625SLionel Sambuc preq->preq_lid = l->l_lid;
37384d9c625SLionel Sambuc
37484d9c625SLionel Sambuc /*
37584d9c625SLionel Sambuc * To support cv_sig, yet another movie: check if there are signals
37684d9c625SLionel Sambuc * pending and we are issueing a non-FAF. If so, return an error
37784d9c625SLionel Sambuc * directly UNLESS we are issueing INACTIVE/RECLAIM. In that case,
37884d9c625SLionel Sambuc * convert it to a FAF, fire off to the file server and return
37984d9c625SLionel Sambuc * an error. Yes, this is bordering disgusting. Barfbags are on me.
38084d9c625SLionel Sambuc */
38184d9c625SLionel Sambuc if (__predict_false((park->park_flags & PARKFLAG_WANTREPLY)
38284d9c625SLionel Sambuc && (park->park_flags & PARKFLAG_CALL) == 0
38384d9c625SLionel Sambuc && (l->l_flag & LW_PENDSIG) != 0 && sigispending(l, 0))) {
38484d9c625SLionel Sambuc sigset_t ss;
38584d9c625SLionel Sambuc
38684d9c625SLionel Sambuc /*
38784d9c625SLionel Sambuc * see the comment about signals in puffs_msg_wait.
38884d9c625SLionel Sambuc */
38984d9c625SLionel Sambuc sigpending1(l, &ss);
39084d9c625SLionel Sambuc if (sigismember(&ss, SIGINT) ||
39184d9c625SLionel Sambuc sigismember(&ss, SIGTERM) ||
39284d9c625SLionel Sambuc sigismember(&ss, SIGKILL) ||
39384d9c625SLionel Sambuc sigismember(&ss, SIGHUP) ||
39484d9c625SLionel Sambuc sigismember(&ss, SIGQUIT)) {
39584d9c625SLionel Sambuc park->park_flags |= PARKFLAG_HASERROR;
39684d9c625SLionel Sambuc preq->preq_rv = EINTR;
39784d9c625SLionel Sambuc if (PUFFSOP_OPCLASS(preq->preq_opclass) == PUFFSOP_VN
39884d9c625SLionel Sambuc && (preq->preq_optype == PUFFS_VN_INACTIVE
39984d9c625SLionel Sambuc || preq->preq_optype == PUFFS_VN_RECLAIM)) {
40084d9c625SLionel Sambuc park->park_preq->preq_opclass |=
40184d9c625SLionel Sambuc PUFFSOPFLAG_FAF;
40284d9c625SLionel Sambuc park->park_flags &= ~PARKFLAG_WANTREPLY;
40384d9c625SLionel Sambuc DPRINTF(("puffs_msg_enqueue: "
40484d9c625SLionel Sambuc "converted to FAF %p\n", park));
40584d9c625SLionel Sambuc } else {
40684d9c625SLionel Sambuc return;
40784d9c625SLionel Sambuc }
40884d9c625SLionel Sambuc }
40984d9c625SLionel Sambuc }
41084d9c625SLionel Sambuc
41184d9c625SLionel Sambuc mutex_enter(&pmp->pmp_lock);
41284d9c625SLionel Sambuc if (pmp->pmp_status != PUFFSTAT_RUNNING) {
41384d9c625SLionel Sambuc mutex_exit(&pmp->pmp_lock);
41484d9c625SLionel Sambuc park->park_flags |= PARKFLAG_HASERROR;
41584d9c625SLionel Sambuc preq->preq_rv = ENXIO;
41684d9c625SLionel Sambuc return;
41784d9c625SLionel Sambuc }
41884d9c625SLionel Sambuc
41984d9c625SLionel Sambuc #ifdef PUFFSDEBUG
42084d9c625SLionel Sambuc parkqdump(&pmp->pmp_msg_touser, puffsdebug > 1);
42184d9c625SLionel Sambuc parkqdump(&pmp->pmp_msg_replywait, puffsdebug > 1);
42284d9c625SLionel Sambuc #endif
42384d9c625SLionel Sambuc
42484d9c625SLionel Sambuc /*
42584d9c625SLionel Sambuc * Note: we don't need to lock park since we have the only
42684d9c625SLionel Sambuc * reference to it at this point.
42784d9c625SLionel Sambuc */
42884d9c625SLionel Sambuc TAILQ_INSERT_TAIL(&pmp->pmp_msg_touser, park, park_entries);
42984d9c625SLionel Sambuc park->park_flags |= PARKFLAG_ONQUEUE1;
43084d9c625SLionel Sambuc pmp->pmp_msg_touser_count++;
43184d9c625SLionel Sambuc park->park_refcount++;
43284d9c625SLionel Sambuc mutex_exit(&pmp->pmp_lock);
43384d9c625SLionel Sambuc
43484d9c625SLionel Sambuc cv_broadcast(&pmp->pmp_msg_waiter_cv);
43584d9c625SLionel Sambuc putter_notify(pmp->pmp_pi);
43684d9c625SLionel Sambuc
43784d9c625SLionel Sambuc DPRINTF(("touser: req %" PRIu64 ", preq: %p, park: %p, "
43884d9c625SLionel Sambuc "c/t: 0x%x/0x%x, f: 0x%x\n", preq->preq_id, preq, park,
43984d9c625SLionel Sambuc preq->preq_opclass, preq->preq_optype, park->park_flags));
44084d9c625SLionel Sambuc }
44184d9c625SLionel Sambuc
44284d9c625SLionel Sambuc int
puffs_msg_wait(struct puffs_mount * pmp,struct puffs_msgpark * park)44384d9c625SLionel Sambuc puffs_msg_wait(struct puffs_mount *pmp, struct puffs_msgpark *park)
44484d9c625SLionel Sambuc {
44584d9c625SLionel Sambuc lwp_t *l = curlwp;
44684d9c625SLionel Sambuc proc_t *p = l->l_proc;
44784d9c625SLionel Sambuc struct puffs_req *preq = park->park_preq; /* XXX: hmmm */
44884d9c625SLionel Sambuc sigset_t ss;
44984d9c625SLionel Sambuc sigset_t oss;
45084d9c625SLionel Sambuc int error = 0;
45184d9c625SLionel Sambuc int rv;
45284d9c625SLionel Sambuc
45384d9c625SLionel Sambuc /*
45484d9c625SLionel Sambuc * block unimportant signals.
45584d9c625SLionel Sambuc *
45684d9c625SLionel Sambuc * The set of "important" signals here was chosen to be same as
45784d9c625SLionel Sambuc * nfs interruptible mount.
45884d9c625SLionel Sambuc */
45984d9c625SLionel Sambuc sigfillset(&ss);
46084d9c625SLionel Sambuc sigdelset(&ss, SIGINT);
46184d9c625SLionel Sambuc sigdelset(&ss, SIGTERM);
46284d9c625SLionel Sambuc sigdelset(&ss, SIGKILL);
46384d9c625SLionel Sambuc sigdelset(&ss, SIGHUP);
46484d9c625SLionel Sambuc sigdelset(&ss, SIGQUIT);
46584d9c625SLionel Sambuc mutex_enter(p->p_lock);
46684d9c625SLionel Sambuc sigprocmask1(l, SIG_BLOCK, &ss, &oss);
46784d9c625SLionel Sambuc mutex_exit(p->p_lock);
46884d9c625SLionel Sambuc
46984d9c625SLionel Sambuc mutex_enter(&pmp->pmp_lock);
47084d9c625SLionel Sambuc puffs_mp_reference(pmp);
47184d9c625SLionel Sambuc mutex_exit(&pmp->pmp_lock);
47284d9c625SLionel Sambuc
47384d9c625SLionel Sambuc mutex_enter(&park->park_mtx);
47484d9c625SLionel Sambuc /* did the response beat us to the wait? */
47584d9c625SLionel Sambuc if (__predict_false((park->park_flags & PARKFLAG_DONE)
47684d9c625SLionel Sambuc || (park->park_flags & PARKFLAG_HASERROR))) {
47784d9c625SLionel Sambuc rv = park->park_preq->preq_rv;
47884d9c625SLionel Sambuc mutex_exit(&park->park_mtx);
47984d9c625SLionel Sambuc goto skipwait;
48084d9c625SLionel Sambuc }
48184d9c625SLionel Sambuc
48284d9c625SLionel Sambuc if ((park->park_flags & PARKFLAG_WANTREPLY) == 0
48384d9c625SLionel Sambuc || (park->park_flags & PARKFLAG_CALL)) {
48484d9c625SLionel Sambuc mutex_exit(&park->park_mtx);
48584d9c625SLionel Sambuc rv = 0;
48684d9c625SLionel Sambuc goto skipwait;
48784d9c625SLionel Sambuc }
48884d9c625SLionel Sambuc
48984d9c625SLionel Sambuc error = cv_wait_sig(&park->park_cv, &park->park_mtx);
49084d9c625SLionel Sambuc DPRINTF(("puffs_touser: waiter for %p woke up with %d\n",
49184d9c625SLionel Sambuc park, error));
49284d9c625SLionel Sambuc if (error) {
49384d9c625SLionel Sambuc park->park_flags |= PARKFLAG_WAITERGONE;
49484d9c625SLionel Sambuc if (park->park_flags & PARKFLAG_DONE) {
49584d9c625SLionel Sambuc rv = preq->preq_rv;
49684d9c625SLionel Sambuc mutex_exit(&park->park_mtx);
49784d9c625SLionel Sambuc } else {
49884d9c625SLionel Sambuc /*
49984d9c625SLionel Sambuc * ok, we marked it as going away, but
50084d9c625SLionel Sambuc * still need to do queue ops. take locks
50184d9c625SLionel Sambuc * in correct order.
50284d9c625SLionel Sambuc *
50384d9c625SLionel Sambuc * We don't want to release our reference
50484d9c625SLionel Sambuc * if it's on replywait queue to avoid error
50584d9c625SLionel Sambuc * to file server. putop() code will DTRT.
50684d9c625SLionel Sambuc */
50784d9c625SLionel Sambuc mutex_exit(&park->park_mtx);
50884d9c625SLionel Sambuc mutex_enter(&pmp->pmp_lock);
50984d9c625SLionel Sambuc mutex_enter(&park->park_mtx);
51084d9c625SLionel Sambuc
51184d9c625SLionel Sambuc /*
51284d9c625SLionel Sambuc * Still on queue1? We can safely remove it
51384d9c625SLionel Sambuc * without any consequences since the file
51484d9c625SLionel Sambuc * server hasn't seen it. "else" we need to
51584d9c625SLionel Sambuc * wait for the response and just ignore it
51684d9c625SLionel Sambuc * to avoid signalling an incorrect error to
51784d9c625SLionel Sambuc * the file server.
51884d9c625SLionel Sambuc */
51984d9c625SLionel Sambuc if (park->park_flags & PARKFLAG_ONQUEUE1) {
52084d9c625SLionel Sambuc TAILQ_REMOVE(&pmp->pmp_msg_touser,
52184d9c625SLionel Sambuc park, park_entries);
52284d9c625SLionel Sambuc puffs_msgpark_release(park);
52384d9c625SLionel Sambuc pmp->pmp_msg_touser_count--;
52484d9c625SLionel Sambuc park->park_flags &= ~PARKFLAG_ONQUEUE1;
52584d9c625SLionel Sambuc } else {
52684d9c625SLionel Sambuc mutex_exit(&park->park_mtx);
52784d9c625SLionel Sambuc }
52884d9c625SLionel Sambuc mutex_exit(&pmp->pmp_lock);
52984d9c625SLionel Sambuc
53084d9c625SLionel Sambuc rv = EINTR;
53184d9c625SLionel Sambuc }
53284d9c625SLionel Sambuc } else {
53384d9c625SLionel Sambuc rv = preq->preq_rv;
53484d9c625SLionel Sambuc mutex_exit(&park->park_mtx);
53584d9c625SLionel Sambuc }
53684d9c625SLionel Sambuc
53784d9c625SLionel Sambuc skipwait:
53884d9c625SLionel Sambuc mutex_enter(&pmp->pmp_lock);
53984d9c625SLionel Sambuc puffs_mp_release(pmp);
54084d9c625SLionel Sambuc mutex_exit(&pmp->pmp_lock);
54184d9c625SLionel Sambuc
54284d9c625SLionel Sambuc mutex_enter(p->p_lock);
54384d9c625SLionel Sambuc sigprocmask1(l, SIG_SETMASK, &oss, NULL);
54484d9c625SLionel Sambuc mutex_exit(p->p_lock);
54584d9c625SLionel Sambuc
54684d9c625SLionel Sambuc return rv;
54784d9c625SLionel Sambuc }
54884d9c625SLionel Sambuc
54984d9c625SLionel Sambuc /*
55084d9c625SLionel Sambuc * XXX: this suuuucks. Hopefully I'll get rid of this lossage once
55184d9c625SLionel Sambuc * the whole setback-nonsense gets fixed.
55284d9c625SLionel Sambuc */
55384d9c625SLionel Sambuc int
puffs_msg_wait2(struct puffs_mount * pmp,struct puffs_msgpark * park,struct puffs_node * pn1,struct puffs_node * pn2)55484d9c625SLionel Sambuc puffs_msg_wait2(struct puffs_mount *pmp, struct puffs_msgpark *park,
55584d9c625SLionel Sambuc struct puffs_node *pn1, struct puffs_node *pn2)
55684d9c625SLionel Sambuc {
55784d9c625SLionel Sambuc struct puffs_req *preq;
55884d9c625SLionel Sambuc int rv;
55984d9c625SLionel Sambuc
56084d9c625SLionel Sambuc rv = puffs_msg_wait(pmp, park);
56184d9c625SLionel Sambuc
56284d9c625SLionel Sambuc preq = park->park_preq;
56384d9c625SLionel Sambuc if (pn1 && preq->preq_setbacks & PUFFS_SETBACK_INACT_N1)
56484d9c625SLionel Sambuc pn1->pn_stat |= PNODE_DOINACT;
56584d9c625SLionel Sambuc if (pn2 && preq->preq_setbacks & PUFFS_SETBACK_INACT_N2)
56684d9c625SLionel Sambuc pn2->pn_stat |= PNODE_DOINACT;
56784d9c625SLionel Sambuc
56884d9c625SLionel Sambuc if (pn1 && preq->preq_setbacks & PUFFS_SETBACK_NOREF_N1)
56984d9c625SLionel Sambuc pn1->pn_stat |= PNODE_NOREFS;
57084d9c625SLionel Sambuc if (pn2 && preq->preq_setbacks & PUFFS_SETBACK_NOREF_N2)
57184d9c625SLionel Sambuc pn2->pn_stat |= PNODE_NOREFS;
57284d9c625SLionel Sambuc
57384d9c625SLionel Sambuc return rv;
57484d9c625SLionel Sambuc
57584d9c625SLionel Sambuc }
57684d9c625SLionel Sambuc
57784d9c625SLionel Sambuc /*
57884d9c625SLionel Sambuc * XXX: lazy bum. please, for the love of foie gras, fix me.
57984d9c625SLionel Sambuc * This should *NOT* depend on setfaf. Also "memcpy" could
58084d9c625SLionel Sambuc * be done more nicely.
58184d9c625SLionel Sambuc */
58284d9c625SLionel Sambuc void
puffs_msg_sendresp(struct puffs_mount * pmp,struct puffs_req * origpreq,int rv)58384d9c625SLionel Sambuc puffs_msg_sendresp(struct puffs_mount *pmp, struct puffs_req *origpreq, int rv)
58484d9c625SLionel Sambuc {
58584d9c625SLionel Sambuc struct puffs_msgpark *park;
58684d9c625SLionel Sambuc struct puffs_req *preq;
58784d9c625SLionel Sambuc
58884d9c625SLionel Sambuc puffs_msgmem_alloc(sizeof(struct puffs_req), &park, (void *)&preq, 1);
58984d9c625SLionel Sambuc puffs_msg_setfaf(park); /* XXXXXX: avoids reqid override */
59084d9c625SLionel Sambuc
59184d9c625SLionel Sambuc memcpy(preq, origpreq, sizeof(struct puffs_req));
59284d9c625SLionel Sambuc preq->preq_rv = rv;
59384d9c625SLionel Sambuc preq->preq_opclass |= PUFFSOPFLAG_ISRESPONSE;
59484d9c625SLionel Sambuc
59584d9c625SLionel Sambuc puffs_msg_enqueue(pmp, park);
59684d9c625SLionel Sambuc puffs_msgmem_release(park);
59784d9c625SLionel Sambuc }
59884d9c625SLionel Sambuc
59984d9c625SLionel Sambuc /*
60084d9c625SLionel Sambuc * Get next request in the outgoing queue. "maxsize" controls the
60184d9c625SLionel Sambuc * size the caller can accommodate and "nonblock" signals if this
60284d9c625SLionel Sambuc * should block while waiting for input. Handles all locking internally.
60384d9c625SLionel Sambuc */
60484d9c625SLionel Sambuc int
puffs_msgif_getout(void * ctx,size_t maxsize,int nonblock,uint8_t ** data,size_t * dlen,void ** parkptr)605*0a6a1f1dSLionel Sambuc puffs_msgif_getout(void *ctx, size_t maxsize, int nonblock,
60684d9c625SLionel Sambuc uint8_t **data, size_t *dlen, void **parkptr)
60784d9c625SLionel Sambuc {
608*0a6a1f1dSLionel Sambuc struct puffs_mount *pmp = ctx;
60984d9c625SLionel Sambuc struct puffs_msgpark *park = NULL;
61084d9c625SLionel Sambuc struct puffs_req *preq = NULL;
61184d9c625SLionel Sambuc int error;
61284d9c625SLionel Sambuc
61384d9c625SLionel Sambuc error = 0;
61484d9c625SLionel Sambuc mutex_enter(&pmp->pmp_lock);
61584d9c625SLionel Sambuc puffs_mp_reference(pmp);
61684d9c625SLionel Sambuc for (;;) {
61784d9c625SLionel Sambuc /* RIP? */
61884d9c625SLionel Sambuc if (pmp->pmp_status != PUFFSTAT_RUNNING) {
61984d9c625SLionel Sambuc error = ENXIO;
62084d9c625SLionel Sambuc break;
62184d9c625SLionel Sambuc }
62284d9c625SLionel Sambuc
62384d9c625SLionel Sambuc /* need platinum yendorian express card? */
62484d9c625SLionel Sambuc if (TAILQ_EMPTY(&pmp->pmp_msg_touser)) {
62584d9c625SLionel Sambuc DPRINTF(("puffs_getout: no outgoing op, "));
62684d9c625SLionel Sambuc if (nonblock) {
62784d9c625SLionel Sambuc DPRINTF(("returning EWOULDBLOCK\n"));
62884d9c625SLionel Sambuc error = EWOULDBLOCK;
62984d9c625SLionel Sambuc break;
63084d9c625SLionel Sambuc }
63184d9c625SLionel Sambuc DPRINTF(("waiting ...\n"));
63284d9c625SLionel Sambuc
63384d9c625SLionel Sambuc error = cv_wait_sig(&pmp->pmp_msg_waiter_cv,
63484d9c625SLionel Sambuc &pmp->pmp_lock);
63584d9c625SLionel Sambuc if (error)
63684d9c625SLionel Sambuc break;
63784d9c625SLionel Sambuc else
63884d9c625SLionel Sambuc continue;
63984d9c625SLionel Sambuc }
64084d9c625SLionel Sambuc
64184d9c625SLionel Sambuc park = TAILQ_FIRST(&pmp->pmp_msg_touser);
64284d9c625SLionel Sambuc if (park == NULL)
64384d9c625SLionel Sambuc continue;
64484d9c625SLionel Sambuc
64584d9c625SLionel Sambuc mutex_enter(&park->park_mtx);
64684d9c625SLionel Sambuc puffs_msgpark_reference(park);
64784d9c625SLionel Sambuc
64884d9c625SLionel Sambuc DPRINTF(("puffs_getout: found park at %p, ", park));
64984d9c625SLionel Sambuc
65084d9c625SLionel Sambuc /* If it's a goner, don't process any furher */
65184d9c625SLionel Sambuc if (park->park_flags & PARKFLAG_WAITERGONE) {
65284d9c625SLionel Sambuc DPRINTF(("waitergone!\n"));
65384d9c625SLionel Sambuc puffs_msgpark_release(park);
65484d9c625SLionel Sambuc continue;
65584d9c625SLionel Sambuc }
65684d9c625SLionel Sambuc preq = park->park_preq;
65784d9c625SLionel Sambuc
65884d9c625SLionel Sambuc #if 0
65984d9c625SLionel Sambuc /* check size */
66084d9c625SLionel Sambuc /*
66184d9c625SLionel Sambuc * XXX: this check is not valid for now, we don't know
66284d9c625SLionel Sambuc * the size of the caller's input buffer. i.e. this
66384d9c625SLionel Sambuc * will most likely go away
66484d9c625SLionel Sambuc */
66584d9c625SLionel Sambuc if (maxsize < preq->preq_frhdr.pfr_len) {
66684d9c625SLionel Sambuc DPRINTF(("buffer too small\n"));
66784d9c625SLionel Sambuc puffs_msgpark_release(park);
66884d9c625SLionel Sambuc error = E2BIG;
66984d9c625SLionel Sambuc break;
67084d9c625SLionel Sambuc }
67184d9c625SLionel Sambuc #endif
67284d9c625SLionel Sambuc
67384d9c625SLionel Sambuc DPRINTF(("returning\n"));
67484d9c625SLionel Sambuc
67584d9c625SLionel Sambuc /*
67684d9c625SLionel Sambuc * Ok, we found what we came for. Release it from the
67784d9c625SLionel Sambuc * outgoing queue but do not unlock. We will unlock
67884d9c625SLionel Sambuc * only after we "releaseout" it to avoid complications:
67984d9c625SLionel Sambuc * otherwise it is (theoretically) possible for userland
68084d9c625SLionel Sambuc * to race us into "put" before we have a change to put
68184d9c625SLionel Sambuc * this baby on the receiving queue.
68284d9c625SLionel Sambuc */
68384d9c625SLionel Sambuc TAILQ_REMOVE(&pmp->pmp_msg_touser, park, park_entries);
68484d9c625SLionel Sambuc KASSERT(park->park_flags & PARKFLAG_ONQUEUE1);
68584d9c625SLionel Sambuc park->park_flags &= ~PARKFLAG_ONQUEUE1;
68684d9c625SLionel Sambuc mutex_exit(&park->park_mtx);
68784d9c625SLionel Sambuc
68884d9c625SLionel Sambuc pmp->pmp_msg_touser_count--;
68984d9c625SLionel Sambuc KASSERT(pmp->pmp_msg_touser_count >= 0);
69084d9c625SLionel Sambuc
69184d9c625SLionel Sambuc break;
69284d9c625SLionel Sambuc }
69384d9c625SLionel Sambuc puffs_mp_release(pmp);
69484d9c625SLionel Sambuc mutex_exit(&pmp->pmp_lock);
69584d9c625SLionel Sambuc
69684d9c625SLionel Sambuc if (error == 0) {
69784d9c625SLionel Sambuc *data = (uint8_t *)preq;
69884d9c625SLionel Sambuc preq->preq_pth.pth_framelen = park->park_copylen;
69984d9c625SLionel Sambuc *dlen = preq->preq_pth.pth_framelen;
70084d9c625SLionel Sambuc *parkptr = park;
70184d9c625SLionel Sambuc }
70284d9c625SLionel Sambuc
70384d9c625SLionel Sambuc return error;
70484d9c625SLionel Sambuc }
70584d9c625SLionel Sambuc
70684d9c625SLionel Sambuc /*
70784d9c625SLionel Sambuc * Release outgoing structure. Now, depending on the success of the
70884d9c625SLionel Sambuc * outgoing send, it is either going onto the result waiting queue
70984d9c625SLionel Sambuc * or the death chamber.
71084d9c625SLionel Sambuc */
71184d9c625SLionel Sambuc void
puffs_msgif_releaseout(void * ctx,void * parkptr,int status)712*0a6a1f1dSLionel Sambuc puffs_msgif_releaseout(void *ctx, void *parkptr, int status)
71384d9c625SLionel Sambuc {
714*0a6a1f1dSLionel Sambuc struct puffs_mount *pmp = ctx;
71584d9c625SLionel Sambuc struct puffs_msgpark *park = parkptr;
71684d9c625SLionel Sambuc
71784d9c625SLionel Sambuc DPRINTF(("puffs_releaseout: returning park %p, errno %d: " ,
71884d9c625SLionel Sambuc park, status));
71984d9c625SLionel Sambuc mutex_enter(&pmp->pmp_lock);
72084d9c625SLionel Sambuc mutex_enter(&park->park_mtx);
72184d9c625SLionel Sambuc if (park->park_flags & PARKFLAG_WANTREPLY) {
72284d9c625SLionel Sambuc if (status == 0) {
72384d9c625SLionel Sambuc DPRINTF(("enqueue replywait\n"));
72484d9c625SLionel Sambuc TAILQ_INSERT_TAIL(&pmp->pmp_msg_replywait, park,
72584d9c625SLionel Sambuc park_entries);
72684d9c625SLionel Sambuc park->park_flags |= PARKFLAG_ONQUEUE2;
72784d9c625SLionel Sambuc } else {
72884d9c625SLionel Sambuc DPRINTF(("error path!\n"));
72984d9c625SLionel Sambuc park->park_preq->preq_rv = status;
73084d9c625SLionel Sambuc park->park_flags |= PARKFLAG_DONE;
73184d9c625SLionel Sambuc cv_signal(&park->park_cv);
73284d9c625SLionel Sambuc }
73384d9c625SLionel Sambuc puffs_msgpark_release(park);
73484d9c625SLionel Sambuc } else {
73584d9c625SLionel Sambuc DPRINTF(("release\n"));
73684d9c625SLionel Sambuc puffs_msgpark_release1(park, 2);
73784d9c625SLionel Sambuc }
73884d9c625SLionel Sambuc mutex_exit(&pmp->pmp_lock);
73984d9c625SLionel Sambuc }
74084d9c625SLionel Sambuc
74184d9c625SLionel Sambuc size_t
puffs_msgif_waitcount(void * ctx)742*0a6a1f1dSLionel Sambuc puffs_msgif_waitcount(void *ctx)
74384d9c625SLionel Sambuc {
744*0a6a1f1dSLionel Sambuc struct puffs_mount *pmp = ctx;
74584d9c625SLionel Sambuc size_t rv;
74684d9c625SLionel Sambuc
74784d9c625SLionel Sambuc mutex_enter(&pmp->pmp_lock);
74884d9c625SLionel Sambuc rv = pmp->pmp_msg_touser_count;
74984d9c625SLionel Sambuc mutex_exit(&pmp->pmp_lock);
75084d9c625SLionel Sambuc
75184d9c625SLionel Sambuc return rv;
75284d9c625SLionel Sambuc }
75384d9c625SLionel Sambuc
75484d9c625SLionel Sambuc /*
75584d9c625SLionel Sambuc * XXX: locking with this one?
75684d9c625SLionel Sambuc */
75784d9c625SLionel Sambuc static void
puffsop_msg(void * ctx,struct puffs_req * preq)758*0a6a1f1dSLionel Sambuc puffsop_msg(void *ctx, struct puffs_req *preq)
75984d9c625SLionel Sambuc {
760*0a6a1f1dSLionel Sambuc struct puffs_mount *pmp = ctx;
76184d9c625SLionel Sambuc struct putter_hdr *pth = &preq->preq_pth;
76284d9c625SLionel Sambuc struct puffs_msgpark *park;
76384d9c625SLionel Sambuc int wgone;
76484d9c625SLionel Sambuc
76584d9c625SLionel Sambuc mutex_enter(&pmp->pmp_lock);
76684d9c625SLionel Sambuc
76784d9c625SLionel Sambuc /* Locate waiter */
76884d9c625SLionel Sambuc TAILQ_FOREACH(park, &pmp->pmp_msg_replywait, park_entries) {
76984d9c625SLionel Sambuc if (park->park_preq->preq_id == preq->preq_id)
77084d9c625SLionel Sambuc break;
77184d9c625SLionel Sambuc }
77284d9c625SLionel Sambuc if (park == NULL) {
77384d9c625SLionel Sambuc DPRINTF(("puffsop_msg: no request: %" PRIu64 "\n",
77484d9c625SLionel Sambuc preq->preq_id));
77584d9c625SLionel Sambuc mutex_exit(&pmp->pmp_lock);
77684d9c625SLionel Sambuc return; /* XXX send error */
77784d9c625SLionel Sambuc }
77884d9c625SLionel Sambuc
77984d9c625SLionel Sambuc mutex_enter(&park->park_mtx);
78084d9c625SLionel Sambuc puffs_msgpark_reference(park);
78184d9c625SLionel Sambuc if (pth->pth_framelen > park->park_maxlen) {
78284d9c625SLionel Sambuc DPRINTF(("puffsop_msg: invalid buffer length: "
78384d9c625SLionel Sambuc "%" PRIu64 " (req %" PRIu64 ", \n", pth->pth_framelen,
78484d9c625SLionel Sambuc preq->preq_id));
78584d9c625SLionel Sambuc park->park_preq->preq_rv = EPROTO;
78684d9c625SLionel Sambuc cv_signal(&park->park_cv);
78784d9c625SLionel Sambuc puffs_msgpark_release1(park, 2);
78884d9c625SLionel Sambuc mutex_exit(&pmp->pmp_lock);
78984d9c625SLionel Sambuc return; /* XXX: error */
79084d9c625SLionel Sambuc }
79184d9c625SLionel Sambuc wgone = park->park_flags & PARKFLAG_WAITERGONE;
79284d9c625SLionel Sambuc
79384d9c625SLionel Sambuc KASSERT(park->park_flags & PARKFLAG_ONQUEUE2);
79484d9c625SLionel Sambuc TAILQ_REMOVE(&pmp->pmp_msg_replywait, park, park_entries);
79584d9c625SLionel Sambuc park->park_flags &= ~PARKFLAG_ONQUEUE2;
79684d9c625SLionel Sambuc mutex_exit(&pmp->pmp_lock);
79784d9c625SLionel Sambuc
79884d9c625SLionel Sambuc if (wgone) {
79984d9c625SLionel Sambuc DPRINTF(("puffsop_msg: bad service - waiter gone for "
80084d9c625SLionel Sambuc "park %p\n", park));
80184d9c625SLionel Sambuc } else {
80284d9c625SLionel Sambuc #if 1
80384d9c625SLionel Sambuc if (park->park_creq) {
80484d9c625SLionel Sambuc struct puffs_req *creq;
80584d9c625SLionel Sambuc size_t csize;
80684d9c625SLionel Sambuc
80784d9c625SLionel Sambuc KASSERT(pmp->pmp_docompat);
80884d9c625SLionel Sambuc puffs_compat_incoming(preq, park->park_creq);
80984d9c625SLionel Sambuc creq = park->park_creq;
81084d9c625SLionel Sambuc csize = park->park_creqlen;
81184d9c625SLionel Sambuc park->park_creq = park->park_preq;
81284d9c625SLionel Sambuc park->park_creqlen = park->park_maxlen;
81384d9c625SLionel Sambuc
81484d9c625SLionel Sambuc park->park_preq = creq;
81584d9c625SLionel Sambuc park->park_maxlen = csize;
81684d9c625SLionel Sambuc
81784d9c625SLionel Sambuc memcpy(park->park_creq, preq, pth->pth_framelen);
81884d9c625SLionel Sambuc } else {
81984d9c625SLionel Sambuc #endif
82084d9c625SLionel Sambuc memcpy(park->park_preq, preq, pth->pth_framelen);
82184d9c625SLionel Sambuc }
82284d9c625SLionel Sambuc
82384d9c625SLionel Sambuc if (park->park_flags & PARKFLAG_CALL) {
82484d9c625SLionel Sambuc DPRINTF(("puffsop_msg: call for %p, arg %p\n",
82584d9c625SLionel Sambuc park->park_preq, park->park_donearg));
82684d9c625SLionel Sambuc park->park_done(pmp, preq, park->park_donearg);
82784d9c625SLionel Sambuc }
82884d9c625SLionel Sambuc }
82984d9c625SLionel Sambuc
83084d9c625SLionel Sambuc if (!wgone) {
83184d9c625SLionel Sambuc DPRINTF(("puffs_putop: flagging done for "
83284d9c625SLionel Sambuc "park %p\n", park));
83384d9c625SLionel Sambuc cv_signal(&park->park_cv);
83484d9c625SLionel Sambuc }
83584d9c625SLionel Sambuc
83684d9c625SLionel Sambuc park->park_flags |= PARKFLAG_DONE;
83784d9c625SLionel Sambuc puffs_msgpark_release1(park, 2);
83884d9c625SLionel Sambuc }
83984d9c625SLionel Sambuc
84084d9c625SLionel Sambuc /*
84184d9c625SLionel Sambuc * Node expiry. We come here after an inactive on an unexpired node.
84284d9c625SLionel Sambuc * The expiry has been queued and is done in sop thread.
84384d9c625SLionel Sambuc */
84484d9c625SLionel Sambuc static void
puffsop_expire(struct puffs_mount * pmp,puffs_cookie_t cookie)84584d9c625SLionel Sambuc puffsop_expire(struct puffs_mount *pmp, puffs_cookie_t cookie)
84684d9c625SLionel Sambuc {
84784d9c625SLionel Sambuc struct vnode *vp;
84884d9c625SLionel Sambuc
84984d9c625SLionel Sambuc KASSERT(PUFFS_USE_FS_TTL(pmp));
85084d9c625SLionel Sambuc
85184d9c625SLionel Sambuc /*
85284d9c625SLionel Sambuc * If it still exists and has no reference,
85384d9c625SLionel Sambuc * vrele should cause it to be reclaimed.
85484d9c625SLionel Sambuc * Otherwise, we have nothing to do.
85584d9c625SLionel Sambuc */
856*0a6a1f1dSLionel Sambuc if (puffs_cookie2vnode(pmp, cookie, &vp) == 0) {
85784d9c625SLionel Sambuc VPTOPP(vp)->pn_stat &= ~PNODE_SOPEXP;
85884d9c625SLionel Sambuc vrele(vp);
85984d9c625SLionel Sambuc }
86084d9c625SLionel Sambuc
86184d9c625SLionel Sambuc return;
86284d9c625SLionel Sambuc }
86384d9c625SLionel Sambuc
86484d9c625SLionel Sambuc static void
puffsop_flush(struct puffs_mount * pmp,struct puffs_flush * pf)86584d9c625SLionel Sambuc puffsop_flush(struct puffs_mount *pmp, struct puffs_flush *pf)
86684d9c625SLionel Sambuc {
86784d9c625SLionel Sambuc struct vnode *vp;
86884d9c625SLionel Sambuc voff_t offlo, offhi;
86984d9c625SLionel Sambuc int rv, flags = 0;
87084d9c625SLionel Sambuc
87184d9c625SLionel Sambuc KASSERT(pf->pf_req.preq_pth.pth_framelen == sizeof(struct puffs_flush));
87284d9c625SLionel Sambuc
87384d9c625SLionel Sambuc /* XXX: slurry */
87484d9c625SLionel Sambuc if (pf->pf_op == PUFFS_INVAL_NAMECACHE_ALL) {
87584d9c625SLionel Sambuc cache_purgevfs(PMPTOMP(pmp));
87684d9c625SLionel Sambuc rv = 0;
87784d9c625SLionel Sambuc goto out;
87884d9c625SLionel Sambuc }
87984d9c625SLionel Sambuc
88084d9c625SLionel Sambuc /*
88184d9c625SLionel Sambuc * Get vnode, don't lock it. Namecache is protected by its own lock
88284d9c625SLionel Sambuc * and we have a reference to protect against premature harvesting.
88384d9c625SLionel Sambuc *
88484d9c625SLionel Sambuc * The node we want here might be locked and the op is in
88584d9c625SLionel Sambuc * userspace waiting for us to complete ==> deadlock. Another
88684d9c625SLionel Sambuc * reason we need to eventually bump locking to userspace, as we
88784d9c625SLionel Sambuc * will need to lock the node if we wish to do flushes.
88884d9c625SLionel Sambuc */
889*0a6a1f1dSLionel Sambuc rv = puffs_cookie2vnode(pmp, pf->pf_cookie, &vp);
89084d9c625SLionel Sambuc if (rv) {
89184d9c625SLionel Sambuc if (rv == PUFFS_NOSUCHCOOKIE)
89284d9c625SLionel Sambuc rv = ENOENT;
89384d9c625SLionel Sambuc goto out;
89484d9c625SLionel Sambuc }
89584d9c625SLionel Sambuc
89684d9c625SLionel Sambuc switch (pf->pf_op) {
89784d9c625SLionel Sambuc #if 0
89884d9c625SLionel Sambuc /* not quite ready, yet */
89984d9c625SLionel Sambuc case PUFFS_INVAL_NAMECACHE_NODE:
90084d9c625SLionel Sambuc struct componentname *pf_cn;
90184d9c625SLionel Sambuc char *name;
90284d9c625SLionel Sambuc /* get comfortab^Wcomponentname */
90384d9c625SLionel Sambuc pf_cn = kmem_alloc(componentname);
90484d9c625SLionel Sambuc memset(pf_cn, 0, sizeof(struct componentname));
90584d9c625SLionel Sambuc break;
90684d9c625SLionel Sambuc
90784d9c625SLionel Sambuc #endif
90884d9c625SLionel Sambuc case PUFFS_INVAL_NAMECACHE_DIR:
90984d9c625SLionel Sambuc if (vp->v_type != VDIR) {
91084d9c625SLionel Sambuc rv = EINVAL;
91184d9c625SLionel Sambuc break;
91284d9c625SLionel Sambuc }
91384d9c625SLionel Sambuc cache_purge1(vp, NULL, 0, PURGE_CHILDREN);
91484d9c625SLionel Sambuc break;
91584d9c625SLionel Sambuc
91684d9c625SLionel Sambuc case PUFFS_INVAL_PAGECACHE_NODE_RANGE:
91784d9c625SLionel Sambuc flags = PGO_FREE;
91884d9c625SLionel Sambuc /*FALLTHROUGH*/
91984d9c625SLionel Sambuc case PUFFS_FLUSH_PAGECACHE_NODE_RANGE:
92084d9c625SLionel Sambuc if (flags == 0)
92184d9c625SLionel Sambuc flags = PGO_CLEANIT;
92284d9c625SLionel Sambuc
92384d9c625SLionel Sambuc if (pf->pf_end > vp->v_size || vp->v_type != VREG) {
92484d9c625SLionel Sambuc rv = EINVAL;
92584d9c625SLionel Sambuc break;
92684d9c625SLionel Sambuc }
92784d9c625SLionel Sambuc
92884d9c625SLionel Sambuc offlo = trunc_page(pf->pf_start);
92984d9c625SLionel Sambuc offhi = round_page(pf->pf_end);
93084d9c625SLionel Sambuc if (offhi != 0 && offlo >= offhi) {
93184d9c625SLionel Sambuc rv = EINVAL;
93284d9c625SLionel Sambuc break;
93384d9c625SLionel Sambuc }
93484d9c625SLionel Sambuc
93584d9c625SLionel Sambuc mutex_enter(vp->v_uobj.vmobjlock);
93684d9c625SLionel Sambuc rv = VOP_PUTPAGES(vp, offlo, offhi, flags);
93784d9c625SLionel Sambuc break;
93884d9c625SLionel Sambuc
93984d9c625SLionel Sambuc default:
94084d9c625SLionel Sambuc rv = EINVAL;
94184d9c625SLionel Sambuc }
94284d9c625SLionel Sambuc
94384d9c625SLionel Sambuc vrele(vp);
94484d9c625SLionel Sambuc
94584d9c625SLionel Sambuc out:
94684d9c625SLionel Sambuc puffs_msg_sendresp(pmp, &pf->pf_req, rv);
94784d9c625SLionel Sambuc }
94884d9c625SLionel Sambuc
94984d9c625SLionel Sambuc int
puffs_msgif_dispatch(void * ctx,struct putter_hdr * pth)950*0a6a1f1dSLionel Sambuc puffs_msgif_dispatch(void *ctx, struct putter_hdr *pth)
95184d9c625SLionel Sambuc {
952*0a6a1f1dSLionel Sambuc struct puffs_mount *pmp = ctx;
95384d9c625SLionel Sambuc struct puffs_req *preq = (struct puffs_req *)pth;
95484d9c625SLionel Sambuc struct puffs_sopreq *psopr;
95584d9c625SLionel Sambuc
95684d9c625SLionel Sambuc if (pth->pth_framelen < sizeof(struct puffs_req)) {
95784d9c625SLionel Sambuc puffs_msg_sendresp(pmp, preq, EINVAL); /* E2SMALL */
95884d9c625SLionel Sambuc return 0;
95984d9c625SLionel Sambuc }
96084d9c625SLionel Sambuc
96184d9c625SLionel Sambuc switch (PUFFSOP_OPCLASS(preq->preq_opclass)) {
96284d9c625SLionel Sambuc case PUFFSOP_VN:
96384d9c625SLionel Sambuc case PUFFSOP_VFS:
96484d9c625SLionel Sambuc DPRINTF(("dispatch: vn/vfs message 0x%x\n", preq->preq_optype));
96584d9c625SLionel Sambuc puffsop_msg(pmp, preq);
96684d9c625SLionel Sambuc break;
96784d9c625SLionel Sambuc
96884d9c625SLionel Sambuc case PUFFSOP_FLUSH: /* process in sop thread */
96984d9c625SLionel Sambuc {
97084d9c625SLionel Sambuc struct puffs_flush *pf;
97184d9c625SLionel Sambuc
97284d9c625SLionel Sambuc DPRINTF(("dispatch: flush 0x%x\n", preq->preq_optype));
97384d9c625SLionel Sambuc
97484d9c625SLionel Sambuc if (preq->preq_pth.pth_framelen != sizeof(struct puffs_flush)) {
97584d9c625SLionel Sambuc puffs_msg_sendresp(pmp, preq, EINVAL); /* E2SMALL */
97684d9c625SLionel Sambuc break;
97784d9c625SLionel Sambuc }
97884d9c625SLionel Sambuc pf = (struct puffs_flush *)preq;
97984d9c625SLionel Sambuc
98084d9c625SLionel Sambuc KASSERT(curlwp != uvm.pagedaemon_lwp);
98184d9c625SLionel Sambuc psopr = kmem_alloc(sizeof(*psopr), KM_SLEEP);
98284d9c625SLionel Sambuc memcpy(&psopr->psopr_pf, pf, sizeof(*pf));
98384d9c625SLionel Sambuc psopr->psopr_sopreq = PUFFS_SOPREQ_FLUSH;
98484d9c625SLionel Sambuc
98584d9c625SLionel Sambuc mutex_enter(&pmp->pmp_sopmtx);
98684d9c625SLionel Sambuc if (pmp->pmp_sopthrcount == 0) {
98784d9c625SLionel Sambuc mutex_exit(&pmp->pmp_sopmtx);
98884d9c625SLionel Sambuc kmem_free(psopr, sizeof(*psopr));
98984d9c625SLionel Sambuc puffs_msg_sendresp(pmp, preq, ENXIO);
99084d9c625SLionel Sambuc } else {
99184d9c625SLionel Sambuc TAILQ_INSERT_TAIL(&pmp->pmp_sopfastreqs,
99284d9c625SLionel Sambuc psopr, psopr_entries);
99384d9c625SLionel Sambuc cv_signal(&pmp->pmp_sopcv);
99484d9c625SLionel Sambuc mutex_exit(&pmp->pmp_sopmtx);
99584d9c625SLionel Sambuc }
99684d9c625SLionel Sambuc break;
99784d9c625SLionel Sambuc }
99884d9c625SLionel Sambuc
99984d9c625SLionel Sambuc case PUFFSOP_UNMOUNT: /* process in sop thread */
100084d9c625SLionel Sambuc {
100184d9c625SLionel Sambuc
100284d9c625SLionel Sambuc DPRINTF(("dispatch: unmount 0x%x\n", preq->preq_optype));
100384d9c625SLionel Sambuc
100484d9c625SLionel Sambuc KASSERT(curlwp != uvm.pagedaemon_lwp);
100584d9c625SLionel Sambuc psopr = kmem_alloc(sizeof(*psopr), KM_SLEEP);
100684d9c625SLionel Sambuc psopr->psopr_preq = *preq;
100784d9c625SLionel Sambuc psopr->psopr_sopreq = PUFFS_SOPREQ_UNMOUNT;
100884d9c625SLionel Sambuc
100984d9c625SLionel Sambuc mutex_enter(&pmp->pmp_sopmtx);
101084d9c625SLionel Sambuc if (pmp->pmp_sopthrcount == 0) {
101184d9c625SLionel Sambuc mutex_exit(&pmp->pmp_sopmtx);
101284d9c625SLionel Sambuc kmem_free(psopr, sizeof(*psopr));
101384d9c625SLionel Sambuc puffs_msg_sendresp(pmp, preq, ENXIO);
101484d9c625SLionel Sambuc } else {
101584d9c625SLionel Sambuc TAILQ_INSERT_TAIL(&pmp->pmp_sopfastreqs,
101684d9c625SLionel Sambuc psopr, psopr_entries);
101784d9c625SLionel Sambuc cv_signal(&pmp->pmp_sopcv);
101884d9c625SLionel Sambuc mutex_exit(&pmp->pmp_sopmtx);
101984d9c625SLionel Sambuc }
102084d9c625SLionel Sambuc break;
102184d9c625SLionel Sambuc }
102284d9c625SLionel Sambuc
102384d9c625SLionel Sambuc default:
1024*0a6a1f1dSLionel Sambuc DPRINTF(("dispatch: invalid opclass 0x%x\n", preq->preq_opclass));
102584d9c625SLionel Sambuc puffs_msg_sendresp(pmp, preq, EOPNOTSUPP);
102684d9c625SLionel Sambuc break;
102784d9c625SLionel Sambuc }
102884d9c625SLionel Sambuc
102984d9c625SLionel Sambuc return 0;
103084d9c625SLionel Sambuc }
103184d9c625SLionel Sambuc
103284d9c625SLionel Sambuc /*
103384d9c625SLionel Sambuc * Work loop for thread processing all ops from server which
103484d9c625SLionel Sambuc * cannot safely be handled in caller context. This includes
103584d9c625SLionel Sambuc * everything which might need a lock currently "held" by the file
103684d9c625SLionel Sambuc * server, i.e. a long-term kernel lock which will be released only
103784d9c625SLionel Sambuc * once the file server acknowledges a request
103884d9c625SLionel Sambuc */
103984d9c625SLionel Sambuc #define TIMED_OUT(expire) \
104084d9c625SLionel Sambuc ((int)((unsigned int)hardclock_ticks - (unsigned int)expire) > 0)
104184d9c625SLionel Sambuc void
puffs_sop_thread(void * arg)104284d9c625SLionel Sambuc puffs_sop_thread(void *arg)
104384d9c625SLionel Sambuc {
104484d9c625SLionel Sambuc struct puffs_mount *pmp = arg;
104584d9c625SLionel Sambuc struct mount *mp = PMPTOMP(pmp);
104684d9c625SLionel Sambuc struct puffs_sopreq *psopr;
104784d9c625SLionel Sambuc bool keeprunning;
104884d9c625SLionel Sambuc bool unmountme = false;
104984d9c625SLionel Sambuc int timeo;
105084d9c625SLionel Sambuc
105184d9c625SLionel Sambuc timeo = PUFFS_USE_FS_TTL(pmp) ? puffs_sopreq_expire_timeout : 0;
105284d9c625SLionel Sambuc
105384d9c625SLionel Sambuc mutex_enter(&pmp->pmp_sopmtx);
105484d9c625SLionel Sambuc for (keeprunning = true; keeprunning; ) {
105584d9c625SLionel Sambuc /*
105684d9c625SLionel Sambuc * We have a fast queue for flush and umount, and a node
105784d9c625SLionel Sambuc * queue for delayes node reclaims. Requests on node queue * are not honoured before clock reaches psopr_at. This
105884d9c625SLionel Sambuc * code assumes that requests are ordered by psopr_at.
105984d9c625SLionel Sambuc */
106084d9c625SLionel Sambuc do {
106184d9c625SLionel Sambuc psopr = TAILQ_FIRST(&pmp->pmp_sopfastreqs);
106284d9c625SLionel Sambuc if (psopr != NULL) {
106384d9c625SLionel Sambuc TAILQ_REMOVE(&pmp->pmp_sopfastreqs,
106484d9c625SLionel Sambuc psopr, psopr_entries);
106584d9c625SLionel Sambuc break;
106684d9c625SLionel Sambuc }
106784d9c625SLionel Sambuc
106884d9c625SLionel Sambuc psopr = TAILQ_FIRST(&pmp->pmp_sopnodereqs);
106984d9c625SLionel Sambuc if ((psopr != NULL) && TIMED_OUT(psopr->psopr_at)) {
107084d9c625SLionel Sambuc TAILQ_REMOVE(&pmp->pmp_sopnodereqs,
107184d9c625SLionel Sambuc psopr, psopr_entries);
107284d9c625SLionel Sambuc break;
107384d9c625SLionel Sambuc }
107484d9c625SLionel Sambuc
107584d9c625SLionel Sambuc cv_timedwait(&pmp->pmp_sopcv, &pmp->pmp_sopmtx, timeo);
107684d9c625SLionel Sambuc } while (1 /* CONSTCOND */);
107784d9c625SLionel Sambuc
107884d9c625SLionel Sambuc mutex_exit(&pmp->pmp_sopmtx);
107984d9c625SLionel Sambuc
108084d9c625SLionel Sambuc switch (psopr->psopr_sopreq) {
108184d9c625SLionel Sambuc case PUFFS_SOPREQSYS_EXIT:
108284d9c625SLionel Sambuc keeprunning = false;
108384d9c625SLionel Sambuc break;
108484d9c625SLionel Sambuc case PUFFS_SOPREQ_FLUSH:
108584d9c625SLionel Sambuc puffsop_flush(pmp, &psopr->psopr_pf);
108684d9c625SLionel Sambuc break;
108784d9c625SLionel Sambuc case PUFFS_SOPREQ_EXPIRE:
108884d9c625SLionel Sambuc puffsop_expire(pmp, psopr->psopr_ck);
108984d9c625SLionel Sambuc break;
109084d9c625SLionel Sambuc case PUFFS_SOPREQ_UNMOUNT:
109184d9c625SLionel Sambuc puffs_msg_sendresp(pmp, &psopr->psopr_preq, 0);
109284d9c625SLionel Sambuc
109384d9c625SLionel Sambuc unmountme = true;
109484d9c625SLionel Sambuc keeprunning = false;
109584d9c625SLionel Sambuc
109684d9c625SLionel Sambuc /*
109784d9c625SLionel Sambuc * We know the mountpoint is still alive because
109884d9c625SLionel Sambuc * the thread that is us (poetic?) is still alive.
109984d9c625SLionel Sambuc */
110084d9c625SLionel Sambuc atomic_inc_uint((unsigned int*)&mp->mnt_refcnt);
110184d9c625SLionel Sambuc break;
110284d9c625SLionel Sambuc }
110384d9c625SLionel Sambuc
110484d9c625SLionel Sambuc kmem_free(psopr, sizeof(*psopr));
110584d9c625SLionel Sambuc mutex_enter(&pmp->pmp_sopmtx);
110684d9c625SLionel Sambuc }
110784d9c625SLionel Sambuc
110884d9c625SLionel Sambuc /*
110984d9c625SLionel Sambuc * Purge remaining ops.
111084d9c625SLionel Sambuc */
111184d9c625SLionel Sambuc while ((psopr = TAILQ_FIRST(&pmp->pmp_sopfastreqs)) != NULL) {
111284d9c625SLionel Sambuc TAILQ_REMOVE(&pmp->pmp_sopfastreqs, psopr, psopr_entries);
111384d9c625SLionel Sambuc mutex_exit(&pmp->pmp_sopmtx);
111484d9c625SLionel Sambuc puffs_msg_sendresp(pmp, &psopr->psopr_preq, ENXIO);
111584d9c625SLionel Sambuc kmem_free(psopr, sizeof(*psopr));
111684d9c625SLionel Sambuc mutex_enter(&pmp->pmp_sopmtx);
111784d9c625SLionel Sambuc }
111884d9c625SLionel Sambuc
111984d9c625SLionel Sambuc while ((psopr = TAILQ_FIRST(&pmp->pmp_sopnodereqs)) != NULL) {
112084d9c625SLionel Sambuc TAILQ_REMOVE(&pmp->pmp_sopnodereqs, psopr, psopr_entries);
112184d9c625SLionel Sambuc mutex_exit(&pmp->pmp_sopmtx);
112284d9c625SLionel Sambuc KASSERT(psopr->psopr_sopreq == PUFFS_SOPREQ_EXPIRE);
112384d9c625SLionel Sambuc kmem_free(psopr, sizeof(*psopr));
112484d9c625SLionel Sambuc mutex_enter(&pmp->pmp_sopmtx);
112584d9c625SLionel Sambuc }
112684d9c625SLionel Sambuc
112784d9c625SLionel Sambuc pmp->pmp_sopthrcount--;
112884d9c625SLionel Sambuc cv_broadcast(&pmp->pmp_sopcv);
112984d9c625SLionel Sambuc mutex_exit(&pmp->pmp_sopmtx); /* not allowed to access fs after this */
113084d9c625SLionel Sambuc
113184d9c625SLionel Sambuc /*
113284d9c625SLionel Sambuc * If unmount was requested, we can now safely do it here, since
113384d9c625SLionel Sambuc * our context is dead from the point-of-view of puffs_unmount()
113484d9c625SLionel Sambuc * and we are just another thread. dounmount() makes internally
113584d9c625SLionel Sambuc * sure that VFS_UNMOUNT() isn't called reentrantly and that it
113684d9c625SLionel Sambuc * is eventually completed.
113784d9c625SLionel Sambuc */
113884d9c625SLionel Sambuc if (unmountme) {
113984d9c625SLionel Sambuc (void)dounmount(mp, MNT_FORCE, curlwp);
114084d9c625SLionel Sambuc vfs_destroy(mp);
114184d9c625SLionel Sambuc }
114284d9c625SLionel Sambuc
114384d9c625SLionel Sambuc kthread_exit(0);
114484d9c625SLionel Sambuc }
114584d9c625SLionel Sambuc
114684d9c625SLionel Sambuc int
puffs_msgif_close(void * ctx)1147*0a6a1f1dSLionel Sambuc puffs_msgif_close(void *ctx)
114884d9c625SLionel Sambuc {
1149*0a6a1f1dSLionel Sambuc struct puffs_mount *pmp = ctx;
115084d9c625SLionel Sambuc struct mount *mp = PMPTOMP(pmp);
115184d9c625SLionel Sambuc
115284d9c625SLionel Sambuc mutex_enter(&pmp->pmp_lock);
115384d9c625SLionel Sambuc puffs_mp_reference(pmp);
115484d9c625SLionel Sambuc
115584d9c625SLionel Sambuc /*
115684d9c625SLionel Sambuc * Free the waiting callers before proceeding any further.
115784d9c625SLionel Sambuc * The syncer might be jogging around in this file system
115884d9c625SLionel Sambuc * currently. If we allow it to go to the userspace of no
115984d9c625SLionel Sambuc * return while trying to get the syncer lock, well ...
116084d9c625SLionel Sambuc */
116184d9c625SLionel Sambuc puffs_userdead(pmp);
116284d9c625SLionel Sambuc
116384d9c625SLionel Sambuc /*
116484d9c625SLionel Sambuc * Make sure someone from puffs_unmount() isn't currently in
116584d9c625SLionel Sambuc * userspace. If we don't take this precautionary step,
116684d9c625SLionel Sambuc * they might notice that the mountpoint has disappeared
116784d9c625SLionel Sambuc * from under them once they return. Especially note that we
116884d9c625SLionel Sambuc * cannot simply test for an unmounter before calling
116984d9c625SLionel Sambuc * dounmount(), since it might be possible that that particular
117084d9c625SLionel Sambuc * invocation of unmount was called without MNT_FORCE. Here we
117184d9c625SLionel Sambuc * *must* make sure unmount succeeds. Also, restart is necessary
117284d9c625SLionel Sambuc * since pmp isn't locked. We might end up with PUTTER_DEAD after
117384d9c625SLionel Sambuc * restart and exit from there.
117484d9c625SLionel Sambuc */
117584d9c625SLionel Sambuc if (pmp->pmp_unmounting) {
117684d9c625SLionel Sambuc cv_wait(&pmp->pmp_unmounting_cv, &pmp->pmp_lock);
117784d9c625SLionel Sambuc puffs_mp_release(pmp);
117884d9c625SLionel Sambuc mutex_exit(&pmp->pmp_lock);
117984d9c625SLionel Sambuc DPRINTF(("puffs_fop_close: unmount was in progress for pmp %p, "
118084d9c625SLionel Sambuc "restart\n", pmp));
118184d9c625SLionel Sambuc return ERESTART;
118284d9c625SLionel Sambuc }
118384d9c625SLionel Sambuc
118484d9c625SLionel Sambuc /* Won't access pmp from here anymore */
118584d9c625SLionel Sambuc atomic_inc_uint((unsigned int*)&mp->mnt_refcnt);
118684d9c625SLionel Sambuc puffs_mp_release(pmp);
118784d9c625SLionel Sambuc mutex_exit(&pmp->pmp_lock);
118884d9c625SLionel Sambuc
118984d9c625SLionel Sambuc /* Detach from VFS. */
119084d9c625SLionel Sambuc (void)dounmount(mp, MNT_FORCE, curlwp);
119184d9c625SLionel Sambuc vfs_destroy(mp);
119284d9c625SLionel Sambuc
119384d9c625SLionel Sambuc return 0;
119484d9c625SLionel Sambuc }
119584d9c625SLionel Sambuc
119684d9c625SLionel Sambuc /*
119784d9c625SLionel Sambuc * We're dead, kaput, RIP, slightly more than merely pining for the
119884d9c625SLionel Sambuc * fjords, belly-up, fallen, lifeless, finished, expired, gone to meet
119984d9c625SLionel Sambuc * our maker, ceased to be, etcetc. YASD. It's a dead FS!
120084d9c625SLionel Sambuc *
120184d9c625SLionel Sambuc * Caller must hold puffs mutex.
120284d9c625SLionel Sambuc */
120384d9c625SLionel Sambuc void
puffs_userdead(struct puffs_mount * pmp)120484d9c625SLionel Sambuc puffs_userdead(struct puffs_mount *pmp)
120584d9c625SLionel Sambuc {
120684d9c625SLionel Sambuc struct puffs_msgpark *park, *park_next;
120784d9c625SLionel Sambuc
120884d9c625SLionel Sambuc /*
120984d9c625SLionel Sambuc * Mark filesystem status as dying so that operations don't
121084d9c625SLionel Sambuc * attempt to march to userspace any longer.
121184d9c625SLionel Sambuc */
121284d9c625SLionel Sambuc pmp->pmp_status = PUFFSTAT_DYING;
121384d9c625SLionel Sambuc
121484d9c625SLionel Sambuc /* signal waiters on REQUEST TO file server queue */
121584d9c625SLionel Sambuc for (park = TAILQ_FIRST(&pmp->pmp_msg_touser); park; park = park_next) {
121684d9c625SLionel Sambuc
121784d9c625SLionel Sambuc mutex_enter(&park->park_mtx);
121884d9c625SLionel Sambuc puffs_msgpark_reference(park);
121984d9c625SLionel Sambuc park_next = TAILQ_NEXT(park, park_entries);
122084d9c625SLionel Sambuc
122184d9c625SLionel Sambuc KASSERT(park->park_flags & PARKFLAG_ONQUEUE1);
122284d9c625SLionel Sambuc TAILQ_REMOVE(&pmp->pmp_msg_touser, park, park_entries);
122384d9c625SLionel Sambuc park->park_flags &= ~PARKFLAG_ONQUEUE1;
122484d9c625SLionel Sambuc pmp->pmp_msg_touser_count--;
122584d9c625SLionel Sambuc
122684d9c625SLionel Sambuc /*
122784d9c625SLionel Sambuc * Even though waiters on QUEUE1 are removed in touser()
122884d9c625SLionel Sambuc * in case of WAITERGONE, it is still possible for us to
122984d9c625SLionel Sambuc * get raced here due to having to retake locks in said
123084d9c625SLionel Sambuc * touser(). In the race case simply "ignore" the item
123184d9c625SLionel Sambuc * on the queue and move on to the next one.
123284d9c625SLionel Sambuc */
123384d9c625SLionel Sambuc if (park->park_flags & PARKFLAG_WAITERGONE) {
123484d9c625SLionel Sambuc KASSERT((park->park_flags & PARKFLAG_CALL) == 0);
123584d9c625SLionel Sambuc KASSERT(park->park_flags & PARKFLAG_WANTREPLY);
123684d9c625SLionel Sambuc puffs_msgpark_release(park);
123784d9c625SLionel Sambuc
123884d9c625SLionel Sambuc } else {
123984d9c625SLionel Sambuc park->park_preq->preq_rv = ENXIO;
124084d9c625SLionel Sambuc
124184d9c625SLionel Sambuc if (park->park_flags & PARKFLAG_CALL) {
124284d9c625SLionel Sambuc park->park_done(pmp, park->park_preq,
124384d9c625SLionel Sambuc park->park_donearg);
124484d9c625SLionel Sambuc puffs_msgpark_release1(park, 2);
124584d9c625SLionel Sambuc } else if ((park->park_flags & PARKFLAG_WANTREPLY)==0) {
124684d9c625SLionel Sambuc puffs_msgpark_release1(park, 2);
124784d9c625SLionel Sambuc } else {
124884d9c625SLionel Sambuc park->park_preq->preq_rv = ENXIO;
124984d9c625SLionel Sambuc cv_signal(&park->park_cv);
125084d9c625SLionel Sambuc puffs_msgpark_release(park);
125184d9c625SLionel Sambuc }
125284d9c625SLionel Sambuc }
125384d9c625SLionel Sambuc }
125484d9c625SLionel Sambuc
125584d9c625SLionel Sambuc /* signal waiters on RESPONSE FROM file server queue */
125684d9c625SLionel Sambuc for (park=TAILQ_FIRST(&pmp->pmp_msg_replywait); park; park=park_next) {
125784d9c625SLionel Sambuc mutex_enter(&park->park_mtx);
125884d9c625SLionel Sambuc puffs_msgpark_reference(park);
125984d9c625SLionel Sambuc park_next = TAILQ_NEXT(park, park_entries);
126084d9c625SLionel Sambuc
126184d9c625SLionel Sambuc KASSERT(park->park_flags & PARKFLAG_ONQUEUE2);
126284d9c625SLionel Sambuc KASSERT(park->park_flags & PARKFLAG_WANTREPLY);
126384d9c625SLionel Sambuc
126484d9c625SLionel Sambuc TAILQ_REMOVE(&pmp->pmp_msg_replywait, park, park_entries);
126584d9c625SLionel Sambuc park->park_flags &= ~PARKFLAG_ONQUEUE2;
126684d9c625SLionel Sambuc
126784d9c625SLionel Sambuc if (park->park_flags & PARKFLAG_WAITERGONE) {
126884d9c625SLionel Sambuc KASSERT((park->park_flags & PARKFLAG_CALL) == 0);
126984d9c625SLionel Sambuc puffs_msgpark_release(park);
127084d9c625SLionel Sambuc } else {
127184d9c625SLionel Sambuc park->park_preq->preq_rv = ENXIO;
127284d9c625SLionel Sambuc if (park->park_flags & PARKFLAG_CALL) {
127384d9c625SLionel Sambuc park->park_done(pmp, park->park_preq,
127484d9c625SLionel Sambuc park->park_donearg);
127584d9c625SLionel Sambuc puffs_msgpark_release1(park, 2);
127684d9c625SLionel Sambuc } else {
127784d9c625SLionel Sambuc cv_signal(&park->park_cv);
127884d9c625SLionel Sambuc puffs_msgpark_release(park);
127984d9c625SLionel Sambuc }
128084d9c625SLionel Sambuc }
128184d9c625SLionel Sambuc }
128284d9c625SLionel Sambuc
128384d9c625SLionel Sambuc cv_broadcast(&pmp->pmp_msg_waiter_cv);
128484d9c625SLionel Sambuc }
1285