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_CONCAT, "tr_concat_data", "GEOM_RAID CONCAT data"); 4489b17223SAlexander Motin 4589b17223SAlexander Motin struct g_raid_tr_concat_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_concat; 5289b17223SAlexander Motin static g_raid_tr_event_t g_raid_tr_event_concat; 5389b17223SAlexander Motin static g_raid_tr_start_t g_raid_tr_start_concat; 5489b17223SAlexander Motin static g_raid_tr_stop_t g_raid_tr_stop_concat; 5589b17223SAlexander Motin static g_raid_tr_iostart_t g_raid_tr_iostart_concat; 5689b17223SAlexander Motin static g_raid_tr_iodone_t g_raid_tr_iodone_concat; 5789b17223SAlexander Motin static g_raid_tr_kerneldump_t g_raid_tr_kerneldump_concat; 5889b17223SAlexander Motin static g_raid_tr_free_t g_raid_tr_free_concat; 5989b17223SAlexander Motin 6089b17223SAlexander Motin static kobj_method_t g_raid_tr_concat_methods[] = { 6189b17223SAlexander Motin KOBJMETHOD(g_raid_tr_taste, g_raid_tr_taste_concat), 6289b17223SAlexander Motin KOBJMETHOD(g_raid_tr_event, g_raid_tr_event_concat), 6389b17223SAlexander Motin KOBJMETHOD(g_raid_tr_start, g_raid_tr_start_concat), 6489b17223SAlexander Motin KOBJMETHOD(g_raid_tr_stop, g_raid_tr_stop_concat), 6589b17223SAlexander Motin KOBJMETHOD(g_raid_tr_iostart, g_raid_tr_iostart_concat), 6689b17223SAlexander Motin KOBJMETHOD(g_raid_tr_iodone, g_raid_tr_iodone_concat), 6789b17223SAlexander Motin KOBJMETHOD(g_raid_tr_kerneldump, g_raid_tr_kerneldump_concat), 6889b17223SAlexander Motin KOBJMETHOD(g_raid_tr_free, g_raid_tr_free_concat), 6989b17223SAlexander Motin { 0, 0 } 7089b17223SAlexander Motin }; 7189b17223SAlexander Motin 7289b17223SAlexander Motin static struct g_raid_tr_class g_raid_tr_concat_class = { 7389b17223SAlexander Motin "CONCAT", 7489b17223SAlexander Motin g_raid_tr_concat_methods, 7589b17223SAlexander Motin sizeof(struct g_raid_tr_concat_object), 76c89d2fbeSAlexander Motin .trc_enable = 1, 7789b17223SAlexander Motin .trc_priority = 50 7889b17223SAlexander Motin }; 7989b17223SAlexander Motin 8089b17223SAlexander Motin static int 8189b17223SAlexander Motin g_raid_tr_taste_concat(struct g_raid_tr_object *tr, struct g_raid_volume *volume) 8289b17223SAlexander Motin { 8389b17223SAlexander Motin struct g_raid_tr_concat_object *trs; 8489b17223SAlexander Motin 8589b17223SAlexander Motin trs = (struct g_raid_tr_concat_object *)tr; 8689b17223SAlexander Motin if (tr->tro_volume->v_raid_level != G_RAID_VOLUME_RL_SINGLE && 8789b17223SAlexander Motin tr->tro_volume->v_raid_level != G_RAID_VOLUME_RL_CONCAT && 8889b17223SAlexander Motin !(tr->tro_volume->v_disks_count == 1 && 8989b17223SAlexander Motin tr->tro_volume->v_raid_level != G_RAID_VOLUME_RL_UNKNOWN)) 9089b17223SAlexander Motin return (G_RAID_TR_TASTE_FAIL); 9189b17223SAlexander Motin trs->trso_starting = 1; 9289b17223SAlexander Motin return (G_RAID_TR_TASTE_SUCCEED); 9389b17223SAlexander Motin } 9489b17223SAlexander Motin 9589b17223SAlexander Motin static int 9689b17223SAlexander Motin g_raid_tr_update_state_concat(struct g_raid_volume *vol) 9789b17223SAlexander Motin { 9889b17223SAlexander Motin struct g_raid_tr_concat_object *trs; 9989b17223SAlexander Motin struct g_raid_softc *sc; 10089b17223SAlexander Motin off_t size; 10189b17223SAlexander Motin u_int s; 10289b17223SAlexander Motin int i, n, f; 10389b17223SAlexander Motin 10489b17223SAlexander Motin sc = vol->v_softc; 10589b17223SAlexander Motin trs = (struct g_raid_tr_concat_object *)vol->v_tr; 10689b17223SAlexander Motin if (trs->trso_stopped) 10789b17223SAlexander Motin s = G_RAID_VOLUME_S_STOPPED; 10889b17223SAlexander Motin else if (trs->trso_starting) 10989b17223SAlexander Motin s = G_RAID_VOLUME_S_STARTING; 11089b17223SAlexander Motin else { 11189b17223SAlexander Motin n = g_raid_nsubdisks(vol, G_RAID_SUBDISK_S_ACTIVE); 11289b17223SAlexander Motin f = g_raid_nsubdisks(vol, G_RAID_SUBDISK_S_FAILED); 11389b17223SAlexander Motin if (n + f == vol->v_disks_count) { 11489b17223SAlexander Motin if (f == 0) 11589b17223SAlexander Motin s = G_RAID_VOLUME_S_OPTIMAL; 11689b17223SAlexander Motin else 11789b17223SAlexander Motin s = G_RAID_VOLUME_S_SUBOPTIMAL; 11889b17223SAlexander Motin } else 11989b17223SAlexander Motin s = G_RAID_VOLUME_S_BROKEN; 12089b17223SAlexander Motin } 12189b17223SAlexander Motin if (s != vol->v_state) { 12289b17223SAlexander Motin 12389b17223SAlexander Motin /* 12489b17223SAlexander Motin * Some metadata modules may not know CONCAT volume 12589b17223SAlexander Motin * mediasize until all disks connected. Recalculate. 12689b17223SAlexander Motin */ 12789b17223SAlexander Motin if (G_RAID_VOLUME_S_ALIVE(s) && 12889b17223SAlexander Motin !G_RAID_VOLUME_S_ALIVE(vol->v_state)) { 12989b17223SAlexander Motin size = 0; 13089b17223SAlexander Motin for (i = 0; i < vol->v_disks_count; i++) { 13189b17223SAlexander Motin if (vol->v_subdisks[i].sd_state != 13289b17223SAlexander Motin G_RAID_SUBDISK_S_NONE) 13389b17223SAlexander Motin size += vol->v_subdisks[i].sd_size; 13489b17223SAlexander Motin } 13589b17223SAlexander Motin vol->v_mediasize = size; 13689b17223SAlexander Motin } 13789b17223SAlexander Motin 13889b17223SAlexander Motin g_raid_event_send(vol, G_RAID_VOLUME_S_ALIVE(s) ? 13989b17223SAlexander Motin G_RAID_VOLUME_E_UP : G_RAID_VOLUME_E_DOWN, 14089b17223SAlexander Motin G_RAID_EVENT_VOLUME); 14189b17223SAlexander Motin g_raid_change_volume_state(vol, s); 14289b17223SAlexander Motin if (!trs->trso_starting && !trs->trso_stopped) 14389b17223SAlexander Motin g_raid_write_metadata(sc, vol, NULL, NULL); 14489b17223SAlexander Motin } 14589b17223SAlexander Motin return (0); 14689b17223SAlexander Motin } 14789b17223SAlexander Motin 14889b17223SAlexander Motin static int 14989b17223SAlexander Motin g_raid_tr_event_concat(struct g_raid_tr_object *tr, 15089b17223SAlexander Motin struct g_raid_subdisk *sd, u_int event) 15189b17223SAlexander Motin { 15289b17223SAlexander Motin struct g_raid_tr_concat_object *trs; 15389b17223SAlexander Motin struct g_raid_softc *sc; 15489b17223SAlexander Motin struct g_raid_volume *vol; 15589b17223SAlexander Motin int state; 15689b17223SAlexander Motin 15789b17223SAlexander Motin trs = (struct g_raid_tr_concat_object *)tr; 15889b17223SAlexander Motin vol = tr->tro_volume; 15989b17223SAlexander Motin sc = vol->v_softc; 16089b17223SAlexander Motin 16189b17223SAlexander Motin state = sd->sd_state; 16289b17223SAlexander Motin if (state != G_RAID_SUBDISK_S_NONE && 16389b17223SAlexander Motin state != G_RAID_SUBDISK_S_FAILED && 16489b17223SAlexander Motin state != G_RAID_SUBDISK_S_ACTIVE) { 16589b17223SAlexander Motin G_RAID_DEBUG1(1, sc, 16689b17223SAlexander Motin "Promote subdisk %s:%d from %s to ACTIVE.", 16789b17223SAlexander Motin vol->v_name, sd->sd_pos, 16889b17223SAlexander Motin g_raid_subdisk_state2str(sd->sd_state)); 16989b17223SAlexander Motin g_raid_change_subdisk_state(sd, G_RAID_SUBDISK_S_ACTIVE); 17089b17223SAlexander Motin } 17189b17223SAlexander Motin if (state != sd->sd_state && 17289b17223SAlexander Motin !trs->trso_starting && !trs->trso_stopped) 17389b17223SAlexander Motin g_raid_write_metadata(sc, vol, sd, NULL); 17489b17223SAlexander Motin g_raid_tr_update_state_concat(vol); 17589b17223SAlexander Motin return (0); 17689b17223SAlexander Motin } 17789b17223SAlexander Motin 17889b17223SAlexander Motin static int 17989b17223SAlexander Motin g_raid_tr_start_concat(struct g_raid_tr_object *tr) 18089b17223SAlexander Motin { 18189b17223SAlexander Motin struct g_raid_tr_concat_object *trs; 18289b17223SAlexander Motin struct g_raid_volume *vol; 18389b17223SAlexander Motin 18489b17223SAlexander Motin trs = (struct g_raid_tr_concat_object *)tr; 18589b17223SAlexander Motin vol = tr->tro_volume; 18689b17223SAlexander Motin trs->trso_starting = 0; 18789b17223SAlexander Motin g_raid_tr_update_state_concat(vol); 18889b17223SAlexander Motin return (0); 18989b17223SAlexander Motin } 19089b17223SAlexander Motin 19189b17223SAlexander Motin static int 19289b17223SAlexander Motin g_raid_tr_stop_concat(struct g_raid_tr_object *tr) 19389b17223SAlexander Motin { 19489b17223SAlexander Motin struct g_raid_tr_concat_object *trs; 19589b17223SAlexander Motin struct g_raid_volume *vol; 19689b17223SAlexander Motin 19789b17223SAlexander Motin trs = (struct g_raid_tr_concat_object *)tr; 19889b17223SAlexander Motin vol = tr->tro_volume; 19989b17223SAlexander Motin trs->trso_starting = 0; 20089b17223SAlexander Motin trs->trso_stopped = 1; 20189b17223SAlexander Motin g_raid_tr_update_state_concat(vol); 20289b17223SAlexander Motin return (0); 20389b17223SAlexander Motin } 20489b17223SAlexander Motin 20589b17223SAlexander Motin static void 20689b17223SAlexander Motin g_raid_tr_iostart_concat(struct g_raid_tr_object *tr, struct bio *bp) 20789b17223SAlexander Motin { 20889b17223SAlexander Motin struct g_raid_volume *vol; 20989b17223SAlexander Motin struct g_raid_subdisk *sd; 21089b17223SAlexander Motin struct bio_queue_head queue; 21189b17223SAlexander Motin struct bio *cbp; 21289b17223SAlexander Motin char *addr; 21389b17223SAlexander Motin off_t offset, length, remain; 21489b17223SAlexander Motin u_int no; 21589b17223SAlexander Motin 21689b17223SAlexander Motin vol = tr->tro_volume; 21789b17223SAlexander Motin if (vol->v_state != G_RAID_VOLUME_S_OPTIMAL && 21889b17223SAlexander Motin vol->v_state != G_RAID_VOLUME_S_SUBOPTIMAL) { 21989b17223SAlexander Motin g_raid_iodone(bp, EIO); 22089b17223SAlexander Motin return; 22189b17223SAlexander Motin } 22289b17223SAlexander Motin if (bp->bio_cmd == BIO_FLUSH) { 22389b17223SAlexander Motin g_raid_tr_flush_common(tr, bp); 22489b17223SAlexander Motin return; 22589b17223SAlexander Motin } 22689b17223SAlexander Motin 22789b17223SAlexander Motin offset = bp->bio_offset; 22889b17223SAlexander Motin remain = bp->bio_length; 22989b17223SAlexander Motin addr = bp->bio_data; 23089b17223SAlexander Motin no = 0; 23189b17223SAlexander Motin while (no < vol->v_disks_count && 23289b17223SAlexander Motin offset >= vol->v_subdisks[no].sd_size) { 23389b17223SAlexander Motin offset -= vol->v_subdisks[no].sd_size; 23489b17223SAlexander Motin no++; 23589b17223SAlexander Motin } 23689b17223SAlexander Motin KASSERT(no < vol->v_disks_count, 23789b17223SAlexander Motin ("Request starts after volume end (%ju)", bp->bio_offset)); 23889b17223SAlexander Motin bioq_init(&queue); 23989b17223SAlexander Motin do { 24089b17223SAlexander Motin sd = &vol->v_subdisks[no]; 24189b17223SAlexander Motin length = MIN(sd->sd_size - offset, remain); 24289b17223SAlexander Motin cbp = g_clone_bio(bp); 24389b17223SAlexander Motin if (cbp == NULL) 24489b17223SAlexander Motin goto failure; 24589b17223SAlexander Motin cbp->bio_offset = offset; 24689b17223SAlexander Motin cbp->bio_data = addr; 24789b17223SAlexander Motin cbp->bio_length = length; 24889b17223SAlexander Motin cbp->bio_caller1 = sd; 24989b17223SAlexander Motin bioq_insert_tail(&queue, cbp); 25089b17223SAlexander Motin remain -= length; 251*609a7474SAlexander Motin if (bp->bio_cmd != BIO_DELETE) 25289b17223SAlexander Motin addr += length; 25389b17223SAlexander Motin offset = 0; 25489b17223SAlexander Motin no++; 25589b17223SAlexander Motin KASSERT(no < vol->v_disks_count || remain == 0, 25689b17223SAlexander Motin ("Request ends after volume end (%ju, %ju)", 25789b17223SAlexander Motin bp->bio_offset, bp->bio_length)); 25889b17223SAlexander Motin } while (remain > 0); 25989b17223SAlexander Motin for (cbp = bioq_first(&queue); cbp != NULL; 26089b17223SAlexander Motin cbp = bioq_first(&queue)) { 26189b17223SAlexander Motin bioq_remove(&queue, cbp); 26289b17223SAlexander Motin sd = cbp->bio_caller1; 26389b17223SAlexander Motin cbp->bio_caller1 = NULL; 26489b17223SAlexander Motin g_raid_subdisk_iostart(sd, cbp); 26589b17223SAlexander Motin } 26689b17223SAlexander Motin return; 26789b17223SAlexander Motin failure: 26889b17223SAlexander Motin for (cbp = bioq_first(&queue); cbp != NULL; 26989b17223SAlexander Motin cbp = bioq_first(&queue)) { 27089b17223SAlexander Motin bioq_remove(&queue, cbp); 27189b17223SAlexander Motin g_destroy_bio(cbp); 27289b17223SAlexander Motin } 27389b17223SAlexander Motin if (bp->bio_error == 0) 27489b17223SAlexander Motin bp->bio_error = ENOMEM; 27589b17223SAlexander Motin g_raid_iodone(bp, bp->bio_error); 27689b17223SAlexander Motin } 27789b17223SAlexander Motin 27889b17223SAlexander Motin static int 27989b17223SAlexander Motin g_raid_tr_kerneldump_concat(struct g_raid_tr_object *tr, 28089b17223SAlexander Motin void *virtual, vm_offset_t physical, off_t boffset, size_t blength) 28189b17223SAlexander Motin { 28289b17223SAlexander Motin struct g_raid_volume *vol; 28389b17223SAlexander Motin struct g_raid_subdisk *sd; 28489b17223SAlexander Motin char *addr; 28589b17223SAlexander Motin off_t offset, length, remain; 28689b17223SAlexander Motin int error, no; 28789b17223SAlexander Motin 28889b17223SAlexander Motin vol = tr->tro_volume; 28989b17223SAlexander Motin if (vol->v_state != G_RAID_VOLUME_S_OPTIMAL) 29089b17223SAlexander Motin return (ENXIO); 29189b17223SAlexander Motin 29289b17223SAlexander Motin offset = boffset; 29389b17223SAlexander Motin remain = blength; 29489b17223SAlexander Motin addr = virtual; 29589b17223SAlexander Motin no = 0; 29689b17223SAlexander Motin while (no < vol->v_disks_count && 29789b17223SAlexander Motin offset >= vol->v_subdisks[no].sd_size) { 29889b17223SAlexander Motin offset -= vol->v_subdisks[no].sd_size; 29989b17223SAlexander Motin no++; 30089b17223SAlexander Motin } 30189b17223SAlexander Motin KASSERT(no < vol->v_disks_count, 30289b17223SAlexander Motin ("Request starts after volume end (%ju)", boffset)); 30389b17223SAlexander Motin do { 30489b17223SAlexander Motin sd = &vol->v_subdisks[no]; 30589b17223SAlexander Motin length = MIN(sd->sd_size - offset, remain); 30689b17223SAlexander Motin error = g_raid_subdisk_kerneldump(&vol->v_subdisks[no], 30789b17223SAlexander Motin addr, 0, offset, length); 30889b17223SAlexander Motin if (error != 0) 30989b17223SAlexander Motin return (error); 31089b17223SAlexander Motin remain -= length; 31189b17223SAlexander Motin addr += length; 31289b17223SAlexander Motin offset = 0; 31389b17223SAlexander Motin no++; 31489b17223SAlexander Motin KASSERT(no < vol->v_disks_count || remain == 0, 31589b17223SAlexander Motin ("Request ends after volume end (%ju, %zu)", 31689b17223SAlexander Motin boffset, blength)); 31789b17223SAlexander Motin } while (remain > 0); 31889b17223SAlexander Motin return (0); 31989b17223SAlexander Motin } 32089b17223SAlexander Motin 32189b17223SAlexander Motin static void 32289b17223SAlexander Motin g_raid_tr_iodone_concat(struct g_raid_tr_object *tr, 32389b17223SAlexander Motin struct g_raid_subdisk *sd,struct bio *bp) 32489b17223SAlexander Motin { 32589b17223SAlexander Motin struct bio *pbp; 32689b17223SAlexander Motin 32789b17223SAlexander Motin pbp = bp->bio_parent; 32889b17223SAlexander Motin if (pbp->bio_error == 0) 32989b17223SAlexander Motin pbp->bio_error = bp->bio_error; 33089b17223SAlexander Motin g_destroy_bio(bp); 33189b17223SAlexander Motin pbp->bio_inbed++; 33289b17223SAlexander Motin if (pbp->bio_children == pbp->bio_inbed) { 33389b17223SAlexander Motin pbp->bio_completed = pbp->bio_length; 33489b17223SAlexander Motin g_raid_iodone(pbp, bp->bio_error); 33589b17223SAlexander Motin } 33689b17223SAlexander Motin } 33789b17223SAlexander Motin 33889b17223SAlexander Motin static int 33989b17223SAlexander Motin g_raid_tr_free_concat(struct g_raid_tr_object *tr) 34089b17223SAlexander Motin { 34189b17223SAlexander Motin 34289b17223SAlexander Motin return (0); 34389b17223SAlexander Motin } 34489b17223SAlexander Motin 345c89d2fbeSAlexander Motin G_RAID_TR_DECLARE(concat, "CONCAT"); 346