xref: /freebsd/sys/geom/vinum/geom_vinum_volume.c (revision fdafd315)
173679edcSLukas Ertl /*-
24d846d26SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause
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/param.h>
3073679edcSLukas Ertl #include <sys/bio.h>
3173679edcSLukas Ertl #include <sys/lock.h>
3273679edcSLukas Ertl #include <sys/malloc.h>
3373679edcSLukas Ertl #include <sys/systm.h>
3473679edcSLukas Ertl 
3573679edcSLukas Ertl #include <geom/geom.h>
3673679edcSLukas Ertl #include <geom/vinum/geom_vinum_var.h>
3773679edcSLukas Ertl #include <geom/vinum/geom_vinum.h>
3873679edcSLukas Ertl 
39c0b9797aSUlf Lilleengen void
gv_volume_flush(struct gv_volume * v)40c0b9797aSUlf Lilleengen gv_volume_flush(struct gv_volume *v)
41c0b9797aSUlf Lilleengen {
42c0b9797aSUlf Lilleengen 	struct gv_softc *sc;
43c0b9797aSUlf Lilleengen 	struct bio *bp;
4467e3ab6eSLukas Ertl 
45c0b9797aSUlf Lilleengen 	KASSERT(v != NULL, ("NULL v"));
46c0b9797aSUlf Lilleengen 	sc = v->vinumconf;
47c0b9797aSUlf Lilleengen 	KASSERT(sc != NULL, ("NULL sc"));
48c0b9797aSUlf Lilleengen 
49c0b9797aSUlf Lilleengen 	bp = bioq_takefirst(v->wqueue);
50c0b9797aSUlf Lilleengen 	while (bp != NULL) {
51c0b9797aSUlf Lilleengen 		gv_volume_start(sc, bp);
52c0b9797aSUlf Lilleengen 		bp = bioq_takefirst(v->wqueue);
53c0b9797aSUlf Lilleengen 	}
54c0b9797aSUlf Lilleengen }
55c0b9797aSUlf Lilleengen 
56c0b9797aSUlf Lilleengen void
gv_volume_start(struct gv_softc * sc,struct bio * bp)57c0b9797aSUlf Lilleengen gv_volume_start(struct gv_softc *sc, struct bio *bp)
5873679edcSLukas Ertl {
5999b536d8SLukas Ertl 	struct gv_volume *v;
60c0b9797aSUlf Lilleengen 	struct gv_plex *p, *lp;
61c0b9797aSUlf Lilleengen 	int numwrites;
6273679edcSLukas Ertl 
63c0b9797aSUlf Lilleengen 	v = bp->bio_to->private;
64c0b9797aSUlf Lilleengen 	if (v == NULL || v->state != GV_VOL_UP) {
6567e3ab6eSLukas Ertl 		g_io_deliver(bp, ENXIO);
6667e3ab6eSLukas Ertl 		return;
6767e3ab6eSLukas Ertl 	}
6867e3ab6eSLukas Ertl 
6967e3ab6eSLukas Ertl 	switch (bp->bio_cmd) {
7067e3ab6eSLukas Ertl 	case BIO_READ:
71d8688e11SLukas Ertl 		/*
72c0b9797aSUlf Lilleengen 		 * Try to find a good plex where we can send the request to,
73c0b9797aSUlf Lilleengen 		 * round-robin-style.  The plex either has to be up, or it's a
74c0b9797aSUlf Lilleengen 		 * degraded RAID5 plex. Check if we have delayed requests. Put
75c0b9797aSUlf Lilleengen 		 * this request on the delayed queue if so. This makes sure that
76c0b9797aSUlf Lilleengen 		 * we don't read old values.
77d8688e11SLukas Ertl 		 */
78c0b9797aSUlf Lilleengen 		if (bioq_first(v->wqueue) != NULL) {
79c0b9797aSUlf Lilleengen 			bioq_insert_tail(v->wqueue, bp);
80c0b9797aSUlf Lilleengen 			break;
81c0b9797aSUlf Lilleengen 		}
827ad68986SLukas Ertl 		lp = v->last_read_plex;
837ad68986SLukas Ertl 		if (lp == NULL)
847ad68986SLukas Ertl 			lp = LIST_FIRST(&v->plexes);
857ad68986SLukas Ertl 		p = LIST_NEXT(lp, in_volume);
867ad68986SLukas Ertl 		if (p == NULL)
877ad68986SLukas Ertl 			p = LIST_FIRST(&v->plexes);
88c0b9797aSUlf Lilleengen 		do {
89c0b9797aSUlf Lilleengen 			if (p == NULL) {
90c0b9797aSUlf Lilleengen 				p = lp;
91c0b9797aSUlf Lilleengen 				break;
92c0b9797aSUlf Lilleengen 			}
93d8688e11SLukas Ertl 			if ((p->state > GV_PLEX_DEGRADED) ||
94d8688e11SLukas Ertl 			    (p->state >= GV_PLEX_DEGRADED &&
95d8688e11SLukas Ertl 			    p->org == GV_PLEX_RAID5))
9667e3ab6eSLukas Ertl 				break;
977ad68986SLukas Ertl 			p = LIST_NEXT(p, in_volume);
98c0b9797aSUlf Lilleengen 			if (p == NULL)
99c0b9797aSUlf Lilleengen 				p = LIST_FIRST(&v->plexes);
1007ad68986SLukas Ertl 		} while (p != lp);
1017ad68986SLukas Ertl 
102c0b9797aSUlf Lilleengen 		if ((p == NULL) ||
1037ad68986SLukas Ertl 		    (p->org == GV_PLEX_RAID5 && p->state < GV_PLEX_DEGRADED) ||
104fdb9eda8SLukas Ertl 		    (p->org != GV_PLEX_RAID5 && p->state <= GV_PLEX_DEGRADED)) {
105d8688e11SLukas Ertl 			g_io_deliver(bp, ENXIO);
106d8688e11SLukas Ertl 			return;
107d8688e11SLukas Ertl 		}
1087ad68986SLukas Ertl 		v->last_read_plex = p;
10967e3ab6eSLukas Ertl 
110c0b9797aSUlf Lilleengen 		/* Hand it down to the plex logic. */
111c0b9797aSUlf Lilleengen 		gv_plex_start(p, bp);
11267e3ab6eSLukas Ertl 		break;
11367e3ab6eSLukas Ertl 
11467e3ab6eSLukas Ertl 	case BIO_WRITE:
11567e3ab6eSLukas Ertl 	case BIO_DELETE:
116c0b9797aSUlf Lilleengen 		/* Delay write-requests if any plex is synchronizing. */
117c0b9797aSUlf Lilleengen 		LIST_FOREACH(p, &v->plexes, in_volume) {
118c0b9797aSUlf Lilleengen 			if (p->flags & GV_PLEX_SYNCING) {
119c0b9797aSUlf Lilleengen 				bioq_insert_tail(v->wqueue, bp);
120c0b9797aSUlf Lilleengen 				return;
121c0b9797aSUlf Lilleengen 			}
122c0b9797aSUlf Lilleengen 		}
123c0b9797aSUlf Lilleengen 
124c0b9797aSUlf Lilleengen 		numwrites = 0;
125c0b9797aSUlf Lilleengen 		/* Give the BIO to each plex of this volume. */
12667e3ab6eSLukas Ertl 		LIST_FOREACH(p, &v->plexes, in_volume) {
12767e3ab6eSLukas Ertl 			if (p->state < GV_PLEX_DEGRADED)
12867e3ab6eSLukas Ertl 				continue;
129c0b9797aSUlf Lilleengen 			gv_plex_start(p, bp);
130c0b9797aSUlf Lilleengen 			numwrites++;
1317ad68986SLukas Ertl 		}
132c0b9797aSUlf Lilleengen 		if (numwrites == 0)
133c0b9797aSUlf Lilleengen 			g_io_deliver(bp, ENXIO);
13467e3ab6eSLukas Ertl 		break;
13567e3ab6eSLukas Ertl 	}
13673679edcSLukas Ertl }
13773679edcSLukas Ertl 
138c0b9797aSUlf Lilleengen void
gv_bio_done(struct gv_softc * sc,struct bio * bp)139c0b9797aSUlf Lilleengen gv_bio_done(struct gv_softc *sc, struct bio *bp)
14073679edcSLukas Ertl {
141739a9c51SEdward Tomasz Napierala 	struct gv_volume *v __diagused;
14273679edcSLukas Ertl 	struct gv_plex *p;
143c0b9797aSUlf Lilleengen 	struct gv_sd *s;
14473679edcSLukas Ertl 
145c0b9797aSUlf Lilleengen 	s = bp->bio_caller1;
146c0b9797aSUlf Lilleengen 	KASSERT(s != NULL, ("gv_bio_done: NULL s"));
147c0b9797aSUlf Lilleengen 	p = s->plex_sc;
148c0b9797aSUlf Lilleengen 	KASSERT(p != NULL, ("gv_bio_done: NULL p"));
149c0b9797aSUlf Lilleengen 	v = p->vol_sc;
150c0b9797aSUlf Lilleengen 	KASSERT(v != NULL, ("gv_bio_done: NULL v"));
15173679edcSLukas Ertl 
152c0b9797aSUlf Lilleengen 	switch (p->org) {
153c0b9797aSUlf Lilleengen 	case GV_PLEX_CONCAT:
154c0b9797aSUlf Lilleengen 	case GV_PLEX_STRIPED:
155c0b9797aSUlf Lilleengen 		gv_plex_normal_done(p, bp);
156c0b9797aSUlf Lilleengen 		break;
157c0b9797aSUlf Lilleengen 	case GV_PLEX_RAID5:
158c0b9797aSUlf Lilleengen 		gv_plex_raid5_done(p, bp);
159c0b9797aSUlf Lilleengen 		break;
1604328802cSLukas Ertl 	}
161a29df733SAlexander Motin 
162a29df733SAlexander Motin 	gv_drive_done(s->drive_sc);
1634328802cSLukas Ertl }
164