geom_event.c revision 136837
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 136837 2004-10-23 20:49:17Z phk $"); 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 9392108Sphkg_orphan_provider(struct g_provider *pp, int error) 9492108Sphk{ 9592108Sphk 96126798Sphk /* G_VALID_PROVIDER(pp) We likely lack topology lock */ 9792108Sphk g_trace(G_T_TOPOLOGY, "g_orphan_provider(%p(%s), %d)", 9892108Sphk pp, pp->name, error); 9992108Sphk KASSERT(error != 0, 10092108Sphk ("g_orphan_provider(%p(%s), 0) error must be non-zero\n", 10192108Sphk pp, pp->name)); 102123233Sphk 10392108Sphk pp->error = error; 104104053Sphk mtx_lock(&g_eventlock); 105123233Sphk KASSERT(!(pp->flags & G_PF_ORPHAN), 106123233Sphk ("g_orphan_provider(%p(%s)), already an orphan", pp, pp->name)); 107123233Sphk pp->flags |= G_PF_ORPHAN; 10892108Sphk TAILQ_INSERT_TAIL(&g_doorstep, pp, orphan); 109104053Sphk mtx_unlock(&g_eventlock); 11092108Sphk wakeup(&g_wait_event); 11192108Sphk} 11292108Sphk 11392108Sphk/* 11492108Sphk * This function is called once on each provider which the event handler 11592108Sphk * finds on its g_doorstep. 11692108Sphk */ 11792108Sphk 11892108Sphkstatic void 11993250Sphkg_orphan_register(struct g_provider *pp) 12092108Sphk{ 12192108Sphk struct g_consumer *cp, *cp2; 122123761Sphk int wf; 12392108Sphk 124126798Sphk g_topology_assert(); 125126798Sphk G_VALID_PROVIDER(pp); 12692108Sphk g_trace(G_T_TOPOLOGY, "g_orphan_register(%s)", pp->name); 12792108Sphk 128123761Sphk wf = pp->flags & G_PF_WITHER; 129123761Sphk pp->flags &= ~G_PF_WITHER; 130123761Sphk 13192108Sphk /* 13292108Sphk * Tell all consumers the bad news. 133112029Sphk * Don't be surprised if they self-destruct. 13492108Sphk */ 13592108Sphk cp = LIST_FIRST(&pp->consumers); 13692108Sphk while (cp != NULL) { 13792108Sphk cp2 = LIST_NEXT(cp, consumers); 13893776Sphk KASSERT(cp->geom->orphan != NULL, 13993776Sphk ("geom %s has no orphan, class %s", 14093776Sphk cp->geom->name, cp->geom->class->name)); 14193776Sphk cp->geom->orphan(cp); 14292108Sphk cp = cp2; 14392108Sphk } 144123761Sphk if (LIST_EMPTY(&pp->consumers) && wf) 145121029Sphk g_destroy_provider(pp); 146123761Sphk else 147123761Sphk pp->flags |= wf; 148112322Sphk#ifdef notyet 149112070Sphk cp = LIST_FIRST(&pp->consumers); 150112070Sphk if (cp != NULL) 151112070Sphk return; 152112070Sphk if (pp->geom->flags & G_GEOM_WITHER) 153112070Sphk g_destroy_provider(pp); 154112322Sphk#endif 15592108Sphk} 15692108Sphk 15792108Sphkstatic int 15893250Sphkone_event(void) 15992108Sphk{ 16092108Sphk struct g_event *ep; 16192108Sphk struct g_provider *pp; 16292108Sphk 16392108Sphk g_topology_lock(); 16492108Sphk for (;;) { 165104053Sphk mtx_lock(&g_eventlock); 16692108Sphk pp = TAILQ_FIRST(&g_doorstep); 167126798Sphk if (pp != NULL) { 168126798Sphk G_VALID_PROVIDER(pp); 16992108Sphk TAILQ_REMOVE(&g_doorstep, pp, orphan); 170126798Sphk } 171104053Sphk mtx_unlock(&g_eventlock); 17292108Sphk if (pp == NULL) 17392108Sphk break; 17493250Sphk g_orphan_register(pp); 17592108Sphk } 176104056Sphk mtx_lock(&g_eventlock); 17792108Sphk ep = TAILQ_FIRST(&g_events); 17892108Sphk if (ep == NULL) { 179104056Sphk mtx_unlock(&g_eventlock); 18092108Sphk g_topology_unlock(); 18192108Sphk return (0); 18292108Sphk } 18392108Sphk TAILQ_REMOVE(&g_events, ep, events); 184104056Sphk mtx_unlock(&g_eventlock); 185113934Sphk g_topology_assert(); 186113934Sphk ep->func(ep->arg, 0); 187113934Sphk g_topology_assert(); 188113940Sphk if (ep->flag & EV_WAKEUP) { 189113940Sphk ep->flag |= EV_DONE; 190113940Sphk wakeup(ep); 191113940Sphk } else { 192114490Sphk g_free(ep); 193113940Sphk } 19492108Sphk g_pending_events--; 195106408Sphk if (g_pending_events == 0) 19692108Sphk wakeup(&g_pending_events); 19792108Sphk g_topology_unlock(); 19892108Sphk return (1); 19992108Sphk} 20092108Sphk 20192108Sphkvoid 20293250Sphkg_run_events() 20392108Sphk{ 204131820Sphk int i; 20592108Sphk 20693250Sphk while (one_event()) 20792108Sphk ; 208131820Sphk g_topology_lock(); 209131820Sphk i = g_wither_work; 210131820Sphk while (i) { 211131820Sphk i = g_wither_washer(); 212131820Sphk g_wither_work = i & 1; 213131820Sphk i &= 2; 214131820Sphk } 215131820Sphk g_topology_unlock(); 21692108Sphk} 21792108Sphk 21892108Sphkvoid 219112988Sphkg_cancel_event(void *ref) 220112518Sphk{ 221112518Sphk struct g_event *ep, *epn; 222114447Sphk struct g_provider *pp; 223112988Sphk u_int n; 224112518Sphk 225112518Sphk mtx_lock(&g_eventlock); 226114447Sphk TAILQ_FOREACH(pp, &g_doorstep, orphan) { 227114447Sphk if (pp != ref) 228114447Sphk continue; 229114447Sphk TAILQ_REMOVE(&g_doorstep, pp, orphan); 230114447Sphk break; 231114447Sphk } 232112988Sphk for (ep = TAILQ_FIRST(&g_events); ep != NULL; ep = epn) { 233112518Sphk epn = TAILQ_NEXT(ep, events); 234112988Sphk for (n = 0; n < G_N_EVENTREFS; n++) { 235112988Sphk if (ep->ref[n] == NULL) 236112988Sphk break; 237112988Sphk if (ep->ref[n] == ref) { 238112988Sphk TAILQ_REMOVE(&g_events, ep, events); 239113934Sphk ep->func(ep->arg, EV_CANCEL); 240113940Sphk if (ep->flag & EV_WAKEUP) { 241113940Sphk ep->flag |= EV_DONE; 242114450Sphk ep->flag |= EV_CANCELED; 243113940Sphk wakeup(ep); 244113940Sphk } else { 245114490Sphk g_free(ep); 246113940Sphk } 247124885Sphk if (--g_pending_events == 0) 248124885Sphk wakeup(&g_pending_events); 249112988Sphk break; 250112988Sphk } 251112518Sphk } 252112518Sphk } 253112518Sphk mtx_unlock(&g_eventlock); 254112518Sphk} 255112518Sphk 256113940Sphkstatic int 257125318Sphkg_post_event_x(g_event_t *func, void *arg, int flag, int wuflag, struct g_event **epp, va_list ap) 258104056Sphk{ 259104056Sphk struct g_event *ep; 260112988Sphk void *p; 261112988Sphk u_int n; 262104056Sphk 263125318Sphk g_trace(G_T_TOPOLOGY, "g_post_event_x(%p, %p, %d, %d)", 264125318Sphk func, arg, flag, wakeup); 265125318Sphk KASSERT(wuflag == 0 || wuflag == EV_WAKEUP, 266125318Sphk ("Wrong wuflag in g_post_event_x(0x%x)", wuflag)); 267113937Sphk ep = g_malloc(sizeof *ep, flag | M_ZERO); 268104056Sphk if (ep == NULL) 269104056Sphk return (ENOMEM); 270125318Sphk ep->flag = wuflag; 271112988Sphk for (n = 0; n < G_N_EVENTREFS; n++) { 272112988Sphk p = va_arg(ap, void *); 273112988Sphk if (p == NULL) 274112988Sphk break; 275112988Sphk g_trace(G_T_TOPOLOGY, " ref %p", p); 276122880Sphk ep->ref[n] = p; 277112988Sphk } 278112988Sphk KASSERT(p == NULL, ("Too many references to event")); 279104056Sphk ep->func = func; 280104056Sphk ep->arg = arg; 281104056Sphk mtx_lock(&g_eventlock); 282104056Sphk g_pending_events++; 283104056Sphk TAILQ_INSERT_TAIL(&g_events, ep, events); 284104056Sphk mtx_unlock(&g_eventlock); 285104056Sphk wakeup(&g_wait_event); 286113940Sphk if (epp != NULL) 287113940Sphk *epp = ep; 288136837Sphk curthread->td_pflags |= TDP_GEOM; 289104056Sphk return (0); 290104056Sphk} 291104056Sphk 292113940Sphkint 293113940Sphkg_post_event(g_event_t *func, void *arg, int flag, ...) 294113940Sphk{ 295113940Sphk va_list ap; 296115949Sphk int i; 297113940Sphk 298113940Sphk KASSERT(flag == M_WAITOK || flag == M_NOWAIT, 299113940Sphk ("Wrong flag to g_post_event")); 300115949Sphk va_start(ap, flag); 301125318Sphk i = g_post_event_x(func, arg, flag, 0, NULL, ap); 302115949Sphk va_end(ap); 303115949Sphk return (i); 304113940Sphk} 305113940Sphk 306131820Sphkvoid 307131820Sphkg_do_wither() { 308113940Sphk 309131820Sphk g_wither_work = 1; 310131820Sphk wakeup(&g_wait_event); 311131820Sphk} 312131820Sphk 313113940Sphk/* 314113940Sphk * XXX: It might actually be useful to call this function with topology held. 315113940Sphk * XXX: This would ensure that the event gets created before anything else 316113940Sphk * XXX: changes. At present all users have a handle on things in some other 317113940Sphk * XXX: way, so this remains an XXX for now. 318113940Sphk */ 319113940Sphk 320113940Sphkint 321113940Sphkg_waitfor_event(g_event_t *func, void *arg, int flag, ...) 322113940Sphk{ 323113940Sphk va_list ap; 324113940Sphk struct g_event *ep; 325113940Sphk int error; 326113940Sphk 327125657Spjd g_topology_assert_not(); 328113940Sphk KASSERT(flag == M_WAITOK || flag == M_NOWAIT, 329113940Sphk ("Wrong flag to g_post_event")); 330115949Sphk va_start(ap, flag); 331125318Sphk error = g_post_event_x(func, arg, flag, EV_WAKEUP, &ep, ap); 332115949Sphk va_end(ap); 333113940Sphk if (error) 334113940Sphk return (error); 335113940Sphk do 336113940Sphk tsleep(ep, PRIBIO, "g_waitfor_event", hz); 337113940Sphk while (!(ep->flag & EV_DONE)); 338114450Sphk if (ep->flag & EV_CANCELED) 339114450Sphk error = EAGAIN; 340114490Sphk g_free(ep); 341114450Sphk return (error); 342113940Sphk} 343113940Sphk 34492108Sphkvoid 34592108Sphkg_event_init() 34692108Sphk{ 34792108Sphk 348104053Sphk mtx_init(&g_eventlock, "GEOM orphanage", NULL, MTX_DEF); 34992108Sphk} 350