diff options
author | pjd <pjd@FreeBSD.org> | 2004-12-21 18:42:51 +0000 |
---|---|---|
committer | pjd <pjd@FreeBSD.org> | 2004-12-21 18:42:51 +0000 |
commit | c5ff5344f313b5fae7c04f1f3c8b1c50d7c3c3f7 (patch) | |
tree | 358405dca8be68b379f3026571dcbb48a0992aaf | |
parent | 27d828652f75a738e05872ea715468cdfacdd27e (diff) | |
download | FreeBSD-src-c5ff5344f313b5fae7c04f1f3c8b1c50d7c3c3f7.zip FreeBSD-src-c5ff5344f313b5fae7c04f1f3c8b1c50d7c3c3f7.tar.gz |
This should not be permitted, but some GEOM classes held the topology lock
while doing g_(read|write)_data() (e.g. BSD). This can cause a deadlock
in MIRROR class. Not sure if this is safe to drop the topology lock in BSD
class, so change the code in MIRROR class to avoid this deadlock.
-rw-r--r-- | sys/geom/mirror/g_mirror.c | 36 |
1 files changed, 30 insertions, 6 deletions
diff --git a/sys/geom/mirror/g_mirror.c b/sys/geom/mirror/g_mirror.c index 3a92172..8ae0540 100644 --- a/sys/geom/mirror/g_mirror.c +++ b/sys/geom/mirror/g_mirror.c @@ -214,12 +214,20 @@ g_mirror_event_get(struct g_mirror_softc *sc) mtx_lock(&sc->sc_events_mtx); ep = TAILQ_FIRST(&sc->sc_events); - if (ep != NULL) - TAILQ_REMOVE(&sc->sc_events, ep, e_next); mtx_unlock(&sc->sc_events_mtx); return (ep); } + +static void +g_mirror_event_remove(struct g_mirror_softc *sc, struct g_mirror_event *ep) +{ + + mtx_lock(&sc->sc_events_mtx); + TAILQ_REMOVE(&sc->sc_events, ep, e_next); + mtx_unlock(&sc->sc_events_mtx); +} + static void g_mirror_event_cancel(struct g_mirror_disk *disk) { @@ -500,6 +508,7 @@ g_mirror_destroy_device(struct g_mirror_softc *sc) g_mirror_destroy_disk(disk); } while ((ep = g_mirror_event_get(sc)) != NULL) { + g_mirror_event_remove(sc, ep); if ((ep->e_flags & G_MIRROR_EVENT_DONTWAIT) != 0) g_mirror_event_free(ep); else { @@ -1461,8 +1470,8 @@ g_mirror_worker(void *arg) * This is important to handle events before any I/O requests. */ ep = g_mirror_event_get(sc); - if (ep != NULL) { - g_topology_lock(); + if (ep != NULL && g_topology_try_lock()) { + g_mirror_event_remove(sc, ep); if ((ep->e_flags & G_MIRROR_EVENT_DEVICE) != 0) { /* Update only device status. */ G_MIRROR_DEBUG(3, @@ -1507,6 +1516,14 @@ g_mirror_worker(void *arg) mtx_lock(&sc->sc_queue_mtx); bp = bioq_first(&sc->sc_queue); if (bp == NULL) { + if (ep != NULL) { + /* + * No I/O requests and topology lock was + * already held? Try again. + */ + mtx_unlock(&sc->sc_queue_mtx); + continue; + } if ((sc->sc_flags & G_MIRROR_DEVICE_FLAG_DESTROY) != 0) { mtx_unlock(&sc->sc_queue_mtx); @@ -1586,10 +1603,17 @@ sleep: G_MIRROR_DEBUG(5, "%s: I'm here 6.", __func__); continue; } + if (ep != NULL) { + /* + * We have some pending events, don't sleep now. + */ + G_MIRROR_DEBUG(5, "%s: I'm here 7.", __func__); + continue; + } mtx_lock(&sc->sc_queue_mtx); if (bioq_first(&sc->sc_queue) != NULL) { mtx_unlock(&sc->sc_queue_mtx); - G_MIRROR_DEBUG(5, "%s: I'm here 7.", __func__); + G_MIRROR_DEBUG(5, "%s: I'm here 8.", __func__); continue; } timeout = hz / sps; @@ -1600,7 +1624,7 @@ sleep: } else { g_mirror_register_request(bp); } - G_MIRROR_DEBUG(5, "%s: I'm here 8.", __func__); + G_MIRROR_DEBUG(5, "%s: I'm here 9.", __func__); } } |