geom_event.c revision 104056
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 104056 2002-09-27 20:38:36Z 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, g_silence_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 int g_shutdown;
70
71void
72g_silence(void)
73{
74
75	g_silence_events = 1;
76}
77
78void
79g_waitidle(void)
80{
81
82	g_silence_events = 0;
83	mtx_lock(&Giant);
84	wakeup(&g_silence_events);
85	while (g_pending_events)
86		tsleep(&g_pending_events, PPAUSE, "g_waitidle", hz/5);
87	mtx_unlock(&Giant);
88}
89
90void
91g_orphan_provider(struct g_provider *pp, int error)
92{
93
94	g_trace(G_T_TOPOLOGY, "g_orphan_provider(%p(%s), %d)",
95	    pp, pp->name, error);
96	KASSERT(error != 0,
97	    ("g_orphan_provider(%p(%s), 0) error must be non-zero\n",
98	     pp, pp->name));
99	pp->error = error;
100	mtx_lock(&g_eventlock);
101	TAILQ_INSERT_TAIL(&g_doorstep, pp, orphan);
102	mtx_unlock(&g_eventlock);
103	wakeup(&g_wait_event);
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->orphan != NULL,
127		    ("geom %s has no orphan, class %s",
128		    cp->geom->name, cp->geom->class->name));
129		cp->geom->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_CALL_ME:
155		ep->func(ep->arg);
156		break;
157	case EV_NEW_CLASS:
158		mp2 = ep->class;
159		if (g_shutdown)
160			break;
161		if (mp2->taste == NULL)
162			break;
163		if (g_shutdown)
164			break;
165		LIST_FOREACH(mp, &g_classes, class) {
166			if (mp2 == mp)
167				continue;
168			LIST_FOREACH(gp, &mp->geom, geom) {
169				LIST_FOREACH(pp, &gp->provider, provider) {
170					mp2->taste(ep->class, pp, 0);
171					g_topology_assert();
172				}
173			}
174		}
175		break;
176	case EV_NEW_PROVIDER:
177		if (g_shutdown)
178			break;
179		g_trace(G_T_TOPOLOGY, "EV_NEW_PROVIDER(%s)",
180		    ep->provider->name);
181		LIST_FOREACH(mp, &g_classes, class) {
182			if (mp->taste == NULL)
183				continue;
184			i = 1;
185			LIST_FOREACH(cp, &ep->provider->consumers, consumers)
186				if(cp->geom->class == mp)
187					i = 0;
188			if (i) {
189				mp->taste(mp, ep->provider, 0);
190				g_topology_assert();
191			}
192		}
193		break;
194	case EV_SPOILED:
195		g_trace(G_T_TOPOLOGY, "EV_SPOILED(%p(%s),%p)",
196		    ep->provider, ep->provider->name, ep->consumer);
197		cp = LIST_FIRST(&ep->provider->consumers);
198		while (cp != NULL) {
199			cp2 = LIST_NEXT(cp, consumers);
200			if (cp->spoiled) {
201				g_trace(G_T_TOPOLOGY, "spoiling %p (%s) (%p)",
202				    cp, cp->geom->name, cp->geom->spoiled);
203				if (cp->geom->spoiled != NULL)
204					cp->geom->spoiled(cp);
205				else
206					cp->spoiled = 0;
207			}
208			cp = cp2;
209		}
210		break;
211	case EV_LAST:
212	default:
213		KASSERT(1 == 0, ("Unknown event %d", ep->event));
214	}
215}
216
217static int
218one_event(void)
219{
220	struct g_event *ep;
221	struct g_provider *pp;
222
223	g_topology_lock();
224	for (;;) {
225		mtx_lock(&g_eventlock);
226		pp = TAILQ_FIRST(&g_doorstep);
227		if (pp != NULL)
228			TAILQ_REMOVE(&g_doorstep, pp, orphan);
229		mtx_unlock(&g_eventlock);
230		if (pp == NULL)
231			break;
232		g_orphan_register(pp);
233	}
234	mtx_lock(&g_eventlock);
235	ep = TAILQ_FIRST(&g_events);
236	if (ep == NULL) {
237		mtx_unlock(&g_eventlock);
238		g_topology_unlock();
239		return (0);
240	}
241	TAILQ_REMOVE(&g_events, ep, events);
242	mtx_unlock(&g_eventlock);
243	if (ep->class != NULL)
244		ep->class->event = NULL;
245	if (ep->geom != NULL)
246		ep->geom->event = NULL;
247	if (ep->provider != NULL)
248		ep->provider->event = NULL;
249	if (ep->consumer != NULL)
250		ep->consumer->event = NULL;
251	g_do_event(ep);
252	g_pending_events--;
253	if (g_pending_events == 0) {
254		wakeup(&g_pending_events);
255	}
256	g_topology_unlock();
257	g_destroy_event(ep);
258	return (1);
259}
260
261void
262g_run_events()
263{
264
265	while (one_event())
266		;
267}
268
269void
270g_post_event(enum g_events ev, struct g_class *mp, struct g_geom *gp, struct g_provider *pp, struct g_consumer *cp)
271{
272	struct g_event *ep;
273
274	g_trace(G_T_TOPOLOGY, "g_post_event(%d, %p, %p, %p, %p)",
275	    ev, mp, gp, pp, cp);
276	g_topology_assert();
277	ep = g_malloc(sizeof *ep, M_WAITOK | M_ZERO);
278	ep->event = ev;
279	if (mp != NULL) {
280		ep->class = mp;
281		KASSERT(mp->event == NULL, ("Double event on class"));
282		mp->event = ep;
283	}
284	if (gp != NULL) {
285		ep->geom = gp;
286		KASSERT(gp->event == NULL, ("Double event on geom"));
287		gp->event = ep;
288	}
289	if (pp != NULL) {
290		ep->provider = pp;
291		KASSERT(pp->event == NULL, ("Double event on provider"));
292		pp->event = ep;
293	}
294	if (cp != NULL) {
295		ep->consumer = cp;
296		KASSERT(cp->event == NULL, ("Double event on consumer"));
297		cp->event = ep;
298	}
299	mtx_lock(&g_eventlock);
300	g_pending_events++;
301	TAILQ_INSERT_TAIL(&g_events, ep, events);
302	mtx_unlock(&g_eventlock);
303	wakeup(&g_wait_event);
304}
305
306int
307g_call_me(g_call_me_t *func, void *arg)
308{
309	struct g_event *ep;
310
311	g_trace(G_T_TOPOLOGY, "g_call_me(%p, %p", func, arg);
312	ep = g_malloc(sizeof *ep, M_NOWAIT | M_ZERO);
313	if (ep == NULL)
314		return (ENOMEM);
315	ep->event = EV_CALL_ME;
316	ep->func = func;
317	ep->arg = arg;
318	mtx_lock(&g_eventlock);
319	g_pending_events++;
320	TAILQ_INSERT_TAIL(&g_events, ep, events);
321	mtx_unlock(&g_eventlock);
322	wakeup(&g_wait_event);
323	return (0);
324}
325
326#ifdef _KERNEL
327static void
328geom_shutdown(void *foo __unused)
329{
330
331	g_shutdown = 1;
332}
333#endif
334
335void
336g_event_init()
337{
338
339#ifdef _KERNEL
340
341	EVENTHANDLER_REGISTER(shutdown_pre_sync, geom_shutdown, NULL,
342		SHUTDOWN_PRI_FIRST);
343#endif
344	mtx_init(&g_eventlock, "GEOM orphanage", NULL, MTX_DEF);
345}
346