aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Baldwin <jhb@FreeBSD.org>2021-07-30 00:09:23 +0000
committerJohn Baldwin <jhb@FreeBSD.org>2021-07-30 00:09:23 +0000
commit419d406e4ee068644218fb881bc80f79f8191970 (patch)
tree93e1785e479d2c04b34eabf5f5469ed138489825
parent5b5d78897c8b1ec6b6e1dd8dd9cdbf19fee32149 (diff)
downloadsrc-419d406e4ee068644218fb881bc80f79f8191970.tar.gz
src-419d406e4ee068644218fb881bc80f79f8191970.zip
geom_vfs: Pre-allocate event for g_vfs_destroy.
When an active g_vfs is orphaned due to an underlying disk going away the destroy is deferred until the filesystem is unmounted in g_vfs_done(). However, g_vfs_done() is invoked from a non-sleepable context and cannot use M_WAITOK to allocate the event. Instead, allocate the event in g_vfs_orphan() and save it in the softc to be retrieved by the last call to g_vfs_done(). Reported by: Jithesh Arakkan @ Chelsio Reviewed by: imp Sponsored by: Chelsio Communications Differential Revision: https://reviews.freebsd.org/D31354
-rw-r--r--sys/geom/geom_vfs.c21
1 files changed, 19 insertions, 2 deletions
diff --git a/sys/geom/geom_vfs.c b/sys/geom/geom_vfs.c
index f01765b8ee30..592062b8b12a 100644
--- a/sys/geom/geom_vfs.c
+++ b/sys/geom/geom_vfs.c
@@ -53,6 +53,7 @@ __FBSDID("$FreeBSD$");
struct g_vfs_softc {
struct mtx sc_mtx;
struct bufobj *sc_bo;
+ struct g_event *sc_event;
int sc_active;
int sc_orphaned;
int sc_enxio_active;
@@ -96,6 +97,7 @@ static void
g_vfs_done(struct bio *bip)
{
struct g_consumer *cp;
+ struct g_event *event;
struct g_vfs_softc *sc;
struct buf *bp;
int destroy;
@@ -157,9 +159,14 @@ g_vfs_done(struct bio *bip)
mtx_lock(&sc->sc_mtx);
destroy = ((--sc->sc_active) == 0 && sc->sc_orphaned);
+ if (destroy) {
+ event = sc->sc_event;
+ sc->sc_event = NULL;
+ } else
+ event = NULL;
mtx_unlock(&sc->sc_mtx);
if (destroy)
- g_post_event(g_vfs_destroy, cp, M_WAITOK, NULL);
+ g_post_event_ep(g_vfs_destroy, cp, event, NULL);
bufdone(bp);
}
@@ -212,6 +219,7 @@ static void
g_vfs_orphan(struct g_consumer *cp)
{
struct g_geom *gp;
+ struct g_event *event;
struct g_vfs_softc *sc;
int destroy;
@@ -222,12 +230,20 @@ g_vfs_orphan(struct g_consumer *cp)
sc = gp->softc;
if (sc == NULL)
return;
+ event = g_alloc_event(M_WAITOK);
mtx_lock(&sc->sc_mtx);
+ KASSERT(sc->sc_event == NULL, ("g_vfs %p already has an event", sc));
sc->sc_orphaned = 1;
destroy = (sc->sc_active == 0);
+ if (!destroy) {
+ sc->sc_event = event;
+ event = NULL;
+ }
mtx_unlock(&sc->sc_mtx);
- if (destroy)
+ if (destroy) {
+ g_free(event);
g_vfs_destroy(cp, 0);
+ }
/*
* Do not destroy the geom. Filesystem will do that during unmount.
@@ -297,5 +313,6 @@ g_vfs_close(struct g_consumer *cp)
mtx_destroy(&sc->sc_mtx);
if (!sc->sc_orphaned || cp->provider == NULL)
g_wither_geom_close(gp, ENXIO);
+ KASSERT(sc->sc_event == NULL, ("g_vfs %p event is non-NULL", sc));
g_free(sc);
}