geom_event.c revision 113929
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 113929 2003-04-23 20:06:38Z 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 void g_do_event(struct g_event *ep); 58static TAILQ_HEAD(,g_provider) g_doorstep = TAILQ_HEAD_INITIALIZER(g_doorstep); 59static struct mtx g_eventlock; 60static struct sx g_eventstall; 61 62void 63g_waitidle(void) 64{ 65 66 while (g_pending_events) 67 tsleep(&g_pending_events, PPAUSE, "g_waitidle", hz/5); 68} 69 70void 71g_stall_events(void) 72{ 73 74 sx_xlock(&g_eventstall); 75} 76 77void 78g_release_events(void) 79{ 80 81 sx_xunlock(&g_eventstall); 82} 83 84void 85g_orphan_provider(struct g_provider *pp, int error) 86{ 87 88 g_trace(G_T_TOPOLOGY, "g_orphan_provider(%p(%s), %d)", 89 pp, pp->name, error); 90 KASSERT(error != 0, 91 ("g_orphan_provider(%p(%s), 0) error must be non-zero\n", 92 pp, pp->name)); 93 pp->error = error; 94 mtx_lock(&g_eventlock); 95 TAILQ_INSERT_TAIL(&g_doorstep, pp, orphan); 96 mtx_unlock(&g_eventlock); 97 wakeup(&g_wait_event); 98} 99 100/* 101 * This function is called once on each provider which the event handler 102 * finds on its g_doorstep. 103 */ 104 105static void 106g_orphan_register(struct g_provider *pp) 107{ 108 struct g_consumer *cp, *cp2; 109 110 g_trace(G_T_TOPOLOGY, "g_orphan_register(%s)", pp->name); 111 g_topology_assert(); 112 113 /* 114 * Tell all consumers the bad news. 115 * Don't be surprised if they self-destruct. 116 */ 117 cp = LIST_FIRST(&pp->consumers); 118 while (cp != NULL) { 119 cp2 = LIST_NEXT(cp, consumers); 120 KASSERT(cp->geom->orphan != NULL, 121 ("geom %s has no orphan, class %s", 122 cp->geom->name, cp->geom->class->name)); 123 cp->geom->orphan(cp); 124 cp = cp2; 125 } 126#ifdef notyet 127 cp = LIST_FIRST(&pp->consumers); 128 if (cp != NULL) 129 return; 130 if (pp->geom->flags & G_GEOM_WITHER) 131 g_destroy_provider(pp); 132#endif 133} 134 135static void 136g_destroy_event(struct g_event *ep) 137{ 138 139 g_free(ep); 140} 141 142static void 143g_do_event(struct g_event *ep) 144{ 145 struct g_class *mp; 146 struct g_consumer *cp; 147 struct g_provider *pp; 148 int i; 149 150 g_trace(G_T_TOPOLOGY, "g_do_event(%p) %d - ", ep, ep->event); 151 g_topology_assert(); 152 switch (ep->event) { 153 case EV_CALL_ME: 154 ep->func(ep->arg, 0); 155 g_topology_assert(); 156 break; 157 case EV_NEW_PROVIDER: 158 if (g_shutdown) 159 break; 160 pp = ep->ref[0]; 161 g_trace(G_T_TOPOLOGY, "EV_NEW_PROVIDER(%s)", pp->name); 162 LIST_FOREACH(mp, &g_classes, class) { 163 if (mp->taste == NULL) 164 continue; 165 i = 1; 166 LIST_FOREACH(cp, &pp->consumers, consumers) 167 if(cp->geom->class == mp) 168 i = 0; 169 if (i) { 170 mp->taste(mp, pp, 0); 171 g_topology_assert(); 172 } 173 } 174 break; 175 case EV_LAST: 176 default: 177 KASSERT(1 == 0, ("Unknown event %d", ep->event)); 178 } 179} 180 181static int 182one_event(void) 183{ 184 struct g_event *ep; 185 struct g_provider *pp; 186 187 sx_xlock(&g_eventstall); 188 g_topology_lock(); 189 for (;;) { 190 mtx_lock(&g_eventlock); 191 pp = TAILQ_FIRST(&g_doorstep); 192 if (pp != NULL) 193 TAILQ_REMOVE(&g_doorstep, pp, orphan); 194 mtx_unlock(&g_eventlock); 195 if (pp == NULL) 196 break; 197 g_orphan_register(pp); 198 } 199 mtx_lock(&g_eventlock); 200 ep = TAILQ_FIRST(&g_events); 201 if (ep == NULL) { 202 mtx_unlock(&g_eventlock); 203 g_topology_unlock(); 204 sx_xunlock(&g_eventstall); 205 return (0); 206 } 207 TAILQ_REMOVE(&g_events, ep, events); 208 mtx_unlock(&g_eventlock); 209 g_do_event(ep); 210 g_destroy_event(ep); 211 g_pending_events--; 212 if (g_pending_events == 0) 213 wakeup(&g_pending_events); 214 g_topology_unlock(); 215 sx_xunlock(&g_eventstall); 216 return (1); 217} 218 219void 220g_run_events() 221{ 222 223 while (one_event()) 224 ; 225} 226 227void 228g_post_event(enum g_events ev, ...) 229{ 230 struct g_event *ep; 231 va_list ap; 232 void *p; 233 int n; 234 235 g_trace(G_T_TOPOLOGY, "g_post_event(%d)", ev); 236 g_topology_assert(); 237 ep = g_malloc(sizeof *ep, M_WAITOK | M_ZERO); 238 ep->event = ev; 239 va_start(ap, ev); 240 for (n = 0; n < G_N_EVENTREFS; n++) { 241 p = va_arg(ap, void *); 242 if (p == NULL) 243 break; 244 g_trace(G_T_TOPOLOGY, " ref %p", p); 245 ep->ref[n] = p; 246 } 247 va_end(ap); 248 KASSERT(p == NULL, ("Too many references to event")); 249 mtx_lock(&g_eventlock); 250 g_pending_events++; 251 TAILQ_INSERT_TAIL(&g_events, ep, events); 252 mtx_unlock(&g_eventlock); 253 wakeup(&g_wait_event); 254} 255 256void 257g_cancel_event(void *ref) 258{ 259 struct g_event *ep, *epn; 260 u_int n; 261 262 mtx_lock(&g_eventlock); 263 for (ep = TAILQ_FIRST(&g_events); ep != NULL; ep = epn) { 264 epn = TAILQ_NEXT(ep, events); 265 for (n = 0; n < G_N_EVENTREFS; n++) { 266 if (ep->ref[n] == NULL) 267 break; 268 if (ep->ref[n] == ref) { 269 TAILQ_REMOVE(&g_events, ep, events); 270 if (ep->event == EV_CALL_ME) 271 ep->func(ep->arg, EV_CANCEL); 272 g_free(ep); 273 break; 274 } 275 } 276 } 277 mtx_unlock(&g_eventlock); 278} 279 280int 281g_call_me(g_call_me_t *func, void *arg, ...) 282{ 283 struct g_event *ep; 284 va_list ap; 285 void *p; 286 u_int n; 287 288 g_trace(G_T_TOPOLOGY, "g_call_me(%p, %p", func, arg); 289 ep = g_malloc(sizeof *ep, M_NOWAIT | M_ZERO); 290 if (ep == NULL) 291 return (ENOMEM); 292 va_start(ap, arg); 293 for (n = 0; n < G_N_EVENTREFS; n++) { 294 p = va_arg(ap, void *); 295 if (p == NULL) 296 break; 297 g_trace(G_T_TOPOLOGY, " ref %p", p); 298 ep->ref[n++] = p; 299 } 300 va_end(ap); 301 KASSERT(p == NULL, ("Too many references to event")); 302 ep->event = EV_CALL_ME; 303 ep->func = func; 304 ep->arg = arg; 305 mtx_lock(&g_eventlock); 306 g_pending_events++; 307 TAILQ_INSERT_TAIL(&g_events, ep, events); 308 mtx_unlock(&g_eventlock); 309 wakeup(&g_wait_event); 310 return (0); 311} 312 313 314void 315g_event_init() 316{ 317 318 mtx_init(&g_eventlock, "GEOM orphanage", NULL, MTX_DEF); 319 sx_init(&g_eventstall, "GEOM event stalling"); 320} 321