aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexander Motin <mav@FreeBSD.org>2019-12-27 21:44:13 +0000
committerAlexander Motin <mav@FreeBSD.org>2019-12-27 21:44:13 +0000
commit2178f45b86b08f8f5bd7dfdbca170ebb13897ebf (patch)
tree60bca8fcc7506e94389fb9ed5a3554540802b40f
parentfa6d8b65d3956f69cde9043a3c5e77fb57788904 (diff)
downloadsrc-2178f45b86b08f8f5bd7dfdbca170ebb13897ebf.tar.gz
src-2178f45b86b08f8f5bd7dfdbca170ebb13897ebf.zip
Fix GEOM_UZIP orphanization.
Previous code destroyed softc even with provider still open, that resulted in panic under load. This change postpones the free till the final close, when we know for sure there will be no more I/O requests. MFC after: 2 weeks Sponsored by: iXsystems, Inc.
Notes
Notes: svn path=/head/; revision=356138
-rw-r--r--sys/geom/uzip/g_uzip.c60
1 files changed, 34 insertions, 26 deletions
diff --git a/sys/geom/uzip/g_uzip.c b/sys/geom/uzip/g_uzip.c
index 8339abb74a82..e029e7eb87fe 100644
--- a/sys/geom/uzip/g_uzip.c
+++ b/sys/geom/uzip/g_uzip.c
@@ -143,13 +143,12 @@ static void g_uzip_read_done(struct bio *bp);
static void g_uzip_do(struct g_uzip_softc *, struct bio *bp);
static void
-g_uzip_softc_free(struct g_uzip_softc *sc, struct g_geom *gp)
+g_uzip_softc_free(struct g_geom *gp)
{
+ struct g_uzip_softc *sc = gp->softc;
- if (gp != NULL) {
- DPRINTF(GUZ_DBG_INFO, ("%s: %d requests, %d cached\n",
- gp->name, sc->req_total, sc->req_cached));
- }
+ DPRINTF(GUZ_DBG_INFO, ("%s: %d requests, %d cached\n",
+ gp->name, sc->req_total, sc->req_cached));
mtx_lock(&sc->queue_mtx);
sc->wrkthr_flags |= GUZ_SHUTDOWN;
@@ -166,6 +165,7 @@ g_uzip_softc_free(struct g_uzip_softc *sc, struct g_geom *gp)
mtx_destroy(&sc->last_mtx);
free(sc->last_buf, M_GEOM_UZIP);
free(sc, M_GEOM_UZIP);
+ gp->softc = NULL;
}
static int
@@ -507,13 +507,27 @@ g_uzip_orphan(struct g_consumer *cp)
{
struct g_geom *gp;
- g_trace(G_T_TOPOLOGY, "%s(%p/%s)", __func__, cp, cp->provider->name);
g_topology_assert();
-
+ G_VALID_CONSUMER(cp);
gp = cp->geom;
- g_uzip_softc_free(gp->softc, gp);
- gp->softc = NULL;
+ g_trace(G_T_TOPOLOGY, "%s(%p/%s)", __func__, cp, gp->name);
g_wither_geom(gp, ENXIO);
+
+ /*
+ * We can safely free the softc now if there are no accesses,
+ * otherwise g_uzip_access() will do that after the last close.
+ */
+ if ((cp->acr + cp->acw + cp->ace) == 0)
+ g_uzip_softc_free(gp);
+}
+
+static void
+g_uzip_spoiled(struct g_consumer *cp)
+{
+
+ g_trace(G_T_TOPOLOGY, "%s(%p/%s)", __func__, cp, cp->geom->name);
+ cp->flags |= G_CF_ORPHAN;
+ g_uzip_orphan(cp);
}
static int
@@ -521,6 +535,7 @@ g_uzip_access(struct g_provider *pp, int dr, int dw, int de)
{
struct g_geom *gp;
struct g_consumer *cp;
+ int error;
gp = pp->geom;
cp = LIST_FIRST(&gp->consumer);
@@ -529,22 +544,17 @@ g_uzip_access(struct g_provider *pp, int dr, int dw, int de)
if (cp->acw + dw > 0)
return (EROFS);
- return (g_access(cp, dr, dw, de));
-}
-
-static void
-g_uzip_spoiled(struct g_consumer *cp)
-{
- struct g_geom *gp;
+ error = g_access(cp, dr, dw, de);
- G_VALID_CONSUMER(cp);
- gp = cp->geom;
- g_trace(G_T_TOPOLOGY, "%s(%p/%s)", __func__, cp, gp->name);
- g_topology_assert();
+ /*
+ * Free the softc if all providers have been closed and this geom
+ * is being removed.
+ */
+ if (error == 0 && (gp->flags & G_GEOM_WITHER) != 0 &&
+ (cp->acr + cp->acw + cp->ace) == 0)
+ g_uzip_softc_free(gp);
- g_uzip_softc_free(gp->softc, gp);
- gp->softc = NULL;
- g_wither_geom(gp, ENXIO);
+ return (error);
}
static int
@@ -954,10 +964,8 @@ g_uzip_destroy_geom(struct gctl_req *req, struct g_class *mp, struct g_geom *gp)
if (pp->acr > 0 || pp->acw > 0 || pp->ace > 0)
return (EBUSY);
- g_uzip_softc_free(gp->softc, gp);
- gp->softc = NULL;
g_wither_geom(gp, ENXIO);
-
+ g_uzip_softc_free(gp);
return (0);
}