diff options
author | le <le@FreeBSD.org> | 2004-06-12 21:16:10 +0000 |
---|---|---|
committer | le <le@FreeBSD.org> | 2004-06-12 21:16:10 +0000 |
commit | cf31d52b42bd2309bb855b34e8260283eabfc570 (patch) | |
tree | b37e9b83eff28125aba7f626ab2e3bea5b487658 /sys/geom/vinum/geom_vinum_volume.c | |
parent | f66d897510d4772f7c5efd834cd66203558e9cb5 (diff) | |
download | FreeBSD-src-cf31d52b42bd2309bb855b34e8260283eabfc570.zip FreeBSD-src-cf31d52b42bd2309bb855b34e8260283eabfc570.tar.gz |
Add a first version of a GEOMified vinum.
Diffstat (limited to 'sys/geom/vinum/geom_vinum_volume.c')
-rw-r--r-- | sys/geom/vinum/geom_vinum_volume.c | 260 |
1 files changed, 260 insertions, 0 deletions
diff --git a/sys/geom/vinum/geom_vinum_volume.c b/sys/geom/vinum/geom_vinum_volume.c new file mode 100644 index 0000000..c916af4 --- /dev/null +++ b/sys/geom/vinum/geom_vinum_volume.c @@ -0,0 +1,260 @@ +/*- + * Copyright (c) 2004 Lukas Ertl + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/param.h> +#include <sys/bio.h> +#include <sys/conf.h> +#include <sys/kernel.h> +#include <sys/libkern.h> +#include <sys/lock.h> +#include <sys/malloc.h> +#include <sys/module.h> +#include <sys/mutex.h> +#include <sys/systm.h> + +#include <geom/geom.h> +#include <geom/vinum/geom_vinum_var.h> +#include <geom/vinum/geom_vinum.h> + +static void +gv_volume_orphan(struct g_consumer *cp) +{ + struct g_geom *gp; + int error; + + g_topology_assert(); + gp = cp->geom; + g_trace(G_T_TOPOLOGY, "gv_volume_orphan(%s)", gp->name); + if (cp->acr != 0 || cp->acw != 0 || cp->ace != 0) + g_access(cp, -cp->acr, -cp->acw, -cp->ace); + error = cp->provider->error; + if (error == 0) + error = ENXIO; + g_detach(cp); + g_destroy_consumer(cp); + if (!LIST_EMPTY(&gp->consumer)) + return; + g_free(gp->softc); + g_wither_geom(gp, error); +} + +/* We end up here after the requests to our plexes are done. */ +static void +gv_volume_done(struct bio *bp) +{ + struct g_consumer *cp; + + /* The next plex in this volume. */ + cp = LIST_NEXT(bp->bio_from, consumer); + + switch (bp->bio_cmd) { + case BIO_READ: + /* + * If no error occured on this request, or if we have no plex + * left, finish here... + */ + if ((bp->bio_error == 0) || (cp == NULL)) { + g_std_done(bp); + return; + } + + /* ... or try to read from the next plex. */ + g_io_request(bp, cp); + return; + + case BIO_WRITE: + case BIO_DELETE: + /* No more plexes left. */ + if (cp == NULL) { + /* + * Clear any errors if one of the previous writes + * succeeded. + */ + if (bp->bio_caller1 == (int *)1) + bp->bio_error = 0; + g_std_done(bp); + return; + } + + /* If this write request had no errors, remember that fact... */ + if (bp->bio_error == 0) + bp->bio_caller1 = (int *)1; + + /* ... and write to the next plex. */ + g_io_request(bp, cp); + return; + } +} + +static void +gv_volume_start(struct bio *bp) +{ + struct g_geom *gp; + struct bio *bp2; + struct gv_volume *v; + + gp = bp->bio_to->geom; + v = gp->softc; + if (v->state != GV_VOL_UP) { + g_io_deliver(bp, ENXIO); + return; + } + switch(bp->bio_cmd) { + case BIO_READ: + case BIO_WRITE: + case BIO_DELETE: + bp2 = g_clone_bio(bp); + if (bp2 == NULL) { + g_io_deliver(bp, ENOMEM); + return; + } + bp2->bio_done = gv_volume_done; + g_io_request(bp2, LIST_FIRST(&gp->consumer)); + return; + default: + g_io_deliver(bp, EOPNOTSUPP); + return; + } +} + +static int +gv_volume_access(struct g_provider *pp, int dr, int dw, int de) +{ + struct g_geom *gp; + struct g_consumer *cp, *cp2; + int error; + + gp = pp->geom; + + error = ENXIO; + LIST_FOREACH(cp, &gp->consumer, consumer) { + error = g_access(cp, dr, dw, de); + if (error) { + LIST_FOREACH(cp2, &gp->consumer, consumer) { + if (cp == cp2) + break; + g_access(cp2, -dr, -dw, -de); + } + return (error); + } + } + return (error); +} + +static struct g_geom * +gv_volume_taste(struct g_class *mp, struct g_provider *pp, int flags __unused) +{ + struct g_geom *gp; + struct g_provider *pp2; + struct g_consumer *cp; + struct gv_softc *sc; + struct gv_volume *v; + struct gv_plex *p; + int first; + + g_trace(G_T_TOPOLOGY, "gv_volume_taste(%s, %s)", mp->name, pp->name); + g_topology_assert(); + + /* First, find the VINUM class and its associated geom. */ + gp = find_vinum_geom(); + if (gp == NULL) + return (NULL); + + sc = gp->softc; + KASSERT(sc != NULL, ("gv_volume_taste: NULL sc")); + + gp = pp->geom; + + /* We only want to attach to plexes. */ + if (strcmp(gp->class->name, "VINUMPLEX")) + return (NULL); + + first = 0; + p = gp->softc; + v = gv_find_vol(sc, p->volume); + if (v == NULL) + return (NULL); + if (v->geom == NULL) { + gp = g_new_geomf(mp, "%s", p->volume); + gp->start = gv_volume_start; + gp->orphan = gv_volume_orphan; + gp->access = gv_volume_access; + gp->softc = v; + first++; + } else + gp = v->geom; + + cp = g_new_consumer(gp); + g_attach(cp, pp); + p->consumer = cp; + + if (p->vol_sc != v) { + p->vol_sc = v; + v->plexcount++; + LIST_INSERT_HEAD(&v->plexes, p, in_volume); + } + + /* We need to setup a new VINUMVOLUME geom. */ + if (first) { + pp2 = g_new_providerf(gp, "gvinum/%s", v->name); + pp2->mediasize = pp->mediasize; + pp2->sectorsize = pp->sectorsize; + g_error_provider(pp2, 0); + v->size = pp2->mediasize; + v->geom = gp; + return (gp); + } + + return (NULL); +} + +static int +gv_volume_destroy_geom(struct gctl_req *req, struct g_class *mp, + struct g_geom *gp) +{ + g_trace(G_T_TOPOLOGY, "gv_volume_destroy_geom: %s", gp->name); + g_topology_assert(); +/* + if (gp->softc != NULL) + g_free(gp->softc); + gp->softc = NULL; +*/ + g_wither_geom(gp, ENXIO); + return (0); +} + +#define VINUMVOLUME_CLASS_NAME "VINUMVOLUME" + +static struct g_class g_vinum_volume_class = { + .name = VINUMVOLUME_CLASS_NAME, + .taste = gv_volume_taste, + .destroy_geom = gv_volume_destroy_geom, +}; + +DECLARE_GEOM_CLASS(g_vinum_volume_class, g_vinum_volume); |