xref: /freebsd/sys/geom/vinum/geom_vinum_volume.c (revision a29df733)
173679edcSLukas Ertl /*-
23728855aSPedro F. Giffuni  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
33728855aSPedro F. Giffuni  *
4c0b9797aSUlf Lilleengen  * Copyright (c) 2007 Lukas Ertl
573679edcSLukas Ertl  * All rights reserved.
673679edcSLukas Ertl  *
773679edcSLukas Ertl  * Redistribution and use in source and binary forms, with or without
873679edcSLukas Ertl  * modification, are permitted provided that the following conditions
973679edcSLukas Ertl  * are met:
1073679edcSLukas Ertl  * 1. Redistributions of source code must retain the above copyright
1173679edcSLukas Ertl  *    notice, this list of conditions and the following disclaimer.
1273679edcSLukas Ertl  * 2. Redistributions in binary form must reproduce the above copyright
1373679edcSLukas Ertl  *    notice, this list of conditions and the following disclaimer in the
1473679edcSLukas Ertl  *    documentation and/or other materials provided with the distribution.
1573679edcSLukas Ertl  *
1673679edcSLukas Ertl  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1773679edcSLukas Ertl  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1873679edcSLukas Ertl  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1973679edcSLukas Ertl  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2073679edcSLukas Ertl  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2173679edcSLukas Ertl  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2273679edcSLukas Ertl  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2373679edcSLukas Ertl  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2473679edcSLukas Ertl  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2573679edcSLukas Ertl  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2673679edcSLukas Ertl  * SUCH DAMAGE.
2773679edcSLukas Ertl  */
2873679edcSLukas Ertl 
2973679edcSLukas Ertl #include <sys/cdefs.h>
3073679edcSLukas Ertl __FBSDID("$FreeBSD$");
3173679edcSLukas Ertl 
3273679edcSLukas Ertl #include <sys/param.h>
3373679edcSLukas Ertl #include <sys/bio.h>
3473679edcSLukas Ertl #include <sys/lock.h>
3573679edcSLukas Ertl #include <sys/malloc.h>
3673679edcSLukas Ertl #include <sys/systm.h>
3773679edcSLukas Ertl 
3873679edcSLukas Ertl #include <geom/geom.h>
3973679edcSLukas Ertl #include <geom/vinum/geom_vinum_var.h>
4073679edcSLukas Ertl #include <geom/vinum/geom_vinum.h>
4173679edcSLukas Ertl 
42c0b9797aSUlf Lilleengen void
43c0b9797aSUlf Lilleengen gv_volume_flush(struct gv_volume *v)
44c0b9797aSUlf Lilleengen {
45c0b9797aSUlf Lilleengen 	struct gv_softc *sc;
46c0b9797aSUlf Lilleengen 	struct bio *bp;
4767e3ab6eSLukas Ertl 
48c0b9797aSUlf Lilleengen 	KASSERT(v != NULL, ("NULL v"));
49c0b9797aSUlf Lilleengen 	sc = v->vinumconf;
50c0b9797aSUlf Lilleengen 	KASSERT(sc != NULL, ("NULL sc"));
51c0b9797aSUlf Lilleengen 
52c0b9797aSUlf Lilleengen 	bp = bioq_takefirst(v->wqueue);
53c0b9797aSUlf Lilleengen 	while (bp != NULL) {
54c0b9797aSUlf Lilleengen 		gv_volume_start(sc, bp);
55c0b9797aSUlf Lilleengen 		bp = bioq_takefirst(v->wqueue);
56c0b9797aSUlf Lilleengen 	}
57c0b9797aSUlf Lilleengen }
58c0b9797aSUlf Lilleengen 
59c0b9797aSUlf Lilleengen void
60c0b9797aSUlf Lilleengen gv_volume_start(struct gv_softc *sc, struct bio *bp)
6173679edcSLukas Ertl {
6273679edcSLukas Ertl 	struct g_geom *gp;
6399b536d8SLukas Ertl 	struct gv_volume *v;
64c0b9797aSUlf Lilleengen 	struct gv_plex *p, *lp;
65c0b9797aSUlf Lilleengen 	int numwrites;
6673679edcSLukas Ertl 
67c0b9797aSUlf Lilleengen 	gp = sc->geom;
68c0b9797aSUlf Lilleengen 	v = bp->bio_to->private;
69c0b9797aSUlf Lilleengen 	if (v == NULL || v->state != GV_VOL_UP) {
7067e3ab6eSLukas Ertl 		g_io_deliver(bp, ENXIO);
7167e3ab6eSLukas Ertl 		return;
7267e3ab6eSLukas Ertl 	}
7367e3ab6eSLukas Ertl 
7467e3ab6eSLukas Ertl 	switch (bp->bio_cmd) {
7567e3ab6eSLukas Ertl 	case BIO_READ:
76d8688e11SLukas Ertl 		/*
77c0b9797aSUlf Lilleengen 		 * Try to find a good plex where we can send the request to,
78c0b9797aSUlf Lilleengen 		 * round-robin-style.  The plex either has to be up, or it's a
79c0b9797aSUlf Lilleengen 		 * degraded RAID5 plex. Check if we have delayed requests. Put
80c0b9797aSUlf Lilleengen 		 * this request on the delayed queue if so. This makes sure that
81c0b9797aSUlf Lilleengen 		 * we don't read old values.
82d8688e11SLukas Ertl 		 */
83c0b9797aSUlf Lilleengen 		if (bioq_first(v->wqueue) != NULL) {
84c0b9797aSUlf Lilleengen 			bioq_insert_tail(v->wqueue, bp);
85c0b9797aSUlf Lilleengen 			break;
86c0b9797aSUlf Lilleengen 		}
877ad68986SLukas Ertl 		lp = v->last_read_plex;
887ad68986SLukas Ertl 		if (lp == NULL)
897ad68986SLukas Ertl 			lp = LIST_FIRST(&v->plexes);
907ad68986SLukas Ertl 		p = LIST_NEXT(lp, in_volume);
917ad68986SLukas Ertl 		if (p == NULL)
927ad68986SLukas Ertl 			p = LIST_FIRST(&v->plexes);
93c0b9797aSUlf Lilleengen 		do {
94c0b9797aSUlf Lilleengen 			if (p == NULL) {
95c0b9797aSUlf Lilleengen 				p = lp;
96c0b9797aSUlf Lilleengen 				break;
97c0b9797aSUlf Lilleengen 			}
98d8688e11SLukas Ertl 			if ((p->state > GV_PLEX_DEGRADED) ||
99d8688e11SLukas Ertl 			    (p->state >= GV_PLEX_DEGRADED &&
100d8688e11SLukas Ertl 			    p->org == GV_PLEX_RAID5))
10167e3ab6eSLukas Ertl 				break;
1027ad68986SLukas Ertl 			p = LIST_NEXT(p, in_volume);
103c0b9797aSUlf Lilleengen 			if (p == NULL)
104c0b9797aSUlf Lilleengen 				p = LIST_FIRST(&v->plexes);
1057ad68986SLukas Ertl 		} while (p != lp);
1067ad68986SLukas Ertl 
107c0b9797aSUlf Lilleengen 		if ((p == NULL) ||
1087ad68986SLukas Ertl 		    (p->org == GV_PLEX_RAID5 && p->state < GV_PLEX_DEGRADED) ||
109fdb9eda8SLukas Ertl 		    (p->org != GV_PLEX_RAID5 && p->state <= GV_PLEX_DEGRADED)) {
110d8688e11SLukas Ertl 			g_io_deliver(bp, ENXIO);
111d8688e11SLukas Ertl 			return;
112d8688e11SLukas Ertl 		}
1137ad68986SLukas Ertl 		v->last_read_plex = p;
11467e3ab6eSLukas Ertl 
115c0b9797aSUlf Lilleengen 		/* Hand it down to the plex logic. */
116c0b9797aSUlf Lilleengen 		gv_plex_start(p, bp);
11767e3ab6eSLukas Ertl 		break;
11867e3ab6eSLukas Ertl 
11967e3ab6eSLukas Ertl 	case BIO_WRITE:
12067e3ab6eSLukas Ertl 	case BIO_DELETE:
121c0b9797aSUlf Lilleengen 		/* Delay write-requests if any plex is synchronizing. */
122c0b9797aSUlf Lilleengen 		LIST_FOREACH(p, &v->plexes, in_volume) {
123c0b9797aSUlf Lilleengen 			if (p->flags & GV_PLEX_SYNCING) {
124c0b9797aSUlf Lilleengen 				bioq_insert_tail(v->wqueue, bp);
125c0b9797aSUlf Lilleengen 				return;
126c0b9797aSUlf Lilleengen 			}
127c0b9797aSUlf Lilleengen 		}
128c0b9797aSUlf Lilleengen 
129c0b9797aSUlf Lilleengen 		numwrites = 0;
130c0b9797aSUlf Lilleengen 		/* Give the BIO to each plex of this volume. */
13167e3ab6eSLukas Ertl 		LIST_FOREACH(p, &v->plexes, in_volume) {
13267e3ab6eSLukas Ertl 			if (p->state < GV_PLEX_DEGRADED)
13367e3ab6eSLukas Ertl 				continue;
134c0b9797aSUlf Lilleengen 			gv_plex_start(p, bp);
135c0b9797aSUlf Lilleengen 			numwrites++;
1367ad68986SLukas Ertl 		}
137c0b9797aSUlf Lilleengen 		if (numwrites == 0)
138c0b9797aSUlf Lilleengen 			g_io_deliver(bp, ENXIO);
13967e3ab6eSLukas Ertl 		break;
14067e3ab6eSLukas Ertl 	}
14173679edcSLukas Ertl }
14273679edcSLukas Ertl 
143c0b9797aSUlf Lilleengen void
144c0b9797aSUlf Lilleengen gv_bio_done(struct gv_softc *sc, struct bio *bp)
14573679edcSLukas Ertl {
14673679edcSLukas Ertl 	struct gv_volume *v;
14773679edcSLukas Ertl 	struct gv_plex *p;
148c0b9797aSUlf Lilleengen 	struct gv_sd *s;
14973679edcSLukas Ertl 
150c0b9797aSUlf Lilleengen 	s = bp->bio_caller1;
151c0b9797aSUlf Lilleengen 	KASSERT(s != NULL, ("gv_bio_done: NULL s"));
152c0b9797aSUlf Lilleengen 	p = s->plex_sc;
153c0b9797aSUlf Lilleengen 	KASSERT(p != NULL, ("gv_bio_done: NULL p"));
154c0b9797aSUlf Lilleengen 	v = p->vol_sc;
155c0b9797aSUlf Lilleengen 	KASSERT(v != NULL, ("gv_bio_done: NULL v"));
15673679edcSLukas Ertl 
157c0b9797aSUlf Lilleengen 	switch (p->org) {
158c0b9797aSUlf Lilleengen 	case GV_PLEX_CONCAT:
159c0b9797aSUlf Lilleengen 	case GV_PLEX_STRIPED:
160c0b9797aSUlf Lilleengen 		gv_plex_normal_done(p, bp);
161c0b9797aSUlf Lilleengen 		break;
162c0b9797aSUlf Lilleengen 	case GV_PLEX_RAID5:
163c0b9797aSUlf Lilleengen 		gv_plex_raid5_done(p, bp);
164c0b9797aSUlf Lilleengen 		break;
1654328802cSLukas Ertl 	}
166a29df733SAlexander Motin 
167a29df733SAlexander Motin 	gv_drive_done(s->drive_sc);
1684328802cSLukas Ertl }
169