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
This commit is contained in:
parent
5b5d78897c
commit
419d406e4e
@ -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);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user