geom_event.c revision 146353
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 3692108Sphk/* 3792108Sphk * XXX: How do we in general know that objects referenced in events 3892108Sphk * have not been destroyed before we get around to handle the event ? 3992108Sphk */ 4092108Sphk 41116196Sobrien#include <sys/cdefs.h> 42116196Sobrien__FBSDID("$FreeBSD: head/sys/geom/geom_event.c 146353 2005-05-18 21:53:08Z pjd $"); 43116196Sobrien 4492108Sphk#include <sys/param.h> 4592108Sphk#include <sys/malloc.h> 4692108Sphk#include <sys/systm.h> 4792108Sphk#include <sys/kernel.h> 4892108Sphk#include <sys/lock.h> 4992108Sphk#include <sys/mutex.h> 50136837Sphk#include <sys/proc.h> 5192108Sphk#include <sys/errno.h> 5292108Sphk#include <sys/time.h> 5392108Sphk#include <geom/geom.h> 5493250Sphk#include <geom/geom_int.h> 5592108Sphk 56136837Sphk#include <machine/stdarg.h> 57136837Sphk 58113938SphkTAILQ_HEAD(event_tailq_head, g_event); 59113938Sphk 6092108Sphkstatic struct event_tailq_head g_events = TAILQ_HEAD_INITIALIZER(g_events); 61109170Sphkstatic u_int g_pending_events; 6292108Sphkstatic TAILQ_HEAD(,g_provider) g_doorstep = TAILQ_HEAD_INITIALIZER(g_doorstep); 63104053Sphkstatic struct mtx g_eventlock; 64131820Sphkstatic int g_wither_work; 6592108Sphk 66113938Sphk#define G_N_EVENTREFS 20 67113938Sphk 68113938Sphkstruct g_event { 69113938Sphk TAILQ_ENTRY(g_event) events; 70113940Sphk g_event_t *func; 71113938Sphk void *arg; 72113940Sphk int flag; 73113938Sphk void *ref[G_N_EVENTREFS]; 74113938Sphk}; 75113938Sphk 76113940Sphk#define EV_DONE 0x80000 77113940Sphk#define EV_WAKEUP 0x40000 78114450Sphk#define EV_CANCELED 0x20000 79113940Sphk 8092108Sphkvoid 8198066Sphkg_waitidle(void) 8292108Sphk{ 8392108Sphk 84136837Sphk g_topology_assert_not(); 85136837Sphk mtx_assert(&Giant, MA_NOTOWNED); 86136837Sphk 8792108Sphk while (g_pending_events) 8898066Sphk tsleep(&g_pending_events, PPAUSE, "g_waitidle", hz/5); 89136837Sphk curthread->td_pflags &= ~TDP_GEOM; 9092108Sphk} 9192108Sphk 9292108Sphkvoid 93137489Spjdg_waitidlelock(void) 94137489Spjd{ 95137489Spjd 96137489Spjd g_topology_assert(); 97137489Spjd while (g_pending_events) { 98137489Spjd g_topology_unlock(); 99137489Spjd tsleep(&g_pending_events, PPAUSE, "g_waitidle", hz/5); 100137489Spjd g_topology_lock(); 101137489Spjd } 102137489Spjd} 103137489Spjd 104137489Spjdvoid 10592108Sphkg_orphan_provider(struct g_provider *pp, int error) 10692108Sphk{ 10792108Sphk 108126798Sphk /* G_VALID_PROVIDER(pp) We likely lack topology lock */ 10992108Sphk g_trace(G_T_TOPOLOGY, "g_orphan_provider(%p(%s), %d)", 11092108Sphk pp, pp->name, error); 11192108Sphk KASSERT(error != 0, 11292108Sphk ("g_orphan_provider(%p(%s), 0) error must be non-zero\n", 11392108Sphk pp, pp->name)); 114123233Sphk 11592108Sphk pp->error = error; 116104053Sphk mtx_lock(&g_eventlock); 117123233Sphk KASSERT(!(pp->flags & G_PF_ORPHAN), 118123233Sphk ("g_orphan_provider(%p(%s)), already an orphan", pp, pp->name)); 119123233Sphk pp->flags |= G_PF_ORPHAN; 12092108Sphk TAILQ_INSERT_TAIL(&g_doorstep, pp, orphan); 121104053Sphk mtx_unlock(&g_eventlock); 12292108Sphk wakeup(&g_wait_event); 12392108Sphk} 12492108Sphk 12592108Sphk/* 12692108Sphk * This function is called once on each provider which the event handler 12792108Sphk * finds on its g_doorstep. 12892108Sphk */ 12992108Sphk 13092108Sphkstatic void 13193250Sphkg_orphan_register(struct g_provider *pp) 13292108Sphk{ 13392108Sphk struct g_consumer *cp, *cp2; 134123761Sphk int wf; 13592108Sphk 136126798Sphk g_topology_assert(); 137126798Sphk G_VALID_PROVIDER(pp); 13892108Sphk g_trace(G_T_TOPOLOGY, "g_orphan_register(%s)", pp->name); 13992108Sphk 140123761Sphk wf = pp->flags & G_PF_WITHER; 141123761Sphk pp->flags &= ~G_PF_WITHER; 142123761Sphk 14392108Sphk /* 14492108Sphk * Tell all consumers the bad news. 145112029Sphk * Don't be surprised if they self-destruct. 14692108Sphk */ 14792108Sphk cp = LIST_FIRST(&pp->consumers); 14892108Sphk while (cp != NULL) { 14992108Sphk cp2 = LIST_NEXT(cp, consumers); 15093776Sphk KASSERT(cp->geom->orphan != NULL, 15193776Sphk ("geom %s has no orphan, class %s", 15293776Sphk cp->geom->name, cp->geom->class->name)); 15393776Sphk cp->geom->orphan(cp); 15492108Sphk cp = cp2; 15592108Sphk } 156123761Sphk if (LIST_EMPTY(&pp->consumers) && wf) 157121029Sphk g_destroy_provider(pp); 158123761Sphk else 159123761Sphk pp->flags |= wf; 160112322Sphk#ifdef notyet 161112070Sphk cp = LIST_FIRST(&pp->consumers); 162112070Sphk if (cp != NULL) 163112070Sphk return; 164112070Sphk if (pp->geom->flags & G_GEOM_WITHER) 165112070Sphk g_destroy_provider(pp); 166112322Sphk#endif 16792108Sphk} 16892108Sphk 16992108Sphkstatic int 17093250Sphkone_event(void) 17192108Sphk{ 17292108Sphk struct g_event *ep; 17392108Sphk struct g_provider *pp; 17492108Sphk 17592108Sphk g_topology_lock(); 17692108Sphk for (;;) { 177104053Sphk mtx_lock(&g_eventlock); 17892108Sphk pp = TAILQ_FIRST(&g_doorstep); 179126798Sphk if (pp != NULL) { 180126798Sphk G_VALID_PROVIDER(pp); 18192108Sphk TAILQ_REMOVE(&g_doorstep, pp, orphan); 182126798Sphk } 183104053Sphk mtx_unlock(&g_eventlock); 18492108Sphk if (pp == NULL) 18592108Sphk break; 18693250Sphk g_orphan_register(pp); 18792108Sphk } 188104056Sphk mtx_lock(&g_eventlock); 18992108Sphk ep = TAILQ_FIRST(&g_events); 19092108Sphk if (ep == NULL) { 191104056Sphk mtx_unlock(&g_eventlock); 19292108Sphk g_topology_unlock(); 19392108Sphk return (0); 19492108Sphk } 19592108Sphk TAILQ_REMOVE(&g_events, ep, events); 196104056Sphk mtx_unlock(&g_eventlock); 197113934Sphk g_topology_assert(); 198113934Sphk ep->func(ep->arg, 0); 199113934Sphk g_topology_assert(); 200113940Sphk if (ep->flag & EV_WAKEUP) { 201113940Sphk ep->flag |= EV_DONE; 202113940Sphk wakeup(ep); 203113940Sphk } else { 204114490Sphk g_free(ep); 205113940Sphk } 20692108Sphk g_pending_events--; 207106408Sphk if (g_pending_events == 0) 20892108Sphk wakeup(&g_pending_events); 20992108Sphk g_topology_unlock(); 21092108Sphk return (1); 21192108Sphk} 21292108Sphk 21392108Sphkvoid 21493250Sphkg_run_events() 21592108Sphk{ 216131820Sphk int i; 21792108Sphk 21893250Sphk while (one_event()) 21992108Sphk ; 220131820Sphk g_topology_lock(); 221131820Sphk i = g_wither_work; 222131820Sphk while (i) { 223131820Sphk i = g_wither_washer(); 224131820Sphk g_wither_work = i & 1; 225131820Sphk i &= 2; 226131820Sphk } 227131820Sphk g_topology_unlock(); 22892108Sphk} 22992108Sphk 23092108Sphkvoid 231112988Sphkg_cancel_event(void *ref) 232112518Sphk{ 233112518Sphk struct g_event *ep, *epn; 234114447Sphk struct g_provider *pp; 235112988Sphk u_int n; 236112518Sphk 237112518Sphk mtx_lock(&g_eventlock); 238114447Sphk TAILQ_FOREACH(pp, &g_doorstep, orphan) { 239114447Sphk if (pp != ref) 240114447Sphk continue; 241114447Sphk TAILQ_REMOVE(&g_doorstep, pp, orphan); 242114447Sphk break; 243114447Sphk } 244112988Sphk for (ep = TAILQ_FIRST(&g_events); ep != NULL; ep = epn) { 245112518Sphk epn = TAILQ_NEXT(ep, events); 246112988Sphk for (n = 0; n < G_N_EVENTREFS; n++) { 247112988Sphk if (ep->ref[n] == NULL) 248112988Sphk break; 249112988Sphk if (ep->ref[n] == ref) { 250112988Sphk TAILQ_REMOVE(&g_events, ep, events); 251113934Sphk ep->func(ep->arg, EV_CANCEL); 252113940Sphk if (ep->flag & EV_WAKEUP) { 253113940Sphk ep->flag |= EV_DONE; 254114450Sphk ep->flag |= EV_CANCELED; 255113940Sphk wakeup(ep); 256113940Sphk } else { 257114490Sphk g_free(ep); 258113940Sphk } 259124885Sphk if (--g_pending_events == 0) 260124885Sphk wakeup(&g_pending_events); 261112988Sphk break; 262112988Sphk } 263112518Sphk } 264112518Sphk } 265112518Sphk mtx_unlock(&g_eventlock); 266112518Sphk} 267112518Sphk 268113940Sphkstatic int 269125318Sphkg_post_event_x(g_event_t *func, void *arg, int flag, int wuflag, struct g_event **epp, va_list ap) 270104056Sphk{ 271104056Sphk struct g_event *ep; 272112988Sphk void *p; 273112988Sphk u_int n; 274104056Sphk 275125318Sphk g_trace(G_T_TOPOLOGY, "g_post_event_x(%p, %p, %d, %d)", 276146353Spjd func, arg, flag, wuflag); 277125318Sphk KASSERT(wuflag == 0 || wuflag == EV_WAKEUP, 278125318Sphk ("Wrong wuflag in g_post_event_x(0x%x)", wuflag)); 279113937Sphk ep = g_malloc(sizeof *ep, flag | M_ZERO); 280104056Sphk if (ep == NULL) 281104056Sphk return (ENOMEM); 282125318Sphk ep->flag = wuflag; 283112988Sphk for (n = 0; n < G_N_EVENTREFS; n++) { 284112988Sphk p = va_arg(ap, void *); 285112988Sphk if (p == NULL) 286112988Sphk break; 287112988Sphk g_trace(G_T_TOPOLOGY, " ref %p", p); 288122880Sphk ep->ref[n] = p; 289112988Sphk } 290112988Sphk KASSERT(p == NULL, ("Too many references to event")); 291104056Sphk ep->func = func; 292104056Sphk ep->arg = arg; 293104056Sphk mtx_lock(&g_eventlock); 294104056Sphk g_pending_events++; 295104056Sphk TAILQ_INSERT_TAIL(&g_events, ep, events); 296104056Sphk mtx_unlock(&g_eventlock); 297104056Sphk wakeup(&g_wait_event); 298113940Sphk if (epp != NULL) 299113940Sphk *epp = ep; 300136837Sphk curthread->td_pflags |= TDP_GEOM; 301104056Sphk return (0); 302104056Sphk} 303104056Sphk 304113940Sphkint 305113940Sphkg_post_event(g_event_t *func, void *arg, int flag, ...) 306113940Sphk{ 307113940Sphk va_list ap; 308115949Sphk int i; 309113940Sphk 310113940Sphk KASSERT(flag == M_WAITOK || flag == M_NOWAIT, 311113940Sphk ("Wrong flag to g_post_event")); 312115949Sphk va_start(ap, flag); 313125318Sphk i = g_post_event_x(func, arg, flag, 0, NULL, ap); 314115949Sphk va_end(ap); 315115949Sphk return (i); 316113940Sphk} 317113940Sphk 318131820Sphkvoid 319131820Sphkg_do_wither() { 320113940Sphk 321131820Sphk g_wither_work = 1; 322131820Sphk wakeup(&g_wait_event); 323131820Sphk} 324131820Sphk 325113940Sphk/* 326113940Sphk * XXX: It might actually be useful to call this function with topology held. 327113940Sphk * XXX: This would ensure that the event gets created before anything else 328113940Sphk * XXX: changes. At present all users have a handle on things in some other 329113940Sphk * XXX: way, so this remains an XXX for now. 330113940Sphk */ 331113940Sphk 332113940Sphkint 333113940Sphkg_waitfor_event(g_event_t *func, void *arg, int flag, ...) 334113940Sphk{ 335113940Sphk va_list ap; 336113940Sphk struct g_event *ep; 337113940Sphk int error; 338113940Sphk 339125657Spjd g_topology_assert_not(); 340113940Sphk KASSERT(flag == M_WAITOK || flag == M_NOWAIT, 341113940Sphk ("Wrong flag to g_post_event")); 342115949Sphk va_start(ap, flag); 343125318Sphk error = g_post_event_x(func, arg, flag, EV_WAKEUP, &ep, ap); 344115949Sphk va_end(ap); 345113940Sphk if (error) 346113940Sphk return (error); 347113940Sphk do 348113940Sphk tsleep(ep, PRIBIO, "g_waitfor_event", hz); 349113940Sphk while (!(ep->flag & EV_DONE)); 350114450Sphk if (ep->flag & EV_CANCELED) 351114450Sphk error = EAGAIN; 352114490Sphk g_free(ep); 353114450Sphk return (error); 354113940Sphk} 355113940Sphk 35692108Sphkvoid 35792108Sphkg_event_init() 35892108Sphk{ 35992108Sphk 360104053Sphk mtx_init(&g_eventlock, "GEOM orphanage", NULL, MTX_DEF); 36192108Sphk} 362