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