diff --git a/sys/conf/NOTES b/sys/conf/NOTES --- a/sys/conf/NOTES +++ b/sys/conf/NOTES @@ -177,7 +177,6 @@ options GEOM_SHSEC # Shared secret. options GEOM_STRIPE # Disk striping. options GEOM_UZIP # Read-only compressed disks -options GEOM_VINUM # Vinum logical volume manager options GEOM_VIRSTOR # Virtual storage. options GEOM_ZERO # Performance testing helper. diff --git a/sys/conf/files b/sys/conf/files --- a/sys/conf/files +++ b/sys/conf/files @@ -3714,21 +3714,6 @@ geom/uzip/g_uzip_zlib.c optional geom_uzip geom/uzip/g_uzip_zstd.c optional geom_uzip zstdio \ compile-with "${NORMAL_C} -I$S/contrib/zstd/lib/freebsd" -geom/vinum/geom_vinum.c optional geom_vinum -geom/vinum/geom_vinum_create.c optional geom_vinum -geom/vinum/geom_vinum_drive.c optional geom_vinum -geom/vinum/geom_vinum_plex.c optional geom_vinum -geom/vinum/geom_vinum_volume.c optional geom_vinum -geom/vinum/geom_vinum_subr.c optional geom_vinum -geom/vinum/geom_vinum_raid5.c optional geom_vinum -geom/vinum/geom_vinum_share.c optional geom_vinum -geom/vinum/geom_vinum_list.c optional geom_vinum -geom/vinum/geom_vinum_rm.c optional geom_vinum -geom/vinum/geom_vinum_init.c optional geom_vinum -geom/vinum/geom_vinum_state.c optional geom_vinum -geom/vinum/geom_vinum_rename.c optional geom_vinum -geom/vinum/geom_vinum_move.c optional geom_vinum -geom/vinum/geom_vinum_events.c optional geom_vinum geom/virstor/binstream.c optional geom_virstor geom/virstor/g_virstor.c optional geom_virstor geom/virstor/g_virstor_md.c optional geom_virstor diff --git a/sys/geom/vinum/geom_vinum.h b/sys/geom/vinum/geom_vinum.h deleted file mode 100644 --- a/sys/geom/vinum/geom_vinum.h +++ /dev/null @@ -1,163 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause - * - * Copyright (c) 2004, 2007 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. - */ - -#ifndef _GEOM_VINUM_H_ -#define _GEOM_VINUM_H_ - -/* geom_vinum_create.c */ -void gv_concat(struct g_geom *gp, struct gctl_req *); -void gv_mirror(struct g_geom *gp, struct gctl_req *); -void gv_stripe(struct g_geom *gp, struct gctl_req *); -void gv_raid5(struct g_geom *gp, struct gctl_req *); -int gv_create_drive(struct gv_softc *, struct gv_drive *); -int gv_create_volume(struct gv_softc *, struct gv_volume *); -int gv_create_plex(struct gv_softc *, struct gv_plex *); -int gv_create_sd(struct gv_softc *, struct gv_sd *); - -/* geom_vinum_drive.c */ -void gv_save_config(struct gv_softc *); -int gv_read_header(struct g_consumer *, struct gv_hdr *); -int gv_write_header(struct g_consumer *, struct gv_hdr *); - -/* geom_vinum_init.c */ -void gv_start_obj(struct g_geom *, struct gctl_req *); -int gv_start_plex(struct gv_plex *); -int gv_start_vol(struct gv_volume *); - -/* geom_vinum_list.c */ -void gv_ld(struct g_geom *, struct gctl_req *, struct sbuf *); -void gv_lp(struct g_geom *, struct gctl_req *, struct sbuf *); -void gv_ls(struct g_geom *, struct gctl_req *, struct sbuf *); -void gv_lv(struct g_geom *, struct gctl_req *, struct sbuf *); -void gv_list(struct g_geom *, struct gctl_req *); - -/* geom_vinum_move.c */ -void gv_move(struct g_geom *, struct gctl_req *); -int gv_move_sd(struct gv_softc *, struct gv_sd *, struct gv_drive *, int); - -/* geom_vinum_rename.c */ -void gv_rename(struct g_geom *, struct gctl_req *); -int gv_rename_drive(struct gv_softc *, struct gv_drive *, char *, int); -int gv_rename_plex(struct gv_softc *, struct gv_plex *, char *, int); -int gv_rename_sd(struct gv_softc *, struct gv_sd *, char *, int); -int gv_rename_vol(struct gv_softc *, struct gv_volume *, char *, int); - -/* geom_vinum_rm.c */ -void gv_remove(struct g_geom *, struct gctl_req *); -int gv_resetconfig(struct gv_softc *); -void gv_rm_sd(struct gv_softc *sc, struct gv_sd *s); -void gv_rm_drive(struct gv_softc *, struct gv_drive *, int); -void gv_rm_plex(struct gv_softc *, struct gv_plex *); -void gv_rm_vol(struct gv_softc *, struct gv_volume *); - -/* geom_vinum_state.c */ -int gv_sdstatemap(struct gv_plex *); -void gv_setstate(struct g_geom *, struct gctl_req *); -int gv_set_drive_state(struct gv_drive *, int, int); -int gv_set_sd_state(struct gv_sd *, int, int); -int gv_set_vol_state(struct gv_volume *, int, int); -int gv_set_plex_state(struct gv_plex *, int, int); -void gv_update_sd_state(struct gv_sd *); -void gv_update_plex_state(struct gv_plex *); -void gv_update_vol_state(struct gv_volume *); - -/* geom_vinum_subr.c */ -void gv_adjust_freespace(struct gv_sd *, off_t); -void gv_free_sd(struct gv_sd *); -struct gv_drive *gv_find_drive(struct gv_softc *, char *); -struct gv_drive *gv_find_drive_device(struct gv_softc *, char *); -struct gv_plex *gv_find_plex(struct gv_softc *, char *); -struct gv_sd *gv_find_sd(struct gv_softc *, char *); -struct gv_volume *gv_find_vol(struct gv_softc *, char *); -void gv_format_config(struct gv_softc *, struct sbuf *, int, - char *); -int gv_is_striped(struct gv_plex *); -int gv_consumer_is_open(struct g_consumer *); -int gv_provider_is_open(struct g_provider *); -int gv_object_type(struct gv_softc *, char *); -void gv_parse_config(struct gv_softc *, char *, - struct gv_drive *); -int gv_sd_to_drive(struct gv_sd *, struct gv_drive *); -int gv_sd_to_plex(struct gv_sd *, struct gv_plex *); -int gv_sdcount(struct gv_plex *, int); -void gv_update_plex_config(struct gv_plex *); -void gv_update_vol_size(struct gv_volume *, off_t); -off_t gv_vol_size(struct gv_volume *); -off_t gv_plex_size(struct gv_plex *); -int gv_plexdown(struct gv_volume *); -int gv_attach_plex(struct gv_plex *, struct gv_volume *, - int); -int gv_attach_sd(struct gv_sd *, struct gv_plex *, off_t, - int); -int gv_detach_plex(struct gv_plex *, int); -int gv_detach_sd(struct gv_sd *, int); - -/* geom_vinum.c */ -void gv_worker(void *); -void gv_post_event(struct gv_softc *, int, void *, void *, intmax_t, - intmax_t); -void gv_worker_exit(struct gv_softc *); -struct gv_event *gv_get_event(struct gv_softc *); -void gv_remove_event(struct gv_softc *, struct gv_event *); -void gv_drive_done(struct gv_drive *); -void gv_drive_tasted(struct gv_softc *, struct g_provider *); -void gv_drive_lost(struct gv_softc *, struct gv_drive *); -void gv_setup_objects(struct gv_softc *); -void gv_start(struct bio *); -int gv_access(struct g_provider *, int, int, int); -void gv_cleanup(struct gv_softc *); - -/* geom_vinum_volume.c */ -void gv_done(struct bio *); -void gv_volume_start(struct gv_softc *, struct bio *); -void gv_volume_flush(struct gv_volume *); -void gv_bio_done(struct gv_softc *, struct bio *); - -/* geom_vinum_plex.c */ -void gv_plex_start(struct gv_plex *, struct bio *); -void gv_plex_raid5_done(struct gv_plex *, struct bio *); -void gv_plex_normal_done(struct gv_plex *, struct bio *); -int gv_grow_request(struct gv_plex *, off_t, off_t, int, caddr_t); -void gv_grow_complete(struct gv_plex *, struct bio *); -void gv_init_request(struct gv_sd *, off_t, caddr_t, off_t); -void gv_init_complete(struct gv_plex *, struct bio *); -void gv_parity_request(struct gv_plex *, int, off_t); -void gv_parity_complete(struct gv_plex *, struct bio *); -void gv_rebuild_complete(struct gv_plex *, struct bio *); -int gv_sync_request(struct gv_plex *, struct gv_plex *, off_t, off_t, int, - caddr_t); -int gv_sync_complete(struct gv_plex *, struct bio *); - -extern u_int g_vinum_debug; - -#define G_VINUM_DEBUG(lvl, ...) \ - _GEOM_DEBUG("GEOM_VINUM", g_vinum_debug, (lvl), NULL, __VA_ARGS__) -#define G_VINUM_LOGREQ(lvl, bp, ...) \ - _GEOM_DEBUG("GEOM_VINUM", g_vinum_debug, (lvl), (bp), __VA_ARGS__) - -#endif /* !_GEOM_VINUM_H_ */ diff --git a/sys/geom/vinum/geom_vinum.c b/sys/geom/vinum/geom_vinum.c deleted file mode 100644 --- a/sys/geom/vinum/geom_vinum.c +++ /dev/null @@ -1,1044 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause - * - * Copyright (c) 2004, 2007 Lukas Ertl - * Copyright (c) 2007, 2009 Ulf Lilleengen - * 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 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 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/param.h> -#include <sys/bio.h> -#include <sys/kernel.h> -#include <sys/kthread.h> -#include <sys/lock.h> -#include <sys/malloc.h> -#include <sys/module.h> -#include <sys/mutex.h> -#include <sys/sbuf.h> -#include <sys/sysctl.h> -#include <sys/systm.h> - -#include <geom/geom.h> -#include <geom/geom_dbg.h> -#include <geom/vinum/geom_vinum_var.h> -#include <geom/vinum/geom_vinum.h> -#include <geom/vinum/geom_vinum_raid5.h> - -SYSCTL_DECL(_kern_geom); -static SYSCTL_NODE(_kern_geom, OID_AUTO, vinum, CTLFLAG_RW | CTLFLAG_MPSAFE, 0, - "GEOM_VINUM stuff"); -u_int g_vinum_debug = 0; -SYSCTL_UINT(_kern_geom_vinum, OID_AUTO, debug, CTLFLAG_RWTUN, &g_vinum_debug, 0, - "Debug level"); - -static int gv_create(struct g_geom *, struct gctl_req *); -static void gv_attach(struct gv_softc *, struct gctl_req *); -static void gv_detach(struct gv_softc *, struct gctl_req *); -static void gv_parityop(struct gv_softc *, struct gctl_req *); - -static void -gv_orphan(struct g_consumer *cp) -{ - struct g_geom *gp; - struct gv_softc *sc; - struct gv_drive *d; - - g_topology_assert(); - - KASSERT(cp != NULL, ("gv_orphan: null cp")); - gp = cp->geom; - KASSERT(gp != NULL, ("gv_orphan: null gp")); - sc = gp->softc; - KASSERT(sc != NULL, ("gv_orphan: null sc")); - d = cp->private; - KASSERT(d != NULL, ("gv_orphan: null d")); - - g_trace(G_T_TOPOLOGY, "gv_orphan(%s)", gp->name); - - gv_post_event(sc, GV_EVENT_DRIVE_LOST, d, NULL, 0, 0); -} - -void -gv_start(struct bio *bp) -{ - struct g_geom *gp; - struct gv_softc *sc; - - gp = bp->bio_to->geom; - sc = gp->softc; - - switch (bp->bio_cmd) { - case BIO_READ: - case BIO_WRITE: - case BIO_DELETE: - break; - case BIO_GETATTR: - default: - g_io_deliver(bp, EOPNOTSUPP); - return; - } - mtx_lock(&sc->bqueue_mtx); - bioq_disksort(sc->bqueue_down, bp); - wakeup(sc); - mtx_unlock(&sc->bqueue_mtx); -} - -void -gv_done(struct bio *bp) -{ - struct g_geom *gp; - struct gv_softc *sc; - - KASSERT(bp != NULL, ("NULL bp")); - - gp = bp->bio_from->geom; - sc = gp->softc; - - mtx_lock(&sc->bqueue_mtx); - bioq_disksort(sc->bqueue_up, bp); - wakeup(sc); - mtx_unlock(&sc->bqueue_mtx); -} - -int -gv_access(struct g_provider *pp, int dr, int dw, int de) -{ - struct g_geom *gp; - struct gv_softc *sc; - struct gv_drive *d, *d2; - int error; - - gp = pp->geom; - sc = gp->softc; - /* - * We want to modify the read count with the write count in case we have - * plexes in a RAID-5 organization. - */ - dr += dw; - - LIST_FOREACH(d, &sc->drives, drive) { - if (d->consumer == NULL) - continue; - error = g_access(d->consumer, dr, dw, de); - if (error) { - LIST_FOREACH(d2, &sc->drives, drive) { - if (d == d2) - break; - g_access(d2->consumer, -dr, -dw, -de); - } - G_VINUM_DEBUG(0, "g_access '%s' failed: %d", d->name, - error); - return (error); - } - } - return (0); -} - -static void -gv_init(struct g_class *mp) -{ - struct g_geom *gp; - struct gv_softc *sc; - - g_trace(G_T_TOPOLOGY, "gv_init(%p)", mp); - - gp = g_new_geomf(mp, "VINUM"); - gp->spoiled = gv_orphan; - gp->orphan = gv_orphan; - gp->access = gv_access; - gp->start = gv_start; - gp->softc = g_malloc(sizeof(struct gv_softc), M_WAITOK | M_ZERO); - sc = gp->softc; - sc->geom = gp; - sc->bqueue_down = g_malloc(sizeof(struct bio_queue_head), - M_WAITOK | M_ZERO); - sc->bqueue_up = g_malloc(sizeof(struct bio_queue_head), - M_WAITOK | M_ZERO); - bioq_init(sc->bqueue_down); - bioq_init(sc->bqueue_up); - LIST_INIT(&sc->drives); - LIST_INIT(&sc->subdisks); - LIST_INIT(&sc->plexes); - LIST_INIT(&sc->volumes); - TAILQ_INIT(&sc->equeue); - mtx_init(&sc->config_mtx, "gv_config", NULL, MTX_DEF); - mtx_init(&sc->equeue_mtx, "gv_equeue", NULL, MTX_DEF); - mtx_init(&sc->bqueue_mtx, "gv_bqueue", NULL, MTX_DEF); - kproc_create(gv_worker, sc, &sc->worker, 0, 0, "gv_worker"); -} - -static int -gv_unload(struct gctl_req *req, struct g_class *mp, struct g_geom *gp) -{ - struct gv_softc *sc; - - g_trace(G_T_TOPOLOGY, "gv_unload(%p)", mp); - - g_topology_assert(); - sc = gp->softc; - - if (sc != NULL) { - gv_worker_exit(sc); - gp->softc = NULL; - g_wither_geom(gp, ENXIO); - } - - return (0); -} - -/* Handle userland request of attaching object. */ -static void -gv_attach(struct gv_softc *sc, struct gctl_req *req) -{ - struct gv_volume *v; - struct gv_plex *p; - struct gv_sd *s; - off_t *offset; - int *rename, type_child, type_parent; - char *child, *parent; - - child = gctl_get_param(req, "child", NULL); - if (child == NULL) { - gctl_error(req, "no child given"); - return; - } - parent = gctl_get_param(req, "parent", NULL); - if (parent == NULL) { - gctl_error(req, "no parent given"); - return; - } - offset = gctl_get_paraml(req, "offset", sizeof(*offset)); - if (offset == NULL) { - gctl_error(req, "no offset given"); - return; - } - rename = gctl_get_paraml(req, "rename", sizeof(*rename)); - if (rename == NULL) { - gctl_error(req, "no rename flag given"); - return; - } - - type_child = gv_object_type(sc, child); - type_parent = gv_object_type(sc, parent); - - switch (type_child) { - case GV_TYPE_PLEX: - if (type_parent != GV_TYPE_VOL) { - gctl_error(req, "no such volume to attach to"); - return; - } - v = gv_find_vol(sc, parent); - p = gv_find_plex(sc, child); - gv_post_event(sc, GV_EVENT_ATTACH_PLEX, p, v, *offset, *rename); - break; - case GV_TYPE_SD: - if (type_parent != GV_TYPE_PLEX) { - gctl_error(req, "no such plex to attach to"); - return; - } - p = gv_find_plex(sc, parent); - s = gv_find_sd(sc, child); - gv_post_event(sc, GV_EVENT_ATTACH_SD, s, p, *offset, *rename); - break; - default: - gctl_error(req, "invalid child type"); - break; - } -} - -/* Handle userland request of detaching object. */ -static void -gv_detach(struct gv_softc *sc, struct gctl_req *req) -{ - struct gv_plex *p; - struct gv_sd *s; - int *flags, type; - char *object; - - object = gctl_get_param(req, "object", NULL); - if (object == NULL) { - gctl_error(req, "no argument given"); - return; - } - - flags = gctl_get_paraml(req, "flags", sizeof(*flags)); - type = gv_object_type(sc, object); - switch (type) { - case GV_TYPE_PLEX: - p = gv_find_plex(sc, object); - gv_post_event(sc, GV_EVENT_DETACH_PLEX, p, NULL, *flags, 0); - break; - case GV_TYPE_SD: - s = gv_find_sd(sc, object); - gv_post_event(sc, GV_EVENT_DETACH_SD, s, NULL, *flags, 0); - break; - default: - gctl_error(req, "invalid object type"); - break; - } -} - -/* Handle userland requests for creating new objects. */ -static int -gv_create(struct g_geom *gp, struct gctl_req *req) -{ - struct gv_softc *sc; - struct gv_drive *d, *d2; - struct gv_plex *p, *p2; - struct gv_sd *s, *s2; - struct gv_volume *v, *v2; - struct g_provider *pp; - int i, *drives, *flags, *plexes, *subdisks, *volumes; - char buf[20]; - - g_topology_assert(); - - sc = gp->softc; - - /* Find out how many of each object have been passed in. */ - volumes = gctl_get_paraml(req, "volumes", sizeof(*volumes)); - plexes = gctl_get_paraml(req, "plexes", sizeof(*plexes)); - subdisks = gctl_get_paraml(req, "subdisks", sizeof(*subdisks)); - drives = gctl_get_paraml(req, "drives", sizeof(*drives)); - if (volumes == NULL || plexes == NULL || subdisks == NULL || - drives == NULL) { - gctl_error(req, "number of objects not given"); - return (-1); - } - flags = gctl_get_paraml(req, "flags", sizeof(*flags)); - if (flags == NULL) { - gctl_error(req, "flags not given"); - return (-1); - } - - /* First, handle drive definitions ... */ - for (i = 0; i < *drives; i++) { - snprintf(buf, sizeof(buf), "drive%d", i); - d2 = gctl_get_paraml(req, buf, sizeof(*d2)); - if (d2 == NULL) { - gctl_error(req, "no drive definition given"); - return (-1); - } - /* - * Make sure that the device specified in the drive config is - * an active GEOM provider. - */ - pp = g_provider_by_name(d2->device); - if (pp == NULL) { - gctl_error(req, "%s: device not found", d2->device); - goto error; - } - if (gv_find_drive(sc, d2->name) != NULL) { - /* Ignore error. */ - if (*flags & GV_FLAG_F) - continue; - gctl_error(req, "drive '%s' already exists", d2->name); - goto error; - } - if (gv_find_drive_device(sc, d2->device) != NULL) { - gctl_error(req, "device '%s' already configured in " - "gvinum", d2->device); - goto error; - } - - d = g_malloc(sizeof(*d), M_WAITOK | M_ZERO); - bcopy(d2, d, sizeof(*d)); - - gv_post_event(sc, GV_EVENT_CREATE_DRIVE, d, NULL, 0, 0); - } - - /* ... then volume definitions ... */ - for (i = 0; i < *volumes; i++) { - snprintf(buf, sizeof(buf), "volume%d", i); - v2 = gctl_get_paraml(req, buf, sizeof(*v2)); - if (v2 == NULL) { - gctl_error(req, "no volume definition given"); - return (-1); - } - if (gv_find_vol(sc, v2->name) != NULL) { - /* Ignore error. */ - if (*flags & GV_FLAG_F) - continue; - gctl_error(req, "volume '%s' already exists", v2->name); - goto error; - } - - v = g_malloc(sizeof(*v), M_WAITOK | M_ZERO); - bcopy(v2, v, sizeof(*v)); - - gv_post_event(sc, GV_EVENT_CREATE_VOLUME, v, NULL, 0, 0); - } - - /* ... then plex definitions ... */ - for (i = 0; i < *plexes; i++) { - snprintf(buf, sizeof(buf), "plex%d", i); - p2 = gctl_get_paraml(req, buf, sizeof(*p2)); - if (p2 == NULL) { - gctl_error(req, "no plex definition given"); - return (-1); - } - if (gv_find_plex(sc, p2->name) != NULL) { - /* Ignore error. */ - if (*flags & GV_FLAG_F) - continue; - gctl_error(req, "plex '%s' already exists", p2->name); - goto error; - } - - p = g_malloc(sizeof(*p), M_WAITOK | M_ZERO); - bcopy(p2, p, sizeof(*p)); - - gv_post_event(sc, GV_EVENT_CREATE_PLEX, p, NULL, 0, 0); - } - - /* ... and, finally, subdisk definitions. */ - for (i = 0; i < *subdisks; i++) { - snprintf(buf, sizeof(buf), "sd%d", i); - s2 = gctl_get_paraml(req, buf, sizeof(*s2)); - if (s2 == NULL) { - gctl_error(req, "no subdisk definition given"); - return (-1); - } - if (gv_find_sd(sc, s2->name) != NULL) { - /* Ignore error. */ - if (*flags & GV_FLAG_F) - continue; - gctl_error(req, "sd '%s' already exists", s2->name); - goto error; - } - - s = g_malloc(sizeof(*s), M_WAITOK | M_ZERO); - bcopy(s2, s, sizeof(*s)); - - gv_post_event(sc, GV_EVENT_CREATE_SD, s, NULL, 0, 0); - } - -error: - gv_post_event(sc, GV_EVENT_SETUP_OBJECTS, sc, NULL, 0, 0); - gv_post_event(sc, GV_EVENT_SAVE_CONFIG, sc, NULL, 0, 0); - - return (0); -} - -static void -gv_config(struct gctl_req *req, struct g_class *mp, char const *verb) -{ - struct g_geom *gp; - struct gv_softc *sc; - struct sbuf *sb; - char *comment; - - g_topology_assert(); - - gp = LIST_FIRST(&mp->geom); - sc = gp->softc; - - if (!strcmp(verb, "attach")) { - gv_attach(sc, req); - - } else if (!strcmp(verb, "concat")) { - gv_concat(gp, req); - - } else if (!strcmp(verb, "detach")) { - gv_detach(sc, req); - - } else if (!strcmp(verb, "list")) { - gv_list(gp, req); - - /* Save our configuration back to disk. */ - } else if (!strcmp(verb, "saveconfig")) { - gv_post_event(sc, GV_EVENT_SAVE_CONFIG, sc, NULL, 0, 0); - - /* Return configuration in string form. */ - } else if (!strcmp(verb, "getconfig")) { - comment = gctl_get_param(req, "comment", NULL); - if (comment == NULL) { - gctl_error(req, "no comment parameter given"); - return; - } - sb = sbuf_new(NULL, NULL, GV_CFG_LEN, SBUF_FIXEDLEN); - gv_format_config(sc, sb, 0, comment); - sbuf_finish(sb); - gctl_set_param(req, "config", sbuf_data(sb), sbuf_len(sb) + 1); - sbuf_delete(sb); - - } else if (!strcmp(verb, "create")) { - gv_create(gp, req); - - } else if (!strcmp(verb, "mirror")) { - gv_mirror(gp, req); - - } else if (!strcmp(verb, "move")) { - gv_move(gp, req); - - } else if (!strcmp(verb, "raid5")) { - gv_raid5(gp, req); - - } else if (!strcmp(verb, "rebuildparity") || - !strcmp(verb, "checkparity")) { - gv_parityop(sc, req); - - } else if (!strcmp(verb, "remove")) { - gv_remove(gp, req); - - } else if (!strcmp(verb, "rename")) { - gv_rename(gp, req); - - } else if (!strcmp(verb, "resetconfig")) { - gv_post_event(sc, GV_EVENT_RESET_CONFIG, sc, NULL, 0, 0); - - } else if (!strcmp(verb, "start")) { - gv_start_obj(gp, req); - - } else if (!strcmp(verb, "stripe")) { - gv_stripe(gp, req); - - } else if (!strcmp(verb, "setstate")) { - gv_setstate(gp, req); - } else - gctl_error(req, "Unknown verb parameter"); -} - -static void -gv_parityop(struct gv_softc *sc, struct gctl_req *req) -{ - struct gv_plex *p; - int *flags, *rebuild, type; - char *plex; - - plex = gctl_get_param(req, "plex", NULL); - if (plex == NULL) { - gctl_error(req, "no plex given"); - return; - } - - flags = gctl_get_paraml(req, "flags", sizeof(*flags)); - if (flags == NULL) { - gctl_error(req, "no flags given"); - return; - } - - rebuild = gctl_get_paraml(req, "rebuild", sizeof(*rebuild)); - if (rebuild == NULL) { - gctl_error(req, "no operation given"); - return; - } - - type = gv_object_type(sc, plex); - if (type != GV_TYPE_PLEX) { - gctl_error(req, "'%s' is not a plex", plex); - return; - } - p = gv_find_plex(sc, plex); - - if (p->state != GV_PLEX_UP) { - gctl_error(req, "plex %s is not completely accessible", - p->name); - return; - } - - if (p->org != GV_PLEX_RAID5) { - gctl_error(req, "plex %s is not a RAID5 plex", p->name); - return; - } - - /* Put it in the event queue. */ - /* XXX: The state of the plex might have changed when this event is - * picked up ... We should perhaps check this afterwards. */ - if (*rebuild) - gv_post_event(sc, GV_EVENT_PARITY_REBUILD, p, NULL, 0, 0); - else - gv_post_event(sc, GV_EVENT_PARITY_CHECK, p, NULL, 0, 0); -} - -static struct g_geom * -gv_taste(struct g_class *mp, struct g_provider *pp, int flags __unused) -{ - struct g_geom *gp; - struct g_consumer *cp; - struct gv_softc *sc; - struct gv_hdr vhdr; - int error; - - g_topology_assert(); - g_trace(G_T_TOPOLOGY, "gv_taste(%s, %s)", mp->name, pp->name); - - gp = LIST_FIRST(&mp->geom); - if (gp == NULL) { - G_VINUM_DEBUG(0, "error: tasting, but not initialized?"); - return (NULL); - } - sc = gp->softc; - - cp = g_new_consumer(gp); - cp->flags |= G_CF_DIRECT_SEND | G_CF_DIRECT_RECEIVE; - if (g_attach(cp, pp) != 0) { - g_destroy_consumer(cp); - return (NULL); - } - if (g_access(cp, 1, 0, 0) != 0) { - g_detach(cp); - g_destroy_consumer(cp); - return (NULL); - } - g_topology_unlock(); - - error = gv_read_header(cp, &vhdr); - - g_topology_lock(); - g_access(cp, -1, 0, 0); - g_detach(cp); - g_destroy_consumer(cp); - - /* Check if what we've been given is a valid vinum drive. */ - if (!error) - gv_post_event(sc, GV_EVENT_DRIVE_TASTED, pp, NULL, 0, 0); - - return (NULL); -} - -void -gv_worker(void *arg) -{ - struct g_provider *pp; - struct gv_softc *sc; - struct gv_event *ev; - struct gv_volume *v; - struct gv_plex *p; - struct gv_sd *s; - struct gv_drive *d; - struct bio *bp; - int newstate, flags, err, rename; - char *newname; - off_t offset; - - sc = arg; - KASSERT(sc != NULL, ("NULL sc")); - for (;;) { - /* Look at the events first... */ - ev = gv_get_event(sc); - if (ev != NULL) { - gv_remove_event(sc, ev); - - switch (ev->type) { - case GV_EVENT_DRIVE_TASTED: - G_VINUM_DEBUG(2, "event 'drive tasted'"); - pp = ev->arg1; - gv_drive_tasted(sc, pp); - break; - - case GV_EVENT_DRIVE_LOST: - G_VINUM_DEBUG(2, "event 'drive lost'"); - d = ev->arg1; - gv_drive_lost(sc, d); - break; - - case GV_EVENT_CREATE_DRIVE: - G_VINUM_DEBUG(2, "event 'create drive'"); - d = ev->arg1; - gv_create_drive(sc, d); - break; - - case GV_EVENT_CREATE_VOLUME: - G_VINUM_DEBUG(2, "event 'create volume'"); - v = ev->arg1; - gv_create_volume(sc, v); - break; - - case GV_EVENT_CREATE_PLEX: - G_VINUM_DEBUG(2, "event 'create plex'"); - p = ev->arg1; - gv_create_plex(sc, p); - break; - - case GV_EVENT_CREATE_SD: - G_VINUM_DEBUG(2, "event 'create sd'"); - s = ev->arg1; - gv_create_sd(sc, s); - break; - - case GV_EVENT_RM_DRIVE: - G_VINUM_DEBUG(2, "event 'remove drive'"); - d = ev->arg1; - flags = ev->arg3; - gv_rm_drive(sc, d, flags); - /*gv_setup_objects(sc);*/ - break; - - case GV_EVENT_RM_VOLUME: - G_VINUM_DEBUG(2, "event 'remove volume'"); - v = ev->arg1; - gv_rm_vol(sc, v); - /*gv_setup_objects(sc);*/ - break; - - case GV_EVENT_RM_PLEX: - G_VINUM_DEBUG(2, "event 'remove plex'"); - p = ev->arg1; - gv_rm_plex(sc, p); - /*gv_setup_objects(sc);*/ - break; - - case GV_EVENT_RM_SD: - G_VINUM_DEBUG(2, "event 'remove sd'"); - s = ev->arg1; - gv_rm_sd(sc, s); - /*gv_setup_objects(sc);*/ - break; - - case GV_EVENT_SAVE_CONFIG: - G_VINUM_DEBUG(2, "event 'save config'"); - gv_save_config(sc); - break; - - case GV_EVENT_SET_SD_STATE: - G_VINUM_DEBUG(2, "event 'setstate sd'"); - s = ev->arg1; - newstate = ev->arg3; - flags = ev->arg4; - err = gv_set_sd_state(s, newstate, flags); - if (err) - G_VINUM_DEBUG(0, "error setting subdisk" - " state: error code %d", err); - break; - - case GV_EVENT_SET_DRIVE_STATE: - G_VINUM_DEBUG(2, "event 'setstate drive'"); - d = ev->arg1; - newstate = ev->arg3; - flags = ev->arg4; - err = gv_set_drive_state(d, newstate, flags); - if (err) - G_VINUM_DEBUG(0, "error setting drive " - "state: error code %d", err); - break; - - case GV_EVENT_SET_VOL_STATE: - G_VINUM_DEBUG(2, "event 'setstate volume'"); - v = ev->arg1; - newstate = ev->arg3; - flags = ev->arg4; - err = gv_set_vol_state(v, newstate, flags); - if (err) - G_VINUM_DEBUG(0, "error setting volume " - "state: error code %d", err); - break; - - case GV_EVENT_SET_PLEX_STATE: - G_VINUM_DEBUG(2, "event 'setstate plex'"); - p = ev->arg1; - newstate = ev->arg3; - flags = ev->arg4; - err = gv_set_plex_state(p, newstate, flags); - if (err) - G_VINUM_DEBUG(0, "error setting plex " - "state: error code %d", err); - break; - - case GV_EVENT_SETUP_OBJECTS: - G_VINUM_DEBUG(2, "event 'setup objects'"); - gv_setup_objects(sc); - break; - - case GV_EVENT_RESET_CONFIG: - G_VINUM_DEBUG(2, "event 'resetconfig'"); - err = gv_resetconfig(sc); - if (err) - G_VINUM_DEBUG(0, "error resetting " - "config: error code %d", err); - break; - - case GV_EVENT_PARITY_REBUILD: - /* - * Start the rebuild. The gv_plex_done will - * handle issuing of the remaining rebuild bio's - * until it's finished. - */ - G_VINUM_DEBUG(2, "event 'rebuild'"); - p = ev->arg1; - if (p->state != GV_PLEX_UP) { - G_VINUM_DEBUG(0, "plex %s is not " - "completely accessible", p->name); - break; - } - if (p->flags & GV_PLEX_SYNCING || - p->flags & GV_PLEX_REBUILDING || - p->flags & GV_PLEX_GROWING) { - G_VINUM_DEBUG(0, "plex %s is busy with " - "syncing or parity build", p->name); - break; - } - p->synced = 0; - p->flags |= GV_PLEX_REBUILDING; - g_topology_assert_not(); - g_topology_lock(); - err = gv_access(p->vol_sc->provider, 1, 1, 0); - if (err) { - G_VINUM_DEBUG(0, "unable to access " - "provider"); - break; - } - g_topology_unlock(); - gv_parity_request(p, GV_BIO_CHECK | - GV_BIO_PARITY, 0); - break; - - case GV_EVENT_PARITY_CHECK: - /* Start parity check. */ - G_VINUM_DEBUG(2, "event 'check'"); - p = ev->arg1; - if (p->state != GV_PLEX_UP) { - G_VINUM_DEBUG(0, "plex %s is not " - "completely accessible", p->name); - break; - } - if (p->flags & GV_PLEX_SYNCING || - p->flags & GV_PLEX_REBUILDING || - p->flags & GV_PLEX_GROWING) { - G_VINUM_DEBUG(0, "plex %s is busy with " - "syncing or parity build", p->name); - break; - } - p->synced = 0; - g_topology_assert_not(); - g_topology_lock(); - err = gv_access(p->vol_sc->provider, 1, 1, 0); - if (err) { - G_VINUM_DEBUG(0, "unable to access " - "provider"); - break; - } - g_topology_unlock(); - gv_parity_request(p, GV_BIO_CHECK, 0); - break; - - case GV_EVENT_START_PLEX: - G_VINUM_DEBUG(2, "event 'start' plex"); - p = ev->arg1; - gv_start_plex(p); - break; - - case GV_EVENT_START_VOLUME: - G_VINUM_DEBUG(2, "event 'start' volume"); - v = ev->arg1; - gv_start_vol(v); - break; - - case GV_EVENT_ATTACH_PLEX: - G_VINUM_DEBUG(2, "event 'attach' plex"); - p = ev->arg1; - v = ev->arg2; - rename = ev->arg4; - err = gv_attach_plex(p, v, rename); - if (err) - G_VINUM_DEBUG(0, "error attaching %s to" - " %s: error code %d", p->name, - v->name, err); - break; - - case GV_EVENT_ATTACH_SD: - G_VINUM_DEBUG(2, "event 'attach' sd"); - s = ev->arg1; - p = ev->arg2; - offset = ev->arg3; - rename = ev->arg4; - err = gv_attach_sd(s, p, offset, rename); - if (err) - G_VINUM_DEBUG(0, "error attaching %s to" - " %s: error code %d", s->name, - p->name, err); - break; - - case GV_EVENT_DETACH_PLEX: - G_VINUM_DEBUG(2, "event 'detach' plex"); - p = ev->arg1; - flags = ev->arg3; - err = gv_detach_plex(p, flags); - if (err) - G_VINUM_DEBUG(0, "error detaching %s: " - "error code %d", p->name, err); - break; - - case GV_EVENT_DETACH_SD: - G_VINUM_DEBUG(2, "event 'detach' sd"); - s = ev->arg1; - flags = ev->arg3; - err = gv_detach_sd(s, flags); - if (err) - G_VINUM_DEBUG(0, "error detaching %s: " - "error code %d", s->name, err); - break; - - case GV_EVENT_RENAME_VOL: - G_VINUM_DEBUG(2, "event 'rename' volume"); - v = ev->arg1; - newname = ev->arg2; - flags = ev->arg3; - err = gv_rename_vol(sc, v, newname, flags); - if (err) - G_VINUM_DEBUG(0, "error renaming %s to " - "%s: error code %d", v->name, - newname, err); - g_free(newname); - /* Destroy and recreate the provider if we can. */ - if (gv_provider_is_open(v->provider)) { - G_VINUM_DEBUG(0, "unable to rename " - "provider to %s: provider in use", - v->name); - break; - } - g_topology_lock(); - g_wither_provider(v->provider, ENOENT); - g_topology_unlock(); - v->provider = NULL; - gv_post_event(sc, GV_EVENT_SETUP_OBJECTS, sc, - NULL, 0, 0); - break; - - case GV_EVENT_RENAME_PLEX: - G_VINUM_DEBUG(2, "event 'rename' plex"); - p = ev->arg1; - newname = ev->arg2; - flags = ev->arg3; - err = gv_rename_plex(sc, p, newname, flags); - if (err) - G_VINUM_DEBUG(0, "error renaming %s to " - "%s: error code %d", p->name, - newname, err); - g_free(newname); - break; - - case GV_EVENT_RENAME_SD: - G_VINUM_DEBUG(2, "event 'rename' sd"); - s = ev->arg1; - newname = ev->arg2; - flags = ev->arg3; - err = gv_rename_sd(sc, s, newname, flags); - if (err) - G_VINUM_DEBUG(0, "error renaming %s to " - "%s: error code %d", s->name, - newname, err); - g_free(newname); - break; - - case GV_EVENT_RENAME_DRIVE: - G_VINUM_DEBUG(2, "event 'rename' drive"); - d = ev->arg1; - newname = ev->arg2; - flags = ev->arg3; - err = gv_rename_drive(sc, d, newname, flags); - if (err) - G_VINUM_DEBUG(0, "error renaming %s to " - "%s: error code %d", d->name, - newname, err); - g_free(newname); - break; - - case GV_EVENT_MOVE_SD: - G_VINUM_DEBUG(2, "event 'move' sd"); - s = ev->arg1; - d = ev->arg2; - flags = ev->arg3; - err = gv_move_sd(sc, s, d, flags); - if (err) - G_VINUM_DEBUG(0, "error moving %s to " - "%s: error code %d", s->name, - d->name, err); - break; - - case GV_EVENT_THREAD_EXIT: - G_VINUM_DEBUG(2, "event 'thread exit'"); - g_free(ev); - mtx_lock(&sc->equeue_mtx); - mtx_lock(&sc->bqueue_mtx); - gv_cleanup(sc); - mtx_destroy(&sc->bqueue_mtx); - mtx_destroy(&sc->equeue_mtx); - g_free(sc->bqueue_down); - g_free(sc->bqueue_up); - g_free(sc); - kproc_exit(0); - /* NOTREACHED */ - - default: - G_VINUM_DEBUG(1, "unknown event %d", ev->type); - } - - g_free(ev); - continue; - } - - /* ... then do I/O processing. */ - mtx_lock(&sc->bqueue_mtx); - /* First do new requests. */ - bp = bioq_takefirst(sc->bqueue_down); - if (bp != NULL) { - mtx_unlock(&sc->bqueue_mtx); - /* A bio that interfered with another bio. */ - if (bp->bio_pflags & GV_BIO_ONHOLD) { - s = bp->bio_caller1; - p = s->plex_sc; - /* Is it still locked out? */ - if (gv_stripe_active(p, bp)) { - /* Park the bio on the waiting queue. */ - bioq_disksort(p->wqueue, bp); - } else { - bp->bio_pflags &= ~GV_BIO_ONHOLD; - g_io_request(bp, s->drive_sc->consumer); - } - /* A special request requireing special handling. */ - } else if (bp->bio_pflags & GV_BIO_INTERNAL) { - p = bp->bio_caller1; - gv_plex_start(p, bp); - } else { - gv_volume_start(sc, bp); - } - mtx_lock(&sc->bqueue_mtx); - } - /* Then do completed requests. */ - bp = bioq_takefirst(sc->bqueue_up); - if (bp == NULL) { - msleep(sc, &sc->bqueue_mtx, PRIBIO, "-", hz/10); - mtx_unlock(&sc->bqueue_mtx); - continue; - } - mtx_unlock(&sc->bqueue_mtx); - gv_bio_done(sc, bp); - } -} - -#define VINUM_CLASS_NAME "VINUM" - -static struct g_class g_vinum_class = { - .name = VINUM_CLASS_NAME, - .version = G_VERSION, - .init = gv_init, - .taste = gv_taste, - .ctlreq = gv_config, - .destroy_geom = gv_unload, -}; - -DECLARE_GEOM_CLASS(g_vinum_class, g_vinum); -MODULE_VERSION(geom_vinum, 0); diff --git a/sys/geom/vinum/geom_vinum_create.c b/sys/geom/vinum/geom_vinum_create.c deleted file mode 100644 --- a/sys/geom/vinum/geom_vinum_create.c +++ /dev/null @@ -1,608 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause - * - * Copyright (c) 2007 Lukas Ertl - * Copyright (c) 2007, 2009 Ulf Lilleengen - * 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/param.h> -#include <sys/bio.h> -#include <sys/conf.h> -#include <sys/jail.h> -#include <sys/kernel.h> -#include <sys/malloc.h> -#include <sys/systm.h> - -#include <geom/geom.h> -#include <geom/geom_dbg.h> -#include <geom/vinum/geom_vinum_var.h> -#include <geom/vinum/geom_vinum.h> - -#define DEFAULT_STRIPESIZE 262144 - -/* - * Create a new drive object, either by user request, during taste of the drive - * itself, or because it was referenced by a subdisk during taste. - */ -int -gv_create_drive(struct gv_softc *sc, struct gv_drive *d) -{ - struct g_geom *gp; - struct g_provider *pp; - struct g_consumer *cp, *cp2; - struct gv_drive *d2; - struct gv_hdr *hdr; - struct gv_freelist *fl; - - KASSERT(d != NULL, ("gv_create_drive: NULL d")); - - gp = sc->geom; - - pp = NULL; - cp = cp2 = NULL; - - /* The drive already has a consumer if it was tasted before. */ - if (d->consumer != NULL) { - cp = d->consumer; - cp->private = d; - pp = cp->provider; - } else if (!(d->flags & GV_DRIVE_REFERENCED)) { - if (gv_find_drive(sc, d->name) != NULL) { - G_VINUM_DEBUG(0, "drive '%s' already exists", d->name); - g_free(d); - return (GV_ERR_CREATE); - } - - if (gv_find_drive_device(sc, d->device) != NULL) { - G_VINUM_DEBUG(0, "provider '%s' already in use by " - "gvinum", d->device); - return (GV_ERR_CREATE); - } - - pp = g_provider_by_name(d->device); - if (pp == NULL) { - G_VINUM_DEBUG(0, "create '%s': device '%s' disappeared", - d->name, d->device); - g_free(d); - return (GV_ERR_CREATE); - } - - g_topology_lock(); - cp = g_new_consumer(gp); - if (g_attach(cp, pp) != 0) { - g_destroy_consumer(cp); - g_topology_unlock(); - G_VINUM_DEBUG(0, "create drive '%s': unable to attach", - d->name); - g_free(d); - return (GV_ERR_CREATE); - } - g_topology_unlock(); - - d->consumer = cp; - cp->private = d; - } - - /* - * If this was just a "referenced" drive, we're almost finished, but - * insert this drive not on the head of the drives list, as - * gv_drive_is_newer() expects a "real" drive from LIST_FIRST(). - */ - if (d->flags & GV_DRIVE_REFERENCED) { - snprintf(d->device, sizeof(d->device), "???"); - d2 = LIST_FIRST(&sc->drives); - if (d2 == NULL) - LIST_INSERT_HEAD(&sc->drives, d, drive); - else - LIST_INSERT_AFTER(d2, d, drive); - return (0); - } - - /* - * Update access counts of the new drive to those of an already - * existing drive. - */ - LIST_FOREACH(d2, &sc->drives, drive) { - if ((d == d2) || (d2->consumer == NULL)) - continue; - - cp2 = d2->consumer; - g_topology_lock(); - if ((cp2->acr || cp2->acw || cp2->ace) && - (g_access(cp, cp2->acr, cp2->acw, cp2->ace) != 0)) { - g_detach(cp); - g_destroy_consumer(cp); - g_topology_unlock(); - G_VINUM_DEBUG(0, "create drive '%s': unable to update " - "access counts", d->name); - g_free(d->hdr); - g_free(d); - return (GV_ERR_CREATE); - } - g_topology_unlock(); - break; - } - - d->size = pp->mediasize - GV_DATA_START; - d->avail = d->size; - d->vinumconf = sc; - LIST_INIT(&d->subdisks); - LIST_INIT(&d->freelist); - - /* The header might have been set during taste. */ - if (d->hdr == NULL) { - hdr = g_malloc(sizeof(*hdr), M_WAITOK | M_ZERO); - hdr->magic = GV_MAGIC; - hdr->config_length = GV_CFG_LEN; - getcredhostname(NULL, hdr->label.sysname, GV_HOSTNAME_LEN); - strlcpy(hdr->label.name, d->name, sizeof(hdr->label.name)); - microtime(&hdr->label.date_of_birth); - d->hdr = hdr; - } - - /* We also need a freelist entry. */ - fl = g_malloc(sizeof(struct gv_freelist), M_WAITOK | M_ZERO); - fl->offset = GV_DATA_START; - fl->size = d->avail; - LIST_INSERT_HEAD(&d->freelist, fl, freelist); - d->freelist_entries = 1; - - if (gv_find_drive(sc, d->name) == NULL) - LIST_INSERT_HEAD(&sc->drives, d, drive); - - gv_set_drive_state(d, GV_DRIVE_UP, 0); - return (0); -} - -int -gv_create_volume(struct gv_softc *sc, struct gv_volume *v) -{ - KASSERT(v != NULL, ("gv_create_volume: NULL v")); - - v->vinumconf = sc; - v->flags |= GV_VOL_NEWBORN; - LIST_INIT(&v->plexes); - LIST_INSERT_HEAD(&sc->volumes, v, volume); - v->wqueue = g_malloc(sizeof(struct bio_queue_head), M_WAITOK | M_ZERO); - bioq_init(v->wqueue); - return (0); -} - -int -gv_create_plex(struct gv_softc *sc, struct gv_plex *p) -{ - struct gv_volume *v; - - KASSERT(p != NULL, ("gv_create_plex: NULL p")); - - /* Find the volume this plex should be attached to. */ - v = gv_find_vol(sc, p->volume); - if (v == NULL) { - G_VINUM_DEBUG(0, "create plex '%s': volume '%s' not found", - p->name, p->volume); - g_free(p); - return (GV_ERR_CREATE); - } - if (!(v->flags & GV_VOL_NEWBORN)) - p->flags |= GV_PLEX_ADDED; - p->vol_sc = v; - v->plexcount++; - p->vinumconf = sc; - p->synced = 0; - p->flags |= GV_PLEX_NEWBORN; - LIST_INSERT_HEAD(&v->plexes, p, in_volume); - LIST_INIT(&p->subdisks); - TAILQ_INIT(&p->packets); - LIST_INSERT_HEAD(&sc->plexes, p, plex); - p->bqueue = g_malloc(sizeof(struct bio_queue_head), M_WAITOK | M_ZERO); - bioq_init(p->bqueue); - p->wqueue = g_malloc(sizeof(struct bio_queue_head), M_WAITOK | M_ZERO); - bioq_init(p->wqueue); - p->rqueue = g_malloc(sizeof(struct bio_queue_head), M_WAITOK | M_ZERO); - bioq_init(p->rqueue); - return (0); -} - -int -gv_create_sd(struct gv_softc *sc, struct gv_sd *s) -{ - struct gv_plex *p; - struct gv_drive *d; - - KASSERT(s != NULL, ("gv_create_sd: NULL s")); - - /* Find the drive where this subdisk should be put on. */ - d = gv_find_drive(sc, s->drive); - if (d == NULL) { - /* - * It's possible that the subdisk references a drive that - * doesn't exist yet (during the taste process), so create a - * practically empty "referenced" drive. - */ - if (s->flags & GV_SD_TASTED) { - d = g_malloc(sizeof(struct gv_drive), - M_WAITOK | M_ZERO); - d->flags |= GV_DRIVE_REFERENCED; - strlcpy(d->name, s->drive, sizeof(d->name)); - gv_create_drive(sc, d); - } else { - G_VINUM_DEBUG(0, "create sd '%s': drive '%s' not found", - s->name, s->drive); - g_free(s); - return (GV_ERR_CREATE); - } - } - - /* Find the plex where this subdisk belongs to. */ - p = gv_find_plex(sc, s->plex); - if (p == NULL) { - G_VINUM_DEBUG(0, "create sd '%s': plex '%s' not found", - s->name, s->plex); - g_free(s); - return (GV_ERR_CREATE); - } - - /* - * First we give the subdisk to the drive, to handle autosized - * values ... - */ - if (gv_sd_to_drive(s, d) != 0) { - g_free(s); - return (GV_ERR_CREATE); - } - - /* - * Then, we give the subdisk to the plex; we check if the - * given values are correct and maybe adjust them. - */ - if (gv_sd_to_plex(s, p) != 0) { - G_VINUM_DEBUG(0, "unable to give sd '%s' to plex '%s'", - s->name, p->name); - if (s->drive_sc && !(s->drive_sc->flags & GV_DRIVE_REFERENCED)) - LIST_REMOVE(s, from_drive); - gv_free_sd(s); - g_free(s); - /* - * If this subdisk can't be created, we won't create - * the attached plex either, if it is also a new one. - */ - if (!(p->flags & GV_PLEX_NEWBORN)) - return (GV_ERR_CREATE); - gv_rm_plex(sc, p); - return (GV_ERR_CREATE); - } - s->flags |= GV_SD_NEWBORN; - - s->vinumconf = sc; - LIST_INSERT_HEAD(&sc->subdisks, s, sd); - - return (0); -} - -/* - * Create a concatenated volume from specified drives or drivegroups. - */ -void -gv_concat(struct g_geom *gp, struct gctl_req *req) -{ - struct gv_drive *d; - struct gv_sd *s; - struct gv_volume *v; - struct gv_plex *p; - struct gv_softc *sc; - char *drive, buf[30], *vol; - int *drives, dcount; - - sc = gp->softc; - dcount = 0; - vol = gctl_get_param(req, "name", NULL); - if (vol == NULL) { - gctl_error(req, "volume name not given"); - return; - } - - drives = gctl_get_paraml(req, "drives", sizeof(*drives)); - - if (drives == NULL) { - gctl_error(req, "drive names not given"); - return; - } - - /* First we create the volume. */ - v = g_malloc(sizeof(*v), M_WAITOK | M_ZERO); - strlcpy(v->name, vol, sizeof(v->name)); - v->state = GV_VOL_UP; - gv_post_event(sc, GV_EVENT_CREATE_VOLUME, v, NULL, 0, 0); - - /* Then we create the plex. */ - p = g_malloc(sizeof(*p), M_WAITOK | M_ZERO); - snprintf(p->name, sizeof(p->name), "%s.p%d", v->name, v->plexcount); - strlcpy(p->volume, v->name, sizeof(p->volume)); - p->org = GV_PLEX_CONCAT; - p->stripesize = 0; - gv_post_event(sc, GV_EVENT_CREATE_PLEX, p, NULL, 0, 0); - - /* Drives are first (right now) priority */ - for (dcount = 0; dcount < *drives; dcount++) { - snprintf(buf, sizeof(buf), "drive%d", dcount); - drive = gctl_get_param(req, buf, NULL); - d = gv_find_drive(sc, drive); - if (d == NULL) { - gctl_error(req, "No such drive '%s'", drive); - continue; - } - s = g_malloc(sizeof(*s), M_WAITOK | M_ZERO); - snprintf(s->name, sizeof(s->name), "%s.s%d", p->name, dcount); - strlcpy(s->plex, p->name, sizeof(s->plex)); - strlcpy(s->drive, drive, sizeof(s->drive)); - s->plex_offset = -1; - s->drive_offset = -1; - s->size = -1; - gv_post_event(sc, GV_EVENT_CREATE_SD, s, NULL, 0, 0); - } - gv_post_event(sc, GV_EVENT_SETUP_OBJECTS, sc, NULL, 0, 0); - gv_post_event(sc, GV_EVENT_SAVE_CONFIG, sc, NULL, 0, 0); -} - -/* - * Create a mirrored volume from specified drives or drivegroups. - */ -void -gv_mirror(struct g_geom *gp, struct gctl_req *req) -{ - struct gv_drive *d; - struct gv_sd *s; - struct gv_volume *v; - struct gv_plex *p; - struct gv_softc *sc; - char *drive, buf[30], *vol; - int *drives, *flags, dcount, pcount, scount; - - sc = gp->softc; - dcount = 0; - scount = 0; - pcount = 0; - vol = gctl_get_param(req, "name", NULL); - if (vol == NULL) { - gctl_error(req, "volume name not given"); - return; - } - - flags = gctl_get_paraml(req, "flags", sizeof(*flags)); - drives = gctl_get_paraml(req, "drives", sizeof(*drives)); - - if (drives == NULL) { - gctl_error(req, "drive names not given"); - return; - } - - /* We must have an even number of drives. */ - if (*drives % 2 != 0) { - gctl_error(req, "mirror organization must have an even number " - "of drives"); - return; - } - if (*flags & GV_FLAG_S && *drives < 4) { - gctl_error(req, "must have at least 4 drives for striped plex"); - return; - } - - /* First we create the volume. */ - v = g_malloc(sizeof(*v), M_WAITOK | M_ZERO); - strlcpy(v->name, vol, sizeof(v->name)); - v->state = GV_VOL_UP; - gv_post_event(sc, GV_EVENT_CREATE_VOLUME, v, NULL, 0, 0); - - /* Then we create the plexes. */ - for (pcount = 0; pcount < 2; pcount++) { - p = g_malloc(sizeof(*p), M_WAITOK | M_ZERO); - snprintf(p->name, sizeof(p->name), "%s.p%d", v->name, - pcount); - strlcpy(p->volume, v->name, sizeof(p->volume)); - if (*flags & GV_FLAG_S) { - p->org = GV_PLEX_STRIPED; - p->stripesize = DEFAULT_STRIPESIZE; - } else { - p->org = GV_PLEX_CONCAT; - p->stripesize = -1; - } - gv_post_event(sc, GV_EVENT_CREATE_PLEX, p, NULL, 0, 0); - - /* - * We just gives each even drive to plex one, and each odd to - * plex two. - */ - scount = 0; - for (dcount = pcount; dcount < *drives; dcount += 2) { - snprintf(buf, sizeof(buf), "drive%d", dcount); - drive = gctl_get_param(req, buf, NULL); - d = gv_find_drive(sc, drive); - if (d == NULL) { - gctl_error(req, "No such drive '%s', aborting", - drive); - scount++; - break; - } - s = g_malloc(sizeof(*s), M_WAITOK | M_ZERO); - snprintf(s->name, sizeof(s->name), "%s.s%d", p->name, - scount); - strlcpy(s->plex, p->name, sizeof(s->plex)); - strlcpy(s->drive, drive, sizeof(s->drive)); - s->plex_offset = -1; - s->drive_offset = -1; - s->size = -1; - gv_post_event(sc, GV_EVENT_CREATE_SD, s, NULL, 0, 0); - scount++; - } - } - gv_post_event(sc, GV_EVENT_SETUP_OBJECTS, sc, NULL, 0, 0); - gv_post_event(sc, GV_EVENT_SAVE_CONFIG, sc, NULL, 0, 0); -} - -void -gv_raid5(struct g_geom *gp, struct gctl_req *req) -{ - struct gv_softc *sc; - struct gv_drive *d; - struct gv_volume *v; - struct gv_plex *p; - struct gv_sd *s; - int *drives, *flags, dcount; - char *vol, *drive, buf[30]; - off_t *stripesize; - - sc = gp->softc; - - vol = gctl_get_param(req, "name", NULL); - if (vol == NULL) { - gctl_error(req, "volume name not given"); - return; - } - flags = gctl_get_paraml(req, "flags", sizeof(*flags)); - drives = gctl_get_paraml(req, "drives", sizeof(*drives)); - stripesize = gctl_get_paraml(req, "stripesize", sizeof(*stripesize)); - - if (stripesize == NULL) { - gctl_error(req, "no stripesize given"); - return; - } - - if (drives == NULL) { - gctl_error(req, "drive names not given"); - return; - } - - /* We must have at least three drives. */ - if (*drives < 3) { - gctl_error(req, "must have at least three drives for this " - "plex organisation"); - return; - } - /* First we create the volume. */ - v = g_malloc(sizeof(*v), M_WAITOK | M_ZERO); - strlcpy(v->name, vol, sizeof(v->name)); - v->state = GV_VOL_UP; - gv_post_event(sc, GV_EVENT_CREATE_VOLUME, v, NULL, 0, 0); - - /* Then we create the plex. */ - p = g_malloc(sizeof(*p), M_WAITOK | M_ZERO); - snprintf(p->name, sizeof(p->name), "%s.p%d", v->name, v->plexcount); - strlcpy(p->volume, v->name, sizeof(p->volume)); - p->org = GV_PLEX_RAID5; - p->stripesize = *stripesize; - gv_post_event(sc, GV_EVENT_CREATE_PLEX, p, NULL, 0, 0); - - /* Create subdisks on drives. */ - for (dcount = 0; dcount < *drives; dcount++) { - snprintf(buf, sizeof(buf), "drive%d", dcount); - drive = gctl_get_param(req, buf, NULL); - d = gv_find_drive(sc, drive); - if (d == NULL) { - gctl_error(req, "No such drive '%s'", drive); - continue; - } - s = g_malloc(sizeof(*s), M_WAITOK | M_ZERO); - snprintf(s->name, sizeof(s->name), "%s.s%d", p->name, dcount); - strlcpy(s->plex, p->name, sizeof(s->plex)); - strlcpy(s->drive, drive, sizeof(s->drive)); - s->plex_offset = -1; - s->drive_offset = -1; - s->size = -1; - gv_post_event(sc, GV_EVENT_CREATE_SD, s, NULL, 0, 0); - } - gv_post_event(sc, GV_EVENT_SETUP_OBJECTS, sc, NULL, 0, 0); - gv_post_event(sc, GV_EVENT_SAVE_CONFIG, sc, NULL, 0, 0); -} - -/* - * Create a striped volume from specified drives or drivegroups. - */ -void -gv_stripe(struct g_geom *gp, struct gctl_req *req) -{ - struct gv_drive *d; - struct gv_sd *s; - struct gv_volume *v; - struct gv_plex *p; - struct gv_softc *sc; - char *drive, buf[30], *vol; - int *drives, *flags, dcount; - - sc = gp->softc; - dcount = 0; - vol = gctl_get_param(req, "name", NULL); - if (vol == NULL) { - gctl_error(req, "volume name not given"); - return; - } - flags = gctl_get_paraml(req, "flags", sizeof(*flags)); - drives = gctl_get_paraml(req, "drives", sizeof(*drives)); - - if (drives == NULL) { - gctl_error(req, "drive names not given"); - return; - } - - /* We must have at least two drives. */ - if (*drives < 2) { - gctl_error(req, "must have at least 2 drives"); - return; - } - - /* First we create the volume. */ - v = g_malloc(sizeof(*v), M_WAITOK | M_ZERO); - strlcpy(v->name, vol, sizeof(v->name)); - v->state = GV_VOL_UP; - gv_post_event(sc, GV_EVENT_CREATE_VOLUME, v, NULL, 0, 0); - - /* Then we create the plex. */ - p = g_malloc(sizeof(*p), M_WAITOK | M_ZERO); - snprintf(p->name, sizeof(p->name), "%s.p%d", v->name, v->plexcount); - strlcpy(p->volume, v->name, sizeof(p->volume)); - p->org = GV_PLEX_STRIPED; - p->stripesize = 262144; - gv_post_event(sc, GV_EVENT_CREATE_PLEX, p, NULL, 0, 0); - - /* Create subdisks on drives. */ - for (dcount = 0; dcount < *drives; dcount++) { - snprintf(buf, sizeof(buf), "drive%d", dcount); - drive = gctl_get_param(req, buf, NULL); - d = gv_find_drive(sc, drive); - if (d == NULL) { - gctl_error(req, "No such drive '%s'", drive); - continue; - } - s = g_malloc(sizeof(*s), M_WAITOK | M_ZERO); - snprintf(s->name, sizeof(s->name), "%s.s%d", p->name, dcount); - strlcpy(s->plex, p->name, sizeof(s->plex)); - strlcpy(s->drive, drive, sizeof(s->drive)); - s->plex_offset = -1; - s->drive_offset = -1; - s->size = -1; - gv_post_event(sc, GV_EVENT_CREATE_SD, s, NULL, 0, 0); - } - gv_post_event(sc, GV_EVENT_SETUP_OBJECTS, sc, NULL, 0, 0); - gv_post_event(sc, GV_EVENT_SAVE_CONFIG, sc, NULL, 0, 0); -} diff --git a/sys/geom/vinum/geom_vinum_drive.c b/sys/geom/vinum/geom_vinum_drive.c deleted file mode 100644 --- a/sys/geom/vinum/geom_vinum_drive.c +++ /dev/null @@ -1,351 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause - * - * Copyright (c) 2004, 2005, 2007 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/types.h> -#include <sys/endian.h> -#include <sys/malloc.h> -#include <sys/sbuf.h> -#include <sys/systm.h> - -#include <geom/geom.h> -#include <geom/geom_dbg.h> -#include <geom/vinum/geom_vinum_var.h> -#include <geom/vinum/geom_vinum.h> - -#define GV_LEGACY_I386 0 -#define GV_LEGACY_AMD64 1 -#define GV_LEGACY_SPARC64 2 -#define GV_LEGACY_POWERPC 3 - -static int gv_legacy_header_type(uint8_t *, int); - -/* - * Here are the "offset (size)" for the various struct gv_hdr fields, - * for the legacy i386 (or 32-bit powerpc), legacy amd64 (or sparc64), and - * current (cpu & endian agnostic) versions of the on-disk format of the vinum - * header structure: - * - * i386 amd64 current field - * -------- -------- -------- ----- - * 0 ( 8) 0 ( 8) 0 ( 8) magic - * 8 ( 4) 8 ( 8) 8 ( 8) config_length - * 12 (32) 16 (32) 16 (32) label.sysname - * 44 (32) 48 (32) 48 (32) label.name - * 76 ( 4) 80 ( 8) 80 ( 8) label.date_of_birth.tv_sec - * 80 ( 4) 88 ( 8) 88 ( 8) label.date_of_birth.tv_usec - * 84 ( 4) 96 ( 8) 96 ( 8) label.last_update.tv_sec - * 88 ( 4) 104 ( 8) 104 ( 8) label.last_update.tv_usec - * 92 ( 8) 112 ( 8) 112 ( 8) label.drive_size - * ======== ======== ======== - * 100 120 120 total size - * - * NOTE: i386 and amd64 formats are stored as little-endian; the current - * format uses big-endian (network order). - */ - -/* Checks for legacy format depending on platform. */ -static int -gv_legacy_header_type(uint8_t *hdr, int bigendian) -{ - uint32_t *i32; - int arch_32, arch_64, i; - - /* Set arch according to endianness. */ - if (bigendian) { - arch_32 = GV_LEGACY_POWERPC; - arch_64 = GV_LEGACY_SPARC64; - } else { - arch_32 = GV_LEGACY_I386; - arch_64 = GV_LEGACY_AMD64; - } - - /* if non-empty hostname overlaps 64-bit config_length */ - i32 = (uint32_t *)(hdr + 12); - if (*i32 != 0) - return (arch_32); - /* check for non-empty hostname */ - if (hdr[16] != 0) - return (arch_64); - /* check bytes past 32-bit structure */ - for (i = 100; i < 120; i++) - if (hdr[i] != 0) - return (arch_32); - /* check for overlapping timestamp */ - i32 = (uint32_t *)(hdr + 84); - - if (*i32 == 0) - return (arch_64); - return (arch_32); -} - -/* - * Read the header while taking magic number into account, and write it to - * destination pointer. - */ -int -gv_read_header(struct g_consumer *cp, struct gv_hdr *m_hdr) -{ - struct g_provider *pp; - uint64_t magic_machdep; - uint8_t *d_hdr; - int be, off; - -#define GV_GET32(endian) \ - endian##32toh(*((uint32_t *)&d_hdr[off])); \ - off += 4 -#define GV_GET64(endian) \ - endian##64toh(*((uint64_t *)&d_hdr[off])); \ - off += 8 - - KASSERT(m_hdr != NULL, ("gv_read_header: null m_hdr")); - KASSERT(cp != NULL, ("gv_read_header: null cp")); - pp = cp->provider; - KASSERT(pp != NULL, ("gv_read_header: null pp")); - - if ((GV_HDR_OFFSET % pp->sectorsize) != 0 || - (GV_HDR_LEN % pp->sectorsize) != 0) - return (ENODEV); - - d_hdr = g_read_data(cp, GV_HDR_OFFSET, pp->sectorsize, NULL); - if (d_hdr == NULL) - return (-1); - off = 0; - m_hdr->magic = GV_GET64(be); - magic_machdep = *((uint64_t *)&d_hdr[0]); - /* - * The big endian machines will have a reverse of GV_OLD_MAGIC, so we - * need to decide if we are running on a big endian machine as well as - * checking the magic against the reverse of GV_OLD_MAGIC. - */ - be = (m_hdr->magic == magic_machdep); - if (m_hdr->magic == GV_MAGIC) { - m_hdr->config_length = GV_GET64(be); - off = 16; - bcopy(d_hdr + off, m_hdr->label.sysname, GV_HOSTNAME_LEN); - off += GV_HOSTNAME_LEN; - bcopy(d_hdr + off, m_hdr->label.name, GV_MAXDRIVENAME); - off += GV_MAXDRIVENAME; - m_hdr->label.date_of_birth.tv_sec = GV_GET64(be); - m_hdr->label.date_of_birth.tv_usec = GV_GET64(be); - m_hdr->label.last_update.tv_sec = GV_GET64(be); - m_hdr->label.last_update.tv_usec = GV_GET64(be); - m_hdr->label.drive_size = GV_GET64(be); - } else if (m_hdr->magic != GV_OLD_MAGIC && - m_hdr->magic != le64toh(GV_OLD_MAGIC)) { - /* Not a gvinum drive. */ - g_free(d_hdr); - return (-1); - } else if (gv_legacy_header_type(d_hdr, be) == GV_LEGACY_SPARC64) { - G_VINUM_DEBUG(1, "detected legacy sparc64 header"); - m_hdr->magic = GV_MAGIC; - /* Legacy sparc64 on-disk header */ - m_hdr->config_length = GV_GET64(be); - bcopy(d_hdr + 16, m_hdr->label.sysname, GV_HOSTNAME_LEN); - off += GV_HOSTNAME_LEN; - bcopy(d_hdr + 48, m_hdr->label.name, GV_MAXDRIVENAME); - off += GV_MAXDRIVENAME; - m_hdr->label.date_of_birth.tv_sec = GV_GET64(be); - m_hdr->label.date_of_birth.tv_usec = GV_GET64(be); - m_hdr->label.last_update.tv_sec = GV_GET64(be); - m_hdr->label.last_update.tv_usec = GV_GET64(be); - m_hdr->label.drive_size = GV_GET64(be); - } else if (gv_legacy_header_type(d_hdr, be) == GV_LEGACY_POWERPC) { - G_VINUM_DEBUG(1, "detected legacy PowerPC header"); - m_hdr->magic = GV_MAGIC; - /* legacy 32-bit big endian on-disk header */ - m_hdr->config_length = GV_GET32(be); - bcopy(d_hdr + off, m_hdr->label.sysname, GV_HOSTNAME_LEN); - off += GV_HOSTNAME_LEN; - bcopy(d_hdr + off, m_hdr->label.name, GV_MAXDRIVENAME); - off += GV_MAXDRIVENAME; - m_hdr->label.date_of_birth.tv_sec = GV_GET32(be); - m_hdr->label.date_of_birth.tv_usec = GV_GET32(be); - m_hdr->label.last_update.tv_sec = GV_GET32(be); - m_hdr->label.last_update.tv_usec = GV_GET32(be); - m_hdr->label.drive_size = GV_GET64(be); - } else if (gv_legacy_header_type(d_hdr, be) == GV_LEGACY_I386) { - G_VINUM_DEBUG(1, "detected legacy i386 header"); - m_hdr->magic = GV_MAGIC; - /* legacy i386 on-disk header */ - m_hdr->config_length = GV_GET32(le); - bcopy(d_hdr + off, m_hdr->label.sysname, GV_HOSTNAME_LEN); - off += GV_HOSTNAME_LEN; - bcopy(d_hdr + off, m_hdr->label.name, GV_MAXDRIVENAME); - off += GV_MAXDRIVENAME; - m_hdr->label.date_of_birth.tv_sec = GV_GET32(le); - m_hdr->label.date_of_birth.tv_usec = GV_GET32(le); - m_hdr->label.last_update.tv_sec = GV_GET32(le); - m_hdr->label.last_update.tv_usec = GV_GET32(le); - m_hdr->label.drive_size = GV_GET64(le); - } else { - G_VINUM_DEBUG(1, "detected legacy amd64 header"); - m_hdr->magic = GV_MAGIC; - /* legacy amd64 on-disk header */ - m_hdr->config_length = GV_GET64(le); - bcopy(d_hdr + 16, m_hdr->label.sysname, GV_HOSTNAME_LEN); - off += GV_HOSTNAME_LEN; - bcopy(d_hdr + 48, m_hdr->label.name, GV_MAXDRIVENAME); - off += GV_MAXDRIVENAME; - m_hdr->label.date_of_birth.tv_sec = GV_GET64(le); - m_hdr->label.date_of_birth.tv_usec = GV_GET64(le); - m_hdr->label.last_update.tv_sec = GV_GET64(le); - m_hdr->label.last_update.tv_usec = GV_GET64(le); - m_hdr->label.drive_size = GV_GET64(le); - } - - g_free(d_hdr); - return (0); -} - -/* Write out the gvinum header. */ -int -gv_write_header(struct g_consumer *cp, struct gv_hdr *m_hdr) -{ - uint8_t d_hdr[GV_HDR_LEN]; - int off, ret; - -#define GV_SET64BE(field) \ - do { \ - *((uint64_t *)&d_hdr[off]) = htobe64(field); \ - off += 8; \ - } while (0) - - KASSERT(m_hdr != NULL, ("gv_write_header: null m_hdr")); - - off = 0; - memset(d_hdr, 0, GV_HDR_LEN); - GV_SET64BE(m_hdr->magic); - GV_SET64BE(m_hdr->config_length); - off = 16; - bcopy(m_hdr->label.sysname, d_hdr + off, GV_HOSTNAME_LEN); - off += GV_HOSTNAME_LEN; - bcopy(m_hdr->label.name, d_hdr + off, GV_MAXDRIVENAME); - off += GV_MAXDRIVENAME; - GV_SET64BE(m_hdr->label.date_of_birth.tv_sec); - GV_SET64BE(m_hdr->label.date_of_birth.tv_usec); - GV_SET64BE(m_hdr->label.last_update.tv_sec); - GV_SET64BE(m_hdr->label.last_update.tv_usec); - GV_SET64BE(m_hdr->label.drive_size); - - ret = g_write_data(cp, GV_HDR_OFFSET, d_hdr, GV_HDR_LEN); - return (ret); -} - -/* Save the vinum configuration back to each involved disk. */ -void -gv_save_config(struct gv_softc *sc) -{ - struct g_consumer *cp; - struct gv_drive *d; - struct gv_hdr *vhdr, *hdr; - struct sbuf *sb; - struct timeval last_update; - int error; - - KASSERT(sc != NULL, ("gv_save_config: null sc")); - - vhdr = g_malloc(GV_HDR_LEN, M_WAITOK | M_ZERO); - vhdr->magic = GV_MAGIC; - vhdr->config_length = GV_CFG_LEN; - microtime(&last_update); - - sb = sbuf_new(NULL, NULL, GV_CFG_LEN, SBUF_FIXEDLEN); - gv_format_config(sc, sb, 1, NULL); - sbuf_finish(sb); - - LIST_FOREACH(d, &sc->drives, drive) { - /* - * We can't save the config on a drive that isn't up, but - * drives that were just created aren't officially up yet, so - * we check a special flag. - */ - if (d->state != GV_DRIVE_UP) - continue; - - cp = d->consumer; - if (cp == NULL) { - G_VINUM_DEBUG(0, "drive '%s' has no consumer!", - d->name); - continue; - } - - hdr = d->hdr; - if (hdr == NULL) { - G_VINUM_DEBUG(0, "drive '%s' has no header", - d->name); - g_free(vhdr); - continue; - } - bcopy(&last_update, &hdr->label.last_update, - sizeof(struct timeval)); - bcopy(&hdr->label, &vhdr->label, sizeof(struct gv_label)); - g_topology_lock(); - error = g_access(cp, 0, 1, 0); - if (error) { - G_VINUM_DEBUG(0, "g_access failed on " - "drive %s, errno %d", d->name, error); - g_topology_unlock(); - continue; - } - g_topology_unlock(); - - error = gv_write_header(cp, vhdr); - if (error) { - G_VINUM_DEBUG(0, "writing vhdr failed on drive %s, " - "errno %d", d->name, error); - g_topology_lock(); - g_access(cp, 0, -1, 0); - g_topology_unlock(); - continue; - } - /* First config copy. */ - error = g_write_data(cp, GV_CFG_OFFSET, sbuf_data(sb), - GV_CFG_LEN); - if (error) { - G_VINUM_DEBUG(0, "writing first config copy failed on " - "drive %s, errno %d", d->name, error); - g_topology_lock(); - g_access(cp, 0, -1, 0); - g_topology_unlock(); - continue; - } - /* Second config copy. */ - error = g_write_data(cp, GV_CFG_OFFSET + GV_CFG_LEN, - sbuf_data(sb), GV_CFG_LEN); - if (error) - G_VINUM_DEBUG(0, "writing second config copy failed on " - "drive %s, errno %d", d->name, error); - - g_topology_lock(); - g_access(cp, 0, -1, 0); - g_topology_unlock(); - } - - sbuf_delete(sb); - g_free(vhdr); -} diff --git a/sys/geom/vinum/geom_vinum_events.c b/sys/geom/vinum/geom_vinum_events.c deleted file mode 100644 --- a/sys/geom/vinum/geom_vinum_events.c +++ /dev/null @@ -1,282 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause - * - * Copyright (c) 2007 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 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 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/param.h> -#include <sys/kernel.h> -#include <sys/lock.h> -#include <sys/malloc.h> -#include <sys/mutex.h> -#include <sys/systm.h> - -#include <geom/geom.h> -#include <geom/geom_dbg.h> -#include <geom/vinum/geom_vinum_var.h> -#include <geom/vinum/geom_vinum.h> - -static bool deprecation_printed; - -void -gv_post_event(struct gv_softc *sc, int event, void *arg1, void *arg2, - intmax_t arg3, intmax_t arg4) -{ - struct gv_event *ev; - - ev = g_malloc(sizeof(*ev), M_WAITOK | M_ZERO); - ev->type = event; - ev->arg1 = arg1; - ev->arg2 = arg2; - ev->arg3 = arg3; - ev->arg4 = arg4; - - mtx_lock(&sc->equeue_mtx); - TAILQ_INSERT_TAIL(&sc->equeue, ev, events); - wakeup(sc); - mtx_unlock(&sc->equeue_mtx); -} - -void -gv_worker_exit(struct gv_softc *sc) -{ - struct gv_event *ev; - - ev = g_malloc(sizeof(*ev), M_WAITOK | M_ZERO); - ev->type = GV_EVENT_THREAD_EXIT; - - mtx_lock(&sc->equeue_mtx); - TAILQ_INSERT_TAIL(&sc->equeue, ev, events); - wakeup(sc); - msleep(sc->worker, &sc->equeue_mtx, PDROP, "gv_wor", 0); -} - -struct gv_event * -gv_get_event(struct gv_softc *sc) -{ - struct gv_event *ev; - - KASSERT(sc != NULL, ("NULL sc")); - mtx_lock(&sc->equeue_mtx); - ev = TAILQ_FIRST(&sc->equeue); - mtx_unlock(&sc->equeue_mtx); - return (ev); -} - -void -gv_remove_event(struct gv_softc *sc, struct gv_event *ev) -{ - - KASSERT(sc != NULL, ("NULL sc")); - KASSERT(ev != NULL, ("NULL ev")); - mtx_lock(&sc->equeue_mtx); - TAILQ_REMOVE(&sc->equeue, ev, events); - mtx_unlock(&sc->equeue_mtx); -} - -void -gv_drive_tasted(struct gv_softc *sc, struct g_provider *pp) -{ - struct g_geom *gp; - struct g_consumer *cp; - struct gv_hdr *hdr; - struct gv_drive *d; - char *buf; - int error; - - hdr = NULL; - buf = NULL; - - G_VINUM_DEBUG(2, "tasted drive on '%s'", pp->name); - if ((GV_CFG_OFFSET % pp->sectorsize) != 0 || - (GV_CFG_LEN % pp->sectorsize) != 0) { - G_VINUM_DEBUG(0, "provider %s has unsupported sectorsize.", - pp->name); - return; - } - - gp = sc->geom; - g_topology_lock(); - cp = g_new_consumer(gp); - if (g_attach(cp, pp) != 0) { - g_destroy_consumer(cp); - g_topology_unlock(); - G_VINUM_DEBUG(0, "failed to attach to provider on taste event"); - return; - } - if (g_access(cp, 1, 0, 0) != 0) { - g_detach(cp); - g_destroy_consumer(cp); - g_topology_unlock(); - G_VINUM_DEBUG(0, "failed to access consumer on taste event"); - return; - } - g_topology_unlock(); - - hdr = g_malloc(GV_HDR_LEN, M_WAITOK | M_ZERO); - /* Read header and on-disk configuration. */ - error = gv_read_header(cp, hdr); - if (error) { - G_VINUM_DEBUG(0, "failed to read header during taste"); - goto failed; - } - - /* - * Setup the drive before we parse the on-disk configuration, so that - * we already know about the drive then. - */ - d = gv_find_drive(sc, hdr->label.name); - if (d == NULL) { - d = g_malloc(sizeof(*d), M_WAITOK | M_ZERO); - strlcpy(d->name, hdr->label.name, sizeof(d->name)); - strlcpy(d->device, pp->name, sizeof(d->device)); - } else if (d->flags & GV_DRIVE_REFERENCED) { - strlcpy(d->device, pp->name, sizeof(d->device)); - d->flags &= ~GV_DRIVE_REFERENCED; - } else { - G_VINUM_DEBUG(2, "drive '%s' is already known", d->name); - goto failed; - } - - /* Add the consumer and header to the new drive. */ - d->consumer = cp; - d->hdr = hdr; - gv_create_drive(sc, d); - - buf = g_read_data(cp, GV_CFG_OFFSET, GV_CFG_LEN, NULL); - if (buf == NULL) { - G_VINUM_DEBUG(0, "failed to read config during taste"); - goto failed; - } - gv_parse_config(sc, buf, d); - g_free(buf); - - g_topology_lock(); - g_access(cp, -1, 0, 0); - g_topology_unlock(); - - gv_setup_objects(sc); - gv_set_drive_state(d, GV_DRIVE_UP, 0); - - /* Emit deprecation notice. */ - if (!deprecation_printed) { - gone_in(15, "gvinum volume manager"); - deprecation_printed = true; - } - G_VINUM_DEBUG(1, "drive '%s' relies on deprecated gvinum", d->name); - - return; - -failed: - g_free(hdr); - g_topology_lock(); - g_access(cp, -1, 0, 0); - g_detach(cp); - g_destroy_consumer(cp); - g_topology_unlock(); -} - -/* - * Count completed BIOs and handle orphanization when all are done. - */ -void -gv_drive_done(struct gv_drive *d) -{ - - KASSERT(d->active >= 0, ("Negative number of BIOs (%d)", d->active)); - if (--d->active == 0 && (d->flags & GV_DRIVE_ORPHANED)) { - d->flags &= ~GV_DRIVE_ORPHANED; - gv_post_event(d->vinumconf, GV_EVENT_DRIVE_LOST, d, NULL, 0, 0); - } -} - -/* - * When losing a drive (e.g. hardware failure), we cut down the consumer - * attached to the underlying device and bring the drive itself to a - * "referenced" state so that normal tasting could bring it up cleanly if it - * possibly arrives again. - */ -void -gv_drive_lost(struct gv_softc *sc, struct gv_drive *d) -{ - struct g_consumer *cp; - struct gv_drive *d2; - struct gv_sd *s, *s2; - struct gv_freelist *fl, *fl2; - - gv_set_drive_state(d, GV_DRIVE_DOWN, - GV_SETSTATE_FORCE | GV_SETSTATE_CONFIG); - - cp = d->consumer; - - if (cp != NULL) { - if (d->active > 0) { - G_VINUM_DEBUG(2, "dead drive '%s' has still active " - "requests, unable to detach consumer", d->name); - d->flags |= GV_DRIVE_ORPHANED; - return; - } - g_topology_lock(); - if (cp->acr != 0 || cp->acw != 0 || cp->ace != 0) - g_access(cp, -cp->acr, -cp->acw, -cp->ace); - g_detach(cp); - g_destroy_consumer(cp); - g_topology_unlock(); - } - - LIST_FOREACH_SAFE(fl, &d->freelist, freelist, fl2) { - LIST_REMOVE(fl, freelist); - g_free(fl); - } - - d->consumer = NULL; - g_free(d->hdr); - d->hdr = NULL; - d->flags |= GV_DRIVE_REFERENCED; - snprintf(d->device, sizeof(d->device), "???"); - d->size = 0; - d->avail = 0; - d->freelist_entries = 0; - d->sdcount = 0; - - /* Put the subdisk in tasted mode, and remove from drive list. */ - LIST_FOREACH_SAFE(s, &d->subdisks, from_drive, s2) { - LIST_REMOVE(s, from_drive); - s->flags |= GV_SD_TASTED; - } - - /* - * Don't forget that gv_is_newer wants a "real" drive at the beginning - * of the list, so, just to be safe, we shuffle around. - */ - LIST_REMOVE(d, drive); - d2 = LIST_FIRST(&sc->drives); - if (d2 == NULL) - LIST_INSERT_HEAD(&sc->drives, d, drive); - else - LIST_INSERT_AFTER(d2, d, drive); - gv_save_config(sc); -} diff --git a/sys/geom/vinum/geom_vinum_init.c b/sys/geom/vinum/geom_vinum_init.c deleted file mode 100644 --- a/sys/geom/vinum/geom_vinum_init.c +++ /dev/null @@ -1,388 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause - * - * Copyright (c) 2004, 2007 Lukas Ertl - * Copyright (c) 2007, 2009 Ulf Lilleengen - * 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/param.h> -#include <sys/bio.h> -#include <sys/libkern.h> -#include <sys/malloc.h> - -#include <geom/geom.h> -#include <geom/geom_dbg.h> -#include <geom/vinum/geom_vinum_var.h> -#include <geom/vinum/geom_vinum.h> - -static int gv_sync(struct gv_volume *); -static int gv_rebuild_plex(struct gv_plex *); -static int gv_init_plex(struct gv_plex *); -static int gv_grow_plex(struct gv_plex *); -static int gv_sync_plex(struct gv_plex *, struct gv_plex *); -static struct gv_plex *gv_find_good_plex(struct gv_volume *); - -void -gv_start_obj(struct g_geom *gp, struct gctl_req *req) -{ - struct gv_softc *sc; - struct gv_volume *v; - struct gv_plex *p; - int *argc, *initsize; - char *argv, buf[20]; - int i, type; - - argc = gctl_get_paraml(req, "argc", sizeof(*argc)); - initsize = gctl_get_paraml(req, "initsize", sizeof(*initsize)); - - if (argc == NULL || *argc == 0) { - gctl_error(req, "no arguments given"); - return; - } - - sc = gp->softc; - - for (i = 0; i < *argc; i++) { - snprintf(buf, sizeof(buf), "argv%d", i); - argv = gctl_get_param(req, buf, NULL); - if (argv == NULL) - continue; - type = gv_object_type(sc, argv); - switch (type) { - case GV_TYPE_VOL: - v = gv_find_vol(sc, argv); - if (v != NULL) - gv_post_event(sc, GV_EVENT_START_VOLUME, v, - NULL, *initsize, 0); - break; - - case GV_TYPE_PLEX: - p = gv_find_plex(sc, argv); - if (p != NULL) - gv_post_event(sc, GV_EVENT_START_PLEX, p, NULL, - *initsize, 0); - break; - - case GV_TYPE_SD: - case GV_TYPE_DRIVE: - /* XXX Not implemented, but what is the use? */ - gctl_error(req, "unable to start '%s' - not yet supported", - argv); - return; - default: - gctl_error(req, "unknown object '%s'", argv); - return; - } - } -} - -int -gv_start_plex(struct gv_plex *p) -{ - struct gv_volume *v; - struct gv_plex *up; - struct gv_sd *s; - int error; - - KASSERT(p != NULL, ("gv_start_plex: NULL p")); - - error = 0; - v = p->vol_sc; - - /* RAID5 plexes can either be init, rebuilt or grown. */ - if (p->org == GV_PLEX_RAID5) { - if (p->state > GV_PLEX_DEGRADED) { - LIST_FOREACH(s, &p->subdisks, in_plex) { - if (s->flags & GV_SD_GROW) { - error = gv_grow_plex(p); - return (error); - } - } - } else if (p->state == GV_PLEX_DEGRADED) { - error = gv_rebuild_plex(p); - } else - error = gv_init_plex(p); - } else { - /* We want to sync from the other plex if we're down. */ - if (p->state == GV_PLEX_DOWN && v->plexcount > 1) { - up = gv_find_good_plex(v); - if (up == NULL) { - G_VINUM_DEBUG(1, "unable to find a good plex"); - return (ENXIO); - } - g_topology_lock(); - error = gv_access(v->provider, 1, 1, 0); - if (error) { - g_topology_unlock(); - G_VINUM_DEBUG(0, "sync from '%s' failed to " - "access volume: %d", up->name, error); - return (error); - } - g_topology_unlock(); - error = gv_sync_plex(p, up); - if (error) - return (error); - /* - * In case we have a stripe that is up, check whether it can be - * grown. - */ - } else if (p->org == GV_PLEX_STRIPED && - p->state != GV_PLEX_DOWN) { - LIST_FOREACH(s, &p->subdisks, in_plex) { - if (s->flags & GV_SD_GROW) { - error = gv_grow_plex(p); - break; - } - } - } - } - return (error); -} - -int -gv_start_vol(struct gv_volume *v) -{ - struct gv_plex *p; - int error; - - KASSERT(v != NULL, ("gv_start_vol: NULL v")); - - error = 0; - - if (v->plexcount == 0) - return (ENXIO); - - else if (v->plexcount == 1) { - p = LIST_FIRST(&v->plexes); - KASSERT(p != NULL, ("gv_start_vol: NULL p on %s", v->name)); - error = gv_start_plex(p); - } else - error = gv_sync(v); - - return (error); -} - -/* Sync a plex p from the plex up. */ -static int -gv_sync_plex(struct gv_plex *p, struct gv_plex *up) -{ - int error; - - KASSERT(p != NULL, ("%s: NULL p", __func__)); - KASSERT(up != NULL, ("%s: NULL up", __func__)); - if ((p == up) || (p->state == GV_PLEX_UP)) - return (0); - if (p->flags & GV_PLEX_SYNCING || - p->flags & GV_PLEX_REBUILDING || - p->flags & GV_PLEX_GROWING) { - return (EINPROGRESS); - } - p->synced = 0; - p->flags |= GV_PLEX_SYNCING; - G_VINUM_DEBUG(1, "starting sync of plex %s", p->name); - error = gv_sync_request(up, p, p->synced, - MIN(GV_DFLT_SYNCSIZE, up->size - p->synced), - BIO_READ, NULL); - if (error) { - G_VINUM_DEBUG(0, "error syncing plex %s", p->name); - return (error); - } - return (0); -} - -/* Return a good plex from volume v. */ -static struct gv_plex * -gv_find_good_plex(struct gv_volume *v) -{ - struct gv_plex *up; - - /* Find the plex that's up. */ - up = NULL; - LIST_FOREACH(up, &v->plexes, in_volume) { - if (up->state == GV_PLEX_UP) - break; - } - /* Didn't find a good plex. */ - return (up); -} - -static int -gv_sync(struct gv_volume *v) -{ - struct gv_softc *sc __diagused; - struct gv_plex *p, *up; - int error; - - KASSERT(v != NULL, ("gv_sync: NULL v")); - sc = v->vinumconf; - KASSERT(sc != NULL, ("gv_sync: NULL sc on %s", v->name)); - - up = gv_find_good_plex(v); - if (up == NULL) - return (ENXIO); - g_topology_lock(); - error = gv_access(v->provider, 1, 1, 0); - if (error) { - g_topology_unlock(); - G_VINUM_DEBUG(0, "sync from '%s' failed to access volume: %d", - up->name, error); - return (error); - } - g_topology_unlock(); - - /* Go through the good plex, and issue BIO's to all other plexes. */ - LIST_FOREACH(p, &v->plexes, in_volume) { - error = gv_sync_plex(p, up); - if (error) - break; - } - return (0); -} - -static int -gv_rebuild_plex(struct gv_plex *p) -{ - struct gv_drive *d; - struct gv_sd *s; - int error; - - if (p->flags & GV_PLEX_SYNCING || - p->flags & GV_PLEX_REBUILDING || - p->flags & GV_PLEX_GROWING) - return (EINPROGRESS); - /* - * Make sure that all subdisks have consumers. We won't allow a rebuild - * unless every subdisk have one. - */ - LIST_FOREACH(s, &p->subdisks, in_plex) { - d = s->drive_sc; - if (d == NULL || (d->flags & GV_DRIVE_REFERENCED)) { - G_VINUM_DEBUG(0, "unable to rebuild %s, subdisk(s) have" - " no drives", p->name); - return (ENXIO); - } - } - p->flags |= GV_PLEX_REBUILDING; - p->synced = 0; - - g_topology_assert_not(); - g_topology_lock(); - error = gv_access(p->vol_sc->provider, 1, 1, 0); - if (error) { - G_VINUM_DEBUG(0, "unable to access provider"); - return (0); - } - g_topology_unlock(); - - gv_parity_request(p, GV_BIO_REBUILD, 0); - return (0); -} - -static int -gv_grow_plex(struct gv_plex *p) -{ - struct gv_volume *v; - struct gv_sd *s; - off_t origsize, origlength; - int error, sdcount; - - KASSERT(p != NULL, ("gv_grow_plex: NULL p")); - v = p->vol_sc; - KASSERT(v != NULL, ("gv_grow_plex: NULL v")); - - if (p->flags & GV_PLEX_GROWING || - p->flags & GV_PLEX_SYNCING || - p->flags & GV_PLEX_REBUILDING) - return (EINPROGRESS); - g_topology_lock(); - error = gv_access(v->provider, 1, 1, 0); - g_topology_unlock(); - if (error) { - G_VINUM_DEBUG(0, "unable to access provider"); - return (error); - } - - /* XXX: This routine with finding origsize is used two other places as - * well, so we should create a function for it. */ - sdcount = p->sdcount; - LIST_FOREACH(s, &p->subdisks, in_plex) { - if (s->flags & GV_SD_GROW) - sdcount--; - } - s = LIST_FIRST(&p->subdisks); - if (s == NULL) { - G_VINUM_DEBUG(0, "error growing plex without subdisks"); - return (GV_ERR_NOTFOUND); - } - p->flags |= GV_PLEX_GROWING; - origsize = (sdcount - 1) * s->size; - origlength = (sdcount - 1) * p->stripesize; - p->synced = 0; - G_VINUM_DEBUG(1, "starting growing of plex %s", p->name); - gv_grow_request(p, 0, MIN(origlength, origsize), BIO_READ, NULL); - - return (0); -} - -static int -gv_init_plex(struct gv_plex *p) -{ - struct gv_drive *d; - struct gv_sd *s; - int error; - off_t start; - caddr_t data; - - KASSERT(p != NULL, ("gv_init_plex: NULL p")); - - LIST_FOREACH(s, &p->subdisks, in_plex) { - if (s->state == GV_SD_INITIALIZING) - return (EINPROGRESS); - gv_set_sd_state(s, GV_SD_INITIALIZING, GV_SETSTATE_FORCE); - s->init_size = GV_DFLT_SYNCSIZE; - start = s->drive_offset + s->initialized; - d = s->drive_sc; - if (d == NULL) { - G_VINUM_DEBUG(0, "subdisk %s has no drive yet", s->name); - break; - } - /* - * Take the lock here since we need to avoid a race in - * gv_init_request if the BIO is completed before the lock is - * released. - */ - g_topology_lock(); - error = g_access(d->consumer, 0, 1, 0); - g_topology_unlock(); - if (error) { - G_VINUM_DEBUG(0, "error accessing consumer when " - "initializing %s", s->name); - break; - } - data = g_malloc(s->init_size, M_WAITOK | M_ZERO); - gv_init_request(s, start, data, s->init_size); - } - return (0); -} diff --git a/sys/geom/vinum/geom_vinum_list.c b/sys/geom/vinum/geom_vinum_list.c deleted file mode 100644 --- a/sys/geom/vinum/geom_vinum_list.c +++ /dev/null @@ -1,500 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause - * - * Copyright (c) 2004, 2007 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 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 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/types.h> -#include <sys/libkern.h> -#include <sys/malloc.h> -#include <sys/sbuf.h> - -#include <geom/geom.h> -#include <geom/vinum/geom_vinum_var.h> -#include <geom/vinum/geom_vinum.h> -#include <geom/vinum/geom_vinum_share.h> - -void gv_lvi(struct gv_volume *, struct sbuf *, int); -void gv_lpi(struct gv_plex *, struct sbuf *, int); -void gv_lsi(struct gv_sd *, struct sbuf *, int); -void gv_ldi(struct gv_drive *, struct sbuf *, int); - -void -gv_list(struct g_geom *gp, struct gctl_req *req) -{ - struct gv_softc *sc; - struct gv_drive *d; - struct gv_plex *p; - struct gv_sd *s; - struct gv_volume *v; - struct sbuf *sb; - int *argc, i, *flags, type; - char *arg, buf[20], *cmd; - - argc = gctl_get_paraml(req, "argc", sizeof(*argc)); - - if (argc == NULL) { - gctl_error(req, "no arguments given"); - return; - } - - flags = gctl_get_paraml(req, "flags", sizeof(*flags)); - if (flags == NULL) { - gctl_error(req, "no flags given"); - return; - } - - sc = gp->softc; - - sb = sbuf_new(NULL, NULL, GV_CFG_LEN, SBUF_FIXEDLEN); - - /* Figure out which command was given. */ - cmd = gctl_get_param(req, "cmd", NULL); - if (cmd == NULL) { - gctl_error(req, "no command given"); - return; - } - - /* List specific objects or everything. */ - if (!strcmp(cmd, "list") || !strcmp(cmd, "l")) { - if (*argc) { - for (i = 0; i < *argc; i++) { - snprintf(buf, sizeof(buf), "argv%d", i); - arg = gctl_get_param(req, buf, NULL); - if (arg == NULL) - continue; - type = gv_object_type(sc, arg); - switch (type) { - case GV_TYPE_VOL: - v = gv_find_vol(sc, arg); - gv_lvi(v, sb, *flags); - break; - case GV_TYPE_PLEX: - p = gv_find_plex(sc, arg); - gv_lpi(p, sb, *flags); - break; - case GV_TYPE_SD: - s = gv_find_sd(sc, arg); - gv_lsi(s, sb, *flags); - break; - case GV_TYPE_DRIVE: - d = gv_find_drive(sc, arg); - gv_ldi(d, sb, *flags); - break; - default: - gctl_error(req, "unknown object '%s'", - arg); - break; - } - } - } else { - gv_ld(gp, req, sb); - sbuf_printf(sb, "\n"); - gv_lv(gp, req, sb); - sbuf_printf(sb, "\n"); - gv_lp(gp, req, sb); - sbuf_printf(sb, "\n"); - gv_ls(gp, req, sb); - } - - /* List drives. */ - } else if (!strcmp(cmd, "ld")) { - if (*argc) { - for (i = 0; i < *argc; i++) { - snprintf(buf, sizeof(buf), "argv%d", i); - arg = gctl_get_param(req, buf, NULL); - if (arg == NULL) - continue; - type = gv_object_type(sc, arg); - if (type != GV_TYPE_DRIVE) { - gctl_error(req, "'%s' is not a drive", - arg); - continue; - } else { - d = gv_find_drive(sc, arg); - gv_ldi(d, sb, *flags); - } - } - } else - gv_ld(gp, req, sb); - - /* List volumes. */ - } else if (!strcmp(cmd, "lv")) { - if (*argc) { - for (i = 0; i < *argc; i++) { - snprintf(buf, sizeof(buf), "argv%d", i); - arg = gctl_get_param(req, buf, NULL); - if (arg == NULL) - continue; - type = gv_object_type(sc, arg); - if (type != GV_TYPE_VOL) { - gctl_error(req, "'%s' is not a volume", - arg); - continue; - } else { - v = gv_find_vol(sc, arg); - gv_lvi(v, sb, *flags); - } - } - } else - gv_lv(gp, req, sb); - - /* List plexes. */ - } else if (!strcmp(cmd, "lp")) { - if (*argc) { - for (i = 0; i < *argc; i++) { - snprintf(buf, sizeof(buf), "argv%d", i); - arg = gctl_get_param(req, buf, NULL); - if (arg == NULL) - continue; - type = gv_object_type(sc, arg); - if (type != GV_TYPE_PLEX) { - gctl_error(req, "'%s' is not a plex", - arg); - continue; - } else { - p = gv_find_plex(sc, arg); - gv_lpi(p, sb, *flags); - } - } - } else - gv_lp(gp, req, sb); - - /* List subdisks. */ - } else if (!strcmp(cmd, "ls")) { - if (*argc) { - for (i = 0; i < *argc; i++) { - snprintf(buf, sizeof(buf), "argv%d", i); - arg = gctl_get_param(req, buf, NULL); - if (arg == NULL) - continue; - type = gv_object_type(sc, arg); - if (type != GV_TYPE_SD) { - gctl_error(req, "'%s' is not a subdisk", - arg); - continue; - } else { - s = gv_find_sd(sc, arg); - gv_lsi(s, sb, *flags); - } - } - } else - gv_ls(gp, req, sb); - - } else - gctl_error(req, "unknown command '%s'", cmd); - - sbuf_finish(sb); - gctl_set_param(req, "config", sbuf_data(sb), sbuf_len(sb) + 1); - sbuf_delete(sb); -} - -/* List one or more volumes. */ -void -gv_lv(struct g_geom *gp, struct gctl_req *req, struct sbuf *sb) -{ - struct gv_softc *sc; - struct gv_volume *v; - int i, *flags; - - sc = gp->softc; - i = 0; - - LIST_FOREACH(v, &sc->volumes, volume) - i++; - - sbuf_printf(sb, "%d volume%s:\n", i, i == 1 ? "" : "s"); - - if (i) { - flags = gctl_get_paraml(req, "flags", sizeof(*flags)); - LIST_FOREACH(v, &sc->volumes, volume) - gv_lvi(v, sb, *flags); - } -} - -/* List a single volume. */ -void -gv_lvi(struct gv_volume *v, struct sbuf *sb, int flags) -{ - struct gv_plex *p; - int i; - - if (flags & GV_FLAG_V) { - sbuf_printf(sb, "Volume %s:\tSize: %jd bytes (%jd MB)\n", - v->name, (intmax_t)v->size, (intmax_t)v->size / MEGABYTE); - sbuf_printf(sb, "\t\tState: %s\n", gv_volstate(v->state)); - } else { - sbuf_printf(sb, "V %-21s State: %s\tPlexes: %7d\tSize: %s\n", - v->name, gv_volstate(v->state), v->plexcount, - gv_roughlength(v->size, 0)); - } - - if (flags & GV_FLAG_VV) { - i = 0; - LIST_FOREACH(p, &v->plexes, in_volume) { - sbuf_printf(sb, "\t\tPlex %2d:\t%s\t(%s), %s\n", i, - p->name, gv_plexstate(p->state), - gv_roughlength(p->size, 0)); - i++; - } - } - - if (flags & GV_FLAG_R) { - LIST_FOREACH(p, &v->plexes, in_volume) - gv_lpi(p, sb, flags); - } -} - -/* List one or more plexes. */ -void -gv_lp(struct g_geom *gp, struct gctl_req *req, struct sbuf *sb) -{ - struct gv_softc *sc; - struct gv_plex *p; - int i, *flags; - - sc = gp->softc; - i = 0; - - LIST_FOREACH(p, &sc->plexes, plex) - i++; - - sbuf_printf(sb, "%d plex%s:\n", i, i == 1 ? "" : "es"); - - if (i) { - flags = gctl_get_paraml(req, "flags", sizeof(*flags)); - LIST_FOREACH(p, &sc->plexes, plex) - gv_lpi(p, sb, *flags); - } -} - -/* List a single plex. */ -void -gv_lpi(struct gv_plex *p, struct sbuf *sb, int flags) -{ - struct gv_sd *s; - int i; - - if (flags & GV_FLAG_V) { - sbuf_printf(sb, "Plex %s:\tSize:\t%9jd bytes (%jd MB)\n", - p->name, (intmax_t)p->size, (intmax_t)p->size / MEGABYTE); - sbuf_printf(sb, "\t\tSubdisks: %8d\n", p->sdcount); - sbuf_printf(sb, "\t\tState: %s\n", gv_plexstate(p->state)); - if ((p->flags & GV_PLEX_SYNCING) || - (p->flags & GV_PLEX_GROWING) || - (p->flags & GV_PLEX_REBUILDING)) { - sbuf_printf(sb, "\t\tSynced: "); - sbuf_printf(sb, "%16jd bytes (%d%%)\n", - (intmax_t)p->synced, - (p->size > 0) ? (int)((p->synced * 100) / p->size) : - 0); - } - sbuf_printf(sb, "\t\tOrganization: %s", gv_plexorg(p->org)); - if (gv_is_striped(p)) { - sbuf_printf(sb, "\tStripe size: %s\n", - gv_roughlength(p->stripesize, 1)); - } - sbuf_printf(sb, "\t\tFlags: %d\n", p->flags); - if (p->vol_sc != NULL) { - sbuf_printf(sb, "\t\tPart of volume %s\n", p->volume); - } - } else { - sbuf_printf(sb, "P %-18s %2s State: ", p->name, - gv_plexorg_short(p->org)); - if ((p->flags & GV_PLEX_SYNCING) || - (p->flags & GV_PLEX_GROWING) || - (p->flags & GV_PLEX_REBUILDING)) { - sbuf_printf(sb, "S %d%%\t", (int)((p->synced * 100) / - p->size)); - } else { - sbuf_printf(sb, "%s\t", gv_plexstate(p->state)); - } - sbuf_printf(sb, "Subdisks: %5d\tSize: %s\n", p->sdcount, - gv_roughlength(p->size, 0)); - } - - if (flags & GV_FLAG_VV) { - i = 0; - LIST_FOREACH(s, &p->subdisks, in_plex) { - sbuf_printf(sb, "\t\tSubdisk %d:\t%s\n", i, s->name); - sbuf_printf(sb, "\t\t state: %s\tsize %11jd " - "(%jd MB)\n", gv_sdstate(s->state), - (intmax_t)s->size, (intmax_t)s->size / MEGABYTE); - if (p->org == GV_PLEX_CONCAT) { - sbuf_printf(sb, "\t\t\toffset %9jd (0x%jx)\n", - (intmax_t)s->plex_offset, - (intmax_t)s->plex_offset); - } - i++; - } - } - - if (flags & GV_FLAG_R) { - LIST_FOREACH(s, &p->subdisks, in_plex) - gv_lsi(s, sb, flags); - } -} - -/* List one or more subdisks. */ -void -gv_ls(struct g_geom *gp, struct gctl_req *req, struct sbuf *sb) -{ - struct gv_softc *sc; - struct gv_sd *s; - int i, *flags; - - sc = gp->softc; - i = 0; - - LIST_FOREACH(s, &sc->subdisks, sd) - i++; - - sbuf_printf(sb, "%d subdisk%s:\n", i, i == 1 ? "" : "s"); - - if (i) { - flags = gctl_get_paraml(req, "flags", sizeof(*flags)); - LIST_FOREACH(s, &sc->subdisks, sd) - gv_lsi(s, sb, *flags); - } -} - -/* List a single subdisk. */ -void -gv_lsi(struct gv_sd *s, struct sbuf *sb, int flags) -{ - if (flags & GV_FLAG_V) { - sbuf_printf(sb, "Subdisk %s:\n", s->name); - sbuf_printf(sb, "\t\tSize: %16jd bytes (%jd MB)\n", - (intmax_t)s->size, (intmax_t)s->size / MEGABYTE); - sbuf_printf(sb, "\t\tState: %s\n", gv_sdstate(s->state)); - - if (s->state == GV_SD_INITIALIZING || - s->state == GV_SD_REVIVING) { - if (s->state == GV_SD_INITIALIZING) - sbuf_printf(sb, "\t\tInitialized: "); - else - sbuf_printf(sb, "\t\tRevived: "); - - sbuf_printf(sb, "%16jd bytes (%d%%)\n", - (intmax_t)s->initialized, - (int)((s->initialized * 100) / s->size)); - } - - if (s->plex_sc != NULL) { - sbuf_printf(sb, "\t\tPlex %s at offset %jd (%s)\n", - s->plex, (intmax_t)s->plex_offset, - gv_roughlength(s->plex_offset, 1)); - } - - sbuf_printf(sb, "\t\tDrive %s (%s) at offset %jd (%s)\n", - s->drive, - s->drive_sc == NULL ? "*missing*" : s->drive_sc->name, - (intmax_t)s->drive_offset, - gv_roughlength(s->drive_offset, 1)); - sbuf_printf(sb, "\t\tFlags: %d\n", s->flags); - } else { - sbuf_printf(sb, "S %-21s State: ", s->name); - if (s->state == GV_SD_INITIALIZING || - s->state == GV_SD_REVIVING) { - if (s->state == GV_SD_INITIALIZING) - sbuf_printf(sb, "I "); - else - sbuf_printf(sb, "R "); - sbuf_printf(sb, "%d%%\t", - (int)((s->initialized * 100) / s->size)); - } else { - sbuf_printf(sb, "%s\t", gv_sdstate(s->state)); - } - sbuf_printf(sb, "D: %-12s Size: %s\n", s->drive, - gv_roughlength(s->size, 0)); - } -} - -/* List one or more drives. */ -void -gv_ld(struct g_geom *gp, struct gctl_req *req, struct sbuf *sb) -{ - struct gv_softc *sc; - struct gv_drive *d; - int i, *flags; - - sc = gp->softc; - i = 0; - - LIST_FOREACH(d, &sc->drives, drive) - i++; - - sbuf_printf(sb, "%d drive%s:\n", i, i == 1 ? "" : "s"); - - if (i) { - flags = gctl_get_paraml(req, "flags", sizeof(*flags)); - LIST_FOREACH(d, &sc->drives, drive) - gv_ldi(d, sb, *flags); - } -} - -/* List a single drive. */ -void -gv_ldi(struct gv_drive *d, struct sbuf *sb, int flags) -{ - struct gv_freelist *fl; - struct gv_sd *s; - - /* Verbose listing. */ - if (flags & GV_FLAG_V) { - sbuf_printf(sb, "Drive %s:\tDevice %s\n", d->name, d->device); - sbuf_printf(sb, "\t\tSize: %16jd bytes (%jd MB)\n", - (intmax_t)d->size, (intmax_t)d->size / MEGABYTE); - sbuf_printf(sb, "\t\tUsed: %16jd bytes (%jd MB)\n", - (intmax_t)d->size - d->avail, - (intmax_t)(d->size - d->avail) / MEGABYTE); - sbuf_printf(sb, "\t\tAvailable: %11jd bytes (%jd MB)\n", - (intmax_t)d->avail, (intmax_t)d->avail / MEGABYTE); - sbuf_printf(sb, "\t\tState: %s\n", gv_drivestate(d->state)); - sbuf_printf(sb, "\t\tFlags: %d\n", d->flags); - - /* Be very verbose. */ - if (flags & GV_FLAG_VV) { - sbuf_printf(sb, "\t\tFree list contains %d entries:\n", - d->freelist_entries); - sbuf_printf(sb, "\t\t Offset\t Size\n"); - LIST_FOREACH(fl, &d->freelist, freelist) - sbuf_printf(sb, "\t\t%9jd\t%9jd\n", - (intmax_t)fl->offset, (intmax_t)fl->size); - } - } else { - sbuf_printf(sb, "D %-21s State: %s\t/dev/%s\tA: %jd/%jd MB " - "(%d%%)\n", d->name, gv_drivestate(d->state), d->device, - (intmax_t)d->avail / MEGABYTE, (intmax_t)d->size / MEGABYTE, - d->size > 0 ? (int)((d->avail * 100) / d->size) : 0); - } - - /* Recursive listing. */ - if (flags & GV_FLAG_R) { - LIST_FOREACH(s, &d->subdisks, from_drive) - gv_lsi(s, sb, flags); - } -} diff --git a/sys/geom/vinum/geom_vinum_move.c b/sys/geom/vinum/geom_vinum_move.c deleted file mode 100644 --- a/sys/geom/vinum/geom_vinum_move.c +++ /dev/null @@ -1,189 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause - * - * Copyright (c) 2005 Chris Jones - * All rights reserved. - * - * This software was developed for the FreeBSD Project by Chris Jones - * thanks to the support of Google's Summer of Code program and - * mentoring by Lukas Ertl. - * - * 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 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 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> -#include <sys/libkern.h> -#include <sys/malloc.h> - -#include <geom/geom.h> -#include <geom/geom_dbg.h> -#include <geom/vinum/geom_vinum_var.h> -#include <geom/vinum/geom_vinum.h> - -void -gv_move(struct g_geom *gp, struct gctl_req *req) -{ - struct gv_softc *sc; - struct gv_sd *s; - struct gv_drive *d; - char buf[20], *destination, *object; - int *argc, *flags, i, type; - - sc = gp->softc; - - argc = gctl_get_paraml(req, "argc", sizeof(*argc)); - if (argc == NULL) { - gctl_error(req, "no arguments given"); - return; - } - flags = gctl_get_paraml(req, "flags", sizeof(*flags)); - if (flags == NULL) { - gctl_error(req, "no flags given"); - return; - } - destination = gctl_get_param(req, "destination", NULL); - if (destination == NULL) { - gctl_error(req, "no destination given"); - return; - } - if (gv_object_type(sc, destination) != GV_TYPE_DRIVE) { - gctl_error(req, "destination '%s' is not a drive", destination); - return; - } - d = gv_find_drive(sc, destination); - - /* - * We start with 1 here, because argv[0] on the command line is the - * destination drive. - */ - for (i = 1; i < *argc; i++) { - snprintf(buf, sizeof(buf), "argv%d", i); - object = gctl_get_param(req, buf, NULL); - if (object == NULL) - continue; - - type = gv_object_type(sc, object); - if (type != GV_TYPE_SD) { - gctl_error(req, "you can only move subdisks; " - "'%s' is not a subdisk", object); - return; - } - - s = gv_find_sd(sc, object); - if (s == NULL) { - gctl_error(req, "unknown subdisk '%s'", object); - return; - } - gv_post_event(sc, GV_EVENT_MOVE_SD, s, d, *flags, 0); - } -} - -/* Move a subdisk. */ -int -gv_move_sd(struct gv_softc *sc, struct gv_sd *cursd, - struct gv_drive *destination, int flags) -{ - struct gv_drive *d; - struct gv_sd *newsd, *s, *s2; - struct gv_plex *p; - int err; - - g_topology_assert(); - KASSERT(cursd != NULL, ("gv_move_sd: NULL cursd")); - KASSERT(destination != NULL, ("gv_move_sd: NULL destination")); - - d = cursd->drive_sc; - - if ((gv_consumer_is_open(d->consumer) || - gv_consumer_is_open(destination->consumer)) && - !(flags & GV_FLAG_F)) { - G_VINUM_DEBUG(0, "consumers on current and destination drive " - " still open"); - return (GV_ERR_ISBUSY); - } - - if (!(flags & GV_FLAG_F)) { - G_VINUM_DEBUG(1, "-f flag not passed; move would be " - "destructive"); - return (GV_ERR_INVFLAG); - } - - if (destination == cursd->drive_sc) { - G_VINUM_DEBUG(1, "subdisk '%s' already on drive '%s'", - cursd->name, destination->name); - return (GV_ERR_ISATTACHED); - } - - /* XXX: Does it have to be part of a plex? */ - p = gv_find_plex(sc, cursd->plex); - if (p == NULL) { - G_VINUM_DEBUG(0, "subdisk '%s' is not part of a plex", - cursd->name); - return (GV_ERR_NOTFOUND); - } - - /* Stale the old subdisk. */ - err = gv_set_sd_state(cursd, GV_SD_STALE, - GV_SETSTATE_FORCE | GV_SETSTATE_CONFIG); - if (err) { - G_VINUM_DEBUG(0, "unable to set the subdisk '%s' to state " - "'stale'", cursd->name); - return (err); - } - - /* - * Create new subdisk. Ideally, we'd use gv_new_sd, but that requires - * us to create a string for it to parse, which is silly. - * TODO: maybe refactor gv_new_sd such that this is no longer the case. - */ - newsd = g_malloc(sizeof(struct gv_sd), M_WAITOK | M_ZERO); - newsd->plex_offset = cursd->plex_offset; - newsd->size = cursd->size; - newsd->drive_offset = -1; - strlcpy(newsd->name, cursd->name, sizeof(newsd->name)); - strlcpy(newsd->drive, destination->name, sizeof(newsd->drive)); - strlcpy(newsd->plex, cursd->plex, sizeof(newsd->plex)); - newsd->state = GV_SD_STALE; - newsd->vinumconf = cursd->vinumconf; - - err = gv_sd_to_drive(newsd, destination); - if (err) { - /* XXX not enough free space? */ - g_free(newsd); - return (err); - } - - /* Replace the old sd by the new one. */ - LIST_FOREACH_SAFE(s, &p->subdisks, in_plex, s2) { - if (s == cursd) { - gv_rm_sd(sc, s); - } - } - gv_sd_to_plex(newsd, p); - LIST_INSERT_HEAD(&sc->subdisks, newsd, sd); - /* Update volume size of plex. */ - if (p->vol_sc != NULL) - gv_update_vol_size(p->vol_sc, gv_vol_size(p->vol_sc)); - gv_save_config(p->vinumconf); - return (0); -} diff --git a/sys/geom/vinum/geom_vinum_plex.c b/sys/geom/vinum/geom_vinum_plex.c deleted file mode 100644 --- a/sys/geom/vinum/geom_vinum_plex.c +++ /dev/null @@ -1,1045 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause - * - * Copyright (c) 2004, 2007 Lukas Ertl - * Copyright (c) 2007, 2009 Ulf Lilleengen - * 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/param.h> -#include <sys/bio.h> -#include <sys/lock.h> -#include <sys/malloc.h> -#include <sys/systm.h> - -#include <geom/geom.h> -#include <geom/geom_dbg.h> -#include <geom/vinum/geom_vinum_var.h> -#include <geom/vinum/geom_vinum_raid5.h> -#include <geom/vinum/geom_vinum.h> - -static int gv_check_parity(struct gv_plex *, struct bio *, - struct gv_raid5_packet *); -static int gv_normal_parity(struct gv_plex *, struct bio *, - struct gv_raid5_packet *); -static void gv_plex_flush(struct gv_plex *); -static int gv_plex_offset(struct gv_plex *, off_t, off_t, off_t *, off_t *, - int *, int); -static int gv_plex_normal_request(struct gv_plex *, struct bio *, off_t, - off_t, caddr_t); -static void gv_post_bio(struct gv_softc *, struct bio *); - -void -gv_plex_start(struct gv_plex *p, struct bio *bp) -{ - struct bio *cbp; - struct gv_sd *s; - struct gv_raid5_packet *wp; - caddr_t addr; - off_t bcount, boff, len; - - bcount = bp->bio_length; - addr = bp->bio_data; - boff = bp->bio_offset; - - /* Walk over the whole length of the request, we might split it up. */ - while (bcount > 0) { - wp = NULL; - - /* - * RAID5 plexes need special treatment, as a single request - * might involve several read/write sub-requests. - */ - if (p->org == GV_PLEX_RAID5) { - wp = gv_raid5_start(p, bp, addr, boff, bcount); - if (wp == NULL) - return; - - len = wp->length; - - if (TAILQ_EMPTY(&wp->bits)) - g_free(wp); - else if (wp->lockbase != -1) - TAILQ_INSERT_TAIL(&p->packets, wp, list); - - /* - * Requests to concatenated and striped plexes go straight - * through. - */ - } else { - len = gv_plex_normal_request(p, bp, boff, bcount, addr); - } - if (len < 0) - return; - - bcount -= len; - addr += len; - boff += len; - } - - /* - * Fire off all sub-requests. We get the correct consumer (== drive) - * to send each request to via the subdisk that was stored in - * cbp->bio_caller1. - */ - cbp = bioq_takefirst(p->bqueue); - while (cbp != NULL) { - /* - * RAID5 sub-requests need to come in correct order, otherwise - * we trip over the parity, as it might be overwritten by - * another sub-request. We abuse cbp->bio_caller2 to mark - * potential overlap situations. - */ - if (cbp->bio_caller2 != NULL && gv_stripe_active(p, cbp)) { - /* Park the bio on the waiting queue. */ - cbp->bio_pflags |= GV_BIO_ONHOLD; - bioq_disksort(p->wqueue, cbp); - } else { - s = cbp->bio_caller1; - g_io_request(cbp, s->drive_sc->consumer); - } - cbp = bioq_takefirst(p->bqueue); - } -} - -static int -gv_plex_offset(struct gv_plex *p, off_t boff, off_t bcount, off_t *real_off, - off_t *real_len, int *sdno, int growing) -{ - struct gv_sd *s; - int i, sdcount; - off_t len_left, stripeend, stripeno, stripestart; - - switch (p->org) { - case GV_PLEX_CONCAT: - /* - * Find the subdisk where this request starts. The subdisks in - * this list must be ordered by plex_offset. - */ - i = 0; - LIST_FOREACH(s, &p->subdisks, in_plex) { - if (s->plex_offset <= boff && - s->plex_offset + s->size > boff) { - *sdno = i; - break; - } - i++; - } - if (s == NULL || s->drive_sc == NULL) - return (GV_ERR_NOTFOUND); - - /* Calculate corresponding offsets on disk. */ - *real_off = boff - s->plex_offset; - len_left = s->size - (*real_off); - KASSERT(len_left >= 0, ("gv_plex_offset: len_left < 0")); - *real_len = (bcount > len_left) ? len_left : bcount; - break; - - case GV_PLEX_STRIPED: - /* The number of the stripe where the request starts. */ - stripeno = boff / p->stripesize; - KASSERT(stripeno >= 0, ("gv_plex_offset: stripeno < 0")); - - /* Take growing subdisks into account when calculating. */ - sdcount = gv_sdcount(p, (boff >= p->synced)); - - if (!(boff + bcount <= p->synced) && - (p->flags & GV_PLEX_GROWING) && - !growing) - return (GV_ERR_ISBUSY); - *sdno = stripeno % sdcount; - - KASSERT(*sdno >= 0, ("gv_plex_offset: sdno < 0")); - stripestart = (stripeno / sdcount) * - p->stripesize; - KASSERT(stripestart >= 0, ("gv_plex_offset: stripestart < 0")); - stripeend = stripestart + p->stripesize; - *real_off = boff - (stripeno * p->stripesize) + - stripestart; - len_left = stripeend - *real_off; - KASSERT(len_left >= 0, ("gv_plex_offset: len_left < 0")); - - *real_len = (bcount <= len_left) ? bcount : len_left; - break; - - default: - return (GV_ERR_PLEXORG); - } - return (0); -} - -/* - * Prepare a normal plex request. - */ -static int -gv_plex_normal_request(struct gv_plex *p, struct bio *bp, off_t boff, - off_t bcount, caddr_t addr) -{ - struct gv_sd *s; - struct bio *cbp; - off_t real_len, real_off; - int i, err, sdno; - - s = NULL; - sdno = -1; - real_len = real_off = 0; - - err = ENXIO; - - if (p == NULL || LIST_EMPTY(&p->subdisks)) - goto bad; - - err = gv_plex_offset(p, boff, bcount, &real_off, - &real_len, &sdno, (bp->bio_pflags & GV_BIO_GROW)); - /* If the request was blocked, put it into wait. */ - if (err == GV_ERR_ISBUSY) { - bioq_disksort(p->rqueue, bp); - return (-1); /* "Fail", and delay request. */ - } - if (err) { - err = ENXIO; - goto bad; - } - err = ENXIO; - - /* Find the right subdisk. */ - i = 0; - LIST_FOREACH(s, &p->subdisks, in_plex) { - if (i == sdno) - break; - i++; - } - - /* Subdisk not found. */ - if (s == NULL || s->drive_sc == NULL) - goto bad; - - /* Now check if we can handle the request on this subdisk. */ - switch (s->state) { - case GV_SD_UP: - /* If the subdisk is up, just continue. */ - break; - case GV_SD_DOWN: - if (bp->bio_pflags & GV_BIO_INTERNAL) - G_VINUM_DEBUG(0, "subdisk must be in the stale state in" - " order to perform administrative requests"); - goto bad; - case GV_SD_STALE: - if (!(bp->bio_pflags & GV_BIO_SYNCREQ)) { - G_VINUM_DEBUG(0, "subdisk stale, unable to perform " - "regular requests"); - goto bad; - } - - G_VINUM_DEBUG(1, "sd %s is initializing", s->name); - gv_set_sd_state(s, GV_SD_INITIALIZING, GV_SETSTATE_FORCE); - break; - case GV_SD_INITIALIZING: - if (bp->bio_cmd == BIO_READ) - goto bad; - break; - default: - /* All other subdisk states mean it's not accessible. */ - goto bad; - } - - /* Clone the bio and adjust the offsets and sizes. */ - cbp = g_clone_bio(bp); - if (cbp == NULL) { - err = ENOMEM; - goto bad; - } - cbp->bio_offset = real_off + s->drive_offset; - cbp->bio_length = real_len; - cbp->bio_data = addr; - cbp->bio_done = gv_done; - cbp->bio_caller1 = s; - s->drive_sc->active++; - - /* Store the sub-requests now and let others issue them. */ - bioq_insert_tail(p->bqueue, cbp); - return (real_len); -bad: - G_VINUM_LOGREQ(0, bp, "plex request failed."); - /* Building the sub-request failed. If internal BIO, do not deliver. */ - if (bp->bio_pflags & GV_BIO_INTERNAL) { - if (bp->bio_pflags & GV_BIO_MALLOC) - g_free(bp->bio_data); - g_destroy_bio(bp); - p->flags &= ~(GV_PLEX_SYNCING | GV_PLEX_REBUILDING | - GV_PLEX_GROWING); - return (-1); - } - g_io_deliver(bp, err); - return (-1); -} - -/* - * Handle a completed request to a striped or concatenated plex. - */ -void -gv_plex_normal_done(struct gv_plex *p, struct bio *bp) -{ - struct bio *pbp; - - pbp = bp->bio_parent; - if (pbp->bio_error == 0) - pbp->bio_error = bp->bio_error; - g_destroy_bio(bp); - pbp->bio_inbed++; - if (pbp->bio_children == pbp->bio_inbed) { - /* Just set it to length since multiple plexes will - * screw things up. */ - pbp->bio_completed = pbp->bio_length; - if (pbp->bio_pflags & GV_BIO_SYNCREQ) - gv_sync_complete(p, pbp); - else if (pbp->bio_pflags & GV_BIO_GROW) - gv_grow_complete(p, pbp); - else - g_io_deliver(pbp, pbp->bio_error); - } -} - -/* - * Handle a completed request to a RAID-5 plex. - */ -void -gv_plex_raid5_done(struct gv_plex *p, struct bio *bp) -{ - struct gv_softc *sc; - struct bio *cbp, *pbp; - struct gv_bioq *bq, *bq2; - struct gv_raid5_packet *wp; - off_t completed; - int i; - - completed = 0; - sc = p->vinumconf; - wp = bp->bio_caller2; - - switch (bp->bio_parent->bio_cmd) { - case BIO_READ: - if (wp == NULL) { - completed = bp->bio_completed; - break; - } - - TAILQ_FOREACH_SAFE(bq, &wp->bits, queue, bq2) { - if (bq->bp != bp) - continue; - TAILQ_REMOVE(&wp->bits, bq, queue); - g_free(bq); - for (i = 0; i < wp->length; i++) - wp->data[i] ^= bp->bio_data[i]; - break; - } - if (TAILQ_EMPTY(&wp->bits)) { - completed = wp->length; - if (wp->lockbase != -1) { - TAILQ_REMOVE(&p->packets, wp, list); - /* Bring the waiting bios back into the game. */ - pbp = bioq_takefirst(p->wqueue); - while (pbp != NULL) { - gv_post_bio(sc, pbp); - pbp = bioq_takefirst(p->wqueue); - } - } - g_free(wp); - } - - break; - - case BIO_WRITE: - /* XXX can this ever happen? */ - if (wp == NULL) { - completed = bp->bio_completed; - break; - } - - /* Check if we need to handle parity data. */ - TAILQ_FOREACH_SAFE(bq, &wp->bits, queue, bq2) { - if (bq->bp != bp) - continue; - TAILQ_REMOVE(&wp->bits, bq, queue); - g_free(bq); - cbp = wp->parity; - if (cbp != NULL) { - for (i = 0; i < wp->length; i++) - cbp->bio_data[i] ^= bp->bio_data[i]; - } - break; - } - - /* Handle parity data. */ - if (TAILQ_EMPTY(&wp->bits)) { - if (bp->bio_parent->bio_pflags & GV_BIO_CHECK) - i = gv_check_parity(p, bp, wp); - else - i = gv_normal_parity(p, bp, wp); - - /* All of our sub-requests have finished. */ - if (i) { - completed = wp->length; - TAILQ_REMOVE(&p->packets, wp, list); - /* Bring the waiting bios back into the game. */ - pbp = bioq_takefirst(p->wqueue); - while (pbp != NULL) { - gv_post_bio(sc, pbp); - pbp = bioq_takefirst(p->wqueue); - } - g_free(wp); - } - } - - break; - } - - pbp = bp->bio_parent; - if (pbp->bio_error == 0) - pbp->bio_error = bp->bio_error; - pbp->bio_completed += completed; - - /* When the original request is finished, we deliver it. */ - pbp->bio_inbed++; - if (pbp->bio_inbed == pbp->bio_children) { - /* Hand it over for checking or delivery. */ - if (pbp->bio_cmd == BIO_WRITE && - (pbp->bio_pflags & GV_BIO_CHECK)) { - gv_parity_complete(p, pbp); - } else if (pbp->bio_cmd == BIO_WRITE && - (pbp->bio_pflags & GV_BIO_REBUILD)) { - gv_rebuild_complete(p, pbp); - } else if (pbp->bio_pflags & GV_BIO_INIT) { - gv_init_complete(p, pbp); - } else if (pbp->bio_pflags & GV_BIO_SYNCREQ) { - gv_sync_complete(p, pbp); - } else if (pbp->bio_pflags & GV_BIO_GROW) { - gv_grow_complete(p, pbp); - } else { - g_io_deliver(pbp, pbp->bio_error); - } - } - - /* Clean up what we allocated. */ - if (bp->bio_cflags & GV_BIO_MALLOC) - g_free(bp->bio_data); - g_destroy_bio(bp); -} - -static int -gv_check_parity(struct gv_plex *p, struct bio *bp, struct gv_raid5_packet *wp) -{ - struct bio *pbp; - struct gv_sd *s; - int err, finished, i; - - err = 0; - finished = 1; - - if (wp->waiting != NULL) { - pbp = wp->waiting; - wp->waiting = NULL; - s = pbp->bio_caller1; - g_io_request(pbp, s->drive_sc->consumer); - finished = 0; - - } else if (wp->parity != NULL) { - pbp = wp->parity; - wp->parity = NULL; - - /* Check if the parity is correct. */ - for (i = 0; i < wp->length; i++) { - if (bp->bio_data[i] != pbp->bio_data[i]) { - err = 1; - break; - } - } - - /* The parity is not correct... */ - if (err) { - bp->bio_parent->bio_error = EAGAIN; - - /* ... but we rebuild it. */ - if (bp->bio_parent->bio_pflags & GV_BIO_PARITY) { - s = pbp->bio_caller1; - g_io_request(pbp, s->drive_sc->consumer); - finished = 0; - } - } - - /* - * Clean up the BIO we would have used for rebuilding the - * parity. - */ - if (finished) { - bp->bio_parent->bio_inbed++; - g_destroy_bio(pbp); - } - } - - return (finished); -} - -static int -gv_normal_parity(struct gv_plex *p, struct bio *bp, struct gv_raid5_packet *wp) -{ - struct bio *cbp, *pbp; - struct gv_sd *s; - int finished, i; - - finished = 1; - - if (wp->waiting != NULL) { - pbp = wp->waiting; - wp->waiting = NULL; - cbp = wp->parity; - for (i = 0; i < wp->length; i++) - cbp->bio_data[i] ^= pbp->bio_data[i]; - s = pbp->bio_caller1; - g_io_request(pbp, s->drive_sc->consumer); - finished = 0; - - } else if (wp->parity != NULL) { - cbp = wp->parity; - wp->parity = NULL; - s = cbp->bio_caller1; - g_io_request(cbp, s->drive_sc->consumer); - finished = 0; - } - - return (finished); -} - -/* Flush the queue with delayed requests. */ -static void -gv_plex_flush(struct gv_plex *p) -{ - struct bio *bp; - - bp = bioq_takefirst(p->rqueue); - while (bp != NULL) { - gv_plex_start(p, bp); - bp = bioq_takefirst(p->rqueue); - } -} - -static void -gv_post_bio(struct gv_softc *sc, struct bio *bp) -{ - - KASSERT(sc != NULL, ("NULL sc")); - KASSERT(bp != NULL, ("NULL bp")); - mtx_lock(&sc->bqueue_mtx); - bioq_disksort(sc->bqueue_down, bp); - wakeup(sc); - mtx_unlock(&sc->bqueue_mtx); -} - -int -gv_sync_request(struct gv_plex *from, struct gv_plex *to, off_t offset, - off_t length, int type, caddr_t data) -{ - struct gv_softc *sc; - struct bio *bp; - - KASSERT(from != NULL, ("NULL from")); - KASSERT(to != NULL, ("NULL to")); - sc = from->vinumconf; - KASSERT(sc != NULL, ("NULL sc")); - - bp = g_new_bio(); - if (bp == NULL) { - G_VINUM_DEBUG(0, "sync from '%s' failed at offset " - " %jd; out of memory", from->name, offset); - return (ENOMEM); - } - bp->bio_length = length; - bp->bio_done = NULL; - bp->bio_pflags |= GV_BIO_SYNCREQ; - bp->bio_offset = offset; - bp->bio_caller1 = from; - bp->bio_caller2 = to; - bp->bio_cmd = type; - if (data == NULL) - data = g_malloc(length, M_WAITOK); - bp->bio_pflags |= GV_BIO_MALLOC; /* Free on the next run. */ - bp->bio_data = data; - - /* Send down next. */ - gv_post_bio(sc, bp); - //gv_plex_start(from, bp); - return (0); -} - -/* - * Handle a finished plex sync bio. - */ -int -gv_sync_complete(struct gv_plex *to, struct bio *bp) -{ - struct gv_plex *from, *p; - struct gv_sd *s; - struct gv_volume *v; - struct gv_softc *sc; - off_t offset; - int err; - - g_topology_assert_not(); - - err = 0; - KASSERT(to != NULL, ("NULL to")); - KASSERT(bp != NULL, ("NULL bp")); - from = bp->bio_caller2; - KASSERT(from != NULL, ("NULL from")); - v = to->vol_sc; - KASSERT(v != NULL, ("NULL v")); - sc = v->vinumconf; - KASSERT(sc != NULL, ("NULL sc")); - - /* If it was a read, write it. */ - if (bp->bio_cmd == BIO_READ) { - err = gv_sync_request(from, to, bp->bio_offset, bp->bio_length, - BIO_WRITE, bp->bio_data); - /* If it was a write, read the next one. */ - } else if (bp->bio_cmd == BIO_WRITE) { - if (bp->bio_pflags & GV_BIO_MALLOC) - g_free(bp->bio_data); - to->synced += bp->bio_length; - /* If we're finished, clean up. */ - if (bp->bio_offset + bp->bio_length >= from->size) { - G_VINUM_DEBUG(1, "syncing of %s from %s completed", - to->name, from->name); - /* Update our state. */ - LIST_FOREACH(s, &to->subdisks, in_plex) - gv_set_sd_state(s, GV_SD_UP, 0); - gv_update_plex_state(to); - to->flags &= ~GV_PLEX_SYNCING; - to->synced = 0; - gv_post_event(sc, GV_EVENT_SAVE_CONFIG, sc, NULL, 0, 0); - } else { - offset = bp->bio_offset + bp->bio_length; - err = gv_sync_request(from, to, offset, - MIN(bp->bio_length, from->size - offset), - BIO_READ, NULL); - } - } - g_destroy_bio(bp); - /* Clean up if there was an error. */ - if (err) { - to->flags &= ~GV_PLEX_SYNCING; - G_VINUM_DEBUG(0, "error syncing plexes: error code %d", err); - } - - /* Check if all plexes are synced, and lower refcounts. */ - g_topology_lock(); - LIST_FOREACH(p, &v->plexes, in_volume) { - if (p->flags & GV_PLEX_SYNCING) { - g_topology_unlock(); - return (-1); - } - } - /* If we came here, all plexes are synced, and we're free. */ - gv_access(v->provider, -1, -1, 0); - g_topology_unlock(); - G_VINUM_DEBUG(1, "plex sync completed"); - gv_volume_flush(v); - return (0); -} - -/* - * Create a new bio struct for the next grow request. - */ -int -gv_grow_request(struct gv_plex *p, off_t offset, off_t length, int type, - caddr_t data) -{ - struct gv_softc *sc; - struct bio *bp; - - KASSERT(p != NULL, ("gv_grow_request: NULL p")); - sc = p->vinumconf; - KASSERT(sc != NULL, ("gv_grow_request: NULL sc")); - - bp = g_new_bio(); - if (bp == NULL) { - G_VINUM_DEBUG(0, "grow of %s failed creating bio: " - "out of memory", p->name); - return (ENOMEM); - } - - bp->bio_cmd = type; - bp->bio_done = NULL; - bp->bio_error = 0; - bp->bio_caller1 = p; - bp->bio_offset = offset; - bp->bio_length = length; - bp->bio_pflags |= GV_BIO_GROW; - if (data == NULL) - data = g_malloc(length, M_WAITOK); - bp->bio_pflags |= GV_BIO_MALLOC; - bp->bio_data = data; - - gv_post_bio(sc, bp); - //gv_plex_start(p, bp); - return (0); -} - -/* - * Finish handling of a bio to a growing plex. - */ -void -gv_grow_complete(struct gv_plex *p, struct bio *bp) -{ - struct gv_softc *sc; - struct gv_sd *s; - struct gv_volume *v; - off_t origsize, offset; - int sdcount, err; - - v = p->vol_sc; - KASSERT(v != NULL, ("gv_grow_complete: NULL v")); - sc = v->vinumconf; - KASSERT(sc != NULL, ("gv_grow_complete: NULL sc")); - err = 0; - - /* If it was a read, write it. */ - if (bp->bio_cmd == BIO_READ) { - p->synced += bp->bio_length; - err = gv_grow_request(p, bp->bio_offset, bp->bio_length, - BIO_WRITE, bp->bio_data); - /* If it was a write, read next. */ - } else if (bp->bio_cmd == BIO_WRITE) { - if (bp->bio_pflags & GV_BIO_MALLOC) - g_free(bp->bio_data); - - /* Find the real size of the plex. */ - sdcount = gv_sdcount(p, 1); - s = LIST_FIRST(&p->subdisks); - KASSERT(s != NULL, ("NULL s")); - origsize = (s->size * (sdcount - 1)); - if (bp->bio_offset + bp->bio_length >= origsize) { - G_VINUM_DEBUG(1, "growing of %s completed", p->name); - p->flags &= ~GV_PLEX_GROWING; - LIST_FOREACH(s, &p->subdisks, in_plex) { - s->flags &= ~GV_SD_GROW; - gv_set_sd_state(s, GV_SD_UP, 0); - } - p->size = gv_plex_size(p); - gv_update_vol_size(v, gv_vol_size(v)); - gv_set_plex_state(p, GV_PLEX_UP, 0); - g_topology_lock(); - gv_access(v->provider, -1, -1, 0); - g_topology_unlock(); - p->synced = 0; - gv_post_event(sc, GV_EVENT_SAVE_CONFIG, sc, NULL, 0, 0); - /* Issue delayed requests. */ - gv_plex_flush(p); - } else { - offset = bp->bio_offset + bp->bio_length; - err = gv_grow_request(p, offset, - MIN(bp->bio_length, origsize - offset), - BIO_READ, NULL); - } - } - g_destroy_bio(bp); - - if (err) { - p->flags &= ~GV_PLEX_GROWING; - G_VINUM_DEBUG(0, "error growing plex: error code %d", err); - } -} - -/* - * Create an initialization BIO and send it off to the consumer. Assume that - * we're given initialization data as parameter. - */ -void -gv_init_request(struct gv_sd *s, off_t start, caddr_t data, off_t length) -{ - struct gv_drive *d; - struct g_consumer *cp; - struct bio *bp, *cbp; - - KASSERT(s != NULL, ("gv_init_request: NULL s")); - d = s->drive_sc; - KASSERT(d != NULL, ("gv_init_request: NULL d")); - cp = d->consumer; - KASSERT(cp != NULL, ("gv_init_request: NULL cp")); - - bp = g_new_bio(); - if (bp == NULL) { - G_VINUM_DEBUG(0, "subdisk '%s' init: write failed at offset %jd" - " (drive offset %jd); out of memory", s->name, - (intmax_t)s->initialized, (intmax_t)start); - return; /* XXX: Error codes. */ - } - bp->bio_cmd = BIO_WRITE; - bp->bio_data = data; - bp->bio_done = NULL; - bp->bio_error = 0; - bp->bio_length = length; - bp->bio_pflags |= GV_BIO_INIT; - bp->bio_offset = start; - bp->bio_caller1 = s; - - /* Then ofcourse, we have to clone it. */ - cbp = g_clone_bio(bp); - if (cbp == NULL) { - G_VINUM_DEBUG(0, "subdisk '%s' init: write failed at offset %jd" - " (drive offset %jd); out of memory", s->name, - (intmax_t)s->initialized, (intmax_t)start); - return; /* XXX: Error codes. */ - } - cbp->bio_done = gv_done; - cbp->bio_caller1 = s; - d->active++; - /* Send it off to the consumer. */ - g_io_request(cbp, cp); -} - -/* - * Handle a finished initialization BIO. - */ -void -gv_init_complete(struct gv_plex *p, struct bio *bp) -{ - struct gv_softc *sc; - struct gv_drive *d; - struct g_consumer *cp; - struct gv_sd *s; - off_t start, length; - caddr_t data; - int error; - - s = bp->bio_caller1; - start = bp->bio_offset; - length = bp->bio_length; - error = bp->bio_error; - data = bp->bio_data; - - KASSERT(s != NULL, ("gv_init_complete: NULL s")); - d = s->drive_sc; - KASSERT(d != NULL, ("gv_init_complete: NULL d")); - cp = d->consumer; - KASSERT(cp != NULL, ("gv_init_complete: NULL cp")); - sc = p->vinumconf; - KASSERT(sc != NULL, ("gv_init_complete: NULL sc")); - - g_destroy_bio(bp); - - /* - * First we need to find out if it was okay, and abort if it's not. - * Then we need to free previous buffers, find out the correct subdisk, - * as well as getting the correct starting point and length of the BIO. - */ - if (start >= s->drive_offset + s->size) { - /* Free the data we initialized. */ - g_free(data); - g_topology_assert_not(); - g_topology_lock(); - g_access(cp, 0, -1, 0); - g_topology_unlock(); - if (error) { - gv_set_sd_state(s, GV_SD_STALE, GV_SETSTATE_FORCE | - GV_SETSTATE_CONFIG); - } else { - gv_set_sd_state(s, GV_SD_UP, GV_SETSTATE_CONFIG); - s->initialized = 0; - gv_post_event(sc, GV_EVENT_SAVE_CONFIG, sc, NULL, 0, 0); - G_VINUM_DEBUG(1, "subdisk '%s' init: finished " - "successfully", s->name); - } - return; - } - s->initialized += length; - start += length; - gv_init_request(s, start, data, length); -} - -/* - * Create a new bio struct for the next parity rebuild. Used both by internal - * rebuild of degraded plexes as well as user initiated rebuilds/checks. - */ -void -gv_parity_request(struct gv_plex *p, int flags, off_t offset) -{ - struct gv_softc *sc; - struct bio *bp; - - KASSERT(p != NULL, ("gv_parity_request: NULL p")); - sc = p->vinumconf; - KASSERT(sc != NULL, ("gv_parity_request: NULL sc")); - - bp = g_new_bio(); - if (bp == NULL) { - G_VINUM_DEBUG(0, "rebuild of %s failed creating bio: " - "out of memory", p->name); - return; - } - - bp->bio_cmd = BIO_WRITE; - bp->bio_done = NULL; - bp->bio_error = 0; - bp->bio_length = p->stripesize; - bp->bio_caller1 = p; - - /* - * Check if it's a rebuild of a degraded plex or a user request of - * parity rebuild. - */ - if (flags & GV_BIO_REBUILD) - bp->bio_data = g_malloc(GV_DFLT_SYNCSIZE, M_WAITOK); - else if (flags & GV_BIO_CHECK) - bp->bio_data = g_malloc(p->stripesize, M_WAITOK | M_ZERO); - else { - G_VINUM_DEBUG(0, "invalid flags given in rebuild"); - return; - } - - bp->bio_pflags = flags; - bp->bio_pflags |= GV_BIO_MALLOC; - - /* We still have more parity to build. */ - bp->bio_offset = offset; - gv_post_bio(sc, bp); - //gv_plex_start(p, bp); /* Send it down to the plex. */ -} - -/* - * Handle a finished parity write. - */ -void -gv_parity_complete(struct gv_plex *p, struct bio *bp) -{ - struct gv_softc *sc; - int error, flags; - - error = bp->bio_error; - flags = bp->bio_pflags; - flags &= ~GV_BIO_MALLOC; - - sc = p->vinumconf; - KASSERT(sc != NULL, ("gv_parity_complete: NULL sc")); - - /* Clean up what we allocated. */ - if (bp->bio_pflags & GV_BIO_MALLOC) - g_free(bp->bio_data); - g_destroy_bio(bp); - - if (error == EAGAIN) { - G_VINUM_DEBUG(0, "parity incorrect at offset 0x%jx", - (intmax_t)p->synced); - } - - /* Any error is fatal, except EAGAIN when we're rebuilding. */ - if (error && !(error == EAGAIN && (flags & GV_BIO_PARITY))) { - /* Make sure we don't have the lock. */ - g_topology_assert_not(); - g_topology_lock(); - gv_access(p->vol_sc->provider, -1, -1, 0); - g_topology_unlock(); - G_VINUM_DEBUG(0, "parity check on %s failed at 0x%jx " - "errno %d", p->name, (intmax_t)p->synced, error); - return; - } else { - p->synced += p->stripesize; - } - - if (p->synced >= p->size) { - /* Make sure we don't have the lock. */ - g_topology_assert_not(); - g_topology_lock(); - gv_access(p->vol_sc->provider, -1, -1, 0); - g_topology_unlock(); - /* We're finished. */ - G_VINUM_DEBUG(1, "parity operation on %s finished", p->name); - p->synced = 0; - gv_post_event(sc, GV_EVENT_SAVE_CONFIG, sc, NULL, 0, 0); - return; - } - - /* Send down next. It will determine if we need to itself. */ - gv_parity_request(p, flags, p->synced); -} - -/* - * Handle a finished plex rebuild bio. - */ -void -gv_rebuild_complete(struct gv_plex *p, struct bio *bp) -{ - struct gv_softc *sc; - struct gv_sd *s; - int error, flags; - off_t offset; - - error = bp->bio_error; - flags = bp->bio_pflags; - offset = bp->bio_offset; - flags &= ~GV_BIO_MALLOC; - sc = p->vinumconf; - KASSERT(sc != NULL, ("gv_rebuild_complete: NULL sc")); - - /* Clean up what we allocated. */ - if (bp->bio_pflags & GV_BIO_MALLOC) - g_free(bp->bio_data); - g_destroy_bio(bp); - - if (error) { - g_topology_assert_not(); - g_topology_lock(); - gv_access(p->vol_sc->provider, -1, -1, 0); - g_topology_unlock(); - - G_VINUM_DEBUG(0, "rebuild of %s failed at offset %jd errno: %d", - p->name, (intmax_t)offset, error); - p->flags &= ~GV_PLEX_REBUILDING; - p->synced = 0; - gv_plex_flush(p); /* Flush out remaining rebuild BIOs. */ - return; - } - - offset += (p->stripesize * (gv_sdcount(p, 1) - 1)); - if (offset >= p->size) { - /* We're finished. */ - g_topology_assert_not(); - g_topology_lock(); - gv_access(p->vol_sc->provider, -1, -1, 0); - g_topology_unlock(); - - G_VINUM_DEBUG(1, "rebuild of %s finished", p->name); - gv_save_config(p->vinumconf); - p->flags &= ~GV_PLEX_REBUILDING; - p->synced = 0; - /* Try to up all subdisks. */ - LIST_FOREACH(s, &p->subdisks, in_plex) - gv_update_sd_state(s); - gv_post_event(sc, GV_EVENT_SAVE_CONFIG, sc, NULL, 0, 0); - gv_plex_flush(p); /* Flush out remaining rebuild BIOs. */ - return; - } - - /* Send down next. It will determine if we need to itself. */ - gv_parity_request(p, flags, offset); -} diff --git a/sys/geom/vinum/geom_vinum_raid5.h b/sys/geom/vinum/geom_vinum_raid5.h deleted file mode 100644 --- a/sys/geom/vinum/geom_vinum_raid5.h +++ /dev/null @@ -1,55 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause - * - * Copyright (c) 2004, 2007 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. - */ - -#ifndef _GEOM_VINUM_RAID5_H_ -#define _GEOM_VINUM_RAID5_H_ - -/* - * A single RAID5 request usually needs more than one I/O transaction, - * depending on the state of the associated subdisks and the direction of the - * transaction (read or write). - */ - -struct gv_raid5_packet { - caddr_t data; /* Data buffer of this sub-request- */ - off_t length; /* Size of data buffer. */ - off_t lockbase; /* Deny access to our plex offset. */ - - struct bio *bio; /* Pointer to the original bio. */ - struct bio *parity; /* The bio containing the parity data. */ - struct bio *waiting; /* A bio that need to wait for other bios. */ - - TAILQ_HEAD(,gv_bioq) bits; /* List of subrequests. */ - TAILQ_ENTRY(gv_raid5_packet) list; /* Entry in plex's packet list. */ -}; - -struct gv_raid5_packet * gv_raid5_start(struct gv_plex *, struct bio *, - caddr_t, off_t, off_t); -int gv_stripe_active(struct gv_plex *, struct bio *); - -#endif /* !_GEOM_VINUM_RAID5_H_ */ diff --git a/sys/geom/vinum/geom_vinum_raid5.c b/sys/geom/vinum/geom_vinum_raid5.c deleted file mode 100644 --- a/sys/geom/vinum/geom_vinum_raid5.c +++ /dev/null @@ -1,662 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause - * - * Copyright (c) 2004, 2007 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/param.h> -#include <sys/bio.h> -#include <sys/lock.h> -#include <sys/malloc.h> -#include <sys/systm.h> - -#include <geom/geom.h> -#include <geom/geom_dbg.h> -#include <geom/vinum/geom_vinum_var.h> -#include <geom/vinum/geom_vinum_raid5.h> -#include <geom/vinum/geom_vinum.h> - -static int gv_raid5_offset(struct gv_plex *, off_t, off_t, - off_t *, off_t *, int *, int *, int); -static struct bio * gv_raid5_clone_bio(struct bio *, struct gv_sd *, - struct gv_raid5_packet *, caddr_t, int); -static int gv_raid5_request(struct gv_plex *, struct gv_raid5_packet *, - struct bio *, caddr_t, off_t, off_t, int *); -static int gv_raid5_check(struct gv_plex *, struct gv_raid5_packet *, - struct bio *, caddr_t, off_t, off_t); -static int gv_raid5_rebuild(struct gv_plex *, struct gv_raid5_packet *, - struct bio *, caddr_t, off_t, off_t); - -struct gv_raid5_packet * -gv_raid5_start(struct gv_plex *p, struct bio *bp, caddr_t addr, off_t boff, - off_t bcount) -{ - struct bio *cbp; - struct gv_raid5_packet *wp, *wp2; - struct gv_bioq *bq, *bq2; - int err, delay; - - delay = 0; - wp = g_malloc(sizeof(*wp), M_WAITOK | M_ZERO); - wp->bio = bp; - wp->waiting = NULL; - wp->parity = NULL; - TAILQ_INIT(&wp->bits); - - if (bp->bio_pflags & GV_BIO_REBUILD) - err = gv_raid5_rebuild(p, wp, bp, addr, boff, bcount); - else if (bp->bio_pflags & GV_BIO_CHECK) - err = gv_raid5_check(p, wp, bp, addr, boff, bcount); - else - err = gv_raid5_request(p, wp, bp, addr, boff, bcount, &delay); - - /* Means we have a delayed request. */ - if (delay) { - g_free(wp); - return (NULL); - } - - /* - * Building the sub-request failed, we probably need to clean up a lot. - */ - if (err) { - G_VINUM_LOGREQ(0, bp, "raid5 plex request failed."); - TAILQ_FOREACH_SAFE(bq, &wp->bits, queue, bq2) { - TAILQ_REMOVE(&wp->bits, bq, queue); - g_free(bq); - } - if (wp->waiting != NULL) { - if (wp->waiting->bio_cflags & GV_BIO_MALLOC) - g_free(wp->waiting->bio_data); - gv_drive_done(wp->waiting->bio_caller1); - g_destroy_bio(wp->waiting); - } - if (wp->parity != NULL) { - if (wp->parity->bio_cflags & GV_BIO_MALLOC) - g_free(wp->parity->bio_data); - gv_drive_done(wp->parity->bio_caller1); - g_destroy_bio(wp->parity); - } - g_free(wp); - - TAILQ_FOREACH_SAFE(wp, &p->packets, list, wp2) { - if (wp->bio != bp) - continue; - - TAILQ_REMOVE(&p->packets, wp, list); - TAILQ_FOREACH_SAFE(bq, &wp->bits, queue, bq2) { - TAILQ_REMOVE(&wp->bits, bq, queue); - g_free(bq); - } - g_free(wp); - } - - cbp = bioq_takefirst(p->bqueue); - while (cbp != NULL) { - if (cbp->bio_cflags & GV_BIO_MALLOC) - g_free(cbp->bio_data); - gv_drive_done(cbp->bio_caller1); - g_destroy_bio(cbp); - cbp = bioq_takefirst(p->bqueue); - } - - /* If internal, stop and reset state. */ - if (bp->bio_pflags & GV_BIO_INTERNAL) { - if (bp->bio_pflags & GV_BIO_MALLOC) - g_free(bp->bio_data); - g_destroy_bio(bp); - /* Reset flags. */ - p->flags &= ~(GV_PLEX_SYNCING | GV_PLEX_REBUILDING | - GV_PLEX_GROWING); - return (NULL); - } - g_io_deliver(bp, err); - return (NULL); - } - - return (wp); -} - -/* - * Check if the stripe that the work packet wants is already being used by - * some other work packet. - */ -int -gv_stripe_active(struct gv_plex *p, struct bio *bp) -{ - struct gv_raid5_packet *wp, *owp; - int overlap; - - wp = bp->bio_caller2; - if (wp->lockbase == -1) - return (0); - - overlap = 0; - TAILQ_FOREACH(owp, &p->packets, list) { - if (owp == wp) - break; - if ((wp->lockbase >= owp->lockbase) && - (wp->lockbase <= owp->lockbase + owp->length)) { - overlap++; - break; - } - if ((wp->lockbase <= owp->lockbase) && - (wp->lockbase + wp->length >= owp->lockbase)) { - overlap++; - break; - } - } - - return (overlap); -} - -static int -gv_raid5_check(struct gv_plex *p, struct gv_raid5_packet *wp, struct bio *bp, - caddr_t addr, off_t boff, off_t bcount) -{ - struct gv_sd *parity, *s; - struct gv_bioq *bq; - struct bio *cbp; - int i, psdno; - off_t real_len, real_off; - - if (p == NULL || LIST_EMPTY(&p->subdisks)) - return (ENXIO); - - gv_raid5_offset(p, boff, bcount, &real_off, &real_len, NULL, &psdno, 1); - - /* Find the right subdisk. */ - parity = NULL; - i = 0; - LIST_FOREACH(s, &p->subdisks, in_plex) { - if (i == psdno) { - parity = s; - break; - } - i++; - } - - /* Parity stripe not found. */ - if (parity == NULL) - return (ENXIO); - - if (parity->state != GV_SD_UP) - return (ENXIO); - - wp->length = real_len; - wp->data = addr; - wp->lockbase = real_off; - - /* Read all subdisks. */ - LIST_FOREACH(s, &p->subdisks, in_plex) { - /* Skip the parity subdisk. */ - if (s == parity) - continue; - /* Skip growing subdisks. */ - if (s->flags & GV_SD_GROW) - continue; - - cbp = gv_raid5_clone_bio(bp, s, wp, NULL, 1); - if (cbp == NULL) - return (ENOMEM); - cbp->bio_cmd = BIO_READ; - - bioq_insert_tail(p->bqueue, cbp); - - bq = g_malloc(sizeof(*bq), M_WAITOK | M_ZERO); - bq->bp = cbp; - TAILQ_INSERT_TAIL(&wp->bits, bq, queue); - } - - /* Read the parity data. */ - cbp = gv_raid5_clone_bio(bp, parity, wp, NULL, 1); - if (cbp == NULL) - return (ENOMEM); - cbp->bio_cmd = BIO_READ; - wp->waiting = cbp; - - /* - * In case we want to rebuild the parity, create an extra BIO to write - * it out. It also acts as buffer for the XOR operations. - */ - cbp = gv_raid5_clone_bio(bp, parity, wp, addr, 1); - if (cbp == NULL) - return (ENOMEM); - wp->parity = cbp; - - return (0); -} - -/* Rebuild a degraded RAID5 plex. */ -static int -gv_raid5_rebuild(struct gv_plex *p, struct gv_raid5_packet *wp, struct bio *bp, - caddr_t addr, off_t boff, off_t bcount) -{ - struct gv_sd *broken, *s; - struct gv_bioq *bq; - struct bio *cbp; - off_t real_len, real_off; - - if (p == NULL || LIST_EMPTY(&p->subdisks)) - return (ENXIO); - - gv_raid5_offset(p, boff, bcount, &real_off, &real_len, NULL, NULL, 1); - - /* Find the right subdisk. */ - broken = NULL; - LIST_FOREACH(s, &p->subdisks, in_plex) { - if (s->state != GV_SD_UP) - broken = s; - } - - /* Broken stripe not found. */ - if (broken == NULL) - return (ENXIO); - - switch (broken->state) { - case GV_SD_UP: - return (EINVAL); - - case GV_SD_STALE: - if (!(bp->bio_pflags & GV_BIO_REBUILD)) - return (ENXIO); - - G_VINUM_DEBUG(1, "sd %s is reviving", broken->name); - gv_set_sd_state(broken, GV_SD_REVIVING, GV_SETSTATE_FORCE); - /* Set this bit now, but should be set at end. */ - broken->flags |= GV_SD_CANGOUP; - break; - - case GV_SD_REVIVING: - break; - - default: - /* All other subdisk states mean it's not accessible. */ - return (ENXIO); - } - - wp->length = real_len; - wp->data = addr; - wp->lockbase = real_off; - - KASSERT(wp->length >= 0, ("gv_rebuild_raid5: wp->length < 0")); - - /* Read all subdisks. */ - LIST_FOREACH(s, &p->subdisks, in_plex) { - /* Skip the broken subdisk. */ - if (s == broken) - continue; - - /* Skip growing subdisks. */ - if (s->flags & GV_SD_GROW) - continue; - - cbp = gv_raid5_clone_bio(bp, s, wp, NULL, 1); - if (cbp == NULL) - return (ENOMEM); - cbp->bio_cmd = BIO_READ; - - bioq_insert_tail(p->bqueue, cbp); - - bq = g_malloc(sizeof(*bq), M_WAITOK | M_ZERO); - bq->bp = cbp; - TAILQ_INSERT_TAIL(&wp->bits, bq, queue); - } - - /* Write the parity data. */ - cbp = gv_raid5_clone_bio(bp, broken, wp, NULL, 1); - if (cbp == NULL) - return (ENOMEM); - wp->parity = cbp; - - p->synced = boff; - - /* Post notification that we're finished. */ - return (0); -} - -/* Build a request group to perform (part of) a RAID5 request. */ -static int -gv_raid5_request(struct gv_plex *p, struct gv_raid5_packet *wp, - struct bio *bp, caddr_t addr, off_t boff, off_t bcount, int *delay) -{ - struct gv_sd *broken, *original, *parity, *s; - struct gv_bioq *bq; - struct bio *cbp; - int i, psdno, sdno, type, grow; - off_t real_len, real_off; - - if (p == NULL || LIST_EMPTY(&p->subdisks)) - return (ENXIO); - - /* We are optimistic and assume that this request will be OK. */ -#define REQ_TYPE_NORMAL 0 -#define REQ_TYPE_DEGRADED 1 -#define REQ_TYPE_NOPARITY 2 - - type = REQ_TYPE_NORMAL; - original = parity = broken = NULL; - - /* XXX: The resize won't crash with rebuild or sync, but we should still - * be aware of it. Also this should perhaps be done on rebuild/check as - * well? - */ - /* If we're over, we must use the old. */ - if (boff >= p->synced) { - grow = 1; - /* Or if over the resized offset, we use all drives. */ - } else if (boff + bcount <= p->synced) { - grow = 0; - /* Else, we're in the middle, and must wait a bit. */ - } else { - bioq_disksort(p->rqueue, bp); - *delay = 1; - return (0); - } - gv_raid5_offset(p, boff, bcount, &real_off, &real_len, - &sdno, &psdno, grow); - - /* Find the right subdisks. */ - i = 0; - LIST_FOREACH(s, &p->subdisks, in_plex) { - if (i == sdno) - original = s; - if (i == psdno) - parity = s; - if (s->state != GV_SD_UP) - broken = s; - i++; - } - - if ((original == NULL) || (parity == NULL)) - return (ENXIO); - - /* Our data stripe is missing. */ - if (original->state != GV_SD_UP) - type = REQ_TYPE_DEGRADED; - - /* If synchronizing request, just write it if disks are stale. */ - if (original->state == GV_SD_STALE && parity->state == GV_SD_STALE && - bp->bio_pflags & GV_BIO_SYNCREQ && bp->bio_cmd == BIO_WRITE) { - type = REQ_TYPE_NORMAL; - /* Our parity stripe is missing. */ - } else if (parity->state != GV_SD_UP) { - /* We cannot take another failure if we're already degraded. */ - if (type != REQ_TYPE_NORMAL) - return (ENXIO); - else - type = REQ_TYPE_NOPARITY; - } - - wp->length = real_len; - wp->data = addr; - wp->lockbase = real_off; - - KASSERT(wp->length >= 0, ("gv_build_raid5_request: wp->length < 0")); - - if ((p->flags & GV_PLEX_REBUILDING) && (boff + real_len < p->synced)) - type = REQ_TYPE_NORMAL; - - if ((p->flags & GV_PLEX_REBUILDING) && (boff + real_len >= p->synced)) { - bioq_disksort(p->rqueue, bp); - *delay = 1; - return (0); - } - - switch (bp->bio_cmd) { - case BIO_READ: - /* - * For a degraded read we need to read in all stripes except - * the broken one plus the parity stripe and then recalculate - * the desired data. - */ - if (type == REQ_TYPE_DEGRADED) { - bzero(wp->data, wp->length); - LIST_FOREACH(s, &p->subdisks, in_plex) { - /* Skip the broken subdisk. */ - if (s == broken) - continue; - /* Skip growing if within offset. */ - if (grow && s->flags & GV_SD_GROW) - continue; - cbp = gv_raid5_clone_bio(bp, s, wp, NULL, 1); - if (cbp == NULL) - return (ENOMEM); - - bioq_insert_tail(p->bqueue, cbp); - - bq = g_malloc(sizeof(*bq), M_WAITOK | M_ZERO); - bq->bp = cbp; - TAILQ_INSERT_TAIL(&wp->bits, bq, queue); - } - - /* A normal read can be fulfilled with the original subdisk. */ - } else { - cbp = gv_raid5_clone_bio(bp, original, wp, addr, 0); - if (cbp == NULL) - return (ENOMEM); - - bioq_insert_tail(p->bqueue, cbp); - } - wp->lockbase = -1; - - break; - - case BIO_WRITE: - /* - * A degraded write means we cannot write to the original data - * subdisk. Thus we need to read in all valid stripes, - * recalculate the parity from the original data, and then - * write the parity stripe back out. - */ - if (type == REQ_TYPE_DEGRADED) { - /* Read all subdisks. */ - LIST_FOREACH(s, &p->subdisks, in_plex) { - /* Skip the broken and the parity subdisk. */ - if ((s == broken) || (s == parity)) - continue; - /* Skip growing if within offset. */ - if (grow && s->flags & GV_SD_GROW) - continue; - - cbp = gv_raid5_clone_bio(bp, s, wp, NULL, 1); - if (cbp == NULL) - return (ENOMEM); - cbp->bio_cmd = BIO_READ; - - bioq_insert_tail(p->bqueue, cbp); - - bq = g_malloc(sizeof(*bq), M_WAITOK | M_ZERO); - bq->bp = cbp; - TAILQ_INSERT_TAIL(&wp->bits, bq, queue); - } - - /* Write the parity data. */ - cbp = gv_raid5_clone_bio(bp, parity, wp, NULL, 1); - if (cbp == NULL) - return (ENOMEM); - bcopy(addr, cbp->bio_data, wp->length); - wp->parity = cbp; - - /* - * When the parity stripe is missing we just write out the data. - */ - } else if (type == REQ_TYPE_NOPARITY) { - cbp = gv_raid5_clone_bio(bp, original, wp, addr, 1); - if (cbp == NULL) - return (ENOMEM); - - bioq_insert_tail(p->bqueue, cbp); - - bq = g_malloc(sizeof(*bq), M_WAITOK | M_ZERO); - bq->bp = cbp; - TAILQ_INSERT_TAIL(&wp->bits, bq, queue); - - /* - * A normal write request goes to the original subdisk, then we - * read in all other stripes, recalculate the parity and write - * out the parity again. - */ - } else { - /* Read old parity. */ - cbp = gv_raid5_clone_bio(bp, parity, wp, NULL, 1); - if (cbp == NULL) - return (ENOMEM); - cbp->bio_cmd = BIO_READ; - - bioq_insert_tail(p->bqueue, cbp); - - bq = g_malloc(sizeof(*bq), M_WAITOK | M_ZERO); - bq->bp = cbp; - TAILQ_INSERT_TAIL(&wp->bits, bq, queue); - - /* Read old data. */ - cbp = gv_raid5_clone_bio(bp, original, wp, NULL, 1); - if (cbp == NULL) - return (ENOMEM); - cbp->bio_cmd = BIO_READ; - - bioq_insert_tail(p->bqueue, cbp); - - bq = g_malloc(sizeof(*bq), M_WAITOK | M_ZERO); - bq->bp = cbp; - TAILQ_INSERT_TAIL(&wp->bits, bq, queue); - - /* Write new data. */ - cbp = gv_raid5_clone_bio(bp, original, wp, addr, 1); - if (cbp == NULL) - return (ENOMEM); - - /* - * We must not write the new data until the old data - * was read, so hold this BIO back until we're ready - * for it. - */ - wp->waiting = cbp; - - /* The final bio for the parity. */ - cbp = gv_raid5_clone_bio(bp, parity, wp, NULL, 1); - if (cbp == NULL) - return (ENOMEM); - - /* Remember that this is the BIO for the parity data. */ - wp->parity = cbp; - } - break; - - default: - return (EINVAL); - } - - return (0); -} - -/* - * Calculate the offsets in the various subdisks for a RAID5 request. Also take - * care of new subdisks in an expanded RAID5 array. - * XXX: This assumes that the new subdisks are inserted after the others (which - * is okay as long as plex_offset is larger). If subdisks are inserted into the - * plexlist before, we get problems. - */ -static int -gv_raid5_offset(struct gv_plex *p, off_t boff, off_t bcount, off_t *real_off, - off_t *real_len, int *sdno, int *psdno, int growing) -{ - struct gv_sd *s; - int sd, psd, sdcount; - off_t len_left, stripeend, stripeoff, stripestart; - - sdcount = p->sdcount; - if (growing) { - LIST_FOREACH(s, &p->subdisks, in_plex) { - if (s->flags & GV_SD_GROW) - sdcount--; - } - } - - /* The number of the subdisk containing the parity stripe. */ - psd = sdcount - 1 - ( boff / (p->stripesize * (sdcount - 1))) % - sdcount; - KASSERT(psd >= 0, ("gv_raid5_offset: psdno < 0")); - - /* Offset of the start address from the start of the stripe. */ - stripeoff = boff % (p->stripesize * (sdcount - 1)); - KASSERT(stripeoff >= 0, ("gv_raid5_offset: stripeoff < 0")); - - /* The number of the subdisk where the stripe resides. */ - sd = stripeoff / p->stripesize; - KASSERT(sd >= 0, ("gv_raid5_offset: sdno < 0")); - - /* At or past parity subdisk. */ - if (sd >= psd) - sd++; - - /* The offset of the stripe on this subdisk. */ - stripestart = (boff - stripeoff) / (sdcount - 1); - KASSERT(stripestart >= 0, ("gv_raid5_offset: stripestart < 0")); - - stripeoff %= p->stripesize; - - /* The offset of the request on this subdisk. */ - *real_off = stripestart + stripeoff; - - stripeend = stripestart + p->stripesize; - len_left = stripeend - *real_off; - KASSERT(len_left >= 0, ("gv_raid5_offset: len_left < 0")); - - *real_len = (bcount <= len_left) ? bcount : len_left; - - if (sdno != NULL) - *sdno = sd; - if (psdno != NULL) - *psdno = psd; - - return (0); -} - -static struct bio * -gv_raid5_clone_bio(struct bio *bp, struct gv_sd *s, struct gv_raid5_packet *wp, - caddr_t addr, int use_wp) -{ - struct bio *cbp; - - cbp = g_clone_bio(bp); - if (cbp == NULL) - return (NULL); - if (addr == NULL) { - cbp->bio_data = g_malloc(wp->length, M_WAITOK | M_ZERO); - cbp->bio_cflags |= GV_BIO_MALLOC; - } else - cbp->bio_data = addr; - cbp->bio_offset = wp->lockbase + s->drive_offset; - cbp->bio_length = wp->length; - cbp->bio_done = gv_done; - cbp->bio_caller1 = s; - s->drive_sc->active++; - if (use_wp) - cbp->bio_caller2 = wp; - - return (cbp); -} diff --git a/sys/geom/vinum/geom_vinum_rename.c b/sys/geom/vinum/geom_vinum_rename.c deleted file mode 100644 --- a/sys/geom/vinum/geom_vinum_rename.c +++ /dev/null @@ -1,261 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause - * - * Copyright (c) 2005 Chris Jones - * All rights reserved. - * - * This software was developed for the FreeBSD Project by Chris Jones - * thanks to the support of Google's Summer of Code program and - * mentoring by Lukas Ertl. - * - * 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 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 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/param.h> -#include <sys/libkern.h> -#include <sys/malloc.h> - -#include <geom/geom.h> -#include <geom/geom_dbg.h> -#include <geom/vinum/geom_vinum_var.h> -#include <geom/vinum/geom_vinum.h> - -void -gv_rename(struct g_geom *gp, struct gctl_req *req) -{ - struct gv_softc *sc; - struct gv_volume *v; - struct gv_plex *p; - struct gv_sd *s; - struct gv_drive *d; - char *newname, *object, *name; - int *flags, type; - - sc = gp->softc; - - flags = gctl_get_paraml(req, "flags", sizeof(*flags)); - if (flags == NULL) { - gctl_error(req, "no flags given"); - return; - } - - newname = gctl_get_param(req, "newname", NULL); - if (newname == NULL) { - gctl_error(req, "no new name given"); - return; - } - - object = gctl_get_param(req, "object", NULL); - if (object == NULL) { - gctl_error(req, "no object given"); - return; - } - - type = gv_object_type(sc, object); - switch (type) { - case GV_TYPE_VOL: - v = gv_find_vol(sc, object); - if (v == NULL) { - gctl_error(req, "unknown volume '%s'", object); - return; - } - name = g_malloc(GV_MAXVOLNAME, M_WAITOK | M_ZERO); - strlcpy(name, newname, GV_MAXVOLNAME); - gv_post_event(sc, GV_EVENT_RENAME_VOL, v, name, *flags, 0); - break; - case GV_TYPE_PLEX: - p = gv_find_plex(sc, object); - if (p == NULL) { - gctl_error(req, "unknown plex '%s'", object); - return; - } - name = g_malloc(GV_MAXPLEXNAME, M_WAITOK | M_ZERO); - strlcpy(name, newname, GV_MAXPLEXNAME); - gv_post_event(sc, GV_EVENT_RENAME_PLEX, p, name, *flags, 0); - break; - case GV_TYPE_SD: - s = gv_find_sd(sc, object); - if (s == NULL) { - gctl_error(req, "unknown subdisk '%s'", object); - return; - } - name = g_malloc(GV_MAXSDNAME, M_WAITOK | M_ZERO); - strlcpy(name, newname, GV_MAXSDNAME); - gv_post_event(sc, GV_EVENT_RENAME_SD, s, name, *flags, 0); - break; - case GV_TYPE_DRIVE: - d = gv_find_drive(sc, object); - if (d == NULL) { - gctl_error(req, "unknown drive '%s'", object); - return; - } - name = g_malloc(GV_MAXDRIVENAME, M_WAITOK | M_ZERO); - strlcpy(name, newname, GV_MAXDRIVENAME); - gv_post_event(sc, GV_EVENT_RENAME_DRIVE, d, name, *flags, 0); - break; - default: - gctl_error(req, "unknown object '%s'", object); - return; - } -} - -int -gv_rename_drive(struct gv_softc *sc, struct gv_drive *d, char *newname, - int flags) -{ - struct gv_sd *s; - - KASSERT(d != NULL, ("gv_rename_drive: NULL d")); - - if (gv_object_type(sc, newname) != GV_ERR_NOTFOUND) { - G_VINUM_DEBUG(1, "drive name '%s' already in use", newname); - return (GV_ERR_NAMETAKEN); - } - - strlcpy(d->name, newname, sizeof(d->name)); - if (d->hdr != NULL) - strlcpy(d->hdr->label.name, newname, sizeof(d->hdr->label.name)); - - LIST_FOREACH(s, &d->subdisks, from_drive) - strlcpy(s->drive, d->name, sizeof(s->drive)); - - return (0); -} - -int -gv_rename_plex(struct gv_softc *sc, struct gv_plex *p, char *newname, int flags) -{ - char newsd[GV_MAXSDNAME]; - struct gv_sd *s; - char *ptr; - int err; - - KASSERT(p != NULL, ("gv_rename_plex: NULL p")); - - if (gv_object_type(sc, newname) != GV_ERR_NOTFOUND) { - G_VINUM_DEBUG(1, "plex name '%s' already in use", newname); - return (GV_ERR_NAMETAKEN); - } - - /* - * Locate the plex number part of the plex names. - * XXX: might be a good idea to sanitize input a bit more - */ - ptr = strrchr(newname, '.'); - if (ptr == NULL) { - G_VINUM_DEBUG(0, "proposed plex name '%s' is not a valid plex " - "name", newname); - return (GV_ERR_INVNAME); - } - - strlcpy(p->name, newname, sizeof(p->name)); - - /* Fix up references and potentially rename subdisks. */ - LIST_FOREACH(s, &p->subdisks, in_plex) { - strlcpy(s->plex, p->name, sizeof(s->plex)); - if (flags & GV_FLAG_R) { - /* - * Look for the two last dots in the string, and assume - * that the old value was ok. - */ - ptr = strrchr(s->name, '.'); - if (ptr == NULL) - return (GV_ERR_INVNAME); - ptr++; - snprintf(newsd, sizeof(newsd), "%s.%s", p->name, ptr); - err = gv_rename_sd(sc, s, newsd, flags); - if (err) - return (err); - } - } - return (0); -} - -/* - * gv_rename_sd: renames a subdisk. Note that the 'flags' argument is ignored, - * since there are no structures below a subdisk. Similarly, we don't have to - * clean up any references elsewhere to the subdisk's name. - */ -int -gv_rename_sd(struct gv_softc *sc, struct gv_sd *s, char *newname, int flags) -{ - char *dot1, *dot2; - - KASSERT(s != NULL, ("gv_rename_sd: NULL s")); - - if (gv_object_type(sc, newname) != GV_ERR_NOTFOUND) { - G_VINUM_DEBUG(1, "subdisk name %s already in use", newname); - return (GV_ERR_NAMETAKEN); - } - - /* Locate the sd number part of the sd names. */ - dot1 = strchr(newname, '.'); - if (dot1 == NULL || (dot2 = strchr(dot1 + 1, '.')) == NULL) { - G_VINUM_DEBUG(0, "proposed sd name '%s' is not a valid sd name", - newname); - return (GV_ERR_INVNAME); - } - strlcpy(s->name, newname, sizeof(s->name)); - return (0); -} - -int -gv_rename_vol(struct gv_softc *sc, struct gv_volume *v, char *newname, - int flags) -{ - struct g_provider *pp __diagused; - struct gv_plex *p; - char newplex[GV_MAXPLEXNAME], *ptr; - int err; - - KASSERT(v != NULL, ("gv_rename_vol: NULL v")); - pp = v->provider; - KASSERT(pp != NULL, ("gv_rename_vol: NULL pp")); - - if (gv_object_type(sc, newname) != GV_ERR_NOTFOUND) { - G_VINUM_DEBUG(1, "volume name %s already in use", newname); - return (GV_ERR_NAMETAKEN); - } - - /* Rename the volume. */ - strlcpy(v->name, newname, sizeof(v->name)); - - /* Fix up references and potentially rename plexes. */ - LIST_FOREACH(p, &v->plexes, in_volume) { - strlcpy(p->volume, v->name, sizeof(p->volume)); - if (flags & GV_FLAG_R) { - /* - * Look for the last dot in the string, and assume that - * the old value was ok. - */ - ptr = strrchr(p->name, '.'); - ptr++; - snprintf(newplex, sizeof(newplex), "%s.%s", v->name, ptr); - err = gv_rename_plex(sc, p, newplex, flags); - if (err) - return (err); - } - } - - return (0); -} diff --git a/sys/geom/vinum/geom_vinum_rm.c b/sys/geom/vinum/geom_vinum_rm.c deleted file mode 100644 --- a/sys/geom/vinum/geom_vinum_rm.c +++ /dev/null @@ -1,387 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause - * - * Copyright (c) 2004, 2007 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 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 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/param.h> -#include <sys/libkern.h> -#include <sys/malloc.h> - -#include <geom/geom.h> -#include <geom/geom_dbg.h> -#include <geom/vinum/geom_vinum_var.h> -#include <geom/vinum/geom_vinum.h> - -/* General 'remove' routine. */ -void -gv_remove(struct g_geom *gp, struct gctl_req *req) -{ - struct gv_softc *sc; - struct gv_volume *v; - struct gv_plex *p; - struct gv_sd *s; - struct gv_drive *d; - int *argc, *flags; - char *argv, buf[20]; - int i, type; - - argc = gctl_get_paraml(req, "argc", sizeof(*argc)); - - if (argc == NULL || *argc == 0) { - gctl_error(req, "no arguments given"); - return; - } - - flags = gctl_get_paraml(req, "flags", sizeof(*flags)); - if (flags == NULL) { - gctl_error(req, "no flags given"); - return; - } - - sc = gp->softc; - - /* XXX config locking */ - - for (i = 0; i < *argc; i++) { - snprintf(buf, sizeof(buf), "argv%d", i); - argv = gctl_get_param(req, buf, NULL); - if (argv == NULL) - continue; - type = gv_object_type(sc, argv); - switch (type) { - case GV_TYPE_VOL: - v = gv_find_vol(sc, argv); - - /* - * If this volume has plexes, we want a recursive - * removal. - */ - if (!LIST_EMPTY(&v->plexes) && !(*flags & GV_FLAG_R)) { - gctl_error(req, "volume '%s' has attached " - "plexes - need recursive removal", v->name); - return; - } - - gv_post_event(sc, GV_EVENT_RM_VOLUME, v, NULL, 0, 0); - break; - - case GV_TYPE_PLEX: - p = gv_find_plex(sc, argv); - - /* - * If this plex has subdisks, we want a recursive - * removal. - */ - if (!LIST_EMPTY(&p->subdisks) && - !(*flags & GV_FLAG_R)) { - gctl_error(req, "plex '%s' has attached " - "subdisks - need recursive removal", - p->name); - return; - } - - /* Don't allow removal of the only plex of a volume. */ - if (p->vol_sc != NULL && p->vol_sc->plexcount == 1) { - gctl_error(req, "plex '%s' is still attached " - "to volume '%s'", p->name, p->volume); - return; - } - - gv_post_event(sc, GV_EVENT_RM_PLEX, p, NULL, 0, 0); - break; - - case GV_TYPE_SD: - s = gv_find_sd(sc, argv); - - /* Don't allow removal if attached to a plex. */ - if (s->plex_sc != NULL) { - gctl_error(req, "subdisk '%s' is still attached" - " to plex '%s'", s->name, s->plex_sc->name); - return; - } - - gv_post_event(sc, GV_EVENT_RM_SD, s, NULL, 0, 0); - break; - - case GV_TYPE_DRIVE: - d = gv_find_drive(sc, argv); - /* We don't allow to remove open drives. */ - if (gv_consumer_is_open(d->consumer) && - !(*flags & GV_FLAG_F)) { - gctl_error(req, "drive '%s' is open", d->name); - return; - } - - /* A drive with subdisks needs a recursive removal. */ -/* if (!LIST_EMPTY(&d->subdisks) && - !(*flags & GV_FLAG_R)) { - gctl_error(req, "drive '%s' still has subdisks" - " - need recursive removal", d->name); - return; - }*/ - - gv_post_event(sc, GV_EVENT_RM_DRIVE, d, NULL, *flags, - 0); - break; - - default: - gctl_error(req, "unknown object '%s'", argv); - return; - } - } - - gv_post_event(sc, GV_EVENT_SAVE_CONFIG, sc, NULL, 0, 0); -} - -/* Resets configuration */ -int -gv_resetconfig(struct gv_softc *sc) -{ - struct gv_drive *d, *d2; - struct gv_volume *v, *v2; - struct gv_plex *p, *p2; - struct gv_sd *s, *s2; - - /* First make sure nothing is open. */ - LIST_FOREACH_SAFE(d, &sc->drives, drive, d2) { - if (gv_consumer_is_open(d->consumer)) { - return (GV_ERR_ISBUSY); - } - } - - /* Make sure nothing is going on internally. */ - LIST_FOREACH_SAFE(p, &sc->plexes, plex, p2) { - if (p->flags & (GV_PLEX_REBUILDING | GV_PLEX_GROWING)) - return (GV_ERR_ISBUSY); - } - - /* Then if not, we remove everything. */ - LIST_FOREACH_SAFE(s, &sc->subdisks, sd, s2) - gv_rm_sd(sc, s); - LIST_FOREACH_SAFE(d, &sc->drives, drive, d2) - gv_rm_drive(sc, d, 0); - LIST_FOREACH_SAFE(p, &sc->plexes, plex, p2) - gv_rm_plex(sc, p); - LIST_FOREACH_SAFE(v, &sc->volumes, volume, v2) - gv_rm_vol(sc, v); - - gv_post_event(sc, GV_EVENT_SAVE_CONFIG, sc, NULL, 0, 0); - - return (0); -} - -/* Remove a volume. */ -void -gv_rm_vol(struct gv_softc *sc, struct gv_volume *v) -{ - struct g_provider *pp; - struct gv_plex *p, *p2; - - KASSERT(v != NULL, ("gv_rm_vol: NULL v")); - pp = v->provider; - KASSERT(pp != NULL, ("gv_rm_vol: NULL pp")); - - /* Check if any of our consumers is open. */ - if (gv_provider_is_open(pp)) { - G_VINUM_DEBUG(0, "unable to remove %s: volume still in use", - v->name); - return; - } - - /* Remove the plexes our volume has. */ - LIST_FOREACH_SAFE(p, &v->plexes, in_volume, p2) - gv_rm_plex(sc, p); - - /* Clean up. */ - LIST_REMOVE(v, volume); - g_free(v); - - /* Get rid of the volume's provider. */ - if (pp != NULL) { - g_topology_lock(); - g_wither_provider(pp, ENXIO); - g_topology_unlock(); - } -} - -/* Remove a plex. */ -void -gv_rm_plex(struct gv_softc *sc, struct gv_plex *p) -{ - struct gv_volume *v; - struct gv_sd *s, *s2; - - KASSERT(p != NULL, ("gv_rm_plex: NULL p")); - v = p->vol_sc; - - /* Check if any of our consumers is open. */ - if (v != NULL && gv_provider_is_open(v->provider) && v->plexcount < 2) { - G_VINUM_DEBUG(0, "unable to remove %s: volume still in use", - p->name); - return; - } - - /* Remove the subdisks our plex has. */ - LIST_FOREACH_SAFE(s, &p->subdisks, in_plex, s2) - gv_rm_sd(sc, s); - - v = p->vol_sc; - /* Clean up and let our geom fade away. */ - LIST_REMOVE(p, plex); - if (p->vol_sc != NULL) { - p->vol_sc->plexcount--; - LIST_REMOVE(p, in_volume); - p->vol_sc = NULL; - /* Correctly update the volume size. */ - gv_update_vol_size(v, gv_vol_size(v)); - } - - g_free(p); -} - -/* Remove a subdisk. */ -void -gv_rm_sd(struct gv_softc *sc, struct gv_sd *s) -{ - struct gv_plex *p; - struct gv_volume *v; - - KASSERT(s != NULL, ("gv_rm_sd: NULL s")); - - p = s->plex_sc; - v = NULL; - - /* Clean up. */ - if (p != NULL) { - LIST_REMOVE(s, in_plex); - s->plex_sc = NULL; - p->sdcount--; - /* Update the plexsize. */ - p->size = gv_plex_size(p); - v = p->vol_sc; - if (v != NULL) { - /* Update the size of our plex' volume. */ - gv_update_vol_size(v, gv_vol_size(v)); - } - } - if (s->drive_sc && !(s->drive_sc->flags & GV_DRIVE_REFERENCED)) - LIST_REMOVE(s, from_drive); - LIST_REMOVE(s, sd); - gv_free_sd(s); - g_free(s); -} - -/* Remove a drive. */ -void -gv_rm_drive(struct gv_softc *sc, struct gv_drive *d, int flags) -{ - struct g_consumer *cp; - struct gv_freelist *fl, *fl2; - struct gv_plex *p; - struct gv_sd *s, *s2; - struct gv_volume *v; - struct gv_drive *d2; - int err; - - KASSERT(d != NULL, ("gv_rm_drive: NULL d")); - - cp = d->consumer; - - if (cp != NULL) { - g_topology_lock(); - err = g_access(cp, 0, 1, 0); - g_topology_unlock(); - - if (err) { - G_VINUM_DEBUG(0, "%s: unable to access '%s', " - "errno: %d", __func__, cp->provider->name, err); - return; - } - - /* Clear the Vinum Magic. */ - d->hdr->magic = GV_NOMAGIC; - err = gv_write_header(cp, d->hdr); - if (err) - G_VINUM_DEBUG(0, "gv_rm_drive: error writing header to" - " '%s', errno: %d", cp->provider->name, err); - - g_topology_lock(); - g_access(cp, -cp->acr, -cp->acw, -cp->ace); - g_detach(cp); - g_destroy_consumer(cp); - g_topology_unlock(); - } - - /* Remove all associated subdisks, plexes, volumes. */ - if (flags & GV_FLAG_R) { - if (!LIST_EMPTY(&d->subdisks)) { - LIST_FOREACH_SAFE(s, &d->subdisks, from_drive, s2) { - p = s->plex_sc; - if (p != NULL) { - v = p->vol_sc; - if (v != NULL) - gv_rm_vol(sc, v); - } - } - } - } - - /* Clean up. */ - LIST_FOREACH_SAFE(fl, &d->freelist, freelist, fl2) { - LIST_REMOVE(fl, freelist); - g_free(fl); - } - - LIST_REMOVE(d, drive); - g_free(d->hdr); - - /* Put ourself into referenced state if we have subdisks. */ - if (d->sdcount > 0) { - d->consumer = NULL; - d->hdr = NULL; - d->flags |= GV_DRIVE_REFERENCED; - snprintf(d->device, sizeof(d->device), "???"); - d->size = 0; - d->avail = 0; - d->freelist_entries = 0; - LIST_FOREACH(s, &d->subdisks, from_drive) { - s->flags |= GV_SD_TASTED; - gv_set_sd_state(s, GV_SD_DOWN, GV_SETSTATE_FORCE); - } - /* Shuffle around so we keep gv_is_newer happy. */ - LIST_REMOVE(d, drive); - d2 = LIST_FIRST(&sc->drives); - if (d2 == NULL) - LIST_INSERT_HEAD(&sc->drives, d, drive); - else - LIST_INSERT_AFTER(d2, d, drive); - return; - } - g_free(d); - - gv_save_config(sc); -} diff --git a/sys/geom/vinum/geom_vinum_share.h b/sys/geom/vinum/geom_vinum_share.h deleted file mode 100644 --- a/sys/geom/vinum/geom_vinum_share.h +++ /dev/null @@ -1,67 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause - * - * Copyright (c) 2004, 2007 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. - */ - -#ifndef _GEOM_VINUM_SHARE_H_ -#define _GEOM_VINUM_SHARE_H_ - -/* Maximum number of arguments for a single command. */ -#define GV_MAXARGS 64 - -enum { - KILOBYTE = 1024, - MEGABYTE = 1048576, - GIGABYTE = 1073741824 -}; - -off_t gv_sizespec(char *); -int gv_tokenize(char *, char **, int); - -struct gv_sd *gv_alloc_sd(void); -struct gv_volume *gv_alloc_volume(void); -struct gv_plex *gv_alloc_plex(void); -struct gv_drive *gv_alloc_drive(void); -struct gv_drive *gv_new_drive(int, char **); -struct gv_plex *gv_new_plex(int, char **); -struct gv_sd *gv_new_sd(int, char **); -struct gv_volume *gv_new_volume(int, char **); - -int gv_drivestatei(char *); -int gv_plexorgi(char *); -int gv_plexstatei(char *); -int gv_sdstatei(char *); -int gv_volstatei(char *); - -const char *gv_drivestate(int); -const char *gv_plexorg(int); -const char *gv_plexorg_short(int); -const char *gv_plexstate(int); -const char *gv_sdstate(int); -const char *gv_volstate(int); -const char *gv_roughlength(off_t, int); - -#endif /* _GEOM_VINUM_SHARE_H_ */ diff --git a/sys/geom/vinum/geom_vinum_share.c b/sys/geom/vinum/geom_vinum_share.c deleted file mode 100644 --- a/sys/geom/vinum/geom_vinum_share.c +++ /dev/null @@ -1,723 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-4-Clause - * - * Copyright (c) 2004, 2007 Lukas Ertl - * Copyright (c) 1997, 1998, 1999 - * Nan Yang Computer Services Limited. All rights reserved. - * - * Parts written by Greg Lehey - * - * This software is distributed under the so-called ``Berkeley - * License'': - * - * 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. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Nan Yang Computer - * Services Limited. - * 4. Neither the name of the Company nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * This software is provided ``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 company 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. - * - */ - -/* This file is shared between kernel and userland. */ - -#include <sys/param.h> -#ifdef _KERNEL -#include <sys/malloc.h> -#include <sys/systm.h> - -#include <geom/geom.h> -#define iswhite(c) (((c) == ' ') || ((c) == '\t')) -#else -#include <ctype.h> -#include <paths.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#define iswhite isspace -#define g_free free -#endif /* _KERNEL */ - -#include <sys/mutex.h> -#include <sys/queue.h> - -#include <geom/vinum/geom_vinum_var.h> -#include <geom/vinum/geom_vinum_share.h> - -/* - * Take a blank separated list of tokens and turn it into a list of - * individual nul-delimited strings. Build a list of pointers at - * token, which must have enough space for the tokens. Return the - * number of tokens, or -1 on error (typically a missing string - * delimiter). - */ -int -gv_tokenize(char *cptr, char *token[], int maxtoken) -{ - int tokennr; /* Index of this token. */ - char delim; /* Delimiter for searching for the partner. */ - - for (tokennr = 0; tokennr < maxtoken;) { - /* Skip leading white space. */ - while (iswhite(*cptr)) - cptr++; - - /* End of line. */ - if ((*cptr == '\0') || (*cptr == '\n') || (*cptr == '#')) - return tokennr; - - delim = *cptr; - token[tokennr] = cptr; /* Point to it. */ - tokennr++; /* One more. */ - - /* Run off the end? */ - if (tokennr == maxtoken) - return tokennr; - - /* Quoted? */ - if ((delim == '\'') || (delim == '"')) { - for (;;) { - cptr++; - - /* Found the partner. */ - if ((*cptr == delim) && (cptr[-1] != '\\')) { - cptr++; - - /* Space after closing quote needed. */ - if (!iswhite(*cptr)) - return -1; - - /* Delimit. */ - *cptr++ = '\0'; - - /* End-of-line? */ - } else if ((*cptr == '\0') || (*cptr == '\n')) - return -1; - } - - /* Not quoted. */ - } else { - while ((*cptr != '\0') && - (!iswhite(*cptr)) && - (*cptr != '\n')) - cptr++; - - /* Not end-of-line; delimit and move to the next. */ - if (*cptr != '\0') - *cptr++ = '\0'; - } - } - - /* Can't get here. */ - return maxtoken; -} - -/* - * Take a number with an optional scale factor and convert it to a number of - * bytes. - * - * The scale factors are: - * - * s sectors (of 512 bytes) - * b blocks (of 512 bytes). This unit is deprecated, because it's - * confusing, but maintained to avoid confusing Veritas users. - * k kilobytes (1024 bytes) - * m megabytes (of 1024 * 1024 bytes) - * g gigabytes (of 1024 * 1024 * 1024 bytes) - * - * XXX: need a way to signal error - */ -off_t -gv_sizespec(char *spec) -{ - uint64_t size; - char *s; - int sign; - - size = 0; - sign = 1; - if (spec != NULL) { /* we have a parameter */ - s = spec; - if (*s == '-') { /* negative, */ - sign = -1; - s++; /* skip */ - } - - /* It's numeric. */ - if ((*s >= '0') && (*s <= '9')) { - /* It's numeric. */ - while ((*s >= '0') && (*s <= '9')) - /* Convert it. */ - size = size * 10 + *s++ - '0'; - - switch (*s) { - case '\0': - return size * sign; - - case 'B': - case 'b': - case 'S': - case 's': - return size * sign * 512; - - case 'K': - case 'k': - return size * sign * 1024; - - case 'M': - case 'm': - return size * sign * 1024 * 1024; - - case 'G': - case 'g': - return size * sign * 1024 * 1024 * 1024; - } - } - } - - return (0); -} - -const char * -gv_drivestate(int state) -{ - switch (state) { - case GV_DRIVE_DOWN: - return "down"; - case GV_DRIVE_UP: - return "up"; - default: - return "??"; - } -} - -int -gv_drivestatei(char *buf) -{ - if (!strcmp(buf, "up")) - return (GV_DRIVE_UP); - else - return (GV_DRIVE_DOWN); -} - -/* Translate from a string to a subdisk state. */ -int -gv_sdstatei(char *buf) -{ - if (!strcmp(buf, "up")) - return (GV_SD_UP); - else if (!strcmp(buf, "reviving")) - return (GV_SD_REVIVING); - else if (!strcmp(buf, "initializing")) - return (GV_SD_INITIALIZING); - else if (!strcmp(buf, "stale")) - return (GV_SD_STALE); - else - return (GV_SD_DOWN); -} - -/* Translate from a subdisk state to a string. */ -const char * -gv_sdstate(int state) -{ - switch (state) { - case GV_SD_INITIALIZING: - return "initializing"; - case GV_SD_STALE: - return "stale"; - case GV_SD_DOWN: - return "down"; - case GV_SD_REVIVING: - return "reviving"; - case GV_SD_UP: - return "up"; - default: - return "??"; - } -} - -/* Translate from a string to a plex state. */ -int -gv_plexstatei(char *buf) -{ - if (!strcmp(buf, "up")) - return (GV_PLEX_UP); - else if (!strcmp(buf, "initializing")) - return (GV_PLEX_INITIALIZING); - else if (!strcmp(buf, "degraded")) - return (GV_PLEX_DEGRADED); - else if (!strcmp(buf, "growable")) - return (GV_PLEX_GROWABLE); - else - return (GV_PLEX_DOWN); -} - -/* Translate from a plex state to a string. */ -const char * -gv_plexstate(int state) -{ - switch (state) { - case GV_PLEX_DOWN: - return "down"; - case GV_PLEX_INITIALIZING: - return "initializing"; - case GV_PLEX_DEGRADED: - return "degraded"; - case GV_PLEX_GROWABLE: - return "growable"; - case GV_PLEX_UP: - return "up"; - default: - return "??"; - } -} - -/* Translate from a string to a plex organization. */ -int -gv_plexorgi(char *buf) -{ - if (!strcmp(buf, "concat")) - return (GV_PLEX_CONCAT); - else if (!strcmp(buf, "striped")) - return (GV_PLEX_STRIPED); - else if (!strcmp(buf, "raid5")) - return (GV_PLEX_RAID5); - else - return (GV_PLEX_DISORG); -} - -int -gv_volstatei(char *buf) -{ - if (!strcmp(buf, "up")) - return (GV_VOL_UP); - else - return (GV_VOL_DOWN); -} - -const char * -gv_volstate(int state) -{ - switch (state) { - case GV_VOL_UP: - return "up"; - case GV_VOL_DOWN: - return "down"; - default: - return "??"; - } -} - -/* Translate from a plex organization to a string. */ -const char * -gv_plexorg(int org) -{ - switch (org) { - case GV_PLEX_DISORG: - return "??"; - case GV_PLEX_CONCAT: - return "concat"; - case GV_PLEX_STRIPED: - return "striped"; - case GV_PLEX_RAID5: - return "raid5"; - default: - return "??"; - } -} - -const char * -gv_plexorg_short(int org) -{ - switch (org) { - case GV_PLEX_DISORG: - return "??"; - case GV_PLEX_CONCAT: - return "C"; - case GV_PLEX_STRIPED: - return "S"; - case GV_PLEX_RAID5: - return "R5"; - default: - return "??"; - } -} - -struct gv_sd * -gv_alloc_sd(void) -{ - struct gv_sd *s; - -#ifdef _KERNEL - s = g_malloc(sizeof(struct gv_sd), M_NOWAIT); -#else - s = malloc(sizeof(struct gv_sd)); -#endif - if (s == NULL) - return (NULL); - bzero(s, sizeof(struct gv_sd)); - s->plex_offset = -1; - s->size = -1; - s->drive_offset = -1; - return (s); -} - -struct gv_drive * -gv_alloc_drive(void) -{ - struct gv_drive *d; - -#ifdef _KERNEL - d = g_malloc(sizeof(struct gv_drive), M_NOWAIT); -#else - d = malloc(sizeof(struct gv_drive)); -#endif - if (d == NULL) - return (NULL); - bzero(d, sizeof(struct gv_drive)); - return (d); -} - -struct gv_volume * -gv_alloc_volume(void) -{ - struct gv_volume *v; - -#ifdef _KERNEL - v = g_malloc(sizeof(struct gv_volume), M_NOWAIT); -#else - v = malloc(sizeof(struct gv_volume)); -#endif - if (v == NULL) - return (NULL); - bzero(v, sizeof(struct gv_volume)); - return (v); -} - -struct gv_plex * -gv_alloc_plex(void) -{ - struct gv_plex *p; - -#ifdef _KERNEL - p = g_malloc(sizeof(struct gv_plex), M_NOWAIT); -#else - p = malloc(sizeof(struct gv_plex)); -#endif - if (p == NULL) - return (NULL); - bzero(p, sizeof(struct gv_plex)); - return (p); -} - -/* Get a new drive object. */ -struct gv_drive * -gv_new_drive(int max, char *token[]) -{ - struct gv_drive *d; - int j, errors; - char *ptr; - - if (token[1] == NULL || *token[1] == '\0') - return (NULL); - d = gv_alloc_drive(); - if (d == NULL) - return (NULL); - errors = 0; - for (j = 1; j < max; j++) { - if (!strcmp(token[j], "state")) { - j++; - if (j >= max) { - errors++; - break; - } - d->state = gv_drivestatei(token[j]); - } else if (!strcmp(token[j], "device")) { - j++; - if (j >= max) { - errors++; - break; - } - ptr = token[j]; - - if (strncmp(ptr, _PATH_DEV, 5) == 0) - ptr += 5; - strlcpy(d->device, ptr, sizeof(d->device)); - } else { - /* We assume this is the drive name. */ - strlcpy(d->name, token[j], sizeof(d->name)); - } - } - - if (strlen(d->name) == 0 || strlen(d->device) == 0) - errors++; - - if (errors) { - g_free(d); - return (NULL); - } - - return (d); -} - -/* Get a new volume object. */ -struct gv_volume * -gv_new_volume(int max, char *token[]) -{ - struct gv_volume *v; - int j, errors; - - if (token[1] == NULL || *token[1] == '\0') - return (NULL); - - v = gv_alloc_volume(); - if (v == NULL) - return (NULL); - - errors = 0; - for (j = 1; j < max; j++) { - if (!strcmp(token[j], "state")) { - j++; - if (j >= max) { - errors++; - break; - } - v->state = gv_volstatei(token[j]); - } else { - /* We assume this is the volume name. */ - strlcpy(v->name, token[j], sizeof(v->name)); - } - } - - if (strlen(v->name) == 0) - errors++; - - if (errors) { - g_free(v); - return (NULL); - } - - return (v); -} - -/* Get a new plex object. */ -struct gv_plex * -gv_new_plex(int max, char *token[]) -{ - struct gv_plex *p; - int j, errors; - - if (token[1] == NULL || *token[1] == '\0') - return (NULL); - - p = gv_alloc_plex(); - if (p == NULL) - return (NULL); - - errors = 0; - for (j = 1; j < max; j++) { - if (!strcmp(token[j], "name")) { - j++; - if (j >= max) { - errors++; - break; - } - strlcpy(p->name, token[j], sizeof(p->name)); - } else if (!strcmp(token[j], "org")) { - j++; - if (j >= max) { - errors++; - break; - } - p->org = gv_plexorgi(token[j]); - if ((p->org == GV_PLEX_RAID5) || - (p->org == GV_PLEX_STRIPED)) { - j++; - if (j >= max) { - errors++; - break; - } - p->stripesize = gv_sizespec(token[j]); - if (p->stripesize == 0) { - errors++; - break; - } - } - } else if (!strcmp(token[j], "state")) { - j++; - if (j >= max) { - errors++; - break; - } - p->state = gv_plexstatei(token[j]); - } else if (!strcmp(token[j], "vol") || - !strcmp(token[j], "volume")) { - j++; - if (j >= max) { - errors++; - break; - } - strlcpy(p->volume, token[j], sizeof(p->volume)); - } else { - errors++; - break; - } - } - - if (errors) { - g_free(p); - return (NULL); - } - - return (p); -} - -/* Get a new subdisk object. */ -struct gv_sd * -gv_new_sd(int max, char *token[]) -{ - struct gv_sd *s; - int j, errors; - - if (token[1] == NULL || *token[1] == '\0') - return (NULL); - - s = gv_alloc_sd(); - if (s == NULL) - return (NULL); - - errors = 0; - for (j = 1; j < max; j++) { - if (!strcmp(token[j], "name")) { - j++; - if (j >= max) { - errors++; - break; - } - strlcpy(s->name, token[j], sizeof(s->name)); - } else if (!strcmp(token[j], "drive")) { - j++; - if (j >= max) { - errors++; - break; - } - strlcpy(s->drive, token[j], sizeof(s->drive)); - } else if (!strcmp(token[j], "plex")) { - j++; - if (j >= max) { - errors++; - break; - } - strlcpy(s->plex, token[j], sizeof(s->plex)); - } else if (!strcmp(token[j], "state")) { - j++; - if (j >= max) { - errors++; - break; - } - s->state = gv_sdstatei(token[j]); - } else if (!strcmp(token[j], "len") || - !strcmp(token[j], "length")) { - j++; - if (j >= max) { - errors++; - break; - } - s->size = gv_sizespec(token[j]); - if (s->size <= 0) - s->size = -1; - } else if (!strcmp(token[j], "driveoffset")) { - j++; - if (j >= max) { - errors++; - break; - } - s->drive_offset = gv_sizespec(token[j]); - if (s->drive_offset != 0 && - s->drive_offset < GV_DATA_START) { - errors++; - break; - } - } else if (!strcmp(token[j], "plexoffset")) { - j++; - if (j >= max) { - errors++; - break; - } - s->plex_offset = gv_sizespec(token[j]); - if (s->plex_offset < 0) { - errors++; - break; - } - } else { - errors++; - break; - } - } - - if (strlen(s->drive) == 0) - errors++; - - if (errors) { - g_free(s); - return (NULL); - } - - return (s); -} - -/* - * Take a size in bytes and return a pointer to a string which represents the - * size best. If lj is != 0, return left justified, otherwise in a fixed 10 - * character field suitable for columnar printing. - * - * Note this uses a static string: it's only intended to be used immediately - * for printing. - */ -const char * -gv_roughlength(off_t bytes, int lj) -{ - static char desc[16]; - - /* Gigabytes. */ - if (bytes > (off_t)MEGABYTE * 10000) - snprintf(desc, sizeof(desc), lj ? "%jd GB" : "%10jd GB", - bytes / GIGABYTE); - - /* Megabytes. */ - else if (bytes > KILOBYTE * 10000) - snprintf(desc, sizeof(desc), lj ? "%jd MB" : "%10jd MB", - bytes / MEGABYTE); - - /* Kilobytes. */ - else if (bytes > 10000) - snprintf(desc, sizeof(desc), lj ? "%jd kB" : "%10jd kB", - bytes / KILOBYTE); - - /* Bytes. */ - else - snprintf(desc, sizeof(desc), lj ? "%jd B" : "%10jd B", bytes); - - return (desc); -} diff --git a/sys/geom/vinum/geom_vinum_state.c b/sys/geom/vinum/geom_vinum_state.c deleted file mode 100644 --- a/sys/geom/vinum/geom_vinum_state.c +++ /dev/null @@ -1,534 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause - * - * Copyright (c) 2004, 2007 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> -#include <sys/libkern.h> -#include <sys/malloc.h> - -#include <geom/geom.h> -#include <geom/geom_dbg.h> -#include <geom/vinum/geom_vinum_var.h> -#include <geom/vinum/geom_vinum.h> -#include <geom/vinum/geom_vinum_share.h> - -void -gv_setstate(struct g_geom *gp, struct gctl_req *req) -{ - struct gv_softc *sc; - struct gv_sd *s; - struct gv_drive *d; - struct gv_volume *v; - struct gv_plex *p; - char *obj, *state; - int f, *flags, type; - - f = 0; - obj = gctl_get_param(req, "object", NULL); - if (obj == NULL) { - gctl_error(req, "no object given"); - return; - } - - state = gctl_get_param(req, "state", NULL); - if (state == NULL) { - gctl_error(req, "no state given"); - return; - } - - flags = gctl_get_paraml(req, "flags", sizeof(*flags)); - if (flags == NULL) { - gctl_error(req, "no flags given"); - return; - } - - if (*flags & GV_FLAG_F) - f = GV_SETSTATE_FORCE; - - sc = gp->softc; - type = gv_object_type(sc, obj); - switch (type) { - case GV_TYPE_VOL: - if (gv_volstatei(state) < 0) { - gctl_error(req, "invalid volume state '%s'", state); - break; - } - v = gv_find_vol(sc, obj); - gv_post_event(sc, GV_EVENT_SET_VOL_STATE, v, NULL, - gv_volstatei(state), f); - break; - - case GV_TYPE_PLEX: - if (gv_plexstatei(state) < 0) { - gctl_error(req, "invalid plex state '%s'", state); - break; - } - p = gv_find_plex(sc, obj); - gv_post_event(sc, GV_EVENT_SET_PLEX_STATE, p, NULL, - gv_plexstatei(state), f); - break; - - case GV_TYPE_SD: - if (gv_sdstatei(state) < 0) { - gctl_error(req, "invalid subdisk state '%s'", state); - break; - } - s = gv_find_sd(sc, obj); - gv_post_event(sc, GV_EVENT_SET_SD_STATE, s, NULL, - gv_sdstatei(state), f); - break; - - case GV_TYPE_DRIVE: - if (gv_drivestatei(state) < 0) { - gctl_error(req, "invalid drive state '%s'", state); - break; - } - d = gv_find_drive(sc, obj); - gv_post_event(sc, GV_EVENT_SET_DRIVE_STATE, d, NULL, - gv_drivestatei(state), f); - break; - - default: - gctl_error(req, "unknown object '%s'", obj); - break; - } -} - -/* Update drive state; return 0 if the state changes, otherwise error. */ -int -gv_set_drive_state(struct gv_drive *d, int newstate, int flags) -{ - struct gv_sd *s; - int oldstate; - - KASSERT(d != NULL, ("gv_set_drive_state: NULL d")); - - oldstate = d->state; - - if (newstate == oldstate) - return (0); - - /* We allow to take down an open drive only with force. */ - if ((newstate == GV_DRIVE_DOWN) && gv_consumer_is_open(d->consumer) && - (!(flags & GV_SETSTATE_FORCE))) - return (GV_ERR_ISBUSY); - - d->state = newstate; - - if (d->state != oldstate) { - LIST_FOREACH(s, &d->subdisks, from_drive) - gv_update_sd_state(s); - } - - /* Save the config back to disk. */ - if (flags & GV_SETSTATE_CONFIG) - gv_save_config(d->vinumconf); - - return (0); -} - -int -gv_set_sd_state(struct gv_sd *s, int newstate, int flags) -{ - struct gv_drive *d; - struct gv_plex *p; - int oldstate, status; - - KASSERT(s != NULL, ("gv_set_sd_state: NULL s")); - - oldstate = s->state; - - /* We are optimistic and assume it will work. */ - status = 0; - - if (newstate == oldstate) - return (0); - - switch (newstate) { - case GV_SD_DOWN: - /* - * If we're attached to a plex, we won't go down without use of - * force. - */ - if ((s->plex_sc != NULL) && !(flags & GV_SETSTATE_FORCE)) - return (GV_ERR_ISATTACHED); - break; - - case GV_SD_REVIVING: - case GV_SD_INITIALIZING: - /* - * Only do this if we're forced, since it usually is done - * internally, and then we do use the force flag. - */ - if (!(flags & GV_SETSTATE_FORCE)) - return (GV_ERR_SETSTATE); - break; - - case GV_SD_UP: - /* We can't bring the subdisk up if our drive is dead. */ - d = s->drive_sc; - if ((d == NULL) || (d->state != GV_DRIVE_UP)) - return (GV_ERR_SETSTATE); - - /* Check from where we want to be brought up. */ - switch (s->state) { - case GV_SD_REVIVING: - case GV_SD_INITIALIZING: - /* - * The subdisk was initializing. We allow it to be - * brought up. - */ - break; - - case GV_SD_DOWN: - /* - * The subdisk is currently down. We allow it to be - * brought up if it is not attached to a plex. - */ - p = s->plex_sc; - if (p == NULL) - break; - - /* - * If this subdisk is attached to a plex, we allow it - * to be brought up if the plex if it's not a RAID5 - * plex, otherwise it's made 'stale'. - */ - - if (p->org != GV_PLEX_RAID5) - break; - else if (s->flags & GV_SD_CANGOUP) { - s->flags &= ~GV_SD_CANGOUP; - break; - } else if (flags & GV_SETSTATE_FORCE) - break; - else - s->state = GV_SD_STALE; - - status = GV_ERR_SETSTATE; - break; - - case GV_SD_STALE: - /* - * A stale subdisk can be brought up only if it's part - * of a concat or striped plex that's the only one in a - * volume, or if the subdisk isn't attached to a plex. - * Otherwise it needs to be revived or initialized - * first. - */ - p = s->plex_sc; - if (p == NULL || flags & GV_SETSTATE_FORCE) - break; - - if ((p->org != GV_PLEX_RAID5 && - p->vol_sc->plexcount == 1) || - (p->flags & GV_PLEX_SYNCING && - p->synced > 0 && - p->org == GV_PLEX_RAID5)) - break; - else - return (GV_ERR_SETSTATE); - - default: - return (GV_ERR_INVSTATE); - } - break; - - /* Other state transitions are only possible with force. */ - default: - if (!(flags & GV_SETSTATE_FORCE)) - return (GV_ERR_SETSTATE); - } - - /* We can change the state and do it. */ - if (status == 0) - s->state = newstate; - - /* Update our plex, if we're attached to one. */ - if (s->plex_sc != NULL) - gv_update_plex_state(s->plex_sc); - - /* Save the config back to disk. */ - if (flags & GV_SETSTATE_CONFIG) - gv_save_config(s->vinumconf); - - return (status); -} - -int -gv_set_plex_state(struct gv_plex *p, int newstate, int flags) -{ - struct gv_volume *v; - int oldstate, plexdown; - - KASSERT(p != NULL, ("gv_set_plex_state: NULL p")); - - oldstate = p->state; - v = p->vol_sc; - plexdown = 0; - - if (newstate == oldstate) - return (0); - - switch (newstate) { - case GV_PLEX_UP: - /* Let update_plex handle if the plex can come up */ - gv_update_plex_state(p); - if (p->state != GV_PLEX_UP && !(flags & GV_SETSTATE_FORCE)) - return (GV_ERR_SETSTATE); - p->state = newstate; - break; - case GV_PLEX_DOWN: - /* - * Set state to GV_PLEX_DOWN only if no-one is using the plex, - * or if the state is forced. - */ - if (v != NULL) { - /* If the only one up, force is needed. */ - plexdown = gv_plexdown(v); - if ((v->plexcount == 1 || - (v->plexcount - plexdown == 1)) && - ((flags & GV_SETSTATE_FORCE) == 0)) - return (GV_ERR_SETSTATE); - } - p->state = newstate; - break; - case GV_PLEX_DEGRADED: - /* Only used internally, so we have to be forced. */ - if (flags & GV_SETSTATE_FORCE) - p->state = newstate; - break; - } - - /* Update our volume if we have one. */ - if (v != NULL) - gv_update_vol_state(v); - - /* Save config. */ - if (flags & GV_SETSTATE_CONFIG) - gv_save_config(p->vinumconf); - return (0); -} - -int -gv_set_vol_state(struct gv_volume *v, int newstate, int flags) -{ - int oldstate; - - KASSERT(v != NULL, ("gv_set_vol_state: NULL v")); - - oldstate = v->state; - - if (newstate == oldstate) - return (0); - - switch (newstate) { - case GV_VOL_UP: - /* Let update handle if the volume can come up. */ - gv_update_vol_state(v); - if (v->state != GV_VOL_UP && !(flags & GV_SETSTATE_FORCE)) - return (GV_ERR_SETSTATE); - v->state = newstate; - break; - case GV_VOL_DOWN: - /* - * Set state to GV_VOL_DOWN only if no-one is using the volume, - * or if the state should be forced. - */ - if (!gv_provider_is_open(v->provider) && - !(flags & GV_SETSTATE_FORCE)) - return (GV_ERR_ISBUSY); - v->state = newstate; - break; - } - /* Save config */ - if (flags & GV_SETSTATE_CONFIG) - gv_save_config(v->vinumconf); - return (0); -} - -/* Update the state of a subdisk based on its environment. */ -void -gv_update_sd_state(struct gv_sd *s) -{ - struct gv_drive *d; - int oldstate; - - KASSERT(s != NULL, ("gv_update_sd_state: NULL s")); - d = s->drive_sc; - KASSERT(d != NULL, ("gv_update_sd_state: NULL d")); - - oldstate = s->state; - - /* If our drive isn't up we cannot be up either. */ - if (d->state != GV_DRIVE_UP) { - s->state = GV_SD_DOWN; - /* If this subdisk was just created, we assume it is good.*/ - } else if (s->flags & GV_SD_NEWBORN) { - s->state = GV_SD_UP; - s->flags &= ~GV_SD_NEWBORN; - } else if (s->state != GV_SD_UP) { - if (s->flags & GV_SD_CANGOUP) { - s->state = GV_SD_UP; - s->flags &= ~GV_SD_CANGOUP; - } else - s->state = GV_SD_STALE; - } else - s->state = GV_SD_UP; - - if (s->state != oldstate) - G_VINUM_DEBUG(1, "subdisk %s state change: %s -> %s", s->name, - gv_sdstate(oldstate), gv_sdstate(s->state)); - - /* Update the plex, if we have one. */ - if (s->plex_sc != NULL) - gv_update_plex_state(s->plex_sc); -} - -/* Update the state of a plex based on its environment. */ -void -gv_update_plex_state(struct gv_plex *p) -{ - struct gv_sd *s; - int sdstates; - int oldstate; - - KASSERT(p != NULL, ("gv_update_plex_state: NULL p")); - - oldstate = p->state; - - /* First, check the state of our subdisks. */ - sdstates = gv_sdstatemap(p); - - /* If all subdisks are up, our plex can be up, too. */ - if (sdstates == GV_SD_UPSTATE) - p->state = GV_PLEX_UP; - - /* One or more of our subdisks are down. */ - else if (sdstates & GV_SD_DOWNSTATE) { - /* A RAID5 plex can handle one dead subdisk. */ - if ((p->org == GV_PLEX_RAID5) && (p->sddown == 1)) - p->state = GV_PLEX_DEGRADED; - else - p->state = GV_PLEX_DOWN; - - /* Some of our subdisks are initializing. */ - } else if (sdstates & GV_SD_INITSTATE) { - if (p->flags & GV_PLEX_SYNCING || - p->flags & GV_PLEX_REBUILDING) - p->state = GV_PLEX_DEGRADED; - else - p->state = GV_PLEX_DOWN; - } else - p->state = GV_PLEX_DOWN; - - if (p->state == GV_PLEX_UP) { - LIST_FOREACH(s, &p->subdisks, in_plex) { - if (s->flags & GV_SD_GROW) { - p->state = GV_PLEX_GROWABLE; - break; - } - } - } - - if (p->state != oldstate) - G_VINUM_DEBUG(1, "plex %s state change: %s -> %s", p->name, - gv_plexstate(oldstate), gv_plexstate(p->state)); - - /* Update our volume, if we have one. */ - if (p->vol_sc != NULL) - gv_update_vol_state(p->vol_sc); -} - -/* Update the volume state based on its plexes. */ -void -gv_update_vol_state(struct gv_volume *v) -{ - struct gv_plex *p; - - KASSERT(v != NULL, ("gv_update_vol_state: NULL v")); - - /* The volume can't be up without plexes. */ - if (v->plexcount == 0) { - v->state = GV_VOL_DOWN; - return; - } - - LIST_FOREACH(p, &v->plexes, in_volume) { - /* One of our plexes is accessible, and so are we. */ - if (p->state > GV_PLEX_DEGRADED) { - v->state = GV_VOL_UP; - return; - - /* We can handle a RAID5 plex with one dead subdisk as well. */ - } else if ((p->org == GV_PLEX_RAID5) && - (p->state == GV_PLEX_DEGRADED)) { - v->state = GV_VOL_UP; - return; - } - } - - /* Not one of our plexes is up, so we can't be either. */ - v->state = GV_VOL_DOWN; -} - -/* Return a state map for the subdisks of a plex. */ -int -gv_sdstatemap(struct gv_plex *p) -{ - struct gv_sd *s; - int statemap; - - KASSERT(p != NULL, ("gv_sdstatemap: NULL p")); - - statemap = 0; - p->sddown = 0; /* No subdisks down yet. */ - - LIST_FOREACH(s, &p->subdisks, in_plex) { - switch (s->state) { - case GV_SD_DOWN: - case GV_SD_STALE: - statemap |= GV_SD_DOWNSTATE; - p->sddown++; /* Another unusable subdisk. */ - break; - - case GV_SD_UP: - statemap |= GV_SD_UPSTATE; - break; - - case GV_SD_INITIALIZING: - statemap |= GV_SD_INITSTATE; - break; - - case GV_SD_REVIVING: - statemap |= GV_SD_INITSTATE; - p->sddown++; /* XXX: Another unusable subdisk? */ - break; - } - } - return (statemap); -} diff --git a/sys/geom/vinum/geom_vinum_subr.c b/sys/geom/vinum/geom_vinum_subr.c deleted file mode 100644 --- a/sys/geom/vinum/geom_vinum_subr.c +++ /dev/null @@ -1,1277 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-4-Clause - * - * Copyright (c) 2004, 2007 Lukas Ertl - * Copyright (c) 2007, 2009 Ulf Lilleengen - * Copyright (c) 1997, 1998, 1999 - * Nan Yang Computer Services Limited. All rights reserved. - * - * Parts written by Greg Lehey - * - * This software is distributed under the so-called ``Berkeley - * License'': - * - * 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. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Nan Yang Computer - * Services Limited. - * 4. Neither the name of the Company nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * This software is provided ``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 company 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/param.h> -#include <sys/malloc.h> -#include <sys/sbuf.h> -#include <sys/systm.h> - -#include <geom/geom.h> -#include <geom/geom_dbg.h> -#include <geom/vinum/geom_vinum_var.h> -#include <geom/vinum/geom_vinum.h> -#include <geom/vinum/geom_vinum_share.h> - -int gv_drive_is_newer(struct gv_softc *, struct gv_drive *); -static off_t gv_plex_smallest_sd(struct gv_plex *); - -void -gv_parse_config(struct gv_softc *sc, char *buf, struct gv_drive *d) -{ - char *aptr, *bptr, *cptr; - struct gv_volume *v, *v2; - struct gv_plex *p, *p2; - struct gv_sd *s, *s2; - int error, is_newer, tokens; - char *token[GV_MAXARGS]; - - is_newer = gv_drive_is_newer(sc, d); - - /* Until the end of the string *buf. */ - for (aptr = buf; *aptr != '\0'; aptr = bptr) { - bptr = aptr; - cptr = aptr; - - /* Separate input lines. */ - while (*bptr != '\n') - bptr++; - *bptr = '\0'; - bptr++; - - tokens = gv_tokenize(cptr, token, GV_MAXARGS); - - if (tokens <= 0) - continue; - - if (!strcmp(token[0], "volume")) { - v = gv_new_volume(tokens, token); - if (v == NULL) { - G_VINUM_DEBUG(0, "config parse failed volume"); - break; - } - - v2 = gv_find_vol(sc, v->name); - if (v2 != NULL) { - if (is_newer) { - v2->state = v->state; - G_VINUM_DEBUG(2, "newer volume found!"); - } - g_free(v); - continue; - } - - gv_create_volume(sc, v); - - } else if (!strcmp(token[0], "plex")) { - p = gv_new_plex(tokens, token); - if (p == NULL) { - G_VINUM_DEBUG(0, "config parse failed plex"); - break; - } - - p2 = gv_find_plex(sc, p->name); - if (p2 != NULL) { - /* XXX */ - if (is_newer) { - p2->state = p->state; - G_VINUM_DEBUG(2, "newer plex found!"); - } - g_free(p); - continue; - } - - error = gv_create_plex(sc, p); - if (error) - continue; - /* - * These flags were set in gv_create_plex() and are not - * needed here (on-disk config parsing). - */ - p->flags &= ~GV_PLEX_ADDED; - - } else if (!strcmp(token[0], "sd")) { - s = gv_new_sd(tokens, token); - - if (s == NULL) { - G_VINUM_DEBUG(0, "config parse failed subdisk"); - break; - } - - s2 = gv_find_sd(sc, s->name); - if (s2 != NULL) { - /* XXX */ - if (is_newer) { - s2->state = s->state; - G_VINUM_DEBUG(2, "newer subdisk found!"); - } - g_free(s); - continue; - } - - /* - * Signal that this subdisk was tasted, and could - * possibly reference a drive that isn't in our config - * yet. - */ - s->flags |= GV_SD_TASTED; - - if (s->state == GV_SD_UP) - s->flags |= GV_SD_CANGOUP; - - error = gv_create_sd(sc, s); - if (error) - continue; - - /* - * This flag was set in gv_create_sd() and is not - * needed here (on-disk config parsing). - */ - s->flags &= ~GV_SD_NEWBORN; - s->flags &= ~GV_SD_GROW; - } - } -} - -/* - * Format the vinum configuration properly. If ondisk is non-zero then the - * configuration is intended to be written to disk later. - */ -void -gv_format_config(struct gv_softc *sc, struct sbuf *sb, int ondisk, char *prefix) -{ - struct gv_drive *d; - struct gv_sd *s; - struct gv_plex *p; - struct gv_volume *v; - - /* - * We don't need the drive configuration if we're not writing the - * config to disk. - */ - if (!ondisk) { - LIST_FOREACH(d, &sc->drives, drive) { - sbuf_printf(sb, "%sdrive %s device /dev/%s\n", prefix, - d->name, d->device); - } - } - - LIST_FOREACH(v, &sc->volumes, volume) { - if (!ondisk) - sbuf_printf(sb, "%s", prefix); - sbuf_printf(sb, "volume %s", v->name); - if (ondisk) - sbuf_printf(sb, " state %s", gv_volstate(v->state)); - sbuf_printf(sb, "\n"); - } - - LIST_FOREACH(p, &sc->plexes, plex) { - if (!ondisk) - sbuf_printf(sb, "%s", prefix); - sbuf_printf(sb, "plex name %s org %s ", p->name, - gv_plexorg(p->org)); - if (gv_is_striped(p)) - sbuf_printf(sb, "%ds ", p->stripesize / 512); - if (p->vol_sc != NULL) - sbuf_printf(sb, "vol %s", p->volume); - if (ondisk) - sbuf_printf(sb, " state %s", gv_plexstate(p->state)); - sbuf_printf(sb, "\n"); - } - - LIST_FOREACH(s, &sc->subdisks, sd) { - if (!ondisk) - sbuf_printf(sb, "%s", prefix); - sbuf_printf(sb, "sd name %s drive %s len %jds driveoffset " - "%jds", s->name, s->drive, s->size / 512, - s->drive_offset / 512); - if (s->plex_sc != NULL) { - sbuf_printf(sb, " plex %s plexoffset %jds", s->plex, - s->plex_offset / 512); - } - if (ondisk) - sbuf_printf(sb, " state %s", gv_sdstate(s->state)); - sbuf_printf(sb, "\n"); - } -} - -static off_t -gv_plex_smallest_sd(struct gv_plex *p) -{ - struct gv_sd *s; - off_t smallest; - - KASSERT(p != NULL, ("gv_plex_smallest_sd: NULL p")); - - s = LIST_FIRST(&p->subdisks); - if (s == NULL) - return (-1); - smallest = s->size; - LIST_FOREACH(s, &p->subdisks, in_plex) { - if (s->size < smallest) - smallest = s->size; - } - return (smallest); -} - -/* Walk over plexes in a volume and count how many are down. */ -int -gv_plexdown(struct gv_volume *v) -{ - int plexdown; - struct gv_plex *p; - - KASSERT(v != NULL, ("gv_plexdown: NULL v")); - - plexdown = 0; - - LIST_FOREACH(p, &v->plexes, plex) { - if (p->state == GV_PLEX_DOWN) - plexdown++; - } - return (plexdown); -} - -int -gv_sd_to_plex(struct gv_sd *s, struct gv_plex *p) -{ - struct gv_sd *s2; - off_t psizeorig, remainder, smallest; - - /* If this subdisk was already given to this plex, do nothing. */ - if (s->plex_sc == p) - return (0); - - /* Check correct size of this subdisk. */ - s2 = LIST_FIRST(&p->subdisks); - /* Adjust the subdisk-size if necessary. */ - if (s2 != NULL && gv_is_striped(p)) { - /* First adjust to the stripesize. */ - remainder = s->size % p->stripesize; - - if (remainder) { - G_VINUM_DEBUG(1, "size of sd %s is not a " - "multiple of plex stripesize, taking off " - "%jd bytes", s->name, - (intmax_t)remainder); - gv_adjust_freespace(s, remainder); - } - - smallest = gv_plex_smallest_sd(p); - /* Then take off extra if other subdisks are smaller. */ - remainder = s->size - smallest; - - /* - * Don't allow a remainder below zero for running plexes, it's too - * painful, and if someone were to accidentally do this, the - * resulting array might be smaller than the original... not god - */ - if (remainder < 0) { - if (!(p->flags & GV_PLEX_NEWBORN)) { - G_VINUM_DEBUG(0, "sd %s too small for plex %s!", - s->name, p->name); - return (GV_ERR_BADSIZE); - } - /* Adjust other subdisks. */ - LIST_FOREACH(s2, &p->subdisks, in_plex) { - G_VINUM_DEBUG(1, "size of sd %s is to big, " - "taking off %jd bytes", s->name, - (intmax_t)remainder); - gv_adjust_freespace(s2, (remainder * -1)); - } - } else if (remainder > 0) { - G_VINUM_DEBUG(1, "size of sd %s is to big, " - "taking off %jd bytes", s->name, - (intmax_t)remainder); - gv_adjust_freespace(s, remainder); - } - } - - /* Find the correct plex offset for this subdisk, if needed. */ - if (s->plex_offset == -1) { - /* - * First set it to 0 to catch the case where we had a detached - * subdisk that didn't get any good offset. - */ - s->plex_offset = 0; - if (p->sdcount) { - LIST_FOREACH(s2, &p->subdisks, in_plex) { - if (gv_is_striped(p)) - s->plex_offset = p->sdcount * - p->stripesize; - else - s->plex_offset = s2->plex_offset + - s2->size; - } - } - } - - /* There are no subdisks for this plex yet, just insert it. */ - if (LIST_EMPTY(&p->subdisks)) { - LIST_INSERT_HEAD(&p->subdisks, s, in_plex); - - /* Insert in correct order, depending on plex_offset. */ - } else { - LIST_FOREACH(s2, &p->subdisks, in_plex) { - if (s->plex_offset < s2->plex_offset) { - LIST_INSERT_BEFORE(s2, s, in_plex); - break; - } else if (LIST_NEXT(s2, in_plex) == NULL) { - LIST_INSERT_AFTER(s2, s, in_plex); - break; - } - } - } - - s->plex_sc = p; - /* Adjust the size of our plex. We check if the plex misses a subdisk, - * so we don't make the plex smaller than it actually should be. - */ - psizeorig = p->size; - p->size = gv_plex_size(p); - /* Make sure the size is not changed. */ - if (p->sddetached > 0) { - if (p->size < psizeorig) { - p->size = psizeorig; - /* We make sure wee need another subdisk. */ - if (p->sddetached == 1) - p->sddetached++; - } - p->sddetached--; - } else { - if ((p->org == GV_PLEX_RAID5 || - p->org == GV_PLEX_STRIPED) && - !(p->flags & GV_PLEX_NEWBORN) && - p->state == GV_PLEX_UP) { - s->flags |= GV_SD_GROW; - } - p->sdcount++; - } - - return (0); -} - -void -gv_update_vol_size(struct gv_volume *v, off_t size) -{ - if (v == NULL) - return; - if (v->provider != NULL) { - g_topology_lock(); - v->provider->mediasize = size; - g_topology_unlock(); - } - v->size = size; -} - -/* Return how many subdisks that constitute the original plex. */ -int -gv_sdcount(struct gv_plex *p, int growing) -{ - struct gv_sd *s; - int sdcount; - - sdcount = p->sdcount; - if (growing) { - LIST_FOREACH(s, &p->subdisks, in_plex) { - if (s->flags & GV_SD_GROW) - sdcount--; - } - } - - return (sdcount); -} - -/* Calculates the plex size. */ -off_t -gv_plex_size(struct gv_plex *p) -{ - struct gv_sd *s; - off_t size; - int sdcount; - - KASSERT(p != NULL, ("gv_plex_size: NULL p")); - - /* Adjust the size of our plex. */ - size = 0; - sdcount = gv_sdcount(p, 1); - switch (p->org) { - case GV_PLEX_CONCAT: - LIST_FOREACH(s, &p->subdisks, in_plex) - size += s->size; - break; - case GV_PLEX_STRIPED: - s = LIST_FIRST(&p->subdisks); - size = ((s != NULL) ? (sdcount * s->size) : 0); - break; - case GV_PLEX_RAID5: - s = LIST_FIRST(&p->subdisks); - size = ((s != NULL) ? ((sdcount - 1) * s->size) : 0); - break; - } - - return (size); -} - -/* Returns the size of a volume. */ -off_t -gv_vol_size(struct gv_volume *v) -{ - struct gv_plex *p; - off_t minplexsize; - - KASSERT(v != NULL, ("gv_vol_size: NULL v")); - - p = LIST_FIRST(&v->plexes); - if (p == NULL) - return (0); - - minplexsize = p->size; - LIST_FOREACH(p, &v->plexes, in_volume) { - if (p->size < minplexsize) { - minplexsize = p->size; - } - } - return (minplexsize); -} - -void -gv_update_plex_config(struct gv_plex *p) -{ - struct gv_sd *s, *s2; - off_t remainder; - int required_sds, state; - - KASSERT(p != NULL, ("gv_update_plex_config: NULL p")); - - /* The plex was added to an already running volume. */ - if (p->flags & GV_PLEX_ADDED) - gv_set_plex_state(p, GV_PLEX_DOWN, GV_SETSTATE_FORCE); - - switch (p->org) { - case GV_PLEX_STRIPED: - required_sds = 2; - break; - case GV_PLEX_RAID5: - required_sds = 3; - break; - case GV_PLEX_CONCAT: - default: - required_sds = 0; - break; - } - - if (required_sds) { - if (p->sdcount < required_sds) { - gv_set_plex_state(p, GV_PLEX_DOWN, GV_SETSTATE_FORCE); - } - - /* - * The subdisks in striped plexes must all have the same size. - */ - s = LIST_FIRST(&p->subdisks); - LIST_FOREACH(s2, &p->subdisks, in_plex) { - if (s->size != s2->size) { - G_VINUM_DEBUG(0, "subdisk size mismatch %s" - "(%jd) <> %s (%jd)", s->name, s->size, - s2->name, s2->size); - gv_set_plex_state(p, GV_PLEX_DOWN, - GV_SETSTATE_FORCE); - } - } - - LIST_FOREACH(s, &p->subdisks, in_plex) { - /* Trim subdisk sizes to match the stripe size. */ - remainder = s->size % p->stripesize; - if (remainder) { - G_VINUM_DEBUG(1, "size of sd %s is not a " - "multiple of plex stripesize, taking off " - "%jd bytes", s->name, (intmax_t)remainder); - gv_adjust_freespace(s, remainder); - } - } - } - - p->size = gv_plex_size(p); - if (p->sdcount == 0) - gv_set_plex_state(p, GV_PLEX_DOWN, GV_SETSTATE_FORCE); - else if (p->org == GV_PLEX_RAID5 && p->flags & GV_PLEX_NEWBORN) { - LIST_FOREACH(s, &p->subdisks, in_plex) - gv_set_sd_state(s, GV_SD_UP, GV_SETSTATE_FORCE); - /* If added to a volume, we want the plex to be down. */ - state = (p->flags & GV_PLEX_ADDED) ? GV_PLEX_DOWN : GV_PLEX_UP; - gv_set_plex_state(p, state, GV_SETSTATE_FORCE); - p->flags &= ~GV_PLEX_ADDED; - } else if (p->flags & GV_PLEX_ADDED) { - LIST_FOREACH(s, &p->subdisks, in_plex) - gv_set_sd_state(s, GV_SD_STALE, GV_SETSTATE_FORCE); - gv_set_plex_state(p, GV_PLEX_DOWN, GV_SETSTATE_FORCE); - p->flags &= ~GV_PLEX_ADDED; - } else if (p->state == GV_PLEX_UP) { - LIST_FOREACH(s, &p->subdisks, in_plex) { - if (s->flags & GV_SD_GROW) { - gv_set_plex_state(p, GV_PLEX_GROWABLE, - GV_SETSTATE_FORCE); - break; - } - } - } - /* Our plex is grown up now. */ - p->flags &= ~GV_PLEX_NEWBORN; -} - -/* - * Give a subdisk to a drive, check and adjust several parameters, adjust - * freelist. - */ -int -gv_sd_to_drive(struct gv_sd *s, struct gv_drive *d) -{ - struct gv_sd *s2; - struct gv_freelist *fl, *fl2; - off_t tmp; - int i; - - fl2 = NULL; - - /* Shortcut for "referenced" drives. */ - if (d->flags & GV_DRIVE_REFERENCED) { - s->drive_sc = d; - return (0); - } - - /* Check if this subdisk was already given to this drive. */ - if (s->drive_sc != NULL) { - if (s->drive_sc == d) { - if (!(s->flags & GV_SD_TASTED)) { - return (0); - } - } else { - G_VINUM_DEBUG(0, "error giving subdisk '%s' to '%s' " - "(already on '%s')", s->name, d->name, - s->drive_sc->name); - return (GV_ERR_ISATTACHED); - } - } - - /* Preliminary checks. */ - if ((s->size > d->avail) || (d->freelist_entries == 0)) { - G_VINUM_DEBUG(0, "not enough space on '%s' for '%s'", d->name, - s->name); - return (GV_ERR_NOSPACE); - } - - /* If no size was given for this subdisk, try to auto-size it... */ - if (s->size == -1) { - /* Find the largest available slot. */ - LIST_FOREACH(fl, &d->freelist, freelist) { - if (fl->size < s->size) - continue; - s->size = fl->size; - s->drive_offset = fl->offset; - fl2 = fl; - } - - /* No good slot found? */ - if (s->size == -1) { - G_VINUM_DEBUG(0, "unable to autosize '%s' on '%s'", - s->name, d->name); - return (GV_ERR_BADSIZE); - } - - /* - * ... or check if we have a free slot that's large enough for the - * given size. - */ - } else { - i = 0; - LIST_FOREACH(fl, &d->freelist, freelist) { - if (fl->size < s->size) - continue; - /* Assign drive offset, if not given. */ - if (s->drive_offset == -1) - s->drive_offset = fl->offset; - fl2 = fl; - i++; - break; - } - - /* Couldn't find a good free slot. */ - if (i == 0) { - G_VINUM_DEBUG(0, "free slots to small for '%s' on '%s'", - s->name, d->name); - return (GV_ERR_NOSPACE); - } - } - - /* No drive offset given, try to calculate it. */ - if (s->drive_offset == -1) { - /* Add offsets and sizes from other subdisks on this drive. */ - LIST_FOREACH(s2, &d->subdisks, from_drive) { - s->drive_offset = s2->drive_offset + s2->size; - } - - /* - * If there are no other subdisks yet, then set the default - * offset to GV_DATA_START. - */ - if (s->drive_offset == -1) - s->drive_offset = GV_DATA_START; - - /* Check if we have a free slot at the given drive offset. */ - } else { - i = 0; - LIST_FOREACH(fl, &d->freelist, freelist) { - /* Yes, this subdisk fits. */ - if ((fl->offset <= s->drive_offset) && - (fl->offset + fl->size >= - s->drive_offset + s->size)) { - i++; - fl2 = fl; - break; - } - } - - /* Couldn't find a good free slot. */ - if (i == 0) { - G_VINUM_DEBUG(0, "given drive_offset for '%s' won't fit " - "on '%s'", s->name, d->name); - return (GV_ERR_NOSPACE); - } - } - - /* - * Now that all parameters are checked and set up, we can give the - * subdisk to the drive and adjust the freelist. - */ - - /* First, adjust the freelist. */ - LIST_FOREACH(fl, &d->freelist, freelist) { - /* Look for the free slot that we have found before. */ - if (fl != fl2) - continue; - - /* The subdisk starts at the beginning of the free slot. */ - if (fl->offset == s->drive_offset) { - fl->offset += s->size; - fl->size -= s->size; - - /* The subdisk uses the whole slot, so remove it. */ - if (fl->size == 0) { - d->freelist_entries--; - LIST_REMOVE(fl, freelist); - } - /* - * The subdisk does not start at the beginning of the free - * slot. - */ - } else { - tmp = fl->offset + fl->size; - fl->size = s->drive_offset - fl->offset; - - /* - * The subdisk didn't use the complete rest of the free - * slot, so we need to split it. - */ - if (s->drive_offset + s->size != tmp) { - fl2 = g_malloc(sizeof(*fl2), M_WAITOK | M_ZERO); - fl2->offset = s->drive_offset + s->size; - fl2->size = tmp - fl2->offset; - LIST_INSERT_AFTER(fl, fl2, freelist); - d->freelist_entries++; - } - } - break; - } - - /* - * This is the first subdisk on this drive, just insert it into the - * list. - */ - if (LIST_EMPTY(&d->subdisks)) { - LIST_INSERT_HEAD(&d->subdisks, s, from_drive); - - /* There are other subdisks, so insert this one in correct order. */ - } else { - LIST_FOREACH(s2, &d->subdisks, from_drive) { - if (s->drive_offset < s2->drive_offset) { - LIST_INSERT_BEFORE(s2, s, from_drive); - break; - } else if (LIST_NEXT(s2, from_drive) == NULL) { - LIST_INSERT_AFTER(s2, s, from_drive); - break; - } - } - } - - d->sdcount++; - d->avail -= s->size; - - s->flags &= ~GV_SD_TASTED; - - /* Link back from the subdisk to this drive. */ - s->drive_sc = d; - - return (0); -} - -void -gv_free_sd(struct gv_sd *s) -{ - struct gv_drive *d; - struct gv_freelist *fl, *fl2; - - KASSERT(s != NULL, ("gv_free_sd: NULL s")); - - d = s->drive_sc; - if (d == NULL) - return; - - /* - * First, find the free slot that's immediately before or after this - * subdisk. - */ - fl = NULL; - LIST_FOREACH(fl, &d->freelist, freelist) { - if (fl->offset == s->drive_offset + s->size) - break; - if (fl->offset + fl->size == s->drive_offset) - break; - } - - /* If there is no free slot behind this subdisk, so create one. */ - if (fl == NULL) { - fl = g_malloc(sizeof(*fl), M_WAITOK | M_ZERO); - fl->size = s->size; - fl->offset = s->drive_offset; - - if (d->freelist_entries == 0) { - LIST_INSERT_HEAD(&d->freelist, fl, freelist); - } else { - LIST_FOREACH(fl2, &d->freelist, freelist) { - if (fl->offset < fl2->offset) { - LIST_INSERT_BEFORE(fl2, fl, freelist); - break; - } else if (LIST_NEXT(fl2, freelist) == NULL) { - LIST_INSERT_AFTER(fl2, fl, freelist); - break; - } - } - } - - d->freelist_entries++; - - /* Expand the free slot we just found. */ - } else { - fl->size += s->size; - if (fl->offset > s->drive_offset) - fl->offset = s->drive_offset; - } - - d->avail += s->size; - d->sdcount--; -} - -void -gv_adjust_freespace(struct gv_sd *s, off_t remainder) -{ - struct gv_drive *d; - struct gv_freelist *fl, *fl2; - - KASSERT(s != NULL, ("gv_adjust_freespace: NULL s")); - d = s->drive_sc; - KASSERT(d != NULL, ("gv_adjust_freespace: NULL d")); - - /* First, find the free slot that's immediately after this subdisk. */ - fl = NULL; - LIST_FOREACH(fl, &d->freelist, freelist) { - if (fl->offset == s->drive_offset + s->size) - break; - } - - /* If there is no free slot behind this subdisk, so create one. */ - if (fl == NULL) { - fl = g_malloc(sizeof(*fl), M_WAITOK | M_ZERO); - fl->size = remainder; - fl->offset = s->drive_offset + s->size - remainder; - - if (d->freelist_entries == 0) { - LIST_INSERT_HEAD(&d->freelist, fl, freelist); - } else { - LIST_FOREACH(fl2, &d->freelist, freelist) { - if (fl->offset < fl2->offset) { - LIST_INSERT_BEFORE(fl2, fl, freelist); - break; - } else if (LIST_NEXT(fl2, freelist) == NULL) { - LIST_INSERT_AFTER(fl2, fl, freelist); - break; - } - } - } - - d->freelist_entries++; - - /* Expand the free slot we just found. */ - } else { - fl->offset -= remainder; - fl->size += remainder; - } - - s->size -= remainder; - d->avail += remainder; -} - -/* Check if the given plex is a striped one. */ -int -gv_is_striped(struct gv_plex *p) -{ - KASSERT(p != NULL, ("gv_is_striped: NULL p")); - switch(p->org) { - case GV_PLEX_STRIPED: - case GV_PLEX_RAID5: - return (1); - default: - return (0); - } -} - -/* Find a volume by name. */ -struct gv_volume * -gv_find_vol(struct gv_softc *sc, char *name) -{ - struct gv_volume *v; - - LIST_FOREACH(v, &sc->volumes, volume) { - if (!strncmp(v->name, name, GV_MAXVOLNAME)) - return (v); - } - - return (NULL); -} - -/* Find a plex by name. */ -struct gv_plex * -gv_find_plex(struct gv_softc *sc, char *name) -{ - struct gv_plex *p; - - LIST_FOREACH(p, &sc->plexes, plex) { - if (!strncmp(p->name, name, GV_MAXPLEXNAME)) - return (p); - } - - return (NULL); -} - -/* Find a subdisk by name. */ -struct gv_sd * -gv_find_sd(struct gv_softc *sc, char *name) -{ - struct gv_sd *s; - - LIST_FOREACH(s, &sc->subdisks, sd) { - if (!strncmp(s->name, name, GV_MAXSDNAME)) - return (s); - } - - return (NULL); -} - -/* Find a drive by name. */ -struct gv_drive * -gv_find_drive(struct gv_softc *sc, char *name) -{ - struct gv_drive *d; - - LIST_FOREACH(d, &sc->drives, drive) { - if (!strncmp(d->name, name, GV_MAXDRIVENAME)) - return (d); - } - - return (NULL); -} - -/* Find a drive given a device. */ -struct gv_drive * -gv_find_drive_device(struct gv_softc *sc, char *device) -{ - struct gv_drive *d; - - LIST_FOREACH(d, &sc->drives, drive) { - if(!strcmp(d->device, device)) - return (d); - } - - return (NULL); -} - -/* Check if any consumer of the given geom is open. */ -int -gv_consumer_is_open(struct g_consumer *cp) -{ - if (cp == NULL) - return (0); - - if (cp->acr || cp->acw || cp->ace) - return (1); - - return (0); -} - -int -gv_provider_is_open(struct g_provider *pp) -{ - if (pp == NULL) - return (0); - - if (pp->acr || pp->acw || pp->ace) - return (1); - - return (0); -} - -/* - * Compare the modification dates of the drives. - * Return 1 if a > b, 0 otherwise. - */ -int -gv_drive_is_newer(struct gv_softc *sc, struct gv_drive *d) -{ - struct gv_drive *d2; - struct timeval *a, *b; - - KASSERT(!LIST_EMPTY(&sc->drives), - ("gv_is_drive_newer: empty drive list")); - - a = &d->hdr->label.last_update; - LIST_FOREACH(d2, &sc->drives, drive) { - if ((d == d2) || (d2->state != GV_DRIVE_UP) || - (d2->hdr == NULL)) - continue; - b = &d2->hdr->label.last_update; - if (timevalcmp(a, b, >)) - return (1); - } - - return (0); -} - -/* Return the type of object identified by string 'name'. */ -int -gv_object_type(struct gv_softc *sc, char *name) -{ - struct gv_drive *d; - struct gv_plex *p; - struct gv_sd *s; - struct gv_volume *v; - - LIST_FOREACH(v, &sc->volumes, volume) { - if (!strncmp(v->name, name, GV_MAXVOLNAME)) - return (GV_TYPE_VOL); - } - - LIST_FOREACH(p, &sc->plexes, plex) { - if (!strncmp(p->name, name, GV_MAXPLEXNAME)) - return (GV_TYPE_PLEX); - } - - LIST_FOREACH(s, &sc->subdisks, sd) { - if (!strncmp(s->name, name, GV_MAXSDNAME)) - return (GV_TYPE_SD); - } - - LIST_FOREACH(d, &sc->drives, drive) { - if (!strncmp(d->name, name, GV_MAXDRIVENAME)) - return (GV_TYPE_DRIVE); - } - - return (GV_ERR_NOTFOUND); -} - -void -gv_setup_objects(struct gv_softc *sc) -{ - struct g_provider *pp; - struct gv_volume *v; - struct gv_plex *p; - struct gv_sd *s; - struct gv_drive *d; - - LIST_FOREACH(s, &sc->subdisks, sd) { - d = gv_find_drive(sc, s->drive); - if (d != NULL) - gv_sd_to_drive(s, d); - p = gv_find_plex(sc, s->plex); - if (p != NULL) - gv_sd_to_plex(s, p); - gv_update_sd_state(s); - } - - LIST_FOREACH(p, &sc->plexes, plex) { - gv_update_plex_config(p); - v = gv_find_vol(sc, p->volume); - if (v != NULL && p->vol_sc != v) { - p->vol_sc = v; - v->plexcount++; - LIST_INSERT_HEAD(&v->plexes, p, in_volume); - } - gv_update_plex_config(p); - } - - LIST_FOREACH(v, &sc->volumes, volume) { - v->size = gv_vol_size(v); - if (v->provider == NULL) { - g_topology_lock(); - pp = g_new_providerf(sc->geom, "gvinum/%s", v->name); - pp->mediasize = v->size; - pp->sectorsize = 512; /* XXX */ - g_error_provider(pp, 0); - v->provider = pp; - pp->private = v; - g_topology_unlock(); - } else if (v->provider->mediasize != v->size) { - g_topology_lock(); - v->provider->mediasize = v->size; - g_topology_unlock(); - } - v->flags &= ~GV_VOL_NEWBORN; - gv_update_vol_state(v); - } -} - -void -gv_cleanup(struct gv_softc *sc) -{ - struct gv_volume *v, *v2; - struct gv_plex *p, *p2; - struct gv_sd *s, *s2; - struct gv_drive *d, *d2; - struct gv_freelist *fl, *fl2; - - mtx_lock(&sc->config_mtx); - LIST_FOREACH_SAFE(v, &sc->volumes, volume, v2) { - LIST_REMOVE(v, volume); - g_free(v->wqueue); - g_free(v); - } - LIST_FOREACH_SAFE(p, &sc->plexes, plex, p2) { - LIST_REMOVE(p, plex); - g_free(p->bqueue); - g_free(p->rqueue); - g_free(p->wqueue); - g_free(p); - } - LIST_FOREACH_SAFE(s, &sc->subdisks, sd, s2) { - LIST_REMOVE(s, sd); - g_free(s); - } - LIST_FOREACH_SAFE(d, &sc->drives, drive, d2) { - LIST_FOREACH_SAFE(fl, &d->freelist, freelist, fl2) { - LIST_REMOVE(fl, freelist); - g_free(fl); - } - LIST_REMOVE(d, drive); - g_free(d->hdr); - g_free(d); - } - mtx_destroy(&sc->config_mtx); -} - -/* General 'attach' routine. */ -int -gv_attach_plex(struct gv_plex *p, struct gv_volume *v, int rename) -{ - struct gv_sd *s; - struct gv_softc *sc __diagused; - - g_topology_assert(); - - sc = p->vinumconf; - KASSERT(sc != NULL, ("NULL sc")); - - if (p->vol_sc != NULL) { - G_VINUM_DEBUG(1, "unable to attach %s: already attached to %s", - p->name, p->volume); - return (GV_ERR_ISATTACHED); - } - - /* Stale all subdisks of this plex. */ - LIST_FOREACH(s, &p->subdisks, in_plex) { - if (s->state != GV_SD_STALE) - gv_set_sd_state(s, GV_SD_STALE, GV_SETSTATE_FORCE); - } - /* Attach to volume. Make sure volume is not up and running. */ - if (gv_provider_is_open(v->provider)) { - G_VINUM_DEBUG(1, "unable to attach %s: volume %s is busy", - p->name, v->name); - return (GV_ERR_ISBUSY); - } - p->vol_sc = v; - strlcpy(p->volume, v->name, sizeof(p->volume)); - v->plexcount++; - if (rename) { - snprintf(p->name, sizeof(p->name), "%s.p%d", v->name, - v->plexcount); - } - LIST_INSERT_HEAD(&v->plexes, p, in_volume); - - /* Get plex up again. */ - gv_update_vol_size(v, gv_vol_size(v)); - gv_set_plex_state(p, GV_PLEX_UP, 0); - gv_save_config(p->vinumconf); - return (0); -} - -int -gv_attach_sd(struct gv_sd *s, struct gv_plex *p, off_t offset, int rename) -{ - struct gv_sd *s2; - int error; - - g_topology_assert(); - - /* If subdisk is attached, don't do it. */ - if (s->plex_sc != NULL) { - G_VINUM_DEBUG(1, "unable to attach %s: already attached to %s", - s->name, s->plex); - return (GV_ERR_ISATTACHED); - } - - gv_set_sd_state(s, GV_SD_STALE, GV_SETSTATE_FORCE); - /* First check that this subdisk has a correct offset. If none other - * starts at the same, and it's correct module stripesize, it is */ - if (offset != -1 && offset % p->stripesize != 0) - return (GV_ERR_BADOFFSET); - LIST_FOREACH(s2, &p->subdisks, in_plex) { - if (s2->plex_offset == offset) - return (GV_ERR_BADOFFSET); - } - - /* Attach the subdisk to the plex at given offset. */ - s->plex_offset = offset; - strlcpy(s->plex, p->name, sizeof(s->plex)); - - error = gv_sd_to_plex(s, p); - if (error) - return (error); - gv_update_plex_config(p); - - if (rename) { - snprintf(s->name, sizeof(s->name), "%s.s%d", s->plex, - p->sdcount); - } - if (p->vol_sc != NULL) - gv_update_vol_size(p->vol_sc, gv_vol_size(p->vol_sc)); - gv_save_config(p->vinumconf); - /* We don't update the subdisk state since the user might have to - * initiate a rebuild/sync first. */ - return (0); -} - -/* Detach a plex from a volume. */ -int -gv_detach_plex(struct gv_plex *p, int flags) -{ - struct gv_volume *v; - - g_topology_assert(); - v = p->vol_sc; - - if (v == NULL) { - G_VINUM_DEBUG(1, "unable to detach %s: already detached", - p->name); - return (0); /* Not an error. */ - } - - /* - * Only proceed if forced or volume inactive. - */ - if (!(flags & GV_FLAG_F) && (gv_provider_is_open(v->provider) || - p->state == GV_PLEX_UP)) { - G_VINUM_DEBUG(1, "unable to detach %s: volume %s is busy", - p->name, p->volume); - return (GV_ERR_ISBUSY); - } - v->plexcount--; - /* Make sure someone don't read us when gone. */ - v->last_read_plex = NULL; - LIST_REMOVE(p, in_volume); - p->vol_sc = NULL; - memset(p->volume, 0, GV_MAXVOLNAME); - gv_update_vol_size(v, gv_vol_size(v)); - gv_save_config(p->vinumconf); - return (0); -} - -/* Detach a subdisk from a plex. */ -int -gv_detach_sd(struct gv_sd *s, int flags) -{ - struct gv_plex *p; - - g_topology_assert(); - p = s->plex_sc; - - if (p == NULL) { - G_VINUM_DEBUG(1, "unable to detach %s: already detached", - s->name); - return (0); /* Not an error. */ - } - - /* - * Don't proceed if we're not forcing, and the plex is up, or degraded - * with this subdisk up. - */ - if (!(flags & GV_FLAG_F) && ((p->state > GV_PLEX_DEGRADED) || - ((p->state == GV_PLEX_DEGRADED) && (s->state == GV_SD_UP)))) { - G_VINUM_DEBUG(1, "unable to detach %s: plex %s is busy", - s->name, s->plex); - return (GV_ERR_ISBUSY); - } - - LIST_REMOVE(s, in_plex); - s->plex_sc = NULL; - memset(s->plex, 0, GV_MAXPLEXNAME); - p->sddetached++; - gv_save_config(s->vinumconf); - return (0); -} diff --git a/sys/geom/vinum/geom_vinum_var.h b/sys/geom/vinum/geom_vinum_var.h deleted file mode 100644 --- a/sys/geom/vinum/geom_vinum_var.h +++ /dev/null @@ -1,393 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-4-Clause - * - * Copyright (c) 2004, 2007 Lukas Ertl - * Copyright (c) 1997, 1998, 1999 - * Nan Yang Computer Services Limited. All rights reserved. - * - * Parts copyright (c) 1997, 1998 Cybernet Corporation, NetMAX project. - * Parts written by Greg Lehey. - * - * This software is distributed under the so-called ``Berkeley - * License'': * - * 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. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Nan Yang Computer - * Services Limited. - * 4. Neither the name of the Company nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * This software is provided ``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 company 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. - * - */ - -#ifndef _GEOM_VINUM_VAR_H_ -#define _GEOM_VINUM_VAR_H_ - -/* - * Slice header - * - * Vinum drives start with this structure: - * - *\ Sector - * |--------------------------------------| - * | PDP-11 memorial boot block | 0 - * |--------------------------------------| - * | Disk label, maybe | 1 - * |--------------------------------------| - * | Slice definition (vinum_hdr) | 8 - * |--------------------------------------| - * | | - * | Configuration info, first copy | 9 - * | | - * |--------------------------------------| - * | | - * | Configuration info, second copy | 9 + size of config - * | | - * |--------------------------------------| - */ - -/* Sizes and offsets of our information. */ -#define GV_HDR_OFFSET 4096 /* Offset of vinum header. */ -#define GV_HDR_LEN 512 /* Size of vinum header. */ -#define GV_CFG_OFFSET 4608 /* Offset of first config copy. */ -#define GV_CFG_LEN 65536 /* Size of config copy. */ - -/* This is where the actual data starts. */ -#define GV_DATA_START (GV_CFG_LEN * 2 + GV_CFG_OFFSET) -/* #define GV_DATA_START (GV_CFG_LEN * 2 + GV_HDR_LEN) */ - -#define GV_MAXDRIVENAME 32 /* Maximum length of a device name. */ -#define GV_MAXSDNAME 64 /* Maximum length of a subdisk name. */ -#define GV_MAXPLEXNAME 64 /* Maximum length of a plex name. */ -#define GV_MAXVOLNAME 64 /* Maximum length of a volume name. */ - -/* Command line flags. */ -#define GV_FLAG_R 0x01 -#define GV_FLAG_S 0x02 -#define GV_FLAG_V 0x04 -#define GV_FLAG_VV 0x08 -#define GV_FLAG_F 0x10 - -/* Object types. */ -#define GV_TYPE_VOL 1 -#define GV_TYPE_PLEX 2 -#define GV_TYPE_SD 3 -#define GV_TYPE_DRIVE 4 - -/* State changing flags. */ -#define GV_SETSTATE_FORCE 0x1 -#define GV_SETSTATE_CONFIG 0x2 - -/* Subdisk state bitmaps for plexes. */ -#define GV_SD_DOWNSTATE 0x01 /* Subdisk is down. */ -#define GV_SD_STALESTATE 0x02 /* Subdisk is stale. */ -#define GV_SD_INITSTATE 0x04 /* Subdisk is initializing. */ -#define GV_SD_UPSTATE 0x08 /* Subdisk is up. */ - -/* Synchronization/initialization request sizes. */ -#define GV_MIN_SYNCSIZE 512 -#define GV_MAX_SYNCSIZE maxphys -#define GV_DFLT_SYNCSIZE 65536 - -/* Flags for BIOs, as they are processed within vinum. */ -#define GV_BIO_GROW 0x01 -#define GV_BIO_MALLOC 0x02 -#define GV_BIO_ONHOLD 0x04 -#define GV_BIO_SYNCREQ 0x08 -#define GV_BIO_INIT 0x10 -#define GV_BIO_REBUILD 0x20 -#define GV_BIO_CHECK 0x40 -#define GV_BIO_PARITY 0x80 -#define GV_BIO_INTERNAL \ - (GV_BIO_SYNCREQ | GV_BIO_INIT | GV_BIO_REBUILD | GV_BIO_CHECK | GV_BIO_GROW) - -/* Error codes to be used within gvinum. */ -#define GV_ERR_SETSTATE (-1) /* Error setting state. */ -#define GV_ERR_BADSIZE (-2) /* Object has wrong size. */ -#define GV_ERR_INVTYPE (-3) /* Invalid object type. */ -#define GV_ERR_CREATE (-4) /* Error creating gvinum object. */ -#define GV_ERR_ISBUSY (-5) /* Object is busy. */ -#define GV_ERR_ISATTACHED (-6) /* Object is attached to another. */ -#define GV_ERR_INVFLAG (-7) /* Invalid flag passed. */ -#define GV_ERR_INVSTATE (-8) /* Invalid state. */ -#define GV_ERR_NOTFOUND (-9) /* Object not found. */ -#define GV_ERR_NAMETAKEN (-10) /* Object name is taken. */ -#define GV_ERR_NOSPACE (-11) /* No space left on drive/subdisk. */ -#define GV_ERR_BADOFFSET (-12) /* Invalid offset specified. */ -#define GV_ERR_INVNAME (-13) /* Invalid object name. */ -#define GV_ERR_PLEXORG (-14) /* Invalid plex organization. */ - -/* - * hostname is 256 bytes long, but we don't need to shlep multiple copies in - * vinum. We use the host name just to identify this system, and 32 bytes - * should be ample for that purpose. - */ - -#define GV_HOSTNAME_LEN 32 -struct gv_label { - char sysname[GV_HOSTNAME_LEN]; /* System name at creation time. */ - char name[GV_MAXDRIVENAME]; /* Our name of the drive. */ - struct timeval date_of_birth; /* The time it was created ... */ - struct timeval last_update; /* ... and the time of last update. */ - off_t drive_size; /* Total size incl. headers. */ -}; - -/* The 'header' of each valid vinum drive. */ -struct gv_hdr { - uint64_t magic; -#define GV_OLD_MAGIC 0x494E2056494E4F00LL -#define GV_OLD_NOMAGIC 0x4E4F2056494E4F00LL -#define GV_MAGIC 0x56494E554D2D3100LL -#define GV_NOMAGIC 0x56494E554D2D2D00LL - - uint64_t config_length; - struct gv_label label; -}; - -/* A single freelist entry of a drive. */ -struct gv_freelist { - off_t size; /* Size of this free slot. */ - off_t offset; /* Offset on the drive. */ - LIST_ENTRY(gv_freelist) freelist; -}; - -/* - * Since we share structures between userland and kernel, we need this helper - * struct instead of struct bio_queue_head and friends. Maybe I find a proper - * solution some day. - */ -struct gv_bioq { - struct bio *bp; - TAILQ_ENTRY(gv_bioq) queue; -}; - -#define GV_EVENT_DRIVE_TASTED 1 -#define GV_EVENT_DRIVE_LOST 2 -#define GV_EVENT_THREAD_EXIT 3 -#define GV_EVENT_CREATE_DRIVE 4 -#define GV_EVENT_CREATE_VOLUME 5 -#define GV_EVENT_CREATE_PLEX 6 -#define GV_EVENT_CREATE_SD 7 -#define GV_EVENT_SAVE_CONFIG 8 -#define GV_EVENT_RM_VOLUME 9 -#define GV_EVENT_RM_PLEX 10 -#define GV_EVENT_RM_SD 11 -#define GV_EVENT_RM_DRIVE 12 -#define GV_EVENT_SET_SD_STATE 13 -#define GV_EVENT_SET_DRIVE_STATE 14 -#define GV_EVENT_SET_VOL_STATE 15 -#define GV_EVENT_SET_PLEX_STATE 16 -#define GV_EVENT_RESET_CONFIG 17 -#define GV_EVENT_PARITY_REBUILD 18 -#define GV_EVENT_PARITY_CHECK 19 -#define GV_EVENT_START_PLEX 20 -#define GV_EVENT_START_VOLUME 21 -#define GV_EVENT_ATTACH_PLEX 22 -#define GV_EVENT_ATTACH_SD 23 -#define GV_EVENT_DETACH_PLEX 24 -#define GV_EVENT_DETACH_SD 25 -#define GV_EVENT_RENAME_VOL 26 -#define GV_EVENT_RENAME_PLEX 27 -#define GV_EVENT_RENAME_SD 28 -#define GV_EVENT_RENAME_DRIVE 29 -#define GV_EVENT_MOVE_SD 30 -#define GV_EVENT_SETUP_OBJECTS 31 - -#ifdef _KERNEL -struct gv_event { - int type; - void *arg1; - void *arg2; - intmax_t arg3; - intmax_t arg4; - TAILQ_ENTRY(gv_event) events; -}; - -/* This struct contains the main vinum config. */ -struct gv_softc { - /* Linked lists of all objects in our setup. */ - LIST_HEAD(,gv_drive) drives; /* All drives. */ - LIST_HEAD(,gv_plex) plexes; /* All plexes. */ - LIST_HEAD(,gv_sd) subdisks; /* All subdisks. */ - LIST_HEAD(,gv_volume) volumes; /* All volumes. */ - - TAILQ_HEAD(,gv_event) equeue; /* Event queue. */ - struct mtx equeue_mtx; /* Event queue lock. */ - struct mtx bqueue_mtx; /* BIO queue lock. */ - struct mtx config_mtx; /* Configuration lock. */ - struct bio_queue_head *bqueue_down; /* BIO queue incoming - requests. */ - struct bio_queue_head *bqueue_up; /* BIO queue for completed - requests. */ - struct g_geom *geom; /* Pointer to our VINUM geom. */ - struct proc *worker; /* Worker process. */ -}; -#endif - -/* softc for a drive. */ -struct gv_drive { - char name[GV_MAXDRIVENAME]; /* The name of this drive. */ - char device[GV_MAXDRIVENAME]; /* Associated device. */ - int state; /* The state of this drive. */ -#define GV_DRIVE_DOWN 0 -#define GV_DRIVE_UP 1 - - off_t size; /* Size of this drive. */ - off_t avail; /* Available space. */ - int sdcount; /* Number of subdisks. */ - - int flags; -#define GV_DRIVE_REFERENCED 0x01 /* The drive isn't really existing, - but was referenced by a subdisk - during taste. */ -#define GV_DRIVE_ORPHANED 0x02 /* The drive was orphaned. */ - - struct gv_hdr *hdr; /* The drive header. */ - - struct g_consumer *consumer; /* Consumer attached to this drive. */ - int active; /* Number of active requests. */ - - int freelist_entries; /* Count of freelist entries. */ - LIST_HEAD(,gv_freelist) freelist; /* List of freelist entries. */ - LIST_HEAD(,gv_sd) subdisks; /* Subdisks on this drive. */ - LIST_ENTRY(gv_drive) drive; /* Entry in the vinum config. */ - - struct gv_softc *vinumconf; /* Pointer to the vinum conf. */ -}; - -/* softc for a subdisk. */ -struct gv_sd { - char name[GV_MAXSDNAME]; /* The name of this subdisk. */ - off_t size; /* The size of this subdisk. */ - off_t drive_offset; /* Offset in the underlying drive. */ - off_t plex_offset; /* Offset in the associated plex. */ - int state; /* The state of this subdisk. */ -#define GV_SD_DOWN 0 -#define GV_SD_STALE 1 -#define GV_SD_INITIALIZING 2 -#define GV_SD_REVIVING 3 -#define GV_SD_UP 4 - - off_t initialized; /* Count of initialized bytes. */ - - int init_size; /* Initialization read/write size. */ - int init_error; /* Flag error on initialization. */ - - int flags; -#define GV_SD_NEWBORN 0x01 /* Subdisk is created by user. */ -#define GV_SD_TASTED 0x02 /* Subdisk is created during taste. */ -#define GV_SD_CANGOUP 0x04 /* Subdisk can go up immediately. */ -#define GV_SD_GROW 0x08 /* Subdisk is added to striped plex. */ - - char drive[GV_MAXDRIVENAME]; /* Name of underlying drive. */ - char plex[GV_MAXPLEXNAME]; /* Name of associated plex. */ - - struct gv_drive *drive_sc; /* Pointer to underlying drive. */ - struct gv_plex *plex_sc; /* Pointer to associated plex. */ - - LIST_ENTRY(gv_sd) from_drive; /* Subdisk list of underlying drive. */ - LIST_ENTRY(gv_sd) in_plex; /* Subdisk list of associated plex. */ - LIST_ENTRY(gv_sd) sd; /* Entry in the vinum config. */ - - struct gv_softc *vinumconf; /* Pointer to the vinum config. */ -}; - -/* softc for a plex. */ -struct gv_plex { - char name[GV_MAXPLEXNAME]; /* The name of the plex. */ - off_t size; /* The size of the plex. */ - int state; /* The plex state. */ -#define GV_PLEX_DOWN 0 -#define GV_PLEX_INITIALIZING 1 -#define GV_PLEX_DEGRADED 2 -#define GV_PLEX_GROWABLE 3 -#define GV_PLEX_UP 4 - - int org; /* The plex organisation. */ -#define GV_PLEX_DISORG 0 -#define GV_PLEX_CONCAT 1 -#define GV_PLEX_STRIPED 2 -#define GV_PLEX_RAID5 4 - - int stripesize; /* The stripe size of the plex. */ - - char volume[GV_MAXVOLNAME]; /* Name of associated volume. */ - struct gv_volume *vol_sc; /* Pointer to associated volume. */ - - int sddetached; /* Number of detached subdisks. */ - int sdcount; /* Number of subdisks in this plex. */ - int sddown; /* Number of subdisks that are down. */ - int flags; -#define GV_PLEX_ADDED 0x01 /* Added to an existing volume. */ -#define GV_PLEX_SYNCING 0x02 /* Plex is syncing from another plex. */ -#define GV_PLEX_NEWBORN 0x20 /* The plex was just created. */ -#define GV_PLEX_REBUILDING 0x40 /* The plex is rebuilding. */ -#define GV_PLEX_GROWING 0x80 /* The plex is growing. */ - - off_t synced; /* Count of synced bytes. */ - - TAILQ_HEAD(,gv_raid5_packet) packets; /* RAID5 sub-requests. */ - - LIST_HEAD(,gv_sd) subdisks; /* List of attached subdisks. */ - LIST_ENTRY(gv_plex) in_volume; /* Plex list of associated volume. */ - LIST_ENTRY(gv_plex) plex; /* Entry in the vinum config. */ - -#ifdef _KERNEL - struct bio_queue_head *bqueue; /* BIO queue. */ - struct bio_queue_head *wqueue; /* Waiting BIO queue. */ - struct bio_queue_head *rqueue; /* Rebuild waiting BIO queue. */ -#else - char *bpad, *wpad, *rpad; /* Padding for userland. */ -#endif - - struct gv_softc *vinumconf; /* Pointer to the vinum config. */ -}; - -/* softc for a volume. */ -struct gv_volume { - char name[GV_MAXVOLNAME]; /* The name of the volume. */ - off_t size; /* The size of the volume. */ - int plexcount; /* Number of plexes. */ - int state; /* The state of the volume. */ -#define GV_VOL_DOWN 0 -#define GV_VOL_UP 1 - - int flags; -#define GV_VOL_NEWBORN 0x08 /* The volume was just created. */ - - LIST_HEAD(,gv_plex) plexes; /* List of attached plexes. */ - LIST_ENTRY(gv_volume) volume; /* Entry in vinum config. */ - - struct g_provider *provider; /* Provider of this volume. */ - -#ifdef _KERNEL - struct bio_queue_head *wqueue; /* BIO delayed request queue. */ -#else - char *wpad; /* Padding for userland. */ -#endif - - struct gv_plex *last_read_plex; - struct gv_softc *vinumconf; /* Pointer to the vinum config. */ -}; - -#endif /* !_GEOM_VINUM_VAR_H */ diff --git a/sys/geom/vinum/geom_vinum_volume.c b/sys/geom/vinum/geom_vinum_volume.c deleted file mode 100644 --- a/sys/geom/vinum/geom_vinum_volume.c +++ /dev/null @@ -1,163 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause - * - * Copyright (c) 2007 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/param.h> -#include <sys/bio.h> -#include <sys/lock.h> -#include <sys/malloc.h> -#include <sys/systm.h> - -#include <geom/geom.h> -#include <geom/vinum/geom_vinum_var.h> -#include <geom/vinum/geom_vinum.h> - -void -gv_volume_flush(struct gv_volume *v) -{ - struct gv_softc *sc; - struct bio *bp; - - KASSERT(v != NULL, ("NULL v")); - sc = v->vinumconf; - KASSERT(sc != NULL, ("NULL sc")); - - bp = bioq_takefirst(v->wqueue); - while (bp != NULL) { - gv_volume_start(sc, bp); - bp = bioq_takefirst(v->wqueue); - } -} - -void -gv_volume_start(struct gv_softc *sc, struct bio *bp) -{ - struct gv_volume *v; - struct gv_plex *p, *lp; - int numwrites; - - v = bp->bio_to->private; - if (v == NULL || v->state != GV_VOL_UP) { - g_io_deliver(bp, ENXIO); - return; - } - - switch (bp->bio_cmd) { - case BIO_READ: - /* - * Try to find a good plex where we can send the request to, - * round-robin-style. The plex either has to be up, or it's a - * degraded RAID5 plex. Check if we have delayed requests. Put - * this request on the delayed queue if so. This makes sure that - * we don't read old values. - */ - if (bioq_first(v->wqueue) != NULL) { - bioq_insert_tail(v->wqueue, bp); - break; - } - lp = v->last_read_plex; - if (lp == NULL) - lp = LIST_FIRST(&v->plexes); - p = LIST_NEXT(lp, in_volume); - if (p == NULL) - p = LIST_FIRST(&v->plexes); - do { - if (p == NULL) { - p = lp; - break; - } - if ((p->state > GV_PLEX_DEGRADED) || - (p->state >= GV_PLEX_DEGRADED && - p->org == GV_PLEX_RAID5)) - break; - p = LIST_NEXT(p, in_volume); - if (p == NULL) - p = LIST_FIRST(&v->plexes); - } while (p != lp); - - if ((p == NULL) || - (p->org == GV_PLEX_RAID5 && p->state < GV_PLEX_DEGRADED) || - (p->org != GV_PLEX_RAID5 && p->state <= GV_PLEX_DEGRADED)) { - g_io_deliver(bp, ENXIO); - return; - } - v->last_read_plex = p; - - /* Hand it down to the plex logic. */ - gv_plex_start(p, bp); - break; - - case BIO_WRITE: - case BIO_DELETE: - /* Delay write-requests if any plex is synchronizing. */ - LIST_FOREACH(p, &v->plexes, in_volume) { - if (p->flags & GV_PLEX_SYNCING) { - bioq_insert_tail(v->wqueue, bp); - return; - } - } - - numwrites = 0; - /* Give the BIO to each plex of this volume. */ - LIST_FOREACH(p, &v->plexes, in_volume) { - if (p->state < GV_PLEX_DEGRADED) - continue; - gv_plex_start(p, bp); - numwrites++; - } - if (numwrites == 0) - g_io_deliver(bp, ENXIO); - break; - } -} - -void -gv_bio_done(struct gv_softc *sc, struct bio *bp) -{ - struct gv_volume *v __diagused; - struct gv_plex *p; - struct gv_sd *s; - - s = bp->bio_caller1; - KASSERT(s != NULL, ("gv_bio_done: NULL s")); - p = s->plex_sc; - KASSERT(p != NULL, ("gv_bio_done: NULL p")); - v = p->vol_sc; - KASSERT(v != NULL, ("gv_bio_done: NULL v")); - - switch (p->org) { - case GV_PLEX_CONCAT: - case GV_PLEX_STRIPED: - gv_plex_normal_done(p, bp); - break; - case GV_PLEX_RAID5: - gv_plex_raid5_done(p, bp); - break; - } - - gv_drive_done(s->drive_sc); -} diff --git a/sys/modules/geom/Makefile b/sys/modules/geom/Makefile --- a/sys/modules/geom/Makefile +++ b/sys/modules/geom/Makefile @@ -20,7 +20,6 @@ geom_stripe \ geom_union \ geom_uzip \ - geom_vinum \ geom_virstor \ geom_zero diff --git a/sys/modules/geom/geom_vinum/Makefile b/sys/modules/geom/geom_vinum/Makefile deleted file mode 100644 --- a/sys/modules/geom/geom_vinum/Makefile +++ /dev/null @@ -1,10 +0,0 @@ -.PATH: ${SRCTOP}/sys/geom/vinum - -KMOD= geom_vinum -SRCS= geom_vinum.c geom_vinum_create.c geom_vinum_drive.c geom_vinum_plex.c \ - geom_vinum_volume.c geom_vinum_subr.c geom_vinum_raid5.c \ - geom_vinum_share.c geom_vinum_list.c geom_vinum_rm.c \ - geom_vinum_init.c geom_vinum_state.c geom_vinum_rename.c \ - geom_vinum_move.c geom_vinum_events.c - -.include <bsd.kmod.mk>