summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormav <mav@FreeBSD.org>2013-03-24 03:15:20 +0000
committermav <mav@FreeBSD.org>2013-03-24 03:15:20 +0000
commit2ebdf6d693c5b5c43ba6dfc4b0764182f83fa035 (patch)
tree4a6e521bbe6077832fa35b9f86aec2fbd461e46a
parent769b0669e1bbb24e62275530e61b143629eec458 (diff)
downloadFreeBSD-src-2ebdf6d693c5b5c43ba6dfc4b0764182f83fa035.zip
FreeBSD-src-2ebdf6d693c5b5c43ba6dfc4b0764182f83fa035.tar.gz
Make g_wither_washer() to not loop by itself, but only when there was some
more topology change done that may require its attention. Add few missing g_do_wither() calls in respective places to signal it. This fixes potential infinite loop here when some provider is withered, but still opened or connected for some reason and so can not be destroyed. For example, see r227009 and r227510.
-rw-r--r--sys/geom/geom_event.c11
-rw-r--r--sys/geom/geom_int.h2
-rw-r--r--sys/geom/geom_subr.c29
3 files changed, 13 insertions, 29 deletions
diff --git a/sys/geom/geom_event.c b/sys/geom/geom_event.c
index b02d088..3a1363e 100644
--- a/sys/geom/geom_event.c
+++ b/sys/geom/geom_event.c
@@ -273,21 +273,16 @@ one_event(void)
void
g_run_events()
{
- int i;
for (;;) {
g_topology_lock();
while (one_event())
;
mtx_assert(&g_eventlock, MA_OWNED);
- i = g_wither_work;
- if (i) {
+ if (g_wither_work) {
+ g_wither_work = 0;
mtx_unlock(&g_eventlock);
- while (i) {
- i = g_wither_washer();
- g_wither_work = i & 1;
- i &= 2;
- }
+ g_wither_washer();
g_topology_unlock();
} else {
g_topology_unlock();
diff --git a/sys/geom/geom_int.h b/sys/geom/geom_int.h
index cb69df3..0a827af 100644
--- a/sys/geom/geom_int.h
+++ b/sys/geom/geom_int.h
@@ -65,7 +65,7 @@ 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);
+void 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 fb8e69a..316e666 100644
--- a/sys/geom/geom_subr.c
+++ b/sys/geom/geom_subr.c
@@ -437,20 +437,16 @@ g_wither_geom_close(struct g_geom *gp, int error)
/*
* 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.
+ * withered bits at present.
*/
-int
+void
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) {
@@ -459,35 +455,25 @@ g_wither_washer()
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;
+ if (cp->acr || cp->acw || cp->ace)
continue;
- }
if (cp->provider != NULL)
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;
}
}
- return (result);
}
struct g_consumer *
@@ -847,9 +833,9 @@ g_detach(struct g_consumer *cp)
pp = cp->provider;
LIST_REMOVE(cp, consumers);
cp->provider = NULL;
- if (pp->geom->flags & G_GEOM_WITHER)
- g_do_wither();
- else if (pp->flags & G_PF_WITHER)
+ if ((cp->geom->flags & G_GEOM_WITHER) ||
+ (pp->geom->flags & G_GEOM_WITHER) ||
+ (pp->flags & G_PF_WITHER))
g_do_wither();
redo_rank(cp->geom);
}
@@ -948,6 +934,9 @@ g_access(struct g_consumer *cp, int dcr, int dcw, int dce)
if (pp->acr != 0 || pp->acw != 0 || pp->ace != 0)
KASSERT(pp->sectorsize > 0,
("Provider %s lacks sectorsize", pp->name));
+ if ((cp->geom->flags & G_GEOM_WITHER) &&
+ cp->acr == 0 && cp->acw == 0 && cp->ace == 0)
+ g_do_wither();
}
return (error);
}
OpenPOWER on IntegriCloud