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);