version 1.20.2.1, 2007/03/29 19:27:54 |
version 1.21, 2007/03/20 10:21:58 |
Line 45 __KERNEL_RCSID(0, "$NetBSD$"); |
|
Line 45 __KERNEL_RCSID(0, "$NetBSD$"); |
|
#include <fs/puffs/puffs_msgif.h> |
#include <fs/puffs/puffs_msgif.h> |
#include <fs/puffs/puffs_sys.h> |
#include <fs/puffs/puffs_sys.h> |
|
|
/* |
|
* 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 |
* kernel-user-kernel waitqueues |
Line 161 puffs_getreqid(struct puffs_mount *pmp) |
|
Line 58 puffs_getreqid(struct puffs_mount *pmp) |
|
{ |
{ |
uint64_t rv; |
uint64_t rv; |
|
|
mutex_enter(&pmp->pmp_lock); |
simple_lock(&pmp->pmp_lock); |
rv = pmp->pmp_nextreq++; |
rv = pmp->pmp_nextreq++; |
mutex_exit(&pmp->pmp_lock); |
simple_unlock(&pmp->pmp_lock); |
|
|
return rv; |
return rv; |
} |
} |
Line 172 puffs_getreqid(struct puffs_mount *pmp) |
|
Line 69 puffs_getreqid(struct puffs_mount *pmp) |
|
int |
int |
puffs_vfstouser(struct puffs_mount *pmp, int optype, void *kbuf, size_t buflen) |
puffs_vfstouser(struct puffs_mount *pmp, int optype, void *kbuf, size_t buflen) |
{ |
{ |
struct puffs_park *ppark; |
struct puffs_park park; |
|
|
ppark = pool_cache_get(&parkpc, PR_WAITOK); |
park.park_preq = kbuf; |
ppark->park_preq = kbuf; |
|
|
|
ppark->park_preq->preq_opclass = PUFFSOP_VFS; |
park.park_preq->preq_opclass = PUFFSOP_VFS; |
ppark->park_preq->preq_optype = optype; |
park.park_preq->preq_optype = optype; |
|
|
ppark->park_maxlen = ppark->park_copylen = buflen; |
park.park_maxlen = park.park_copylen = buflen; |
ppark->park_flags = 0; |
park.park_flags = 0; |
|
|
return touser(pmp, ppark, puffs_getreqid(pmp), NULL, NULL); |
return touser(pmp, &park, puffs_getreqid(pmp), NULL, NULL); |
} |
} |
|
|
void |
void |
Line 194 puffs_suspendtouser(struct puffs_mount * |
|
Line 90 puffs_suspendtouser(struct puffs_mount * |
|
|
|
pvfsr_susp = malloc(sizeof(struct puffs_vfsreq_suspend), |
pvfsr_susp = malloc(sizeof(struct puffs_vfsreq_suspend), |
M_PUFFS, M_WAITOK | M_ZERO); |
M_PUFFS, M_WAITOK | M_ZERO); |
ppark = pool_cache_get(&parkpc, PR_WAITOK); |
ppark = malloc(sizeof(struct puffs_park), M_PUFFS, M_WAITOK | M_ZERO); |
|
|
pvfsr_susp->pvfsr_status = status; |
pvfsr_susp->pvfsr_status = status; |
ppark->park_preq = (struct puffs_req *)pvfsr_susp; |
ppark->park_preq = (struct puffs_req *)pvfsr_susp; |
Line 217 puffs_vntouser(struct puffs_mount *pmp, |
|
Line 113 puffs_vntouser(struct puffs_mount *pmp, |
|
void *kbuf, size_t buflen, void *cookie, |
void *kbuf, size_t buflen, void *cookie, |
struct vnode *vp1, struct vnode *vp2) |
struct vnode *vp1, struct vnode *vp2) |
{ |
{ |
struct puffs_park *ppark; |
struct puffs_park park; |
|
|
ppark = pool_cache_get(&parkpc, PR_WAITOK); |
park.park_preq = kbuf; |
ppark->park_preq = kbuf; |
|
|
|
ppark->park_preq->preq_opclass = PUFFSOP_VN; |
park.park_preq->preq_opclass = PUFFSOP_VN; |
ppark->park_preq->preq_optype = optype; |
park.park_preq->preq_optype = optype; |
ppark->park_preq->preq_cookie = cookie; |
park.park_preq->preq_cookie = cookie; |
|
|
ppark->park_maxlen = ppark->park_copylen = buflen; |
park.park_maxlen = park.park_copylen = buflen; |
ppark->park_flags = 0; |
park.park_flags = 0; |
|
|
return touser(pmp, ppark, puffs_getreqid(pmp), vp1, vp2); |
return touser(pmp, &park, puffs_getreqid(pmp), vp1, vp2); |
} |
} |
|
|
/* |
/* |
Line 240 puffs_vntouser_req(struct puffs_mount *p |
|
Line 135 puffs_vntouser_req(struct puffs_mount *p |
|
void *kbuf, size_t buflen, void *cookie, uint64_t reqid, |
void *kbuf, size_t buflen, void *cookie, uint64_t reqid, |
struct vnode *vp1, struct vnode *vp2) |
struct vnode *vp1, struct vnode *vp2) |
{ |
{ |
struct puffs_park *ppark; |
struct puffs_park park; |
|
|
ppark = pool_cache_get(&parkpc, PR_WAITOK); |
park.park_preq = kbuf; |
ppark->park_preq = kbuf; |
|
|
|
ppark->park_preq->preq_opclass = PUFFSOP_VN; |
park.park_preq->preq_opclass = PUFFSOP_VN; |
ppark->park_preq->preq_optype = optype; |
park.park_preq->preq_optype = optype; |
ppark->park_preq->preq_cookie = cookie; |
park.park_preq->preq_cookie = cookie; |
|
|
ppark->park_maxlen = ppark->park_copylen = buflen; |
park.park_maxlen = park.park_copylen = buflen; |
ppark->park_flags = 0; |
park.park_flags = 0; |
|
|
return touser(pmp, ppark, reqid, vp1, vp2); |
return touser(pmp, &park, reqid, vp1, vp2); |
} |
} |
|
|
|
/* |
|
* vnode level request, copy routines can adjust "kernbuf". |
|
*/ |
int |
int |
puffs_vntouser_delta(struct puffs_mount *pmp, int optype, |
puffs_vntouser_adjbuf(struct puffs_mount *pmp, int optype, |
void *kbuf, size_t buflen, size_t maxdelta, |
void **kbuf, size_t *buflen, size_t maxdelta, |
void *cookie, struct vnode *vp1, struct vnode *vp2) |
void *cookie, struct vnode *vp1, struct vnode *vp2) |
{ |
{ |
struct puffs_park *ppark; |
struct puffs_park park; |
|
int error; |
|
|
ppark = pool_cache_get(&parkpc, PR_WAITOK); |
park.park_preq = *kbuf; |
ppark->park_preq = kbuf; |
|
|
|
ppark->park_preq->preq_opclass = PUFFSOP_VN; |
park.park_preq->preq_opclass = PUFFSOP_VN; |
ppark->park_preq->preq_optype = optype; |
park.park_preq->preq_optype = optype; |
ppark->park_preq->preq_cookie = cookie; |
park.park_preq->preq_cookie = cookie; |
|
|
ppark->park_copylen = buflen; |
park.park_copylen = *buflen; |
ppark->park_maxlen = buflen + maxdelta; |
park.park_maxlen = maxdelta + *buflen; |
ppark->park_flags = 0; |
park.park_flags = PUFFS_PARKFLAG_ADJUSTABLE; |
|
|
|
error = touser(pmp, &park, puffs_getreqid(pmp), vp1, vp2); |
|
|
|
*kbuf = park.park_preq; |
|
*buflen = park.park_copylen; |
|
|
return touser(pmp, ppark, puffs_getreqid(pmp), vp1, vp2); |
return error; |
} |
} |
|
|
/* |
/* |
* File server interaction is async from caller perspective. |
* File server interaction is async from caller perspective. |
* biodone(bp) is signalled in putop. |
* biodone(bp)J is signalled in putop. |
*/ |
*/ |
void |
void |
puffs_vntouser_bioread_async(struct puffs_mount *pmp, void *cookie, |
puffs_vntouser_bioread_async(struct puffs_mount *pmp, void *cookie, |
Line 288 puffs_vntouser_bioread_async(struct puff |
|
Line 190 puffs_vntouser_bioread_async(struct puff |
|
struct puffs_park *ppark; |
struct puffs_park *ppark; |
struct puffs_vnreq_read *read_argp; |
struct puffs_vnreq_read *read_argp; |
|
|
ppark = pool_cache_get(&parkpc, PR_WAITOK); |
MALLOC(ppark, struct puffs_park *, sizeof(struct puffs_park), |
|
M_PUFFS, M_WAITOK); |
MALLOC(read_argp, struct puffs_vnreq_read *, |
MALLOC(read_argp, struct puffs_vnreq_read *, |
sizeof(struct puffs_vnreq_read) + tomove, |
sizeof(struct puffs_vnreq_read), M_PUFFS, M_WAITOK | M_ZERO); |
M_PUFFS, M_WAITOK | M_ZERO); |
|
|
|
read_argp->pvnr_ioflag = 0; |
read_argp->pvnr_ioflag = 0; |
read_argp->pvnr_resid = tomove; |
read_argp->pvnr_resid = tomove; |
Line 306 puffs_vntouser_bioread_async(struct puff |
|
Line 208 puffs_vntouser_bioread_async(struct puff |
|
ppark->park_copylen = sizeof(struct puffs_vnreq_read); |
ppark->park_copylen = sizeof(struct puffs_vnreq_read); |
ppark->park_maxlen = sizeof(struct puffs_vnreq_read) + tomove; |
ppark->park_maxlen = sizeof(struct puffs_vnreq_read) + tomove; |
ppark->park_bp = bp; |
ppark->park_bp = bp; |
ppark->park_flags = PARKFLAG_ASYNCBIOREAD; |
ppark->park_flags |
|
= PUFFS_PARKFLAG_ADJUSTABLE | PUFFS_PARKFLAG_ASYNCBIOREAD; |
|
|
(void)touser(pmp, ppark, puffs_getreqid(pmp), vp1, vp2); |
(void)touser(pmp, ppark, puffs_getreqid(pmp), vp1, vp2); |
} |
} |
Line 323 puffs_vntouser_faf(struct puffs_mount *p |
|
Line 226 puffs_vntouser_faf(struct puffs_mount *p |
|
struct puffs_park *ppark; |
struct puffs_park *ppark; |
|
|
/* XXX: is it allowable to sleep here? */ |
/* XXX: is it allowable to sleep here? */ |
ppark = pool_cache_get(&parkpc, PR_NOWAIT); |
ppark = malloc(sizeof(struct puffs_park), M_PUFFS, M_NOWAIT | M_ZERO); |
if (ppark == NULL) |
if (ppark == NULL) |
return; /* 2bad */ |
return; /* 2bad */ |
|
|
|
|
touser(struct puffs_mount *pmp, struct puffs_park *ppark, uint64_t reqid, |
touser(struct puffs_mount *pmp, struct puffs_park *ppark, uint64_t reqid, |
struct vnode *vp1, struct vnode *vp2) |
struct vnode *vp1, struct vnode *vp2) |
{ |
{ |
|
struct lwp *l = curlwp; |
struct mount *mp; |
struct mount *mp; |
struct puffs_req *preq; |
struct puffs_req *preq; |
int rv = 0; |
int rv = 0; |
Line 377 touser(struct puffs_mount *pmp, struct p |
|
Line 281 touser(struct puffs_mount *pmp, struct p |
|
preq->preq_id = ppark->park_id = reqid; |
preq->preq_id = ppark->park_id = reqid; |
preq->preq_buflen = ALIGN(ppark->park_maxlen); |
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 |
* To support PCATCH, yet another movie: check if there are signals |
* pending and we are issueing a non-FAF. If so, return an error |
* pending and we are issueing a non-FAF. If so, return an error |
Line 390 touser(struct puffs_mount *pmp, struct p |
|
Line 288 touser(struct puffs_mount *pmp, struct p |
|
* it to a FAF, fire off to the file server and return an error. |
* it to a FAF, fire off to the file server and return an error. |
* Yes, this is bordering disgusting. Barfbags are on me. |
* Yes, this is bordering disgusting. Barfbags are on me. |
*/ |
*/ |
if (PUFFSOP_WANTREPLY(preq->preq_opclass) |
if (PUFFSOP_WANTREPLY(ppark->park_preq->preq_opclass) |
&& (ppark->park_flags & PARKFLAG_ASYNCBIOREAD) == 0 |
&& (ppark->park_flags & PUFFS_PARKFLAG_ASYNCBIOREAD) == 0 |
&& (l->l_flag & LW_PENDSIG) != 0 && sigispending(l, 0)) { |
&& (l->l_flag & LW_PENDSIG) != 0 && sigispending(l, 0)) { |
if (PUFFSOP_OPCLASS(preq->preq_opclass) == PUFFSOP_VN |
if (PUFFSOP_OPCLASS(preq->preq_opclass) == PUFFSOP_VN |
&& preq->preq_optype == PUFFS_VN_INACTIVE) { |
&& preq->preq_optype == PUFFS_VN_INACTIVE) { |
puffs_reqtofaf(ppark); |
struct puffs_park *newpark; |
DPRINTF(("puffs touser: converted to FAF %p\n", ppark)); |
|
|
newpark = puffs_reqtofaf(ppark); |
|
DPRINTF(("puffs touser: converted to FAF, old %p, " |
|
"new %p\n", ppark, newpark)); |
|
ppark = newpark; |
rv = EINTR; |
rv = EINTR; |
} else { |
} else { |
return EINTR; |
return EINTR; |
} |
} |
} |
} |
#endif |
|
|
|
/* |
/* |
* test for suspension lock. |
* test for suspension lock. |
Line 427 touser(struct puffs_mount *pmp, struct p |
|
Line 328 touser(struct puffs_mount *pmp, struct p |
|
* in the kernel while the fs is suspending. It's not a very |
* in the kernel while the fs is suspending. It's not a very |
* likely event, but it needs to be fixed some day. |
* 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); |
fstrans_start(mp, FSTRANS_NORMAL); |
mutex_enter(&pmp->pmp_lock); |
simple_lock(&pmp->pmp_lock); |
fstrans_done(mp); |
fstrans_done(mp); |
|
|
if (pmp->pmp_status != PUFFSTAT_RUNNING) { |
if (pmp->pmp_status != PUFFSTAT_RUNNING) { |
mutex_exit(&pmp->pmp_lock); |
simple_unlock(&pmp->pmp_lock); |
pool_cache_put(&parkpc, ppark); |
|
return ENXIO; |
return ENXIO; |
} |
} |
|
|
TAILQ_INSERT_TAIL(&pmp->pmp_req_touser, ppark, park_entries); |
TAILQ_INSERT_TAIL(&pmp->pmp_req_touser, ppark, park_entries); |
pmp->pmp_req_waiters++; |
pmp->pmp_req_touser_waiters++; |
|
|
#if 0 |
|
/* |
/* |
* Don't do unlock-relock dance yet. There are a couple of |
* Don't do unlock-relock dance yet. There are a couple of |
* unsolved issues with it. If we don't unlock, we can have |
* unsolved issues with it. If we don't unlock, we can have |
Line 454 touser(struct puffs_mount *pmp, struct p |
|
Line 348 touser(struct puffs_mount *pmp, struct p |
|
* would of course be nicer to have antilocking in the userspace |
* would of course be nicer to have antilocking in the userspace |
* interface protocol itself.. your patience will be rewarded. |
* interface protocol itself.. your patience will be rewarded. |
*/ |
*/ |
|
#if 0 |
/* unlock */ |
/* unlock */ |
if (vp2) |
if (vp2) |
VOP_UNLOCK(vp2, 0); |
VOP_UNLOCK(vp2, 0); |
Line 461 touser(struct puffs_mount *pmp, struct p |
|
Line 356 touser(struct puffs_mount *pmp, struct p |
|
VOP_UNLOCK(vp1, 0); |
VOP_UNLOCK(vp1, 0); |
#endif |
#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, " |
DPRINTF(("touser: req %" PRIu64 ", preq: %p, park: %p, " |
"c/t: 0x%x/0x%x, f: 0x%x\n", preq->preq_id, preq, ppark, |
"c/t: 0x%x/0x%x, f: 0x%x\n", preq->preq_id, preq, ppark, |
preq->preq_opclass, preq->preq_optype, ppark->park_flags)); |
preq->preq_opclass, preq->preq_optype, ppark->park_flags)); |
|
|
cv_broadcast(&pmp->pmp_req_waiter_cv); |
wakeup(&pmp->pmp_req_touser); |
selnotify(pmp->pmp_sel, 0); |
selnotify(pmp->pmp_sel, 0); |
|
|
if (PUFFSOP_WANTREPLY(preq->preq_opclass) |
if (PUFFSOP_WANTREPLY(ppark->park_preq->preq_opclass) |
&& (ppark->park_flags & PARKFLAG_ASYNCBIOREAD) == 0) { |
&& (ppark->park_flags & PUFFS_PARKFLAG_ASYNCBIOREAD) == 0) { |
|
struct puffs_park *valetpark = NULL; |
int error; |
int error; |
|
|
error = 0; /* XXX: no interrupt for now */ |
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; |
|
} |
|
|
cv_wait(&ppark->park_cv, &pmp->pmp_lock); |
|
if (error) { |
if (error) { |
ppark->park_flags |= PARKFLAG_WAITERGONE; |
DPRINTF(("puffs touser: got %d from ltsleep, " |
if (ppark->park_flags & PARKFLAG_PROCESSING) { |
"(unlocked) flags 0x%x (park %p)\n", |
cv_wait(&ppark->park_cv, &pmp->pmp_lock); |
error, ppark->park_flags, ppark)); |
rv = preq->preq_rv; |
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; |
|
} |
} else { |
} else { |
rv = error; |
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)); |
} |
} |
} else { |
|
rv = preq->preq_rv; |
|
} |
} |
mutex_exit(&pmp->pmp_lock); |
|
pool_cache_put(&parkpc, ppark); |
|
|
|
/* |
/* |
* retake the lock and release. This makes sure (haha, |
* retake the lock and release. This makes sure (haha, |
* I'm humorous) that we don't process the same vnode in |
* I'm humorous) that we don't process the same vnode in |
Line 502 touser(struct puffs_mount *pmp, struct p |
|
Line 482 touser(struct puffs_mount *pmp, struct p |
|
fstrans_start(mp, FSTRANS_NORMAL); |
fstrans_start(mp, FSTRANS_NORMAL); |
fstrans_done(mp); |
fstrans_done(mp); |
} |
} |
} else { |
|
mutex_exit(&pmp->pmp_lock); |
|
} |
} |
|
|
#if 0 |
#if 0 |
Line 514 touser(struct puffs_mount *pmp, struct p |
|
Line 492 touser(struct puffs_mount *pmp, struct p |
|
KASSERT(vn_lock(vp2, LK_EXCLUSIVE | LK_RETRY) == 0); |
KASSERT(vn_lock(vp2, LK_EXCLUSIVE | LK_RETRY) == 0); |
#endif |
#endif |
|
|
mutex_enter(&pmp->pmp_lock); |
simple_lock(&pmp->pmp_lock); |
if (--pmp->pmp_req_waiters == 0) { |
if (--pmp->pmp_req_touser_waiters == 0) |
KASSERT(cv_has_waiters(&pmp->pmp_req_waitersink_cv) <= 1); |
wakeup(&pmp->pmp_req_touser_waiters); |
cv_signal(&pmp->pmp_req_waitersink_cv); |
simple_unlock(&pmp->pmp_lock); |
} |
|
mutex_exit(&pmp->pmp_lock); |
|
|
|
return rv; |
return rv; |
} |
} |
Line 546 puffs_getop(struct puffs_mount *pmp, str |
|
Line 522 puffs_getop(struct puffs_mount *pmp, str |
|
donesome = error = 0; |
donesome = error = 0; |
bufpos = phg->phg_buf; |
bufpos = phg->phg_buf; |
|
|
mutex_enter(&pmp->pmp_lock); |
simple_lock(&pmp->pmp_lock); |
while (phg->phg_nops == 0 || donesome != phg->phg_nops) { |
while (phg->phg_nops == 0 || donesome != phg->phg_nops) { |
again: |
again: |
if (pmp->pmp_status != PUFFSTAT_RUNNING) { |
if (pmp->pmp_status != PUFFSTAT_RUNNING) { |
Line 563 puffs_getop(struct puffs_mount *pmp, str |
|
Line 539 puffs_getop(struct puffs_mount *pmp, str |
|
goto out; |
goto out; |
} |
} |
|
|
error = cv_wait_sig(&pmp->pmp_req_waiter_cv, |
error = ltsleep(&pmp->pmp_req_touser, PUSER | PCATCH, |
&pmp->pmp_lock); |
"puffs2", 0, &pmp->pmp_lock); |
if (error) |
if (error) |
goto out; |
goto out; |
else |
else |
Line 573 puffs_getop(struct puffs_mount *pmp, str |
|
Line 549 puffs_getop(struct puffs_mount *pmp, str |
|
|
|
park = TAILQ_FIRST(&pmp->pmp_req_touser); |
park = TAILQ_FIRST(&pmp->pmp_req_touser); |
preq = park->park_preq; |
preq = park->park_preq; |
|
|
if (phg->phg_buflen < preq->preq_buflen) { |
if (phg->phg_buflen < preq->preq_buflen) { |
if (!donesome) |
if (!donesome) |
error = E2BIG; |
error = E2BIG; |
goto out; |
goto out; |
} |
} |
TAILQ_REMOVE(&pmp->pmp_req_touser, park, park_entries); |
TAILQ_REMOVE(&pmp->pmp_req_touser, park, park_entries); |
|
park->park_flags |= PUFFS_PARKFLAG_PROCESSING; |
/* If it's a goner, don't process any furher */ |
simple_unlock(&pmp->pmp_lock); |
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 " |
DPRINTF(("puffsgetop: get op %" PRIu64 " (%d.), from %p " |
"len %zu (buflen %zu), target %p\n", preq->preq_id, |
"len %zu (buflen %zu), target %p\n", preq->preq_id, |
Line 595 puffs_getop(struct puffs_mount *pmp, str |
|
Line 565 puffs_getop(struct puffs_mount *pmp, str |
|
bufpos)); |
bufpos)); |
|
|
if ((error = copyout(preq, bufpos, park->park_copylen)) != 0) { |
if ((error = copyout(preq, bufpos, park->park_copylen)) != 0) { |
DPRINTF(("puffs_getop: copyout failed\n")); |
DPRINTF((" FAILED %d\n", error)); |
/* |
/* |
* ok, user server is probably trying to cheat. |
* ok, user server is probably trying to cheat. |
* stuff op back & return error to user |
* stuff op back & return error to user |
*/ |
*/ |
mutex_enter(&pmp->pmp_lock); |
simple_lock(&pmp->pmp_lock); |
TAILQ_INSERT_HEAD(&pmp->pmp_req_touser, park, |
TAILQ_INSERT_HEAD(&pmp->pmp_req_touser, park, |
park_entries); |
park_entries); |
|
|
Line 612 puffs_getop(struct puffs_mount *pmp, str |
|
Line 582 puffs_getop(struct puffs_mount *pmp, str |
|
phg->phg_buflen -= preq->preq_buflen; |
phg->phg_buflen -= preq->preq_buflen; |
donesome++; |
donesome++; |
|
|
mutex_enter(&pmp->pmp_lock); |
simple_lock(&pmp->pmp_lock); |
if (PUFFSOP_WANTREPLY(preq->preq_opclass)) { |
if (PUFFSOP_WANTREPLY(preq->preq_opclass)) { |
TAILQ_INSERT_TAIL(&pmp->pmp_req_replywait, park, |
if ((park->park_flags & PUFFS_PARKFLAG_WAITERGONE)==0) { |
park_entries); |
TAILQ_INSERT_TAIL(&pmp->pmp_req_replywait, park, |
|
park_entries); |
|
park->park_flags |= PUFFS_PARKFLAG_RQUEUE; |
|
} |
} else { |
} else { |
|
simple_unlock(&pmp->pmp_lock); |
free(preq, M_PUFFS); |
free(preq, M_PUFFS); |
pool_cache_put(&parkpc, park); |
free(park, M_PUFFS); |
|
simple_lock(&pmp->pmp_lock); |
} |
} |
} |
} |
|
|
out: |
out: |
phg->phg_more = pmp->pmp_req_waiters; |
phg->phg_more = pmp->pmp_req_touser_waiters; |
mutex_exit(&pmp->pmp_lock); |
simple_unlock(&pmp->pmp_lock); |
|
|
phg->phg_nops = donesome; |
phg->phg_nops = donesome; |
|
|
return error; |
return error; |
} |
} |
|
|
|
/* |
|
* urgh, too complex, be very very careful while editing, i.e. NEEDS CLEANUP |
|
*/ |
int |
int |
puffs_putop(struct puffs_mount *pmp, struct puffs_reqh_put *php) |
puffs_putop(struct puffs_mount *pmp, struct puffs_reqh_put *php) |
{ |
{ |
Line 649 puffs_putop(struct puffs_mount *pmp, str |
|
Line 627 puffs_putop(struct puffs_mount *pmp, str |
|
userbuf = php->php_buf; |
userbuf = php->php_buf; |
reqlen = php->php_buflen; |
reqlen = php->php_buflen; |
|
|
mutex_enter(&pmp->pmp_lock); |
simple_lock(&pmp->pmp_lock); |
while (donesome != php->php_nops) { |
while (donesome != php->php_nops) { |
#ifdef PUFFSDEBUG |
#ifdef PUFFSDEBUG |
|
simple_unlock(&pmp->pmp_lock); |
DPRINTF(("puffsputop: searching for %" PRIu64 ", ubuf: %p, " |
DPRINTF(("puffsputop: searching for %" PRIu64 ", ubuf: %p, " |
"len %zu\n", id, userbuf, reqlen)); |
"len %zu\n", id, userbuf, reqlen)); |
|
simple_lock(&pmp->pmp_lock); |
#endif |
#endif |
TAILQ_FOREACH(park, &pmp->pmp_req_replywait, park_entries) { |
TAILQ_FOREACH(park, &pmp->pmp_req_replywait, park_entries) { |
if (park->park_id == id) |
if (park->park_id == id) |
Line 665 puffs_putop(struct puffs_mount *pmp, str |
|
Line 645 puffs_putop(struct puffs_mount *pmp, str |
|
break; |
break; |
} |
} |
TAILQ_REMOVE(&pmp->pmp_req_replywait, park, park_entries); |
TAILQ_REMOVE(&pmp->pmp_req_replywait, park, park_entries); |
wgone = park->park_flags & PARKFLAG_WAITERGONE; |
park->park_flags |= PUFFS_PARKFLAG_RECVREPLY; |
park->park_flags |= PARKFLAG_PROCESSING; |
simple_unlock(&pmp->pmp_lock); |
mutex_exit(&pmp->pmp_lock); |
|
|
|
/* |
/* |
* If the caller has gone south, go to next, collect |
* If the caller has gone south, go to next, collect |
* $200 and free the structure there instead of wakeup. |
* $200 and free the structure there instead of wakeup. |
* We also need to copyin the |
* We also need to copyin the |
*/ |
*/ |
if (wgone) { |
if (park->park_flags & PUFFS_PARKFLAG_WAITERGONE) { |
panic("puffs: wgone impossible for now\n"); |
|
DPRINTF(("puffs_putop: bad service - waiter gone for " |
DPRINTF(("puffs_putop: bad service - waiter gone for " |
"park %p\n", park)); |
"park %p\n", park)); |
|
wgone = 1; |
error = copyin(userbuf, &tmpreq, |
error = copyin(userbuf, &tmpreq, |
sizeof(struct puffs_req)); |
sizeof(struct puffs_req)); |
if (error) |
if (error) |
Line 686 puffs_putop(struct puffs_mount *pmp, str |
|
Line 665 puffs_putop(struct puffs_mount *pmp, str |
|
goto next; |
goto next; |
} |
} |
|
|
if (reqlen == 0 || reqlen > park->park_maxlen) { |
if (park->park_flags & PUFFS_PARKFLAG_ADJUSTABLE) { |
reqlen = park->park_maxlen; |
/* sanitycheck size of incoming transmission. */ |
DPRINTF(("puffsputop: kernel bufsize override: " |
if (reqlen > pmp->pmp_req_maxsize) { |
"%zu\n", reqlen)); |
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)); |
|
} |
} |
} |
|
|
DPRINTF(("puffsputpop: copyin from %p to %p, len %zu\n", |
DPRINTF(("puffsputpop: copyin from %p to %p, len %zu\n", |
Line 700 puffs_putop(struct puffs_mount *pmp, str |
|
Line 706 puffs_putop(struct puffs_mount *pmp, str |
|
nextpreq = park->park_preq; |
nextpreq = park->park_preq; |
bp = park->park_bp; |
bp = park->park_bp; |
|
|
if (park->park_flags & PARKFLAG_ASYNCBIOREAD) { |
if (park->park_flags & PUFFS_PARKFLAG_ASYNCBIOREAD) { |
struct puffs_vnreq_read *read_argp; |
struct puffs_vnreq_read *read_argp; |
size_t moved; |
size_t moved; |
|
|
Line 730 puffs_putop(struct puffs_mount *pmp, str |
|
Line 736 puffs_putop(struct puffs_mount *pmp, str |
|
loopout: |
loopout: |
if (error && park->park_preq) { |
if (error && park->park_preq) { |
park->park_preq->preq_rv = error; |
park->park_preq->preq_rv = error; |
if (park->park_flags & PARKFLAG_ASYNCBIOREAD) { |
if (park->park_flags & PUFFS_PARKFLAG_ASYNCBIOREAD) { |
bp = park->park_bp; |
bp = park->park_bp; |
bp->b_error = error; |
bp->b_error = error; |
bp->b_flags |= B_ERROR; |
bp->b_flags |= B_ERROR; |
Line 738 puffs_putop(struct puffs_mount *pmp, str |
|
Line 744 puffs_putop(struct puffs_mount *pmp, str |
|
} |
} |
} |
} |
|
|
mutex_enter(&pmp->pmp_lock); |
if (wgone) { |
if (!wgone) { |
FREE(park, M_PUFFS); |
if (park->park_flags & PARKFLAG_ASYNCBIOREAD) { |
simple_lock(&pmp->pmp_lock); |
free(park->park_preq, M_PUFFS); |
} else if (park->park_flags & PUFFS_PARKFLAG_ASYNCBIOREAD) { |
pool_cache_put(&parkpc, park); |
free(park->park_preq, M_PUFFS); |
} else { |
FREE(park, M_PUFFS); |
DPRINTF(("puffs_putop: flagging done for " |
simple_lock(&pmp->pmp_lock); |
"park %p\n", park)); |
} else { |
|
DPRINTF(("puffs_putop: flagging done for park %p\n", |
cv_signal(&park->park_cv); |
park)); |
} |
simple_lock(&pmp->pmp_lock); |
|
park->park_flags |= PUFFS_PARKFLAG_DONE; |
|
wakeup(park); |
} |
} |
|
|
if (error) |
if (error) |
Line 756 puffs_putop(struct puffs_mount *pmp, str |
|
Line 764 puffs_putop(struct puffs_mount *pmp, str |
|
wgone = 0; |
wgone = 0; |
} |
} |
|
|
mutex_exit(&pmp->pmp_lock); |
simple_unlock(&pmp->pmp_lock); |
php->php_nops -= donesome; |
php->php_nops -= donesome; |
|
|
return error; |
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? */ |
/* this is probably going to die away at some point? */ |
/* |
/* |
* XXX: currently bitrotted |
* XXX: currently bitrotted |
Line 839 puffssizeop(struct puffs_mount *pmp, str |
|
Line 784 puffssizeop(struct puffs_mount *pmp, str |
|
int error; |
int error; |
|
|
/* locate correct op */ |
/* locate correct op */ |
mutex_enter(&pmp->pmp_lock); |
simple_lock(&pmp->pmp_lock); |
TAILQ_FOREACH(pspark, &pmp->pmp_req_sizepark, pkso_entries) { |
TAILQ_FOREACH(pspark, &pmp->pmp_req_sizepark, pkso_entries) { |
if (pspark->pkso_reqid == psop_user->pso_reqid) { |
if (pspark->pkso_reqid == psop_user->pso_reqid) { |
TAILQ_REMOVE(&pmp->pmp_req_sizepark, pspark, |
TAILQ_REMOVE(&pmp->pmp_req_sizepark, pspark, |
Line 847 puffssizeop(struct puffs_mount *pmp, str |
|
Line 792 puffssizeop(struct puffs_mount *pmp, str |
|
break; |
break; |
} |
} |
} |
} |
mutex_exit(&pmp->pmp_lock); |
simple_unlock(&pmp->pmp_lock); |
|
|
if (pspark == NULL) |
if (pspark == NULL) |
return EINVAL; |
return EINVAL; |