summaryrefslogtreecommitdiffstats
path: root/sys/geom/geom_subr.c
diff options
context:
space:
mode:
authorphk <phk@FreeBSD.org>2004-07-08 16:17:14 +0000
committerphk <phk@FreeBSD.org>2004-07-08 16:17:14 +0000
commit042d10f8ef48e69d0af980b7709a295d34a9d987 (patch)
treea2bc0c14b24fa444e03a2cf0a77ec7bc53390e33 /sys/geom/geom_subr.c
parentee6a790d1159a338d31f43dc0373c731d1106bb8 (diff)
downloadFreeBSD-src-042d10f8ef48e69d0af980b7709a295d34a9d987.zip
FreeBSD-src-042d10f8ef48e69d0af980b7709a295d34a9d987.tar.gz
Make withering water tight.
When we orphan/wither a provider, an attached geom+consumer could end up being withered as a result and it may be in front of us in the normal object scanning order so we need to do multi-pass. On the other hand, there may be withering stuff we can't get rid off (yet), so we need to keep track of both the existence of withering stuff and if there is more we can do at this time.
Diffstat (limited to 'sys/geom/geom_subr.c')
-rw-r--r--sys/geom/geom_subr.c84
1 files changed, 59 insertions, 25 deletions
diff --git a/sys/geom/geom_subr.c b/sys/geom/geom_subr.c
index aea06f6..d65b2b5 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);
}
OpenPOWER on IntegriCloud