1dd84a43cSPoul-Henning Kamp /*- 2dd84a43cSPoul-Henning Kamp * Copyright (c) 2002 Poul-Henning Kamp 3dd84a43cSPoul-Henning Kamp * Copyright (c) 2002 Networks Associates Technology, Inc. 4dd84a43cSPoul-Henning Kamp * All rights reserved. 5dd84a43cSPoul-Henning Kamp * 6dd84a43cSPoul-Henning Kamp * This software was developed for the FreeBSD Project by Poul-Henning Kamp 7dd84a43cSPoul-Henning Kamp * and NAI Labs, the Security Research Division of Network Associates, Inc. 8dd84a43cSPoul-Henning Kamp * under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the 9dd84a43cSPoul-Henning Kamp * DARPA CHATS research program. 10dd84a43cSPoul-Henning Kamp * 11dd84a43cSPoul-Henning Kamp * Redistribution and use in source and binary forms, with or without 12dd84a43cSPoul-Henning Kamp * modification, are permitted provided that the following conditions 13dd84a43cSPoul-Henning Kamp * are met: 14dd84a43cSPoul-Henning Kamp * 1. Redistributions of source code must retain the above copyright 15dd84a43cSPoul-Henning Kamp * notice, this list of conditions and the following disclaimer. 16dd84a43cSPoul-Henning Kamp * 2. Redistributions in binary form must reproduce the above copyright 17dd84a43cSPoul-Henning Kamp * notice, this list of conditions and the following disclaimer in the 18dd84a43cSPoul-Henning Kamp * documentation and/or other materials provided with the distribution. 19dd84a43cSPoul-Henning Kamp * 3. The names of the authors may not be used to endorse or promote 20dd84a43cSPoul-Henning Kamp * products derived from this software without specific prior written 21dd84a43cSPoul-Henning Kamp * permission. 22dd84a43cSPoul-Henning Kamp * 23dd84a43cSPoul-Henning Kamp * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 24dd84a43cSPoul-Henning Kamp * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25dd84a43cSPoul-Henning Kamp * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26dd84a43cSPoul-Henning Kamp * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 27dd84a43cSPoul-Henning Kamp * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28dd84a43cSPoul-Henning Kamp * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29dd84a43cSPoul-Henning Kamp * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30dd84a43cSPoul-Henning Kamp * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31dd84a43cSPoul-Henning Kamp * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32dd84a43cSPoul-Henning Kamp * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33dd84a43cSPoul-Henning Kamp * SUCH DAMAGE. 34dd84a43cSPoul-Henning Kamp * 35dd84a43cSPoul-Henning Kamp * $FreeBSD$ 36dd84a43cSPoul-Henning Kamp */ 37dd84a43cSPoul-Henning Kamp 38dd84a43cSPoul-Henning Kamp /* 39dd84a43cSPoul-Henning Kamp * XXX: How do we in general know that objects referenced in events 40dd84a43cSPoul-Henning Kamp * have not been destroyed before we get around to handle the event ? 41dd84a43cSPoul-Henning Kamp */ 42dd84a43cSPoul-Henning Kamp 43dd84a43cSPoul-Henning Kamp #include <sys/param.h> 44dd84a43cSPoul-Henning Kamp #include <sys/malloc.h> 45dd84a43cSPoul-Henning Kamp #include <sys/systm.h> 46dd84a43cSPoul-Henning Kamp #include <sys/kernel.h> 47dd84a43cSPoul-Henning Kamp #include <sys/lock.h> 48dd84a43cSPoul-Henning Kamp #include <sys/mutex.h> 49afcbcfaeSPoul-Henning Kamp #include <machine/stdarg.h> 50dd84a43cSPoul-Henning Kamp #include <sys/errno.h> 51dd84a43cSPoul-Henning Kamp #include <sys/time.h> 52dd84a43cSPoul-Henning Kamp #include <geom/geom.h> 53b1876192SPoul-Henning Kamp #include <geom/geom_int.h> 54dd84a43cSPoul-Henning Kamp 55dd84a43cSPoul-Henning Kamp static struct event_tailq_head g_events = TAILQ_HEAD_INITIALIZER(g_events); 56abb50a48SPoul-Henning Kamp static u_int g_pending_events; 57dd84a43cSPoul-Henning Kamp static TAILQ_HEAD(,g_provider) g_doorstep = TAILQ_HEAD_INITIALIZER(g_doorstep); 58903e43feSPoul-Henning Kamp static struct mtx g_eventlock; 59d943f1b0SPoul-Henning Kamp static struct sx g_eventstall; 60dd84a43cSPoul-Henning Kamp 61dd84a43cSPoul-Henning Kamp void 62503abe45SPoul-Henning Kamp g_waitidle(void) 63dd84a43cSPoul-Henning Kamp { 64dd84a43cSPoul-Henning Kamp 65dd84a43cSPoul-Henning Kamp while (g_pending_events) 66503abe45SPoul-Henning Kamp tsleep(&g_pending_events, PPAUSE, "g_waitidle", hz/5); 67dd84a43cSPoul-Henning Kamp } 68dd84a43cSPoul-Henning Kamp 69dd84a43cSPoul-Henning Kamp void 70d943f1b0SPoul-Henning Kamp g_stall_events(void) 71d943f1b0SPoul-Henning Kamp { 72d943f1b0SPoul-Henning Kamp 73fbf79df3SPoul-Henning Kamp sx_xlock(&g_eventstall); 74d943f1b0SPoul-Henning Kamp } 75d943f1b0SPoul-Henning Kamp 76d943f1b0SPoul-Henning Kamp void 77d943f1b0SPoul-Henning Kamp g_release_events(void) 78d943f1b0SPoul-Henning Kamp { 79d943f1b0SPoul-Henning Kamp 80fbf79df3SPoul-Henning Kamp sx_xunlock(&g_eventstall); 81d943f1b0SPoul-Henning Kamp } 82d943f1b0SPoul-Henning Kamp 83d943f1b0SPoul-Henning Kamp void 84dd84a43cSPoul-Henning Kamp g_orphan_provider(struct g_provider *pp, int error) 85dd84a43cSPoul-Henning Kamp { 86dd84a43cSPoul-Henning Kamp 87dd84a43cSPoul-Henning Kamp g_trace(G_T_TOPOLOGY, "g_orphan_provider(%p(%s), %d)", 88dd84a43cSPoul-Henning Kamp pp, pp->name, error); 89dd84a43cSPoul-Henning Kamp KASSERT(error != 0, 90dd84a43cSPoul-Henning Kamp ("g_orphan_provider(%p(%s), 0) error must be non-zero\n", 91dd84a43cSPoul-Henning Kamp pp, pp->name)); 92dd84a43cSPoul-Henning Kamp pp->error = error; 93903e43feSPoul-Henning Kamp mtx_lock(&g_eventlock); 94dd84a43cSPoul-Henning Kamp TAILQ_INSERT_TAIL(&g_doorstep, pp, orphan); 95903e43feSPoul-Henning Kamp mtx_unlock(&g_eventlock); 96dd84a43cSPoul-Henning Kamp wakeup(&g_wait_event); 97dd84a43cSPoul-Henning Kamp } 98dd84a43cSPoul-Henning Kamp 99dd84a43cSPoul-Henning Kamp /* 100dd84a43cSPoul-Henning Kamp * This function is called once on each provider which the event handler 101dd84a43cSPoul-Henning Kamp * finds on its g_doorstep. 102dd84a43cSPoul-Henning Kamp */ 103dd84a43cSPoul-Henning Kamp 104dd84a43cSPoul-Henning Kamp static void 105b1876192SPoul-Henning Kamp g_orphan_register(struct g_provider *pp) 106dd84a43cSPoul-Henning Kamp { 107dd84a43cSPoul-Henning Kamp struct g_consumer *cp, *cp2; 108dd84a43cSPoul-Henning Kamp 109dd84a43cSPoul-Henning Kamp g_trace(G_T_TOPOLOGY, "g_orphan_register(%s)", pp->name); 110dd84a43cSPoul-Henning Kamp g_topology_assert(); 111dd84a43cSPoul-Henning Kamp 112dd84a43cSPoul-Henning Kamp /* 113dd84a43cSPoul-Henning Kamp * Tell all consumers the bad news. 114f48b8819SPoul-Henning Kamp * Don't be surprised if they self-destruct. 115dd84a43cSPoul-Henning Kamp */ 116dd84a43cSPoul-Henning Kamp cp = LIST_FIRST(&pp->consumers); 117dd84a43cSPoul-Henning Kamp while (cp != NULL) { 118dd84a43cSPoul-Henning Kamp cp2 = LIST_NEXT(cp, consumers); 11907d77fc6SPoul-Henning Kamp KASSERT(cp->geom->orphan != NULL, 12007d77fc6SPoul-Henning Kamp ("geom %s has no orphan, class %s", 12107d77fc6SPoul-Henning Kamp cp->geom->name, cp->geom->class->name)); 12207d77fc6SPoul-Henning Kamp cp->geom->orphan(cp); 123dd84a43cSPoul-Henning Kamp cp = cp2; 124dd84a43cSPoul-Henning Kamp } 12520d2026bSPoul-Henning Kamp #ifdef notyet 126e5829909SPoul-Henning Kamp cp = LIST_FIRST(&pp->consumers); 127e5829909SPoul-Henning Kamp if (cp != NULL) 128e5829909SPoul-Henning Kamp return; 129e5829909SPoul-Henning Kamp if (pp->geom->flags & G_GEOM_WITHER) 130e5829909SPoul-Henning Kamp g_destroy_provider(pp); 13120d2026bSPoul-Henning Kamp #endif 132dd84a43cSPoul-Henning Kamp } 133dd84a43cSPoul-Henning Kamp 134dd84a43cSPoul-Henning Kamp static void 135dd84a43cSPoul-Henning Kamp g_destroy_event(struct g_event *ep) 136dd84a43cSPoul-Henning Kamp { 137dd84a43cSPoul-Henning Kamp 138dd84a43cSPoul-Henning Kamp g_free(ep); 139dd84a43cSPoul-Henning Kamp } 140dd84a43cSPoul-Henning Kamp 141dd84a43cSPoul-Henning Kamp static int 142b1876192SPoul-Henning Kamp one_event(void) 143dd84a43cSPoul-Henning Kamp { 144dd84a43cSPoul-Henning Kamp struct g_event *ep; 145dd84a43cSPoul-Henning Kamp struct g_provider *pp; 146dd84a43cSPoul-Henning Kamp 147d943f1b0SPoul-Henning Kamp sx_xlock(&g_eventstall); 148dd84a43cSPoul-Henning Kamp g_topology_lock(); 149dd84a43cSPoul-Henning Kamp for (;;) { 150903e43feSPoul-Henning Kamp mtx_lock(&g_eventlock); 151dd84a43cSPoul-Henning Kamp pp = TAILQ_FIRST(&g_doorstep); 152dd84a43cSPoul-Henning Kamp if (pp != NULL) 153dd84a43cSPoul-Henning Kamp TAILQ_REMOVE(&g_doorstep, pp, orphan); 154903e43feSPoul-Henning Kamp mtx_unlock(&g_eventlock); 155dd84a43cSPoul-Henning Kamp if (pp == NULL) 156dd84a43cSPoul-Henning Kamp break; 157b1876192SPoul-Henning Kamp g_orphan_register(pp); 158dd84a43cSPoul-Henning Kamp } 159346cd5feSPoul-Henning Kamp mtx_lock(&g_eventlock); 160dd84a43cSPoul-Henning Kamp ep = TAILQ_FIRST(&g_events); 161dd84a43cSPoul-Henning Kamp if (ep == NULL) { 162346cd5feSPoul-Henning Kamp mtx_unlock(&g_eventlock); 163dd84a43cSPoul-Henning Kamp g_topology_unlock(); 164d943f1b0SPoul-Henning Kamp sx_xunlock(&g_eventstall); 165dd84a43cSPoul-Henning Kamp return (0); 166dd84a43cSPoul-Henning Kamp } 167dd84a43cSPoul-Henning Kamp TAILQ_REMOVE(&g_events, ep, events); 168346cd5feSPoul-Henning Kamp mtx_unlock(&g_eventlock); 169d98777f8SPoul-Henning Kamp g_topology_assert(); 170d98777f8SPoul-Henning Kamp ep->func(ep->arg, 0); 171d98777f8SPoul-Henning Kamp g_topology_assert(); 172dd84a43cSPoul-Henning Kamp g_destroy_event(ep); 173a9ed5e11SPoul-Henning Kamp g_pending_events--; 174a9ed5e11SPoul-Henning Kamp if (g_pending_events == 0) 175a9ed5e11SPoul-Henning Kamp wakeup(&g_pending_events); 176a9ed5e11SPoul-Henning Kamp g_topology_unlock(); 177d943f1b0SPoul-Henning Kamp sx_xunlock(&g_eventstall); 178dd84a43cSPoul-Henning Kamp return (1); 179dd84a43cSPoul-Henning Kamp } 180dd84a43cSPoul-Henning Kamp 181dd84a43cSPoul-Henning Kamp void 182b1876192SPoul-Henning Kamp g_run_events() 183dd84a43cSPoul-Henning Kamp { 184dd84a43cSPoul-Henning Kamp 185b1876192SPoul-Henning Kamp while (one_event()) 186dd84a43cSPoul-Henning Kamp ; 187dd84a43cSPoul-Henning Kamp } 188dd84a43cSPoul-Henning Kamp 189dd84a43cSPoul-Henning Kamp void 190afcbcfaeSPoul-Henning Kamp g_cancel_event(void *ref) 191dddc28bfSPoul-Henning Kamp { 192dddc28bfSPoul-Henning Kamp struct g_event *ep, *epn; 193afcbcfaeSPoul-Henning Kamp u_int n; 194dddc28bfSPoul-Henning Kamp 195dddc28bfSPoul-Henning Kamp mtx_lock(&g_eventlock); 196afcbcfaeSPoul-Henning Kamp for (ep = TAILQ_FIRST(&g_events); ep != NULL; ep = epn) { 197dddc28bfSPoul-Henning Kamp epn = TAILQ_NEXT(ep, events); 198afcbcfaeSPoul-Henning Kamp for (n = 0; n < G_N_EVENTREFS; n++) { 199afcbcfaeSPoul-Henning Kamp if (ep->ref[n] == NULL) 200afcbcfaeSPoul-Henning Kamp break; 201afcbcfaeSPoul-Henning Kamp if (ep->ref[n] == ref) { 202dddc28bfSPoul-Henning Kamp TAILQ_REMOVE(&g_events, ep, events); 203316aed03SPoul-Henning Kamp ep->func(ep->arg, EV_CANCEL); 204dddc28bfSPoul-Henning Kamp g_free(ep); 205afcbcfaeSPoul-Henning Kamp break; 206dddc28bfSPoul-Henning Kamp } 207afcbcfaeSPoul-Henning Kamp } 208dddc28bfSPoul-Henning Kamp } 209dddc28bfSPoul-Henning Kamp mtx_unlock(&g_eventlock); 210dddc28bfSPoul-Henning Kamp } 211dddc28bfSPoul-Henning Kamp 212346cd5feSPoul-Henning Kamp int 213afcbcfaeSPoul-Henning Kamp g_call_me(g_call_me_t *func, void *arg, ...) 214346cd5feSPoul-Henning Kamp { 215346cd5feSPoul-Henning Kamp struct g_event *ep; 216afcbcfaeSPoul-Henning Kamp va_list ap; 217afcbcfaeSPoul-Henning Kamp void *p; 218afcbcfaeSPoul-Henning Kamp u_int n; 219346cd5feSPoul-Henning Kamp 220346cd5feSPoul-Henning Kamp g_trace(G_T_TOPOLOGY, "g_call_me(%p, %p", func, arg); 221346cd5feSPoul-Henning Kamp ep = g_malloc(sizeof *ep, M_NOWAIT | M_ZERO); 222346cd5feSPoul-Henning Kamp if (ep == NULL) 223346cd5feSPoul-Henning Kamp return (ENOMEM); 224afcbcfaeSPoul-Henning Kamp va_start(ap, arg); 225afcbcfaeSPoul-Henning Kamp for (n = 0; n < G_N_EVENTREFS; n++) { 226afcbcfaeSPoul-Henning Kamp p = va_arg(ap, void *); 227afcbcfaeSPoul-Henning Kamp if (p == NULL) 228afcbcfaeSPoul-Henning Kamp break; 229afcbcfaeSPoul-Henning Kamp g_trace(G_T_TOPOLOGY, " ref %p", p); 230afcbcfaeSPoul-Henning Kamp ep->ref[n++] = p; 231afcbcfaeSPoul-Henning Kamp } 232afcbcfaeSPoul-Henning Kamp va_end(ap); 233afcbcfaeSPoul-Henning Kamp KASSERT(p == NULL, ("Too many references to event")); 234346cd5feSPoul-Henning Kamp ep->func = func; 235346cd5feSPoul-Henning Kamp ep->arg = arg; 236346cd5feSPoul-Henning Kamp mtx_lock(&g_eventlock); 237346cd5feSPoul-Henning Kamp g_pending_events++; 238346cd5feSPoul-Henning Kamp TAILQ_INSERT_TAIL(&g_events, ep, events); 239346cd5feSPoul-Henning Kamp mtx_unlock(&g_eventlock); 240346cd5feSPoul-Henning Kamp wakeup(&g_wait_event); 241346cd5feSPoul-Henning Kamp return (0); 242346cd5feSPoul-Henning Kamp } 243346cd5feSPoul-Henning Kamp 244ed0ff8e5SPoul-Henning Kamp 245dd84a43cSPoul-Henning Kamp void 246dd84a43cSPoul-Henning Kamp g_event_init() 247dd84a43cSPoul-Henning Kamp { 248dd84a43cSPoul-Henning Kamp 249903e43feSPoul-Henning Kamp mtx_init(&g_eventlock, "GEOM orphanage", NULL, MTX_DEF); 250d943f1b0SPoul-Henning Kamp sx_init(&g_eventstall, "GEOM event stalling"); 251dd84a43cSPoul-Henning Kamp } 252