summaryrefslogtreecommitdiffstats
path: root/sys/geom/mirror
diff options
context:
space:
mode:
authorpjd <pjd@FreeBSD.org>2006-02-11 17:39:29 +0000
committerpjd <pjd@FreeBSD.org>2006-02-11 17:39:29 +0000
commit392d25e4bc345d6563f9272d1132f57731ee2f15 (patch)
treece6eb498372120a43967ea30a24cf1e59f255910 /sys/geom/mirror
parent1aa881eae67cf08f30cfa9d656d3e2beb11d1702 (diff)
downloadFreeBSD-src-392d25e4bc345d6563f9272d1132f57731ee2f15.zip
FreeBSD-src-392d25e4bc345d6563f9272d1132f57731ee2f15.tar.gz
- Add kern.geom.mirror.disconnect_on_failure sysctl/tunnable (default to 1
to preserve currect behaviour). When set to 0, components are not disconnected - gmirror will try to still use them (only first error will be logged). This is helpful when we have two broken components, but in different places, so actually all data is available. Such buggy component will be visible in 'gmirror list' output with flag BROKEN. - Never disconnect the last valid component. If we detect errors there we will just pass them up. This wasn't reasonable to deny access to the whole provider because of one broken sector. Prodded by: ru MFC after: 3 days
Diffstat (limited to 'sys/geom/mirror')
-rw-r--r--sys/geom/mirror/g_mirror.c56
-rw-r--r--sys/geom/mirror/g_mirror.h1
2 files changed, 47 insertions, 10 deletions
diff --git a/sys/geom/mirror/g_mirror.c b/sys/geom/mirror/g_mirror.c
index f5929a4..4edd9af 100644
--- a/sys/geom/mirror/g_mirror.c
+++ b/sys/geom/mirror/g_mirror.c
@@ -70,6 +70,11 @@ static u_int g_mirror_syncs_per_sec = 1000;
SYSCTL_UINT(_kern_geom_mirror, OID_AUTO, syncs_per_sec, CTLFLAG_RW,
&g_mirror_syncs_per_sec, 0,
"Number of synchronizations requests per second");
+static u_int g_mirror_disconnect_on_failure = 1;
+TUNABLE_INT("kern.geom.mirror.disconnect_on_failure",
+ &g_mirror_disconnect_on_failure);
+SYSCTL_UINT(_kern_geom_mirror, OID_AUTO, disconnect_on_failure, CTLFLAG_RW,
+ &g_mirror_disconnect_on_failure, 0, "Disconnect component on I/O failure.");
#define MSLEEP(ident, mtx, priority, wmesg, timeout) do { \
G_MIRROR_DEBUG(4, "%s: Sleeping %p.", __func__, (ident)); \
@@ -625,9 +630,23 @@ g_mirror_write_metadata(struct g_mirror_disk *disk,
g_topology_lock();
free(sector, M_MIRROR);
if (error != 0) {
- disk->d_softc->sc_bump_id |= G_MIRROR_BUMP_GENID;
- g_mirror_event_send(disk, G_MIRROR_DISK_STATE_DISCONNECTED,
- G_MIRROR_EVENT_DONTWAIT);
+ if ((disk->d_flags & G_MIRROR_DISK_FLAG_BROKEN) == 0) {
+ disk->d_flags |= G_MIRROR_DISK_FLAG_BROKEN;
+ G_MIRROR_DEBUG(0, "Cannot write metadata on %s "
+ "(device=%s, error=%d).",
+ g_mirror_get_diskname(disk), sc->sc_name, error);
+ } else {
+ G_MIRROR_DEBUG(1, "Cannot write metadata on %s "
+ "(device=%s, error=%d).",
+ g_mirror_get_diskname(disk), sc->sc_name, error);
+ }
+ if (g_mirror_disconnect_on_failure &&
+ g_mirror_ndisks(sc, G_MIRROR_DISK_STATE_ACTIVE) > 1) {
+ sc->sc_bump_id |= G_MIRROR_BUMP_GENID;
+ g_mirror_event_send(disk,
+ G_MIRROR_DISK_STATE_DISCONNECTED,
+ G_MIRROR_EVENT_DONTWAIT);
+ }
}
return (error);
}
@@ -884,13 +903,25 @@ g_mirror_regular_request(struct bio *bp)
} else if (bp->bio_error != 0) {
if (pbp->bio_error == 0)
pbp->bio_error = bp->bio_error;
- G_MIRROR_LOGREQ(0, bp, "Request failed (error=%d).",
- bp->bio_error);
if (disk != NULL) {
- sc->sc_bump_id |= G_MIRROR_BUMP_GENID;
- g_mirror_event_send(disk,
- G_MIRROR_DISK_STATE_DISCONNECTED,
- G_MIRROR_EVENT_DONTWAIT);
+ if ((disk->d_flags & G_MIRROR_DISK_FLAG_BROKEN) == 0) {
+ disk->d_flags |= G_MIRROR_DISK_FLAG_BROKEN;
+ G_MIRROR_LOGREQ(0, bp,
+ "Request failed (error=%d).",
+ bp->bio_error);
+ } else {
+ G_MIRROR_LOGREQ(1, bp,
+ "Request failed (error=%d).",
+ bp->bio_error);
+ }
+ if (g_mirror_disconnect_on_failure &&
+ g_mirror_ndisks(sc, G_MIRROR_DISK_STATE_ACTIVE) > 1)
+ {
+ sc->sc_bump_id |= G_MIRROR_BUMP_GENID;
+ g_mirror_event_send(disk,
+ G_MIRROR_DISK_STATE_DISCONNECTED,
+ G_MIRROR_EVENT_DONTWAIT);
+ }
}
switch (pbp->bio_cmd) {
case BIO_DELETE:
@@ -904,7 +935,11 @@ g_mirror_regular_request(struct bio *bp)
switch (pbp->bio_cmd) {
case BIO_READ:
- if (pbp->bio_children == pbp->bio_inbed) {
+ if (pbp->bio_inbed < pbp->bio_children)
+ break;
+ if (g_mirror_ndisks(sc, G_MIRROR_DISK_STATE_ACTIVE) == 1)
+ g_io_deliver(pbp, pbp->bio_error);
+ else {
pbp->bio_error = 0;
mtx_lock(&sc->sc_queue_mtx);
bioq_disksort(&sc->sc_queue, pbp);
@@ -2739,6 +2774,7 @@ g_mirror_dumpconf(struct sbuf *sb, const char *indent, struct g_geom *gp,
ADD_FLAG(G_MIRROR_DISK_FLAG_SYNCHRONIZING,
"SYNCHRONIZING");
ADD_FLAG(G_MIRROR_DISK_FLAG_FORCE_SYNC, "FORCE_SYNC");
+ ADD_FLAG(G_MIRROR_DISK_FLAG_BROKEN, "BROKEN");
#undef ADD_FLAG
}
sbuf_printf(sb, "</Flags>\n");
diff --git a/sys/geom/mirror/g_mirror.h b/sys/geom/mirror/g_mirror.h
index 35d84b4..1e13e5a 100644
--- a/sys/geom/mirror/g_mirror.h
+++ b/sys/geom/mirror/g_mirror.h
@@ -57,6 +57,7 @@
#define G_MIRROR_DISK_FLAG_FORCE_SYNC 0x0000000000000004ULL
#define G_MIRROR_DISK_FLAG_INACTIVE 0x0000000000000008ULL
#define G_MIRROR_DISK_FLAG_HARDCODED 0x0000000000000010ULL
+#define G_MIRROR_DISK_FLAG_BROKEN 0x0000000000000020ULL
#define G_MIRROR_DISK_FLAG_MASK (G_MIRROR_DISK_FLAG_DIRTY | \
G_MIRROR_DISK_FLAG_SYNCHRONIZING | \
G_MIRROR_DISK_FLAG_FORCE_SYNC | \
OpenPOWER on IntegriCloud