From 78c53bec48d6a0e27d11e4961ec3362a0cd0060c Mon Sep 17 00:00:00 2001 From: avg Date: Fri, 15 Sep 2017 13:57:08 +0000 Subject: [PATCH] gmirror: treat ENXIO as disk disconnect, not media error In theory, all data access errors mean that a member is out of sync at most. But they were treated as more serious errors to avoid the situation where a flaky disk gets repeatedly disconnected, re-synchronized, reconnected and then disconnected again. ENXIO is a special error that means that the member disk disappeared, so it should get the same handling as the GEOM orphaning event. There is a better chance that when the disk is reconnected, it will be a good member again. When ENXIO happens on a read we use the exisiting G_MIRROR_BUMP_SYNCID mechanism which means that the mirror's syncid is increased as soon as there is a write to the mirror. That's because no data has got out of sync yet, but the problematic memeber is disconnected, so the future write will make it stale. When ENXIO happens on a write we use a new G_MIRROR_BUMP_SYNCID_NOW mechanism which means that we update the mirror metadata as soon as possible because the problematic memeber is already behind. Reviewed by: markj, imp MFC after: 3 weeks Differential Revision: https://reviews.freebsd.org/D9463 --- sys/geom/mirror/g_mirror.c | 12 +++++++++++- sys/geom/mirror/g_mirror.h | 6 ++++-- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/sys/geom/mirror/g_mirror.c b/sys/geom/mirror/g_mirror.c index 4447ce2a2dd2..d9b7e4cdb445 100644 --- a/sys/geom/mirror/g_mirror.c +++ b/sys/geom/mirror/g_mirror.c @@ -982,7 +982,13 @@ g_mirror_regular_request(struct bio *bp) if (g_mirror_disconnect_on_failure && g_mirror_ndisks(sc, G_MIRROR_DISK_STATE_ACTIVE) > 1) { - sc->sc_bump_id |= G_MIRROR_BUMP_GENID; + if (bp->bio_error == ENXIO && + bp->bio_cmd == BIO_READ) + sc->sc_bump_id |= G_MIRROR_BUMP_SYNCID; + else if (bp->bio_error == ENXIO) + sc->sc_bump_id |= G_MIRROR_BUMP_SYNCID_NOW; + else + sc->sc_bump_id |= G_MIRROR_BUMP_GENID; g_mirror_event_send(disk, G_MIRROR_DISK_STATE_DISCONNECTED, G_MIRROR_EVENT_DONTWAIT); @@ -2518,6 +2524,10 @@ g_mirror_update_device(struct g_mirror_softc *sc, bool force) sc->sc_bump_id &= ~G_MIRROR_BUMP_GENID; g_mirror_bump_genid(sc); } + if ((sc->sc_bump_id & G_MIRROR_BUMP_SYNCID_NOW) != 0) { + sc->sc_bump_id &= ~G_MIRROR_BUMP_SYNCID_NOW; + g_mirror_bump_syncid(sc); + } break; default: KASSERT(1 == 0, ("Wrong device state (%s, %s).", diff --git a/sys/geom/mirror/g_mirror.h b/sys/geom/mirror/g_mirror.h index e573acc5e806..f3a4a0070093 100644 --- a/sys/geom/mirror/g_mirror.h +++ b/sys/geom/mirror/g_mirror.h @@ -169,9 +169,11 @@ struct g_mirror_event { #define G_MIRROR_TYPE_AUTOMATIC 1 /* Bump syncid on first write. */ -#define G_MIRROR_BUMP_SYNCID 0x1 +#define G_MIRROR_BUMP_SYNCID 0x1 /* Bump genid immediately. */ -#define G_MIRROR_BUMP_GENID 0x2 +#define G_MIRROR_BUMP_GENID 0x2 +/* Bump syncid immediately. */ +#define G_MIRROR_BUMP_SYNCID_NOW 0x4 struct g_mirror_softc { u_int sc_type; /* Device type (manual/automatic). */ u_int sc_state; /* Device state. */