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