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 <jmcne...@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 @@
 	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);

Reply via email to