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.
This commit is contained in:
parent
e615b0fd93
commit
346cd5fe2d
@ -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);
|
||||
|
@ -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,11 +296,33 @@ 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
|
||||
static void
|
||||
geom_shutdown(void *foo __unused)
|
||||
|
@ -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 */
|
||||
|
Loading…
Reference in New Issue
Block a user