aboutsummaryrefslogtreecommitdiff
path: root/sys/geom/concat
diff options
context:
space:
mode:
authorAlexander Motin <mav@FreeBSD.org>2011-11-01 20:56:19 +0000
committerAlexander Motin <mav@FreeBSD.org>2011-11-01 20:56:19 +0000
commitdf96fd6e14b5cea556de886b6e4f7d745ae68d28 (patch)
tree961747cbd5a8187e64771c81928283e26794b5ea /sys/geom/concat
parent84ceb5f6d3059b38a41277fd4ad64d713a86301e (diff)
downloadsrc-df96fd6e14b5cea556de886b6e4f7d745ae68d28.tar.gz
src-df96fd6e14b5cea556de886b6e4f7d745ae68d28.zip
Refactor disk disconnection and geom destruction handling sequences.
Do not close/destroy opened consumer directly in case of disconnect. Instead keep it existing until it will be closed in regular way in response to upstream provider destruction. Delay geom destruction in the same way. Previous implementation could destroy consumers still having active requests and worked only because of global workaround made on GEOM level.
Notes
Notes: svn path=/head/; revision=227004
Diffstat (limited to 'sys/geom/concat')
-rw-r--r--sys/geom/concat/g_concat.c93
-rw-r--r--sys/geom/concat/g_concat.h1
2 files changed, 44 insertions, 50 deletions
diff --git a/sys/geom/concat/g_concat.c b/sys/geom/concat/g_concat.c
index b2196b7b40ea..c9cdcc590393 100644
--- a/sys/geom/concat/g_concat.c
+++ b/sys/geom/concat/g_concat.c
@@ -117,25 +117,33 @@ g_concat_remove_disk(struct g_concat_disk *disk)
struct g_consumer *cp;
struct g_concat_softc *sc;
+ g_topology_assert();
KASSERT(disk->d_consumer != NULL, ("Non-valid disk in %s.", __func__));
sc = disk->d_softc;
cp = disk->d_consumer;
- G_CONCAT_DEBUG(0, "Disk %s removed from %s.", cp->provider->name,
- sc->sc_name);
+ if (!disk->d_removed) {
+ G_CONCAT_DEBUG(0, "Disk %s removed from %s.",
+ cp->provider->name, sc->sc_name);
+ disk->d_removed = 1;
+ }
- disk->d_consumer = NULL;
if (sc->sc_provider != NULL) {
sc->sc_provider->flags |= G_PF_WITHER;
+ G_CONCAT_DEBUG(0, "Device %s deactivated.",
+ sc->sc_provider->name);
g_orphan_provider(sc->sc_provider, ENXIO);
sc->sc_provider = NULL;
- G_CONCAT_DEBUG(0, "Device %s removed.", sc->sc_name);
}
if (cp->acr > 0 || cp->acw > 0 || cp->ace > 0)
- g_access(cp, -cp->acr, -cp->acw, -cp->ace);
+ return;
+ disk->d_consumer = NULL;
g_detach(cp);
g_destroy_consumer(cp);
+ /* If there are no valid disks anymore, remove device. */
+ if (LIST_EMPTY(&sc->sc_geom->consumer))
+ g_concat_destroy(sc, 1);
}
static void
@@ -155,37 +163,18 @@ g_concat_orphan(struct g_consumer *cp)
if (disk == NULL) /* Possible? */
return;
g_concat_remove_disk(disk);
-
- /* If there are no valid disks anymore, remove device. */
- if (g_concat_nvalid(sc) == 0)
- g_concat_destroy(sc, 1);
}
static int
g_concat_access(struct g_provider *pp, int dr, int dw, int de)
{
- struct g_consumer *cp1, *cp2;
- struct g_concat_softc *sc;
+ struct g_consumer *cp1, *cp2, *tmp;
+ struct g_concat_disk *disk;
struct g_geom *gp;
int error;
+ g_topology_assert();
gp = pp->geom;
- sc = gp->softc;
-
- if (sc == NULL) {
- /*
- * It looks like geom is being withered.
- * In that case we allow only negative requests.
- */
- KASSERT(dr <= 0 && dw <= 0 && de <= 0,
- ("Positive access request (device=%s).", pp->name));
- if ((pp->acr + dr) == 0 && (pp->acw + dw) == 0 &&
- (pp->ace + de) == 0) {
- G_CONCAT_DEBUG(0, "Device %s definitely destroyed.",
- gp->name);
- }
- return (0);
- }
/* On first open, grab an extra "exclusive" bit */
if (pp->acr == 0 && pp->acw == 0 && pp->ace == 0)
@@ -194,22 +183,24 @@ g_concat_access(struct g_provider *pp, int dr, int dw, int de)
if ((pp->acr + dr) == 0 && (pp->acw + dw) == 0 && (pp->ace + de) == 0)
de--;
- error = ENXIO;
- LIST_FOREACH(cp1, &gp->consumer, consumer) {
+ LIST_FOREACH_SAFE(cp1, &gp->consumer, consumer, tmp) {
error = g_access(cp1, dr, dw, de);
- if (error == 0)
- continue;
- /*
- * If we fail here, backout all previous changes.
- */
- LIST_FOREACH(cp2, &gp->consumer, consumer) {
- if (cp1 == cp2)
- return (error);
- g_access(cp2, -dr, -dw, -de);
+ if (error != 0)
+ goto fail;
+ disk = cp1->private;
+ if (cp1->acr == 0 && cp1->acw == 0 && cp1->ace == 0 &&
+ disk->d_removed) {
+ g_concat_remove_disk(disk); /* May destroy geom. */
}
- /* NOTREACHED */
}
+ return (0);
+fail:
+ LIST_FOREACH(cp2, &gp->consumer, consumer) {
+ if (cp1 == cp2)
+ break;
+ g_access(cp2, -dr, -dw, -de);
+ }
return (error);
}
@@ -391,6 +382,7 @@ g_concat_check_and_run(struct g_concat_softc *sc)
u_int no, sectorsize = 0;
off_t start;
+ g_topology_assert();
if (g_concat_nvalid(sc) != sc->sc_ndisks)
return;
@@ -419,7 +411,7 @@ g_concat_check_and_run(struct g_concat_softc *sc)
sc->sc_provider = pp;
g_error_provider(pp, 0);
- G_CONCAT_DEBUG(0, "Device %s activated.", sc->sc_name);
+ G_CONCAT_DEBUG(0, "Device %s activated.", sc->sc_provider->name);
}
static int
@@ -461,6 +453,7 @@ g_concat_add_disk(struct g_concat_softc *sc, struct g_provider *pp, u_int no)
struct g_geom *gp;
int error;
+ g_topology_assert();
/* Metadata corrupted? */
if (no >= sc->sc_ndisks)
return (EINVAL);
@@ -509,6 +502,7 @@ g_concat_add_disk(struct g_concat_softc *sc, struct g_provider *pp, u_int no)
disk->d_softc = sc;
disk->d_start = 0; /* not yet */
disk->d_end = 0; /* not yet */
+ disk->d_removed = 0;
G_CONCAT_DEBUG(0, "Disk %s attached to %s.", pp->name, sc->sc_name);
@@ -576,8 +570,8 @@ static int
g_concat_destroy(struct g_concat_softc *sc, boolean_t force)
{
struct g_provider *pp;
+ struct g_consumer *cp, *cp1;
struct g_geom *gp;
- u_int no;
g_topology_assert();
@@ -597,24 +591,23 @@ g_concat_destroy(struct g_concat_softc *sc, boolean_t force)
}
}
- for (no = 0; no < sc->sc_ndisks; no++) {
- if (sc->sc_disks[no].d_consumer != NULL)
- g_concat_remove_disk(&sc->sc_disks[no]);
+ gp = sc->sc_geom;
+ LIST_FOREACH_SAFE(cp, &gp->consumer, consumer, cp1) {
+ g_concat_remove_disk(cp->private);
+ if (cp1 == NULL)
+ return (0); /* Recursion happened. */
}
+ if (!LIST_EMPTY(&gp->consumer))
+ return (EINPROGRESS);
- gp = sc->sc_geom;
gp->softc = NULL;
KASSERT(sc->sc_provider == NULL, ("Provider still exists? (device=%s)",
gp->name));
free(sc->sc_disks, M_CONCAT);
free(sc, M_CONCAT);
- pp = LIST_FIRST(&gp->provider);
- if (pp == NULL || (pp->acr == 0 && pp->acw == 0 && pp->ace == 0))
- G_CONCAT_DEBUG(0, "Device %s destroyed.", gp->name);
-
+ G_CONCAT_DEBUG(0, "Device %s destroyed.", gp->name);
g_wither_geom(gp, ENXIO);
-
return (0);
}
diff --git a/sys/geom/concat/g_concat.h b/sys/geom/concat/g_concat.h
index def0a9813a22..1c1e6f584d4a 100644
--- a/sys/geom/concat/g_concat.h
+++ b/sys/geom/concat/g_concat.h
@@ -72,6 +72,7 @@ struct g_concat_disk {
struct g_concat_softc *d_softc;
off_t d_start;
off_t d_end;
+ int d_removed;
};
struct g_concat_softc {