commit a0c22efdbfe4ed1473037d32930f58bf5d8a8b83 Author: Andriy Gapon Date: Wed Sep 19 20:15:13 2012 +0300 allow providers that were used by withered geoms to be re-tasted ... after the corresponding consumers are detached and destroyed. Those consumers might have prevented tasting by their geom's class. Mark the skipped providers with G_PF_OWE_TASTE flag, so that we don't needlessly retaste providers that don't require that. Also, taste methods may have leave withering "taster" geoms behind them, so indiscriminating retasting could lead to an endless loop in wither-washer. Note: g_renew_provider seems to come from a local patch and may not be present upstream! diff --git a/sys/geom/geom.h b/sys/geom/geom.h index ced343a..defd779 100644 --- a/sys/geom/geom.h +++ b/sys/geom/geom.h @@ -206,6 +206,7 @@ struct g_provider { u_int flags; #define G_PF_WITHER 0x2 #define G_PF_ORPHAN 0x4 +#define G_PF_OWE_TASTE 0x8 /* Two fields for the implementing class to use */ void *private; diff --git a/sys/geom/geom_subr.c b/sys/geom/geom_subr.c index d00b09d..07aa67a 100644 --- a/sys/geom/geom_subr.c +++ b/sys/geom/geom_subr.c @@ -470,18 +470,38 @@ g_wither_washer() else result |= 1; } + + /* + * Do not start purging consumers until + * all providers are gone. + */ + if (!LIST_EMPTY(&gp->provider)) + continue; + LIST_FOREACH_SAFE(cp, &gp->consumer, consumer, cp2) { if (cp->acr || cp->acw || cp->ace) { result |= 1; continue; } - if (cp->provider != NULL) + if ((pp = cp->provider) != NULL) g_detach(cp); g_destroy_consumer(cp); result |= 2; + + /* The destroyed consumer may have prevented + * tasting of the connected provider by this + * geom's class. Post a taste event now to + * give the class a chance. + */ + if (pp != NULL && + (pp->flags & G_PF_OWE_TASTE) != 0 && + (pp->flags & G_PF_WITHER) == 0 && + (pp->geom->flags & G_GEOM_WITHER) == 0) { + pp->flags &= ~G_PF_OWE_TASTE; + g_renew_provider(pp); + } } - if (LIST_EMPTY(&gp->provider) && - LIST_EMPTY(&gp->consumer)) + if (LIST_EMPTY(&gp->consumer)) g_destroy_geom(gp); else result |= 1; @@ -561,8 +581,10 @@ g_new_provider_event(void *arg, int flag) if (cp->geom->class == mp && (cp->flags & G_CF_ORPHAN) == 0) break; - if (cp != NULL && !(cp->geom->flags & G_GEOM_TASTER)) + if (cp != NULL && !(cp->geom->flags & G_GEOM_TASTER)) { + pp->flags |= G_PF_OWE_TASTE; continue; + } mp->taste(mp, pp, 0); g_topology_assert(); } @@ -675,8 +697,10 @@ g_resize_provider_event(void *arg, int flag) if (cp->geom->class == mp && (cp->flags & G_CF_ORPHAN) == 0) break; - if (cp != NULL) + if (cp != NULL) { + pp->flags |= G_PF_OWE_TASTE; continue; + } mp->taste(mp, pp, 0); g_topology_assert(); }