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/cdefs.h> 3089b17223SAlexander Motin __FBSDID("$FreeBSD$"); 3189b17223SAlexander Motin 3289b17223SAlexander Motin #include <sys/param.h> 3389b17223SAlexander Motin #include <sys/bio.h> 3489b17223SAlexander Motin #include <sys/endian.h> 3589b17223SAlexander Motin #include <sys/kernel.h> 3689b17223SAlexander Motin #include <sys/kobj.h> 3789b17223SAlexander Motin #include <sys/lock.h> 3889b17223SAlexander Motin #include <sys/malloc.h> 3989b17223SAlexander Motin #include <sys/mutex.h> 4089b17223SAlexander Motin #include <sys/systm.h> 4189b17223SAlexander Motin #include <geom/geom.h> 42ac03832eSConrad Meyer #include <geom/geom_dbg.h> 4389b17223SAlexander Motin #include "geom/raid/g_raid.h" 4489b17223SAlexander Motin #include "g_raid_tr_if.h" 4589b17223SAlexander Motin 4689b17223SAlexander Motin static MALLOC_DEFINE(M_TR_RAID0, "tr_raid0_data", "GEOM_RAID RAID0 data"); 4789b17223SAlexander Motin 4889b17223SAlexander Motin struct g_raid_tr_raid0_object { 4989b17223SAlexander Motin struct g_raid_tr_object trso_base; 5089b17223SAlexander Motin int trso_starting; 5189b17223SAlexander Motin int trso_stopped; 5289b17223SAlexander Motin }; 5389b17223SAlexander Motin 5489b17223SAlexander Motin static g_raid_tr_taste_t g_raid_tr_taste_raid0; 5589b17223SAlexander Motin static g_raid_tr_event_t g_raid_tr_event_raid0; 5689b17223SAlexander Motin static g_raid_tr_start_t g_raid_tr_start_raid0; 5789b17223SAlexander Motin static g_raid_tr_stop_t g_raid_tr_stop_raid0; 5889b17223SAlexander Motin static g_raid_tr_iostart_t g_raid_tr_iostart_raid0; 5989b17223SAlexander Motin static g_raid_tr_iodone_t g_raid_tr_iodone_raid0; 6089b17223SAlexander Motin static g_raid_tr_kerneldump_t g_raid_tr_kerneldump_raid0; 6189b17223SAlexander Motin static g_raid_tr_free_t g_raid_tr_free_raid0; 6289b17223SAlexander Motin 6389b17223SAlexander Motin static kobj_method_t g_raid_tr_raid0_methods[] = { 6489b17223SAlexander Motin KOBJMETHOD(g_raid_tr_taste, g_raid_tr_taste_raid0), 6589b17223SAlexander Motin KOBJMETHOD(g_raid_tr_event, g_raid_tr_event_raid0), 6689b17223SAlexander Motin KOBJMETHOD(g_raid_tr_start, g_raid_tr_start_raid0), 6789b17223SAlexander Motin KOBJMETHOD(g_raid_tr_stop, g_raid_tr_stop_raid0), 6889b17223SAlexander Motin KOBJMETHOD(g_raid_tr_iostart, g_raid_tr_iostart_raid0), 6989b17223SAlexander Motin KOBJMETHOD(g_raid_tr_iodone, g_raid_tr_iodone_raid0), 7089b17223SAlexander Motin KOBJMETHOD(g_raid_tr_kerneldump, g_raid_tr_kerneldump_raid0), 7189b17223SAlexander Motin KOBJMETHOD(g_raid_tr_free, g_raid_tr_free_raid0), 7289b17223SAlexander Motin { 0, 0 } 7389b17223SAlexander Motin }; 7489b17223SAlexander Motin 7589b17223SAlexander Motin static struct g_raid_tr_class g_raid_tr_raid0_class = { 7689b17223SAlexander Motin "RAID0", 7789b17223SAlexander Motin g_raid_tr_raid0_methods, 7889b17223SAlexander Motin sizeof(struct g_raid_tr_raid0_object), 79c89d2fbeSAlexander Motin .trc_enable = 1, 80b43560abSAlexander Motin .trc_priority = 100, 81b43560abSAlexander Motin .trc_accept_unmapped = 1 8289b17223SAlexander Motin }; 8389b17223SAlexander Motin 8489b17223SAlexander Motin static int 8589b17223SAlexander Motin g_raid_tr_taste_raid0(struct g_raid_tr_object *tr, struct g_raid_volume *volume) 8689b17223SAlexander Motin { 8789b17223SAlexander Motin struct g_raid_tr_raid0_object *trs; 8889b17223SAlexander Motin 8989b17223SAlexander Motin trs = (struct g_raid_tr_raid0_object *)tr; 9089b17223SAlexander Motin if (tr->tro_volume->v_raid_level != G_RAID_VOLUME_RL_RAID0 || 9189b17223SAlexander Motin tr->tro_volume->v_raid_level_qualifier != G_RAID_VOLUME_RLQ_NONE) 9289b17223SAlexander Motin return (G_RAID_TR_TASTE_FAIL); 9389b17223SAlexander Motin trs->trso_starting = 1; 9489b17223SAlexander Motin return (G_RAID_TR_TASTE_SUCCEED); 9589b17223SAlexander Motin } 9689b17223SAlexander Motin 9789b17223SAlexander Motin static int 9889b17223SAlexander Motin g_raid_tr_update_state_raid0(struct g_raid_volume *vol) 9989b17223SAlexander Motin { 10089b17223SAlexander Motin struct g_raid_tr_raid0_object *trs; 10189b17223SAlexander Motin struct g_raid_softc *sc; 10289b17223SAlexander Motin u_int s; 10389b17223SAlexander Motin int n, f; 10489b17223SAlexander Motin 10589b17223SAlexander Motin sc = vol->v_softc; 10689b17223SAlexander Motin trs = (struct g_raid_tr_raid0_object *)vol->v_tr; 10789b17223SAlexander Motin if (trs->trso_stopped) 10889b17223SAlexander Motin s = G_RAID_VOLUME_S_STOPPED; 10989b17223SAlexander Motin else if (trs->trso_starting) 11089b17223SAlexander Motin s = G_RAID_VOLUME_S_STARTING; 11189b17223SAlexander Motin else { 11289b17223SAlexander Motin n = g_raid_nsubdisks(vol, G_RAID_SUBDISK_S_ACTIVE); 11389b17223SAlexander Motin f = g_raid_nsubdisks(vol, G_RAID_SUBDISK_S_FAILED); 11489b17223SAlexander Motin if (n + f == vol->v_disks_count) { 11589b17223SAlexander Motin if (f == 0) 11689b17223SAlexander Motin s = G_RAID_VOLUME_S_OPTIMAL; 11789b17223SAlexander Motin else 11889b17223SAlexander Motin s = G_RAID_VOLUME_S_SUBOPTIMAL; 11989b17223SAlexander Motin } else 12089b17223SAlexander Motin s = G_RAID_VOLUME_S_BROKEN; 12189b17223SAlexander Motin } 12289b17223SAlexander Motin if (s != vol->v_state) { 12389b17223SAlexander Motin g_raid_event_send(vol, G_RAID_VOLUME_S_ALIVE(s) ? 12489b17223SAlexander Motin G_RAID_VOLUME_E_UP : G_RAID_VOLUME_E_DOWN, 12589b17223SAlexander Motin G_RAID_EVENT_VOLUME); 12689b17223SAlexander Motin g_raid_change_volume_state(vol, s); 12789b17223SAlexander Motin if (!trs->trso_starting && !trs->trso_stopped) 12889b17223SAlexander Motin g_raid_write_metadata(sc, vol, NULL, NULL); 12989b17223SAlexander Motin } 13089b17223SAlexander Motin return (0); 13189b17223SAlexander Motin } 13289b17223SAlexander Motin 13389b17223SAlexander Motin static int 13489b17223SAlexander Motin g_raid_tr_event_raid0(struct g_raid_tr_object *tr, 13589b17223SAlexander Motin struct g_raid_subdisk *sd, u_int event) 13689b17223SAlexander Motin { 13789b17223SAlexander Motin struct g_raid_tr_raid0_object *trs; 13889b17223SAlexander Motin struct g_raid_softc *sc; 13989b17223SAlexander Motin struct g_raid_volume *vol; 14089b17223SAlexander Motin int state; 14189b17223SAlexander Motin 14289b17223SAlexander Motin trs = (struct g_raid_tr_raid0_object *)tr; 14389b17223SAlexander Motin vol = tr->tro_volume; 14489b17223SAlexander Motin sc = vol->v_softc; 14589b17223SAlexander Motin 14689b17223SAlexander Motin state = sd->sd_state; 14789b17223SAlexander Motin if (state != G_RAID_SUBDISK_S_NONE && 14889b17223SAlexander Motin state != G_RAID_SUBDISK_S_FAILED && 14989b17223SAlexander Motin state != G_RAID_SUBDISK_S_ACTIVE) { 15089b17223SAlexander Motin G_RAID_DEBUG1(1, sc, 15189b17223SAlexander Motin "Promote subdisk %s:%d from %s to ACTIVE.", 15289b17223SAlexander Motin vol->v_name, sd->sd_pos, 15389b17223SAlexander Motin g_raid_subdisk_state2str(sd->sd_state)); 15489b17223SAlexander Motin g_raid_change_subdisk_state(sd, G_RAID_SUBDISK_S_ACTIVE); 15589b17223SAlexander Motin } 15689b17223SAlexander Motin if (state != sd->sd_state && 15789b17223SAlexander Motin !trs->trso_starting && !trs->trso_stopped) 15889b17223SAlexander Motin g_raid_write_metadata(sc, vol, sd, NULL); 15989b17223SAlexander Motin g_raid_tr_update_state_raid0(vol); 16089b17223SAlexander Motin return (0); 16189b17223SAlexander Motin } 16289b17223SAlexander Motin 16389b17223SAlexander Motin static int 16489b17223SAlexander Motin g_raid_tr_start_raid0(struct g_raid_tr_object *tr) 16589b17223SAlexander Motin { 16689b17223SAlexander Motin struct g_raid_tr_raid0_object *trs; 16789b17223SAlexander Motin struct g_raid_volume *vol; 16889b17223SAlexander Motin 16989b17223SAlexander Motin trs = (struct g_raid_tr_raid0_object *)tr; 17089b17223SAlexander Motin vol = tr->tro_volume; 17189b17223SAlexander Motin trs->trso_starting = 0; 17289b17223SAlexander Motin g_raid_tr_update_state_raid0(vol); 17389b17223SAlexander Motin return (0); 17489b17223SAlexander Motin } 17589b17223SAlexander Motin 17689b17223SAlexander Motin static int 17789b17223SAlexander Motin g_raid_tr_stop_raid0(struct g_raid_tr_object *tr) 17889b17223SAlexander Motin { 17989b17223SAlexander Motin struct g_raid_tr_raid0_object *trs; 18089b17223SAlexander Motin struct g_raid_volume *vol; 18189b17223SAlexander Motin 18289b17223SAlexander Motin trs = (struct g_raid_tr_raid0_object *)tr; 18389b17223SAlexander Motin vol = tr->tro_volume; 18489b17223SAlexander Motin trs->trso_starting = 0; 18589b17223SAlexander Motin trs->trso_stopped = 1; 18689b17223SAlexander Motin g_raid_tr_update_state_raid0(vol); 18789b17223SAlexander Motin return (0); 18889b17223SAlexander Motin } 18989b17223SAlexander Motin 19089b17223SAlexander Motin static void 19189b17223SAlexander Motin g_raid_tr_iostart_raid0(struct g_raid_tr_object *tr, struct bio *bp) 19289b17223SAlexander Motin { 19389b17223SAlexander Motin struct g_raid_volume *vol; 19489b17223SAlexander Motin struct g_raid_subdisk *sd; 19589b17223SAlexander Motin struct bio_queue_head queue; 19689b17223SAlexander Motin struct bio *cbp; 19789b17223SAlexander Motin char *addr; 19889b17223SAlexander Motin off_t offset, start, length, nstripe, remain; 19989b17223SAlexander Motin u_int no, strip_size; 20089b17223SAlexander Motin 20189b17223SAlexander Motin vol = tr->tro_volume; 20289b17223SAlexander Motin if (vol->v_state != G_RAID_VOLUME_S_OPTIMAL && 20389b17223SAlexander Motin vol->v_state != G_RAID_VOLUME_S_SUBOPTIMAL) { 20489b17223SAlexander Motin g_raid_iodone(bp, EIO); 20589b17223SAlexander Motin return; 20689b17223SAlexander Motin } 2078b522bdaSWarner Losh if (bp->bio_cmd == BIO_FLUSH || bp->bio_cmd == BIO_SPEEDUP) { 20889b17223SAlexander Motin g_raid_tr_flush_common(tr, bp); 20989b17223SAlexander Motin return; 21089b17223SAlexander Motin } 211b43560abSAlexander Motin if ((bp->bio_flags & BIO_UNMAPPED) != 0) 212b43560abSAlexander Motin addr = NULL; 213b43560abSAlexander Motin else 21489b17223SAlexander Motin addr = bp->bio_data; 21589b17223SAlexander Motin strip_size = vol->v_strip_size; 21689b17223SAlexander Motin 21789b17223SAlexander Motin /* Stripe number. */ 21889b17223SAlexander Motin nstripe = bp->bio_offset / strip_size; 21989b17223SAlexander Motin /* Start position in stripe. */ 22089b17223SAlexander Motin start = bp->bio_offset % strip_size; 22189b17223SAlexander Motin /* Disk number. */ 22289b17223SAlexander Motin no = nstripe % vol->v_disks_count; 22389b17223SAlexander Motin /* Stripe start position in disk. */ 22489b17223SAlexander Motin offset = (nstripe / vol->v_disks_count) * strip_size; 22589b17223SAlexander Motin /* Length of data to operate. */ 22689b17223SAlexander Motin remain = bp->bio_length; 22789b17223SAlexander Motin 22889b17223SAlexander Motin bioq_init(&queue); 22989b17223SAlexander Motin do { 23089b17223SAlexander Motin length = MIN(strip_size - start, remain); 23189b17223SAlexander Motin cbp = g_clone_bio(bp); 23289b17223SAlexander Motin if (cbp == NULL) 23389b17223SAlexander Motin goto failure; 23489b17223SAlexander Motin cbp->bio_offset = offset + start; 23589b17223SAlexander Motin cbp->bio_length = length; 236b43560abSAlexander Motin if ((bp->bio_flags & BIO_UNMAPPED) != 0 && 237b43560abSAlexander Motin bp->bio_cmd != BIO_DELETE) { 238b43560abSAlexander Motin cbp->bio_ma_offset += (uintptr_t)addr; 239b43560abSAlexander Motin cbp->bio_ma += cbp->bio_ma_offset / PAGE_SIZE; 240b43560abSAlexander Motin cbp->bio_ma_offset %= PAGE_SIZE; 241b43560abSAlexander Motin cbp->bio_ma_n = round_page(cbp->bio_ma_offset + 242b43560abSAlexander Motin cbp->bio_length) / PAGE_SIZE; 243b43560abSAlexander Motin } else 244b43560abSAlexander Motin cbp->bio_data = addr; 24589b17223SAlexander Motin cbp->bio_caller1 = &vol->v_subdisks[no]; 24689b17223SAlexander Motin bioq_insert_tail(&queue, cbp); 24789b17223SAlexander Motin if (++no >= vol->v_disks_count) { 24889b17223SAlexander Motin no = 0; 24989b17223SAlexander Motin offset += strip_size; 25089b17223SAlexander Motin } 25189b17223SAlexander Motin remain -= length; 252609a7474SAlexander Motin if (bp->bio_cmd != BIO_DELETE) 25389b17223SAlexander Motin addr += length; 25489b17223SAlexander Motin start = 0; 25589b17223SAlexander Motin } while (remain > 0); 256b43560abSAlexander Motin while ((cbp = bioq_takefirst(&queue)) != NULL) { 25789b17223SAlexander Motin sd = cbp->bio_caller1; 25889b17223SAlexander Motin cbp->bio_caller1 = NULL; 25989b17223SAlexander Motin g_raid_subdisk_iostart(sd, cbp); 26089b17223SAlexander Motin } 26189b17223SAlexander Motin return; 26289b17223SAlexander Motin failure: 263b43560abSAlexander Motin while ((cbp = bioq_takefirst(&queue)) != NULL) 26489b17223SAlexander Motin g_destroy_bio(cbp); 26589b17223SAlexander Motin if (bp->bio_error == 0) 26689b17223SAlexander Motin bp->bio_error = ENOMEM; 26789b17223SAlexander Motin g_raid_iodone(bp, bp->bio_error); 26889b17223SAlexander Motin } 26989b17223SAlexander Motin 27089b17223SAlexander Motin static int 27189b17223SAlexander Motin g_raid_tr_kerneldump_raid0(struct g_raid_tr_object *tr, 272489ba222SMitchell Horne void *virtual, off_t boffset, size_t blength) 27389b17223SAlexander Motin { 27489b17223SAlexander Motin struct g_raid_volume *vol; 27589b17223SAlexander Motin char *addr; 27689b17223SAlexander Motin off_t offset, start, length, nstripe, remain; 27789b17223SAlexander Motin u_int no, strip_size; 27889b17223SAlexander Motin int error; 27989b17223SAlexander Motin 28089b17223SAlexander Motin vol = tr->tro_volume; 28189b17223SAlexander Motin if (vol->v_state != G_RAID_VOLUME_S_OPTIMAL) 28289b17223SAlexander Motin return (ENXIO); 28389b17223SAlexander Motin addr = virtual; 28489b17223SAlexander Motin strip_size = vol->v_strip_size; 28589b17223SAlexander Motin 28689b17223SAlexander Motin /* Stripe number. */ 28789b17223SAlexander Motin nstripe = boffset / strip_size; 28889b17223SAlexander Motin /* Start position in stripe. */ 28989b17223SAlexander Motin start = boffset % strip_size; 29089b17223SAlexander Motin /* Disk number. */ 29189b17223SAlexander Motin no = nstripe % vol->v_disks_count; 29289b17223SAlexander Motin /* Stripe tart position in disk. */ 29389b17223SAlexander Motin offset = (nstripe / vol->v_disks_count) * strip_size; 29489b17223SAlexander Motin /* Length of data to operate. */ 29589b17223SAlexander Motin remain = blength; 29689b17223SAlexander Motin 29789b17223SAlexander Motin do { 29889b17223SAlexander Motin length = MIN(strip_size - start, remain); 299489ba222SMitchell Horne error = g_raid_subdisk_kerneldump(&vol->v_subdisks[no], addr, 300489ba222SMitchell Horne offset + start, length); 30189b17223SAlexander Motin if (error != 0) 30289b17223SAlexander Motin return (error); 30389b17223SAlexander Motin if (++no >= vol->v_disks_count) { 30489b17223SAlexander Motin no = 0; 30589b17223SAlexander Motin offset += strip_size; 30689b17223SAlexander Motin } 30789b17223SAlexander Motin remain -= length; 30889b17223SAlexander Motin addr += length; 30989b17223SAlexander Motin start = 0; 31089b17223SAlexander Motin } while (remain > 0); 31189b17223SAlexander Motin return (0); 31289b17223SAlexander Motin } 31389b17223SAlexander Motin 31489b17223SAlexander Motin static void 31589b17223SAlexander Motin g_raid_tr_iodone_raid0(struct g_raid_tr_object *tr, 31689b17223SAlexander Motin struct g_raid_subdisk *sd,struct bio *bp) 31789b17223SAlexander Motin { 31889b17223SAlexander Motin struct bio *pbp; 31989b17223SAlexander Motin 32089b17223SAlexander Motin pbp = bp->bio_parent; 32189b17223SAlexander Motin if (pbp->bio_error == 0) 32289b17223SAlexander Motin pbp->bio_error = bp->bio_error; 32389b17223SAlexander Motin g_destroy_bio(bp); 32489b17223SAlexander Motin pbp->bio_inbed++; 32589b17223SAlexander Motin if (pbp->bio_children == pbp->bio_inbed) { 32689b17223SAlexander Motin pbp->bio_completed = pbp->bio_length; 327cf4a52cfSAlexander Motin g_raid_iodone(pbp, pbp->bio_error); 32889b17223SAlexander Motin } 32989b17223SAlexander Motin } 33089b17223SAlexander Motin 33189b17223SAlexander Motin static int 33289b17223SAlexander Motin g_raid_tr_free_raid0(struct g_raid_tr_object *tr) 33389b17223SAlexander Motin { 33489b17223SAlexander Motin 33589b17223SAlexander Motin return (0); 33689b17223SAlexander Motin } 33789b17223SAlexander Motin 338c89d2fbeSAlexander Motin G_RAID_TR_DECLARE(raid0, "RAID0"); 339