version 1.40, 2007/07/19 22:05:22 |
version 1.40.4.4, 2007/10/28 20:11:09 |
Line 34 __KERNEL_RCSID(0, "$NetBSD$"); |
|
Line 34 __KERNEL_RCSID(0, "$NetBSD$"); |
|
|
|
#include <sys/param.h> |
#include <sys/param.h> |
#include <sys/fstrans.h> |
#include <sys/fstrans.h> |
|
#include <sys/kmem.h> |
#include <sys/malloc.h> |
#include <sys/malloc.h> |
#include <sys/mount.h> |
#include <sys/mount.h> |
#include <sys/vnode.h> |
#include <sys/vnode.h> |
Line 51 __KERNEL_RCSID(0, "$NetBSD$"); |
|
Line 52 __KERNEL_RCSID(0, "$NetBSD$"); |
|
* While a request is going to userspace, park the caller within the |
* While a request is going to userspace, park the caller within the |
* kernel. This is the kernel counterpart of "struct puffs_req". |
* kernel. This is the kernel counterpart of "struct puffs_req". |
*/ |
*/ |
struct puffs_park { |
struct puffs_msgpark { |
struct puffs_req *park_preq; /* req followed by buf */ |
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_copylen; /* userspace copylength */ |
size_t park_maxlen; /* max size in comeback */ |
size_t park_maxlen; /* max size in comeback */ |
|
|
parkdone_fn park_done; |
parkdone_fn park_done; /* "biodone" a'la puffs */ |
void *park_donearg; |
void *park_donearg; |
|
|
int park_flags; |
int park_flags; |
Line 67 struct puffs_park { |
|
Line 67 struct puffs_park { |
|
kcondvar_t park_cv; |
kcondvar_t park_cv; |
kmutex_t park_mtx; |
kmutex_t park_mtx; |
|
|
TAILQ_ENTRY(puffs_park) park_entries; |
TAILQ_ENTRY(puffs_msgpark) park_entries; |
}; |
}; |
#define PARKFLAG_WAITERGONE 0x01 |
#define PARKFLAG_WAITERGONE 0x01 |
#define PARKFLAG_DONE 0x02 |
#define PARKFLAG_DONE 0x02 |
Line 82 static struct pool parkpool; |
|
Line 82 static struct pool parkpool; |
|
static int |
static int |
makepark(void *arg, void *obj, int flags) |
makepark(void *arg, void *obj, int flags) |
{ |
{ |
struct puffs_park *park = obj; |
struct puffs_msgpark *park = obj; |
|
|
mutex_init(&park->park_mtx, MUTEX_DEFAULT, IPL_NONE); |
mutex_init(&park->park_mtx, MUTEX_DEFAULT, IPL_NONE); |
cv_init(&park->park_cv, "puffsrpl"); |
cv_init(&park->park_cv, "puffsrpl"); |
Line 93 makepark(void *arg, void *obj, int flags |
|
Line 93 makepark(void *arg, void *obj, int flags |
|
static void |
static void |
nukepark(void *arg, void *obj) |
nukepark(void *arg, void *obj) |
{ |
{ |
struct puffs_park *park = obj; |
struct puffs_msgpark *park = obj; |
|
|
cv_destroy(&park->park_cv); |
cv_destroy(&park->park_cv); |
mutex_destroy(&park->park_mtx); |
mutex_destroy(&park->park_mtx); |
|
|
puffs_msgif_init() |
puffs_msgif_init() |
{ |
{ |
|
|
pool_init(&parkpool, sizeof(struct puffs_park), 0, 0, 0, |
pool_init(&parkpool, sizeof(struct puffs_msgpark), 0, 0, 0, |
"puffprkl", &pool_allocator_nointr, IPL_NONE); |
"puffprkl", &pool_allocator_nointr, IPL_NONE); |
pool_cache_init(&parkpc, &parkpool, makepark, nukepark, NULL); |
pool_cache_init(&parkpc, &parkpool, makepark, nukepark, NULL); |
} |
} |
Line 116 puffs_msgif_destroy() |
|
Line 116 puffs_msgif_destroy() |
|
pool_destroy(&parkpool); |
pool_destroy(&parkpool); |
} |
} |
|
|
void * |
static int alloced; |
puffs_park_alloc(int waitok) |
|
|
static struct puffs_msgpark * |
|
puffs_msgpark_alloc(int waitok) |
{ |
{ |
struct puffs_park *park; |
struct puffs_msgpark *park; |
|
|
park = pool_cache_get(&parkpc, waitok ? PR_WAITOK : PR_NOWAIT); |
park = pool_cache_get(&parkpc, waitok ? PR_WAITOK : PR_NOWAIT); |
if (park) { |
if (park == NULL) |
park->park_refcount = 1; |
return park; |
mutex_enter(&park->park_mtx); |
|
} |
park->park_refcount = 1; |
|
park->park_preq = NULL; |
|
park->park_flags = PARKFLAG_WANTREPLY; |
|
|
return park; |
return park; |
} |
} |
|
|
static void |
static void |
puffs_park_reference(struct puffs_park *park) |
puffs_msgpark_reference(struct puffs_msgpark *park) |
{ |
{ |
|
|
mutex_enter(&park->park_mtx); |
KASSERT(mutex_owned(&park->park_mtx)); |
park->park_refcount++; |
park->park_refcount++; |
} |
} |
|
|
void |
/* |
puffs_park_release(void *arg, int fullnuke) |
* Release reference to park structure. |
|
*/ |
|
static void |
|
puffs_msgpark_release1(struct puffs_msgpark *park, int howmany) |
{ |
{ |
struct puffs_park *park = arg; |
struct puffs_req *preq = park->park_preq; |
|
int refcnt; |
|
|
KASSERT(mutex_owned(&park->park_mtx)); |
KASSERT(mutex_owned(&park->park_mtx)); |
--park->park_refcount; |
refcnt = park->park_refcount -= howmany; |
|
|
mutex_exit(&park->park_mtx); |
mutex_exit(&park->park_mtx); |
if (park->park_refcount == 0 || fullnuke) |
|
|
KASSERT(refcnt >= 0); |
|
|
|
if (refcnt == 0) { |
|
alloced--; |
|
if (preq) |
|
kmem_free(preq, park->park_maxlen); |
pool_cache_put(&parkpc, park); |
pool_cache_put(&parkpc, park); |
|
} |
} |
} |
|
#define puffs_msgpark_release(a) puffs_msgpark_release1(a, 1) |
|
|
#ifdef PUFFSDEBUG |
#ifdef PUFFSDEBUG |
static void |
static void |
parkdump(struct puffs_park *park) |
parkdump(struct puffs_msgpark *park) |
{ |
{ |
|
|
DPRINTF(("park %p, preq %p, id %" PRIu64 "\n" |
DPRINTF(("park %p, preq %p, id %" PRIu64 "\n" |
"\tcopy %zu, max %zu - done: %p/%p\n" |
"\tcopy %zu, max %zu - done: %p/%p\n" |
"\tflags 0x%08x, refcount %d, cv/mtx: %p/%p\n", |
"\tflags 0x%08x, refcount %d, cv/mtx: %p/%p\n", |
park, park->park_preq, park->park_id, |
park, park->park_preq, park->park_preq->preq_id, |
park->park_copylen, park->park_maxlen, |
park->park_copylen, park->park_maxlen, |
park->park_done, park->park_donearg, |
park->park_done, park->park_donearg, |
park->park_flags, park->park_refcount, |
park->park_flags, park->park_refcount, |
Line 169 parkdump(struct puffs_park *park) |
|
Line 184 parkdump(struct puffs_park *park) |
|
static void |
static void |
parkqdump(struct puffs_wq *q, int dumpall) |
parkqdump(struct puffs_wq *q, int dumpall) |
{ |
{ |
struct puffs_park *park; |
struct puffs_msgpark *park; |
int total = 0; |
int total = 0; |
|
|
TAILQ_FOREACH(park, q, park_entries) { |
TAILQ_FOREACH(park, q, park_entries) { |
Line 183 parkqdump(struct puffs_wq *q, int dumpal |
|
Line 198 parkqdump(struct puffs_wq *q, int dumpal |
|
#endif /* PUFFSDEBUG */ |
#endif /* PUFFSDEBUG */ |
|
|
/* |
/* |
* Converts a non-FAF op to a FAF. This simply involves making copies |
* A word about locking in the park structures: the lock protects the |
* of the park and request structures and tagging the request as a FAF. |
* fields of the *park* structure (not preq) and acts as an interlock |
* It is safe to block here, since the original op is not a FAF. |
* in cv operations. The lock is always internal to this module and |
|
* callers do not need to worry about it. |
*/ |
*/ |
static void |
|
puffs_reqtofaf(struct puffs_park *park) |
int |
|
puffs_msgmem_alloc(size_t len, struct puffs_msgpark **ppark, void **mem, |
|
int cansleep) |
{ |
{ |
struct puffs_req *newpreq; |
struct puffs_msgpark *park; |
|
void *m; |
|
|
|
m = kmem_zalloc(len, cansleep ? KM_SLEEP : KM_NOSLEEP); |
|
if (m == NULL) { |
|
KASSERT(cansleep == 0); |
|
return ENOMEM; |
|
} |
|
|
KASSERT((park->park_preq->preq_opclass & PUFFSOPFLAG_FAF) == 0); |
park = puffs_msgpark_alloc(cansleep); |
|
if (park == NULL) { |
|
KASSERT(cansleep == 0); |
|
kmem_free(m, len); |
|
return ENOMEM; |
|
} |
|
|
MALLOC(newpreq, struct puffs_req *, park->park_copylen, |
park->park_preq = m; |
M_PUFFS, M_ZERO | M_WAITOK); |
park->park_maxlen = len; |
|
|
memcpy(newpreq, park->park_preq, park->park_copylen); |
*ppark = park; |
|
*mem = m; |
|
|
park->park_preq = newpreq; |
return 0; |
park->park_preq->preq_opclass |= PUFFSOPFLAG_FAF; |
} |
park->park_flags &= ~PARKFLAG_WANTREPLY; |
|
|
void |
|
puffs_msgmem_release(struct puffs_msgpark *park) |
|
{ |
|
|
|
if (park == NULL) |
|
return; |
|
|
|
mutex_enter(&park->park_mtx); |
|
puffs_msgpark_release(park); |
} |
} |
|
|
|
void |
|
puffs_msg_setfaf(struct puffs_msgpark *park) |
|
{ |
|
|
|
park->park_flags &= ~PARKFLAG_WANTREPLY; |
|
} |
|
|
/* |
/* |
* kernel-user-kernel waitqueues |
* kernel-user-kernel waitqueues |
*/ |
*/ |
|
|
static int touser(struct puffs_mount *, struct puffs_park *, uint64_t); |
static int touser(struct puffs_mount *, struct puffs_msgpark *); |
|
|
uint64_t |
static uint64_t |
puffs_getreqid(struct puffs_mount *pmp) |
puffs_getmsgid(struct puffs_mount *pmp) |
{ |
{ |
uint64_t rv; |
uint64_t rv; |
|
|
mutex_enter(&pmp->pmp_lock); |
mutex_enter(&pmp->pmp_lock); |
rv = pmp->pmp_nextreq++; |
rv = pmp->pmp_nextmsgid++; |
mutex_exit(&pmp->pmp_lock); |
mutex_exit(&pmp->pmp_lock); |
|
|
return rv; |
return rv; |
Line 225 puffs_getreqid(struct puffs_mount *pmp) |
|
Line 271 puffs_getreqid(struct puffs_mount *pmp) |
|
|
|
/* vfs request */ |
/* vfs request */ |
int |
int |
puffs_vfstouser(struct puffs_mount *pmp, int optype, void *kbuf, size_t buflen) |
puffs_msg_vfs(struct puffs_mount *pmp, struct puffs_msgpark *park, int optype) |
{ |
{ |
struct puffs_park *park; |
|
|
|
park = puffs_park_alloc(1); |
|
park->park_preq = kbuf; |
|
|
|
park->park_preq->preq_opclass = PUFFSOP_VFS; |
park->park_preq->preq_opclass = PUFFSOP_VFS; |
park->park_preq->preq_optype = optype; |
park->park_preq->preq_optype = optype; |
|
|
park->park_maxlen = park->park_copylen = buflen; |
park->park_copylen = park->park_maxlen; |
park->park_flags = 0; |
|
|
|
return touser(pmp, park, puffs_getreqid(pmp)); |
return touser(pmp, park); |
} |
|
|
|
void |
|
puffs_suspendtouser(struct puffs_mount *pmp, int status) |
|
{ |
|
struct puffs_vfsreq_suspend *pvfsr_susp; |
|
struct puffs_park *park; |
|
|
|
pvfsr_susp = malloc(sizeof(struct puffs_vfsreq_suspend), |
|
M_PUFFS, M_WAITOK | M_ZERO); |
|
park = puffs_park_alloc(1); |
|
|
|
pvfsr_susp->pvfsr_status = status; |
|
park->park_preq = (struct puffs_req *)pvfsr_susp; |
|
|
|
park->park_preq->preq_opclass = PUFFSOP_VFS | PUFFSOPFLAG_FAF; |
|
park->park_preq->preq_optype = PUFFS_VFS_SUSPEND; |
|
|
|
park->park_maxlen = park->park_copylen |
|
= sizeof(struct puffs_vfsreq_suspend); |
|
park->park_flags = 0; |
|
|
|
(void)touser(pmp, park, 0); |
|
} |
} |
|
|
/* |
/* |
* vnode level request |
* vnode level request |
*/ |
*/ |
int |
int |
puffs_vntouser(struct puffs_mount *pmp, int optype, |
puffs_msg_vn(struct puffs_mount *pmp, struct puffs_msgpark *park, |
void *kbuf, size_t buflen, size_t maxdelta, |
int optype, size_t delta, struct vnode *vp_opc, struct vnode *vp_aux) |
struct vnode *vp_opc, struct vnode *vp_aux) |
|
{ |
{ |
struct puffs_park *park; |
|
struct puffs_req *preq; |
struct puffs_req *preq; |
void *cookie = VPTOPNC(vp_opc); |
void *cookie = VPTOPNC(vp_opc); |
struct puffs_node *pnode; |
struct puffs_node *pnode; |
int rv; |
int rv; |
|
|
park = puffs_park_alloc(1); |
|
park->park_preq = kbuf; |
|
|
|
park->park_preq->preq_opclass = PUFFSOP_VN; |
park->park_preq->preq_opclass = PUFFSOP_VN; |
park->park_preq->preq_optype = optype; |
park->park_preq->preq_optype = optype; |
park->park_preq->preq_cookie = cookie; |
park->park_preq->preq_cookie = cookie; |
|
|
park->park_copylen = buflen; |
KASSERT(delta < park->park_maxlen); /* "<=" wouldn't make sense */ |
park->park_maxlen = buflen + maxdelta; |
park->park_copylen = park->park_maxlen - delta; |
park->park_flags = 0; |
|
|
|
rv = touser(pmp, park, puffs_getreqid(pmp)); |
rv = touser(pmp, park); |
|
|
/* |
/* |
* Check if the user server requests that inactive be called |
* Check if the user server requests that inactive be called |
Line 322 puffs_vntouser(struct puffs_mount *pmp, |
|
Line 334 puffs_vntouser(struct puffs_mount *pmp, |
|
return rv; |
return rv; |
} |
} |
|
|
/* |
|
* vnode level request, caller-controller req id |
|
*/ |
|
int |
|
puffs_vntouser_req(struct puffs_mount *pmp, int optype, |
|
void *kbuf, size_t buflen, size_t maxdelta, |
|
uint64_t reqid, struct vnode *vp_opc, struct vnode *vp_aux) |
|
{ |
|
struct puffs_park *park; |
|
void *cookie = VPTOPNC(vp_opc); |
|
|
|
park = puffs_park_alloc(1); |
|
park->park_preq = kbuf; |
|
|
|
park->park_preq->preq_opclass = PUFFSOP_VN; |
|
park->park_preq->preq_optype = optype; |
|
park->park_preq->preq_cookie = cookie; |
|
|
|
park->park_copylen = buflen; |
|
park->park_maxlen = buflen + maxdelta; |
|
park->park_flags = 0; |
|
|
|
return touser(pmp, park, reqid); |
|
} |
|
|
|
void |
void |
puffs_vntouser_call(struct puffs_mount *pmp, int optype, |
puffs_msg_vncall(struct puffs_mount *pmp, struct puffs_msgpark *park, |
void *kbuf, size_t buflen, size_t maxdelta, |
int optype, size_t delta, parkdone_fn donefn, void *donearg, |
parkdone_fn donefn, void *donearg, |
struct vnode *vp_opc) |
struct vnode *vp_opc, struct vnode *vp_aux) |
|
{ |
{ |
struct puffs_park *park; |
|
void *cookie = VPTOPNC(vp_opc); |
void *cookie = VPTOPNC(vp_opc); |
|
|
park = puffs_park_alloc(1); |
|
park->park_preq = kbuf; |
|
|
|
park->park_preq->preq_opclass = PUFFSOP_VN; |
park->park_preq->preq_opclass = PUFFSOP_VN; |
park->park_preq->preq_optype = optype; |
park->park_preq->preq_optype = optype; |
park->park_preq->preq_cookie = cookie; |
park->park_preq->preq_cookie = cookie; |
|
|
park->park_copylen = buflen; |
KASSERT(delta < park->park_maxlen); |
park->park_maxlen = buflen + maxdelta; |
park->park_copylen = park->park_maxlen - delta; |
park->park_done = donefn; |
park->park_done = donefn; |
park->park_donearg = donearg; |
park->park_donearg = donearg; |
park->park_flags = PARKFLAG_CALL; |
park->park_flags |= PARKFLAG_CALL; |
|
|
(void) touser(pmp, park, puffs_getreqid(pmp)); |
(void) touser(pmp, park); |
} |
} |
|
|
/* |
int |
* Notice: kbuf will be free'd later. I must be allocated from the |
puffs_msg_raw(struct puffs_mount *pmp, struct puffs_msgpark *park) |
* kernel heap and it's ownership is shifted to this function from |
|
* now on, i.e. the caller is not allowed to use it anymore! |
|
*/ |
|
void |
|
puffs_vntouser_faf(struct puffs_mount *pmp, int optype, |
|
void *kbuf, size_t buflen, struct vnode *vp_opc) |
|
{ |
{ |
struct puffs_park *park; |
|
void *cookie = VPTOPNC(vp_opc); |
|
|
|
/* XXX: is it allowable to sleep here? */ |
|
park = puffs_park_alloc(0); |
|
if (park == NULL) |
|
return; /* 2bad */ |
|
|
|
park->park_preq = kbuf; |
park->park_copylen = park->park_maxlen; |
|
|
park->park_preq->preq_opclass = PUFFSOP_VN | PUFFSOPFLAG_FAF; |
return touser(pmp, park); |
park->park_preq->preq_optype = optype; |
|
park->park_preq->preq_cookie = cookie; |
|
|
|
park->park_maxlen = park->park_copylen = buflen; |
|
park->park_flags = 0; |
|
|
|
(void)touser(pmp, park, 0); |
|
} |
} |
|
|
void |
void |
puffs_cacheop(struct puffs_mount *pmp, struct puffs_park *park, |
puffs_msg_errnotify(struct puffs_mount *pmp, uint8_t type, int error, |
struct puffs_cacheinfo *pcinfo, size_t pcilen, void *cookie) |
const char *str, void *cookie) |
{ |
{ |
|
struct puffs_msgpark *park; |
|
struct puffs_error *perr; |
|
|
|
puffs_msgmem_alloc(sizeof(struct puffs_error), &park, (void **)&perr,1); |
|
|
|
perr->perr_error = error; |
|
strlcpy(perr->perr_str, str, sizeof(perr->perr_str)); |
|
|
park->park_preq = (struct puffs_req *)pcinfo; |
park->park_preq->preq_opclass |= PUFFSOP_ERROR | PUFFSOPFLAG_FAF; |
park->park_preq->preq_opclass = PUFFSOP_CACHE | PUFFSOPFLAG_FAF; |
park->park_preq->preq_optype = type; |
park->park_preq->preq_optype = PCACHE_TYPE_WRITE; /* XXX */ |
|
park->park_preq->preq_cookie = cookie; |
park->park_preq->preq_cookie = cookie; |
|
|
park->park_maxlen = park->park_copylen = pcilen; |
park->park_copylen = park->park_maxlen; |
park->park_flags = 0; |
|
|
|
(void)touser(pmp, park, 0); |
(void)touser(pmp, park); |
} |
} |
|
|
/* |
/* |
Line 428 puffs_cacheop(struct puffs_mount *pmp, s |
|
Line 395 puffs_cacheop(struct puffs_mount *pmp, s |
|
* there's a slight ugly-factor also, but let's not worry about that. |
* there's a slight ugly-factor also, but let's not worry about that. |
*/ |
*/ |
static int |
static int |
touser(struct puffs_mount *pmp, struct puffs_park *park, uint64_t reqid) |
touser(struct puffs_mount *pmp, struct puffs_msgpark *park) |
{ |
{ |
struct lwp *l = curlwp; |
struct lwp *l = curlwp; |
struct mount *mp; |
struct mount *mp; |
Line 437 touser(struct puffs_mount *pmp, struct p |
|
Line 404 touser(struct puffs_mount *pmp, struct p |
|
|
|
mp = PMPTOMP(pmp); |
mp = PMPTOMP(pmp); |
preq = park->park_preq; |
preq = park->park_preq; |
preq->preq_id = park->park_id = reqid; |
preq->preq_buflen = park->park_maxlen; |
preq->preq_buflen = ALIGN(park->park_maxlen); |
KASSERT(preq->preq_id == 0); |
|
|
if (PUFFSOP_WANTREPLY(preq->preq_opclass)) |
if ((park->park_flags & PARKFLAG_WANTREPLY) == 0) |
park->park_flags |= PARKFLAG_WANTREPLY; |
preq->preq_opclass |= PUFFSOPFLAG_FAF; |
|
else |
|
preq->preq_id = puffs_getmsgid(pmp); |
|
|
|
/* fill in caller information */ |
|
preq->preq_pid = l->l_proc->p_pid; |
|
preq->preq_lid = l->l_lid; |
|
|
/* |
/* |
* To support PCATCH, yet another movie: check if there are signals |
* To support PCATCH, yet another movie: check if there are signals |
Line 455 touser(struct puffs_mount *pmp, struct p |
|
Line 428 touser(struct puffs_mount *pmp, struct p |
|
&& (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(park); |
park->park_preq->preq_opclass |= PUFFSOPFLAG_FAF; |
|
park->park_flags &= ~PARKFLAG_WANTREPLY; |
DPRINTF(("puffs touser: converted to FAF %p\n", park)); |
DPRINTF(("puffs touser: converted to FAF %p\n", park)); |
rv = EINTR; |
rv = EINTR; |
} else { |
} else { |
puffs_park_release(park, 0); |
|
return EINTR; |
return EINTR; |
} |
} |
} |
} |
Line 498 touser(struct puffs_mount *pmp, struct p |
|
Line 471 touser(struct puffs_mount *pmp, struct p |
|
|
|
if (pmp->pmp_status != PUFFSTAT_RUNNING) { |
if (pmp->pmp_status != PUFFSTAT_RUNNING) { |
mutex_exit(&pmp->pmp_lock); |
mutex_exit(&pmp->pmp_lock); |
puffs_park_release(park, 0); |
|
return ENXIO; |
return ENXIO; |
} |
} |
|
|
#ifdef PUFFSDEBUG |
#ifdef PUFFSDEBUG |
parkqdump(&pmp->pmp_req_touser, puffsdebug > 1); |
parkqdump(&pmp->pmp_msg_touser, puffsdebug > 1); |
parkqdump(&pmp->pmp_req_replywait, puffsdebug > 1); |
parkqdump(&pmp->pmp_msg_replywait, puffsdebug > 1); |
#endif |
#endif |
|
|
TAILQ_INSERT_TAIL(&pmp->pmp_req_touser, park, park_entries); |
mutex_enter(&park->park_mtx); |
|
TAILQ_INSERT_TAIL(&pmp->pmp_msg_touser, park, park_entries); |
park->park_flags |= PARKFLAG_ONQUEUE1; |
park->park_flags |= PARKFLAG_ONQUEUE1; |
puffs_mp_reference(pmp); |
puffs_mp_reference(pmp); |
pmp->pmp_req_touser_count++; |
pmp->pmp_msg_touser_count++; |
mutex_exit(&pmp->pmp_lock); |
mutex_exit(&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, park, |
"c/t: 0x%x/0x%x, f: 0x%x\n", preq->preq_id, preq, park, |
preq->preq_opclass, preq->preq_optype, park->park_flags)); |
preq->preq_opclass, preq->preq_optype, park->park_flags)); |
|
|
cv_broadcast(&pmp->pmp_req_waiter_cv); |
cv_broadcast(&pmp->pmp_msg_waiter_cv); |
selnotify(pmp->pmp_sel, 0); |
selnotify(pmp->pmp_sel, 0); |
|
|
if ((park->park_flags & PARKFLAG_WANTREPLY) |
if ((park->park_flags & PARKFLAG_WANTREPLY) |
Line 525 touser(struct puffs_mount *pmp, struct p |
|
Line 498 touser(struct puffs_mount *pmp, struct p |
|
int error; |
int error; |
|
|
error = cv_wait_sig(&park->park_cv, &park->park_mtx); |
error = cv_wait_sig(&park->park_cv, &park->park_mtx); |
|
DPRINTF(("puffs_touser: waiter for %p woke up with %d\n", |
|
park, error)); |
if (error) { |
if (error) { |
park->park_flags |= PARKFLAG_WAITERGONE; |
park->park_flags |= PARKFLAG_WAITERGONE; |
if (park->park_flags & PARKFLAG_DONE) { |
if (park->park_flags & PARKFLAG_DONE) { |
rv = preq->preq_rv; |
rv = preq->preq_rv; |
puffs_park_release(park, 0); |
|
} else { |
} else { |
/* |
/* |
* ok, we marked it as going away, but |
* ok, we marked it as going away, but |
Line 540 touser(struct puffs_mount *pmp, struct p |
|
Line 514 touser(struct puffs_mount *pmp, struct p |
|
* if it's on replywait queue to avoid error |
* if it's on replywait queue to avoid error |
* to file server. putop() code will DTRT. |
* to file server. putop() code will DTRT. |
*/ |
*/ |
KASSERT(park->park_flags & |
|
(PARKFLAG_ONQUEUE1 | PARKFLAG_ONQUEUE2)); |
|
mutex_exit(&park->park_mtx); |
mutex_exit(&park->park_mtx); |
|
|
mutex_enter(&pmp->pmp_lock); |
mutex_enter(&pmp->pmp_lock); |
mutex_enter(&park->park_mtx); |
mutex_enter(&park->park_mtx); |
|
|
|
/* remove from queue1 */ |
if (park->park_flags & PARKFLAG_ONQUEUE1) { |
if (park->park_flags & PARKFLAG_ONQUEUE1) { |
TAILQ_REMOVE(&pmp->pmp_req_touser, |
TAILQ_REMOVE(&pmp->pmp_msg_touser, |
park, park_entries); |
park, park_entries); |
pmp->pmp_req_touser_count--; |
pmp->pmp_msg_touser_count--; |
park->park_flags &= ~PARKFLAG_ONQUEUE1; |
park->park_flags &= ~PARKFLAG_ONQUEUE1; |
} |
} |
if ((park->park_flags & PARKFLAG_ONQUEUE2) == 0) |
|
puffs_park_release(park, 0); |
/* |
else |
* If it's waiting for a response already, |
mutex_exit(&park->park_mtx); |
* boost reference count. Park will get |
|
* nuked once the response arrives from |
|
* the file server. |
|
*/ |
|
if (park->park_flags & PARKFLAG_ONQUEUE2) |
|
puffs_msgpark_reference(park); |
|
|
mutex_exit(&pmp->pmp_lock); |
mutex_exit(&pmp->pmp_lock); |
|
|
rv = error; |
rv = error; |
} |
} |
} else { |
} else { |
rv = preq->preq_rv; |
rv = preq->preq_rv; |
puffs_park_release(park, 0); |
|
} |
} |
|
|
/* |
/* |
Line 579 touser(struct puffs_mount *pmp, struct p |
|
Line 557 touser(struct puffs_mount *pmp, struct p |
|
fstrans_done(mp); |
fstrans_done(mp); |
} |
} |
} else { |
} else { |
mutex_exit(&park->park_mtx); |
/* |
|
* Take extra reference for FAF, i.e. don't free us |
|
* immediately upon return to the caller, but rather |
|
* only when the message has been transported. |
|
*/ |
|
puffs_msgpark_reference(park); |
} |
} |
|
|
|
mutex_exit(&park->park_mtx); |
|
|
mutex_enter(&pmp->pmp_lock); |
mutex_enter(&pmp->pmp_lock); |
puffs_mp_release(pmp); |
puffs_mp_release(pmp); |
mutex_exit(&pmp->pmp_lock); |
mutex_exit(&pmp->pmp_lock); |
Line 589 touser(struct puffs_mount *pmp, struct p |
|
Line 574 touser(struct puffs_mount *pmp, struct p |
|
return rv; |
return rv; |
} |
} |
|
|
|
|
/* |
/* |
* getop: scan through queued requests until: |
* Get next request in the outgoing queue. "maxsize" controls the |
* 1) max number of requests satisfied |
* size the caller can accommodate and "nonblock" signals if this |
* OR |
* should block while waiting for input. Handles all locking internally. |
* 2) buffer runs out of space |
|
* OR |
|
* 3) nonblocking is set AND there are no operations available |
|
* OR |
|
* 4) at least one operation was transferred AND there are no more waiting |
|
*/ |
*/ |
int |
int |
puffs_getop(struct puffs_mount *pmp, struct puffs_reqh_get *phg, int nonblock) |
puffs_msgif_getout(void *this, size_t maxsize, int nonblock, |
|
uint8_t **data, size_t *dlen, void **parkptr) |
{ |
{ |
struct puffs_park *park; |
struct puffs_mount *pmp = this; |
|
struct puffs_msgpark *park; |
struct puffs_req *preq; |
struct puffs_req *preq; |
uint8_t *bufpos; |
int error; |
int error, donesome; |
|
|
|
donesome = error = 0; |
|
bufpos = phg->phg_buf; |
|
|
|
|
error = 0; |
mutex_enter(&pmp->pmp_lock); |
mutex_enter(&pmp->pmp_lock); |
while (phg->phg_nops == 0 || donesome != phg->phg_nops) { |
puffs_mp_reference(pmp); |
again: |
for (;;) { |
|
/* RIP? */ |
if (pmp->pmp_status != PUFFSTAT_RUNNING) { |
if (pmp->pmp_status != PUFFSTAT_RUNNING) { |
/* if we got some, they don't really matter anymore */ |
|
error = ENXIO; |
error = ENXIO; |
goto out; |
break; |
} |
} |
if (TAILQ_EMPTY(&pmp->pmp_req_touser)) { |
|
if (donesome) |
|
goto out; |
|
|
|
|
/* need platinum yendorian express card? */ |
|
if (TAILQ_EMPTY(&pmp->pmp_msg_touser)) { |
|
DPRINTF(("puffs_getout: no outgoing op, ")); |
if (nonblock) { |
if (nonblock) { |
|
DPRINTF(("returning EWOULDBLOCK\n")); |
error = EWOULDBLOCK; |
error = EWOULDBLOCK; |
goto out; |
break; |
} |
} |
|
DPRINTF(("waiting ...\n")); |
|
|
error = cv_wait_sig(&pmp->pmp_req_waiter_cv, |
error = cv_wait_sig(&pmp->pmp_msg_waiter_cv, |
&pmp->pmp_lock); |
&pmp->pmp_lock); |
if (error) |
if (error) |
goto out; |
break; |
else |
else |
goto again; |
continue; |
} |
} |
|
|
park = TAILQ_FIRST(&pmp->pmp_req_touser); |
park = TAILQ_FIRST(&pmp->pmp_msg_touser); |
puffs_park_reference(park); |
if (park == NULL) |
|
continue; |
|
|
|
mutex_enter(&park->park_mtx); |
|
puffs_msgpark_reference(park); |
|
|
|
DPRINTF(("puffs_getout: found park at %p, ", park)); |
|
|
/* If it's a goner, don't process any furher */ |
/* If it's a goner, don't process any furher */ |
if (park->park_flags & PARKFLAG_WAITERGONE) { |
if (park->park_flags & PARKFLAG_WAITERGONE) { |
puffs_park_release(park, 0); |
DPRINTF(("waitergone!\n")); |
|
puffs_msgpark_release(park); |
continue; |
continue; |
} |
} |
|
|
|
/* check size */ |
preq = park->park_preq; |
preq = park->park_preq; |
if (phg->phg_buflen < preq->preq_buflen) { |
if (maxsize < preq->preq_frhdr.pfr_len) { |
if (!donesome) |
DPRINTF(("buffer too small\n")); |
error = E2BIG; |
puffs_msgpark_release(park); |
puffs_park_release(park, 0); |
error = E2BIG; |
goto out; |
break; |
} |
} |
|
|
TAILQ_REMOVE(&pmp->pmp_req_touser, park, park_entries); |
DPRINTF(("returning\n")); |
|
|
|
/* |
|
* Ok, we found what we came for. Release it from the |
|
* outgoing queue but do not unlock. We will unlock |
|
* only after we "releaseout" it to avoid complications: |
|
* otherwise it is (theoretically) possible for userland |
|
* to race us into "put" before we have a change to put |
|
* this baby on the receiving queue. |
|
*/ |
|
TAILQ_REMOVE(&pmp->pmp_msg_touser, park, park_entries); |
KASSERT(park->park_flags & PARKFLAG_ONQUEUE1); |
KASSERT(park->park_flags & PARKFLAG_ONQUEUE1); |
park->park_flags &= ~PARKFLAG_ONQUEUE1; |
park->park_flags &= ~PARKFLAG_ONQUEUE1; |
pmp->pmp_req_touser_count--; |
mutex_exit(&park->park_mtx); |
KASSERT(pmp->pmp_req_touser_count >= 0); |
|
mutex_exit(&pmp->pmp_lock); |
|
|
|
DPRINTF(("puffsgetop: get op %" PRIu64 " (%d.), from %p " |
pmp->pmp_msg_touser_count--; |
"len %zu (buflen %zu), target %p\n", preq->preq_id, |
KASSERT(pmp->pmp_msg_touser_count >= 0); |
donesome, preq, park->park_copylen, preq->preq_buflen, |
|
bufpos)); |
|
|
|
if ((error = copyout(preq, bufpos, park->park_copylen)) != 0) { |
|
DPRINTF(("puffs_getop: copyout failed: %d\n", error)); |
|
/* |
|
* ok, user server is probably trying to cheat. |
|
* stuff op back & return error to user. We need |
|
* to take locks in the correct order. |
|
*/ |
|
mutex_exit(&park->park_mtx); |
|
|
|
/* |
|
* XXX: ONQUEUE1 | ONQUEUE2 invariant doesn't |
|
* hold here |
|
*/ |
|
|
|
mutex_enter(&pmp->pmp_lock); |
|
mutex_enter(&park->park_mtx); |
|
if ((park->park_flags & PARKFLAG_WAITERGONE) == 0) { |
|
TAILQ_INSERT_HEAD(&pmp->pmp_req_touser, park, |
|
park_entries); |
|
park->park_flags |= PARKFLAG_ONQUEUE1; |
|
pmp->pmp_req_touser_count++; |
|
} |
|
|
|
if (donesome) |
break; |
error = 0; |
} |
puffs_park_release(park, 0); |
puffs_mp_release(pmp); |
goto out; |
mutex_exit(&pmp->pmp_lock); |
} |
|
bufpos += preq->preq_buflen; |
|
phg->phg_buflen -= preq->preq_buflen; |
|
donesome++; |
|
|
|
/* XXXfixme: taking this lock in the wrong order */ |
if (error == 0) { |
mutex_enter(&pmp->pmp_lock); |
*data = (uint8_t *)preq; |
|
preq->preq_frhdr.pfr_len = park->park_copylen; |
|
preq->preq_frhdr.pfr_alloclen = park->park_maxlen; |
|
preq->preq_frhdr.pfr_type = preq->preq_opclass; /* yay! */ |
|
*dlen = preq->preq_frhdr.pfr_len; |
|
*parkptr = park; |
|
} |
|
|
|
return error; |
|
} |
|
|
|
/* |
|
* Release outgoing structure. Now, depending on the success of the |
|
* outgoing send, it is either going onto the result waiting queue |
|
* or the death chamber. |
|
*/ |
|
void |
|
puffs_msgif_releaseout(void *this, void *parkptr, int status) |
|
{ |
|
struct puffs_mount *pmp = this; |
|
struct puffs_msgpark *park = parkptr; |
|
|
if (park->park_flags & PARKFLAG_WANTREPLY) { |
DPRINTF(("puffs_releaseout: returning park %p, errno %d: " , |
TAILQ_INSERT_TAIL(&pmp->pmp_req_replywait, park, |
park, status)); |
|
mutex_enter(&pmp->pmp_lock); |
|
mutex_enter(&park->park_mtx); |
|
if (park->park_flags & PARKFLAG_WANTREPLY) { |
|
if (status == 0) { |
|
DPRINTF(("enqueue replywait\n")); |
|
TAILQ_INSERT_TAIL(&pmp->pmp_msg_replywait, park, |
park_entries); |
park_entries); |
park->park_flags |= PARKFLAG_ONQUEUE2; |
park->park_flags |= PARKFLAG_ONQUEUE2; |
puffs_park_release(park, 0); |
|
} else { |
} else { |
free(preq, M_PUFFS); |
DPRINTF(("error path!\n")); |
puffs_park_release(park, 1); |
park->park_preq->preq_rv = status; |
|
park->park_flags |= PARKFLAG_DONE; |
|
cv_signal(&park->park_cv); |
} |
} |
|
puffs_msgpark_release(park); |
|
} else { |
|
DPRINTF(("release\n")); |
|
puffs_msgpark_release1(park, 2); |
} |
} |
|
|
out: |
|
phg->phg_more = pmp->pmp_req_touser_count; |
|
mutex_exit(&pmp->pmp_lock); |
mutex_exit(&pmp->pmp_lock); |
|
|
phg->phg_nops = donesome; |
|
|
|
return error; |
|
} |
} |
|
|
int |
/* |
puffs_putop(struct puffs_mount *pmp, struct puffs_reqh_put *php) |
* XXX: locking with this one? |
|
*/ |
|
void |
|
puffs_msgif_incoming(void *this, void *buf) |
{ |
{ |
struct puffs_park *park; |
struct puffs_mount *pmp = this; |
struct puffs_req tmpreq; |
struct puffs_req *preq = buf; |
struct puffs_req *nextpreq; |
struct puffs_frame *pfr = &preq->preq_frhdr; |
void *userbuf; |
struct puffs_msgpark *park; |
uint64_t id; |
int release, wgone; |
size_t reqlen; |
|
int donesome, error, wgone, release; |
/* XXX */ |
|
if (PUFFSOP_OPCLASS(preq->preq_opclass) != PUFFSOP_VN |
donesome = error = wgone = 0; |
&& PUFFSOP_OPCLASS(preq->preq_opclass) != PUFFSOP_VFS) |
|
return; |
id = php->php_id; |
|
userbuf = php->php_buf; |
|
reqlen = php->php_buflen; |
|
|
|
mutex_enter(&pmp->pmp_lock); |
mutex_enter(&pmp->pmp_lock); |
while (donesome != php->php_nops) { |
|
release = 0; |
|
#ifdef PUFFSDEBUG |
|
DPRINTF(("puffsputop: searching for %" PRIu64 ", ubuf: %p, " |
|
"len %zu\n", id, userbuf, reqlen)); |
|
#endif |
|
TAILQ_FOREACH(park, &pmp->pmp_req_replywait, park_entries) { |
|
if (park->park_id == id) |
|
break; |
|
} |
|
|
|
if (park == NULL) { |
/* Locate waiter */ |
DPRINTF(("puffsputop: no request: %" PRIu64 "\n", id)); |
TAILQ_FOREACH(park, &pmp->pmp_msg_replywait, park_entries) { |
error = EINVAL; |
if (park->park_preq->preq_id == preq->preq_id) |
break; |
break; |
} |
} |
|
if (park == NULL) { |
puffs_park_reference(park); |
DPRINTF(("puffs_msgif_income: no request: %" PRIu64 "\n", |
if (reqlen == 0 || reqlen > park->park_maxlen) { |
preq->preq_id)); |
DPRINTF(("puffsputop: invalid buffer length: " |
mutex_exit(&pmp->pmp_lock); |
"%zu\n", reqlen)); |
return; /* XXX send error */ |
error = E2BIG; |
} |
puffs_park_release(park, 0); |
|
break; |
|
} |
|
wgone = park->park_flags & PARKFLAG_WAITERGONE; |
|
|
|
/* check if it's still on the queue after acquiring lock */ |
|
if (park->park_flags & PARKFLAG_ONQUEUE2) { |
|
TAILQ_REMOVE(&pmp->pmp_req_replywait, park, |
|
park_entries); |
|
park->park_flags &= ~PARKFLAG_ONQUEUE2; |
|
} |
|
|
|
|
mutex_enter(&park->park_mtx); |
|
puffs_msgpark_reference(park); |
|
if (pfr->pfr_len > park->park_maxlen) { |
|
DPRINTF(("puffs_msgif_income: invalid buffer length: " |
|
"%zu (req %" PRIu64 ", \n", pfr->pfr_len, preq->preq_id)); |
|
park->park_preq->preq_rv = EPROTO; |
|
cv_signal(&park->park_cv); |
|
puffs_msgpark_release(park); |
mutex_exit(&pmp->pmp_lock); |
mutex_exit(&pmp->pmp_lock); |
|
return; /* XXX: error */ |
|
} |
|
wgone = park->park_flags & PARKFLAG_WAITERGONE; |
|
|
/* |
KASSERT(park->park_flags & PARKFLAG_ONQUEUE2); |
* If the caller has gone south, go to next, collect |
TAILQ_REMOVE(&pmp->pmp_msg_replywait, park, park_entries); |
* $200 and free the structure there instead of wakeup. |
park->park_flags &= ~PARKFLAG_ONQUEUE2; |
* We also need to copyin the header info. Flag structure |
mutex_exit(&pmp->pmp_lock); |
* release to mode total and utter destruction. |
|
*/ |
|
if (wgone) { |
|
DPRINTF(("puffs_putop: bad service - waiter gone for " |
|
"park %p\n", park)); |
|
error = copyin(userbuf, &tmpreq, |
|
sizeof(struct puffs_req)); |
|
release = 1; |
|
if (error) |
|
goto loopout; |
|
nextpreq = &tmpreq; |
|
goto next; |
|
} |
|
|
|
DPRINTF(("puffsputpop: copyin from %p to %p, len %zu\n", |
|
userbuf, park->park_preq, reqlen)); |
|
error = copyin(userbuf, park->park_preq, reqlen); |
|
if (error) |
|
goto loopout; |
|
nextpreq = park->park_preq; |
|
|
|
next: |
|
/* all's well, prepare for next op */ |
|
id = nextpreq->preq_id; |
|
reqlen = nextpreq->preq_buflen; |
|
userbuf = nextpreq->preq_nextbuf; |
|
donesome++; |
|
|
|
loopout: |
|
if (error && !wgone) |
|
park->park_preq->preq_rv = error; |
|
|
|
|
if (wgone) { |
|
DPRINTF(("puffs_putop: bad service - waiter gone for " |
|
"park %p\n", park)); |
|
release = 2; |
|
} else { |
if (park->park_flags & PARKFLAG_CALL) { |
if (park->park_flags & PARKFLAG_CALL) { |
DPRINTF(("puffsputopt: call for %p, arg %p\n", |
DPRINTF(("puffs_msgif_income: call for %p, arg %p\n", |
park->park_preq, park->park_donearg)); |
park->park_preq, park->park_donearg)); |
park->park_done(park->park_preq, park->park_donearg); |
park->park_done(pmp, buf, park->park_donearg); |
|
release = 2; |
|
} else { |
|
/* XXX: yes, I know */ |
|
memcpy(park->park_preq, buf, pfr->pfr_len); |
release = 1; |
release = 1; |
} |
} |
|
|
if (!wgone) { |
|
DPRINTF(("puffs_putop: flagging done for " |
|
"park %p\n", park)); |
|
|
|
cv_signal(&park->park_cv); |
|
} |
|
park->park_flags |= PARKFLAG_DONE; |
|
puffs_park_release(park, release); |
|
|
|
mutex_enter(&pmp->pmp_lock); |
|
if (error) |
|
break; |
|
wgone = 0; |
|
} |
} |
|
|
mutex_exit(&pmp->pmp_lock); |
if (!wgone) { |
php->php_nops -= donesome; |
DPRINTF(("puffs_putop: flagging done for " |
|
"park %p\n", park)); |
|
cv_signal(&park->park_cv); |
|
} |
|
|
return error; |
park->park_flags |= PARKFLAG_DONE; |
|
puffs_msgpark_release1(park, release); |
} |
} |
|
|
/* |
/* |
Line 848 puffs_putop(struct puffs_mount *pmp, str |
|
Line 797 puffs_putop(struct puffs_mount *pmp, str |
|
void |
void |
puffs_userdead(struct puffs_mount *pmp) |
puffs_userdead(struct puffs_mount *pmp) |
{ |
{ |
struct puffs_park *park, *park_next; |
struct puffs_msgpark *park, *park_next; |
|
|
/* |
/* |
* Mark filesystem status as dying so that operations don't |
* Mark filesystem status as dying so that operations don't |
Line 857 puffs_userdead(struct puffs_mount *pmp) |
|
Line 806 puffs_userdead(struct puffs_mount *pmp) |
|
pmp->pmp_status = PUFFSTAT_DYING; |
pmp->pmp_status = PUFFSTAT_DYING; |
|
|
/* signal waiters on REQUEST TO file server queue */ |
/* signal waiters on REQUEST TO file server queue */ |
for (park = TAILQ_FIRST(&pmp->pmp_req_touser); park; park = park_next) { |
for (park = TAILQ_FIRST(&pmp->pmp_msg_touser); park; park = park_next) { |
uint8_t opclass; |
uint8_t opclass; |
|
|
puffs_park_reference(park); |
mutex_enter(&park->park_mtx); |
|
puffs_msgpark_reference(park); |
park_next = TAILQ_NEXT(park, park_entries); |
park_next = TAILQ_NEXT(park, park_entries); |
|
|
KASSERT(park->park_flags & PARKFLAG_ONQUEUE1); |
KASSERT(park->park_flags & PARKFLAG_ONQUEUE1); |
TAILQ_REMOVE(&pmp->pmp_req_touser, park, park_entries); |
TAILQ_REMOVE(&pmp->pmp_msg_touser, park, park_entries); |
park->park_flags &= ~PARKFLAG_ONQUEUE1; |
park->park_flags &= ~PARKFLAG_ONQUEUE1; |
pmp->pmp_req_touser_count--; |
pmp->pmp_msg_touser_count--; |
|
|
/* |
/* |
* If the waiter is gone, we may *NOT* access preq anymore. |
* If the waiter is gone, we may *NOT* access preq anymore. |
Line 874 puffs_userdead(struct puffs_mount *pmp) |
|
Line 824 puffs_userdead(struct puffs_mount *pmp) |
|
if (park->park_flags & PARKFLAG_WAITERGONE) { |
if (park->park_flags & PARKFLAG_WAITERGONE) { |
KASSERT((park->park_flags & PARKFLAG_CALL) == 0); |
KASSERT((park->park_flags & PARKFLAG_CALL) == 0); |
KASSERT(park->park_flags & PARKFLAG_WANTREPLY); |
KASSERT(park->park_flags & PARKFLAG_WANTREPLY); |
puffs_park_release(park, 0); |
puffs_msgpark_release(park); |
} else { |
} else { |
opclass = park->park_preq->preq_opclass; |
opclass = park->park_preq->preq_opclass; |
park->park_preq->preq_rv = ENXIO; |
park->park_preq->preq_rv = ENXIO; |
|
|
if (park->park_flags & PARKFLAG_CALL) { |
if (park->park_flags & PARKFLAG_CALL) { |
park->park_done(park->park_preq, |
park->park_done(pmp, park->park_preq, |
park->park_donearg); |
park->park_donearg); |
puffs_park_release(park, 1); |
puffs_msgpark_release1(park, 2); |
} else if ((park->park_flags & PARKFLAG_WANTREPLY)==0) { |
} else if ((park->park_flags & PARKFLAG_WANTREPLY)==0) { |
free(park->park_preq, M_PUFFS); |
puffs_msgpark_release1(park, 2); |
puffs_park_release(park, 1); |
|
} else { |
} else { |
park->park_preq->preq_rv = ENXIO; |
park->park_preq->preq_rv = ENXIO; |
cv_signal(&park->park_cv); |
cv_signal(&park->park_cv); |
puffs_park_release(park, 0); |
puffs_msgpark_release(park); |
} |
} |
} |
} |
} |
} |
|
|
/* signal waiters on RESPONSE FROM file server queue */ |
/* signal waiters on RESPONSE FROM file server queue */ |
for (park=TAILQ_FIRST(&pmp->pmp_req_replywait); park; park=park_next) { |
for (park=TAILQ_FIRST(&pmp->pmp_msg_replywait); park; park=park_next) { |
puffs_park_reference(park); |
mutex_enter(&park->park_mtx); |
|
puffs_msgpark_reference(park); |
park_next = TAILQ_NEXT(park, park_entries); |
park_next = TAILQ_NEXT(park, park_entries); |
|
|
KASSERT(park->park_flags & PARKFLAG_ONQUEUE2); |
KASSERT(park->park_flags & PARKFLAG_ONQUEUE2); |
KASSERT(park->park_flags & PARKFLAG_WANTREPLY); |
KASSERT(park->park_flags & PARKFLAG_WANTREPLY); |
|
|
TAILQ_REMOVE(&pmp->pmp_req_replywait, park, park_entries); |
TAILQ_REMOVE(&pmp->pmp_msg_replywait, park, park_entries); |
park->park_flags &= ~PARKFLAG_ONQUEUE2; |
park->park_flags &= ~PARKFLAG_ONQUEUE2; |
|
|
/* |
/* |
Line 910 puffs_userdead(struct puffs_mount *pmp) |
|
Line 860 puffs_userdead(struct puffs_mount *pmp) |
|
*/ |
*/ |
if (park->park_flags & PARKFLAG_WAITERGONE) { |
if (park->park_flags & PARKFLAG_WAITERGONE) { |
KASSERT((park->park_flags & PARKFLAG_CALL) == 0); |
KASSERT((park->park_flags & PARKFLAG_CALL) == 0); |
puffs_park_release(park, 0); |
puffs_msgpark_release(park); |
} else { |
} else { |
park->park_preq->preq_rv = ENXIO; |
park->park_preq->preq_rv = ENXIO; |
if (park->park_flags & PARKFLAG_CALL) { |
if (park->park_flags & PARKFLAG_CALL) { |
park->park_done(park->park_preq, |
park->park_done(pmp, park->park_preq, |
park->park_donearg); |
park->park_donearg); |
puffs_park_release(park, 1); |
puffs_msgpark_release1(park, 2); |
} else { |
} else { |
cv_signal(&park->park_cv); |
cv_signal(&park->park_cv); |
puffs_park_release(park, 0); |
puffs_msgpark_release(park); |
} |
} |
} |
} |
} |
} |
} |
|
|
|
/* this is probably going to die away at some point? */ |
cv_broadcast(&pmp->pmp_msg_waiter_cv); |
/* |
|
* XXX: currently bitrotted |
|
*/ |
|
#if 0 |
|
static int |
|
puffssizeop(struct puffs_mount *pmp, struct puffs_sizeop *psop_user) |
|
{ |
|
struct puffs_sizepark *pspark; |
|
void *kernbuf; |
|
size_t copylen; |
|
int error; |
|
|
|
/* locate correct op */ |
|
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, |
|
pkso_entries); |
|
break; |
|
} |
|
} |
|
mutex_exit(&pmp->pmp_lock); |
|
|
|
if (pspark == NULL) |
|
return EINVAL; |
|
|
|
error = 0; |
|
copylen = MIN(pspark->pkso_bufsize, psop_user->pso_bufsize); |
|
|
|
/* |
|
* XXX: uvm stuff to avoid bouncy-bouncy copying? |
|
*/ |
|
if (PUFFS_SIZEOP_UIO(pspark->pkso_reqtype)) { |
|
kernbuf = malloc(copylen, M_PUFFS, M_WAITOK | M_ZERO); |
|
if (pspark->pkso_reqtype == PUFFS_SIZEOPREQ_UIO_IN) { |
|
error = copyin(psop_user->pso_userbuf, |
|
kernbuf, copylen); |
|
if (error) { |
|
printf("psop ERROR1 %d\n", error); |
|
goto escape; |
|
} |
|
} |
|
error = uiomove(kernbuf, copylen, pspark->pkso_uio); |
|
if (error) { |
|
printf("uiomove from kernel %p, len %d failed: %d\n", |
|
kernbuf, (int)copylen, error); |
|
goto escape; |
|
} |
|
|
|
if (pspark->pkso_reqtype == PUFFS_SIZEOPREQ_UIO_OUT) { |
|
error = copyout(kernbuf, |
|
psop_user->pso_userbuf, copylen); |
|
if (error) { |
|
printf("psop ERROR2 %d\n", error); |
|
goto escape; |
|
} |
|
} |
|
escape: |
|
free(kernbuf, M_PUFFS); |
|
} else if (PUFFS_SIZEOP_BUF(pspark->pkso_reqtype)) { |
|
copylen = MAX(pspark->pkso_bufsize, psop_user->pso_bufsize); |
|
if (pspark->pkso_reqtype == PUFFS_SIZEOPREQ_BUF_IN) { |
|
error = copyin(psop_user->pso_userbuf, |
|
pspark->pkso_copybuf, copylen); |
|
} else { |
|
error = copyout(pspark->pkso_copybuf, |
|
psop_user->pso_userbuf, copylen); |
|
} |
|
} |
|
#ifdef DIAGNOSTIC |
|
else |
|
panic("puffssizeop: invalid reqtype %d\n", |
|
pspark->pkso_reqtype); |
|
#endif /* DIAGNOSTIC */ |
|
|
|
return error; |
|
} |
} |
#endif |
|