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: releng/10.3/sys/geom/geom_event.c 266970 2014-06-02 10:14:03Z ae $"); 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 79208927Smjacob#define EV_INPROGRESS 0x10000 80113940Sphk 8192108Sphkvoid 8298066Sphkg_waitidle(void) 8392108Sphk{ 8492108Sphk 85136837Sphk g_topology_assert_not(); 86136837Sphk mtx_assert(&Giant, MA_NOTOWNED); 87136837Sphk 88149787Sphk mtx_lock(&g_eventlock); 89149787Sphk while (!TAILQ_EMPTY(&g_events)) 90149787Sphk msleep(&g_pending_events, &g_eventlock, PPAUSE, 91149787Sphk "g_waitidle", hz/5); 92149787Sphk mtx_unlock(&g_eventlock); 93136837Sphk curthread->td_pflags &= ~TDP_GEOM; 9492108Sphk} 9592108Sphk 96149787Sphk#if 0 9792108Sphkvoid 98137489Spjdg_waitidlelock(void) 99137489Spjd{ 100137489Spjd 101137489Spjd g_topology_assert(); 102149787Sphk mtx_lock(&g_eventlock); 103149787Sphk while (!TAILQ_EMPTY(&g_events)) { 104137489Spjd g_topology_unlock(); 105149787Sphk msleep(&g_pending_events, &g_eventlock, PPAUSE, 106149787Sphk "g_waitidlel", hz/5); 107137489Spjd g_topology_lock(); 108137489Spjd } 109149787Sphk mtx_unlock(&g_eventlock); 110137489Spjd} 111149787Sphk#endif 112137489Spjd 113223089Sgibbsstruct g_attrchanged_args { 114223089Sgibbs struct g_provider *pp; 115223089Sgibbs const char *attr; 116223089Sgibbs}; 117223089Sgibbs 118223089Sgibbsstatic void 119223089Sgibbsg_attr_changed_event(void *arg, int flag) 120223089Sgibbs{ 121223089Sgibbs struct g_attrchanged_args *args; 122223089Sgibbs struct g_provider *pp; 123223089Sgibbs struct g_consumer *cp; 124223089Sgibbs struct g_consumer *next_cp; 125223089Sgibbs 126223089Sgibbs args = arg; 127223089Sgibbs pp = args->pp; 128223089Sgibbs 129223089Sgibbs g_topology_assert(); 130223089Sgibbs if (flag != EV_CANCEL && g_shutdown == 0) { 131223089Sgibbs 132223089Sgibbs /* 133223089Sgibbs * Tell all consumers of the change. 134223089Sgibbs */ 135223089Sgibbs LIST_FOREACH_SAFE(cp, &pp->consumers, consumers, next_cp) { 136223089Sgibbs if (cp->geom->attrchanged != NULL) 137223089Sgibbs cp->geom->attrchanged(cp, args->attr); 138223089Sgibbs } 139223089Sgibbs } 140223089Sgibbs g_free(args); 141223089Sgibbs} 142223089Sgibbs 143223089Sgibbsint 144223089Sgibbsg_attr_changed(struct g_provider *pp, const char *attr, int flag) 145223089Sgibbs{ 146223089Sgibbs struct g_attrchanged_args *args; 147223089Sgibbs int error; 148223089Sgibbs 149223089Sgibbs args = g_malloc(sizeof *args, flag); 150223089Sgibbs if (args == NULL) 151223089Sgibbs return (ENOMEM); 152223089Sgibbs args->pp = pp; 153223089Sgibbs args->attr = attr; 154223089Sgibbs error = g_post_event(g_attr_changed_event, args, flag, pp, NULL); 155223089Sgibbs if (error != 0) 156223089Sgibbs g_free(args); 157223089Sgibbs return (error); 158223089Sgibbs} 159223089Sgibbs 160137489Spjdvoid 16192108Sphkg_orphan_provider(struct g_provider *pp, int error) 16292108Sphk{ 16392108Sphk 164126798Sphk /* G_VALID_PROVIDER(pp) We likely lack topology lock */ 16592108Sphk g_trace(G_T_TOPOLOGY, "g_orphan_provider(%p(%s), %d)", 16692108Sphk pp, pp->name, error); 16792108Sphk KASSERT(error != 0, 16892108Sphk ("g_orphan_provider(%p(%s), 0) error must be non-zero\n", 16992108Sphk pp, pp->name)); 170123233Sphk 17192108Sphk pp->error = error; 172104053Sphk mtx_lock(&g_eventlock); 173123233Sphk KASSERT(!(pp->flags & G_PF_ORPHAN), 174123233Sphk ("g_orphan_provider(%p(%s)), already an orphan", pp, pp->name)); 175123233Sphk pp->flags |= G_PF_ORPHAN; 17692108Sphk TAILQ_INSERT_TAIL(&g_doorstep, pp, orphan); 177104053Sphk mtx_unlock(&g_eventlock); 17892108Sphk wakeup(&g_wait_event); 17992108Sphk} 18092108Sphk 18192108Sphk/* 18292108Sphk * This function is called once on each provider which the event handler 18392108Sphk * finds on its g_doorstep. 18492108Sphk */ 18592108Sphk 18692108Sphkstatic void 18793250Sphkg_orphan_register(struct g_provider *pp) 18892108Sphk{ 18992108Sphk struct g_consumer *cp, *cp2; 190123761Sphk int wf; 19192108Sphk 192126798Sphk g_topology_assert(); 193126798Sphk G_VALID_PROVIDER(pp); 19492108Sphk g_trace(G_T_TOPOLOGY, "g_orphan_register(%s)", pp->name); 19592108Sphk 196172354Spjd g_cancel_event(pp); 197172354Spjd 198123761Sphk wf = pp->flags & G_PF_WITHER; 199123761Sphk pp->flags &= ~G_PF_WITHER; 200123761Sphk 20192108Sphk /* 20292108Sphk * Tell all consumers the bad news. 203112029Sphk * Don't be surprised if they self-destruct. 20492108Sphk */ 205238886Smav LIST_FOREACH_SAFE(cp, &pp->consumers, consumers, cp2) { 20693776Sphk KASSERT(cp->geom->orphan != NULL, 20793776Sphk ("geom %s has no orphan, class %s", 20893776Sphk cp->geom->name, cp->geom->class->name)); 209266970Sae /* 210266970Sae * XXX: g_dev_orphan method does deferred destroying 211266970Sae * and it is possible, that other event could already 212266970Sae * call the orphan method. Check consumer's flags to 213266970Sae * do not schedule it twice. 214266970Sae */ 215266970Sae if (cp->flags & G_CF_ORPHAN) 216266970Sae continue; 217238886Smav cp->flags |= G_CF_ORPHAN; 21893776Sphk cp->geom->orphan(cp); 21992108Sphk } 220123761Sphk if (LIST_EMPTY(&pp->consumers) && wf) 221121029Sphk g_destroy_provider(pp); 222123761Sphk else 223123761Sphk pp->flags |= wf; 224112322Sphk#ifdef notyet 225112070Sphk cp = LIST_FIRST(&pp->consumers); 226112070Sphk if (cp != NULL) 227112070Sphk return; 228112070Sphk if (pp->geom->flags & G_GEOM_WITHER) 229112070Sphk g_destroy_provider(pp); 230112322Sphk#endif 23192108Sphk} 23292108Sphk 23392108Sphkstatic int 23493250Sphkone_event(void) 23592108Sphk{ 23692108Sphk struct g_event *ep; 23792108Sphk struct g_provider *pp; 23892108Sphk 239215687Sjh g_topology_assert(); 240215687Sjh mtx_lock(&g_eventlock); 241215687Sjh TAILQ_FOREACH(pp, &g_doorstep, orphan) { 242215687Sjh if (pp->nstart == pp->nend) 243215687Sjh break; 244215687Sjh } 245215687Sjh if (pp != NULL) { 246215687Sjh G_VALID_PROVIDER(pp); 247215687Sjh TAILQ_REMOVE(&g_doorstep, pp, orphan); 248104053Sphk mtx_unlock(&g_eventlock); 24993250Sphk g_orphan_register(pp); 250215687Sjh return (1); 25192108Sphk } 252215687Sjh 25392108Sphk ep = TAILQ_FIRST(&g_events); 25492108Sphk if (ep == NULL) { 255149787Sphk wakeup(&g_pending_events); 25692108Sphk return (0); 25792108Sphk } 258208927Smjacob if (ep->flag & EV_INPROGRESS) { 259208927Smjacob mtx_unlock(&g_eventlock); 260208927Smjacob return (1); 261208927Smjacob } 262208927Smjacob ep->flag |= EV_INPROGRESS; 263104056Sphk mtx_unlock(&g_eventlock); 264113934Sphk g_topology_assert(); 265113934Sphk ep->func(ep->arg, 0); 266113934Sphk g_topology_assert(); 267149787Sphk mtx_lock(&g_eventlock); 268149787Sphk TAILQ_REMOVE(&g_events, ep, events); 269208927Smjacob ep->flag &= ~EV_INPROGRESS; 270113940Sphk if (ep->flag & EV_WAKEUP) { 271113940Sphk ep->flag |= EV_DONE; 272214748Sjh mtx_unlock(&g_eventlock); 273113940Sphk wakeup(ep); 274113940Sphk } else { 275214748Sjh mtx_unlock(&g_eventlock); 276114490Sphk g_free(ep); 277113940Sphk } 27892108Sphk return (1); 27992108Sphk} 28092108Sphk 28192108Sphkvoid 28293250Sphkg_run_events() 28392108Sphk{ 28492108Sphk 285215687Sjh for (;;) { 286215687Sjh g_topology_lock(); 287215687Sjh while (one_event()) 288215687Sjh ; 289215687Sjh mtx_assert(&g_eventlock, MA_OWNED); 290248674Smav if (g_wither_work) { 291248674Smav g_wither_work = 0; 292215687Sjh mtx_unlock(&g_eventlock); 293248674Smav g_wither_washer(); 294215687Sjh g_topology_unlock(); 295215687Sjh } else { 296215687Sjh g_topology_unlock(); 297215687Sjh msleep(&g_wait_event, &g_eventlock, PRIBIO | PDROP, 298226985Smav "-", TAILQ_EMPTY(&g_doorstep) ? 0 : hz / 10); 299215687Sjh } 300131820Sphk } 301215687Sjh /* NOTREACHED */ 30292108Sphk} 30392108Sphk 30492108Sphkvoid 305112988Sphkg_cancel_event(void *ref) 306112518Sphk{ 307112518Sphk struct g_event *ep, *epn; 308114447Sphk struct g_provider *pp; 309112988Sphk u_int n; 310112518Sphk 311112518Sphk mtx_lock(&g_eventlock); 312114447Sphk TAILQ_FOREACH(pp, &g_doorstep, orphan) { 313114447Sphk if (pp != ref) 314114447Sphk continue; 315114447Sphk TAILQ_REMOVE(&g_doorstep, pp, orphan); 316114447Sphk break; 317114447Sphk } 318149787Sphk TAILQ_FOREACH_SAFE(ep, &g_events, events, epn) { 319208927Smjacob if (ep->flag & EV_INPROGRESS) 320208927Smjacob continue; 321112988Sphk for (n = 0; n < G_N_EVENTREFS; n++) { 322112988Sphk if (ep->ref[n] == NULL) 323112988Sphk break; 324149787Sphk if (ep->ref[n] != ref) 325149787Sphk continue; 326149787Sphk TAILQ_REMOVE(&g_events, ep, events); 327149787Sphk ep->func(ep->arg, EV_CANCEL); 328149787Sphk mtx_assert(&g_eventlock, MA_OWNED); 329149787Sphk if (ep->flag & EV_WAKEUP) { 330149787Sphk ep->flag |= (EV_DONE|EV_CANCELED); 331149787Sphk wakeup(ep); 332149787Sphk } else { 333149787Sphk g_free(ep); 334112988Sphk } 335149787Sphk break; 336112518Sphk } 337112518Sphk } 338149787Sphk if (TAILQ_EMPTY(&g_events)) 339149787Sphk wakeup(&g_pending_events); 340112518Sphk mtx_unlock(&g_eventlock); 341112518Sphk} 342112518Sphk 343113940Sphkstatic int 344125318Sphkg_post_event_x(g_event_t *func, void *arg, int flag, int wuflag, struct g_event **epp, va_list ap) 345104056Sphk{ 346104056Sphk struct g_event *ep; 347112988Sphk void *p; 348112988Sphk u_int n; 349104056Sphk 350125318Sphk g_trace(G_T_TOPOLOGY, "g_post_event_x(%p, %p, %d, %d)", 351146353Spjd func, arg, flag, wuflag); 352125318Sphk KASSERT(wuflag == 0 || wuflag == EV_WAKEUP, 353125318Sphk ("Wrong wuflag in g_post_event_x(0x%x)", wuflag)); 354113937Sphk ep = g_malloc(sizeof *ep, flag | M_ZERO); 355104056Sphk if (ep == NULL) 356104056Sphk return (ENOMEM); 357125318Sphk ep->flag = wuflag; 358112988Sphk for (n = 0; n < G_N_EVENTREFS; n++) { 359112988Sphk p = va_arg(ap, void *); 360112988Sphk if (p == NULL) 361112988Sphk break; 362112988Sphk g_trace(G_T_TOPOLOGY, " ref %p", p); 363122880Sphk ep->ref[n] = p; 364112988Sphk } 365112988Sphk KASSERT(p == NULL, ("Too many references to event")); 366104056Sphk ep->func = func; 367104056Sphk ep->arg = arg; 368104056Sphk mtx_lock(&g_eventlock); 369104056Sphk TAILQ_INSERT_TAIL(&g_events, ep, events); 370104056Sphk mtx_unlock(&g_eventlock); 371104056Sphk wakeup(&g_wait_event); 372113940Sphk if (epp != NULL) 373113940Sphk *epp = ep; 374136837Sphk curthread->td_pflags |= TDP_GEOM; 375104056Sphk return (0); 376104056Sphk} 377104056Sphk 378113940Sphkint 379113940Sphkg_post_event(g_event_t *func, void *arg, int flag, ...) 380113940Sphk{ 381113940Sphk va_list ap; 382115949Sphk int i; 383113940Sphk 384113940Sphk KASSERT(flag == M_WAITOK || flag == M_NOWAIT, 385113940Sphk ("Wrong flag to g_post_event")); 386115949Sphk va_start(ap, flag); 387125318Sphk i = g_post_event_x(func, arg, flag, 0, NULL, ap); 388115949Sphk va_end(ap); 389115949Sphk return (i); 390113940Sphk} 391113940Sphk 392131820Sphkvoid 393215687Sjhg_do_wither() 394215687Sjh{ 395113940Sphk 396215687Sjh mtx_lock(&g_eventlock); 397131820Sphk g_wither_work = 1; 398215687Sjh mtx_unlock(&g_eventlock); 399131820Sphk wakeup(&g_wait_event); 400131820Sphk} 401131820Sphk 402113940Sphk/* 403113940Sphk * XXX: It might actually be useful to call this function with topology held. 404113940Sphk * XXX: This would ensure that the event gets created before anything else 405113940Sphk * XXX: changes. At present all users have a handle on things in some other 406113940Sphk * XXX: way, so this remains an XXX for now. 407113940Sphk */ 408113940Sphk 409113940Sphkint 410113940Sphkg_waitfor_event(g_event_t *func, void *arg, int flag, ...) 411113940Sphk{ 412113940Sphk va_list ap; 413113940Sphk struct g_event *ep; 414113940Sphk int error; 415113940Sphk 416125657Spjd g_topology_assert_not(); 417113940Sphk KASSERT(flag == M_WAITOK || flag == M_NOWAIT, 418113940Sphk ("Wrong flag to g_post_event")); 419115949Sphk va_start(ap, flag); 420125318Sphk error = g_post_event_x(func, arg, flag, EV_WAKEUP, &ep, ap); 421115949Sphk va_end(ap); 422113940Sphk if (error) 423113940Sphk return (error); 424214748Sjh 425214748Sjh mtx_lock(&g_eventlock); 426214748Sjh while (!(ep->flag & EV_DONE)) 427214748Sjh msleep(ep, &g_eventlock, PRIBIO, "g_waitfor_event", hz); 428114450Sphk if (ep->flag & EV_CANCELED) 429114450Sphk error = EAGAIN; 430214748Sjh mtx_unlock(&g_eventlock); 431214748Sjh 432114490Sphk g_free(ep); 433114450Sphk return (error); 434113940Sphk} 435113940Sphk 43692108Sphkvoid 43792108Sphkg_event_init() 43892108Sphk{ 43992108Sphk 440104053Sphk mtx_init(&g_eventlock, "GEOM orphanage", NULL, MTX_DEF); 44192108Sphk} 442