geom_event.c revision 113937
1/*- 2 * Copyright (c) 2002 Poul-Henning Kamp 3 * Copyright (c) 2002 Networks Associates Technology, Inc. 4 * All rights reserved. 5 * 6 * This software was developed for the FreeBSD Project by Poul-Henning Kamp 7 * and NAI Labs, the Security Research Division of Network Associates, Inc. 8 * under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the 9 * DARPA CHATS research program. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 3. The names of the authors may not be used to endorse or promote 20 * products derived from this software without specific prior written 21 * permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 * 35 * $FreeBSD: head/sys/geom/geom_event.c 113937 2003-04-23 20:46:12Z phk $ 36 */ 37 38/* 39 * XXX: How do we in general know that objects referenced in events 40 * have not been destroyed before we get around to handle the event ? 41 */ 42 43#include <sys/param.h> 44#include <sys/malloc.h> 45#include <sys/systm.h> 46#include <sys/kernel.h> 47#include <sys/lock.h> 48#include <sys/mutex.h> 49#include <machine/stdarg.h> 50#include <sys/errno.h> 51#include <sys/time.h> 52#include <geom/geom.h> 53#include <geom/geom_int.h> 54 55static struct event_tailq_head g_events = TAILQ_HEAD_INITIALIZER(g_events); 56static u_int g_pending_events; 57static TAILQ_HEAD(,g_provider) g_doorstep = TAILQ_HEAD_INITIALIZER(g_doorstep); 58static struct mtx g_eventlock; 59static struct sx g_eventstall; 60 61void 62g_waitidle(void) 63{ 64 65 while (g_pending_events) 66 tsleep(&g_pending_events, PPAUSE, "g_waitidle", hz/5); 67} 68 69void 70g_stall_events(void) 71{ 72 73 sx_xlock(&g_eventstall); 74} 75 76void 77g_release_events(void) 78{ 79 80 sx_xunlock(&g_eventstall); 81} 82 83void 84g_orphan_provider(struct g_provider *pp, int error) 85{ 86 87 g_trace(G_T_TOPOLOGY, "g_orphan_provider(%p(%s), %d)", 88 pp, pp->name, error); 89 KASSERT(error != 0, 90 ("g_orphan_provider(%p(%s), 0) error must be non-zero\n", 91 pp, pp->name)); 92 pp->error = error; 93 mtx_lock(&g_eventlock); 94 TAILQ_INSERT_TAIL(&g_doorstep, pp, orphan); 95 mtx_unlock(&g_eventlock); 96 wakeup(&g_wait_event); 97} 98 99/* 100 * This function is called once on each provider which the event handler 101 * finds on its g_doorstep. 102 */ 103 104static void 105g_orphan_register(struct g_provider *pp) 106{ 107 struct g_consumer *cp, *cp2; 108 109 g_trace(G_T_TOPOLOGY, "g_orphan_register(%s)", pp->name); 110 g_topology_assert(); 111 112 /* 113 * Tell all consumers the bad news. 114 * Don't be surprised if they self-destruct. 115 */ 116 cp = LIST_FIRST(&pp->consumers); 117 while (cp != NULL) { 118 cp2 = LIST_NEXT(cp, consumers); 119 KASSERT(cp->geom->orphan != NULL, 120 ("geom %s has no orphan, class %s", 121 cp->geom->name, cp->geom->class->name)); 122 cp->geom->orphan(cp); 123 cp = cp2; 124 } 125#ifdef notyet 126 cp = LIST_FIRST(&pp->consumers); 127 if (cp != NULL) 128 return; 129 if (pp->geom->flags & G_GEOM_WITHER) 130 g_destroy_provider(pp); 131#endif 132} 133 134static void 135g_destroy_event(struct g_event *ep) 136{ 137 138 g_free(ep); 139} 140 141static int 142one_event(void) 143{ 144 struct g_event *ep; 145 struct g_provider *pp; 146 147 sx_xlock(&g_eventstall); 148 g_topology_lock(); 149 for (;;) { 150 mtx_lock(&g_eventlock); 151 pp = TAILQ_FIRST(&g_doorstep); 152 if (pp != NULL) 153 TAILQ_REMOVE(&g_doorstep, pp, orphan); 154 mtx_unlock(&g_eventlock); 155 if (pp == NULL) 156 break; 157 g_orphan_register(pp); 158 } 159 mtx_lock(&g_eventlock); 160 ep = TAILQ_FIRST(&g_events); 161 if (ep == NULL) { 162 mtx_unlock(&g_eventlock); 163 g_topology_unlock(); 164 sx_xunlock(&g_eventstall); 165 return (0); 166 } 167 TAILQ_REMOVE(&g_events, ep, events); 168 mtx_unlock(&g_eventlock); 169 g_topology_assert(); 170 ep->func(ep->arg, 0); 171 g_topology_assert(); 172 g_destroy_event(ep); 173 g_pending_events--; 174 if (g_pending_events == 0) 175 wakeup(&g_pending_events); 176 g_topology_unlock(); 177 sx_xunlock(&g_eventstall); 178 return (1); 179} 180 181void 182g_run_events() 183{ 184 185 while (one_event()) 186 ; 187} 188 189void 190g_cancel_event(void *ref) 191{ 192 struct g_event *ep, *epn; 193 u_int n; 194 195 mtx_lock(&g_eventlock); 196 for (ep = TAILQ_FIRST(&g_events); ep != NULL; ep = epn) { 197 epn = TAILQ_NEXT(ep, events); 198 for (n = 0; n < G_N_EVENTREFS; n++) { 199 if (ep->ref[n] == NULL) 200 break; 201 if (ep->ref[n] == ref) { 202 TAILQ_REMOVE(&g_events, ep, events); 203 ep->func(ep->arg, EV_CANCEL); 204 g_free(ep); 205 break; 206 } 207 } 208 } 209 mtx_unlock(&g_eventlock); 210} 211 212int 213g_post_event(g_event_t *func, void *arg, int flag, ...) 214{ 215 struct g_event *ep; 216 va_list ap; 217 void *p; 218 u_int n; 219 220 g_trace(G_T_TOPOLOGY, "g_post_event(%p, %p, %d", func, arg, flag); 221 KASSERT(flag == M_NOWAIT || flag == M_WAITOK, 222 ("Wrong flag to g_post_event")); 223 ep = g_malloc(sizeof *ep, flag | M_ZERO); 224 if (ep == NULL) 225 return (ENOMEM); 226 va_start(ap, flag); 227 for (n = 0; n < G_N_EVENTREFS; n++) { 228 p = va_arg(ap, void *); 229 if (p == NULL) 230 break; 231 g_trace(G_T_TOPOLOGY, " ref %p", p); 232 ep->ref[n++] = p; 233 } 234 va_end(ap); 235 KASSERT(p == NULL, ("Too many references to event")); 236 ep->func = func; 237 ep->arg = arg; 238 mtx_lock(&g_eventlock); 239 g_pending_events++; 240 TAILQ_INSERT_TAIL(&g_events, ep, events); 241 mtx_unlock(&g_eventlock); 242 wakeup(&g_wait_event); 243 return (0); 244} 245 246 247void 248g_event_init() 249{ 250 251 mtx_init(&g_eventlock, "GEOM orphanage", NULL, MTX_DEF); 252 sx_init(&g_eventstall, "GEOM event stalling"); 253} 254