diff options
author | phk <phk@FreeBSD.org> | 2002-09-27 20:38:36 +0000 |
---|---|---|
committer | phk <phk@FreeBSD.org> | 2002-09-27 20:38:36 +0000 |
commit | 83aec680cb55261466c7d21ac999144f9985d59e (patch) | |
tree | 7b1c2e6a84e3db3c03aa2837e686fbd1569016ee /sys | |
parent | a09a7e0aa751dc58e8f65d2417ed2cbb9cb3e686 (diff) | |
download | FreeBSD-src-83aec680cb55261466c7d21ac999144f9985d59e.zip FreeBSD-src-83aec680cb55261466c7d21ac999144f9985d59e.tar.gz |
Implement g_call_me() as a way for geom methods to schedule operations
to be performed in the event-thread.
To do this, we need to lock the eventlist with g_eventlock (nee g_doorlock),
since g_call_me() being called from the UP/DOWN paths will not be able to
aquire g_topology_lock.
This also means that for now these events are not referenced on any
particular consumer/provider/geom.
For UP/DOWN path use, this will not become a problem since the access()
function will make sure we drain any bio's before we dismantle.
Sponsored by: DARPA & NAI Labs.
Diffstat (limited to 'sys')
-rw-r--r-- | sys/geom/geom.h | 4 | ||||
-rw-r--r-- | sys/geom/geom_event.c | 30 | ||||
-rw-r--r-- | sys/geom/geom_int.h | 3 |
3 files changed, 36 insertions, 1 deletions
diff --git a/sys/geom/geom.h b/sys/geom/geom.h index df7ecb5..018c8f6 100644 --- a/sys/geom/geom.h +++ b/sys/geom/geom.h @@ -180,9 +180,11 @@ void g_trace(int level, char *, ...); /* geom_event.c */ +typedef void g_call_me_t(void *); +int g_call_me(g_call_me_t *func, void *arg); void g_orphan_provider(struct g_provider *pp, int error); -void g_waitidle(void); void g_silence(void); +void g_waitidle(void); /* geom_subr.c */ int g_access_abs(struct g_consumer *cp, int read, int write, int exclusive); diff --git a/sys/geom/geom_event.c b/sys/geom/geom_event.c index c6c7c9a..4188405 100644 --- a/sys/geom/geom_event.c +++ b/sys/geom/geom_event.c @@ -151,8 +151,13 @@ g_do_event(struct g_event *ep) ep, ep->event, ep->class, ep->geom, ep->provider, ep->consumer); g_topology_assert(); switch (ep->event) { + case EV_CALL_ME: + ep->func(ep->arg); + break; case EV_NEW_CLASS: mp2 = ep->class; + if (g_shutdown) + break; if (mp2->taste == NULL) break; if (g_shutdown) @@ -226,12 +231,15 @@ one_event(void) break; g_orphan_register(pp); } + mtx_lock(&g_eventlock); ep = TAILQ_FIRST(&g_events); if (ep == NULL) { + mtx_unlock(&g_eventlock); g_topology_unlock(); return (0); } TAILQ_REMOVE(&g_events, ep, events); + mtx_unlock(&g_eventlock); if (ep->class != NULL) ep->class->event = NULL; if (ep->geom != NULL) @@ -288,9 +296,31 @@ g_post_event(enum g_events ev, struct g_class *mp, struct g_geom *gp, struct g_p KASSERT(cp->event == NULL, ("Double event on consumer")); cp->event = ep; } + mtx_lock(&g_eventlock); g_pending_events++; TAILQ_INSERT_TAIL(&g_events, ep, events); + mtx_unlock(&g_eventlock); + wakeup(&g_wait_event); +} + +int +g_call_me(g_call_me_t *func, void *arg) +{ + struct g_event *ep; + + g_trace(G_T_TOPOLOGY, "g_call_me(%p, %p", func, arg); + ep = g_malloc(sizeof *ep, M_NOWAIT | M_ZERO); + if (ep == NULL) + return (ENOMEM); + ep->event = EV_CALL_ME; + ep->func = func; + ep->arg = arg; + mtx_lock(&g_eventlock); + g_pending_events++; + TAILQ_INSERT_TAIL(&g_events, ep, events); + mtx_unlock(&g_eventlock); wakeup(&g_wait_event); + return (0); } #ifdef _KERNEL diff --git a/sys/geom/geom_int.h b/sys/geom/geom_int.h index b7a5ad6..33fd675 100644 --- a/sys/geom/geom_int.h +++ b/sys/geom/geom_int.h @@ -51,6 +51,7 @@ enum g_events { EV_NEW_CLASS, /* class */ EV_NEW_PROVIDER, /* provider */ EV_SPOILED, /* provider, consumer */ + EV_CALL_ME, /* func, arg */ EV_LAST }; @@ -61,6 +62,8 @@ struct g_event { struct g_geom *geom; struct g_provider *provider; struct g_consumer *consumer; + void *arg; + g_call_me_t *func; }; /* geom_dump.c */ |