Module Name: src
Committed By: dyoung
Date: Wed Jul 8 18:53:36 UTC 2009
Modified Files:
src/sys/kern: kern_pmf.c
Log Message:
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.
To generate a diff of this commit:
cvs rdiff -u -r1.27 -r1.28 src/sys/kern/kern_pmf.c
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/sys/kern/kern_pmf.c
diff -u src/sys/kern/kern_pmf.c:1.27 src/sys/kern/kern_pmf.c:1.28
--- src/sys/kern/kern_pmf.c:1.27 Fri Jun 26 19:30:45 2009
+++ src/sys/kern/kern_pmf.c Wed Jul 8 18:53:36 2009
@@ -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 <[email protected]>
@@ -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 @@
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 @@
(*event->pmf_handler)(event->pmf_device);
}
- kmem_free(pew, sizeof(*pew));
+ pmf_event_workitem_put(pew);
}
static bool
@@ -555,7 +560,7 @@
{
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 @@
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);