geom_event.c revision 113937
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 113937 2003-04-23 20:46:12Z 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#include <sys/malloc.h>
4592108Sphk#include <sys/systm.h>
4692108Sphk#include <sys/kernel.h>
4792108Sphk#include <sys/lock.h>
4892108Sphk#include <sys/mutex.h>
49112988Sphk#include <machine/stdarg.h>
5092108Sphk#include <sys/errno.h>
5192108Sphk#include <sys/time.h>
5292108Sphk#include <geom/geom.h>
5393250Sphk#include <geom/geom_int.h>
5492108Sphk
5592108Sphkstatic struct event_tailq_head g_events = TAILQ_HEAD_INITIALIZER(g_events);
56109170Sphkstatic u_int g_pending_events;
5792108Sphkstatic TAILQ_HEAD(,g_provider) g_doorstep = TAILQ_HEAD_INITIALIZER(g_doorstep);
58104053Sphkstatic struct mtx g_eventlock;
59112517Sphkstatic struct sx g_eventstall;
6092108Sphk
6192108Sphkvoid
6298066Sphkg_waitidle(void)
6392108Sphk{
6492108Sphk
6592108Sphk	while (g_pending_events)
6698066Sphk		tsleep(&g_pending_events, PPAUSE, "g_waitidle", hz/5);
6792108Sphk}
6892108Sphk
6992108Sphkvoid
70112517Sphkg_stall_events(void)
71112517Sphk{
72112517Sphk
73112533Sphk	sx_xlock(&g_eventstall);
74112517Sphk}
75112517Sphk
76112517Sphkvoid
77112517Sphkg_release_events(void)
78112517Sphk{
79112517Sphk
80112533Sphk	sx_xunlock(&g_eventstall);
81112517Sphk}
82112517Sphk
83112517Sphkvoid
8492108Sphkg_orphan_provider(struct g_provider *pp, int error)
8592108Sphk{
8692108Sphk
8792108Sphk	g_trace(G_T_TOPOLOGY, "g_orphan_provider(%p(%s), %d)",
8892108Sphk	    pp, pp->name, error);
8992108Sphk	KASSERT(error != 0,
9092108Sphk	    ("g_orphan_provider(%p(%s), 0) error must be non-zero\n",
9192108Sphk	     pp, pp->name));
9292108Sphk	pp->error = error;
93104053Sphk	mtx_lock(&g_eventlock);
9492108Sphk	TAILQ_INSERT_TAIL(&g_doorstep, pp, orphan);
95104053Sphk	mtx_unlock(&g_eventlock);
9692108Sphk	wakeup(&g_wait_event);
9792108Sphk}
9892108Sphk
9992108Sphk/*
10092108Sphk * This function is called once on each provider which the event handler
10192108Sphk * finds on its g_doorstep.
10292108Sphk */
10392108Sphk
10492108Sphkstatic void
10593250Sphkg_orphan_register(struct g_provider *pp)
10692108Sphk{
10792108Sphk	struct g_consumer *cp, *cp2;
10892108Sphk
10992108Sphk	g_trace(G_T_TOPOLOGY, "g_orphan_register(%s)", pp->name);
11092108Sphk	g_topology_assert();
11192108Sphk
11292108Sphk	/*
11392108Sphk	 * Tell all consumers the bad news.
114112029Sphk	 * Don't be surprised if they self-destruct.
11592108Sphk	 */
11692108Sphk	cp = LIST_FIRST(&pp->consumers);
11792108Sphk	while (cp != NULL) {
11892108Sphk		cp2 = LIST_NEXT(cp, consumers);
11993776Sphk		KASSERT(cp->geom->orphan != NULL,
12093776Sphk		    ("geom %s has no orphan, class %s",
12193776Sphk		    cp->geom->name, cp->geom->class->name));
12293776Sphk		cp->geom->orphan(cp);
12392108Sphk		cp = cp2;
12492108Sphk	}
125112322Sphk#ifdef notyet
126112070Sphk	cp = LIST_FIRST(&pp->consumers);
127112070Sphk	if (cp != NULL)
128112070Sphk		return;
129112070Sphk	if (pp->geom->flags & G_GEOM_WITHER)
130112070Sphk		g_destroy_provider(pp);
131112322Sphk#endif
13292108Sphk}
13392108Sphk
13492108Sphkstatic void
13592108Sphkg_destroy_event(struct g_event *ep)
13692108Sphk{
13792108Sphk
13892108Sphk	g_free(ep);
13992108Sphk}
14092108Sphk
14192108Sphkstatic int
14293250Sphkone_event(void)
14392108Sphk{
14492108Sphk	struct g_event *ep;
14592108Sphk	struct g_provider *pp;
14692108Sphk
147112517Sphk	sx_xlock(&g_eventstall);
14892108Sphk	g_topology_lock();
14992108Sphk	for (;;) {
150104053Sphk		mtx_lock(&g_eventlock);
15192108Sphk		pp = TAILQ_FIRST(&g_doorstep);
15292108Sphk		if (pp != NULL)
15392108Sphk			TAILQ_REMOVE(&g_doorstep, pp, orphan);
154104053Sphk		mtx_unlock(&g_eventlock);
15592108Sphk		if (pp == NULL)
15692108Sphk			break;
15793250Sphk		g_orphan_register(pp);
15892108Sphk	}
159104056Sphk	mtx_lock(&g_eventlock);
16092108Sphk	ep = TAILQ_FIRST(&g_events);
16192108Sphk	if (ep == NULL) {
162104056Sphk		mtx_unlock(&g_eventlock);
16392108Sphk		g_topology_unlock();
164112517Sphk		sx_xunlock(&g_eventstall);
16592108Sphk		return (0);
16692108Sphk	}
16792108Sphk	TAILQ_REMOVE(&g_events, ep, events);
168104056Sphk	mtx_unlock(&g_eventlock);
169113934Sphk	g_topology_assert();
170113934Sphk	ep->func(ep->arg, 0);
171113934Sphk	g_topology_assert();
172106408Sphk	g_destroy_event(ep);
17392108Sphk	g_pending_events--;
174106408Sphk	if (g_pending_events == 0)
17592108Sphk		wakeup(&g_pending_events);
17692108Sphk	g_topology_unlock();
177112517Sphk	sx_xunlock(&g_eventstall);
17892108Sphk	return (1);
17992108Sphk}
18092108Sphk
18192108Sphkvoid
18293250Sphkg_run_events()
18392108Sphk{
18492108Sphk
18593250Sphk	while (one_event())
18692108Sphk		;
18792108Sphk}
18892108Sphk
18992108Sphkvoid
190112988Sphkg_cancel_event(void *ref)
191112518Sphk{
192112518Sphk	struct g_event *ep, *epn;
193112988Sphk	u_int n;
194112518Sphk
195112518Sphk	mtx_lock(&g_eventlock);
196112988Sphk	for (ep = TAILQ_FIRST(&g_events); ep != NULL; ep = epn) {
197112518Sphk		epn = TAILQ_NEXT(ep, events);
198112988Sphk		for (n = 0; n < G_N_EVENTREFS; n++) {
199112988Sphk			if (ep->ref[n] == NULL)
200112988Sphk				break;
201112988Sphk			if (ep->ref[n] == ref) {
202112988Sphk				TAILQ_REMOVE(&g_events, ep, events);
203113934Sphk				ep->func(ep->arg, EV_CANCEL);
204112988Sphk				g_free(ep);
205112988Sphk				break;
206112988Sphk			}
207112518Sphk		}
208112518Sphk	}
209112518Sphk	mtx_unlock(&g_eventlock);
210112518Sphk}
211112518Sphk
212104056Sphkint
213113937Sphkg_post_event(g_event_t *func, void *arg, int flag, ...)
214104056Sphk{
215104056Sphk	struct g_event *ep;
216112988Sphk	va_list ap;
217112988Sphk	void *p;
218112988Sphk	u_int n;
219104056Sphk
220113937Sphk	g_trace(G_T_TOPOLOGY, "g_post_event(%p, %p, %d", func, arg, flag);
221113937Sphk	KASSERT(flag == M_NOWAIT || flag == M_WAITOK,
222113937Sphk	    ("Wrong flag to g_post_event"));
223113937Sphk	ep = g_malloc(sizeof *ep, flag | M_ZERO);
224104056Sphk	if (ep == NULL)
225104056Sphk		return (ENOMEM);
226113937Sphk	va_start(ap, flag);
227112988Sphk	for (n = 0; n < G_N_EVENTREFS; n++) {
228112988Sphk		p = va_arg(ap, void *);
229112988Sphk		if (p == NULL)
230112988Sphk			break;
231112988Sphk		g_trace(G_T_TOPOLOGY, "  ref %p", p);
232112988Sphk		ep->ref[n++] = p;
233112988Sphk	}
234112988Sphk	va_end(ap);
235112988Sphk	KASSERT(p == NULL, ("Too many references to event"));
236104056Sphk	ep->func = func;
237104056Sphk	ep->arg = arg;
238104056Sphk	mtx_lock(&g_eventlock);
239104056Sphk	g_pending_events++;
240104056Sphk	TAILQ_INSERT_TAIL(&g_events, ep, events);
241104056Sphk	mtx_unlock(&g_eventlock);
242104056Sphk	wakeup(&g_wait_event);
243104056Sphk	return (0);
244104056Sphk}
245104056Sphk
246104054Sphk
24792108Sphkvoid
24892108Sphkg_event_init()
24992108Sphk{
25092108Sphk
251104053Sphk	mtx_init(&g_eventlock, "GEOM orphanage", NULL, MTX_DEF);
252112517Sphk	sx_init(&g_eventstall, "GEOM event stalling");
25392108Sphk}
254