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