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