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