189b17223SAlexander Motin /*-
2*4d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause
33728855aSPedro F. Giffuni *
489b17223SAlexander Motin * Copyright (c) 2010 Alexander Motin <mav@FreeBSD.org>
589b17223SAlexander Motin * All rights reserved.
689b17223SAlexander Motin *
789b17223SAlexander Motin * Redistribution and use in source and binary forms, with or without
889b17223SAlexander Motin * modification, are permitted provided that the following conditions
989b17223SAlexander Motin * are met:
1089b17223SAlexander Motin * 1. Redistributions of source code must retain the above copyright
1189b17223SAlexander Motin * notice, this list of conditions and the following disclaimer.
1289b17223SAlexander Motin * 2. Redistributions in binary form must reproduce the above copyright
1389b17223SAlexander Motin * notice, this list of conditions and the following disclaimer in the
1489b17223SAlexander Motin * documentation and/or other materials provided with the distribution.
1589b17223SAlexander Motin *
1689b17223SAlexander Motin * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
1789b17223SAlexander Motin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1889b17223SAlexander Motin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1989b17223SAlexander Motin * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
2089b17223SAlexander Motin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2189b17223SAlexander Motin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2289b17223SAlexander Motin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2389b17223SAlexander Motin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2489b17223SAlexander Motin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2589b17223SAlexander Motin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2689b17223SAlexander Motin * SUCH DAMAGE.
2789b17223SAlexander Motin */
2889b17223SAlexander Motin
2989b17223SAlexander Motin #include <sys/param.h>
3089b17223SAlexander Motin #include <sys/bio.h>
3189b17223SAlexander Motin #include <sys/endian.h>
3289b17223SAlexander Motin #include <sys/kernel.h>
3389b17223SAlexander Motin #include <sys/kobj.h>
3489b17223SAlexander Motin #include <sys/lock.h>
3589b17223SAlexander Motin #include <sys/malloc.h>
3689b17223SAlexander Motin #include <sys/mutex.h>
3789b17223SAlexander Motin #include <sys/systm.h>
3889b17223SAlexander Motin #include <geom/geom.h>
39ac03832eSConrad Meyer #include <geom/geom_dbg.h>
4089b17223SAlexander Motin #include "geom/raid/g_raid.h"
4189b17223SAlexander Motin #include "g_raid_tr_if.h"
4289b17223SAlexander Motin
4389b17223SAlexander Motin static MALLOC_DEFINE(M_TR_RAID0, "tr_raid0_data", "GEOM_RAID RAID0 data");
4489b17223SAlexander Motin
4589b17223SAlexander Motin struct g_raid_tr_raid0_object {
4689b17223SAlexander Motin struct g_raid_tr_object trso_base;
4789b17223SAlexander Motin int trso_starting;
4889b17223SAlexander Motin int trso_stopped;
4989b17223SAlexander Motin };
5089b17223SAlexander Motin
5189b17223SAlexander Motin static g_raid_tr_taste_t g_raid_tr_taste_raid0;
5289b17223SAlexander Motin static g_raid_tr_event_t g_raid_tr_event_raid0;
5389b17223SAlexander Motin static g_raid_tr_start_t g_raid_tr_start_raid0;
5489b17223SAlexander Motin static g_raid_tr_stop_t g_raid_tr_stop_raid0;
5589b17223SAlexander Motin static g_raid_tr_iostart_t g_raid_tr_iostart_raid0;
5689b17223SAlexander Motin static g_raid_tr_iodone_t g_raid_tr_iodone_raid0;
5789b17223SAlexander Motin static g_raid_tr_kerneldump_t g_raid_tr_kerneldump_raid0;
5889b17223SAlexander Motin static g_raid_tr_free_t g_raid_tr_free_raid0;
5989b17223SAlexander Motin
6089b17223SAlexander Motin static kobj_method_t g_raid_tr_raid0_methods[] = {
6189b17223SAlexander Motin KOBJMETHOD(g_raid_tr_taste, g_raid_tr_taste_raid0),
6289b17223SAlexander Motin KOBJMETHOD(g_raid_tr_event, g_raid_tr_event_raid0),
6389b17223SAlexander Motin KOBJMETHOD(g_raid_tr_start, g_raid_tr_start_raid0),
6489b17223SAlexander Motin KOBJMETHOD(g_raid_tr_stop, g_raid_tr_stop_raid0),
6589b17223SAlexander Motin KOBJMETHOD(g_raid_tr_iostart, g_raid_tr_iostart_raid0),
6689b17223SAlexander Motin KOBJMETHOD(g_raid_tr_iodone, g_raid_tr_iodone_raid0),
6789b17223SAlexander Motin KOBJMETHOD(g_raid_tr_kerneldump, g_raid_tr_kerneldump_raid0),
6889b17223SAlexander Motin KOBJMETHOD(g_raid_tr_free, g_raid_tr_free_raid0),
6989b17223SAlexander Motin { 0, 0 }
7089b17223SAlexander Motin };
7189b17223SAlexander Motin
7289b17223SAlexander Motin static struct g_raid_tr_class g_raid_tr_raid0_class = {
7389b17223SAlexander Motin "RAID0",
7489b17223SAlexander Motin g_raid_tr_raid0_methods,
7589b17223SAlexander Motin sizeof(struct g_raid_tr_raid0_object),
76c89d2fbeSAlexander Motin .trc_enable = 1,
77b43560abSAlexander Motin .trc_priority = 100,
78b43560abSAlexander Motin .trc_accept_unmapped = 1
7989b17223SAlexander Motin };
8089b17223SAlexander Motin
8189b17223SAlexander Motin static int
g_raid_tr_taste_raid0(struct g_raid_tr_object * tr,struct g_raid_volume * volume)8289b17223SAlexander Motin g_raid_tr_taste_raid0(struct g_raid_tr_object *tr, struct g_raid_volume *volume)
8389b17223SAlexander Motin {
8489b17223SAlexander Motin struct g_raid_tr_raid0_object *trs;
8589b17223SAlexander Motin
8689b17223SAlexander Motin trs = (struct g_raid_tr_raid0_object *)tr;
8789b17223SAlexander Motin if (tr->tro_volume->v_raid_level != G_RAID_VOLUME_RL_RAID0 ||
8889b17223SAlexander Motin tr->tro_volume->v_raid_level_qualifier != G_RAID_VOLUME_RLQ_NONE)
8989b17223SAlexander Motin return (G_RAID_TR_TASTE_FAIL);
9089b17223SAlexander Motin trs->trso_starting = 1;
9189b17223SAlexander Motin return (G_RAID_TR_TASTE_SUCCEED);
9289b17223SAlexander Motin }
9389b17223SAlexander Motin
9489b17223SAlexander Motin static int
g_raid_tr_update_state_raid0(struct g_raid_volume * vol)9589b17223SAlexander Motin g_raid_tr_update_state_raid0(struct g_raid_volume *vol)
9689b17223SAlexander Motin {
9789b17223SAlexander Motin struct g_raid_tr_raid0_object *trs;
9889b17223SAlexander Motin struct g_raid_softc *sc;
9989b17223SAlexander Motin u_int s;
10089b17223SAlexander Motin int n, f;
10189b17223SAlexander Motin
10289b17223SAlexander Motin sc = vol->v_softc;
10389b17223SAlexander Motin trs = (struct g_raid_tr_raid0_object *)vol->v_tr;
10489b17223SAlexander Motin if (trs->trso_stopped)
10589b17223SAlexander Motin s = G_RAID_VOLUME_S_STOPPED;
10689b17223SAlexander Motin else if (trs->trso_starting)
10789b17223SAlexander Motin s = G_RAID_VOLUME_S_STARTING;
10889b17223SAlexander Motin else {
10989b17223SAlexander Motin n = g_raid_nsubdisks(vol, G_RAID_SUBDISK_S_ACTIVE);
11089b17223SAlexander Motin f = g_raid_nsubdisks(vol, G_RAID_SUBDISK_S_FAILED);
11189b17223SAlexander Motin if (n + f == vol->v_disks_count) {
11289b17223SAlexander Motin if (f == 0)
11389b17223SAlexander Motin s = G_RAID_VOLUME_S_OPTIMAL;
11489b17223SAlexander Motin else
11589b17223SAlexander Motin s = G_RAID_VOLUME_S_SUBOPTIMAL;
11689b17223SAlexander Motin } else
11789b17223SAlexander Motin s = G_RAID_VOLUME_S_BROKEN;
11889b17223SAlexander Motin }
11989b17223SAlexander Motin if (s != vol->v_state) {
12089b17223SAlexander Motin g_raid_event_send(vol, G_RAID_VOLUME_S_ALIVE(s) ?
12189b17223SAlexander Motin G_RAID_VOLUME_E_UP : G_RAID_VOLUME_E_DOWN,
12289b17223SAlexander Motin G_RAID_EVENT_VOLUME);
12389b17223SAlexander Motin g_raid_change_volume_state(vol, s);
12489b17223SAlexander Motin if (!trs->trso_starting && !trs->trso_stopped)
12589b17223SAlexander Motin g_raid_write_metadata(sc, vol, NULL, NULL);
12689b17223SAlexander Motin }
12789b17223SAlexander Motin return (0);
12889b17223SAlexander Motin }
12989b17223SAlexander Motin
13089b17223SAlexander Motin static int
g_raid_tr_event_raid0(struct g_raid_tr_object * tr,struct g_raid_subdisk * sd,u_int event)13189b17223SAlexander Motin g_raid_tr_event_raid0(struct g_raid_tr_object *tr,
13289b17223SAlexander Motin struct g_raid_subdisk *sd, u_int event)
13389b17223SAlexander Motin {
13489b17223SAlexander Motin struct g_raid_tr_raid0_object *trs;
13589b17223SAlexander Motin struct g_raid_softc *sc;
13689b17223SAlexander Motin struct g_raid_volume *vol;
13789b17223SAlexander Motin int state;
13889b17223SAlexander Motin
13989b17223SAlexander Motin trs = (struct g_raid_tr_raid0_object *)tr;
14089b17223SAlexander Motin vol = tr->tro_volume;
14189b17223SAlexander Motin sc = vol->v_softc;
14289b17223SAlexander Motin
14389b17223SAlexander Motin state = sd->sd_state;
14489b17223SAlexander Motin if (state != G_RAID_SUBDISK_S_NONE &&
14589b17223SAlexander Motin state != G_RAID_SUBDISK_S_FAILED &&
14689b17223SAlexander Motin state != G_RAID_SUBDISK_S_ACTIVE) {
14789b17223SAlexander Motin G_RAID_DEBUG1(1, sc,
14889b17223SAlexander Motin "Promote subdisk %s:%d from %s to ACTIVE.",
14989b17223SAlexander Motin vol->v_name, sd->sd_pos,
15089b17223SAlexander Motin g_raid_subdisk_state2str(sd->sd_state));
15189b17223SAlexander Motin g_raid_change_subdisk_state(sd, G_RAID_SUBDISK_S_ACTIVE);
15289b17223SAlexander Motin }
15389b17223SAlexander Motin if (state != sd->sd_state &&
15489b17223SAlexander Motin !trs->trso_starting && !trs->trso_stopped)
15589b17223SAlexander Motin g_raid_write_metadata(sc, vol, sd, NULL);
15689b17223SAlexander Motin g_raid_tr_update_state_raid0(vol);
15789b17223SAlexander Motin return (0);
15889b17223SAlexander Motin }
15989b17223SAlexander Motin
16089b17223SAlexander Motin static int
g_raid_tr_start_raid0(struct g_raid_tr_object * tr)16189b17223SAlexander Motin g_raid_tr_start_raid0(struct g_raid_tr_object *tr)
16289b17223SAlexander Motin {
16389b17223SAlexander Motin struct g_raid_tr_raid0_object *trs;
16489b17223SAlexander Motin struct g_raid_volume *vol;
16589b17223SAlexander Motin
16689b17223SAlexander Motin trs = (struct g_raid_tr_raid0_object *)tr;
16789b17223SAlexander Motin vol = tr->tro_volume;
16889b17223SAlexander Motin trs->trso_starting = 0;
16989b17223SAlexander Motin g_raid_tr_update_state_raid0(vol);
17089b17223SAlexander Motin return (0);
17189b17223SAlexander Motin }
17289b17223SAlexander Motin
17389b17223SAlexander Motin static int
g_raid_tr_stop_raid0(struct g_raid_tr_object * tr)17489b17223SAlexander Motin g_raid_tr_stop_raid0(struct g_raid_tr_object *tr)
17589b17223SAlexander Motin {
17689b17223SAlexander Motin struct g_raid_tr_raid0_object *trs;
17789b17223SAlexander Motin struct g_raid_volume *vol;
17889b17223SAlexander Motin
17989b17223SAlexander Motin trs = (struct g_raid_tr_raid0_object *)tr;
18089b17223SAlexander Motin vol = tr->tro_volume;
18189b17223SAlexander Motin trs->trso_starting = 0;
18289b17223SAlexander Motin trs->trso_stopped = 1;
18389b17223SAlexander Motin g_raid_tr_update_state_raid0(vol);
18489b17223SAlexander Motin return (0);
18589b17223SAlexander Motin }
18689b17223SAlexander Motin
18789b17223SAlexander Motin static void
g_raid_tr_iostart_raid0(struct g_raid_tr_object * tr,struct bio * bp)18889b17223SAlexander Motin g_raid_tr_iostart_raid0(struct g_raid_tr_object *tr, struct bio *bp)
18989b17223SAlexander Motin {
19089b17223SAlexander Motin struct g_raid_volume *vol;
19189b17223SAlexander Motin struct g_raid_subdisk *sd;
19289b17223SAlexander Motin struct bio_queue_head queue;
19389b17223SAlexander Motin struct bio *cbp;
19489b17223SAlexander Motin char *addr;
19589b17223SAlexander Motin off_t offset, start, length, nstripe, remain;
19689b17223SAlexander Motin u_int no, strip_size;
19789b17223SAlexander Motin
19889b17223SAlexander Motin vol = tr->tro_volume;
19989b17223SAlexander Motin if (vol->v_state != G_RAID_VOLUME_S_OPTIMAL &&
20089b17223SAlexander Motin vol->v_state != G_RAID_VOLUME_S_SUBOPTIMAL) {
20189b17223SAlexander Motin g_raid_iodone(bp, EIO);
20289b17223SAlexander Motin return;
20389b17223SAlexander Motin }
2048b522bdaSWarner Losh if (bp->bio_cmd == BIO_FLUSH || bp->bio_cmd == BIO_SPEEDUP) {
20589b17223SAlexander Motin g_raid_tr_flush_common(tr, bp);
20689b17223SAlexander Motin return;
20789b17223SAlexander Motin }
208b43560abSAlexander Motin if ((bp->bio_flags & BIO_UNMAPPED) != 0)
209b43560abSAlexander Motin addr = NULL;
210b43560abSAlexander Motin else
21189b17223SAlexander Motin addr = bp->bio_data;
21289b17223SAlexander Motin strip_size = vol->v_strip_size;
21389b17223SAlexander Motin
21489b17223SAlexander Motin /* Stripe number. */
21589b17223SAlexander Motin nstripe = bp->bio_offset / strip_size;
21689b17223SAlexander Motin /* Start position in stripe. */
21789b17223SAlexander Motin start = bp->bio_offset % strip_size;
21889b17223SAlexander Motin /* Disk number. */
21989b17223SAlexander Motin no = nstripe % vol->v_disks_count;
22089b17223SAlexander Motin /* Stripe start position in disk. */
22189b17223SAlexander Motin offset = (nstripe / vol->v_disks_count) * strip_size;
22289b17223SAlexander Motin /* Length of data to operate. */
22389b17223SAlexander Motin remain = bp->bio_length;
22489b17223SAlexander Motin
22589b17223SAlexander Motin bioq_init(&queue);
22689b17223SAlexander Motin do {
22789b17223SAlexander Motin length = MIN(strip_size - start, remain);
22889b17223SAlexander Motin cbp = g_clone_bio(bp);
22989b17223SAlexander Motin if (cbp == NULL)
23089b17223SAlexander Motin goto failure;
23189b17223SAlexander Motin cbp->bio_offset = offset + start;
23289b17223SAlexander Motin cbp->bio_length = length;
233b43560abSAlexander Motin if ((bp->bio_flags & BIO_UNMAPPED) != 0 &&
234b43560abSAlexander Motin bp->bio_cmd != BIO_DELETE) {
235b43560abSAlexander Motin cbp->bio_ma_offset += (uintptr_t)addr;
236b43560abSAlexander Motin cbp->bio_ma += cbp->bio_ma_offset / PAGE_SIZE;
237b43560abSAlexander Motin cbp->bio_ma_offset %= PAGE_SIZE;
238b43560abSAlexander Motin cbp->bio_ma_n = round_page(cbp->bio_ma_offset +
239b43560abSAlexander Motin cbp->bio_length) / PAGE_SIZE;
240b43560abSAlexander Motin } else
241b43560abSAlexander Motin cbp->bio_data = addr;
24289b17223SAlexander Motin cbp->bio_caller1 = &vol->v_subdisks[no];
24389b17223SAlexander Motin bioq_insert_tail(&queue, cbp);
24489b17223SAlexander Motin if (++no >= vol->v_disks_count) {
24589b17223SAlexander Motin no = 0;
24689b17223SAlexander Motin offset += strip_size;
24789b17223SAlexander Motin }
24889b17223SAlexander Motin remain -= length;
249609a7474SAlexander Motin if (bp->bio_cmd != BIO_DELETE)
25089b17223SAlexander Motin addr += length;
25189b17223SAlexander Motin start = 0;
25289b17223SAlexander Motin } while (remain > 0);
253b43560abSAlexander Motin while ((cbp = bioq_takefirst(&queue)) != NULL) {
25489b17223SAlexander Motin sd = cbp->bio_caller1;
25589b17223SAlexander Motin cbp->bio_caller1 = NULL;
25689b17223SAlexander Motin g_raid_subdisk_iostart(sd, cbp);
25789b17223SAlexander Motin }
25889b17223SAlexander Motin return;
25989b17223SAlexander Motin failure:
260b43560abSAlexander Motin while ((cbp = bioq_takefirst(&queue)) != NULL)
26189b17223SAlexander Motin g_destroy_bio(cbp);
26289b17223SAlexander Motin if (bp->bio_error == 0)
26389b17223SAlexander Motin bp->bio_error = ENOMEM;
26489b17223SAlexander Motin g_raid_iodone(bp, bp->bio_error);
26589b17223SAlexander Motin }
26689b17223SAlexander Motin
26789b17223SAlexander Motin static int
g_raid_tr_kerneldump_raid0(struct g_raid_tr_object * tr,void * virtual,off_t boffset,size_t blength)26889b17223SAlexander Motin g_raid_tr_kerneldump_raid0(struct g_raid_tr_object *tr,
269489ba222SMitchell Horne void *virtual, off_t boffset, size_t blength)
27089b17223SAlexander Motin {
27189b17223SAlexander Motin struct g_raid_volume *vol;
27289b17223SAlexander Motin char *addr;
27389b17223SAlexander Motin off_t offset, start, length, nstripe, remain;
27489b17223SAlexander Motin u_int no, strip_size;
27589b17223SAlexander Motin int error;
27689b17223SAlexander Motin
27789b17223SAlexander Motin vol = tr->tro_volume;
27889b17223SAlexander Motin if (vol->v_state != G_RAID_VOLUME_S_OPTIMAL)
27989b17223SAlexander Motin return (ENXIO);
28089b17223SAlexander Motin addr = virtual;
28189b17223SAlexander Motin strip_size = vol->v_strip_size;
28289b17223SAlexander Motin
28389b17223SAlexander Motin /* Stripe number. */
28489b17223SAlexander Motin nstripe = boffset / strip_size;
28589b17223SAlexander Motin /* Start position in stripe. */
28689b17223SAlexander Motin start = boffset % strip_size;
28789b17223SAlexander Motin /* Disk number. */
28889b17223SAlexander Motin no = nstripe % vol->v_disks_count;
28989b17223SAlexander Motin /* Stripe tart position in disk. */
29089b17223SAlexander Motin offset = (nstripe / vol->v_disks_count) * strip_size;
29189b17223SAlexander Motin /* Length of data to operate. */
29289b17223SAlexander Motin remain = blength;
29389b17223SAlexander Motin
29489b17223SAlexander Motin do {
29589b17223SAlexander Motin length = MIN(strip_size - start, remain);
296489ba222SMitchell Horne error = g_raid_subdisk_kerneldump(&vol->v_subdisks[no], addr,
297489ba222SMitchell Horne offset + start, length);
29889b17223SAlexander Motin if (error != 0)
29989b17223SAlexander Motin return (error);
30089b17223SAlexander Motin if (++no >= vol->v_disks_count) {
30189b17223SAlexander Motin no = 0;
30289b17223SAlexander Motin offset += strip_size;
30389b17223SAlexander Motin }
30489b17223SAlexander Motin remain -= length;
30589b17223SAlexander Motin addr += length;
30689b17223SAlexander Motin start = 0;
30789b17223SAlexander Motin } while (remain > 0);
30889b17223SAlexander Motin return (0);
30989b17223SAlexander Motin }
31089b17223SAlexander Motin
31189b17223SAlexander Motin static void
g_raid_tr_iodone_raid0(struct g_raid_tr_object * tr,struct g_raid_subdisk * sd,struct bio * bp)31289b17223SAlexander Motin g_raid_tr_iodone_raid0(struct g_raid_tr_object *tr,
31389b17223SAlexander Motin struct g_raid_subdisk *sd,struct bio *bp)
31489b17223SAlexander Motin {
31589b17223SAlexander Motin struct bio *pbp;
31689b17223SAlexander Motin
31789b17223SAlexander Motin pbp = bp->bio_parent;
31889b17223SAlexander Motin if (pbp->bio_error == 0)
31989b17223SAlexander Motin pbp->bio_error = bp->bio_error;
32089b17223SAlexander Motin g_destroy_bio(bp);
32189b17223SAlexander Motin pbp->bio_inbed++;
32289b17223SAlexander Motin if (pbp->bio_children == pbp->bio_inbed) {
32389b17223SAlexander Motin pbp->bio_completed = pbp->bio_length;
324cf4a52cfSAlexander Motin g_raid_iodone(pbp, pbp->bio_error);
32589b17223SAlexander Motin }
32689b17223SAlexander Motin }
32789b17223SAlexander Motin
32889b17223SAlexander Motin static int
g_raid_tr_free_raid0(struct g_raid_tr_object * tr)32989b17223SAlexander Motin g_raid_tr_free_raid0(struct g_raid_tr_object *tr)
33089b17223SAlexander Motin {
33189b17223SAlexander Motin
33289b17223SAlexander Motin return (0);
33389b17223SAlexander Motin }
33489b17223SAlexander Motin
335c89d2fbeSAlexander Motin G_RAID_TR_DECLARE(raid0, "RAID0");
336