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/11.0/sys/geom/geom_event.c 300287 2016-05-20 08:22:20Z kib $"); 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 87149787Sphk mtx_lock(&g_eventlock); 88149787Sphk while (!TAILQ_EMPTY(&g_events)) 89149787Sphk msleep(&g_pending_events, &g_eventlock, PPAUSE, 90149787Sphk "g_waitidle", hz/5); 91149787Sphk mtx_unlock(&g_eventlock); 92136837Sphk curthread->td_pflags &= ~TDP_GEOM; 9392108Sphk} 9492108Sphk 95149787Sphk#if 0 9692108Sphkvoid 97137489Spjdg_waitidlelock(void) 98137489Spjd{ 99137489Spjd 100137489Spjd g_topology_assert(); 101149787Sphk mtx_lock(&g_eventlock); 102149787Sphk while (!TAILQ_EMPTY(&g_events)) { 103137489Spjd g_topology_unlock(); 104149787Sphk msleep(&g_pending_events, &g_eventlock, PPAUSE, 105149787Sphk "g_waitidlel", hz/5); 106137489Spjd g_topology_lock(); 107137489Spjd } 108149787Sphk mtx_unlock(&g_eventlock); 109137489Spjd} 110149787Sphk#endif 111137489Spjd 112223089Sgibbsstruct g_attrchanged_args { 113223089Sgibbs struct g_provider *pp; 114223089Sgibbs const char *attr; 115223089Sgibbs}; 116223089Sgibbs 117223089Sgibbsstatic void 118223089Sgibbsg_attr_changed_event(void *arg, int flag) 119223089Sgibbs{ 120223089Sgibbs struct g_attrchanged_args *args; 121223089Sgibbs struct g_provider *pp; 122223089Sgibbs struct g_consumer *cp; 123223089Sgibbs struct g_consumer *next_cp; 124223089Sgibbs 125223089Sgibbs args = arg; 126223089Sgibbs pp = args->pp; 127223089Sgibbs 128223089Sgibbs g_topology_assert(); 129223089Sgibbs if (flag != EV_CANCEL && g_shutdown == 0) { 130223089Sgibbs 131223089Sgibbs /* 132223089Sgibbs * Tell all consumers of the change. 133223089Sgibbs */ 134223089Sgibbs LIST_FOREACH_SAFE(cp, &pp->consumers, consumers, next_cp) { 135223089Sgibbs if (cp->geom->attrchanged != NULL) 136223089Sgibbs cp->geom->attrchanged(cp, args->attr); 137223089Sgibbs } 138223089Sgibbs } 139223089Sgibbs g_free(args); 140223089Sgibbs} 141223089Sgibbs 142223089Sgibbsint 143223089Sgibbsg_attr_changed(struct g_provider *pp, const char *attr, int flag) 144223089Sgibbs{ 145223089Sgibbs struct g_attrchanged_args *args; 146223089Sgibbs int error; 147223089Sgibbs 148223089Sgibbs args = g_malloc(sizeof *args, flag); 149223089Sgibbs if (args == NULL) 150223089Sgibbs return (ENOMEM); 151223089Sgibbs args->pp = pp; 152223089Sgibbs args->attr = attr; 153223089Sgibbs error = g_post_event(g_attr_changed_event, args, flag, pp, NULL); 154223089Sgibbs if (error != 0) 155223089Sgibbs g_free(args); 156223089Sgibbs return (error); 157223089Sgibbs} 158223089Sgibbs 159137489Spjdvoid 16092108Sphkg_orphan_provider(struct g_provider *pp, int error) 16192108Sphk{ 16292108Sphk 163126798Sphk /* G_VALID_PROVIDER(pp) We likely lack topology lock */ 16492108Sphk g_trace(G_T_TOPOLOGY, "g_orphan_provider(%p(%s), %d)", 16592108Sphk pp, pp->name, error); 16692108Sphk KASSERT(error != 0, 16792108Sphk ("g_orphan_provider(%p(%s), 0) error must be non-zero\n", 16892108Sphk pp, pp->name)); 169123233Sphk 17092108Sphk pp->error = error; 171104053Sphk mtx_lock(&g_eventlock); 172123233Sphk KASSERT(!(pp->flags & G_PF_ORPHAN), 173123233Sphk ("g_orphan_provider(%p(%s)), already an orphan", pp, pp->name)); 174123233Sphk pp->flags |= G_PF_ORPHAN; 17592108Sphk TAILQ_INSERT_TAIL(&g_doorstep, pp, orphan); 176104053Sphk mtx_unlock(&g_eventlock); 17792108Sphk wakeup(&g_wait_event); 17892108Sphk} 17992108Sphk 18092108Sphk/* 18192108Sphk * This function is called once on each provider which the event handler 18292108Sphk * finds on its g_doorstep. 18392108Sphk */ 18492108Sphk 18592108Sphkstatic void 18693250Sphkg_orphan_register(struct g_provider *pp) 18792108Sphk{ 18892108Sphk struct g_consumer *cp, *cp2; 189123761Sphk int wf; 19092108Sphk 191126798Sphk g_topology_assert(); 192126798Sphk G_VALID_PROVIDER(pp); 19392108Sphk g_trace(G_T_TOPOLOGY, "g_orphan_register(%s)", pp->name); 19492108Sphk 195172354Spjd g_cancel_event(pp); 196172354Spjd 197123761Sphk wf = pp->flags & G_PF_WITHER; 198123761Sphk pp->flags &= ~G_PF_WITHER; 199123761Sphk 20092108Sphk /* 20192108Sphk * Tell all consumers the bad news. 202112029Sphk * Don't be surprised if they self-destruct. 20392108Sphk */ 204238886Smav LIST_FOREACH_SAFE(cp, &pp->consumers, consumers, cp2) { 20593776Sphk KASSERT(cp->geom->orphan != NULL, 20693776Sphk ("geom %s has no orphan, class %s", 20793776Sphk cp->geom->name, cp->geom->class->name)); 208266444Sae /* 209266444Sae * XXX: g_dev_orphan method does deferred destroying 210266444Sae * and it is possible, that other event could already 211266444Sae * call the orphan method. Check consumer's flags to 212266444Sae * do not schedule it twice. 213266444Sae */ 214266444Sae if (cp->flags & G_CF_ORPHAN) 215266444Sae continue; 216238886Smav cp->flags |= G_CF_ORPHAN; 21793776Sphk cp->geom->orphan(cp); 21892108Sphk } 219123761Sphk if (LIST_EMPTY(&pp->consumers) && wf) 220121029Sphk g_destroy_provider(pp); 221123761Sphk else 222123761Sphk pp->flags |= wf; 223112322Sphk#ifdef notyet 224112070Sphk cp = LIST_FIRST(&pp->consumers); 225112070Sphk if (cp != NULL) 226112070Sphk return; 227112070Sphk if (pp->geom->flags & G_GEOM_WITHER) 228112070Sphk g_destroy_provider(pp); 229112322Sphk#endif 23092108Sphk} 23192108Sphk 23292108Sphkstatic int 23393250Sphkone_event(void) 23492108Sphk{ 23592108Sphk struct g_event *ep; 23692108Sphk struct g_provider *pp; 23792108Sphk 238215687Sjh g_topology_assert(); 239215687Sjh mtx_lock(&g_eventlock); 240215687Sjh TAILQ_FOREACH(pp, &g_doorstep, orphan) { 241215687Sjh if (pp->nstart == pp->nend) 242215687Sjh break; 243215687Sjh } 244215687Sjh if (pp != NULL) { 245215687Sjh G_VALID_PROVIDER(pp); 246215687Sjh TAILQ_REMOVE(&g_doorstep, pp, orphan); 247104053Sphk mtx_unlock(&g_eventlock); 24893250Sphk g_orphan_register(pp); 249215687Sjh return (1); 25092108Sphk } 251215687Sjh 25292108Sphk ep = TAILQ_FIRST(&g_events); 25392108Sphk if (ep == NULL) { 254149787Sphk wakeup(&g_pending_events); 25592108Sphk return (0); 25692108Sphk } 257208927Smjacob if (ep->flag & EV_INPROGRESS) { 258208927Smjacob mtx_unlock(&g_eventlock); 259208927Smjacob return (1); 260208927Smjacob } 261208927Smjacob ep->flag |= EV_INPROGRESS; 262104056Sphk mtx_unlock(&g_eventlock); 263113934Sphk g_topology_assert(); 264113934Sphk ep->func(ep->arg, 0); 265113934Sphk g_topology_assert(); 266149787Sphk mtx_lock(&g_eventlock); 267149787Sphk TAILQ_REMOVE(&g_events, ep, events); 268208927Smjacob ep->flag &= ~EV_INPROGRESS; 269113940Sphk if (ep->flag & EV_WAKEUP) { 270113940Sphk ep->flag |= EV_DONE; 271214748Sjh mtx_unlock(&g_eventlock); 272113940Sphk wakeup(ep); 273113940Sphk } else { 274214748Sjh mtx_unlock(&g_eventlock); 275114490Sphk g_free(ep); 276113940Sphk } 27792108Sphk return (1); 27892108Sphk} 27992108Sphk 28092108Sphkvoid 28193250Sphkg_run_events() 28292108Sphk{ 28392108Sphk 284215687Sjh for (;;) { 285215687Sjh g_topology_lock(); 286215687Sjh while (one_event()) 287215687Sjh ; 288215687Sjh mtx_assert(&g_eventlock, MA_OWNED); 289248674Smav if (g_wither_work) { 290248674Smav g_wither_work = 0; 291215687Sjh mtx_unlock(&g_eventlock); 292248674Smav g_wither_washer(); 293215687Sjh g_topology_unlock(); 294215687Sjh } else { 295215687Sjh g_topology_unlock(); 296215687Sjh msleep(&g_wait_event, &g_eventlock, PRIBIO | PDROP, 297226985Smav "-", TAILQ_EMPTY(&g_doorstep) ? 0 : hz / 10); 298215687Sjh } 299131820Sphk } 300215687Sjh /* NOTREACHED */ 30192108Sphk} 30292108Sphk 30392108Sphkvoid 304112988Sphkg_cancel_event(void *ref) 305112518Sphk{ 306112518Sphk struct g_event *ep, *epn; 307114447Sphk struct g_provider *pp; 308112988Sphk u_int n; 309112518Sphk 310112518Sphk mtx_lock(&g_eventlock); 311114447Sphk TAILQ_FOREACH(pp, &g_doorstep, orphan) { 312114447Sphk if (pp != ref) 313114447Sphk continue; 314114447Sphk TAILQ_REMOVE(&g_doorstep, pp, orphan); 315114447Sphk break; 316114447Sphk } 317149787Sphk TAILQ_FOREACH_SAFE(ep, &g_events, events, epn) { 318208927Smjacob if (ep->flag & EV_INPROGRESS) 319208927Smjacob continue; 320112988Sphk for (n = 0; n < G_N_EVENTREFS; n++) { 321112988Sphk if (ep->ref[n] == NULL) 322112988Sphk break; 323149787Sphk if (ep->ref[n] != ref) 324149787Sphk continue; 325149787Sphk TAILQ_REMOVE(&g_events, ep, events); 326149787Sphk ep->func(ep->arg, EV_CANCEL); 327149787Sphk mtx_assert(&g_eventlock, MA_OWNED); 328149787Sphk if (ep->flag & EV_WAKEUP) { 329149787Sphk ep->flag |= (EV_DONE|EV_CANCELED); 330149787Sphk wakeup(ep); 331149787Sphk } else { 332149787Sphk g_free(ep); 333112988Sphk } 334149787Sphk break; 335112518Sphk } 336112518Sphk } 337149787Sphk if (TAILQ_EMPTY(&g_events)) 338149787Sphk wakeup(&g_pending_events); 339112518Sphk mtx_unlock(&g_eventlock); 340112518Sphk} 341112518Sphk 342113940Sphkstatic int 343125318Sphkg_post_event_x(g_event_t *func, void *arg, int flag, int wuflag, struct g_event **epp, va_list ap) 344104056Sphk{ 345104056Sphk struct g_event *ep; 346112988Sphk void *p; 347112988Sphk u_int n; 348104056Sphk 349125318Sphk g_trace(G_T_TOPOLOGY, "g_post_event_x(%p, %p, %d, %d)", 350146353Spjd func, arg, flag, wuflag); 351125318Sphk KASSERT(wuflag == 0 || wuflag == EV_WAKEUP, 352125318Sphk ("Wrong wuflag in g_post_event_x(0x%x)", wuflag)); 353113937Sphk ep = g_malloc(sizeof *ep, flag | M_ZERO); 354104056Sphk if (ep == NULL) 355104056Sphk return (ENOMEM); 356125318Sphk ep->flag = wuflag; 357112988Sphk for (n = 0; n < G_N_EVENTREFS; n++) { 358112988Sphk p = va_arg(ap, void *); 359112988Sphk if (p == NULL) 360112988Sphk break; 361112988Sphk g_trace(G_T_TOPOLOGY, " ref %p", p); 362122880Sphk ep->ref[n] = p; 363112988Sphk } 364112988Sphk KASSERT(p == NULL, ("Too many references to event")); 365104056Sphk ep->func = func; 366104056Sphk ep->arg = arg; 367104056Sphk mtx_lock(&g_eventlock); 368104056Sphk TAILQ_INSERT_TAIL(&g_events, ep, events); 369104056Sphk mtx_unlock(&g_eventlock); 370104056Sphk wakeup(&g_wait_event); 371113940Sphk if (epp != NULL) 372113940Sphk *epp = ep; 373136837Sphk curthread->td_pflags |= TDP_GEOM; 374104056Sphk return (0); 375104056Sphk} 376104056Sphk 377113940Sphkint 378113940Sphkg_post_event(g_event_t *func, void *arg, int flag, ...) 379113940Sphk{ 380113940Sphk va_list ap; 381115949Sphk int i; 382113940Sphk 383113940Sphk KASSERT(flag == M_WAITOK || flag == M_NOWAIT, 384113940Sphk ("Wrong flag to g_post_event")); 385115949Sphk va_start(ap, flag); 386125318Sphk i = g_post_event_x(func, arg, flag, 0, NULL, ap); 387115949Sphk va_end(ap); 388115949Sphk return (i); 389113940Sphk} 390113940Sphk 391131820Sphkvoid 392215687Sjhg_do_wither() 393215687Sjh{ 394113940Sphk 395215687Sjh mtx_lock(&g_eventlock); 396131820Sphk g_wither_work = 1; 397215687Sjh mtx_unlock(&g_eventlock); 398131820Sphk wakeup(&g_wait_event); 399131820Sphk} 400131820Sphk 401113940Sphk/* 402113940Sphk * XXX: It might actually be useful to call this function with topology held. 403113940Sphk * XXX: This would ensure that the event gets created before anything else 404113940Sphk * XXX: changes. At present all users have a handle on things in some other 405113940Sphk * XXX: way, so this remains an XXX for now. 406113940Sphk */ 407113940Sphk 408113940Sphkint 409113940Sphkg_waitfor_event(g_event_t *func, void *arg, int flag, ...) 410113940Sphk{ 411113940Sphk va_list ap; 412113940Sphk struct g_event *ep; 413113940Sphk int error; 414113940Sphk 415125657Spjd g_topology_assert_not(); 416113940Sphk KASSERT(flag == M_WAITOK || flag == M_NOWAIT, 417113940Sphk ("Wrong flag to g_post_event")); 418115949Sphk va_start(ap, flag); 419125318Sphk error = g_post_event_x(func, arg, flag, EV_WAKEUP, &ep, ap); 420115949Sphk va_end(ap); 421113940Sphk if (error) 422113940Sphk return (error); 423214748Sjh 424214748Sjh mtx_lock(&g_eventlock); 425214748Sjh while (!(ep->flag & EV_DONE)) 426214748Sjh msleep(ep, &g_eventlock, PRIBIO, "g_waitfor_event", hz); 427114450Sphk if (ep->flag & EV_CANCELED) 428114450Sphk error = EAGAIN; 429214748Sjh mtx_unlock(&g_eventlock); 430214748Sjh 431114490Sphk g_free(ep); 432114450Sphk return (error); 433113940Sphk} 434113940Sphk 43592108Sphkvoid 43692108Sphkg_event_init() 43792108Sphk{ 43892108Sphk 439104053Sphk mtx_init(&g_eventlock, "GEOM orphanage", NULL, MTX_DEF); 44092108Sphk} 441