- Add support for 'round-robin' and 'verify' modes. - Make kern.geom.raid3.debug sysctl tunable. - Add warnings. - Bump version number and add version history. - Don't handle spoiling for synchronization geom. - Skip providers with 0 sectorsize. --- class/raid3/geom_raid3.c Mon Aug 16 08:23:13 2004 +++ sbin/geom/class/raid3/geom_raid3.c Tue Aug 31 00:08:00 2004 @@ -25,7 +25,7 @@ */ #include -__FBSDID("$FreeBSD: src/sbin/geom/class/raid3/geom_raid3.c,v 1.1 2004/08/16 06:23:13 pjd Exp $"); +__FBSDID("$FreeBSD: src/sbin/geom/class/raid3/geom_raid3.c,v 1.6 2004/08/30 22:08:00 pjd Exp $"); #include #include @@ -58,6 +58,10 @@ { 'd', "dynamic", NULL, G_TYPE_NONE }, { 'h', "hardcode", NULL, G_TYPE_NONE }, { 'n', "noautosync", NULL, G_TYPE_NONE }, + { 'r', "round_robin", NULL, G_TYPE_NONE }, + { 'R', "noround_robin", NULL, G_TYPE_NONE }, + { 'w', "verify", NULL, G_TYPE_NONE }, + { 'W', "noverify", NULL, G_TYPE_NONE }, G_OPT_SENTINEL } }, @@ -73,6 +77,8 @@ { { 'h', "hardcode", NULL, G_TYPE_NONE }, { 'n', "noautosync", NULL, G_TYPE_NONE }, + { 'r', "round_robin", NULL, G_TYPE_NONE }, + { 'w', "verify", NULL, G_TYPE_NONE }, G_OPT_SENTINEL } }, @@ -99,14 +105,14 @@ usage(const char *comm) { fprintf(stderr, - "usage: %s label [-hnv] name prov prov prov [prov [...]]\n" + "usage: %s label [-hnrvw] name prov prov prov [prov [...]]\n" " %s clear [-v] prov [prov [...]]\n" " %s dump prov [prov [...]]\n" - " %s configure [-adhnv] name\n" + " %s configure [-adhnrRvwW] name\n" " %s rebuild [-v] name prov\n" " %s insert [-hv] <-n number> name prov\n" " %s remove [-v] <-n number> name\n" - " %s stop [-fv] name\n", + " %s stop [-fv] name [...]\n", comm, comm, comm, comm, comm, comm, comm, comm); exit(EXIT_FAILURE); } @@ -141,9 +147,10 @@ u_char sector[512]; const char *str; char param[16]; - int *hardcode, *nargs, *noautosync, error, i; - unsigned sectorsize; - off_t mediasize; + int *hardcode, *nargs, *noautosync, *round_robin, *verify; + int error, i; + unsigned sectorsize, ssize; + off_t mediasize, msize; nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs)); if (nargs == NULL) { @@ -184,6 +191,24 @@ } if (*noautosync) md.md_mflags |= G_RAID3_DEVICE_FLAG_NOAUTOSYNC; + round_robin = gctl_get_paraml(req, "round_robin", sizeof(*round_robin)); + if (round_robin == NULL) { + gctl_error(req, "No '%s' argument.", "round_robin"); + return; + } + if (*round_robin) + md.md_mflags |= G_RAID3_DEVICE_FLAG_ROUND_ROBIN; + verify = gctl_get_paraml(req, "verify", sizeof(*verify)); + if (verify == NULL) { + gctl_error(req, "No '%s' argument.", "verify"); + return; + } + if (*verify) + md.md_mflags |= G_RAID3_DEVICE_FLAG_VERIFY; + if (*round_robin && *verify) { + gctl_error(req, "Both '%c' and '%c' options given.", 'r', 'w'); + return; + } hardcode = gctl_get_paraml(req, "hardcode", sizeof(*hardcode)); if (hardcode == NULL) { gctl_error(req, "No '%s' argument.", "hardcode"); @@ -197,9 +222,6 @@ mediasize = 0; sectorsize = 0; for (i = 1; i < *nargs; i++) { - unsigned ssize; - off_t msize; - snprintf(param, sizeof(param), "arg%u", i); str = gctl_get_asciiparam(req, param); @@ -243,6 +265,13 @@ snprintf(param, sizeof(param), "arg%u", i); str = gctl_get_asciiparam(req, param); + msize = g_get_mediasize(str) - g_get_sectorsize(str); + if (mediasize < msize) { + fprintf(stderr, + "warning: %s: only %jd bytes from %jd bytes used.\n", + str, (intmax_t)mediasize, (intmax_t)msize); + } + md.md_no = i - 1; if (!*hardcode) bzero(md.md_provider, sizeof(md.md_provider)); @@ -250,6 +279,13 @@ if (strncmp(str, _PATH_DEV, strlen(_PATH_DEV)) == 0) str += strlen(_PATH_DEV); strlcpy(md.md_provider, str, sizeof(md.md_provider)); + } + if (*verify && md.md_no == md.md_all - 1) { + /* + * In "verify" mode, force synchronization of parity + * component on start. + */ + md.md_syncid = 0; } raid3_metadata_encode(&md, sector); error = g_metadata_store(str, sector, sizeof(sector)); --- ../../sys/geom/raid3/g_raid3.c Mon Aug 16 12:33:35 2004 +++ sys/geom/raid3/g_raid3.c Mon Aug 30 20:50:05 2004 @@ -25,7 +25,7 @@ */ #include -__FBSDID("$FreeBSD: src/sys/geom/raid3/g_raid3.c,v 1.4 2004/08/16 10:33:35 obrien Exp $"); +__FBSDID("$FreeBSD: src/sys/geom/raid3/g_raid3.c,v 1.13 2004/08/30 18:50:05 pjd Exp $"); #include #include @@ -51,6 +51,7 @@ SYSCTL_DECL(_kern_geom); SYSCTL_NODE(_kern_geom, OID_AUTO, raid3, CTLFLAG_RW, 0, "GEOM_RAID3 stuff"); u_int g_raid3_debug = 0; +TUNABLE_INT("kern.geom.raid3.debug", &g_raid3_debug); SYSCTL_UINT(_kern_geom_raid3, OID_AUTO, debug, CTLFLAG_RW, &g_raid3_debug, 0, "Debug level"); static u_int g_raid3_timeout = 8; @@ -80,6 +81,9 @@ SYSCTL_NODE(_kern_geom_raid3, OID_AUTO, stat, CTLFLAG_RW, 0, "GEOM_RAID3 statistics"); +static u_int g_raid3_parity_mismatch = 0; +SYSCTL_UINT(_kern_geom_raid3_stat, OID_AUTO, parity_mismatch, CTLFLAG_RD, + &g_raid3_parity_mismatch, 0, "Number of failures in VERIFY mode"); static u_int g_raid3_64k_requested = 0; SYSCTL_UINT(_kern_geom_raid3_stat, OID_AUTO, 64k_requested, CTLFLAG_RD, &g_raid3_64k_requested, 0, "Number of requested 64kB allocations"); @@ -214,6 +218,24 @@ } } +static int +g_raid3_is_zero(struct bio *bp) +{ + static const uint64_t zeros[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }; + u_char *addr; + ssize_t size; + + size = bp->bio_length; + addr = (u_char *)bp->bio_data; + for (; size > 0; size -= sizeof(zeros), addr += sizeof(zeros)) { + if (bcmp(addr, zeros, sizeof(zeros)) != 0) + return (0); + } + return (1); +} + /* * --- Events handling functions --- * Events in geom_raid3 are used to maintain disks and device status @@ -727,6 +749,46 @@ } static void +g_raid3_remove_bio(struct bio *cbp) +{ + struct bio *pbp, *bp; + + pbp = cbp->bio_parent; + if (G_RAID3_HEAD_BIO(pbp) == cbp) + G_RAID3_HEAD_BIO(pbp) = G_RAID3_NEXT_BIO(cbp); + else { + G_RAID3_FOREACH_BIO(pbp, bp) { + if (G_RAID3_NEXT_BIO(bp) == cbp) { + G_RAID3_NEXT_BIO(bp) = G_RAID3_NEXT_BIO(cbp); + break; + } + } + } + G_RAID3_NEXT_BIO(cbp) = NULL; +} + +static void +g_raid3_replace_bio(struct bio *sbp, struct bio *dbp) +{ + struct bio *pbp, *bp; + + g_raid3_remove_bio(sbp); + pbp = dbp->bio_parent; + G_RAID3_NEXT_BIO(sbp) = G_RAID3_NEXT_BIO(dbp); + if (G_RAID3_HEAD_BIO(pbp) == dbp) + G_RAID3_HEAD_BIO(pbp) = sbp; + else { + G_RAID3_FOREACH_BIO(pbp, bp) { + if (G_RAID3_NEXT_BIO(bp) == dbp) { + G_RAID3_NEXT_BIO(bp) = sbp; + break; + } + } + } + G_RAID3_NEXT_BIO(dbp) = NULL; +} + +static void g_raid3_destroy_bio(struct g_raid3_softc *sc, struct bio *cbp) { struct bio *bp, *pbp; @@ -751,10 +813,12 @@ if (G_RAID3_NEXT_BIO(bp) == cbp) break; } - KASSERT(bp != NULL, ("NULL bp")); - KASSERT(G_RAID3_NEXT_BIO(bp) != NULL, ("NULL bp->bio_driver1")); - G_RAID3_NEXT_BIO(bp) = G_RAID3_NEXT_BIO(cbp); - G_RAID3_NEXT_BIO(cbp) = NULL; + if (bp != NULL) { + KASSERT(G_RAID3_NEXT_BIO(bp) != NULL, + ("NULL bp->bio_driver1")); + G_RAID3_NEXT_BIO(bp) = G_RAID3_NEXT_BIO(cbp); + G_RAID3_NEXT_BIO(cbp) = NULL; + } g_destroy_bio(cbp); } } @@ -872,121 +936,116 @@ { struct g_raid3_softc *sc; struct g_raid3_disk *disk; - struct bio *bp, *cbp; + struct bio *xbp, *fbp, *cbp; off_t atom, cadd, padd, left; sc = pbp->bio_to->geom->softc; - if ((pbp->bio_pflags & G_RAID3_BIO_PFLAG_DEGRADED) != 0) { + /* + * Find bio for which we have to calculate data. + * While going through this path, check if all requests + * succeeded, if not, deny whole request. + * If we're in COMPLETE mode, we allow one request to fail, + * so if we find one, we're sending it to the parity consumer. + * If there are more failed requests, we deny whole request. + */ + xbp = fbp = NULL; + G_RAID3_FOREACH_BIO(pbp, cbp) { + if ((cbp->bio_cflags & G_RAID3_BIO_CFLAG_PARITY) != 0) { + KASSERT(xbp == NULL, ("More than one parity bio.")); + xbp = cbp; + } + if (cbp->bio_error == 0) + continue; /* - * Find bio for which we should calculate data. - * While going through this path, check if all requests - * succeeded, if not, deny whole request. + * Found failed request. */ - bp = NULL; - G_RAID3_FOREACH_BIO(pbp, cbp) { - if ((cbp->bio_cflags & G_RAID3_BIO_CFLAG_PARITY) != 0) { - KASSERT(bp == NULL, - ("More than one parity bio.")); - bp = cbp; - } - if (cbp->bio_error == 0) - continue; + G_RAID3_LOGREQ(0, cbp, "Request failed."); + disk = cbp->bio_caller2; + if (disk != NULL) { /* - * Found failed request. + * Actually this is pointless to bump syncid, + * because whole device is fucked up. */ - if (pbp->bio_error == 0) - pbp->bio_error = cbp->bio_error; - disk = cbp->bio_caller2; - if (disk != NULL) { + sc->sc_bump_syncid = G_RAID3_BUMP_IMMEDIATELY; + g_raid3_event_send(disk, + G_RAID3_DISK_STATE_DISCONNECTED, + G_RAID3_EVENT_DONTWAIT); + } + if (fbp == NULL) { + if ((pbp->bio_pflags & G_RAID3_BIO_PFLAG_DEGRADED) != 0) { /* - * Actually this is pointless to bump syncid, - * because whole device is fucked up. + * We are already in degraded mode, so we can't + * accept any failures. */ - sc->sc_bump_syncid = G_RAID3_BUMP_IMMEDIATELY; - g_raid3_event_send(disk, - G_RAID3_DISK_STATE_DISCONNECTED, - G_RAID3_EVENT_DONTWAIT); + if (pbp->bio_error == 0) + pbp->bio_error = fbp->bio_error; + } else { + fbp = cbp; } - } - KASSERT(bp != NULL, ("NULL parity bio.")); - if (pbp->bio_error != 0) { + } else { /* - * Deny whole request. + * Next failed request, that's too many. */ - goto finish; + if (pbp->bio_error == 0) + pbp->bio_error = fbp->bio_error; } + } + if (pbp->bio_error != 0) + goto finish; + if (fbp != NULL && (pbp->bio_pflags & G_RAID3_BIO_PFLAG_VERIFY) != 0) { + pbp->bio_pflags &= ~G_RAID3_BIO_PFLAG_VERIFY; + if (xbp != fbp) + g_raid3_replace_bio(xbp, fbp); + g_raid3_destroy_bio(sc, fbp); + } else if (fbp != NULL) { + struct g_consumer *cp; + /* - * Calculate parity. + * One request failed, so send the same request to + * the parity consumer. */ - G_RAID3_FOREACH_BIO(pbp, cbp) { - if ((cbp->bio_cflags & G_RAID3_BIO_CFLAG_PARITY) != 0) - continue; - g_raid3_xor(cbp->bio_data, bp->bio_data, bp->bio_data, - bp->bio_length); + disk = pbp->bio_driver2; + if (disk->d_state != G_RAID3_DISK_STATE_ACTIVE) { + pbp->bio_error = fbp->bio_error; + goto finish; } - bp->bio_cflags &= ~G_RAID3_BIO_CFLAG_PARITY; - } else { + pbp->bio_pflags |= G_RAID3_BIO_PFLAG_DEGRADED; + pbp->bio_inbed--; + fbp->bio_flags &= ~(BIO_DONE | BIO_ERROR); + if (disk->d_no == sc->sc_ndisks - 1) + fbp->bio_cflags |= G_RAID3_BIO_CFLAG_PARITY; + fbp->bio_error = 0; + fbp->bio_completed = 0; + fbp->bio_children = 0; + fbp->bio_inbed = 0; + cp = disk->d_consumer; + fbp->bio_caller2 = disk; + fbp->bio_to = cp->provider; + G_RAID3_LOGREQ(3, fbp, "Sending request (recover)."); + KASSERT(cp->acr > 0 && cp->ace > 0, + ("Consumer %s not opened (r%dw%de%d).", cp->provider->name, + cp->acr, cp->acw, cp->ace)); + g_io_request(fbp, cp); + return; + } + if (xbp != NULL) { /* - * If we're in COMPLETE mode, we allow one request to fail, - * so if we find one, we're sending it to the parity consumer. - * If there are more failed requests, we deny whole request. + * Calculate parity. */ - bp = NULL; G_RAID3_FOREACH_BIO(pbp, cbp) { - if (cbp->bio_error == 0) + if ((cbp->bio_cflags & G_RAID3_BIO_CFLAG_PARITY) != 0) continue; - /* - * Found failed request. - */ - G_RAID3_LOGREQ(0, cbp, "Request failed."); - disk = cbp->bio_caller2; - if (disk != NULL) { - sc->sc_bump_syncid = G_RAID3_BUMP_IMMEDIATELY; - g_raid3_event_send(disk, - G_RAID3_DISK_STATE_DISCONNECTED, - G_RAID3_EVENT_DONTWAIT); - } - if (bp == NULL) - bp = cbp; - else { - /* - * Next failed request, that's too many. - */ - if (pbp->bio_error == 0) - pbp->bio_error = bp->bio_error; - } + g_raid3_xor(cbp->bio_data, xbp->bio_data, xbp->bio_data, + xbp->bio_length); } - if (pbp->bio_error != 0) - goto finish; - if (bp != NULL) { - struct g_consumer *cp; - - /* - * One request failed, so send the same request to - * the parity consumer. - */ - disk = &sc->sc_disks[sc->sc_ndisks - 1]; - if (disk->d_state != G_RAID3_DISK_STATE_ACTIVE) { - pbp->bio_error = bp->bio_error; + xbp->bio_cflags &= ~G_RAID3_BIO_CFLAG_PARITY; + if ((pbp->bio_pflags & G_RAID3_BIO_PFLAG_VERIFY) != 0) { + if (!g_raid3_is_zero(xbp)) { + g_raid3_parity_mismatch++; + pbp->bio_error = EIO; goto finish; } - pbp->bio_pflags |= G_RAID3_BIO_PFLAG_DEGRADED; - pbp->bio_inbed--; - bp->bio_flags &= ~(BIO_DONE | BIO_ERROR); - bp->bio_cflags |= G_RAID3_BIO_CFLAG_PARITY; - bp->bio_error = 0; - bp->bio_completed = 0; - bp->bio_children = 0; - bp->bio_inbed = 0; - cp = disk->d_consumer; - bp->bio_caller2 = disk; - bp->bio_to = cp->provider; - G_RAID3_LOGREQ(3, bp, "Sending request (parity)."); - KASSERT(cp->acr > 0 && cp->ace > 0, - ("Consumer %s not opened (r%dw%de%d).", cp->provider->name, - cp->acr, cp->acw, cp->ace)); - g_io_request(bp, cp); - return; + g_raid3_destroy_bio(sc, xbp); } } atom = sc->sc_sectorsize / (sc->sc_ndisks - 1); @@ -1002,9 +1061,13 @@ finish: if (pbp->bio_error == 0) G_RAID3_LOGREQ(3, pbp, "Request finished."); - else - G_RAID3_LOGREQ(0, pbp, "Request failed."); - pbp->bio_pflags &= ~G_RAID3_BIO_PFLAG_DEGRADED; + else { + if ((pbp->bio_pflags & G_RAID3_BIO_PFLAG_VERIFY) != 0) + G_RAID3_LOGREQ(1, pbp, "Verification error."); + else + G_RAID3_LOGREQ(0, pbp, "Request failed."); + } + pbp->bio_pflags &= ~G_RAID3_BIO_PFLAG_MASK; g_io_deliver(pbp, pbp->bio_error); while ((cbp = G_RAID3_HEAD_BIO(pbp)) != NULL) g_raid3_destroy_bio(sc, cbp); @@ -1270,7 +1333,7 @@ disk->d_sync.ds_offset_done = bp->bio_offset + bp->bio_length; g_destroy_bio(bp); if (disk->d_sync.ds_offset_done == - sc->sc_provider->mediasize / (sc->sc_ndisks - 1)) { + sc->sc_mediasize / (sc->sc_ndisks - 1)) { /* * Disk up-to-date, activate it. */ @@ -1304,6 +1367,7 @@ struct bio *cbp; off_t offset, length; u_int n, ndisks; + int round_robin, verify; ndisks = 0; sc = pbp->bio_to->geom->softc; @@ -1315,9 +1379,27 @@ g_raid3_init_bio(pbp); length = pbp->bio_length / (sc->sc_ndisks - 1); offset = pbp->bio_offset / (sc->sc_ndisks - 1); + round_robin = verify = 0; switch (pbp->bio_cmd) { case BIO_READ: - ndisks = sc->sc_ndisks - 1; + if ((sc->sc_flags & G_RAID3_DEVICE_FLAG_VERIFY) != 0 && + sc->sc_state == G_RAID3_DEVICE_STATE_COMPLETE) { + pbp->bio_pflags |= G_RAID3_BIO_PFLAG_VERIFY; + verify = 1; + ndisks = sc->sc_ndisks; + } else { + verify = 0; + ndisks = sc->sc_ndisks - 1; + } + if ((sc->sc_flags & G_RAID3_DEVICE_FLAG_ROUND_ROBIN) != 0 && + sc->sc_state == G_RAID3_DEVICE_STATE_COMPLETE) { + round_robin = 1; + } else { + round_robin = 0; + } + KASSERT(!round_robin || !verify, + ("ROUND-ROBIN and VERIFY are mutually exclusive.")); + pbp->bio_driver2 = &sc->sc_disks[sc->sc_ndisks - 1]; break; case BIO_WRITE: case BIO_DELETE: @@ -1345,6 +1427,19 @@ disk = &sc->sc_disks[sc->sc_ndisks - 1]; cbp->bio_cflags |= G_RAID3_BIO_CFLAG_PARITY; pbp->bio_pflags |= G_RAID3_BIO_PFLAG_DEGRADED; + } else if (round_robin && + disk->d_no == sc->sc_round_robin) { + /* + * In round-robin mode skip one data component + * and use parity component when reading. + */ + pbp->bio_driver2 = disk; + disk = &sc->sc_disks[sc->sc_ndisks - 1]; + cbp->bio_cflags |= G_RAID3_BIO_CFLAG_PARITY; + sc->sc_round_robin++; + round_robin = 0; + } else if (verify && disk->d_no == sc->sc_ndisks - 1) { + cbp->bio_cflags |= G_RAID3_BIO_CFLAG_PARITY; } break; case BIO_WRITE: @@ -1382,6 +1477,14 @@ } switch (pbp->bio_cmd) { case BIO_READ: + if (round_robin) { + /* + * If we are in round-robin mode and 'round_robin' is + * still 1, it means, that we skipped parity component + * for this read and must reset sc_round_robin field. + */ + sc->sc_round_robin = 0; + } G_RAID3_FOREACH_BIO(pbp, cbp) { disk = cbp->bio_caller2; cp = disk->d_consumer; @@ -1547,7 +1650,7 @@ nreqs = 0; disk = sc->sc_syncdisk; if (disk->d_sync.ds_offset < - sc->sc_provider->mediasize / (sc->sc_ndisks - 1) && + sc->sc_mediasize / (sc->sc_ndisks - 1) && disk->d_sync.ds_offset == disk->d_sync.ds_offset_done) { g_raid3_sync_one(sc); @@ -2346,6 +2449,15 @@ pp->name, sc->sc_name); return (EINVAL); } + if ((md->md_mflags & G_RAID3_DEVICE_FLAG_VERIFY) != 0 && + (md->md_mflags & G_RAID3_DEVICE_FLAG_ROUND_ROBIN) != 0) { + /* + * VERIFY and ROUND-ROBIN options are mutally exclusive. + */ + G_RAID3_DEBUG(1, "Both VERIFY and ROUND-ROBIN flags exist on " + "disk %s (device %s), skipping.", pp->name, sc->sc_name); + return (EINVAL); + } if ((md->md_dflags & ~G_RAID3_DISK_FLAG_MASK) != 0) { G_RAID3_DEBUG(1, "Invalid disk flags on disk %s (device %s), skipping.", @@ -2474,6 +2586,7 @@ sc->sc_mediasize = md->md_mediasize; sc->sc_sectorsize = md->md_sectorsize; sc->sc_ndisks = md->md_all; + sc->sc_round_robin = 0; sc->sc_flags = md->md_mflags; sc->sc_bump_syncid = 0; for (n = 0; n < sc->sc_ndisks; n++) @@ -2492,7 +2605,6 @@ */ gp = g_new_geomf(mp, "%s.sync", md->md_name); gp->softc = sc; - gp->spoiled = g_raid3_spoiled; gp->orphan = g_raid3_orphan; sc->sc_sync.ds_geom = gp; sc->sc_zone_64k = uma_zcreate("gr3:64k", 65536, NULL, NULL, NULL, NULL, @@ -2592,6 +2704,9 @@ g_topology_assert(); g_trace(G_T_TOPOLOGY, "%s(%s, %s)", __func__, mp->name, pp->name); G_RAID3_DEBUG(2, "Tasting %s.", pp->name); + /* Skip providers with 0 sectorsize. */ + if (pp->sectorsize == 0) + return (NULL); gp = g_new_geomf(mp, "raid3:taste"); /* This orphan function should be never called. */ @@ -2619,6 +2734,7 @@ /* * Let's check if device already exists. */ + sc = NULL; LIST_FOREACH(gp, &mp->geom, geom) { sc = gp->softc; if (sc == NULL) @@ -2702,8 +2818,7 @@ else { sbuf_printf(sb, "%u%%", (u_int)((disk->d_sync.ds_offset_done * 100) / - (sc->sc_provider->mediasize / - (sc->sc_ndisks - 1)))); + (sc->sc_mediasize / (sc->sc_ndisks - 1)))); } sbuf_printf(sb, "\n"); } @@ -2753,11 +2868,16 @@ } \ } while (0) ADD_FLAG(G_RAID3_DEVICE_FLAG_NOAUTOSYNC, "NOAUTOSYNC"); + ADD_FLAG(G_RAID3_DEVICE_FLAG_ROUND_ROBIN, + "ROUND-ROBIN"); + ADD_FLAG(G_RAID3_DEVICE_FLAG_VERIFY, "VERIFY"); #undef ADD_FLAG } sbuf_printf(sb, "\n"); sbuf_printf(sb, "%s%u\n", indent, sc->sc_ndisks); + sbuf_printf(sb, "%s%s\n", indent, + g_raid3_device_state2str(sc->sc_state)); } } --- ../../sys/geom/raid3/g_raid3.h Mon Aug 16 08:23:14 2004 +++ sys/geom/raid3/g_raid3.h Sat Aug 28 04:18:25 2004 @@ -23,7 +23,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $FreeBSD: src/sys/geom/raid3/g_raid3.h,v 1.1 2004/08/16 06:23:14 pjd Exp $ + * $FreeBSD: src/sys/geom/raid3/g_raid3.h,v 1.4 2004/08/22 16:21:12 pjd Exp $ */ #ifndef _G_RAID3_H_ @@ -35,7 +35,13 @@ #define G_RAID3_CLASS_NAME "RAID3" #define G_RAID3_MAGIC "GEOM::RAID3" -#define G_RAID3_VERSION 0 +/* + * Version history: + * 0 - Initial version number. + * 1 - Added 'round-robin reading' algorithm. + * 2 - Added 'verify reading' algorithm. + */ +#define G_RAID3_VERSION 2 #define G_RAID3_DISK_FLAG_DIRTY 0x0000000000000001ULL #define G_RAID3_DISK_FLAG_SYNCHRONIZING 0x0000000000000002ULL @@ -46,7 +52,11 @@ G_RAID3_DISK_FLAG_FORCE_SYNC) #define G_RAID3_DEVICE_FLAG_NOAUTOSYNC 0x0000000000000001ULL -#define G_RAID3_DEVICE_FLAG_MASK (G_RAID3_DEVICE_FLAG_NOAUTOSYNC) +#define G_RAID3_DEVICE_FLAG_ROUND_ROBIN 0x0000000000000002ULL +#define G_RAID3_DEVICE_FLAG_VERIFY 0x0000000000000004ULL +#define G_RAID3_DEVICE_FLAG_MASK (G_RAID3_DEVICE_FLAG_NOAUTOSYNC | \ + G_RAID3_DEVICE_FLAG_ROUND_ROBIN | \ + G_RAID3_DEVICE_FLAG_VERIFY) #ifdef _KERNEL extern u_int g_raid3_debug; @@ -81,9 +91,18 @@ #define G_RAID3_BIO_CFLAG_PARITY 0x04 #define G_RAID3_BIO_CFLAG_NODISK 0x08 #define G_RAID3_BIO_CFLAG_REGSYNC 0x10 +#define G_RAID3_BIO_CFLAG_MASK (G_RAID3_BIO_CFLAG_REGULAR | \ + G_RAID3_BIO_CFLAG_SYNC | \ + G_RAID3_BIO_CFLAG_PARITY | \ + G_RAID3_BIO_CFLAG_NODISK | \ + G_RAID3_BIO_CFLAG_REGSYNC) #define G_RAID3_BIO_PFLAG_DEGRADED 0x01 #define G_RAID3_BIO_PFLAG_NOPARITY 0x02 +#define G_RAID3_BIO_PFLAG_VERIFY 0x04 +#define G_RAID3_BIO_PFLAG_MASK (G_RAID3_BIO_PFLAG_DEGRADED | \ + G_RAID3_BIO_PFLAG_NOPARITY | \ + G_RAID3_BIO_PFLAG_VERIFY) /* * Informations needed for synchronization. @@ -162,6 +181,7 @@ struct g_raid3_disk *sc_disks; u_int sc_ndisks; /* Number of disks. */ + u_int sc_round_robin; struct g_raid3_disk *sc_syncdisk; uma_zone_t sc_zone_64k; @@ -281,6 +301,10 @@ else { if ((md->md_mflags & G_RAID3_DEVICE_FLAG_NOAUTOSYNC) != 0) printf(" NOAUTOSYNC"); + if ((md->md_mflags & G_RAID3_DEVICE_FLAG_ROUND_ROBIN) != 0) + printf(" ROUND-ROBIN"); + if ((md->md_mflags & G_RAID3_DEVICE_FLAG_VERIFY) != 0) + printf(" VERIFY"); } printf("\n"); printf(" dflags:"); --- ../../sys/geom/raid3/g_raid3_ctl.c Mon Aug 16 08:23:14 2004 +++ sys/geom/raid3/g_raid3_ctl.c Sat Aug 28 04:34:10 2004 @@ -25,7 +25,7 @@ */ #include -__FBSDID("$FreeBSD: src/sys/geom/raid3/g_raid3_ctl.c,v 1.1 2004/08/16 06:23:14 pjd Exp $"); +__FBSDID("$FreeBSD: src/sys/geom/raid3/g_raid3_ctl.c,v 1.5 2004/08/28 02:34:10 pjd Exp $"); #include #include @@ -93,7 +93,10 @@ struct g_raid3_softc *sc; struct g_raid3_disk *disk; const char *name; - int *nargs, *autosync, *noautosync, do_sync = 0; + int *nargs, do_sync = 0; + int *autosync, *noautosync; + int *round_robin, *noround_robin; + int *verify, *noverify; u_int n; g_topology_assert(); @@ -122,15 +125,47 @@ gctl_error(req, "No '%s' argument.", "noautosync"); return; } - if (!*autosync && !*noautosync) { - gctl_error(req, "Nothing has changed."); - return; - } if (*autosync && *noautosync) { gctl_error(req, "'%s' and '%s' specified.", "autosync", "noautosync"); return; } + round_robin = gctl_get_paraml(req, "round_robin", sizeof(*round_robin)); + if (round_robin == NULL) { + gctl_error(req, "No '%s' argument.", "round_robin"); + return; + } + noround_robin = gctl_get_paraml(req, "noround_robin", + sizeof(*noround_robin)); + if (noround_robin == NULL) { + gctl_error(req, "No '%s' argument.", "noround_robin"); + return; + } + if (*round_robin && *noround_robin) { + gctl_error(req, "'%s' and '%s' specified.", "round_robin", + "noround_robin"); + return; + } + verify = gctl_get_paraml(req, "verify", sizeof(*verify)); + if (verify == NULL) { + gctl_error(req, "No '%s' argument.", "verify"); + return; + } + noverify = gctl_get_paraml(req, "noverify", sizeof(*noverify)); + if (noverify == NULL) { + gctl_error(req, "No '%s' argument.", "noverify"); + return; + } + if (*verify && *noverify) { + gctl_error(req, "'%s' and '%s' specified.", "verify", + "noverify"); + return; + } + if (!*autosync && !*noautosync && !*round_robin && !*noround_robin && + !*verify && !*noverify) { + gctl_error(req, "Nothing has changed."); + return; + } if ((sc->sc_flags & G_RAID3_DEVICE_FLAG_NOAUTOSYNC) != 0) { if (*autosync) { sc->sc_flags &= ~G_RAID3_DEVICE_FLAG_NOAUTOSYNC; @@ -140,6 +175,27 @@ if (*noautosync) sc->sc_flags |= G_RAID3_DEVICE_FLAG_NOAUTOSYNC; } + if ((sc->sc_flags & G_RAID3_DEVICE_FLAG_VERIFY) != 0) { + if (*noverify) + sc->sc_flags &= ~G_RAID3_DEVICE_FLAG_VERIFY; + } else { + if (*verify) + sc->sc_flags |= G_RAID3_DEVICE_FLAG_VERIFY; + } + if ((sc->sc_flags & G_RAID3_DEVICE_FLAG_ROUND_ROBIN) != 0) { + if (*noround_robin) + sc->sc_flags &= ~G_RAID3_DEVICE_FLAG_ROUND_ROBIN; + } else { + if (*round_robin) + sc->sc_flags |= G_RAID3_DEVICE_FLAG_ROUND_ROBIN; + } + if ((sc->sc_flags & G_RAID3_DEVICE_FLAG_VERIFY) != 0 && + (sc->sc_flags & G_RAID3_DEVICE_FLAG_ROUND_ROBIN) != 0) { + /* + * VERIFY and ROUND-ROBIN options are mutally exclusive. + */ + sc->sc_flags &= ~G_RAID3_DEVICE_FLAG_ROUND_ROBIN; + } for (n = 0; n < sc->sc_ndisks; n++) { disk = &sc->sc_disks[n]; if (do_sync) { @@ -282,6 +338,7 @@ struct g_consumer *cp; const char *name; u_char *sector; + off_t compsize; intmax_t *no; int *hardcode, *nargs, error; @@ -339,6 +396,17 @@ "Cannot insert provider %s, because of its sector size.", pp->name); return; + } + compsize = sc->sc_mediasize / (sc->sc_ndisks - 1); + if (compsize > pp->mediasize - pp->sectorsize) { + gctl_error(req, "Provider %s too small.", pp->name); + return; + } + if (compsize < pp->mediasize - pp->sectorsize) { + gctl_error(req, + "warning: %s: only %jd bytes from %jd bytes used.", + pp->name, (intmax_t)compsize, + (intmax_t)(pp->mediasize - pp->sectorsize)); } gp = g_new_geomf(mp, "raid3:insert"); gp->orphan = g_raid3_ctl_insert_orphan;