summaryrefslogtreecommitdiffstats
path: root/sys/geom
diff options
context:
space:
mode:
Diffstat (limited to 'sys/geom')
-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 b2196b7..c9cdcc5 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 def0a98..1c1e6f5 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 {
OpenPOWER on IntegriCloud