geom_event.c revision 93248
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 93248 2002-03-26 21:40:06Z 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#endif 58#include <sys/errno.h> 59#include <sys/time.h> 60#include <geom/geom.h> 61 62static struct event_tailq_head g_events = TAILQ_HEAD_INITIALIZER(g_events); 63static u_int g_pending_events, g_silence_events; 64static void g_do_event(struct g_event *ep, struct thread *tp); 65static TAILQ_HEAD(,g_provider) g_doorstep = TAILQ_HEAD_INITIALIZER(g_doorstep); 66static struct mtx g_doorlock; 67 68void 69g_silence(void) 70{ 71 72 g_silence_events = 1; 73} 74 75void 76g_rattle(void) 77{ 78 79 g_silence_events = 0; 80 mtx_lock(&Giant); 81 wakeup(&g_silence_events); 82 while (g_pending_events) 83 tsleep(&g_pending_events, PPAUSE, "g_rattle", hz/5); 84 mtx_unlock(&Giant); 85} 86 87void 88g_orphan_provider(struct g_provider *pp, int error) 89{ 90 91 g_trace(G_T_TOPOLOGY, "g_orphan_provider(%p(%s), %d)", 92 pp, pp->name, error); 93 KASSERT(error != 0, 94 ("g_orphan_provider(%p(%s), 0) error must be non-zero\n", 95 pp, pp->name)); 96 pp->error = error; 97 mtx_lock(&g_doorlock); 98 TAILQ_INSERT_TAIL(&g_doorstep, pp, orphan); 99 mtx_unlock(&g_doorlock); 100 mtx_lock(&Giant); 101 wakeup(&g_wait_event); 102 mtx_unlock(&Giant); 103} 104 105/* 106 * This function is called once on each provider which the event handler 107 * finds on its g_doorstep. 108 */ 109 110static void 111g_orphan_register(struct g_provider *pp, struct thread *tp) 112{ 113 struct g_consumer *cp, *cp2; 114 115 g_trace(G_T_TOPOLOGY, "g_orphan_register(%s)", pp->name); 116 g_topology_assert(); 117 118 /* 119 * Tell all consumers the bad news. 120 * Don't get surprised if they self-destruct. 121 */ 122 cp = LIST_FIRST(&pp->consumers); 123 while (cp != NULL) { 124 cp2 = LIST_NEXT(cp, consumers); 125 KASSERT(cp->geom->class->orphan != NULL, 126 ("class %s has no orphan, geom %s", 127 cp->geom->class->name, cp->geom->name)); 128 cp->geom->class->orphan(cp, tp); 129 cp = cp2; 130 } 131} 132 133static void 134g_destroy_event(struct g_event *ep) 135{ 136 137 g_free(ep); 138} 139 140static void 141g_do_event(struct g_event *ep, struct thread *tp) 142{ 143 struct g_class *mp, *mp2; 144 struct g_geom *gp; 145 struct g_consumer *cp, *cp2; 146 struct g_provider *pp; 147 int i; 148 149 g_trace(G_T_TOPOLOGY, "g_do_event(%p) %d m:%p g:%p p:%p c:%p - ", 150 ep, ep->event, ep->class, ep->geom, ep->provider, ep->consumer); 151 g_topology_assert(); 152 switch (ep->event) { 153 case EV_NEW_CLASS: 154 mp2 = ep->class; 155 if (mp2->taste == NULL) 156 break; 157 LIST_FOREACH(mp, &g_classs, class) { 158 if (mp2 == mp) 159 continue; 160 LIST_FOREACH(gp, &mp->geom, geom) { 161 LIST_FOREACH(pp, &gp->provider, provider) { 162 mp2->taste(ep->class, pp, tp, 0); 163 g_topology_assert(); 164 } 165 } 166 } 167 break; 168 case EV_NEW_PROVIDER: 169 g_trace(G_T_TOPOLOGY, "EV_NEW_PROVIDER(%s)", 170 ep->provider->name); 171 LIST_FOREACH(mp, &g_classs, class) { 172 if (mp->taste == NULL) 173 continue; 174 i = 1; 175 LIST_FOREACH(cp, &ep->provider->consumers, consumers) 176 if(cp->geom->class == mp) 177 i = 0; 178 if (i) { 179 mp->taste(mp, ep->provider, tp, 0); 180 g_topology_assert(); 181 } 182 } 183 break; 184 case EV_SPOILED: 185 g_trace(G_T_TOPOLOGY, "EV_SPOILED(%p(%s),%p)", 186 ep->provider, ep->provider->name, ep->consumer); 187 cp = LIST_FIRST(&ep->provider->consumers); 188 while (cp != NULL) { 189 cp2 = LIST_NEXT(cp, consumers); 190 if (cp->spoiled) { 191 g_trace(G_T_TOPOLOGY, "spoiling %p (%s) (%p)", 192 cp, cp->geom->name, cp->geom->spoiled); 193 if (cp->geom->spoiled != NULL) 194 cp->geom->spoiled(cp); 195 cp->spoiled = 0; 196 } 197 cp = cp2; 198 } 199 break; 200 case EV_LAST: 201 default: 202 KASSERT(1 == 0, ("Unknown event %d", ep->event)); 203 } 204} 205 206static int 207one_event(struct thread *tp) 208{ 209 struct g_event *ep; 210 struct g_provider *pp; 211 212 g_topology_lock(); 213 for (;;) { 214 mtx_lock(&g_doorlock); 215 pp = TAILQ_FIRST(&g_doorstep); 216 if (pp != NULL) 217 TAILQ_REMOVE(&g_doorstep, pp, orphan); 218 mtx_unlock(&g_doorlock); 219 if (pp == NULL) 220 break; 221 g_orphan_register(pp, tp); 222 } 223 ep = TAILQ_FIRST(&g_events); 224 if (ep == NULL) { 225 g_topology_unlock(); 226 return (0); 227 } 228 TAILQ_REMOVE(&g_events, ep, events); 229 if (ep->class != NULL) 230 ep->class->event = NULL; 231 if (ep->geom != NULL) 232 ep->geom->event = NULL; 233 if (ep->provider != NULL) 234 ep->provider->event = NULL; 235 if (ep->consumer != NULL) 236 ep->consumer->event = NULL; 237 g_do_event(ep, tp); 238 g_pending_events--; 239 if (g_pending_events == 0) { 240 mtx_lock(&Giant); 241 wakeup(&g_pending_events); 242 mtx_unlock(&Giant); 243 } 244 g_topology_unlock(); 245 g_destroy_event(ep); 246 return (1); 247} 248 249void 250g_run_events(struct thread *tp) 251{ 252 253 while (one_event(tp)) 254 ; 255} 256 257void 258g_post_event(enum g_events ev, struct g_class *mp, struct g_geom *gp, struct g_provider *pp, struct g_consumer *cp) 259{ 260 struct g_event *ep; 261 262 g_trace(G_T_TOPOLOGY, "g_post_event(%d, %p, %p, %p, %p)", 263 ev, mp, gp, pp, cp); 264 g_topology_assert(); 265 ep = g_malloc(sizeof *ep, M_WAITOK | M_ZERO); 266 ep->event = ev; 267 if (mp != NULL) { 268 ep->class = mp; 269 KASSERT(mp->event == NULL, ("Double event on class")); 270 mp->event = ep; 271 } 272 if (gp != NULL) { 273 ep->geom = gp; 274 KASSERT(gp->event == NULL, ("Double event on geom")); 275 gp->event = ep; 276 } 277 if (pp != NULL) { 278 ep->provider = pp; 279 KASSERT(pp->event == NULL, ("Double event on provider")); 280 pp->event = ep; 281 } 282 if (cp != NULL) { 283 ep->consumer = cp; 284 KASSERT(cp->event == NULL, ("Double event on consumer")); 285 cp->event = ep; 286 } 287 g_pending_events++; 288 TAILQ_INSERT_TAIL(&g_events, ep, events); 289 mtx_lock(&Giant); 290 wakeup(&g_wait_event); 291 mtx_unlock(&Giant); 292} 293 294void 295g_event_init() 296{ 297 298 mtx_init(&g_doorlock, "GEOM orphanage", MTX_DEF); 299} 300