diff options
author | Poul-Henning Kamp <phk@FreeBSD.org> | 2004-07-08 16:17:14 +0000 |
---|---|---|
committer | Poul-Henning Kamp <phk@FreeBSD.org> | 2004-07-08 16:17:14 +0000 |
commit | 1b464bd889e4425f0c2dada5c6bae51c80783f4e (patch) | |
tree | a2bc0c14b24fa444e03a2cf0a77ec7bc53390e33 | |
parent | d5103548b4611551a1586204558be772623268b4 (diff) |
Notes
-rw-r--r-- | sys/geom/geom_event.c | 16 | ||||
-rw-r--r-- | sys/geom/geom_int.h | 2 | ||||
-rw-r--r-- | sys/geom/geom_subr.c | 84 |
3 files changed, 77 insertions, 25 deletions
diff --git a/sys/geom/geom_event.c b/sys/geom/geom_event.c index afb214f7ffcd..d26bac08cfa9 100644 --- a/sys/geom/geom_event.c +++ b/sys/geom/geom_event.c @@ -59,6 +59,7 @@ static struct event_tailq_head g_events = TAILQ_HEAD_INITIALIZER(g_events); static u_int g_pending_events; static TAILQ_HEAD(,g_provider) g_doorstep = TAILQ_HEAD_INITIALIZER(g_doorstep); static struct mtx g_eventlock; +static int g_wither_work; #define G_N_EVENTREFS 20 @@ -194,9 +195,18 @@ one_event(void) void g_run_events() { + int i; while (one_event()) ; + g_topology_lock(); + i = g_wither_work; + while (i) { + i = g_wither_washer(); + g_wither_work = i & 1; + i &= 2; + } + g_topology_unlock(); } void @@ -286,6 +296,12 @@ g_post_event(g_event_t *func, void *arg, int flag, ...) return (i); } +void +g_do_wither() { + + g_wither_work = 1; + wakeup(&g_wait_event); +} /* * XXX: It might actually be useful to call this function with topology held. diff --git a/sys/geom/geom_int.h b/sys/geom/geom_int.h index 1b945498e39c..39b3f1033ea9 100644 --- a/sys/geom/geom_int.h +++ b/sys/geom/geom_int.h @@ -68,10 +68,12 @@ void g_conftxt(void *, int flag); /* geom_event.c */ void g_event_init(void); void g_run_events(void); +void g_do_wither(void); /* geom_subr.c */ extern struct class_list_head g_classes; extern char *g_wait_event, *g_wait_sim, *g_wait_up, *g_wait_down; +int g_wither_washer(void); /* geom_io.c */ void g_io_init(void); diff --git a/sys/geom/geom_subr.c b/sys/geom/geom_subr.c index aea06f68ade8..d65b2b5fa4af 100644 --- a/sys/geom/geom_subr.c +++ b/sys/geom/geom_subr.c @@ -263,15 +263,10 @@ g_destroy_geom(struct g_geom *gp) void g_wither_geom(struct g_geom *gp, int error) { - struct g_provider *pp, *pp2; - struct g_consumer *cp, *cp2; - static int once_is_enough; + struct g_provider *pp; g_topology_assert(); G_VALID_GEOM(gp); - if (once_is_enough) - return; - once_is_enough = 1; g_trace(G_T_TOPOLOGY, "g_wither_geom(%p(%s))", gp, gp->name); if (!(gp->flags & G_GEOM_WITHER)) { gp->flags |= G_GEOM_WITHER; @@ -279,22 +274,61 @@ g_wither_geom(struct g_geom *gp, int error) if (!(pp->flags & G_PF_ORPHAN)) g_orphan_provider(pp, error); } - for (pp = LIST_FIRST(&gp->provider); pp != NULL; pp = pp2) { - pp2 = LIST_NEXT(pp, provider); - if (!LIST_EMPTY(&pp->consumers)) - continue; - g_destroy_provider(pp); - } - for (cp = LIST_FIRST(&gp->consumer); cp != NULL; cp = cp2) { - cp2 = LIST_NEXT(cp, consumer); - if (cp->acr || cp->acw || cp->ace) - continue; - g_detach(cp); - g_destroy_consumer(cp); + g_do_wither(); +} + +/* + * This function is called (repeatedly) until we cant wash away more + * withered bits at present. Return value contains two bits. Bit 0 + * set means "withering stuff we can't wash now", bit 1 means "call + * me again, there may be stuff I didn't get the first time around. + */ +int +g_wither_washer() +{ + struct g_class *mp; + struct g_geom *gp, *gp2; + struct g_provider *pp, *pp2; + struct g_consumer *cp, *cp2; + int result; + + result = 0; + g_topology_assert(); + LIST_FOREACH(mp, &g_classes, class) { + LIST_FOREACH_SAFE(gp, &mp->geom, geom, gp2) { + LIST_FOREACH_SAFE(pp, &gp->provider, provider, pp2) { + if (!(pp->flags & G_PF_WITHER)) + continue; + if (LIST_EMPTY(&pp->consumers)) + g_destroy_provider(pp); + else + result |= 1; + } + if (!(gp->flags & G_GEOM_WITHER)) + continue; + LIST_FOREACH_SAFE(pp, &gp->provider, provider, pp2) { + if (LIST_EMPTY(&pp->consumers)) + g_destroy_provider(pp); + else + result |= 1; + } + LIST_FOREACH_SAFE(cp, &gp->consumer, consumer, cp2) { + if (cp->acr || cp->acw || cp->ace) { + result |= 1; + continue; + } + g_detach(cp); + g_destroy_consumer(cp); + result |= 2; + } + if (LIST_EMPTY(&gp->provider) && + LIST_EMPTY(&gp->consumer)) + g_destroy_geom(gp); + else + result |= 1; + } } - if (LIST_EMPTY(&gp->provider) && LIST_EMPTY(&gp->consumer)) - g_destroy_geom(gp); - once_is_enough = 0; + return (result); } struct g_consumer * @@ -337,7 +371,7 @@ g_destroy_consumer(struct g_consumer *cp) devstat_remove_entry(cp->stat); g_free(cp); if (gp->flags & G_GEOM_WITHER) - g_wither_geom(gp, 0); + g_do_wither(); } static void @@ -451,7 +485,7 @@ g_destroy_provider(struct g_provider *pp) devstat_remove_entry(pp->stat); g_free(pp); if ((gp->flags & G_GEOM_WITHER)) - g_wither_geom(gp, 0); + g_do_wither(); } /* @@ -561,9 +595,9 @@ g_detach(struct g_consumer *cp) LIST_REMOVE(cp, consumers); cp->provider = NULL; if (pp->geom->flags & G_GEOM_WITHER) - g_wither_geom(pp->geom, 0); + g_do_wither(); else if (pp->flags & G_PF_WITHER) - g_destroy_provider(pp); + g_do_wither(); redo_rank(cp->geom); } |