1dd84a43cSPoul-Henning Kamp /*- 23728855aSPedro F. Giffuni * SPDX-License-Identifier: BSD-3-Clause 33728855aSPedro F. Giffuni * 4dd84a43cSPoul-Henning Kamp * Copyright (c) 2002 Poul-Henning Kamp 5dd84a43cSPoul-Henning Kamp * Copyright (c) 2002 Networks Associates Technology, Inc. 6dd84a43cSPoul-Henning Kamp * All rights reserved. 7dd84a43cSPoul-Henning Kamp * 8dd84a43cSPoul-Henning Kamp * This software was developed for the FreeBSD Project by Poul-Henning Kamp 9dd84a43cSPoul-Henning Kamp * and NAI Labs, the Security Research Division of Network Associates, Inc. 10dd84a43cSPoul-Henning Kamp * under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the 11dd84a43cSPoul-Henning Kamp * DARPA CHATS research program. 12dd84a43cSPoul-Henning Kamp * 13dd84a43cSPoul-Henning Kamp * Redistribution and use in source and binary forms, with or without 14dd84a43cSPoul-Henning Kamp * modification, are permitted provided that the following conditions 15dd84a43cSPoul-Henning Kamp * are met: 16dd84a43cSPoul-Henning Kamp * 1. Redistributions of source code must retain the above copyright 17dd84a43cSPoul-Henning Kamp * notice, this list of conditions and the following disclaimer. 18dd84a43cSPoul-Henning Kamp * 2. Redistributions in binary form must reproduce the above copyright 19dd84a43cSPoul-Henning Kamp * notice, this list of conditions and the following disclaimer in the 20dd84a43cSPoul-Henning Kamp * documentation and/or other materials provided with the distribution. 21dd84a43cSPoul-Henning Kamp * 3. The names of the authors may not be used to endorse or promote 22dd84a43cSPoul-Henning Kamp * products derived from this software without specific prior written 23dd84a43cSPoul-Henning Kamp * permission. 24dd84a43cSPoul-Henning Kamp * 25dd84a43cSPoul-Henning Kamp * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 26dd84a43cSPoul-Henning Kamp * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27dd84a43cSPoul-Henning Kamp * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 28dd84a43cSPoul-Henning Kamp * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 29dd84a43cSPoul-Henning Kamp * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 30dd84a43cSPoul-Henning Kamp * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 31dd84a43cSPoul-Henning Kamp * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 32dd84a43cSPoul-Henning Kamp * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 33dd84a43cSPoul-Henning Kamp * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 34dd84a43cSPoul-Henning Kamp * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 35dd84a43cSPoul-Henning Kamp * SUCH DAMAGE. 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 4350b1faefSDavid E. O'Brien #include <sys/cdefs.h> 4450b1faefSDavid E. O'Brien __FBSDID("$FreeBSD$"); 4550b1faefSDavid E. O'Brien 46dd84a43cSPoul-Henning Kamp #include <sys/param.h> 47dd84a43cSPoul-Henning Kamp #include <sys/malloc.h> 48dd84a43cSPoul-Henning Kamp #include <sys/systm.h> 49dd84a43cSPoul-Henning Kamp #include <sys/kernel.h> 50dd84a43cSPoul-Henning Kamp #include <sys/lock.h> 51dd84a43cSPoul-Henning Kamp #include <sys/mutex.h> 529197ce2eSPoul-Henning Kamp #include <sys/proc.h> 53dd84a43cSPoul-Henning Kamp #include <sys/errno.h> 54dd84a43cSPoul-Henning Kamp #include <sys/time.h> 55dd84a43cSPoul-Henning Kamp #include <geom/geom.h> 56b1876192SPoul-Henning Kamp #include <geom/geom_int.h> 57dd84a43cSPoul-Henning Kamp 589197ce2eSPoul-Henning Kamp #include <machine/stdarg.h> 599197ce2eSPoul-Henning Kamp 60a974614bSPoul-Henning Kamp TAILQ_HEAD(event_tailq_head, g_event); 61a974614bSPoul-Henning Kamp 62dd84a43cSPoul-Henning Kamp static struct event_tailq_head g_events = TAILQ_HEAD_INITIALIZER(g_events); 63abb50a48SPoul-Henning Kamp static u_int g_pending_events; 64dd84a43cSPoul-Henning Kamp static TAILQ_HEAD(,g_provider) g_doorstep = TAILQ_HEAD_INITIALIZER(g_doorstep); 65903e43feSPoul-Henning Kamp static struct mtx g_eventlock; 661b464bd8SPoul-Henning Kamp static int g_wither_work; 67dd84a43cSPoul-Henning Kamp 68a974614bSPoul-Henning Kamp #define G_N_EVENTREFS 20 69a974614bSPoul-Henning Kamp 70a974614bSPoul-Henning Kamp struct g_event { 71a974614bSPoul-Henning Kamp TAILQ_ENTRY(g_event) events; 72a974614bSPoul-Henning Kamp g_event_t *func; 730a9c130cSPoul-Henning Kamp void *arg; 740a9c130cSPoul-Henning Kamp int flag; 75a974614bSPoul-Henning Kamp void *ref[G_N_EVENTREFS]; 76a974614bSPoul-Henning Kamp }; 77a974614bSPoul-Henning Kamp 780a9c130cSPoul-Henning Kamp #define EV_DONE 0x80000 790a9c130cSPoul-Henning Kamp #define EV_WAKEUP 0x40000 80c8589ad1SPoul-Henning Kamp #define EV_CANCELED 0x20000 8159ccfe81SMatt Jacob #define EV_INPROGRESS 0x10000 820a9c130cSPoul-Henning Kamp 83dd84a43cSPoul-Henning Kamp void 84503abe45SPoul-Henning Kamp g_waitidle(void) 85dd84a43cSPoul-Henning Kamp { 86dd84a43cSPoul-Henning Kamp 879197ce2eSPoul-Henning Kamp g_topology_assert_not(); 889197ce2eSPoul-Henning Kamp 89e4da09c0SPoul-Henning Kamp mtx_lock(&g_eventlock); 908b8a7c43SColin Percival TSWAIT("GEOM events"); 91e4da09c0SPoul-Henning Kamp while (!TAILQ_EMPTY(&g_events)) 92e4da09c0SPoul-Henning Kamp msleep(&g_pending_events, &g_eventlock, PPAUSE, 93f4bf48c2SAlexander Motin "g_waitidle", 0); 948b8a7c43SColin Percival TSUNWAIT("GEOM events"); 95e4da09c0SPoul-Henning Kamp mtx_unlock(&g_eventlock); 969197ce2eSPoul-Henning Kamp curthread->td_pflags &= ~TDP_GEOM; 97dd84a43cSPoul-Henning Kamp } 98dd84a43cSPoul-Henning Kamp 99c6d31b83SKonstantin Belousov static void 100c6d31b83SKonstantin Belousov ast_geom(struct thread *td __unused, int tda __unused) 101c6d31b83SKonstantin Belousov { 102c6d31b83SKonstantin Belousov /* 103c6d31b83SKonstantin Belousov * If this thread tickled GEOM, we need to wait for the giggling to 104c6d31b83SKonstantin Belousov * stop before we return to userland. 105c6d31b83SKonstantin Belousov */ 106c6d31b83SKonstantin Belousov g_waitidle(); 107c6d31b83SKonstantin Belousov } 108c6d31b83SKonstantin Belousov 109c6d31b83SKonstantin Belousov static void 110c6d31b83SKonstantin Belousov geom_event_init(void *arg __unused) 111c6d31b83SKonstantin Belousov { 112c6d31b83SKonstantin Belousov ast_register(TDA_GEOM, ASTR_ASTF_REQUIRED | ASTR_TDP | ASTR_KCLEAR, 113c6d31b83SKonstantin Belousov TDP_GEOM, ast_geom); 114c6d31b83SKonstantin Belousov } 115c6d31b83SKonstantin Belousov SYSINIT(geom_event, SI_SUB_INTRINSIC, SI_ORDER_ANY, geom_event_init, NULL); 116c6d31b83SKonstantin Belousov 117416494d7SJustin T. Gibbs struct g_attrchanged_args { 118416494d7SJustin T. Gibbs struct g_provider *pp; 119416494d7SJustin T. Gibbs const char *attr; 120416494d7SJustin T. Gibbs }; 121416494d7SJustin T. Gibbs 122416494d7SJustin T. Gibbs static void 123416494d7SJustin T. Gibbs g_attr_changed_event(void *arg, int flag) 124416494d7SJustin T. Gibbs { 125416494d7SJustin T. Gibbs struct g_attrchanged_args *args; 126416494d7SJustin T. Gibbs struct g_provider *pp; 127416494d7SJustin T. Gibbs struct g_consumer *cp; 128416494d7SJustin T. Gibbs struct g_consumer *next_cp; 129416494d7SJustin T. Gibbs 130416494d7SJustin T. Gibbs args = arg; 131416494d7SJustin T. Gibbs pp = args->pp; 132416494d7SJustin T. Gibbs 133416494d7SJustin T. Gibbs g_topology_assert(); 134416494d7SJustin T. Gibbs if (flag != EV_CANCEL && g_shutdown == 0) { 135416494d7SJustin T. Gibbs /* 136416494d7SJustin T. Gibbs * Tell all consumers of the change. 137416494d7SJustin T. Gibbs */ 138416494d7SJustin T. Gibbs LIST_FOREACH_SAFE(cp, &pp->consumers, consumers, next_cp) { 139416494d7SJustin T. Gibbs if (cp->geom->attrchanged != NULL) 140416494d7SJustin T. Gibbs cp->geom->attrchanged(cp, args->attr); 141416494d7SJustin T. Gibbs } 142416494d7SJustin T. Gibbs } 143416494d7SJustin T. Gibbs g_free(args); 144416494d7SJustin T. Gibbs } 145416494d7SJustin T. Gibbs 146416494d7SJustin T. Gibbs int 147416494d7SJustin T. Gibbs g_attr_changed(struct g_provider *pp, const char *attr, int flag) 148416494d7SJustin T. Gibbs { 149416494d7SJustin T. Gibbs struct g_attrchanged_args *args; 150416494d7SJustin T. Gibbs int error; 151416494d7SJustin T. Gibbs 152416494d7SJustin T. Gibbs args = g_malloc(sizeof *args, flag); 153416494d7SJustin T. Gibbs if (args == NULL) 154416494d7SJustin T. Gibbs return (ENOMEM); 155416494d7SJustin T. Gibbs args->pp = pp; 156416494d7SJustin T. Gibbs args->attr = attr; 157416494d7SJustin T. Gibbs error = g_post_event(g_attr_changed_event, args, flag, pp, NULL); 158416494d7SJustin T. Gibbs if (error != 0) 159416494d7SJustin T. Gibbs g_free(args); 160416494d7SJustin T. Gibbs return (error); 161416494d7SJustin T. Gibbs } 162416494d7SJustin T. Gibbs 163b8005b9bSPawel Jakub Dawidek void 164dd84a43cSPoul-Henning Kamp g_orphan_provider(struct g_provider *pp, int error) 165dd84a43cSPoul-Henning Kamp { 166dd84a43cSPoul-Henning Kamp 1673d1d5bc3SPoul-Henning Kamp /* G_VALID_PROVIDER(pp) We likely lack topology lock */ 168dd84a43cSPoul-Henning Kamp g_trace(G_T_TOPOLOGY, "g_orphan_provider(%p(%s), %d)", 169dd84a43cSPoul-Henning Kamp pp, pp->name, error); 170dd84a43cSPoul-Henning Kamp KASSERT(error != 0, 171dd84a43cSPoul-Henning Kamp ("g_orphan_provider(%p(%s), 0) error must be non-zero\n", 172dd84a43cSPoul-Henning Kamp pp, pp->name)); 173d0265773SPoul-Henning Kamp 174dd84a43cSPoul-Henning Kamp pp->error = error; 175903e43feSPoul-Henning Kamp mtx_lock(&g_eventlock); 176d0265773SPoul-Henning Kamp KASSERT(!(pp->flags & G_PF_ORPHAN), 177d0265773SPoul-Henning Kamp ("g_orphan_provider(%p(%s)), already an orphan", pp, pp->name)); 178d0265773SPoul-Henning Kamp pp->flags |= G_PF_ORPHAN; 179dd84a43cSPoul-Henning Kamp TAILQ_INSERT_TAIL(&g_doorstep, pp, orphan); 180903e43feSPoul-Henning Kamp mtx_unlock(&g_eventlock); 181dd84a43cSPoul-Henning Kamp wakeup(&g_wait_event); 182dd84a43cSPoul-Henning Kamp } 183dd84a43cSPoul-Henning Kamp 184dd84a43cSPoul-Henning Kamp /* 185dd84a43cSPoul-Henning Kamp * This function is called once on each provider which the event handler 186dd84a43cSPoul-Henning Kamp * finds on its g_doorstep. 187dd84a43cSPoul-Henning Kamp */ 188dd84a43cSPoul-Henning Kamp 189dd84a43cSPoul-Henning Kamp static void 190b1876192SPoul-Henning Kamp g_orphan_register(struct g_provider *pp) 191dd84a43cSPoul-Henning Kamp { 192dd84a43cSPoul-Henning Kamp struct g_consumer *cp, *cp2; 1938592d7a7SPoul-Henning Kamp int wf; 194dd84a43cSPoul-Henning Kamp 195dd84a43cSPoul-Henning Kamp g_topology_assert(); 1963d1d5bc3SPoul-Henning Kamp G_VALID_PROVIDER(pp); 1973d1d5bc3SPoul-Henning Kamp g_trace(G_T_TOPOLOGY, "g_orphan_register(%s)", pp->name); 198dd84a43cSPoul-Henning Kamp 1993ea5d7ecSPawel Jakub Dawidek g_cancel_event(pp); 2003ea5d7ecSPawel Jakub Dawidek 2018592d7a7SPoul-Henning Kamp wf = pp->flags & G_PF_WITHER; 2028592d7a7SPoul-Henning Kamp pp->flags &= ~G_PF_WITHER; 2038592d7a7SPoul-Henning Kamp 204dd84a43cSPoul-Henning Kamp /* 205dd84a43cSPoul-Henning Kamp * Tell all consumers the bad news. 206f48b8819SPoul-Henning Kamp * Don't be surprised if they self-destruct. 207dd84a43cSPoul-Henning Kamp */ 2083631c638SAlexander Motin LIST_FOREACH_SAFE(cp, &pp->consumers, consumers, cp2) { 20907d77fc6SPoul-Henning Kamp KASSERT(cp->geom->orphan != NULL, 21007d77fc6SPoul-Henning Kamp ("geom %s has no orphan, class %s", 21107d77fc6SPoul-Henning Kamp cp->geom->name, cp->geom->class->name)); 212362073c0SAndrey V. Elsukov /* 213362073c0SAndrey V. Elsukov * XXX: g_dev_orphan method does deferred destroying 214362073c0SAndrey V. Elsukov * and it is possible, that other event could already 215362073c0SAndrey V. Elsukov * call the orphan method. Check consumer's flags to 216362073c0SAndrey V. Elsukov * do not schedule it twice. 217362073c0SAndrey V. Elsukov */ 218362073c0SAndrey V. Elsukov if (cp->flags & G_CF_ORPHAN) 219362073c0SAndrey V. Elsukov continue; 2203631c638SAlexander Motin cp->flags |= G_CF_ORPHAN; 22107d77fc6SPoul-Henning Kamp cp->geom->orphan(cp); 222dd84a43cSPoul-Henning Kamp } 2238592d7a7SPoul-Henning Kamp if (LIST_EMPTY(&pp->consumers) && wf) 224b144e6ffSPoul-Henning Kamp g_destroy_provider(pp); 2258592d7a7SPoul-Henning Kamp else 2268592d7a7SPoul-Henning Kamp pp->flags |= wf; 22720d2026bSPoul-Henning Kamp #ifdef notyet 228e5829909SPoul-Henning Kamp cp = LIST_FIRST(&pp->consumers); 229e5829909SPoul-Henning Kamp if (cp != NULL) 230e5829909SPoul-Henning Kamp return; 231e5829909SPoul-Henning Kamp if (pp->geom->flags & G_GEOM_WITHER) 232e5829909SPoul-Henning Kamp g_destroy_provider(pp); 23320d2026bSPoul-Henning Kamp #endif 234dd84a43cSPoul-Henning Kamp } 235dd84a43cSPoul-Henning Kamp 236dd84a43cSPoul-Henning Kamp static int 237b1876192SPoul-Henning Kamp one_event(void) 238dd84a43cSPoul-Henning Kamp { 239dd84a43cSPoul-Henning Kamp struct g_event *ep; 240dd84a43cSPoul-Henning Kamp struct g_provider *pp; 241dd84a43cSPoul-Henning Kamp 242f7842e00SJaakko Heinonen g_topology_assert(); 243903e43feSPoul-Henning Kamp mtx_lock(&g_eventlock); 2449794a803SAlexander Motin pp = TAILQ_FIRST(&g_doorstep); 2453d1d5bc3SPoul-Henning Kamp if (pp != NULL) { 2463d1d5bc3SPoul-Henning Kamp G_VALID_PROVIDER(pp); 247dd84a43cSPoul-Henning Kamp TAILQ_REMOVE(&g_doorstep, pp, orphan); 248903e43feSPoul-Henning Kamp mtx_unlock(&g_eventlock); 249b1876192SPoul-Henning Kamp g_orphan_register(pp); 250f7842e00SJaakko Heinonen return (1); 251dd84a43cSPoul-Henning Kamp } 252f7842e00SJaakko Heinonen 253dd84a43cSPoul-Henning Kamp ep = TAILQ_FIRST(&g_events); 254dd84a43cSPoul-Henning Kamp if (ep == NULL) { 255e4da09c0SPoul-Henning Kamp wakeup(&g_pending_events); 256dd84a43cSPoul-Henning Kamp return (0); 257dd84a43cSPoul-Henning Kamp } 25859ccfe81SMatt Jacob ep->flag |= EV_INPROGRESS; 259346cd5feSPoul-Henning Kamp mtx_unlock(&g_eventlock); 260d98777f8SPoul-Henning Kamp g_topology_assert(); 261d98777f8SPoul-Henning Kamp ep->func(ep->arg, 0); 262d98777f8SPoul-Henning Kamp g_topology_assert(); 263e4da09c0SPoul-Henning Kamp mtx_lock(&g_eventlock); 2648b8a7c43SColin Percival TSRELEASE("GEOM events"); 265e4da09c0SPoul-Henning Kamp TAILQ_REMOVE(&g_events, ep, events); 26659ccfe81SMatt Jacob ep->flag &= ~EV_INPROGRESS; 2670a9c130cSPoul-Henning Kamp if (ep->flag & EV_WAKEUP) { 2680a9c130cSPoul-Henning Kamp ep->flag |= EV_DONE; 2690a9c130cSPoul-Henning Kamp wakeup(ep); 270f4bf48c2SAlexander Motin mtx_unlock(&g_eventlock); 2710a9c130cSPoul-Henning Kamp } else { 2729d142a6eSJaakko Heinonen mtx_unlock(&g_eventlock); 2739dfffbc9SPoul-Henning Kamp g_free(ep); 2740a9c130cSPoul-Henning Kamp } 275dd84a43cSPoul-Henning Kamp return (1); 276dd84a43cSPoul-Henning Kamp } 277dd84a43cSPoul-Henning Kamp 278dd84a43cSPoul-Henning Kamp void 279ac315343SDimitry Andric g_run_events(void) 280dd84a43cSPoul-Henning Kamp { 281dd84a43cSPoul-Henning Kamp 282f7842e00SJaakko Heinonen for (;;) { 283f7842e00SJaakko Heinonen g_topology_lock(); 284b1876192SPoul-Henning Kamp while (one_event()) 285dd84a43cSPoul-Henning Kamp ; 286f7842e00SJaakko Heinonen mtx_assert(&g_eventlock, MA_OWNED); 28750199fa0SAlexander Motin if (g_wither_work) { 28850199fa0SAlexander Motin g_wither_work = 0; 289f7842e00SJaakko Heinonen mtx_unlock(&g_eventlock); 29050199fa0SAlexander Motin g_wither_washer(); 2911b464bd8SPoul-Henning Kamp g_topology_unlock(); 292f7842e00SJaakko Heinonen } else { 293f7842e00SJaakko Heinonen g_topology_unlock(); 294f7842e00SJaakko Heinonen msleep(&g_wait_event, &g_eventlock, PRIBIO | PDROP, 2959794a803SAlexander Motin "-", 0); 296f7842e00SJaakko Heinonen } 297f7842e00SJaakko Heinonen } 298f7842e00SJaakko Heinonen /* NOTREACHED */ 299dd84a43cSPoul-Henning Kamp } 300dd84a43cSPoul-Henning Kamp 301dd84a43cSPoul-Henning Kamp void 302afcbcfaeSPoul-Henning Kamp g_cancel_event(void *ref) 303dddc28bfSPoul-Henning Kamp { 304dddc28bfSPoul-Henning Kamp struct g_event *ep, *epn; 3052ab31b05SPoul-Henning Kamp struct g_provider *pp; 306afcbcfaeSPoul-Henning Kamp u_int n; 307dddc28bfSPoul-Henning Kamp 308dddc28bfSPoul-Henning Kamp mtx_lock(&g_eventlock); 3092ab31b05SPoul-Henning Kamp TAILQ_FOREACH(pp, &g_doorstep, orphan) { 3102ab31b05SPoul-Henning Kamp if (pp != ref) 3112ab31b05SPoul-Henning Kamp continue; 3122ab31b05SPoul-Henning Kamp TAILQ_REMOVE(&g_doorstep, pp, orphan); 3132ab31b05SPoul-Henning Kamp break; 3142ab31b05SPoul-Henning Kamp } 315e4da09c0SPoul-Henning Kamp TAILQ_FOREACH_SAFE(ep, &g_events, events, epn) { 31659ccfe81SMatt Jacob if (ep->flag & EV_INPROGRESS) 31759ccfe81SMatt Jacob continue; 318afcbcfaeSPoul-Henning Kamp for (n = 0; n < G_N_EVENTREFS; n++) { 319afcbcfaeSPoul-Henning Kamp if (ep->ref[n] == NULL) 320afcbcfaeSPoul-Henning Kamp break; 321e4da09c0SPoul-Henning Kamp if (ep->ref[n] != ref) 322e4da09c0SPoul-Henning Kamp continue; 3238b8a7c43SColin Percival TSRELEASE("GEOM events"); 324dddc28bfSPoul-Henning Kamp TAILQ_REMOVE(&g_events, ep, events); 325316aed03SPoul-Henning Kamp ep->func(ep->arg, EV_CANCEL); 326e4da09c0SPoul-Henning Kamp mtx_assert(&g_eventlock, MA_OWNED); 3270a9c130cSPoul-Henning Kamp if (ep->flag & EV_WAKEUP) { 328e4da09c0SPoul-Henning Kamp ep->flag |= (EV_DONE|EV_CANCELED); 3290a9c130cSPoul-Henning Kamp wakeup(ep); 3300a9c130cSPoul-Henning Kamp } else { 3319dfffbc9SPoul-Henning Kamp g_free(ep); 3320a9c130cSPoul-Henning Kamp } 333afcbcfaeSPoul-Henning Kamp break; 334dddc28bfSPoul-Henning Kamp } 335afcbcfaeSPoul-Henning Kamp } 336e4da09c0SPoul-Henning Kamp if (TAILQ_EMPTY(&g_events)) 337e4da09c0SPoul-Henning Kamp wakeup(&g_pending_events); 338dddc28bfSPoul-Henning Kamp mtx_unlock(&g_eventlock); 339dddc28bfSPoul-Henning Kamp } 340dddc28bfSPoul-Henning Kamp 341380710a5SWarner Losh struct g_event * 342380710a5SWarner Losh g_alloc_event(int flag) 343346cd5feSPoul-Henning Kamp { 344380710a5SWarner Losh KASSERT(flag == M_WAITOK || flag == M_NOWAIT, 345380710a5SWarner Losh ("Wrong flag to g_alloc_event")); 346380710a5SWarner Losh 347380710a5SWarner Losh return (g_malloc(sizeof(struct g_event), flag | M_ZERO)); 348380710a5SWarner Losh } 349380710a5SWarner Losh 350380710a5SWarner Losh static void 351380710a5SWarner Losh g_post_event_ep_va(g_event_t *func, void *arg, int wuflag, 352380710a5SWarner Losh struct g_event *ep, va_list ap) 353380710a5SWarner Losh { 354afcbcfaeSPoul-Henning Kamp void *p; 355afcbcfaeSPoul-Henning Kamp u_int n; 356346cd5feSPoul-Henning Kamp 357793ffa8eSPoul-Henning Kamp ep->flag = wuflag; 358afcbcfaeSPoul-Henning Kamp for (n = 0; n < G_N_EVENTREFS; n++) { 359afcbcfaeSPoul-Henning Kamp p = va_arg(ap, void *); 360afcbcfaeSPoul-Henning Kamp if (p == NULL) 361afcbcfaeSPoul-Henning Kamp break; 362afcbcfaeSPoul-Henning Kamp g_trace(G_T_TOPOLOGY, " ref %p", p); 363e0d617c1SPoul-Henning Kamp ep->ref[n] = p; 364afcbcfaeSPoul-Henning Kamp } 365afcbcfaeSPoul-Henning Kamp KASSERT(p == NULL, ("Too many references to event")); 366346cd5feSPoul-Henning Kamp ep->func = func; 367346cd5feSPoul-Henning Kamp ep->arg = arg; 368346cd5feSPoul-Henning Kamp mtx_lock(&g_eventlock); 3698b8a7c43SColin Percival TSHOLD("GEOM events"); 370346cd5feSPoul-Henning Kamp TAILQ_INSERT_TAIL(&g_events, ep, events); 371346cd5feSPoul-Henning Kamp mtx_unlock(&g_eventlock); 372346cd5feSPoul-Henning Kamp wakeup(&g_wait_event); 3739197ce2eSPoul-Henning Kamp curthread->td_pflags |= TDP_GEOM; 374c6d31b83SKonstantin Belousov ast_sched(curthread, TDA_GEOM); 375380710a5SWarner Losh } 376380710a5SWarner Losh 377380710a5SWarner Losh void 378380710a5SWarner Losh g_post_event_ep(g_event_t *func, void *arg, struct g_event *ep, ...) 379380710a5SWarner Losh { 380380710a5SWarner Losh va_list ap; 381380710a5SWarner Losh 382380710a5SWarner Losh va_start(ap, ep); 383380710a5SWarner Losh g_post_event_ep_va(func, arg, 0, ep, ap); 384380710a5SWarner Losh va_end(ap); 385380710a5SWarner Losh } 386380710a5SWarner Losh 387380710a5SWarner Losh 388380710a5SWarner Losh static int 389380710a5SWarner Losh g_post_event_x(g_event_t *func, void *arg, int flag, int wuflag, struct g_event **epp, va_list ap) 390380710a5SWarner Losh { 391380710a5SWarner Losh struct g_event *ep; 392380710a5SWarner Losh 393380710a5SWarner Losh g_trace(G_T_TOPOLOGY, "g_post_event_x(%p, %p, %d, %d)", 394380710a5SWarner Losh func, arg, flag, wuflag); 395380710a5SWarner Losh KASSERT(wuflag == 0 || wuflag == EV_WAKEUP, 396380710a5SWarner Losh ("Wrong wuflag in g_post_event_x(0x%x)", wuflag)); 397380710a5SWarner Losh ep = g_alloc_event(flag); 398380710a5SWarner Losh if (ep == NULL) 399380710a5SWarner Losh return (ENOMEM); 400380710a5SWarner Losh if (epp != NULL) 401380710a5SWarner Losh *epp = ep; 402380710a5SWarner Losh g_post_event_ep_va(func, arg, wuflag, ep, ap); 4030a9c130cSPoul-Henning Kamp return (0); 4040a9c130cSPoul-Henning Kamp } 4050a9c130cSPoul-Henning Kamp 4060a9c130cSPoul-Henning Kamp int 4070a9c130cSPoul-Henning Kamp g_post_event(g_event_t *func, void *arg, int flag, ...) 4080a9c130cSPoul-Henning Kamp { 4090a9c130cSPoul-Henning Kamp va_list ap; 410a1a9b445SPoul-Henning Kamp int i; 4110a9c130cSPoul-Henning Kamp 4120a9c130cSPoul-Henning Kamp KASSERT(flag == M_WAITOK || flag == M_NOWAIT, 4130a9c130cSPoul-Henning Kamp ("Wrong flag to g_post_event")); 414a1a9b445SPoul-Henning Kamp va_start(ap, flag); 415793ffa8eSPoul-Henning Kamp i = g_post_event_x(func, arg, flag, 0, NULL, ap); 416a1a9b445SPoul-Henning Kamp va_end(ap); 417a1a9b445SPoul-Henning Kamp return (i); 4180a9c130cSPoul-Henning Kamp } 4190a9c130cSPoul-Henning Kamp 4201b464bd8SPoul-Henning Kamp void 421ac315343SDimitry Andric g_do_wither(void) 422f7842e00SJaakko Heinonen { 4231b464bd8SPoul-Henning Kamp 424f7842e00SJaakko Heinonen mtx_lock(&g_eventlock); 4251b464bd8SPoul-Henning Kamp g_wither_work = 1; 426f7842e00SJaakko Heinonen mtx_unlock(&g_eventlock); 4271b464bd8SPoul-Henning Kamp wakeup(&g_wait_event); 4281b464bd8SPoul-Henning Kamp } 4290a9c130cSPoul-Henning Kamp 4300a9c130cSPoul-Henning Kamp /* 4310a9c130cSPoul-Henning Kamp * XXX: It might actually be useful to call this function with topology held. 4320a9c130cSPoul-Henning Kamp * XXX: This would ensure that the event gets created before anything else 4330a9c130cSPoul-Henning Kamp * XXX: changes. At present all users have a handle on things in some other 4340a9c130cSPoul-Henning Kamp * XXX: way, so this remains an XXX for now. 4350a9c130cSPoul-Henning Kamp */ 4360a9c130cSPoul-Henning Kamp 4370a9c130cSPoul-Henning Kamp int 4380a9c130cSPoul-Henning Kamp g_waitfor_event(g_event_t *func, void *arg, int flag, ...) 4390a9c130cSPoul-Henning Kamp { 4400a9c130cSPoul-Henning Kamp va_list ap; 4410a9c130cSPoul-Henning Kamp struct g_event *ep; 4420a9c130cSPoul-Henning Kamp int error; 4430a9c130cSPoul-Henning Kamp 44418e88d82SPawel Jakub Dawidek g_topology_assert_not(); 4450a9c130cSPoul-Henning Kamp KASSERT(flag == M_WAITOK || flag == M_NOWAIT, 4460a9c130cSPoul-Henning Kamp ("Wrong flag to g_post_event")); 447a1a9b445SPoul-Henning Kamp va_start(ap, flag); 448793ffa8eSPoul-Henning Kamp error = g_post_event_x(func, arg, flag, EV_WAKEUP, &ep, ap); 449a1a9b445SPoul-Henning Kamp va_end(ap); 4500a9c130cSPoul-Henning Kamp if (error) 4510a9c130cSPoul-Henning Kamp return (error); 4529d142a6eSJaakko Heinonen 4539d142a6eSJaakko Heinonen mtx_lock(&g_eventlock); 4549d142a6eSJaakko Heinonen while (!(ep->flag & EV_DONE)) 455f4bf48c2SAlexander Motin msleep(ep, &g_eventlock, PRIBIO, "g_waitfor_event", 0); 456c8589ad1SPoul-Henning Kamp if (ep->flag & EV_CANCELED) 457c8589ad1SPoul-Henning Kamp error = EAGAIN; 4589d142a6eSJaakko Heinonen mtx_unlock(&g_eventlock); 4599d142a6eSJaakko Heinonen 4609dfffbc9SPoul-Henning Kamp g_free(ep); 461c8589ad1SPoul-Henning Kamp return (error); 462346cd5feSPoul-Henning Kamp } 463346cd5feSPoul-Henning Kamp 464dd84a43cSPoul-Henning Kamp void 465ac315343SDimitry Andric g_event_init(void) 466dd84a43cSPoul-Henning Kamp { 467dd84a43cSPoul-Henning Kamp 468903e43feSPoul-Henning Kamp mtx_init(&g_eventlock, "GEOM orphanage", NULL, MTX_DEF); 469dd84a43cSPoul-Henning Kamp } 470