geom_event.c revision 112988
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 112988 2003-04-02 20:41:18Z 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#ifndef _KERNEL 45#include <stdio.h> 46#include <unistd.h> 47#include <string.h> 48#include <stdlib.h> 49#include <signal.h> 50#include <err.h> 51#else 52#include <sys/malloc.h> 53#include <sys/systm.h> 54#include <sys/kernel.h> 55#include <sys/lock.h> 56#include <sys/mutex.h> 57#include <sys/eventhandler.h> 58#include <machine/stdarg.h> 59#endif 60#include <sys/errno.h> 61#include <sys/time.h> 62#include <geom/geom.h> 63#include <geom/geom_int.h> 64 65static struct event_tailq_head g_events = TAILQ_HEAD_INITIALIZER(g_events); 66static u_int g_pending_events; 67static void g_do_event(struct g_event *ep); 68static TAILQ_HEAD(,g_provider) g_doorstep = TAILQ_HEAD_INITIALIZER(g_doorstep); 69static struct mtx g_eventlock; 70static struct sx g_eventstall; 71static int g_shutdown; 72 73void 74g_waitidle(void) 75{ 76 77 while (g_pending_events) 78 tsleep(&g_pending_events, PPAUSE, "g_waitidle", hz/5); 79} 80 81void 82g_stall_events(void) 83{ 84 85 sx_xlock(&g_eventstall); 86} 87 88void 89g_release_events(void) 90{ 91 92 sx_xunlock(&g_eventstall); 93} 94 95void 96g_orphan_provider(struct g_provider *pp, int error) 97{ 98 99 g_trace(G_T_TOPOLOGY, "g_orphan_provider(%p(%s), %d)", 100 pp, pp->name, error); 101 KASSERT(error != 0, 102 ("g_orphan_provider(%p(%s), 0) error must be non-zero\n", 103 pp, pp->name)); 104 pp->error = error; 105 mtx_lock(&g_eventlock); 106 TAILQ_INSERT_TAIL(&g_doorstep, pp, orphan); 107 mtx_unlock(&g_eventlock); 108 wakeup(&g_wait_event); 109} 110 111/* 112 * This function is called once on each provider which the event handler 113 * finds on its g_doorstep. 114 */ 115 116static void 117g_orphan_register(struct g_provider *pp) 118{ 119 struct g_consumer *cp, *cp2; 120 121 g_trace(G_T_TOPOLOGY, "g_orphan_register(%s)", pp->name); 122 g_topology_assert(); 123 124 /* 125 * Tell all consumers the bad news. 126 * Don't be surprised if they self-destruct. 127 */ 128 cp = LIST_FIRST(&pp->consumers); 129 while (cp != NULL) { 130 cp2 = LIST_NEXT(cp, consumers); 131 KASSERT(cp->geom->orphan != NULL, 132 ("geom %s has no orphan, class %s", 133 cp->geom->name, cp->geom->class->name)); 134 cp->geom->orphan(cp); 135 cp = cp2; 136 } 137#ifdef notyet 138 cp = LIST_FIRST(&pp->consumers); 139 if (cp != NULL) 140 return; 141 if (pp->geom->flags & G_GEOM_WITHER) 142 g_destroy_provider(pp); 143#endif 144} 145 146static void 147g_destroy_event(struct g_event *ep) 148{ 149 150 g_free(ep); 151} 152 153static void 154g_do_event(struct g_event *ep) 155{ 156 struct g_class *mp, *mp2; 157 struct g_geom *gp; 158 struct g_consumer *cp, *cp2; 159 struct g_provider *pp; 160 int i; 161 162 g_trace(G_T_TOPOLOGY, "g_do_event(%p) %d - ", ep, ep->event); 163 g_topology_assert(); 164 switch (ep->event) { 165 case EV_CALL_ME: 166 ep->func(ep->arg, 0); 167 g_topology_assert(); 168 break; 169 case EV_NEW_CLASS: 170 if (g_shutdown) 171 break; 172 mp2 = ep->ref[0]; 173 if (mp2->taste == NULL) 174 break; 175 LIST_FOREACH(mp, &g_classes, class) { 176 if (mp2 == mp) 177 continue; 178 LIST_FOREACH(gp, &mp->geom, geom) { 179 LIST_FOREACH(pp, &gp->provider, provider) { 180 mp2->taste(mp2, pp, 0); 181 g_topology_assert(); 182 } 183 } 184 } 185 break; 186 case EV_NEW_PROVIDER: 187 if (g_shutdown) 188 break; 189 pp = ep->ref[0]; 190 g_trace(G_T_TOPOLOGY, "EV_NEW_PROVIDER(%s)", pp->name); 191 LIST_FOREACH(mp, &g_classes, class) { 192 if (mp->taste == NULL) 193 continue; 194 i = 1; 195 LIST_FOREACH(cp, &pp->consumers, consumers) 196 if(cp->geom->class == mp) 197 i = 0; 198 if (i) { 199 mp->taste(mp, pp, 0); 200 g_topology_assert(); 201 } 202 } 203 break; 204 case EV_SPOILED: 205 pp = ep->ref[0]; 206 g_trace(G_T_TOPOLOGY, "EV_SPOILED(%p(%s),%p)", 207 pp, pp->name, ep->ref[1]); 208 cp = LIST_FIRST(&pp->consumers); 209 while (cp != NULL) { 210 cp2 = LIST_NEXT(cp, consumers); 211 if (cp->spoiled) { 212 g_trace(G_T_TOPOLOGY, "spoiling %p (%s) (%p)", 213 cp, cp->geom->name, cp->geom->spoiled); 214 if (cp->geom->spoiled != NULL) 215 cp->geom->spoiled(cp); 216 else 217 cp->spoiled = 0; 218 } 219 cp = cp2; 220 } 221 break; 222 case EV_LAST: 223 default: 224 KASSERT(1 == 0, ("Unknown event %d", ep->event)); 225 } 226} 227 228static int 229one_event(void) 230{ 231 struct g_event *ep; 232 struct g_provider *pp; 233 234 sx_xlock(&g_eventstall); 235 g_topology_lock(); 236 for (;;) { 237 mtx_lock(&g_eventlock); 238 pp = TAILQ_FIRST(&g_doorstep); 239 if (pp != NULL) 240 TAILQ_REMOVE(&g_doorstep, pp, orphan); 241 mtx_unlock(&g_eventlock); 242 if (pp == NULL) 243 break; 244 g_orphan_register(pp); 245 } 246 mtx_lock(&g_eventlock); 247 ep = TAILQ_FIRST(&g_events); 248 if (ep == NULL) { 249 mtx_unlock(&g_eventlock); 250 g_topology_unlock(); 251 sx_xunlock(&g_eventstall); 252 return (0); 253 } 254 TAILQ_REMOVE(&g_events, ep, events); 255 mtx_unlock(&g_eventlock); 256 g_do_event(ep); 257 g_destroy_event(ep); 258 g_pending_events--; 259 if (g_pending_events == 0) 260 wakeup(&g_pending_events); 261 g_topology_unlock(); 262 sx_xunlock(&g_eventstall); 263 return (1); 264} 265 266void 267g_run_events() 268{ 269 270 while (one_event()) 271 ; 272} 273 274void 275g_post_event(enum g_events ev, ...) 276{ 277 struct g_event *ep; 278 va_list ap; 279 void *p; 280 int n; 281 282 g_trace(G_T_TOPOLOGY, "g_post_event(%d)", ev); 283 g_topology_assert(); 284 ep = g_malloc(sizeof *ep, M_WAITOK | M_ZERO); 285 ep->event = ev; 286 va_start(ap, ev); 287 for (n = 0; n < G_N_EVENTREFS; n++) { 288 p = va_arg(ap, void *); 289 if (p == NULL) 290 break; 291 g_trace(G_T_TOPOLOGY, " ref %p", p); 292 ep->ref[n++] = p; 293 } 294 va_end(ap); 295 KASSERT(p == NULL, ("Too many references to event")); 296 mtx_lock(&g_eventlock); 297 g_pending_events++; 298 TAILQ_INSERT_TAIL(&g_events, ep, events); 299 mtx_unlock(&g_eventlock); 300 wakeup(&g_wait_event); 301} 302 303void 304g_cancel_event(void *ref) 305{ 306 struct g_event *ep, *epn; 307 u_int n; 308 309 mtx_lock(&g_eventlock); 310 for (ep = TAILQ_FIRST(&g_events); ep != NULL; ep = epn) { 311 epn = TAILQ_NEXT(ep, events); 312 for (n = 0; n < G_N_EVENTREFS; n++) { 313 if (ep->ref[n] == NULL) 314 break; 315 if (ep->ref[n] == ref) { 316 TAILQ_REMOVE(&g_events, ep, events); 317 g_free(ep); 318 break; 319 } 320 } 321 } 322 mtx_unlock(&g_eventlock); 323} 324 325int 326g_call_me(g_call_me_t *func, void *arg, ...) 327{ 328 struct g_event *ep; 329 va_list ap; 330 void *p; 331 u_int n; 332 333 g_trace(G_T_TOPOLOGY, "g_call_me(%p, %p", func, arg); 334 ep = g_malloc(sizeof *ep, M_NOWAIT | M_ZERO); 335 if (ep == NULL) 336 return (ENOMEM); 337 va_start(ap, arg); 338 for (n = 0; n < G_N_EVENTREFS; n++) { 339 p = va_arg(ap, void *); 340 if (p == NULL) 341 break; 342 g_trace(G_T_TOPOLOGY, " ref %p", p); 343 ep->ref[n++] = p; 344 } 345 va_end(ap); 346 KASSERT(p == NULL, ("Too many references to event")); 347 ep->event = EV_CALL_ME; 348 ep->func = func; 349 ep->arg = arg; 350 mtx_lock(&g_eventlock); 351 g_pending_events++; 352 TAILQ_INSERT_TAIL(&g_events, ep, events); 353 mtx_unlock(&g_eventlock); 354 wakeup(&g_wait_event); 355 return (0); 356} 357 358#ifdef _KERNEL 359static void 360geom_shutdown(void *foo __unused) 361{ 362 363 g_shutdown = 1; 364} 365#endif 366 367void 368g_event_init() 369{ 370 371#ifdef _KERNEL 372 373 EVENTHANDLER_REGISTER(shutdown_pre_sync, geom_shutdown, NULL, 374 SHUTDOWN_PRI_FIRST); 375#endif 376 mtx_init(&g_eventlock, "GEOM orphanage", NULL, MTX_DEF); 377 sx_init(&g_eventstall, "GEOM event stalling"); 378} 379