Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files. =================================================================== RCS file: /ftp/cvs/cvsroot/src/sys/fs/puffs/puffs_msgif.c,v rcsdiff: /ftp/cvs/cvsroot/src/sys/fs/puffs/puffs_msgif.c,v: warning: Unknown phrases like `commitid ...;' are present. retrieving revision 1.21 retrieving revision 1.22 diff -u -p -r1.21 -r1.22 --- src/sys/fs/puffs/puffs_msgif.c 2007/03/20 10:21:58 1.21 +++ src/sys/fs/puffs/puffs_msgif.c 2007/03/29 16:04:26 1.22 @@ -1,4 +1,4 @@ -/* $NetBSD: puffs_msgif.c,v 1.21 2007/03/20 10:21:58 pooka Exp $ */ +/* $NetBSD: puffs_msgif.c,v 1.22 2007/03/29 16:04:26 pooka Exp $ */ /* * Copyright (c) 2005, 2006, 2007 Antti Kantee. All Rights Reserved. @@ -33,7 +33,7 @@ */ #include -__KERNEL_RCSID(0, "$NetBSD: puffs_msgif.c,v 1.21 2007/03/20 10:21:58 pooka Exp $"); +__KERNEL_RCSID(0, "$NetBSD: puffs_msgif.c,v 1.22 2007/03/29 16:04:26 pooka Exp $"); #include #include @@ -45,6 +45,109 @@ __KERNEL_RCSID(0, "$NetBSD: puffs_msgif. #include #include +/* + * waitq data structures + */ + +/* + * While a request is going to userspace, park the caller within the + * kernel. This is the kernel counterpart of "struct puffs_req". + */ +struct puffs_park { + struct puffs_req *park_preq; /* req followed by buf */ + uint64_t park_id; /* duplicate of preq_id */ + + size_t park_copylen; /* userspace copylength */ + size_t park_maxlen; /* max size in comeback */ + struct buf *park_bp; /* bp, ASYNCBIOREAD */ + + int park_flags; + + kcondvar_t park_cv; + kmutex_t park_ilck; + + TAILQ_ENTRY(puffs_park) park_entries; +}; +#define PARKFLAG_WAITERGONE 0x01 +#define PARKFLAG_PROCESSING 0x02 +#define PARKFLAG_ASYNCBIOREAD 0x04 + +static struct pool_cache parkpc; +static struct pool parkpool; + +static int +makepark(void *arg, void *obj, int flags) +{ + struct puffs_park *park = obj; + + cv_init(&park->park_cv, "puffsrpl"); + + return 0; +} + +static void +nukepark(void *arg, void *obj) +{ + struct puffs_park *park = obj; + + cv_destroy(&park->park_cv); +} + +void +puffs_msgif_init() +{ + + pool_init(&parkpool, sizeof(struct puffs_park), 0, 0, 0, + "puffprkl", &pool_allocator_nointr, IPL_NONE); + pool_cache_init(&parkpc, &parkpool, makepark, nukepark, NULL); +} + +void +puffs_msgif_destroy() +{ + + pool_cache_destroy(&parkpc); + pool_destroy(&parkpool); +} + +void * +puffs_parkmem_alloc(int waitok) +{ + + return pool_cache_get(&parkpc, waitok ? PR_WAITOK : PR_NOWAIT); +} + +void +puffs_parkmem_free(void *ppark) +{ + + pool_cache_put(&parkpc, ppark); +} + + +/* + * Converts a non-FAF op to a FAF. This simply involves making copies + * of the park and request structures and tagging the request as a FAF. + * It is safe to block here, since the original op is not a FAF. + */ +#if 0 +static void +puffs_reqtofaf(struct puffs_park *ppark) +{ + struct puffs_req *newpreq; + + KASSERT((ppark->park_preq->preq_opclass & PUFFSOPFLAG_FAF) == 0); + + MALLOC(newpreq, struct puffs_req *, ppark->park_copylen, + M_PUFFS, M_ZERO | M_WAITOK); + + memcpy(newpreq, ppark->park_preq, ppark->park_copylen); + + ppark->park_preq = newpreq; + ppark->park_preq->preq_opclass |= PUFFSOPFLAG_FAF; +} +#endif + /* * kernel-user-kernel waitqueues @@ -58,9 +161,9 @@ puffs_getreqid(struct puffs_mount *pmp) { uint64_t rv; - simple_lock(&pmp->pmp_lock); + mutex_enter(&pmp->pmp_lock); rv = pmp->pmp_nextreq++; - simple_unlock(&pmp->pmp_lock); + mutex_exit(&pmp->pmp_lock); return rv; } @@ -69,17 +172,18 @@ puffs_getreqid(struct puffs_mount *pmp) int puffs_vfstouser(struct puffs_mount *pmp, int optype, void *kbuf, size_t buflen) { - struct puffs_park park; + struct puffs_park *ppark; - park.park_preq = kbuf; + ppark = pool_cache_get(&parkpc, PR_WAITOK); + ppark->park_preq = kbuf; - park.park_preq->preq_opclass = PUFFSOP_VFS; - park.park_preq->preq_optype = optype; + ppark->park_preq->preq_opclass = PUFFSOP_VFS; + ppark->park_preq->preq_optype = optype; - park.park_maxlen = park.park_copylen = buflen; - park.park_flags = 0; + ppark->park_maxlen = ppark->park_copylen = buflen; + ppark->park_flags = 0; - return touser(pmp, &park, puffs_getreqid(pmp), NULL, NULL); + return touser(pmp, ppark, puffs_getreqid(pmp), NULL, NULL); } void @@ -90,7 +194,7 @@ puffs_suspendtouser(struct puffs_mount * pvfsr_susp = malloc(sizeof(struct puffs_vfsreq_suspend), M_PUFFS, M_WAITOK | M_ZERO); - ppark = malloc(sizeof(struct puffs_park), M_PUFFS, M_WAITOK | M_ZERO); + ppark = pool_cache_get(&parkpc, PR_WAITOK); pvfsr_susp->pvfsr_status = status; ppark->park_preq = (struct puffs_req *)pvfsr_susp; @@ -113,18 +217,19 @@ puffs_vntouser(struct puffs_mount *pmp, void *kbuf, size_t buflen, void *cookie, struct vnode *vp1, struct vnode *vp2) { - struct puffs_park park; + struct puffs_park *ppark; - park.park_preq = kbuf; + ppark = pool_cache_get(&parkpc, PR_WAITOK); + ppark->park_preq = kbuf; - park.park_preq->preq_opclass = PUFFSOP_VN; - park.park_preq->preq_optype = optype; - park.park_preq->preq_cookie = cookie; + ppark->park_preq->preq_opclass = PUFFSOP_VN; + ppark->park_preq->preq_optype = optype; + ppark->park_preq->preq_cookie = cookie; - park.park_maxlen = park.park_copylen = buflen; - park.park_flags = 0; + ppark->park_maxlen = ppark->park_copylen = buflen; + ppark->park_flags = 0; - return touser(pmp, &park, puffs_getreqid(pmp), vp1, vp2); + return touser(pmp, ppark, puffs_getreqid(pmp), vp1, vp2); } /* @@ -135,52 +240,45 @@ puffs_vntouser_req(struct puffs_mount *p void *kbuf, size_t buflen, void *cookie, uint64_t reqid, struct vnode *vp1, struct vnode *vp2) { - struct puffs_park park; + struct puffs_park *ppark; - park.park_preq = kbuf; + ppark = pool_cache_get(&parkpc, PR_WAITOK); + ppark->park_preq = kbuf; - park.park_preq->preq_opclass = PUFFSOP_VN; - park.park_preq->preq_optype = optype; - park.park_preq->preq_cookie = cookie; + ppark->park_preq->preq_opclass = PUFFSOP_VN; + ppark->park_preq->preq_optype = optype; + ppark->park_preq->preq_cookie = cookie; - park.park_maxlen = park.park_copylen = buflen; - park.park_flags = 0; + ppark->park_maxlen = ppark->park_copylen = buflen; + ppark->park_flags = 0; - return touser(pmp, &park, reqid, vp1, vp2); + return touser(pmp, ppark, reqid, vp1, vp2); } -/* - * vnode level request, copy routines can adjust "kernbuf". - */ int -puffs_vntouser_adjbuf(struct puffs_mount *pmp, int optype, - void **kbuf, size_t *buflen, size_t maxdelta, +puffs_vntouser_delta(struct puffs_mount *pmp, int optype, + void *kbuf, size_t buflen, size_t maxdelta, void *cookie, struct vnode *vp1, struct vnode *vp2) { - struct puffs_park park; - int error; - - park.park_preq = *kbuf; - - park.park_preq->preq_opclass = PUFFSOP_VN; - park.park_preq->preq_optype = optype; - park.park_preq->preq_cookie = cookie; + struct puffs_park *ppark; - park.park_copylen = *buflen; - park.park_maxlen = maxdelta + *buflen; - park.park_flags = PUFFS_PARKFLAG_ADJUSTABLE; + ppark = pool_cache_get(&parkpc, PR_WAITOK); + ppark->park_preq = kbuf; - error = touser(pmp, &park, puffs_getreqid(pmp), vp1, vp2); + ppark->park_preq->preq_opclass = PUFFSOP_VN; + ppark->park_preq->preq_optype = optype; + ppark->park_preq->preq_cookie = cookie; - *kbuf = park.park_preq; - *buflen = park.park_copylen; + ppark->park_copylen = buflen; + ppark->park_maxlen = buflen + maxdelta; + ppark->park_flags = 0; - return error; + return touser(pmp, ppark, puffs_getreqid(pmp), vp1, vp2); } /* * File server interaction is async from caller perspective. - * biodone(bp)J is signalled in putop. + * biodone(bp) is signalled in putop. */ void puffs_vntouser_bioread_async(struct puffs_mount *pmp, void *cookie, @@ -190,10 +288,10 @@ puffs_vntouser_bioread_async(struct puff struct puffs_park *ppark; struct puffs_vnreq_read *read_argp; - MALLOC(ppark, struct puffs_park *, sizeof(struct puffs_park), - M_PUFFS, M_WAITOK); + ppark = pool_cache_get(&parkpc, PR_WAITOK); MALLOC(read_argp, struct puffs_vnreq_read *, - sizeof(struct puffs_vnreq_read), M_PUFFS, M_WAITOK | M_ZERO); + sizeof(struct puffs_vnreq_read) + tomove, + M_PUFFS, M_WAITOK | M_ZERO); read_argp->pvnr_ioflag = 0; read_argp->pvnr_resid = tomove; @@ -208,8 +306,7 @@ puffs_vntouser_bioread_async(struct puff ppark->park_copylen = sizeof(struct puffs_vnreq_read); ppark->park_maxlen = sizeof(struct puffs_vnreq_read) + tomove; ppark->park_bp = bp; - ppark->park_flags - = PUFFS_PARKFLAG_ADJUSTABLE | PUFFS_PARKFLAG_ASYNCBIOREAD; + ppark->park_flags = PARKFLAG_ASYNCBIOREAD; (void)touser(pmp, ppark, puffs_getreqid(pmp), vp1, vp2); } @@ -226,7 +323,7 @@ puffs_vntouser_faf(struct puffs_mount *p struct puffs_park *ppark; /* XXX: is it allowable to sleep here? */ - ppark = malloc(sizeof(struct puffs_park), M_PUFFS, M_NOWAIT | M_ZERO); + ppark = pool_cache_get(&parkpc, PR_NOWAIT); if (ppark == NULL) return; /* 2bad */ @@ -271,7 +368,6 @@ static int touser(struct puffs_mount *pmp, struct puffs_park *ppark, uint64_t reqid, struct vnode *vp1, struct vnode *vp2) { - struct lwp *l = curlwp; struct mount *mp; struct puffs_req *preq; int rv = 0; @@ -281,6 +377,12 @@ touser(struct puffs_mount *pmp, struct p preq->preq_id = ppark->park_id = reqid; preq->preq_buflen = ALIGN(ppark->park_maxlen); +#if 0 + /* + * We don't trap signals currently + */ + struct lwp *l = curlwp; + /* * To support PCATCH, yet another movie: check if there are signals * pending and we are issueing a non-FAF. If so, return an error @@ -288,22 +390,19 @@ touser(struct puffs_mount *pmp, struct p * it to a FAF, fire off to the file server and return an error. * Yes, this is bordering disgusting. Barfbags are on me. */ - if (PUFFSOP_WANTREPLY(ppark->park_preq->preq_opclass) - && (ppark->park_flags & PUFFS_PARKFLAG_ASYNCBIOREAD) == 0 + if (PUFFSOP_WANTREPLY(preq->preq_opclass) + && (ppark->park_flags & PARKFLAG_ASYNCBIOREAD) == 0 && (l->l_flag & LW_PENDSIG) != 0 && sigispending(l, 0)) { if (PUFFSOP_OPCLASS(preq->preq_opclass) == PUFFSOP_VN && preq->preq_optype == PUFFS_VN_INACTIVE) { - struct puffs_park *newpark; - - newpark = puffs_reqtofaf(ppark); - DPRINTF(("puffs touser: converted to FAF, old %p, " - "new %p\n", ppark, newpark)); - ppark = newpark; + puffs_reqtofaf(ppark); + DPRINTF(("puffs touser: converted to FAF %p\n", ppark)); rv = EINTR; } else { return EINTR; } } +#endif /* * test for suspension lock. @@ -328,18 +427,25 @@ touser(struct puffs_mount *pmp, struct p * in the kernel while the fs is suspending. It's not a very * likely event, but it needs to be fixed some day. */ + + /* + * MOREXXX: once PUFFS_WCACHEINFO is enabled, we can't take + * the mutex here, since getpages() might be called locked. + */ fstrans_start(mp, FSTRANS_NORMAL); - simple_lock(&pmp->pmp_lock); + mutex_enter(&pmp->pmp_lock); fstrans_done(mp); if (pmp->pmp_status != PUFFSTAT_RUNNING) { - simple_unlock(&pmp->pmp_lock); + mutex_exit(&pmp->pmp_lock); + pool_cache_put(&parkpc, ppark); return ENXIO; } TAILQ_INSERT_TAIL(&pmp->pmp_req_touser, ppark, park_entries); - pmp->pmp_req_touser_waiters++; + pmp->pmp_req_waiters++; +#if 0 /* * Don't do unlock-relock dance yet. There are a couple of * unsolved issues with it. If we don't unlock, we can have @@ -348,7 +454,6 @@ touser(struct puffs_mount *pmp, struct p * would of course be nicer to have antilocking in the userspace * interface protocol itself.. your patience will be rewarded. */ -#if 0 /* unlock */ if (vp2) VOP_UNLOCK(vp2, 0); @@ -356,119 +461,34 @@ touser(struct puffs_mount *pmp, struct p VOP_UNLOCK(vp1, 0); #endif - /* - * XXX: does releasing the lock here cause trouble? Can't hold - * it, because otherwise the below would cause locking against - * oneself-problems in the kqueue stuff. yes, it is a - * theoretical race, so it must be solved - */ - simple_unlock(&pmp->pmp_lock); - DPRINTF(("touser: req %" PRIu64 ", preq: %p, park: %p, " "c/t: 0x%x/0x%x, f: 0x%x\n", preq->preq_id, preq, ppark, preq->preq_opclass, preq->preq_optype, ppark->park_flags)); - wakeup(&pmp->pmp_req_touser); + cv_broadcast(&pmp->pmp_req_waiter_cv); selnotify(pmp->pmp_sel, 0); - if (PUFFSOP_WANTREPLY(ppark->park_preq->preq_opclass) - && (ppark->park_flags & PUFFS_PARKFLAG_ASYNCBIOREAD) == 0) { - struct puffs_park *valetpark = NULL; + if (PUFFSOP_WANTREPLY(preq->preq_opclass) + && (ppark->park_flags & PARKFLAG_ASYNCBIOREAD) == 0) { int error; - error = ltsleep(ppark, PUSER | PCATCH, "puffs1", 0, NULL); - rv = ppark->park_preq->preq_rv; - - /* - * Ok, so it gets a bit tricky around here once again. - * We want to give interruptibility to the sleep to work - * around all kinds of locking-against-oneself problems - * and the file system recursing into itself and so forth. - * So if we break out of the ltsleep() for anything except - * natural causes, we need to caution ourselves. - * - * The stages at which we can break out are: - * 1) operation waiting to be fetched by file server - * 2) operation being copied to userspace, not on either queue - * 3) file server operating on .. err .. operation - * 4) putop: locate the correct park structure from the queue - * 5) putop: copy response from userspace - * 6) putop: wakeup waiter - * - * If we are still at stage 1, no problem, just remove - * ourselves from the queue to userspace. If we are at - * the stage before 4 has completed, replace the park structure - * with a park structure indicating that the caller is - * no more and no proper reply is required. If the server - * is already copying data from userspace to the kernel, - * wait for it to finish and return the real return value to - * the caller. - */ - checkagain: - if (valetpark) { - FREE(valetpark, M_PUFFS); - valetpark = NULL; - } + error = 0; /* XXX: no interrupt for now */ + cv_wait(&ppark->park_cv, &pmp->pmp_lock); if (error) { - DPRINTF(("puffs touser: got %d from ltsleep, " - "(unlocked) flags 0x%x (park %p)\n", - error, ppark->park_flags, ppark)); - rv = error; - - MALLOC(valetpark, struct puffs_park *, - sizeof(struct puffs_park), M_PUFFS, - M_ZERO | M_WAITOK); - - simple_lock(&pmp->pmp_lock); - - /* - * The order here for the clauses, per description - * in comment above, is: - * 1, after 6, after 4, 2-3. - */ - if ((ppark->park_flags&PUFFS_PARKFLAG_PROCESSING)==0) { - TAILQ_REMOVE(&pmp->pmp_req_touser, ppark, - park_entries); - simple_unlock(&pmp->pmp_lock); - FREE(valetpark, M_PUFFS); - DPRINTF(("puffs touser: park %p removed " - "from queue one\n", ppark)); - } else if - (ppark->park_flags & PUFFS_PARKFLAG_RECVREPLY) { - if (ppark->park_flags & PUFFS_PARKFLAG_DONE) { - rv = ppark->park_preq->preq_rv; - simple_unlock(&pmp->pmp_lock); - FREE(valetpark, M_PUFFS); - } else { - error = ltsleep(ppark, - PUSER | PCATCH | PNORELOCK, - "puffsre1", 0, &pmp->pmp_lock); - goto checkagain; - } + ppark->park_flags |= PARKFLAG_WAITERGONE; + if (ppark->park_flags & PARKFLAG_PROCESSING) { + cv_wait(&ppark->park_cv, &pmp->pmp_lock); + rv = preq->preq_rv; } else { - valetpark->park_flags - = PUFFS_PARKFLAG_WAITERGONE; - ppark->park_flags |= PUFFS_PARKFLAG_WAITERGONE; - valetpark->park_id = ppark->park_id; - - if (ppark->park_flags & PUFFS_PARKFLAG_RQUEUE) { - TAILQ_INSERT_BEFORE(ppark, valetpark, - park_entries); - TAILQ_REMOVE(&pmp->pmp_req_replywait, - ppark, park_entries); - } else { - TAILQ_INSERT_TAIL( - &pmp->pmp_req_replywait, - valetpark, park_entries); - } - - simple_unlock(&pmp->pmp_lock); - DPRINTF(("puffs touser: replaced park %p " - "with valet park %p\n", ppark, valetpark)); + rv = error; } + } else { + rv = preq->preq_rv; } - + mutex_exit(&pmp->pmp_lock); + pool_cache_put(&parkpc, ppark); + /* * retake the lock and release. This makes sure (haha, * I'm humorous) that we don't process the same vnode in @@ -482,6 +502,8 @@ touser(struct puffs_mount *pmp, struct p fstrans_start(mp, FSTRANS_NORMAL); fstrans_done(mp); } + } else { + mutex_exit(&pmp->pmp_lock); } #if 0 @@ -492,10 +514,12 @@ touser(struct puffs_mount *pmp, struct p KASSERT(vn_lock(vp2, LK_EXCLUSIVE | LK_RETRY) == 0); #endif - simple_lock(&pmp->pmp_lock); - if (--pmp->pmp_req_touser_waiters == 0) - wakeup(&pmp->pmp_req_touser_waiters); - simple_unlock(&pmp->pmp_lock); + mutex_enter(&pmp->pmp_lock); + if (--pmp->pmp_req_waiters == 0) { + KASSERT(cv_has_waiters(&pmp->pmp_req_waitersink_cv) <= 1); + cv_signal(&pmp->pmp_req_waitersink_cv); + } + mutex_exit(&pmp->pmp_lock); return rv; } @@ -522,7 +546,7 @@ puffs_getop(struct puffs_mount *pmp, str donesome = error = 0; bufpos = phg->phg_buf; - simple_lock(&pmp->pmp_lock); + mutex_enter(&pmp->pmp_lock); while (phg->phg_nops == 0 || donesome != phg->phg_nops) { again: if (pmp->pmp_status != PUFFSTAT_RUNNING) { @@ -539,8 +563,8 @@ puffs_getop(struct puffs_mount *pmp, str goto out; } - error = ltsleep(&pmp->pmp_req_touser, PUSER | PCATCH, - "puffs2", 0, &pmp->pmp_lock); + error = cv_wait_sig(&pmp->pmp_req_waiter_cv, + &pmp->pmp_lock); if (error) goto out; else @@ -549,15 +573,21 @@ puffs_getop(struct puffs_mount *pmp, str park = TAILQ_FIRST(&pmp->pmp_req_touser); preq = park->park_preq; - if (phg->phg_buflen < preq->preq_buflen) { if (!donesome) error = E2BIG; goto out; } TAILQ_REMOVE(&pmp->pmp_req_touser, park, park_entries); - park->park_flags |= PUFFS_PARKFLAG_PROCESSING; - simple_unlock(&pmp->pmp_lock); + + /* If it's a goner, don't process any furher */ + if (park->park_flags & PARKFLAG_WAITERGONE) { + panic("impossible for now"); + pool_cache_put(&parkpc, park); + continue; + } + + mutex_exit(&pmp->pmp_lock); DPRINTF(("puffsgetop: get op %" PRIu64 " (%d.), from %p " "len %zu (buflen %zu), target %p\n", preq->preq_id, @@ -565,12 +595,12 @@ puffs_getop(struct puffs_mount *pmp, str bufpos)); if ((error = copyout(preq, bufpos, park->park_copylen)) != 0) { - DPRINTF((" FAILED %d\n", error)); + DPRINTF(("puffs_getop: copyout failed\n")); /* * ok, user server is probably trying to cheat. * stuff op back & return error to user */ - simple_lock(&pmp->pmp_lock); + mutex_enter(&pmp->pmp_lock); TAILQ_INSERT_HEAD(&pmp->pmp_req_touser, park, park_entries); @@ -582,33 +612,25 @@ puffs_getop(struct puffs_mount *pmp, str phg->phg_buflen -= preq->preq_buflen; donesome++; - simple_lock(&pmp->pmp_lock); + mutex_enter(&pmp->pmp_lock); if (PUFFSOP_WANTREPLY(preq->preq_opclass)) { - if ((park->park_flags & PUFFS_PARKFLAG_WAITERGONE)==0) { - TAILQ_INSERT_TAIL(&pmp->pmp_req_replywait, park, - park_entries); - park->park_flags |= PUFFS_PARKFLAG_RQUEUE; - } + TAILQ_INSERT_TAIL(&pmp->pmp_req_replywait, park, + park_entries); } else { - simple_unlock(&pmp->pmp_lock); free(preq, M_PUFFS); - free(park, M_PUFFS); - simple_lock(&pmp->pmp_lock); + pool_cache_put(&parkpc, park); } } out: - phg->phg_more = pmp->pmp_req_touser_waiters; - simple_unlock(&pmp->pmp_lock); + phg->phg_more = pmp->pmp_req_waiters; + mutex_exit(&pmp->pmp_lock); phg->phg_nops = donesome; return error; } -/* - * urgh, too complex, be very very careful while editing, i.e. NEEDS CLEANUP - */ int puffs_putop(struct puffs_mount *pmp, struct puffs_reqh_put *php) { @@ -627,13 +649,11 @@ puffs_putop(struct puffs_mount *pmp, str userbuf = php->php_buf; reqlen = php->php_buflen; - simple_lock(&pmp->pmp_lock); + mutex_enter(&pmp->pmp_lock); while (donesome != php->php_nops) { #ifdef PUFFSDEBUG - simple_unlock(&pmp->pmp_lock); DPRINTF(("puffsputop: searching for %" PRIu64 ", ubuf: %p, " "len %zu\n", id, userbuf, reqlen)); - simple_lock(&pmp->pmp_lock); #endif TAILQ_FOREACH(park, &pmp->pmp_req_replywait, park_entries) { if (park->park_id == id) @@ -645,18 +665,19 @@ puffs_putop(struct puffs_mount *pmp, str break; } TAILQ_REMOVE(&pmp->pmp_req_replywait, park, park_entries); - park->park_flags |= PUFFS_PARKFLAG_RECVREPLY; - simple_unlock(&pmp->pmp_lock); + wgone = park->park_flags & PARKFLAG_WAITERGONE; + park->park_flags |= PARKFLAG_PROCESSING; + mutex_exit(&pmp->pmp_lock); /* * If the caller has gone south, go to next, collect * $200 and free the structure there instead of wakeup. * We also need to copyin the */ - if (park->park_flags & PUFFS_PARKFLAG_WAITERGONE) { + if (wgone) { + panic("puffs: wgone impossible for now\n"); DPRINTF(("puffs_putop: bad service - waiter gone for " "park %p\n", park)); - wgone = 1; error = copyin(userbuf, &tmpreq, sizeof(struct puffs_req)); if (error) @@ -665,37 +686,10 @@ puffs_putop(struct puffs_mount *pmp, str goto next; } - if (park->park_flags & PUFFS_PARKFLAG_ADJUSTABLE) { - /* sanitycheck size of incoming transmission. */ - if (reqlen > pmp->pmp_req_maxsize) { - DPRINTF(("puffsputop: outrageous user buf " - "size: %zu\n", reqlen)); - error = EINVAL; - goto loopout; - } - - if (reqlen > park->park_copylen) { - if (reqlen > park->park_maxlen) { - DPRINTF(("puffsputop: adj copysize " - "> max size, %zu vs %zu\n", - reqlen, park->park_maxlen)); - error = EINVAL; - goto loopout; - } - free(park->park_preq, M_PUFFS); - park->park_preq = malloc(reqlen, - M_PUFFS, M_WAITOK); - - park->park_copylen = reqlen; - DPRINTF(("puffsputop: adjbuf, new addr %p, " - "len %zu\n", park->park_preq, reqlen)); - } - } else { - if (reqlen == 0 || reqlen > park->park_copylen) { - reqlen = park->park_copylen; - DPRINTF(("puffsputop: kernel bufsize override: " - "%zu\n", reqlen)); - } + if (reqlen == 0 || reqlen > park->park_maxlen) { + reqlen = park->park_maxlen; + DPRINTF(("puffsputop: kernel bufsize override: " + "%zu\n", reqlen)); } DPRINTF(("puffsputpop: copyin from %p to %p, len %zu\n", @@ -706,7 +700,7 @@ puffs_putop(struct puffs_mount *pmp, str nextpreq = park->park_preq; bp = park->park_bp; - if (park->park_flags & PUFFS_PARKFLAG_ASYNCBIOREAD) { + if (park->park_flags & PARKFLAG_ASYNCBIOREAD) { struct puffs_vnreq_read *read_argp; size_t moved; @@ -736,7 +730,7 @@ puffs_putop(struct puffs_mount *pmp, str loopout: if (error && park->park_preq) { park->park_preq->preq_rv = error; - if (park->park_flags & PUFFS_PARKFLAG_ASYNCBIOREAD) { + if (park->park_flags & PARKFLAG_ASYNCBIOREAD) { bp = park->park_bp; bp->b_error = error; bp->b_flags |= B_ERROR; @@ -744,19 +738,17 @@ puffs_putop(struct puffs_mount *pmp, str } } - if (wgone) { - FREE(park, M_PUFFS); - simple_lock(&pmp->pmp_lock); - } else if (park->park_flags & PUFFS_PARKFLAG_ASYNCBIOREAD) { - free(park->park_preq, M_PUFFS); - FREE(park, M_PUFFS); - simple_lock(&pmp->pmp_lock); - } else { - DPRINTF(("puffs_putop: flagging done for park %p\n", - park)); - simple_lock(&pmp->pmp_lock); - park->park_flags |= PUFFS_PARKFLAG_DONE; - wakeup(park); + mutex_enter(&pmp->pmp_lock); + if (!wgone) { + if (park->park_flags & PARKFLAG_ASYNCBIOREAD) { + free(park->park_preq, M_PUFFS); + pool_cache_put(&parkpc, park); + } else { + DPRINTF(("puffs_putop: flagging done for " + "park %p\n", park)); + + cv_signal(&park->park_cv); + } } if (error) @@ -764,12 +756,75 @@ puffs_putop(struct puffs_mount *pmp, str wgone = 0; } - simple_unlock(&pmp->pmp_lock); + mutex_exit(&pmp->pmp_lock); php->php_nops -= donesome; return error; } +/* + * We're dead, kaput, RIP, slightly more than merely pining for the + * fjords, belly-up, fallen, lifeless, finished, expired, gone to meet + * our maker, ceased to be, etcetc. YASD. It's a dead FS! + * + * Caller must hold puffs mutex. + */ +void +puffs_userdead(struct puffs_mount *pmp) +{ + struct puffs_park *park; + struct buf *bp; + + /* + * Mark filesystem status as dying so that operations don't + * attempt to march to userspace any longer. + */ + pmp->pmp_status = PUFFSTAT_DYING; + + /* signal waiters on REQUEST TO file server queue */ + TAILQ_FOREACH(park, &pmp->pmp_req_touser, park_entries) { + uint8_t opclass; + + opclass = park->park_preq->preq_rv; + park->park_preq->preq_rv = ENXIO; + + TAILQ_REMOVE(&pmp->pmp_req_touser, park, park_entries); + + if (park->park_flags & PARKFLAG_ASYNCBIOREAD) { + bp = park->park_bp; + bp->b_error = ENXIO; + bp->b_flags |= B_ERROR; + biodone(bp); + free(park->park_preq, M_PUFFS); + pool_cache_put(&parkpc, park); + } else if (!PUFFSOP_WANTREPLY(opclass)) { + free(park->park_preq, M_PUFFS); + pool_cache_put(&parkpc, park); + } else { + cv_signal(&park->park_cv); + } + } + + /* signal waiters on RESPONSE FROM file server queue */ + TAILQ_FOREACH(park, &pmp->pmp_req_replywait, park_entries) { + KASSERT(PUFFSOP_WANTREPLY(park->park_preq->preq_opclass)); + + park->park_preq->preq_rv = ENXIO; + TAILQ_REMOVE(&pmp->pmp_req_replywait, park, park_entries); + + if (park->park_flags & PARKFLAG_ASYNCBIOREAD) { + bp = park->park_bp; + bp->b_error = ENXIO; + bp->b_flags |= B_ERROR; + biodone(bp); + free(park->park_preq, M_PUFFS); + pool_cache_put(&parkpc, park); + } else { + cv_signal(&park->park_cv); + } + } +} + /* this is probably going to die away at some point? */ /* * XXX: currently bitrotted @@ -784,7 +839,7 @@ puffssizeop(struct puffs_mount *pmp, str int error; /* locate correct op */ - simple_lock(&pmp->pmp_lock); + mutex_enter(&pmp->pmp_lock); TAILQ_FOREACH(pspark, &pmp->pmp_req_sizepark, pkso_entries) { if (pspark->pkso_reqid == psop_user->pso_reqid) { TAILQ_REMOVE(&pmp->pmp_req_sizepark, pspark, @@ -792,7 +847,7 @@ puffssizeop(struct puffs_mount *pmp, str break; } } - simple_unlock(&pmp->pmp_lock); + mutex_exit(&pmp->pmp_lock); if (pspark == NULL) return EINVAL;