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>