189b17223SAlexander Motin /*- 289b17223SAlexander Motin * Copyright (c) 2010 Alexander Motin <mav@FreeBSD.org> 389b17223SAlexander Motin * All rights reserved. 489b17223SAlexander Motin * 589b17223SAlexander Motin * Redistribution and use in source and binary forms, with or without 689b17223SAlexander Motin * modification, are permitted provided that the following conditions 789b17223SAlexander Motin * are met: 889b17223SAlexander Motin * 1. Redistributions of source code must retain the above copyright 989b17223SAlexander Motin * notice, this list of conditions and the following disclaimer. 1089b17223SAlexander Motin * 2. Redistributions in binary form must reproduce the above copyright 1189b17223SAlexander Motin * notice, this list of conditions and the following disclaimer in the 1289b17223SAlexander Motin * documentation and/or other materials provided with the distribution. 1389b17223SAlexander Motin * 1489b17223SAlexander Motin * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 1589b17223SAlexander Motin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1689b17223SAlexander Motin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1789b17223SAlexander Motin * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 1889b17223SAlexander Motin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1989b17223SAlexander Motin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2089b17223SAlexander Motin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2189b17223SAlexander Motin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2289b17223SAlexander Motin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2389b17223SAlexander Motin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2489b17223SAlexander Motin * SUCH DAMAGE. 2589b17223SAlexander Motin */ 2689b17223SAlexander Motin 2789b17223SAlexander Motin #include <sys/cdefs.h> 2889b17223SAlexander Motin __FBSDID("$FreeBSD$"); 2989b17223SAlexander Motin 3089b17223SAlexander Motin #include <sys/param.h> 3189b17223SAlexander Motin #include <sys/bio.h> 3289b17223SAlexander Motin #include <sys/endian.h> 3389b17223SAlexander Motin #include <sys/kernel.h> 3489b17223SAlexander Motin #include <sys/kobj.h> 3589b17223SAlexander Motin #include <sys/lock.h> 3689b17223SAlexander Motin #include <sys/malloc.h> 3789b17223SAlexander Motin #include <sys/mutex.h> 3889b17223SAlexander Motin #include <sys/systm.h> 3989b17223SAlexander Motin #include <geom/geom.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), 76*c89d2fbeSAlexander Motin .trc_enable = 1, 7789b17223SAlexander Motin .trc_priority = 100 7889b17223SAlexander Motin }; 7989b17223SAlexander Motin 8089b17223SAlexander Motin static int 8189b17223SAlexander Motin g_raid_tr_taste_raid0(struct g_raid_tr_object *tr, struct g_raid_volume *volume) 8289b17223SAlexander Motin { 8389b17223SAlexander Motin struct g_raid_tr_raid0_object *trs; 8489b17223SAlexander Motin 8589b17223SAlexander Motin trs = (struct g_raid_tr_raid0_object *)tr; 8689b17223SAlexander Motin if (tr->tro_volume->v_raid_level != G_RAID_VOLUME_RL_RAID0 || 8789b17223SAlexander Motin tr->tro_volume->v_raid_level_qualifier != G_RAID_VOLUME_RLQ_NONE) 8889b17223SAlexander Motin return (G_RAID_TR_TASTE_FAIL); 8989b17223SAlexander Motin trs->trso_starting = 1; 9089b17223SAlexander Motin return (G_RAID_TR_TASTE_SUCCEED); 9189b17223SAlexander Motin } 9289b17223SAlexander Motin 9389b17223SAlexander Motin static int 9489b17223SAlexander Motin g_raid_tr_update_state_raid0(struct g_raid_volume *vol) 9589b17223SAlexander Motin { 9689b17223SAlexander Motin struct g_raid_tr_raid0_object *trs; 9789b17223SAlexander Motin struct g_raid_softc *sc; 9889b17223SAlexander Motin u_int s; 9989b17223SAlexander Motin int n, f; 10089b17223SAlexander Motin 10189b17223SAlexander Motin sc = vol->v_softc; 10289b17223SAlexander Motin trs = (struct g_raid_tr_raid0_object *)vol->v_tr; 10389b17223SAlexander Motin if (trs->trso_stopped) 10489b17223SAlexander Motin s = G_RAID_VOLUME_S_STOPPED; 10589b17223SAlexander Motin else if (trs->trso_starting) 10689b17223SAlexander Motin s = G_RAID_VOLUME_S_STARTING; 10789b17223SAlexander Motin else { 10889b17223SAlexander Motin n = g_raid_nsubdisks(vol, G_RAID_SUBDISK_S_ACTIVE); 10989b17223SAlexander Motin f = g_raid_nsubdisks(vol, G_RAID_SUBDISK_S_FAILED); 11089b17223SAlexander Motin if (n + f == vol->v_disks_count) { 11189b17223SAlexander Motin if (f == 0) 11289b17223SAlexander Motin s = G_RAID_VOLUME_S_OPTIMAL; 11389b17223SAlexander Motin else 11489b17223SAlexander Motin s = G_RAID_VOLUME_S_SUBOPTIMAL; 11589b17223SAlexander Motin } else 11689b17223SAlexander Motin s = G_RAID_VOLUME_S_BROKEN; 11789b17223SAlexander Motin } 11889b17223SAlexander Motin if (s != vol->v_state) { 11989b17223SAlexander Motin g_raid_event_send(vol, G_RAID_VOLUME_S_ALIVE(s) ? 12089b17223SAlexander Motin G_RAID_VOLUME_E_UP : G_RAID_VOLUME_E_DOWN, 12189b17223SAlexander Motin G_RAID_EVENT_VOLUME); 12289b17223SAlexander Motin g_raid_change_volume_state(vol, s); 12389b17223SAlexander Motin if (!trs->trso_starting && !trs->trso_stopped) 12489b17223SAlexander Motin g_raid_write_metadata(sc, vol, NULL, NULL); 12589b17223SAlexander Motin } 12689b17223SAlexander Motin return (0); 12789b17223SAlexander Motin } 12889b17223SAlexander Motin 12989b17223SAlexander Motin static int 13089b17223SAlexander Motin g_raid_tr_event_raid0(struct g_raid_tr_object *tr, 13189b17223SAlexander Motin struct g_raid_subdisk *sd, u_int event) 13289b17223SAlexander Motin { 13389b17223SAlexander Motin struct g_raid_tr_raid0_object *trs; 13489b17223SAlexander Motin struct g_raid_softc *sc; 13589b17223SAlexander Motin struct g_raid_volume *vol; 13689b17223SAlexander Motin int state; 13789b17223SAlexander Motin 13889b17223SAlexander Motin trs = (struct g_raid_tr_raid0_object *)tr; 13989b17223SAlexander Motin vol = tr->tro_volume; 14089b17223SAlexander Motin sc = vol->v_softc; 14189b17223SAlexander Motin 14289b17223SAlexander Motin state = sd->sd_state; 14389b17223SAlexander Motin if (state != G_RAID_SUBDISK_S_NONE && 14489b17223SAlexander Motin state != G_RAID_SUBDISK_S_FAILED && 14589b17223SAlexander Motin state != G_RAID_SUBDISK_S_ACTIVE) { 14689b17223SAlexander Motin G_RAID_DEBUG1(1, sc, 14789b17223SAlexander Motin "Promote subdisk %s:%d from %s to ACTIVE.", 14889b17223SAlexander Motin vol->v_name, sd->sd_pos, 14989b17223SAlexander Motin g_raid_subdisk_state2str(sd->sd_state)); 15089b17223SAlexander Motin g_raid_change_subdisk_state(sd, G_RAID_SUBDISK_S_ACTIVE); 15189b17223SAlexander Motin } 15289b17223SAlexander Motin if (state != sd->sd_state && 15389b17223SAlexander Motin !trs->trso_starting && !trs->trso_stopped) 15489b17223SAlexander Motin g_raid_write_metadata(sc, vol, sd, NULL); 15589b17223SAlexander Motin g_raid_tr_update_state_raid0(vol); 15689b17223SAlexander Motin return (0); 15789b17223SAlexander Motin } 15889b17223SAlexander Motin 15989b17223SAlexander Motin static int 16089b17223SAlexander Motin g_raid_tr_start_raid0(struct g_raid_tr_object *tr) 16189b17223SAlexander Motin { 16289b17223SAlexander Motin struct g_raid_tr_raid0_object *trs; 16389b17223SAlexander Motin struct g_raid_volume *vol; 16489b17223SAlexander Motin 16589b17223SAlexander Motin trs = (struct g_raid_tr_raid0_object *)tr; 16689b17223SAlexander Motin vol = tr->tro_volume; 16789b17223SAlexander Motin trs->trso_starting = 0; 16889b17223SAlexander Motin g_raid_tr_update_state_raid0(vol); 16989b17223SAlexander Motin return (0); 17089b17223SAlexander Motin } 17189b17223SAlexander Motin 17289b17223SAlexander Motin static int 17389b17223SAlexander Motin g_raid_tr_stop_raid0(struct g_raid_tr_object *tr) 17489b17223SAlexander Motin { 17589b17223SAlexander Motin struct g_raid_tr_raid0_object *trs; 17689b17223SAlexander Motin struct g_raid_volume *vol; 17789b17223SAlexander Motin 17889b17223SAlexander Motin trs = (struct g_raid_tr_raid0_object *)tr; 17989b17223SAlexander Motin vol = tr->tro_volume; 18089b17223SAlexander Motin trs->trso_starting = 0; 18189b17223SAlexander Motin trs->trso_stopped = 1; 18289b17223SAlexander Motin g_raid_tr_update_state_raid0(vol); 18389b17223SAlexander Motin return (0); 18489b17223SAlexander Motin } 18589b17223SAlexander Motin 18689b17223SAlexander Motin static void 18789b17223SAlexander Motin g_raid_tr_iostart_raid0(struct g_raid_tr_object *tr, struct bio *bp) 18889b17223SAlexander Motin { 18989b17223SAlexander Motin struct g_raid_volume *vol; 19089b17223SAlexander Motin struct g_raid_subdisk *sd; 19189b17223SAlexander Motin struct bio_queue_head queue; 19289b17223SAlexander Motin struct bio *cbp; 19389b17223SAlexander Motin char *addr; 19489b17223SAlexander Motin off_t offset, start, length, nstripe, remain; 19589b17223SAlexander Motin u_int no, strip_size; 19689b17223SAlexander Motin 19789b17223SAlexander Motin vol = tr->tro_volume; 19889b17223SAlexander Motin if (vol->v_state != G_RAID_VOLUME_S_OPTIMAL && 19989b17223SAlexander Motin vol->v_state != G_RAID_VOLUME_S_SUBOPTIMAL) { 20089b17223SAlexander Motin g_raid_iodone(bp, EIO); 20189b17223SAlexander Motin return; 20289b17223SAlexander Motin } 20389b17223SAlexander Motin if (bp->bio_cmd == BIO_FLUSH) { 20489b17223SAlexander Motin g_raid_tr_flush_common(tr, bp); 20589b17223SAlexander Motin return; 20689b17223SAlexander Motin } 20789b17223SAlexander Motin addr = bp->bio_data; 20889b17223SAlexander Motin strip_size = vol->v_strip_size; 20989b17223SAlexander Motin 21089b17223SAlexander Motin /* Stripe number. */ 21189b17223SAlexander Motin nstripe = bp->bio_offset / strip_size; 21289b17223SAlexander Motin /* Start position in stripe. */ 21389b17223SAlexander Motin start = bp->bio_offset % strip_size; 21489b17223SAlexander Motin /* Disk number. */ 21589b17223SAlexander Motin no = nstripe % vol->v_disks_count; 21689b17223SAlexander Motin /* Stripe start position in disk. */ 21789b17223SAlexander Motin offset = (nstripe / vol->v_disks_count) * strip_size; 21889b17223SAlexander Motin /* Length of data to operate. */ 21989b17223SAlexander Motin remain = bp->bio_length; 22089b17223SAlexander Motin 22189b17223SAlexander Motin bioq_init(&queue); 22289b17223SAlexander Motin do { 22389b17223SAlexander Motin length = MIN(strip_size - start, remain); 22489b17223SAlexander Motin cbp = g_clone_bio(bp); 22589b17223SAlexander Motin if (cbp == NULL) 22689b17223SAlexander Motin goto failure; 22789b17223SAlexander Motin cbp->bio_offset = offset + start; 22889b17223SAlexander Motin cbp->bio_data = addr; 22989b17223SAlexander Motin cbp->bio_length = length; 23089b17223SAlexander Motin cbp->bio_caller1 = &vol->v_subdisks[no]; 23189b17223SAlexander Motin bioq_insert_tail(&queue, cbp); 23289b17223SAlexander Motin if (++no >= vol->v_disks_count) { 23389b17223SAlexander Motin no = 0; 23489b17223SAlexander Motin offset += strip_size; 23589b17223SAlexander Motin } 23689b17223SAlexander Motin remain -= length; 23789b17223SAlexander Motin addr += length; 23889b17223SAlexander Motin start = 0; 23989b17223SAlexander Motin } while (remain > 0); 24089b17223SAlexander Motin for (cbp = bioq_first(&queue); cbp != NULL; 24189b17223SAlexander Motin cbp = bioq_first(&queue)) { 24289b17223SAlexander Motin bioq_remove(&queue, cbp); 24389b17223SAlexander Motin sd = cbp->bio_caller1; 24489b17223SAlexander Motin cbp->bio_caller1 = NULL; 24589b17223SAlexander Motin g_raid_subdisk_iostart(sd, cbp); 24689b17223SAlexander Motin } 24789b17223SAlexander Motin return; 24889b17223SAlexander Motin failure: 24989b17223SAlexander Motin for (cbp = bioq_first(&queue); cbp != NULL; 25089b17223SAlexander Motin cbp = bioq_first(&queue)) { 25189b17223SAlexander Motin bioq_remove(&queue, cbp); 25289b17223SAlexander Motin g_destroy_bio(cbp); 25389b17223SAlexander Motin } 25489b17223SAlexander Motin if (bp->bio_error == 0) 25589b17223SAlexander Motin bp->bio_error = ENOMEM; 25689b17223SAlexander Motin g_raid_iodone(bp, bp->bio_error); 25789b17223SAlexander Motin } 25889b17223SAlexander Motin 25989b17223SAlexander Motin static int 26089b17223SAlexander Motin g_raid_tr_kerneldump_raid0(struct g_raid_tr_object *tr, 26189b17223SAlexander Motin void *virtual, vm_offset_t physical, off_t boffset, size_t blength) 26289b17223SAlexander Motin { 26389b17223SAlexander Motin struct g_raid_volume *vol; 26489b17223SAlexander Motin char *addr; 26589b17223SAlexander Motin off_t offset, start, length, nstripe, remain; 26689b17223SAlexander Motin u_int no, strip_size; 26789b17223SAlexander Motin int error; 26889b17223SAlexander Motin 26989b17223SAlexander Motin vol = tr->tro_volume; 27089b17223SAlexander Motin if (vol->v_state != G_RAID_VOLUME_S_OPTIMAL) 27189b17223SAlexander Motin return (ENXIO); 27289b17223SAlexander Motin addr = virtual; 27389b17223SAlexander Motin strip_size = vol->v_strip_size; 27489b17223SAlexander Motin 27589b17223SAlexander Motin /* Stripe number. */ 27689b17223SAlexander Motin nstripe = boffset / strip_size; 27789b17223SAlexander Motin /* Start position in stripe. */ 27889b17223SAlexander Motin start = boffset % strip_size; 27989b17223SAlexander Motin /* Disk number. */ 28089b17223SAlexander Motin no = nstripe % vol->v_disks_count; 28189b17223SAlexander Motin /* Stripe tart position in disk. */ 28289b17223SAlexander Motin offset = (nstripe / vol->v_disks_count) * strip_size; 28389b17223SAlexander Motin /* Length of data to operate. */ 28489b17223SAlexander Motin remain = blength; 28589b17223SAlexander Motin 28689b17223SAlexander Motin do { 28789b17223SAlexander Motin length = MIN(strip_size - start, remain); 28889b17223SAlexander Motin error = g_raid_subdisk_kerneldump(&vol->v_subdisks[no], 28989b17223SAlexander Motin addr, 0, offset + start, length); 29089b17223SAlexander Motin if (error != 0) 29189b17223SAlexander Motin return (error); 29289b17223SAlexander Motin if (++no >= vol->v_disks_count) { 29389b17223SAlexander Motin no = 0; 29489b17223SAlexander Motin offset += strip_size; 29589b17223SAlexander Motin } 29689b17223SAlexander Motin remain -= length; 29789b17223SAlexander Motin addr += length; 29889b17223SAlexander Motin start = 0; 29989b17223SAlexander Motin } while (remain > 0); 30089b17223SAlexander Motin return (0); 30189b17223SAlexander Motin } 30289b17223SAlexander Motin 30389b17223SAlexander Motin static void 30489b17223SAlexander Motin g_raid_tr_iodone_raid0(struct g_raid_tr_object *tr, 30589b17223SAlexander Motin struct g_raid_subdisk *sd,struct bio *bp) 30689b17223SAlexander Motin { 30789b17223SAlexander Motin struct bio *pbp; 30889b17223SAlexander Motin 30989b17223SAlexander Motin pbp = bp->bio_parent; 31089b17223SAlexander Motin if (pbp->bio_error == 0) 31189b17223SAlexander Motin pbp->bio_error = bp->bio_error; 31289b17223SAlexander Motin g_destroy_bio(bp); 31389b17223SAlexander Motin pbp->bio_inbed++; 31489b17223SAlexander Motin if (pbp->bio_children == pbp->bio_inbed) { 31589b17223SAlexander Motin pbp->bio_completed = pbp->bio_length; 31689b17223SAlexander Motin g_raid_iodone(pbp, bp->bio_error); 31789b17223SAlexander Motin } 31889b17223SAlexander Motin } 31989b17223SAlexander Motin 32089b17223SAlexander Motin static int 32189b17223SAlexander Motin g_raid_tr_free_raid0(struct g_raid_tr_object *tr) 32289b17223SAlexander Motin { 32389b17223SAlexander Motin 32489b17223SAlexander Motin return (0); 32589b17223SAlexander Motin } 32689b17223SAlexander Motin 327*c89d2fbeSAlexander Motin G_RAID_TR_DECLARE(raid0, "RAID0"); 328