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