1139778Simp/*-
2190507Slulf *  Copyright (c) 2004, 2007 Lukas Ertl
3190507Slulf *  Copyright (c) 2007, 2009 Ulf Lilleengen
4130389Sle *  All rights reserved.
5130389Sle *
6130389Sle * Redistribution and use in source and binary forms, with or without
7130389Sle * modification, are permitted provided that the following conditions
8130389Sle * are met:
9130389Sle * 1. Redistributions of source code must retain the above copyright
10130389Sle *    notice, this list of conditions and the following disclaimer.
11130389Sle * 2. Redistributions in binary form must reproduce the above copyright
12130389Sle *    notice, this list of conditions and the following disclaimer in the
13130389Sle *    documentation and/or other materials provided with the distribution.
14130389Sle *
15130389Sle * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16130389Sle * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17130389Sle * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18130389Sle * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
19130389Sle * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20130389Sle * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21130389Sle * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22130389Sle * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23130389Sle * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24130389Sle * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25130389Sle * SUCH DAMAGE.
26130389Sle *
27130389Sle */
28130389Sle
29130389Sle#include <sys/cdefs.h>
30130389Sle__FBSDID("$FreeBSD$");
31130389Sle
32130389Sle#include <sys/param.h>
33130389Sle#include <sys/bio.h>
34130389Sle#include <sys/kernel.h>
35190507Slulf#include <sys/kthread.h>
36130389Sle#include <sys/lock.h>
37130389Sle#include <sys/malloc.h>
38130389Sle#include <sys/module.h>
39130389Sle#include <sys/mutex.h>
40223921Sae#include <sys/sbuf.h>
41184292Slulf#include <sys/sysctl.h>
42130389Sle#include <sys/systm.h>
43130389Sle
44130389Sle#include <geom/geom.h>
45130389Sle#include <geom/vinum/geom_vinum_var.h>
46130389Sle#include <geom/vinum/geom_vinum.h>
47190507Slulf#include <geom/vinum/geom_vinum_raid5.h>
48130389Sle
49130389SleSYSCTL_DECL(_kern_geom);
50227309Sedstatic SYSCTL_NODE(_kern_geom, OID_AUTO, vinum, CTLFLAG_RW, 0,
51227309Sed    "GEOM_VINUM stuff");
52184292Slulfu_int g_vinum_debug = 0;
53184292SlulfTUNABLE_INT("kern.geom.vinum.debug", &g_vinum_debug);
54184292SlulfSYSCTL_UINT(_kern_geom_vinum, OID_AUTO, debug, CTLFLAG_RW, &g_vinum_debug, 0,
55130389Sle    "Debug level");
56130389Sle
57190507Slulfstatic int	gv_create(struct g_geom *, struct gctl_req *);
58190507Slulfstatic void	gv_attach(struct gv_softc *, struct gctl_req *);
59190507Slulfstatic void	gv_detach(struct gv_softc *, struct gctl_req *);
60190507Slulfstatic void	gv_parityop(struct gv_softc *, struct gctl_req *);
61130389Sle
62190507Slulf
63130389Slestatic void
64130389Slegv_orphan(struct g_consumer *cp)
65130389Sle{
66130389Sle	struct g_geom *gp;
67130389Sle	struct gv_softc *sc;
68190507Slulf	struct gv_drive *d;
69130389Sle
70130389Sle	g_topology_assert();
71130389Sle
72130389Sle	KASSERT(cp != NULL, ("gv_orphan: null cp"));
73130389Sle	gp = cp->geom;
74130389Sle	KASSERT(gp != NULL, ("gv_orphan: null gp"));
75130389Sle	sc = gp->softc;
76190507Slulf	KASSERT(sc != NULL, ("gv_orphan: null sc"));
77190507Slulf	d = cp->private;
78190507Slulf	KASSERT(d != NULL, ("gv_orphan: null d"));
79130389Sle
80130389Sle	g_trace(G_T_TOPOLOGY, "gv_orphan(%s)", gp->name);
81130389Sle
82190507Slulf	gv_post_event(sc, GV_EVENT_DRIVE_LOST, d, NULL, 0, 0);
83130389Sle}
84130389Sle
85190507Slulfvoid
86130389Slegv_start(struct bio *bp)
87130389Sle{
88130389Sle	struct g_geom *gp;
89190507Slulf	struct gv_softc *sc;
90130389Sle
91130389Sle	gp = bp->bio_to->geom;
92190507Slulf	sc = gp->softc;
93190507Slulf
94190507Slulf	switch (bp->bio_cmd) {
95130389Sle	case BIO_READ:
96130389Sle	case BIO_WRITE:
97130389Sle	case BIO_DELETE:
98190507Slulf		break;
99190507Slulf	case BIO_GETATTR:
100130389Sle	default:
101130389Sle		g_io_deliver(bp, EOPNOTSUPP);
102130389Sle		return;
103130389Sle	}
104191856Slulf	mtx_lock(&sc->bqueue_mtx);
105191856Slulf	bioq_disksort(sc->bqueue_down, bp);
106191856Slulf	wakeup(sc);
107191856Slulf	mtx_unlock(&sc->bqueue_mtx);
108130389Sle}
109130389Sle
110190507Slulfvoid
111190507Slulfgv_done(struct bio *bp)
112190507Slulf{
113190507Slulf	struct g_geom *gp;
114190507Slulf	struct gv_softc *sc;
115190507Slulf
116190507Slulf	KASSERT(bp != NULL, ("NULL bp"));
117190507Slulf
118190507Slulf	gp = bp->bio_from->geom;
119190507Slulf	sc = gp->softc;
120190507Slulf
121191856Slulf	mtx_lock(&sc->bqueue_mtx);
122191856Slulf	bioq_disksort(sc->bqueue_up, bp);
123191856Slulf	wakeup(sc);
124191856Slulf	mtx_unlock(&sc->bqueue_mtx);
125190507Slulf}
126190507Slulf
127190507Slulfint
128130389Slegv_access(struct g_provider *pp, int dr, int dw, int de)
129130389Sle{
130130389Sle	struct g_geom *gp;
131190507Slulf	struct gv_softc *sc;
132190507Slulf	struct gv_drive *d, *d2;
133130389Sle	int error;
134130389Sle
135130389Sle	gp = pp->geom;
136190507Slulf	sc = gp->softc;
137195752Slulf	/*
138195752Slulf	 * We want to modify the read count with the write count in case we have
139195752Slulf	 * plexes in a RAID-5 organization.
140195752Slulf	 */
141195752Slulf	dr += dw;
142195752Slulf
143190507Slulf	LIST_FOREACH(d, &sc->drives, drive) {
144190507Slulf		if (d->consumer == NULL)
145190507Slulf			continue;
146190507Slulf		error = g_access(d->consumer, dr, dw, de);
147190507Slulf		if (error) {
148190507Slulf			LIST_FOREACH(d2, &sc->drives, drive) {
149190507Slulf				if (d == d2)
150190507Slulf					break;
151190507Slulf				g_access(d2->consumer, -dr, -dw, -de);
152190507Slulf			}
153190507Slulf			G_VINUM_DEBUG(0, "g_access '%s' failed: %d", d->name,
154190507Slulf			    error);
155190507Slulf			return (error);
156190507Slulf		}
157190507Slulf	}
158190507Slulf	return (0);
159130389Sle}
160130389Sle
161152773Slestatic void
162152773Slegv_init(struct g_class *mp)
163130389Sle{
164130389Sle	struct g_geom *gp;
165130389Sle	struct gv_softc *sc;
166130389Sle
167152773Sle	g_trace(G_T_TOPOLOGY, "gv_init(%p)", mp);
168130389Sle
169152773Sle	gp = g_new_geomf(mp, "VINUM");
170152773Sle	gp->spoiled = gv_orphan;
171152773Sle	gp->orphan = gv_orphan;
172152773Sle	gp->access = gv_access;
173152773Sle	gp->start = gv_start;
174152773Sle	gp->softc = g_malloc(sizeof(struct gv_softc), M_WAITOK | M_ZERO);
175152773Sle	sc = gp->softc;
176152773Sle	sc->geom = gp;
177191856Slulf	sc->bqueue_down = g_malloc(sizeof(struct bio_queue_head),
178191856Slulf	    M_WAITOK | M_ZERO);
179191856Slulf	sc->bqueue_up = g_malloc(sizeof(struct bio_queue_head),
180191856Slulf	    M_WAITOK | M_ZERO);
181191856Slulf	bioq_init(sc->bqueue_down);
182191856Slulf	bioq_init(sc->bqueue_up);
183152773Sle	LIST_INIT(&sc->drives);
184152773Sle	LIST_INIT(&sc->subdisks);
185152773Sle	LIST_INIT(&sc->plexes);
186152773Sle	LIST_INIT(&sc->volumes);
187190507Slulf	TAILQ_INIT(&sc->equeue);
188190507Slulf	mtx_init(&sc->config_mtx, "gv_config", NULL, MTX_DEF);
189191849Slulf	mtx_init(&sc->equeue_mtx, "gv_equeue", NULL, MTX_DEF);
190191849Slulf	mtx_init(&sc->bqueue_mtx, "gv_bqueue", NULL, MTX_DEF);
191207878Sjh	kproc_create(gv_worker, sc, &sc->worker, 0, 0, "gv_worker");
192130389Sle}
193130389Sle
194190507Slulfstatic int
195190507Slulfgv_unload(struct gctl_req *req, struct g_class *mp, struct g_geom *gp)
196190507Slulf{
197190507Slulf	struct gv_softc *sc;
198190507Slulf
199190507Slulf	g_trace(G_T_TOPOLOGY, "gv_unload(%p)", mp);
200190507Slulf
201190507Slulf	g_topology_assert();
202190507Slulf	sc = gp->softc;
203190507Slulf
204190507Slulf	if (sc != NULL) {
205207878Sjh		gv_worker_exit(sc);
206190507Slulf		gp->softc = NULL;
207190507Slulf		g_wither_geom(gp, ENXIO);
208190507Slulf	}
209190507Slulf
210190507Slulf	return (0);
211190507Slulf}
212190507Slulf
213190507Slulf/* Handle userland request of attaching object. */
214190507Slulfstatic void
215190507Slulfgv_attach(struct gv_softc *sc, struct gctl_req *req)
216190507Slulf{
217190507Slulf	struct gv_volume *v;
218190507Slulf	struct gv_plex *p;
219190507Slulf	struct gv_sd *s;
220190507Slulf	off_t *offset;
221190507Slulf	int *rename, type_child, type_parent;
222190507Slulf	char *child, *parent;
223190507Slulf
224190507Slulf	child = gctl_get_param(req, "child", NULL);
225190507Slulf	if (child == NULL) {
226190507Slulf		gctl_error(req, "no child given");
227190507Slulf		return;
228190507Slulf	}
229190507Slulf	parent = gctl_get_param(req, "parent", NULL);
230190507Slulf	if (parent == NULL) {
231190507Slulf		gctl_error(req, "no parent given");
232190507Slulf		return;
233190507Slulf	}
234190507Slulf	offset = gctl_get_paraml(req, "offset", sizeof(*offset));
235190507Slulf	if (offset == NULL) {
236190507Slulf		gctl_error(req, "no offset given");
237190507Slulf		return;
238190507Slulf	}
239190507Slulf	rename = gctl_get_paraml(req, "rename", sizeof(*rename));
240190507Slulf	if (rename == NULL) {
241190507Slulf		gctl_error(req, "no rename flag given");
242190507Slulf		return;
243190507Slulf	}
244190507Slulf
245190507Slulf	type_child = gv_object_type(sc, child);
246190507Slulf	type_parent = gv_object_type(sc, parent);
247190507Slulf
248190507Slulf	switch (type_child) {
249190507Slulf	case GV_TYPE_PLEX:
250190507Slulf		if (type_parent != GV_TYPE_VOL) {
251190507Slulf			gctl_error(req, "no such volume to attach to");
252190507Slulf			return;
253190507Slulf		}
254190507Slulf		v = gv_find_vol(sc, parent);
255190507Slulf		p = gv_find_plex(sc, child);
256190507Slulf		gv_post_event(sc, GV_EVENT_ATTACH_PLEX, p, v, *offset, *rename);
257190507Slulf		break;
258190507Slulf	case GV_TYPE_SD:
259190507Slulf		if (type_parent != GV_TYPE_PLEX) {
260190507Slulf			gctl_error(req, "no such plex to attach to");
261190507Slulf			return;
262190507Slulf		}
263190507Slulf		p = gv_find_plex(sc, parent);
264190507Slulf		s = gv_find_sd(sc, child);
265190507Slulf		gv_post_event(sc, GV_EVENT_ATTACH_SD, s, p, *offset, *rename);
266190507Slulf		break;
267190507Slulf	default:
268190507Slulf		gctl_error(req, "invalid child type");
269190507Slulf		break;
270190507Slulf	}
271190507Slulf}
272190507Slulf
273190507Slulf/* Handle userland request of detaching object. */
274190507Slulfstatic void
275190507Slulfgv_detach(struct gv_softc *sc, struct gctl_req *req)
276190507Slulf{
277190507Slulf	struct gv_plex *p;
278190507Slulf	struct gv_sd *s;
279190507Slulf	int *flags, type;
280190507Slulf	char *object;
281190507Slulf
282190507Slulf	object = gctl_get_param(req, "object", NULL);
283190507Slulf	if (object == NULL) {
284190507Slulf		gctl_error(req, "no argument given");
285190507Slulf		return;
286190507Slulf	}
287190507Slulf
288190507Slulf	flags = gctl_get_paraml(req, "flags", sizeof(*flags));
289190507Slulf	type = gv_object_type(sc, object);
290190507Slulf	switch (type) {
291190507Slulf	case GV_TYPE_PLEX:
292190507Slulf		p = gv_find_plex(sc, object);
293190507Slulf		gv_post_event(sc, GV_EVENT_DETACH_PLEX, p, NULL, *flags, 0);
294190507Slulf		break;
295190507Slulf	case GV_TYPE_SD:
296190507Slulf		s = gv_find_sd(sc, object);
297190507Slulf		gv_post_event(sc, GV_EVENT_DETACH_SD, s, NULL, *flags, 0);
298190507Slulf		break;
299190507Slulf	default:
300190507Slulf		gctl_error(req, "invalid object type");
301190507Slulf		break;
302190507Slulf	}
303190507Slulf}
304190507Slulf
305130389Sle/* Handle userland requests for creating new objects. */
306190507Slulfstatic int
307130389Slegv_create(struct g_geom *gp, struct gctl_req *req)
308130389Sle{
309130389Sle	struct gv_softc *sc;
310130389Sle	struct gv_drive *d, *d2;
311130389Sle	struct gv_plex *p, *p2;
312130389Sle	struct gv_sd *s, *s2;
313130389Sle	struct gv_volume *v, *v2;
314130389Sle	struct g_provider *pp;
315190507Slulf	int error, i, *drives, *flags, *plexes, *subdisks, *volumes;
316190507Slulf	char buf[20];
317130389Sle
318130389Sle	g_topology_assert();
319130389Sle
320130389Sle	sc = gp->softc;
321130389Sle
322130389Sle	/* Find out how many of each object have been passed in. */
323130389Sle	volumes = gctl_get_paraml(req, "volumes", sizeof(*volumes));
324130389Sle	plexes = gctl_get_paraml(req, "plexes", sizeof(*plexes));
325130389Sle	subdisks = gctl_get_paraml(req, "subdisks", sizeof(*subdisks));
326130389Sle	drives = gctl_get_paraml(req, "drives", sizeof(*drives));
327185309Slulf	if (volumes == NULL || plexes == NULL || subdisks == NULL ||
328185309Slulf	    drives == NULL) {
329185309Slulf		gctl_error(req, "number of objects not given");
330185309Slulf		return (-1);
331185309Slulf	}
332190507Slulf	flags = gctl_get_paraml(req, "flags", sizeof(*flags));
333190507Slulf	if (flags == NULL) {
334190507Slulf		gctl_error(req, "flags not given");
335190507Slulf		return (-1);
336190507Slulf	}
337130389Sle
338130389Sle	/* First, handle drive definitions ... */
339130389Sle	for (i = 0; i < *drives; i++) {
340130389Sle		snprintf(buf, sizeof(buf), "drive%d", i);
341130389Sle		d2 = gctl_get_paraml(req, buf, sizeof(*d2));
342185309Slulf		if (d2 == NULL) {
343185309Slulf			gctl_error(req, "no drive definition given");
344185309Slulf			return (-1);
345185309Slulf		}
346131015Scsjp		/*
347190507Slulf		 * Make sure that the device specified in the drive config is
348190507Slulf		 * an active GEOM provider.
349131015Scsjp		 */
350190507Slulf		pp = g_provider_by_name(d2->device);
351131015Scsjp		if (pp == NULL) {
352190507Slulf			gctl_error(req, "%s: device not found", d2->device);
353190507Slulf			goto error;
354131015Scsjp		}
355190507Slulf		if (gv_find_drive(sc, d2->name) != NULL) {
356190507Slulf			/* Ignore error. */
357190507Slulf			if (*flags & GV_FLAG_F)
358190507Slulf				continue;
359190507Slulf			gctl_error(req, "drive '%s' already exists", d2->name);
360190507Slulf			goto error;
361190507Slulf		}
362190507Slulf		if (gv_find_drive_device(sc, d2->device) != NULL) {
363190507Slulf			gctl_error(req, "device '%s' already configured in "
364190507Slulf			    "gvinum", d2->device);
365190507Slulf			goto error;
366190507Slulf		}
367130389Sle
368130389Sle
369190507Slulf		d = g_malloc(sizeof(*d), M_WAITOK | M_ZERO);
370190507Slulf		bcopy(d2, d, sizeof(*d));
371190507Slulf
372190507Slulf		gv_post_event(sc, GV_EVENT_CREATE_DRIVE, d, NULL, 0, 0);
373130389Sle	}
374130389Sle
375130389Sle	/* ... then volume definitions ... */
376130389Sle	for (i = 0; i < *volumes; i++) {
377130389Sle		error = 0;
378130389Sle		snprintf(buf, sizeof(buf), "volume%d", i);
379130389Sle		v2 = gctl_get_paraml(req, buf, sizeof(*v2));
380185309Slulf		if (v2 == NULL) {
381185309Slulf			gctl_error(req, "no volume definition given");
382185309Slulf			return (-1);
383185309Slulf		}
384190507Slulf		if (gv_find_vol(sc, v2->name) != NULL) {
385190507Slulf			/* Ignore error. */
386190507Slulf			if (*flags & GV_FLAG_F)
387190507Slulf				continue;
388190507Slulf			gctl_error(req, "volume '%s' already exists", v2->name);
389190507Slulf			goto error;
390130389Sle		}
391130389Sle
392130389Sle		v = g_malloc(sizeof(*v), M_WAITOK | M_ZERO);
393130389Sle		bcopy(v2, v, sizeof(*v));
394130389Sle
395190507Slulf		gv_post_event(sc, GV_EVENT_CREATE_VOLUME, v, NULL, 0, 0);
396130389Sle	}
397130389Sle
398130389Sle	/* ... then plex definitions ... */
399130389Sle	for (i = 0; i < *plexes; i++) {
400130389Sle		error = 0;
401130389Sle		snprintf(buf, sizeof(buf), "plex%d", i);
402130389Sle		p2 = gctl_get_paraml(req, buf, sizeof(*p2));
403185309Slulf		if (p2 == NULL) {
404185309Slulf			gctl_error(req, "no plex definition given");
405185309Slulf			return (-1);
406185309Slulf		}
407190507Slulf		if (gv_find_plex(sc, p2->name) != NULL) {
408190507Slulf			/* Ignore error. */
409190507Slulf			if (*flags & GV_FLAG_F)
410190507Slulf				continue;
411190507Slulf			gctl_error(req, "plex '%s' already exists", p2->name);
412190507Slulf			goto error;
413130389Sle		}
414130389Sle
415130389Sle		p = g_malloc(sizeof(*p), M_WAITOK | M_ZERO);
416130389Sle		bcopy(p2, p, sizeof(*p));
417130389Sle
418190507Slulf		gv_post_event(sc, GV_EVENT_CREATE_PLEX, p, NULL, 0, 0);
419130389Sle	}
420130389Sle
421190507Slulf	/* ... and, finally, subdisk definitions. */
422130389Sle	for (i = 0; i < *subdisks; i++) {
423130389Sle		error = 0;
424130389Sle		snprintf(buf, sizeof(buf), "sd%d", i);
425130389Sle		s2 = gctl_get_paraml(req, buf, sizeof(*s2));
426185309Slulf		if (s2 == NULL) {
427185309Slulf			gctl_error(req, "no subdisk definition given");
428185309Slulf			return (-1);
429185309Slulf		}
430190507Slulf		if (gv_find_sd(sc, s2->name) != NULL) {
431190507Slulf			/* Ignore error. */
432190507Slulf			if (*flags & GV_FLAG_F)
433190507Slulf				continue;
434190507Slulf			gctl_error(req, "sd '%s' already exists", s2->name);
435190507Slulf			goto error;
436130389Sle		}
437130389Sle
438130389Sle		s = g_malloc(sizeof(*s), M_WAITOK | M_ZERO);
439130389Sle		bcopy(s2, s, sizeof(*s));
440130389Sle
441190507Slulf		gv_post_event(sc, GV_EVENT_CREATE_SD, s, NULL, 0, 0);
442130389Sle	}
443130389Sle
444190507Slulferror:
445190507Slulf	gv_post_event(sc, GV_EVENT_SETUP_OBJECTS, sc, NULL, 0, 0);
446190507Slulf	gv_post_event(sc, GV_EVENT_SAVE_CONFIG, sc, NULL, 0, 0);
447130389Sle
448130389Sle	return (0);
449130389Sle}
450130389Sle
451130389Slestatic void
452130389Slegv_config(struct gctl_req *req, struct g_class *mp, char const *verb)
453130389Sle{
454130389Sle	struct g_geom *gp;
455130389Sle	struct gv_softc *sc;
456130389Sle	struct sbuf *sb;
457130389Sle	char *comment;
458130389Sle
459130389Sle	g_topology_assert();
460130389Sle
461130389Sle	gp = LIST_FIRST(&mp->geom);
462130389Sle	sc = gp->softc;
463130389Sle
464190507Slulf	if (!strcmp(verb, "attach")) {
465190507Slulf		gv_attach(sc, req);
466190507Slulf
467190507Slulf	} else if (!strcmp(verb, "concat")) {
468190507Slulf		gv_concat(gp, req);
469190507Slulf
470190507Slulf	} else if (!strcmp(verb, "detach")) {
471190507Slulf		gv_detach(sc, req);
472190507Slulf
473190507Slulf	} else if (!strcmp(verb, "list")) {
474130389Sle		gv_list(gp, req);
475130389Sle
476130389Sle	/* Save our configuration back to disk. */
477130389Sle	} else if (!strcmp(verb, "saveconfig")) {
478190507Slulf		gv_post_event(sc, GV_EVENT_SAVE_CONFIG, sc, NULL, 0, 0);
479130389Sle
480130389Sle	/* Return configuration in string form. */
481130389Sle	} else if (!strcmp(verb, "getconfig")) {
482130389Sle		comment = gctl_get_param(req, "comment", NULL);
483185309Slulf		if (comment == NULL) {
484185309Slulf			gctl_error(req, "no comment parameter given");
485185309Slulf			return;
486185309Slulf		}
487130389Sle		sb = sbuf_new(NULL, NULL, GV_CFG_LEN, SBUF_FIXEDLEN);
488130389Sle		gv_format_config(sc, sb, 0, comment);
489130389Sle		sbuf_finish(sb);
490130389Sle		gctl_set_param(req, "config", sbuf_data(sb), sbuf_len(sb) + 1);
491130389Sle		sbuf_delete(sb);
492130389Sle
493130389Sle	} else if (!strcmp(verb, "create")) {
494130389Sle		gv_create(gp, req);
495130389Sle
496190507Slulf	} else if (!strcmp(verb, "mirror")) {
497190507Slulf		gv_mirror(gp, req);
498190507Slulf
499152615Sle	} else if (!strcmp(verb, "move")) {
500152615Sle		gv_move(gp, req);
501152615Sle
502190507Slulf	} else if (!strcmp(verb, "raid5")) {
503190507Slulf		gv_raid5(gp, req);
504138110Sle
505190507Slulf	} else if (!strcmp(verb, "rebuildparity") ||
506190507Slulf	    !strcmp(verb, "checkparity")) {
507190507Slulf		gv_parityop(sc, req);
508190507Slulf
509130389Sle	} else if (!strcmp(verb, "remove")) {
510130389Sle		gv_remove(gp, req);
511130389Sle
512152615Sle	} else if (!strcmp(verb, "rename")) {
513152615Sle		gv_rename(gp, req);
514157052Sle
515157052Sle	} else if (!strcmp(verb, "resetconfig")) {
516190507Slulf		gv_post_event(sc, GV_EVENT_RESET_CONFIG, sc, NULL, 0, 0);
517152615Sle
518130389Sle	} else if (!strcmp(verb, "start")) {
519130389Sle		gv_start_obj(gp, req);
520130389Sle
521190507Slulf	} else if (!strcmp(verb, "stripe")) {
522190507Slulf		gv_stripe(gp, req);
523190507Slulf
524138112Sle	} else if (!strcmp(verb, "setstate")) {
525138112Sle		gv_setstate(gp, req);
526130389Sle	} else
527130389Sle		gctl_error(req, "Unknown verb parameter");
528130389Sle}
529130389Sle
530190507Slulfstatic void
531190507Slulfgv_parityop(struct gv_softc *sc, struct gctl_req *req)
532130389Sle{
533190507Slulf	struct gv_plex *p;
534190507Slulf	int *flags, *rebuild, type;
535190507Slulf	char *plex;
536130389Sle
537190507Slulf	plex = gctl_get_param(req, "plex", NULL);
538190507Slulf	if (plex == NULL) {
539190507Slulf		gctl_error(req, "no plex given");
540190507Slulf		return;
541190507Slulf	}
542130389Sle
543190507Slulf	flags = gctl_get_paraml(req, "flags", sizeof(*flags));
544190507Slulf	if (flags == NULL) {
545190507Slulf		gctl_error(req, "no flags given");
546190507Slulf		return;
547190507Slulf	}
548130389Sle
549190507Slulf	rebuild = gctl_get_paraml(req, "rebuild", sizeof(*rebuild));
550190507Slulf	if (rebuild == NULL) {
551190507Slulf		gctl_error(req, "no operation given");
552190507Slulf		return;
553190507Slulf	}
554130389Sle
555190507Slulf	type = gv_object_type(sc, plex);
556190507Slulf	if (type != GV_TYPE_PLEX) {
557190507Slulf		gctl_error(req, "'%s' is not a plex", plex);
558190507Slulf		return;
559130389Sle	}
560190507Slulf	p = gv_find_plex(sc, plex);
561130389Sle
562190507Slulf	if (p->state != GV_PLEX_UP) {
563190507Slulf		gctl_error(req, "plex %s is not completely accessible",
564190507Slulf		    p->name);
565190507Slulf		return;
566130389Sle	}
567130389Sle
568190507Slulf	if (p->org != GV_PLEX_RAID5) {
569190507Slulf		gctl_error(req, "plex %s is not a RAID5 plex", p->name);
570190507Slulf		return;
571130697Sle	}
572130697Sle
573190507Slulf	/* Put it in the event queue. */
574190507Slulf	/* XXX: The state of the plex might have changed when this event is
575190507Slulf	 * picked up ... We should perhaps check this afterwards. */
576190507Slulf	if (*rebuild)
577190507Slulf		gv_post_event(sc, GV_EVENT_PARITY_REBUILD, p, NULL, 0, 0);
578190507Slulf	else
579190507Slulf		gv_post_event(sc, GV_EVENT_PARITY_CHECK, p, NULL, 0, 0);
580190507Slulf}
581190507Slulf
582190507Slulf
583190507Slulfstatic struct g_geom *
584190507Slulfgv_taste(struct g_class *mp, struct g_provider *pp, int flags __unused)
585190507Slulf{
586190507Slulf	struct g_geom *gp;
587190507Slulf	struct g_consumer *cp;
588190507Slulf	struct gv_softc *sc;
589190507Slulf	struct gv_hdr vhdr;
590190507Slulf	int error;
591190507Slulf
592190507Slulf 	g_topology_assert();
593190507Slulf	g_trace(G_T_TOPOLOGY, "gv_taste(%s, %s)", mp->name, pp->name);
594190507Slulf
595190507Slulf	gp = LIST_FIRST(&mp->geom);
596190507Slulf	if (gp == NULL) {
597190507Slulf		G_VINUM_DEBUG(0, "error: tasting, but not initialized?");
598190507Slulf		return (NULL);
599130697Sle	}
600190507Slulf	sc = gp->softc;
601130697Sle
602190507Slulf	cp = g_new_consumer(gp);
603190507Slulf	if (g_attach(cp, pp) != 0) {
604190507Slulf		g_destroy_consumer(cp);
605190507Slulf		return (NULL);
606130697Sle	}
607190507Slulf	if (g_access(cp, 1, 0, 0) != 0) {
608190507Slulf		g_detach(cp);
609190507Slulf		g_destroy_consumer(cp);
610190507Slulf		return (NULL);
611190507Slulf	}
612190507Slulf	g_topology_unlock();
613130697Sle
614190507Slulf	error = gv_read_header(cp, &vhdr);
615190507Slulf
616190507Slulf	g_topology_lock();
617190507Slulf	g_access(cp, -1, 0, 0);
618190507Slulf	g_detach(cp);
619190507Slulf	g_destroy_consumer(cp);
620190507Slulf
621190507Slulf	/* Check if what we've been given is a valid vinum drive. */
622190507Slulf	if (!error)
623190507Slulf		gv_post_event(sc, GV_EVENT_DRIVE_TASTED, pp, NULL, 0, 0);
624190507Slulf
625190507Slulf	return (NULL);
626130389Sle}
627130389Sle
628190507Slulfvoid
629190507Slulfgv_worker(void *arg)
630190507Slulf{
631190507Slulf	struct g_provider *pp;
632190507Slulf	struct gv_softc *sc;
633190507Slulf	struct gv_event *ev;
634190507Slulf	struct gv_volume *v;
635190507Slulf	struct gv_plex *p;
636190507Slulf	struct gv_sd *s;
637190507Slulf	struct gv_drive *d;
638190507Slulf	struct bio *bp;
639190507Slulf	int newstate, flags, err, rename;
640190507Slulf	char *newname;
641190507Slulf	off_t offset;
642190507Slulf
643190507Slulf	sc = arg;
644190507Slulf	KASSERT(sc != NULL, ("NULL sc"));
645190507Slulf	for (;;) {
646190507Slulf		/* Look at the events first... */
647191849Slulf		ev = gv_get_event(sc);
648190507Slulf		if (ev != NULL) {
649191849Slulf			gv_remove_event(sc, ev);
650190507Slulf
651190507Slulf			switch (ev->type) {
652190507Slulf			case GV_EVENT_DRIVE_TASTED:
653190507Slulf				G_VINUM_DEBUG(2, "event 'drive tasted'");
654190507Slulf				pp = ev->arg1;
655190507Slulf				gv_drive_tasted(sc, pp);
656190507Slulf				break;
657190507Slulf
658190507Slulf			case GV_EVENT_DRIVE_LOST:
659190507Slulf				G_VINUM_DEBUG(2, "event 'drive lost'");
660190507Slulf				d = ev->arg1;
661190507Slulf				gv_drive_lost(sc, d);
662190507Slulf				break;
663190507Slulf
664190507Slulf			case GV_EVENT_CREATE_DRIVE:
665190507Slulf				G_VINUM_DEBUG(2, "event 'create drive'");
666190507Slulf				d = ev->arg1;
667190507Slulf				gv_create_drive(sc, d);
668190507Slulf				break;
669190507Slulf
670190507Slulf			case GV_EVENT_CREATE_VOLUME:
671190507Slulf				G_VINUM_DEBUG(2, "event 'create volume'");
672190507Slulf				v = ev->arg1;
673190507Slulf				gv_create_volume(sc, v);
674190507Slulf				break;
675190507Slulf
676190507Slulf			case GV_EVENT_CREATE_PLEX:
677190507Slulf				G_VINUM_DEBUG(2, "event 'create plex'");
678190507Slulf				p = ev->arg1;
679190507Slulf				gv_create_plex(sc, p);
680190507Slulf				break;
681190507Slulf
682190507Slulf			case GV_EVENT_CREATE_SD:
683190507Slulf				G_VINUM_DEBUG(2, "event 'create sd'");
684190507Slulf				s = ev->arg1;
685190507Slulf				gv_create_sd(sc, s);
686190507Slulf				break;
687190507Slulf
688190507Slulf			case GV_EVENT_RM_DRIVE:
689190507Slulf				G_VINUM_DEBUG(2, "event 'remove drive'");
690190507Slulf				d = ev->arg1;
691190507Slulf				flags = ev->arg3;
692190507Slulf				gv_rm_drive(sc, d, flags);
693190507Slulf				/*gv_setup_objects(sc);*/
694190507Slulf				break;
695190507Slulf
696190507Slulf			case GV_EVENT_RM_VOLUME:
697190507Slulf				G_VINUM_DEBUG(2, "event 'remove volume'");
698190507Slulf				v = ev->arg1;
699190507Slulf				gv_rm_vol(sc, v);
700190507Slulf				/*gv_setup_objects(sc);*/
701190507Slulf				break;
702190507Slulf
703190507Slulf			case GV_EVENT_RM_PLEX:
704190507Slulf				G_VINUM_DEBUG(2, "event 'remove plex'");
705190507Slulf				p = ev->arg1;
706190507Slulf				gv_rm_plex(sc, p);
707190507Slulf				/*gv_setup_objects(sc);*/
708190507Slulf				break;
709190507Slulf
710190507Slulf			case GV_EVENT_RM_SD:
711190507Slulf				G_VINUM_DEBUG(2, "event 'remove sd'");
712190507Slulf				s = ev->arg1;
713190507Slulf				gv_rm_sd(sc, s);
714190507Slulf				/*gv_setup_objects(sc);*/
715190507Slulf				break;
716190507Slulf
717190507Slulf			case GV_EVENT_SAVE_CONFIG:
718190507Slulf				G_VINUM_DEBUG(2, "event 'save config'");
719190507Slulf				gv_save_config(sc);
720190507Slulf				break;
721190507Slulf
722190507Slulf			case GV_EVENT_SET_SD_STATE:
723190507Slulf				G_VINUM_DEBUG(2, "event 'setstate sd'");
724190507Slulf				s = ev->arg1;
725190507Slulf				newstate = ev->arg3;
726190507Slulf				flags = ev->arg4;
727190507Slulf				err = gv_set_sd_state(s, newstate, flags);
728190507Slulf				if (err)
729190507Slulf					G_VINUM_DEBUG(0, "error setting subdisk"
730190507Slulf					    " state: error code %d", err);
731190507Slulf				break;
732190507Slulf
733190507Slulf			case GV_EVENT_SET_DRIVE_STATE:
734190507Slulf				G_VINUM_DEBUG(2, "event 'setstate drive'");
735190507Slulf				d = ev->arg1;
736190507Slulf				newstate = ev->arg3;
737190507Slulf				flags = ev->arg4;
738190507Slulf				err = gv_set_drive_state(d, newstate, flags);
739190507Slulf				if (err)
740190507Slulf					G_VINUM_DEBUG(0, "error setting drive "
741190507Slulf					    "state: error code %d", err);
742190507Slulf				break;
743190507Slulf
744190507Slulf			case GV_EVENT_SET_VOL_STATE:
745190507Slulf				G_VINUM_DEBUG(2, "event 'setstate volume'");
746190507Slulf				v = ev->arg1;
747190507Slulf				newstate = ev->arg3;
748190507Slulf				flags = ev->arg4;
749190507Slulf				err = gv_set_vol_state(v, newstate, flags);
750190507Slulf				if (err)
751190507Slulf					G_VINUM_DEBUG(0, "error setting volume "
752190507Slulf					    "state: error code %d", err);
753190507Slulf				break;
754190507Slulf
755190507Slulf			case GV_EVENT_SET_PLEX_STATE:
756190507Slulf				G_VINUM_DEBUG(2, "event 'setstate plex'");
757190507Slulf				p = ev->arg1;
758190507Slulf				newstate = ev->arg3;
759190507Slulf				flags = ev->arg4;
760190507Slulf				err = gv_set_plex_state(p, newstate, flags);
761190507Slulf				if (err)
762190507Slulf					G_VINUM_DEBUG(0, "error setting plex "
763190507Slulf					    "state: error code %d", err);
764190507Slulf				break;
765190507Slulf
766190507Slulf			case GV_EVENT_SETUP_OBJECTS:
767190507Slulf				G_VINUM_DEBUG(2, "event 'setup objects'");
768190507Slulf				gv_setup_objects(sc);
769190507Slulf				break;
770190507Slulf
771190507Slulf			case GV_EVENT_RESET_CONFIG:
772190507Slulf				G_VINUM_DEBUG(2, "event 'resetconfig'");
773190507Slulf				err = gv_resetconfig(sc);
774190507Slulf				if (err)
775190507Slulf					G_VINUM_DEBUG(0, "error resetting "
776190507Slulf					    "config: error code %d", err);
777190507Slulf				break;
778190507Slulf
779190507Slulf			case GV_EVENT_PARITY_REBUILD:
780190507Slulf				/*
781190507Slulf				 * Start the rebuild. The gv_plex_done will
782190507Slulf				 * handle issuing of the remaining rebuild bio's
783190507Slulf				 * until it's finished.
784190507Slulf				 */
785190507Slulf				G_VINUM_DEBUG(2, "event 'rebuild'");
786190507Slulf				p = ev->arg1;
787190507Slulf				if (p->state != GV_PLEX_UP) {
788190507Slulf					G_VINUM_DEBUG(0, "plex %s is not "
789190507Slulf					    "completely accessible", p->name);
790190507Slulf					break;
791190507Slulf				}
792204886Slulf				if (p->flags & GV_PLEX_SYNCING ||
793204886Slulf				    p->flags & GV_PLEX_REBUILDING ||
794204886Slulf				    p->flags & GV_PLEX_GROWING) {
795204886Slulf					G_VINUM_DEBUG(0, "plex %s is busy with "
796204886Slulf					    "syncing or parity build", p->name);
797204886Slulf					break;
798204886Slulf				}
799190507Slulf				p->synced = 0;
800204886Slulf				p->flags |= GV_PLEX_REBUILDING;
801190507Slulf				g_topology_assert_not();
802190507Slulf				g_topology_lock();
803190507Slulf				err = gv_access(p->vol_sc->provider, 1, 1, 0);
804190507Slulf				if (err) {
805190507Slulf					G_VINUM_DEBUG(0, "unable to access "
806190507Slulf					    "provider");
807190507Slulf					break;
808190507Slulf				}
809190507Slulf				g_topology_unlock();
810190507Slulf				gv_parity_request(p, GV_BIO_CHECK |
811190507Slulf				    GV_BIO_PARITY, 0);
812190507Slulf				break;
813190507Slulf
814190507Slulf			case GV_EVENT_PARITY_CHECK:
815190507Slulf				/* Start parity check. */
816190507Slulf				G_VINUM_DEBUG(2, "event 'check'");
817190507Slulf				p = ev->arg1;
818190507Slulf				if (p->state != GV_PLEX_UP) {
819190507Slulf					G_VINUM_DEBUG(0, "plex %s is not "
820190507Slulf					    "completely accessible", p->name);
821190507Slulf					break;
822190507Slulf				}
823204886Slulf				if (p->flags & GV_PLEX_SYNCING ||
824204886Slulf				    p->flags & GV_PLEX_REBUILDING ||
825204886Slulf				    p->flags & GV_PLEX_GROWING) {
826204886Slulf					G_VINUM_DEBUG(0, "plex %s is busy with "
827204886Slulf					    "syncing or parity build", p->name);
828204886Slulf					break;
829204886Slulf				}
830190507Slulf				p->synced = 0;
831190507Slulf				g_topology_assert_not();
832190507Slulf				g_topology_lock();
833190507Slulf				err = gv_access(p->vol_sc->provider, 1, 1, 0);
834190507Slulf				if (err) {
835190507Slulf					G_VINUM_DEBUG(0, "unable to access "
836190507Slulf					    "provider");
837190507Slulf					break;
838190507Slulf				}
839190507Slulf				g_topology_unlock();
840190507Slulf				gv_parity_request(p, GV_BIO_CHECK, 0);
841190507Slulf				break;
842190507Slulf
843190507Slulf			case GV_EVENT_START_PLEX:
844190507Slulf				G_VINUM_DEBUG(2, "event 'start' plex");
845190507Slulf				p = ev->arg1;
846190507Slulf				gv_start_plex(p);
847190507Slulf				break;
848190507Slulf
849190507Slulf			case GV_EVENT_START_VOLUME:
850190507Slulf				G_VINUM_DEBUG(2, "event 'start' volume");
851190507Slulf				v = ev->arg1;
852190507Slulf				gv_start_vol(v);
853190507Slulf				break;
854190507Slulf
855190507Slulf			case GV_EVENT_ATTACH_PLEX:
856190507Slulf				G_VINUM_DEBUG(2, "event 'attach' plex");
857190507Slulf				p = ev->arg1;
858190507Slulf				v = ev->arg2;
859190507Slulf				rename = ev->arg4;
860190507Slulf				err = gv_attach_plex(p, v, rename);
861190507Slulf				if (err)
862190507Slulf					G_VINUM_DEBUG(0, "error attaching %s to"
863190507Slulf					    " %s: error code %d", p->name,
864190507Slulf					    v->name, err);
865190507Slulf				break;
866190507Slulf
867190507Slulf			case GV_EVENT_ATTACH_SD:
868190507Slulf				G_VINUM_DEBUG(2, "event 'attach' sd");
869190507Slulf				s = ev->arg1;
870190507Slulf				p = ev->arg2;
871190507Slulf				offset = ev->arg3;
872190507Slulf				rename = ev->arg4;
873190507Slulf				err = gv_attach_sd(s, p, offset, rename);
874190507Slulf				if (err)
875190507Slulf					G_VINUM_DEBUG(0, "error attaching %s to"
876190507Slulf					    " %s: error code %d", s->name,
877190507Slulf					    p->name, err);
878190507Slulf				break;
879190507Slulf
880190507Slulf			case GV_EVENT_DETACH_PLEX:
881190507Slulf				G_VINUM_DEBUG(2, "event 'detach' plex");
882190507Slulf				p = ev->arg1;
883190507Slulf				flags = ev->arg3;
884190507Slulf				err = gv_detach_plex(p, flags);
885190507Slulf				if (err)
886190507Slulf					G_VINUM_DEBUG(0, "error detaching %s: "
887190507Slulf					    "error code %d", p->name, err);
888190507Slulf				break;
889190507Slulf
890190507Slulf			case GV_EVENT_DETACH_SD:
891190507Slulf				G_VINUM_DEBUG(2, "event 'detach' sd");
892190507Slulf				s = ev->arg1;
893190507Slulf				flags = ev->arg3;
894190507Slulf				err = gv_detach_sd(s, flags);
895190507Slulf				if (err)
896190507Slulf					G_VINUM_DEBUG(0, "error detaching %s: "
897190507Slulf					    "error code %d", s->name, err);
898190507Slulf				break;
899190507Slulf
900190507Slulf			case GV_EVENT_RENAME_VOL:
901190507Slulf				G_VINUM_DEBUG(2, "event 'rename' volume");
902190507Slulf				v = ev->arg1;
903190507Slulf				newname = ev->arg2;
904190507Slulf				flags = ev->arg3;
905190507Slulf				err = gv_rename_vol(sc, v, newname, flags);
906190507Slulf				if (err)
907190507Slulf					G_VINUM_DEBUG(0, "error renaming %s to "
908190507Slulf					    "%s: error code %d", v->name,
909190507Slulf					    newname, err);
910190507Slulf				g_free(newname);
911190507Slulf				/* Destroy and recreate the provider if we can. */
912190507Slulf				if (gv_provider_is_open(v->provider)) {
913190507Slulf					G_VINUM_DEBUG(0, "unable to rename "
914190507Slulf					    "provider to %s: provider in use",
915190507Slulf					    v->name);
916190507Slulf					break;
917190507Slulf				}
918191248Slulf				g_topology_lock();
919190507Slulf				g_wither_provider(v->provider, ENOENT);
920191248Slulf				g_topology_unlock();
921190507Slulf				v->provider = NULL;
922190507Slulf				gv_post_event(sc, GV_EVENT_SETUP_OBJECTS, sc,
923190507Slulf				    NULL, 0, 0);
924190507Slulf				break;
925190507Slulf
926190507Slulf			case GV_EVENT_RENAME_PLEX:
927190507Slulf				G_VINUM_DEBUG(2, "event 'rename' plex");
928190507Slulf				p = ev->arg1;
929190507Slulf				newname = ev->arg2;
930190507Slulf				flags = ev->arg3;
931190507Slulf				err = gv_rename_plex(sc, p, newname, flags);
932190507Slulf				if (err)
933190507Slulf					G_VINUM_DEBUG(0, "error renaming %s to "
934190507Slulf					    "%s: error code %d", p->name,
935190507Slulf					    newname, err);
936190507Slulf				g_free(newname);
937190507Slulf				break;
938190507Slulf
939190507Slulf			case GV_EVENT_RENAME_SD:
940190507Slulf				G_VINUM_DEBUG(2, "event 'rename' sd");
941190507Slulf				s = ev->arg1;
942190507Slulf				newname = ev->arg2;
943190507Slulf				flags = ev->arg3;
944190507Slulf				err = gv_rename_sd(sc, s, newname, flags);
945190507Slulf				if (err)
946190507Slulf					G_VINUM_DEBUG(0, "error renaming %s to "
947190507Slulf					    "%s: error code %d", s->name,
948190507Slulf					    newname, err);
949190507Slulf				g_free(newname);
950190507Slulf				break;
951190507Slulf
952190507Slulf			case GV_EVENT_RENAME_DRIVE:
953190507Slulf				G_VINUM_DEBUG(2, "event 'rename' drive");
954190507Slulf				d = ev->arg1;
955190507Slulf				newname = ev->arg2;
956190507Slulf				flags = ev->arg3;
957190507Slulf				err = gv_rename_drive(sc, d, newname, flags);
958190507Slulf				if (err)
959190507Slulf					G_VINUM_DEBUG(0, "error renaming %s to "
960190507Slulf					    "%s: error code %d", d->name,
961190507Slulf					    newname, err);
962190507Slulf				g_free(newname);
963190507Slulf				break;
964190507Slulf
965190507Slulf			case GV_EVENT_MOVE_SD:
966190507Slulf				G_VINUM_DEBUG(2, "event 'move' sd");
967190507Slulf				s = ev->arg1;
968190507Slulf				d = ev->arg2;
969190507Slulf				flags = ev->arg3;
970190507Slulf				err = gv_move_sd(sc, s, d, flags);
971190507Slulf				if (err)
972190507Slulf					G_VINUM_DEBUG(0, "error moving %s to "
973190507Slulf					    "%s: error code %d", s->name,
974190507Slulf					    d->name, err);
975190507Slulf				break;
976190507Slulf
977190507Slulf			case GV_EVENT_THREAD_EXIT:
978190507Slulf				G_VINUM_DEBUG(2, "event 'thread exit'");
979190507Slulf				g_free(ev);
980191849Slulf				mtx_lock(&sc->equeue_mtx);
981191849Slulf				mtx_lock(&sc->bqueue_mtx);
982190507Slulf				gv_cleanup(sc);
983191849Slulf				mtx_destroy(&sc->bqueue_mtx);
984191849Slulf				mtx_destroy(&sc->equeue_mtx);
985191856Slulf				g_free(sc->bqueue_down);
986191856Slulf				g_free(sc->bqueue_up);
987190507Slulf				g_free(sc);
988207878Sjh				kproc_exit(0);
989207878Sjh				/* NOTREACHED */
990190507Slulf
991190507Slulf			default:
992190507Slulf				G_VINUM_DEBUG(1, "unknown event %d", ev->type);
993190507Slulf			}
994190507Slulf
995190507Slulf			g_free(ev);
996190507Slulf			continue;
997190507Slulf		}
998190507Slulf
999190507Slulf		/* ... then do I/O processing. */
1000191849Slulf		mtx_lock(&sc->bqueue_mtx);
1001191856Slulf		/* First do new requests. */
1002191856Slulf		bp = bioq_takefirst(sc->bqueue_down);
1003191856Slulf		if (bp != NULL) {
1004191856Slulf			mtx_unlock(&sc->bqueue_mtx);
1005191856Slulf			/* A bio that interfered with another bio. */
1006191856Slulf			if (bp->bio_pflags & GV_BIO_ONHOLD) {
1007191856Slulf				s = bp->bio_caller1;
1008191856Slulf				p = s->plex_sc;
1009191856Slulf				/* Is it still locked out? */
1010191856Slulf				if (gv_stripe_active(p, bp)) {
1011191856Slulf					/* Park the bio on the waiting queue. */
1012191856Slulf					bioq_disksort(p->wqueue, bp);
1013191856Slulf				} else {
1014191856Slulf					bp->bio_pflags &= ~GV_BIO_ONHOLD;
1015191856Slulf					g_io_request(bp, s->drive_sc->consumer);
1016191856Slulf				}
1017191856Slulf			/* A special request requireing special handling. */
1018191856Slulf			} else if (bp->bio_pflags & GV_BIO_INTERNAL) {
1019191856Slulf				p = bp->bio_caller1;
1020191856Slulf				gv_plex_start(p, bp);
1021191856Slulf			} else {
1022191856Slulf				gv_volume_start(sc, bp);
1023191856Slulf			}
1024191856Slulf			mtx_lock(&sc->bqueue_mtx);
1025191856Slulf		}
1026191856Slulf		/* Then do completed requests. */
1027191856Slulf		bp = bioq_takefirst(sc->bqueue_up);
1028190507Slulf		if (bp == NULL) {
1029191849Slulf			msleep(sc, &sc->bqueue_mtx, PRIBIO, "-", hz/10);
1030191849Slulf			mtx_unlock(&sc->bqueue_mtx);
1031190507Slulf			continue;
1032190507Slulf		}
1033191849Slulf		mtx_unlock(&sc->bqueue_mtx);
1034191856Slulf		gv_bio_done(sc, bp);
1035190507Slulf	}
1036190507Slulf}
1037190507Slulf
1038130389Sle#define	VINUM_CLASS_NAME "VINUM"
1039130389Sle
1040130389Slestatic struct g_class g_vinum_class	= {
1041130389Sle	.name = VINUM_CLASS_NAME,
1042133318Sphk	.version = G_VERSION,
1043152773Sle	.init = gv_init,
1044190507Slulf	.taste = gv_taste,
1045130389Sle	.ctlreq = gv_config,
1046190507Slulf	.destroy_geom = gv_unload,
1047130389Sle};
1048130389Sle
1049130389SleDECLARE_GEOM_CLASS(g_vinum_class, g_vinum);
1050