summaryrefslogtreecommitdiffstats
path: root/sys/geom/geom_subr.c
diff options
context:
space:
mode:
authorphk <phk@FreeBSD.org>2003-05-02 06:15:27 +0000
committerphk <phk@FreeBSD.org>2003-05-02 06:15:27 +0000
commit098143e63b811524ad866fd02231119efc04077b (patch)
tree4eabd0071f499b2dd9e80fdb0cfde3396743b3b2 /sys/geom/geom_subr.c
parent1f97a57472eaa9798ee5eae67db8538dfe685609 (diff)
downloadFreeBSD-src-098143e63b811524ad866fd02231119efc04077b.zip
FreeBSD-src-098143e63b811524ad866fd02231119efc04077b.tar.gz
Rework the "withering" mechanism:
Introduce g_wither_geom() to do the work in one single place.
Diffstat (limited to 'sys/geom/geom_subr.c')
-rw-r--r--sys/geom/geom_subr.c63
1 files changed, 46 insertions, 17 deletions
diff --git a/sys/geom/geom_subr.c b/sys/geom/geom_subr.c
index 700c60f..d45dd2b 100644
--- a/sys/geom/geom_subr.c
+++ b/sys/geom/geom_subr.c
@@ -154,6 +154,44 @@ g_destroy_geom(struct g_geom *gp)
g_free(gp);
}
+/*
+ * This function is called (repeatedly) until has withered away.
+ */
+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;
+
+ if (once_is_enough)
+ return;
+ once_is_enough = 1;
+ g_trace(G_T_TOPOLOGY, "g_wither_geom(%p(%s))", gp, gp->name);
+ g_topology_assert();
+ if (!(gp->flags & G_GEOM_WITHER)) {
+ gp->flags |= G_GEOM_WITHER;
+ LIST_FOREACH(pp, &gp->provider, provider)
+ 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);
+ }
+ if (LIST_EMPTY(&gp->provider) && LIST_EMPTY(&gp->consumer))
+ g_destroy_geom(gp);
+ once_is_enough = 0;
+}
+
struct g_consumer *
g_new_consumer(struct g_geom *gp)
{
@@ -176,6 +214,7 @@ g_new_consumer(struct g_geom *gp)
void
g_destroy_consumer(struct g_consumer *cp)
{
+ struct g_geom *gp;
g_trace(G_T_TOPOLOGY, "g_destroy_consumer(%p)", cp);
g_topology_assert();
@@ -184,9 +223,12 @@ g_destroy_consumer(struct g_consumer *cp)
KASSERT (cp->acw == 0, ("g_destroy_consumer with acw"));
KASSERT (cp->ace == 0, ("g_destroy_consumer with ace"));
g_cancel_event(cp);
+ gp = cp->geom;
LIST_REMOVE(cp, consumer);
devstat_remove_entry(cp->stat);
g_free(cp);
+ if (gp->flags & G_GEOM_WITHER)
+ g_wither_geom(gp, 0);
}
static void
@@ -258,7 +300,6 @@ void
g_destroy_provider(struct g_provider *pp)
{
struct g_geom *gp;
- struct g_consumer *cp;
g_topology_assert();
KASSERT(LIST_EMPTY(&pp->consumers),
@@ -272,18 +313,8 @@ g_destroy_provider(struct g_provider *pp)
gp = pp->geom;
devstat_remove_entry(pp->stat);
g_free(pp);
- if (!(gp->flags & G_GEOM_WITHER))
- return;
- if (!LIST_EMPTY(&gp->provider))
- return;
- for (;;) {
- cp = LIST_FIRST(&gp->consumer);
- if (cp == NULL)
- break;
- g_detach(cp);
- g_destroy_consumer(cp);
- }
- g_destroy_geom(gp);
+ if ((gp->flags & G_GEOM_WITHER))
+ g_wither_geom(gp, 0);
}
/*
@@ -389,10 +420,8 @@ g_detach(struct g_consumer *cp)
pp = cp->provider;
LIST_REMOVE(cp, consumers);
cp->provider = NULL;
- if (LIST_EMPTY(&pp->consumers)) {
- if (pp->geom->flags & G_GEOM_WITHER)
- g_destroy_provider(pp);
- }
+ if (pp->geom->flags & G_GEOM_WITHER)
+ g_wither_geom(pp->geom, 0);
redo_rank(cp->geom);
}
OpenPOWER on IntegriCloud