geom_event.c revision 104053
192108Sphk/*-
292108Sphk * Copyright (c) 2002 Poul-Henning Kamp
392108Sphk * Copyright (c) 2002 Networks Associates Technology, Inc.
492108Sphk * All rights reserved.
592108Sphk *
692108Sphk * This software was developed for the FreeBSD Project by Poul-Henning Kamp
792108Sphk * and NAI Labs, the Security Research Division of Network Associates, Inc.
892108Sphk * under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the
992108Sphk * DARPA CHATS research program.
1092108Sphk *
1192108Sphk * Redistribution and use in source and binary forms, with or without
1292108Sphk * modification, are permitted provided that the following conditions
1392108Sphk * are met:
1492108Sphk * 1. Redistributions of source code must retain the above copyright
1592108Sphk *    notice, this list of conditions and the following disclaimer.
1692108Sphk * 2. Redistributions in binary form must reproduce the above copyright
1792108Sphk *    notice, this list of conditions and the following disclaimer in the
1892108Sphk *    documentation and/or other materials provided with the distribution.
1992108Sphk * 3. The names of the authors may not be used to endorse or promote
2092108Sphk *    products derived from this software without specific prior written
2192108Sphk *    permission.
2292108Sphk *
2392108Sphk * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
2492108Sphk * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2592108Sphk * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2692108Sphk * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2792108Sphk * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2892108Sphk * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2992108Sphk * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3092108Sphk * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3192108Sphk * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3292108Sphk * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3392108Sphk * SUCH DAMAGE.
3492108Sphk *
3592108Sphk * $FreeBSD: head/sys/geom/geom_event.c 104053 2002-09-27 20:18:16Z phk $
3692108Sphk */
3792108Sphk
3892108Sphk/*
3992108Sphk * XXX: How do we in general know that objects referenced in events
4092108Sphk * have not been destroyed before we get around to handle the event ?
4192108Sphk */
4292108Sphk
4392108Sphk#include <sys/param.h>
4492108Sphk#ifndef _KERNEL
4592108Sphk#include <stdio.h>
4692108Sphk#include <unistd.h>
4792108Sphk#include <string.h>
4892108Sphk#include <stdlib.h>
4992108Sphk#include <signal.h>
5092108Sphk#include <err.h>
5192108Sphk#else
5292108Sphk#include <sys/malloc.h>
5392108Sphk#include <sys/systm.h>
5492108Sphk#include <sys/kernel.h>
5592108Sphk#include <sys/lock.h>
5692108Sphk#include <sys/mutex.h>
5792108Sphk#endif
5892108Sphk#include <sys/errno.h>
5992108Sphk#include <sys/time.h>
6092108Sphk#include <geom/geom.h>
6193250Sphk#include <geom/geom_int.h>
6292108Sphk
6392108Sphkstatic struct event_tailq_head g_events = TAILQ_HEAD_INITIALIZER(g_events);
6492108Sphkstatic u_int g_pending_events, g_silence_events;
6593250Sphkstatic void g_do_event(struct g_event *ep);
6692108Sphkstatic TAILQ_HEAD(,g_provider) g_doorstep = TAILQ_HEAD_INITIALIZER(g_doorstep);
67104053Sphkstatic struct mtx g_eventlock;
6892108Sphk
6992108Sphkvoid
7092108Sphkg_silence(void)
7192108Sphk{
7292108Sphk
7392108Sphk	g_silence_events = 1;
7492108Sphk}
7592108Sphk
7692108Sphkvoid
7798066Sphkg_waitidle(void)
7892108Sphk{
7992108Sphk
8092108Sphk	g_silence_events = 0;
8192108Sphk	mtx_lock(&Giant);
8292108Sphk	wakeup(&g_silence_events);
8392108Sphk	while (g_pending_events)
8498066Sphk		tsleep(&g_pending_events, PPAUSE, "g_waitidle", hz/5);
8592108Sphk	mtx_unlock(&Giant);
8692108Sphk}
8792108Sphk
8892108Sphkvoid
8992108Sphkg_orphan_provider(struct g_provider *pp, int error)
9092108Sphk{
9192108Sphk
9292108Sphk	g_trace(G_T_TOPOLOGY, "g_orphan_provider(%p(%s), %d)",
9392108Sphk	    pp, pp->name, error);
9492108Sphk	KASSERT(error != 0,
9592108Sphk	    ("g_orphan_provider(%p(%s), 0) error must be non-zero\n",
9692108Sphk	     pp, pp->name));
9792108Sphk	pp->error = error;
98104053Sphk	mtx_lock(&g_eventlock);
9992108Sphk	TAILQ_INSERT_TAIL(&g_doorstep, pp, orphan);
100104053Sphk	mtx_unlock(&g_eventlock);
10192108Sphk	wakeup(&g_wait_event);
10292108Sphk}
10392108Sphk
10492108Sphk/*
10592108Sphk * This function is called once on each provider which the event handler
10692108Sphk * finds on its g_doorstep.
10792108Sphk */
10892108Sphk
10992108Sphkstatic void
11093250Sphkg_orphan_register(struct g_provider *pp)
11192108Sphk{
11292108Sphk	struct g_consumer *cp, *cp2;
11392108Sphk
11492108Sphk	g_trace(G_T_TOPOLOGY, "g_orphan_register(%s)", pp->name);
11592108Sphk	g_topology_assert();
11692108Sphk
11792108Sphk	/*
11892108Sphk	 * Tell all consumers the bad news.
11992108Sphk	 * Don't get surprised if they self-destruct.
12092108Sphk	 */
12192108Sphk	cp = LIST_FIRST(&pp->consumers);
12292108Sphk	while (cp != NULL) {
12392108Sphk		cp2 = LIST_NEXT(cp, consumers);
12493776Sphk		KASSERT(cp->geom->orphan != NULL,
12593776Sphk		    ("geom %s has no orphan, class %s",
12693776Sphk		    cp->geom->name, cp->geom->class->name));
12793776Sphk		cp->geom->orphan(cp);
12892108Sphk		cp = cp2;
12992108Sphk	}
13092108Sphk}
13192108Sphk
13292108Sphkstatic void
13392108Sphkg_destroy_event(struct g_event *ep)
13492108Sphk{
13592108Sphk
13692108Sphk	g_free(ep);
13792108Sphk}
13892108Sphk
13992108Sphkstatic void
14093250Sphkg_do_event(struct g_event *ep)
14192108Sphk{
14293248Sphk	struct g_class *mp, *mp2;
14392108Sphk	struct g_geom *gp;
14492108Sphk	struct g_consumer *cp, *cp2;
14592108Sphk	struct g_provider *pp;
14692108Sphk	int i;
14792108Sphk
14892108Sphk	g_trace(G_T_TOPOLOGY, "g_do_event(%p) %d m:%p g:%p p:%p c:%p - ",
14993248Sphk	    ep, ep->event, ep->class, ep->geom, ep->provider, ep->consumer);
15092108Sphk	g_topology_assert();
15192108Sphk	switch (ep->event) {
15293248Sphk	case EV_NEW_CLASS:
15393248Sphk		mp2 = ep->class;
15492108Sphk		if (mp2->taste == NULL)
15592108Sphk			break;
15693774Sphk		LIST_FOREACH(mp, &g_classes, class) {
15792108Sphk			if (mp2 == mp)
15892108Sphk				continue;
15992108Sphk			LIST_FOREACH(gp, &mp->geom, geom) {
16092108Sphk				LIST_FOREACH(pp, &gp->provider, provider) {
16193250Sphk					mp2->taste(ep->class, pp, 0);
16292108Sphk					g_topology_assert();
16392108Sphk				}
16492108Sphk			}
16592108Sphk		}
16692108Sphk		break;
16792108Sphk	case EV_NEW_PROVIDER:
16892108Sphk		g_trace(G_T_TOPOLOGY, "EV_NEW_PROVIDER(%s)",
16992108Sphk		    ep->provider->name);
17093774Sphk		LIST_FOREACH(mp, &g_classes, class) {
17192108Sphk			if (mp->taste == NULL)
17292108Sphk				continue;
17392108Sphk			i = 1;
17492108Sphk			LIST_FOREACH(cp, &ep->provider->consumers, consumers)
17593248Sphk				if(cp->geom->class == mp)
17692108Sphk					i = 0;
17792108Sphk			if (i) {
17893250Sphk				mp->taste(mp, ep->provider, 0);
17992108Sphk				g_topology_assert();
18092108Sphk			}
18192108Sphk		}
18292108Sphk		break;
18392108Sphk	case EV_SPOILED:
18492108Sphk		g_trace(G_T_TOPOLOGY, "EV_SPOILED(%p(%s),%p)",
18592108Sphk		    ep->provider, ep->provider->name, ep->consumer);
18692108Sphk		cp = LIST_FIRST(&ep->provider->consumers);
18792108Sphk		while (cp != NULL) {
18892108Sphk			cp2 = LIST_NEXT(cp, consumers);
18992108Sphk			if (cp->spoiled) {
19092108Sphk				g_trace(G_T_TOPOLOGY, "spoiling %p (%s) (%p)",
19192108Sphk				    cp, cp->geom->name, cp->geom->spoiled);
19292108Sphk				if (cp->geom->spoiled != NULL)
19392108Sphk					cp->geom->spoiled(cp);
19497316Sphk				else
19597316Sphk					cp->spoiled = 0;
19692108Sphk			}
19792108Sphk			cp = cp2;
19892108Sphk		}
19992108Sphk		break;
20092108Sphk	case EV_LAST:
20192108Sphk	default:
20292108Sphk		KASSERT(1 == 0, ("Unknown event %d", ep->event));
20392108Sphk	}
20492108Sphk}
20592108Sphk
20692108Sphkstatic int
20793250Sphkone_event(void)
20892108Sphk{
20992108Sphk	struct g_event *ep;
21092108Sphk	struct g_provider *pp;
21192108Sphk
21292108Sphk	g_topology_lock();
21392108Sphk	for (;;) {
214104053Sphk		mtx_lock(&g_eventlock);
21592108Sphk		pp = TAILQ_FIRST(&g_doorstep);
21692108Sphk		if (pp != NULL)
21792108Sphk			TAILQ_REMOVE(&g_doorstep, pp, orphan);
218104053Sphk		mtx_unlock(&g_eventlock);
21992108Sphk		if (pp == NULL)
22092108Sphk			break;
22193250Sphk		g_orphan_register(pp);
22292108Sphk	}
22392108Sphk	ep = TAILQ_FIRST(&g_events);
22492108Sphk	if (ep == NULL) {
22592108Sphk		g_topology_unlock();
22692108Sphk		return (0);
22792108Sphk	}
22892108Sphk	TAILQ_REMOVE(&g_events, ep, events);
22993248Sphk	if (ep->class != NULL)
23093248Sphk		ep->class->event = NULL;
23192108Sphk	if (ep->geom != NULL)
23292108Sphk		ep->geom->event = NULL;
23392108Sphk	if (ep->provider != NULL)
23492108Sphk		ep->provider->event = NULL;
23592108Sphk	if (ep->consumer != NULL)
23692108Sphk		ep->consumer->event = NULL;
23793250Sphk	g_do_event(ep);
23892108Sphk	g_pending_events--;
23992108Sphk	if (g_pending_events == 0) {
24092108Sphk		wakeup(&g_pending_events);
24192108Sphk	}
24292108Sphk	g_topology_unlock();
24392108Sphk	g_destroy_event(ep);
24492108Sphk	return (1);
24592108Sphk}
24692108Sphk
24792108Sphkvoid
24893250Sphkg_run_events()
24992108Sphk{
25092108Sphk
25193250Sphk	while (one_event())
25292108Sphk		;
25392108Sphk}
25492108Sphk
25592108Sphkvoid
25693248Sphkg_post_event(enum g_events ev, struct g_class *mp, struct g_geom *gp, struct g_provider *pp, struct g_consumer *cp)
25792108Sphk{
25892108Sphk	struct g_event *ep;
25992108Sphk
26092108Sphk	g_trace(G_T_TOPOLOGY, "g_post_event(%d, %p, %p, %p, %p)",
26192108Sphk	    ev, mp, gp, pp, cp);
26292108Sphk	g_topology_assert();
26392108Sphk	ep = g_malloc(sizeof *ep, M_WAITOK | M_ZERO);
26492108Sphk	ep->event = ev;
26592108Sphk	if (mp != NULL) {
26693248Sphk		ep->class = mp;
26793248Sphk		KASSERT(mp->event == NULL, ("Double event on class"));
26892108Sphk		mp->event = ep;
26992108Sphk	}
27092108Sphk	if (gp != NULL) {
27192108Sphk		ep->geom = gp;
27292108Sphk		KASSERT(gp->event == NULL, ("Double event on geom"));
27392108Sphk		gp->event = ep;
27492108Sphk	}
27592108Sphk	if (pp != NULL) {
27692108Sphk		ep->provider = pp;
27792108Sphk		KASSERT(pp->event == NULL, ("Double event on provider"));
27892108Sphk		pp->event = ep;
27992108Sphk	}
28092108Sphk	if (cp != NULL) {
28192108Sphk		ep->consumer = cp;
28292108Sphk		KASSERT(cp->event == NULL, ("Double event on consumer"));
28392108Sphk		cp->event = ep;
28492108Sphk	}
28592108Sphk	g_pending_events++;
28692108Sphk	TAILQ_INSERT_TAIL(&g_events, ep, events);
28792108Sphk	wakeup(&g_wait_event);
28892108Sphk}
28992108Sphk
29092108Sphkvoid
29192108Sphkg_event_init()
29292108Sphk{
29392108Sphk
294104053Sphk	mtx_init(&g_eventlock, "GEOM orphanage", NULL, MTX_DEF);
29592108Sphk}
296