diff options
author | pjd <pjd@FreeBSD.org> | 2004-12-22 23:09:32 +0000 |
---|---|---|
committer | pjd <pjd@FreeBSD.org> | 2004-12-22 23:09:32 +0000 |
commit | b58db25ebeed85a1cc3d68bda134815500157aaa (patch) | |
tree | b0d86c753f73582bc08dbd2224d2dc7047934432 /sys/geom/mirror | |
parent | 3a1bb12c828f9bb4b003f8f8fb2a55d3d78b575d (diff) | |
download | FreeBSD-src-b58db25ebeed85a1cc3d68bda134815500157aaa.zip FreeBSD-src-b58db25ebeed85a1cc3d68bda134815500157aaa.tar.gz |
- Add genid field to the metadata which will allow to improve reliability a bit.
After this change, when component is disconnected because of an I/O error,
it will not be connected and synchronized automatically, it will be logged
as broken and skipped. Autosynchronization can occur, when component is
disconnected (on orphan event) and connected again - there were no I/O
error, so there is no need to not connected the component, but when there were
writes while it wasn't connected, it will be synchronized.
This fix cases, when component is disconnected because of I/O error and can be
connected again and again.
- Bump version number.
- Add version change history.
- Implement backward compatibility mechanism. After this change when metadata in
old version is detected, it is automatically upgraded to the new (current)
version.
Diffstat (limited to 'sys/geom/mirror')
-rw-r--r-- | sys/geom/mirror/g_mirror.c | 133 | ||||
-rw-r--r-- | sys/geom/mirror/g_mirror.h | 107 | ||||
-rw-r--r-- | sys/geom/mirror/g_mirror_ctl.c | 2 |
3 files changed, 185 insertions, 57 deletions
diff --git a/sys/geom/mirror/g_mirror.c b/sys/geom/mirror/g_mirror.c index fadf447..6e9f4f2 100644 --- a/sys/geom/mirror/g_mirror.c +++ b/sys/geom/mirror/g_mirror.c @@ -218,7 +218,6 @@ g_mirror_event_get(struct g_mirror_softc *sc) return (ep); } - static void g_mirror_event_remove(struct g_mirror_softc *sc, struct g_mirror_event *ep) { @@ -445,6 +444,7 @@ g_mirror_init_disk(struct g_mirror_softc *sc, struct g_provider *pp, disk->d_sync.ds_offset = md->md_sync_offset; disk->d_sync.ds_offset_done = md->md_sync_offset; disk->d_sync.ds_resync = -1; + disk->d_genid = md->md_genid; disk->d_sync.ds_syncid = md->md_syncid; if (errorp != NULL) *errorp = 0; @@ -544,7 +544,7 @@ g_mirror_orphan(struct g_consumer *cp) disk = cp->private; if (disk == NULL) return; - disk->d_softc->sc_bump_syncid = G_MIRROR_BUMP_ON_FIRST_WRITE; + disk->d_softc->sc_bump_id |= G_MIRROR_BUMP_SYNCID_OFW; g_mirror_event_send(disk, G_MIRROR_DISK_STATE_DISCONNECTED, G_MIRROR_EVENT_DONTWAIT); } @@ -559,7 +559,7 @@ g_mirror_spoiled(struct g_consumer *cp) disk = cp->private; if (disk == NULL) return; - disk->d_softc->sc_bump_syncid = G_MIRROR_BUMP_IMMEDIATELY; + disk->d_softc->sc_bump_id |= G_MIRROR_BUMP_SYNCID_IMM; g_mirror_event_send(disk, G_MIRROR_DISK_STATE_DISCONNECTED, G_MIRROR_EVENT_DONTWAIT); } @@ -635,7 +635,7 @@ g_mirror_write_metadata(struct g_mirror_disk *disk, g_topology_lock(); free(sector, M_MIRROR); if (error != 0) { - disk->d_softc->sc_bump_syncid = G_MIRROR_BUMP_IMMEDIATELY; + disk->d_softc->sc_bump_id |= G_MIRROR_BUMP_GENID_IMM; g_mirror_event_send(disk, G_MIRROR_DISK_STATE_DISCONNECTED, G_MIRROR_EVENT_DONTWAIT); } @@ -672,6 +672,7 @@ g_mirror_fill_metadata(struct g_mirror_softc *sc, struct g_mirror_disk *disk, md->md_all = sc->sc_ndisks; md->md_slice = sc->sc_slice; md->md_balance = sc->sc_balance; + md->md_genid = sc->sc_genid; md->md_mediasize = sc->sc_mediasize; md->md_sectorsize = sc->sc_sectorsize; md->md_mflags = (sc->sc_flags & G_MIRROR_DEVICE_FLAG_MASK); @@ -741,6 +742,27 @@ g_mirror_bump_syncid(struct g_mirror_softc *sc) } static void +g_mirror_bump_genid(struct g_mirror_softc *sc) +{ + struct g_mirror_disk *disk; + + g_topology_assert(); + KASSERT(g_mirror_ndisks(sc, G_MIRROR_DISK_STATE_ACTIVE) > 0, + ("%s called with no active disks (device=%s).", __func__, + sc->sc_name)); + + sc->sc_genid++; + G_MIRROR_DEBUG(1, "Device %s: genid bumped to %u.", sc->sc_name, + sc->sc_genid); + LIST_FOREACH(disk, &sc->sc_disks, d_next) { + if (disk->d_state == G_MIRROR_DISK_STATE_ACTIVE || + disk->d_state == G_MIRROR_DISK_STATE_SYNCHRONIZING) { + g_mirror_update_metadata(disk); + } + } +} + +static void g_mirror_idle(struct g_mirror_softc *sc) { struct g_mirror_disk *disk; @@ -880,7 +902,7 @@ g_mirror_regular_request(struct bio *bp) G_MIRROR_LOGREQ(0, bp, "Request failed (error=%d).", bp->bio_error); if (disk != NULL) { - sc->sc_bump_syncid = G_MIRROR_BUMP_IMMEDIATELY; + sc->sc_bump_id |= G_MIRROR_BUMP_GENID_IMM; g_mirror_event_send(disk, G_MIRROR_DISK_STATE_DISCONNECTED, G_MIRROR_EVENT_DONTWAIT); @@ -1062,7 +1084,7 @@ g_mirror_sync_request(struct bio *bp) "Synchronization request failed (error=%d).", bp->bio_error); g_destroy_bio(bp); - sc->sc_bump_syncid = G_MIRROR_BUMP_IMMEDIATELY; + sc->sc_bump_id |= G_MIRROR_BUMP_GENID_IMM; g_mirror_event_send(disk, G_MIRROR_DISK_STATE_DISCONNECTED, G_MIRROR_EVENT_DONTWAIT); @@ -1381,8 +1403,8 @@ g_mirror_register_request(struct bio *bp) /* * Bump syncid on first write. */ - if (sc->sc_bump_syncid == G_MIRROR_BUMP_ON_FIRST_WRITE) { - sc->sc_bump_syncid = 0; + if ((sc->sc_bump_id & G_MIRROR_BUMP_SYNCID_OFW) != 0) { + sc->sc_bump_id &= ~G_MIRROR_BUMP_SYNCID; g_topology_lock(); g_mirror_bump_syncid(sc); g_topology_unlock(); @@ -1422,23 +1444,18 @@ static int g_mirror_try_destroy(struct g_mirror_softc *sc) { + g_topology_lock(); + if (!g_mirror_can_destroy(sc)) { + g_topology_unlock(); + return (0); + } if ((sc->sc_flags & G_MIRROR_DEVICE_FLAG_WAIT) != 0) { - g_topology_lock(); - if (!g_mirror_can_destroy(sc)) { - g_topology_unlock(); - return (0); - } g_topology_unlock(); G_MIRROR_DEBUG(4, "%s: Waking up %p.", __func__, &sc->sc_worker); wakeup(&sc->sc_worker); sc->sc_worker = NULL; } else { - g_topology_lock(); - if (!g_mirror_can_destroy(sc)) { - g_topology_unlock(); - return (0); - } g_mirror_destroy_device(sc); g_topology_unlock(); free(sc, M_MIRROR); @@ -1861,8 +1878,8 @@ g_mirror_update_device(struct g_mirror_softc *sc, boolean_t force) switch (sc->sc_state) { case G_MIRROR_DEVICE_STATE_STARTING: { - struct g_mirror_disk *pdisk; - u_int dirty, ndisks, syncid; + struct g_mirror_disk *pdisk, *tdisk; + u_int dirty, ndisks, genid, syncid; KASSERT(sc->sc_provider == NULL, ("Non-NULL provider in STARTING state (%s).", sc->sc_name)); @@ -1911,7 +1928,28 @@ g_mirror_update_device(struct g_mirror_softc *sc, boolean_t force) } /* - * Find disk with the biggest syncid. + * Find the biggest genid. + */ + genid = 0; + LIST_FOREACH(disk, &sc->sc_disks, d_next) { + if (disk->d_genid > genid) + genid = disk->d_genid; + } + sc->sc_genid = genid; + /* + * Remove all disks without the biggest genid. + */ + LIST_FOREACH_SAFE(disk, &sc->sc_disks, d_next, tdisk) { + if (disk->d_genid < genid) { + G_MIRROR_DEBUG(0, + "Component %s (device %s) broken, skipping.", + g_mirror_get_diskname(disk), sc->sc_name); + g_mirror_destroy_disk(disk); + } + } + + /* + * Find the biggest syncid. */ syncid = 0; LIST_FOREACH(disk, &sc->sc_disks, d_next) { @@ -1999,7 +2037,7 @@ g_mirror_update_device(struct g_mirror_softc *sc, boolean_t force) sc->sc_syncid = syncid; if (force) { /* Remember to bump syncid on first write. */ - sc->sc_bump_syncid = G_MIRROR_BUMP_ON_FIRST_WRITE; + sc->sc_bump_id |= G_MIRROR_BUMP_SYNCID_OFW; } state = G_MIRROR_DEVICE_STATE_RUNNING; G_MIRROR_DEBUG(1, "Device %s state changed from %s to %s.", @@ -2010,10 +2048,8 @@ g_mirror_update_device(struct g_mirror_softc *sc, boolean_t force) state = g_mirror_determine_state(disk); g_mirror_event_send(disk, state, G_MIRROR_EVENT_DONTWAIT); - if (state == G_MIRROR_DISK_STATE_STALE) { - sc->sc_bump_syncid = - G_MIRROR_BUMP_ON_FIRST_WRITE; - } + if (state == G_MIRROR_DISK_STATE_STALE) + sc->sc_bump_id |= G_MIRROR_BUMP_SYNCID_OFW; } wakeup(&g_mirror_class); break; @@ -2042,10 +2078,14 @@ g_mirror_update_device(struct g_mirror_softc *sc, boolean_t force) /* * Bump syncid here, if we need to do it immediately. */ - if (sc->sc_bump_syncid == G_MIRROR_BUMP_IMMEDIATELY) { - sc->sc_bump_syncid = 0; + if ((sc->sc_bump_id & G_MIRROR_BUMP_SYNCID_IMM) != 0) { + sc->sc_bump_id &= ~G_MIRROR_BUMP_SYNCID; g_mirror_bump_syncid(sc); } + if ((sc->sc_bump_id & G_MIRROR_BUMP_GENID_IMM) != 0) { + sc->sc_bump_id &= ~G_MIRROR_BUMP_GENID; + g_mirror_bump_genid(sc); + } break; default: KASSERT(1 == 0, ("Wrong device state (%s, %s).", @@ -2233,8 +2273,8 @@ again: * Reset bumping syncid if disk disappeared in STARTING * state. */ - if (sc->sc_bump_syncid == G_MIRROR_BUMP_ON_FIRST_WRITE) - sc->sc_bump_syncid = 0; + if ((sc->sc_bump_id & G_MIRROR_BUMP_SYNCID_OFW) != 0) + sc->sc_bump_id &= ~G_MIRROR_BUMP_SYNCID; #ifdef INVARIANTS } else { KASSERT(1 == 0, ("Wrong device state (%s, %s, %s, %s).", @@ -2296,6 +2336,8 @@ g_mirror_read_metadata(struct g_consumer *cp, struct g_mirror_metadata *md) g_topology_lock(); g_access(cp, -1, 0, 0); if (error != 0) { + G_MIRROR_DEBUG(1, "Cannot read metadata from %s (error=%d).", + cp->provider->name, error); if (buf != NULL) g_free(buf); return (error); @@ -2306,6 +2348,12 @@ g_mirror_read_metadata(struct g_consumer *cp, struct g_mirror_metadata *md) g_free(buf); if (strcmp(md->md_magic, G_MIRROR_MAGIC) != 0) return (EINVAL); + if (md->md_version > G_MIRROR_VERSION) { + G_MIRROR_DEBUG(0, + "Kernel module is too old to handle metadata from %s.", + cp->provider->name); + return (EINVAL); + } if (error != 0) { G_MIRROR_DEBUG(1, "MD5 metadata hash mismatch for provider %s.", cp->provider->name); @@ -2395,12 +2443,25 @@ g_mirror_add_disk(struct g_mirror_softc *sc, struct g_provider *pp, error = g_mirror_check_metadata(sc, pp, md); if (error != 0) return (error); + if (sc->sc_state == G_MIRROR_DEVICE_STATE_RUNNING && + md->md_genid < sc->sc_genid) { + G_MIRROR_DEBUG(0, "Component %s (device %s) broken, skipping.", + pp->name, sc->sc_name); + return (EINVAL); + } disk = g_mirror_init_disk(sc, pp, md, &error); if (disk == NULL) return (error); error = g_mirror_event_send(disk, G_MIRROR_DISK_STATE_NEW, G_MIRROR_EVENT_WAIT); - return (error); + if (error != 0) + return (error); + if (md->md_version < G_MIRROR_VERSION) { + G_MIRROR_DEBUG(0, "Upgrading metadata on %s (v%d->v%d).", + pp->name, md->md_version, G_MIRROR_VERSION); + g_mirror_update_metadata(disk); + } + return (0); } static int @@ -2481,7 +2542,7 @@ g_mirror_create(struct g_class *mp, const struct g_mirror_metadata *md) sc->sc_sectorsize = md->md_sectorsize; sc->sc_ndisks = md->md_all; sc->sc_flags = md->md_mflags; - sc->sc_bump_syncid = 0; + sc->sc_bump_id = 0; sc->sc_idle = 0; bioq_init(&sc->sc_queue); mtx_init(&sc->sc_queue_mtx, "gmirror:queue", NULL, MTX_DEF); @@ -2599,11 +2660,6 @@ g_mirror_taste(struct g_class *mp, struct g_provider *pp, int flags __unused) return (NULL); gp = NULL; - if (md.md_version > G_MIRROR_VERSION) { - printf("geom_mirror.ko module is too old to handle %s.\n", - pp->name); - return (NULL); - } if (md.md_provider[0] != '\0' && strcmp(md.md_provider, pp->name) != 0) return (NULL); if ((md.md_dflags & G_MIRROR_DISK_FLAG_INACTIVE) != 0) { @@ -2699,6 +2755,8 @@ g_mirror_dumpconf(struct sbuf *sb, const char *indent, struct g_geom *gp, } sbuf_printf(sb, "%s<SyncID>%u</SyncID>\n", indent, disk->d_sync.ds_syncid); + sbuf_printf(sb, "%s<GenID>%u</GenID>\n", indent, + disk->d_genid); sbuf_printf(sb, "%s<Flags>", indent); if (disk->d_flags == 0) sbuf_printf(sb, "NONE"); @@ -2730,6 +2788,7 @@ g_mirror_dumpconf(struct sbuf *sb, const char *indent, struct g_geom *gp, } else { sbuf_printf(sb, "%s<ID>%u</ID>\n", indent, (u_int)sc->sc_id); sbuf_printf(sb, "%s<SyncID>%u</SyncID>\n", indent, sc->sc_syncid); + sbuf_printf(sb, "%s<GenID>%u</GenID>\n", indent, sc->sc_genid); sbuf_printf(sb, "%s<Flags>", indent); if (sc->sc_flags == 0) sbuf_printf(sb, "NONE"); diff --git a/sys/geom/mirror/g_mirror.h b/sys/geom/mirror/g_mirror.h index a9cb27c..b80308d 100644 --- a/sys/geom/mirror/g_mirror.h +++ b/sys/geom/mirror/g_mirror.h @@ -35,7 +35,13 @@ #define G_MIRROR_CLASS_NAME "MIRROR" #define G_MIRROR_MAGIC "GEOM::MIRROR" -#define G_MIRROR_VERSION 1 +/* + * Version history: + * 0 - Initial version number. + * 1 - Added 'prefer' balance algorithm. + * 2 - Added md_genid field to metadata. + */ +#define G_MIRROR_VERSION 2 #define G_MIRROR_BALANCE_NONE 0 #define G_MIRROR_BALANCE_ROUND_ROBIN 1 @@ -125,6 +131,7 @@ struct g_mirror_disk { struct bintime d_delay; /* Disk delay. */ struct bintime d_last_used; /* When disk was last used. */ uint64_t d_flags; /* Additional flags. */ + u_int d_genid; /* Disk's generation ID. */ struct g_mirror_disk_sync d_sync;/* Sync information. */ LIST_ENTRY(g_mirror_disk) d_next; }; @@ -148,8 +155,15 @@ struct g_mirror_event { #define G_MIRROR_DEVICE_STATE_STARTING 0 #define G_MIRROR_DEVICE_STATE_RUNNING 1 -#define G_MIRROR_BUMP_ON_FIRST_WRITE 1 -#define G_MIRROR_BUMP_IMMEDIATELY 2 +/* Bump syncid on first write. */ +#define G_MIRROR_BUMP_SYNCID_OFW 0x1 +/* Bump syncid immediately. */ +#define G_MIRROR_BUMP_SYNCID_IMM 0x2 +#define G_MIRROR_BUMP_SYNCID (G_MIRROR_BUMP_SYNCID_OFW | \ + G_MIRROR_BUMP_SYNCID_IMM) +/* Bump genid immediately. */ +#define G_MIRROR_BUMP_GENID_IMM 0x4 +#define G_MIRROR_BUMP_GENID (G_MIRROR_BUMP_GENID_IMM) struct g_mirror_softc { u_int sc_state; /* Device state. */ uint32_t sc_slice; /* Slice size. */ @@ -171,8 +185,9 @@ struct g_mirror_softc { u_int sc_ndisks; /* Number of disks. */ struct g_mirror_disk *sc_hint; + u_int sc_genid; /* Generation ID. */ u_int sc_syncid; /* Synchronization ID. */ - int sc_bump_syncid; + int sc_bump_id; struct g_mirror_device_sync sc_sync; int sc_idle; /* DIRTY flags removed. */ @@ -201,6 +216,7 @@ struct g_mirror_metadata { uint32_t md_mid; /* Mirror unique ID. */ uint32_t md_did; /* Disk unique ID. */ uint8_t md_all; /* Number of disks in mirror. */ + uint32_t md_genid; /* Generation ID. */ uint32_t md_syncid; /* Synchronization ID. */ uint8_t md_priority; /* Disk priority. */ uint32_t md_slice; /* Slice size. */ @@ -225,28 +241,27 @@ mirror_metadata_encode(struct g_mirror_metadata *md, u_char *data) le32enc(data + 36, md->md_mid); le32enc(data + 40, md->md_did); *(data + 44) = md->md_all; - le32enc(data + 45, md->md_syncid); - *(data + 49) = md->md_priority; - le32enc(data + 50, md->md_slice); - *(data + 54) = md->md_balance; - le64enc(data + 55, md->md_mediasize); - le32enc(data + 63, md->md_sectorsize); - le64enc(data + 67, md->md_sync_offset); - le64enc(data + 75, md->md_mflags); - le64enc(data + 83, md->md_dflags); - bcopy(md->md_provider, data + 91, 16); + le32enc(data + 45, md->md_genid); + le32enc(data + 49, md->md_syncid); + *(data + 53) = md->md_priority; + le32enc(data + 54, md->md_slice); + *(data + 58) = md->md_balance; + le64enc(data + 59, md->md_mediasize); + le32enc(data + 67, md->md_sectorsize); + le64enc(data + 71, md->md_sync_offset); + le64enc(data + 79, md->md_mflags); + le64enc(data + 87, md->md_dflags); + bcopy(md->md_provider, data + 95, 16); MD5Init(&ctx); - MD5Update(&ctx, data, 107); + MD5Update(&ctx, data, 111); MD5Final(md->md_hash, &ctx); - bcopy(md->md_hash, data + 107, 16); + bcopy(md->md_hash, data + 111, 16); } static __inline int -mirror_metadata_decode(const u_char *data, struct g_mirror_metadata *md) +mirror_metadata_decode_v0v1(const u_char *data, struct g_mirror_metadata *md) { MD5_CTX ctx; - bcopy(data, md->md_magic, 16); - md->md_version = le32dec(data + 16); bcopy(data + 20, md->md_name, 16); md->md_mid = le32dec(data + 36); md->md_did = le32dec(data + 40); @@ -267,8 +282,61 @@ mirror_metadata_decode(const u_char *data, struct g_mirror_metadata *md) MD5Final(md->md_hash, &ctx); if (bcmp(md->md_hash, data + 107, 16) != 0) return (EINVAL); + + /* New fields. */ + md->md_genid = 0; + return (0); } +static __inline int +mirror_metadata_decode_v2(const u_char *data, struct g_mirror_metadata *md) +{ + MD5_CTX ctx; + + bcopy(data + 20, md->md_name, 16); + md->md_mid = le32dec(data + 36); + md->md_did = le32dec(data + 40); + md->md_all = *(data + 44); + md->md_genid = le32dec(data + 45); + md->md_syncid = le32dec(data + 49); + md->md_priority = *(data + 53); + md->md_slice = le32dec(data + 54); + md->md_balance = *(data + 58); + md->md_mediasize = le64dec(data + 59); + md->md_sectorsize = le32dec(data + 67); + md->md_sync_offset = le64dec(data + 71); + md->md_mflags = le64dec(data + 79); + md->md_dflags = le64dec(data + 87); + bcopy(data + 95, md->md_provider, 16); + bcopy(data + 111, md->md_hash, 16); + MD5Init(&ctx); + MD5Update(&ctx, data, 111); + MD5Final(md->md_hash, &ctx); + if (bcmp(md->md_hash, data + 111, 16) != 0) + return (EINVAL); + return (0); +} +static __inline int +mirror_metadata_decode(const u_char *data, struct g_mirror_metadata *md) +{ + int error; + + bcopy(data, md->md_magic, 16); + md->md_version = le32dec(data + 16); + switch (md->md_version) { + case 0: + case 1: + error = mirror_metadata_decode_v0v1(data, md); + break; + case 2: + error = mirror_metadata_decode_v2(data, md); + break; + default: + error = EINVAL; + break; + } + return (error); +} static __inline const char * balance_name(u_int balance) @@ -320,6 +388,7 @@ mirror_metadata_dump(const struct g_mirror_metadata *md) printf(" mid: %u\n", (u_int)md->md_mid); printf(" did: %u\n", (u_int)md->md_did); printf(" all: %u\n", (u_int)md->md_all); + printf(" genid: %u\n", (u_int)md->md_genid); printf(" syncid: %u\n", (u_int)md->md_syncid); printf(" priority: %u\n", (u_int)md->md_priority); printf(" slice: %u\n", (u_int)md->md_slice); diff --git a/sys/geom/mirror/g_mirror_ctl.c b/sys/geom/mirror/g_mirror_ctl.c index 2afa1ac..65c52bd 100644 --- a/sys/geom/mirror/g_mirror_ctl.c +++ b/sys/geom/mirror/g_mirror_ctl.c @@ -527,7 +527,7 @@ g_mirror_ctl_deactivate(struct gctl_req *req, struct g_class *mp) disk->d_flags |= G_MIRROR_DISK_FLAG_INACTIVE; disk->d_flags &= ~G_MIRROR_DISK_FLAG_FORCE_SYNC; g_mirror_update_metadata(disk); - sc->sc_bump_syncid = G_MIRROR_BUMP_ON_FIRST_WRITE; + sc->sc_bump_id |= G_MIRROR_BUMP_SYNCID_OFW; g_mirror_event_send(disk, G_MIRROR_DISK_STATE_DISCONNECTED, G_MIRROR_EVENT_WAIT); } |