diff options
author | le <le@FreeBSD.org> | 2004-11-26 12:01:00 +0000 |
---|---|---|
committer | le <le@FreeBSD.org> | 2004-11-26 12:01:00 +0000 |
commit | e257308b07ececec004a50897bcb88d5ae23203e (patch) | |
tree | dd2cb0511f95c52d44ae3ac4b8ed2c625ad75ee9 /sys/geom/vinum/geom_vinum_init.c | |
parent | e2512dff3e6b6f073758b6a5872f46261c09094c (diff) | |
download | FreeBSD-src-e257308b07ececec004a50897bcb88d5ae23203e.zip FreeBSD-src-e257308b07ececec004a50897bcb88d5ae23203e.tar.gz |
Implement checkparity/rebuildparity.
Diffstat (limited to 'sys/geom/vinum/geom_vinum_init.c')
-rw-r--r-- | sys/geom/vinum/geom_vinum_init.c | 119 |
1 files changed, 119 insertions, 0 deletions
diff --git a/sys/geom/vinum/geom_vinum_init.c b/sys/geom/vinum/geom_vinum_init.c index 46d9d51..95b3d6a 100644 --- a/sys/geom/vinum/geom_vinum_init.c +++ b/sys/geom/vinum/geom_vinum_init.c @@ -58,6 +58,125 @@ struct gv_sync_args { }; void +gv_parityop(struct g_geom *gp, struct gctl_req *req) +{ + struct gv_softc *sc; + struct gv_plex *p; + struct bio *bp; + struct g_consumer *cp; + int error, *flags, type, *rebuild, rv; + char *plex; + + rv = -1; + + plex = gctl_get_param(req, "plex", NULL); + if (plex == NULL) { + gctl_error(req, "no plex given"); + goto out; + } + + flags = gctl_get_paraml(req, "flags", sizeof(*flags)); + if (flags == NULL) { + gctl_error(req, "no flags given"); + goto out; + } + + rebuild = gctl_get_paraml(req, "rebuild", sizeof(*rebuild)); + if (rebuild == NULL) { + gctl_error(req, "no rebuild op given"); + goto out; + } + + sc = gp->softc; + type = gv_object_type(sc, plex); + switch (type) { + case GV_TYPE_PLEX: + break; + case GV_TYPE_VOL: + case GV_TYPE_SD: + case GV_TYPE_DRIVE: + default: + gctl_error(req, "'%s' is not a plex", plex); + goto out; + } + + p = gv_find_plex(sc, plex); + if (p->state != GV_PLEX_UP) { + gctl_error(req, "plex %s is not completely accessible", + p->name); + goto out; + } + + cp = p->consumer; + error = g_access(cp, 1, 1, 0); + if (error) { + gctl_error(req, "cannot access consumer"); + goto out; + } + g_topology_unlock(); + + /* Reset the check pointer when using -f. */ + if (*flags & GV_FLAG_F) + p->synced = 0; + + bp = g_new_bio(); + if (bp == NULL) { + gctl_error(req, "cannot create BIO - out of memory"); + g_topology_lock(); + error = g_access(cp, -1, -1, 0); + goto out; + } + bp->bio_cmd = BIO_WRITE; + bp->bio_done = NULL; + bp->bio_data = g_malloc(p->stripesize, M_WAITOK | M_ZERO); + bp->bio_cflags |= GV_BIO_CHECK; + if (*rebuild) + bp->bio_cflags |= GV_BIO_PARITY; + bp->bio_offset = p->synced; + bp->bio_length = p->stripesize; + + /* Schedule it down ... */ + g_io_request(bp, cp); + + /* ... and wait for the result. */ + error = biowait(bp, "gwrite"); + g_free(bp->bio_data); + g_destroy_bio(bp); + + if (error) { + /* Incorrect parity. */ + if (error == EAGAIN) + rv = 1; + + /* Some other error happened. */ + else + gctl_error(req, "Parity check failed at offset 0x%jx, " + "errno %d", (intmax_t)p->synced, error); + + /* Correct parity. */ + } else + rv = 0; + + gctl_set_param(req, "offset", &p->synced, sizeof(p->synced)); + + /* Advance the checkpointer if there was no error. */ + if (rv == 0) + p->synced += p->stripesize; + + /* End of plex; reset the check pointer and signal it to the caller. */ + if (p->synced >= p->size) { + p->synced = 0; + rv = -2; + } + + g_topology_lock(); + error = g_access(cp, -1, -1, 0); + +out: + gctl_set_param(req, "rv", &rv, sizeof(rv)); +} + +void gv_start_obj(struct g_geom *gp, struct gctl_req *req) { struct gv_softc *sc; |