summaryrefslogtreecommitdiffstats
path: root/sys/geom/vinum/geom_vinum_init.c
diff options
context:
space:
mode:
authorle <le@FreeBSD.org>2004-11-26 12:01:00 +0000
committerle <le@FreeBSD.org>2004-11-26 12:01:00 +0000
commite257308b07ececec004a50897bcb88d5ae23203e (patch)
treedd2cb0511f95c52d44ae3ac4b8ed2c625ad75ee9 /sys/geom/vinum/geom_vinum_init.c
parente2512dff3e6b6f073758b6a5872f46261c09094c (diff)
downloadFreeBSD-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.c119
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;
OpenPOWER on IntegriCloud