pmf_event_inject(9) may be called from interrupt context, so we
must not allocate a pmf_event_workitem_t using kmem_alloc(9). Use pool_cache(9), instead, because it is safe in interrupt context. Thanks, rmind@, for catching the problem and suggesting the solution.
This commit is contained in:
parent
e17701cfef
commit
bfd7452af9
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: kern_pmf.c,v 1.27 2009/06/26 19:30:45 dyoung Exp $ */
|
||||
/* $NetBSD: kern_pmf.c,v 1.28 2009/07/08 18:53:36 dyoung Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2007 Jared D. McNeill <jmcneill@invisible.ca>
|
||||
@ -27,7 +27,7 @@
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: kern_pmf.c,v 1.27 2009/06/26 19:30:45 dyoung Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: kern_pmf.c,v 1.28 2009/07/08 18:53:36 dyoung Exp $");
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/param.h>
|
||||
@ -94,6 +94,11 @@ typedef struct pmf_event_workitem {
|
||||
device_t pew_device;
|
||||
} pmf_event_workitem_t;
|
||||
|
||||
static pool_cache_t pew_pc;
|
||||
|
||||
static pmf_event_workitem_t *pmf_event_workitem_get(void);
|
||||
static void pmf_event_workitem_put(pmf_event_workitem_t *);
|
||||
|
||||
|
||||
|
||||
static bool pmf_device_resume_locked(device_t PMF_FN_PROTO);
|
||||
@ -116,7 +121,7 @@ pmf_event_worker(struct work *wk, void *dummy)
|
||||
(*event->pmf_handler)(event->pmf_device);
|
||||
}
|
||||
|
||||
kmem_free(pew, sizeof(*pew));
|
||||
pmf_event_workitem_put(pew);
|
||||
}
|
||||
|
||||
static bool
|
||||
@ -555,7 +560,7 @@ pmf_event_inject(device_t dv, pmf_generic_event_t ev)
|
||||
{
|
||||
pmf_event_workitem_t *pew;
|
||||
|
||||
pew = kmem_alloc(sizeof(pmf_event_workitem_t), KM_NOSLEEP);
|
||||
pew = pmf_event_workitem_get();
|
||||
if (pew == NULL) {
|
||||
PMF_EVENT_PRINTF(("%s: PMF event %d dropped (no memory)\n",
|
||||
dv ? device_xname(dv) : "<anonymous>", ev));
|
||||
@ -686,11 +691,36 @@ pmf_class_display_register(device_t dv)
|
||||
return true;
|
||||
}
|
||||
|
||||
static void
|
||||
pmf_event_workitem_put(pmf_event_workitem_t *pew)
|
||||
{
|
||||
KASSERT(pew != NULL);
|
||||
pool_cache_put(pew_pc, pew);
|
||||
}
|
||||
|
||||
static pmf_event_workitem_t *
|
||||
pmf_event_workitem_get(void)
|
||||
{
|
||||
return pool_cache_get(pew_pc, PR_NOWAIT);
|
||||
}
|
||||
|
||||
static int
|
||||
pew_constructor(void *arg, void *obj, int flags)
|
||||
{
|
||||
memset(obj, 0, sizeof(pmf_event_workitem_t));
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
pmf_init(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
pew_pc = pool_cache_init(sizeof(pmf_event_workitem_t), 0, 0, 0,
|
||||
"pew pool", NULL, IPL_HIGH, pew_constructor, NULL, NULL);
|
||||
pool_cache_setlowat(pew_pc, 16);
|
||||
pool_cache_sethiwat(pew_pc, 256);
|
||||
|
||||
KASSERT(pmf_event_workqueue == NULL);
|
||||
err = workqueue_create(&pmf_event_workqueue, "pmfevent",
|
||||
pmf_event_worker, NULL, PRI_NONE, IPL_VM, 0);
|
||||
|
Loading…
x
Reference in New Issue
Block a user