1b09121f9SPawel Jakub Dawidek /*- 2b09121f9SPawel Jakub Dawidek * Copyright (c) 2003 Pawel Jakub Dawidek <pjd@FreeBSD.org> 3b09121f9SPawel Jakub Dawidek * All rights reserved. 4b09121f9SPawel Jakub Dawidek * 5b09121f9SPawel Jakub Dawidek * Redistribution and use in source and binary forms, with or without 6b09121f9SPawel Jakub Dawidek * modification, are permitted provided that the following conditions 7b09121f9SPawel Jakub Dawidek * are met: 8b09121f9SPawel Jakub Dawidek * 1. Redistributions of source code must retain the above copyright 9b09121f9SPawel Jakub Dawidek * notice, this list of conditions and the following disclaimer. 10b09121f9SPawel Jakub Dawidek * 2. Redistributions in binary form must reproduce the above copyright 11b09121f9SPawel Jakub Dawidek * notice, this list of conditions and the following disclaimer in the 12b09121f9SPawel Jakub Dawidek * documentation and/or other materials provided with the distribution. 13b09121f9SPawel Jakub Dawidek * 14b09121f9SPawel Jakub Dawidek * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 15b09121f9SPawel Jakub Dawidek * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16b09121f9SPawel Jakub Dawidek * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17b09121f9SPawel Jakub Dawidek * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 18b09121f9SPawel Jakub Dawidek * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19b09121f9SPawel Jakub Dawidek * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20b09121f9SPawel Jakub Dawidek * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21b09121f9SPawel Jakub Dawidek * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22b09121f9SPawel Jakub Dawidek * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23b09121f9SPawel Jakub Dawidek * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24b09121f9SPawel Jakub Dawidek * SUCH DAMAGE. 25b09121f9SPawel Jakub Dawidek */ 26b09121f9SPawel Jakub Dawidek 27b09121f9SPawel Jakub Dawidek #include <sys/cdefs.h> 28b09121f9SPawel Jakub Dawidek __FBSDID("$FreeBSD$"); 29b09121f9SPawel Jakub Dawidek 30b09121f9SPawel Jakub Dawidek #include <sys/param.h> 31b09121f9SPawel Jakub Dawidek #include <sys/systm.h> 32b09121f9SPawel Jakub Dawidek #include <sys/kernel.h> 33b09121f9SPawel Jakub Dawidek #include <sys/module.h> 34b09121f9SPawel Jakub Dawidek #include <sys/lock.h> 35b09121f9SPawel Jakub Dawidek #include <sys/mutex.h> 36b09121f9SPawel Jakub Dawidek #include <sys/bio.h> 37b09121f9SPawel Jakub Dawidek #include <sys/sysctl.h> 38b09121f9SPawel Jakub Dawidek #include <sys/malloc.h> 394c55f05bSPawel Jakub Dawidek #include <vm/uma.h> 40b09121f9SPawel Jakub Dawidek #include <geom/geom.h> 41b09121f9SPawel Jakub Dawidek #include <geom/stripe/g_stripe.h> 42b09121f9SPawel Jakub Dawidek 43b09121f9SPawel Jakub Dawidek 444c55f05bSPawel Jakub Dawidek #define MAX_IO_SIZE (DFLTPHYS * 2) 45b09121f9SPawel Jakub Dawidek static MALLOC_DEFINE(M_STRIPE, "stripe data", "GEOM_STRIPE Data"); 46b09121f9SPawel Jakub Dawidek 474c55f05bSPawel Jakub Dawidek static uma_zone_t g_stripe_zone; 48b09121f9SPawel Jakub Dawidek 49b09121f9SPawel Jakub Dawidek static int g_stripe_destroy(struct g_stripe_softc *sc, boolean_t force); 50b09121f9SPawel Jakub Dawidek static int g_stripe_destroy_geom(struct gctl_req *req, struct g_class *mp, 51b09121f9SPawel Jakub Dawidek struct g_geom *gp); 52b09121f9SPawel Jakub Dawidek 53b09121f9SPawel Jakub Dawidek static g_taste_t g_stripe_taste; 54b09121f9SPawel Jakub Dawidek static g_ctl_req_t g_stripe_config; 55b09121f9SPawel Jakub Dawidek static g_dumpconf_t g_stripe_dumpconf; 564c55f05bSPawel Jakub Dawidek static g_init_t g_stripe_init; 574c55f05bSPawel Jakub Dawidek static g_fini_t g_stripe_fini; 58b09121f9SPawel Jakub Dawidek 59b09121f9SPawel Jakub Dawidek struct g_class g_stripe_class = { 60b09121f9SPawel Jakub Dawidek .name = G_STRIPE_CLASS_NAME, 61b09121f9SPawel Jakub Dawidek .ctlreq = g_stripe_config, 62b09121f9SPawel Jakub Dawidek .taste = g_stripe_taste, 634c55f05bSPawel Jakub Dawidek .destroy_geom = g_stripe_destroy_geom, 644c55f05bSPawel Jakub Dawidek .init = g_stripe_init, 654c55f05bSPawel Jakub Dawidek .fini = g_stripe_fini 66b09121f9SPawel Jakub Dawidek }; 67b09121f9SPawel Jakub Dawidek 684c55f05bSPawel Jakub Dawidek SYSCTL_DECL(_kern_geom); 694c55f05bSPawel Jakub Dawidek SYSCTL_NODE(_kern_geom, OID_AUTO, stripe, CTLFLAG_RW, 0, "GEOM_STRIPE stuff"); 704c55f05bSPawel Jakub Dawidek static u_int g_stripe_debug = 0; 714c55f05bSPawel Jakub Dawidek SYSCTL_UINT(_kern_geom_stripe, OID_AUTO, debug, CTLFLAG_RW, &g_stripe_debug, 0, 724c55f05bSPawel Jakub Dawidek "Debug level"); 734c55f05bSPawel Jakub Dawidek static int g_stripe_fast = 1; 744c55f05bSPawel Jakub Dawidek TUNABLE_INT("kern.geom.stripe.fast", &g_stripe_fast); 754c55f05bSPawel Jakub Dawidek static int 764c55f05bSPawel Jakub Dawidek g_sysctl_stripe_fast(SYSCTL_HANDLER_ARGS) 774c55f05bSPawel Jakub Dawidek { 784c55f05bSPawel Jakub Dawidek int error, fast; 794c55f05bSPawel Jakub Dawidek 804c55f05bSPawel Jakub Dawidek fast = g_stripe_fast; 814c55f05bSPawel Jakub Dawidek error = sysctl_handle_int(oidp, &fast, sizeof(fast), req); 824c55f05bSPawel Jakub Dawidek if (error == 0 && req->newptr != NULL) 834c55f05bSPawel Jakub Dawidek g_stripe_fast = fast; 844c55f05bSPawel Jakub Dawidek return (error); 854c55f05bSPawel Jakub Dawidek } 864c55f05bSPawel Jakub Dawidek SYSCTL_PROC(_kern_geom_stripe, OID_AUTO, fast, CTLTYPE_INT | CTLFLAG_RW, 8771df0725SPawel Jakub Dawidek NULL, 0, g_sysctl_stripe_fast, "I", "Fast, but memory-consuming, mode"); 884c55f05bSPawel Jakub Dawidek static u_int g_stripe_maxmem = MAX_IO_SIZE * 10; 894c55f05bSPawel Jakub Dawidek TUNABLE_INT("kern.geom.stripe.maxmem", &g_stripe_maxmem); 904c55f05bSPawel Jakub Dawidek SYSCTL_UINT(_kern_geom_stripe, OID_AUTO, maxmem, CTLFLAG_RD, &g_stripe_maxmem, 9171df0725SPawel Jakub Dawidek 0, "Maximum memory that can be allocated in \"fast\" mode (in bytes)"); 92cea36368SPawel Jakub Dawidek static u_int g_stripe_fast_failed = 0; 93cea36368SPawel Jakub Dawidek SYSCTL_UINT(_kern_geom_stripe, OID_AUTO, fast_failed, CTLFLAG_RD, 94cea36368SPawel Jakub Dawidek &g_stripe_fast_failed, 0, "How many times \"fast\" mode failed"); 95b09121f9SPawel Jakub Dawidek 96b09121f9SPawel Jakub Dawidek /* 97b09121f9SPawel Jakub Dawidek * Greatest Common Divisor. 98b09121f9SPawel Jakub Dawidek */ 99b09121f9SPawel Jakub Dawidek static u_int 100b09121f9SPawel Jakub Dawidek gcd(u_int a, u_int b) 101b09121f9SPawel Jakub Dawidek { 102b09121f9SPawel Jakub Dawidek u_int c; 103b09121f9SPawel Jakub Dawidek 104b09121f9SPawel Jakub Dawidek while (b != 0) { 105b09121f9SPawel Jakub Dawidek c = a; 106b09121f9SPawel Jakub Dawidek a = b; 107b09121f9SPawel Jakub Dawidek b = (c % b); 108b09121f9SPawel Jakub Dawidek } 109b09121f9SPawel Jakub Dawidek return (a); 110b09121f9SPawel Jakub Dawidek } 111b09121f9SPawel Jakub Dawidek 112b09121f9SPawel Jakub Dawidek /* 113b09121f9SPawel Jakub Dawidek * Least Common Multiple. 114b09121f9SPawel Jakub Dawidek */ 115b09121f9SPawel Jakub Dawidek static u_int 116b09121f9SPawel Jakub Dawidek lcm(u_int a, u_int b) 117b09121f9SPawel Jakub Dawidek { 118b09121f9SPawel Jakub Dawidek 119b09121f9SPawel Jakub Dawidek return ((a * b) / gcd(a, b)); 120b09121f9SPawel Jakub Dawidek } 121b09121f9SPawel Jakub Dawidek 1224c55f05bSPawel Jakub Dawidek static void 1234c55f05bSPawel Jakub Dawidek g_stripe_init(struct g_class *mp __unused) 1244c55f05bSPawel Jakub Dawidek { 1254c55f05bSPawel Jakub Dawidek 1264c55f05bSPawel Jakub Dawidek g_stripe_zone = uma_zcreate("g_stripe_zone", MAX_IO_SIZE, NULL, NULL, 1274c55f05bSPawel Jakub Dawidek NULL, NULL, 0, 0); 1284c55f05bSPawel Jakub Dawidek g_stripe_maxmem -= g_stripe_maxmem % MAX_IO_SIZE; 1294c55f05bSPawel Jakub Dawidek uma_zone_set_max(g_stripe_zone, g_stripe_maxmem / MAX_IO_SIZE); 1304c55f05bSPawel Jakub Dawidek } 1314c55f05bSPawel Jakub Dawidek 1324c55f05bSPawel Jakub Dawidek static void 1334c55f05bSPawel Jakub Dawidek g_stripe_fini(struct g_class *mp __unused) 1344c55f05bSPawel Jakub Dawidek { 1354c55f05bSPawel Jakub Dawidek 1364c55f05bSPawel Jakub Dawidek uma_zdestroy(g_stripe_zone); 1374c55f05bSPawel Jakub Dawidek } 1384c55f05bSPawel Jakub Dawidek 139b09121f9SPawel Jakub Dawidek /* 140b09121f9SPawel Jakub Dawidek * Return the number of valid disks. 141b09121f9SPawel Jakub Dawidek */ 142b09121f9SPawel Jakub Dawidek static u_int 143b09121f9SPawel Jakub Dawidek g_stripe_nvalid(struct g_stripe_softc *sc) 144b09121f9SPawel Jakub Dawidek { 145b09121f9SPawel Jakub Dawidek u_int i, no; 146b09121f9SPawel Jakub Dawidek 147b09121f9SPawel Jakub Dawidek no = 0; 148b09121f9SPawel Jakub Dawidek for (i = 0; i < sc->sc_ndisks; i++) { 149b09121f9SPawel Jakub Dawidek if (sc->sc_disks[i] != NULL) 150b09121f9SPawel Jakub Dawidek no++; 151b09121f9SPawel Jakub Dawidek } 152b09121f9SPawel Jakub Dawidek 153b09121f9SPawel Jakub Dawidek return (no); 154b09121f9SPawel Jakub Dawidek } 155b09121f9SPawel Jakub Dawidek 156b09121f9SPawel Jakub Dawidek static void 157b09121f9SPawel Jakub Dawidek g_stripe_remove_disk(struct g_consumer *cp) 158b09121f9SPawel Jakub Dawidek { 159b09121f9SPawel Jakub Dawidek struct g_stripe_softc *sc; 160b09121f9SPawel Jakub Dawidek u_int no; 161b09121f9SPawel Jakub Dawidek 162b09121f9SPawel Jakub Dawidek KASSERT(cp != NULL, ("Non-valid disk in %s.", __func__)); 163b09121f9SPawel Jakub Dawidek sc = (struct g_stripe_softc *)cp->private; 164b09121f9SPawel Jakub Dawidek KASSERT(sc != NULL, ("NULL sc in %s.", __func__)); 165b09121f9SPawel Jakub Dawidek no = cp->index; 166b09121f9SPawel Jakub Dawidek 167b09121f9SPawel Jakub Dawidek G_STRIPE_DEBUG(0, "Disk %s removed from %s.", cp->provider->name, 168889c5dc2SPawel Jakub Dawidek sc->sc_name); 169b09121f9SPawel Jakub Dawidek 170b09121f9SPawel Jakub Dawidek sc->sc_disks[no] = NULL; 171b09121f9SPawel Jakub Dawidek if (sc->sc_provider != NULL) { 172b09121f9SPawel Jakub Dawidek g_orphan_provider(sc->sc_provider, ENXIO); 173b09121f9SPawel Jakub Dawidek sc->sc_provider = NULL; 174889c5dc2SPawel Jakub Dawidek G_STRIPE_DEBUG(0, "Device %s removed.", sc->sc_name); 175b09121f9SPawel Jakub Dawidek } 176b09121f9SPawel Jakub Dawidek 177b09121f9SPawel Jakub Dawidek if (cp->acr > 0 || cp->acw > 0 || cp->ace > 0) 178b09121f9SPawel Jakub Dawidek g_access(cp, -cp->acr, -cp->acw, -cp->ace); 179b09121f9SPawel Jakub Dawidek g_detach(cp); 180b09121f9SPawel Jakub Dawidek g_destroy_consumer(cp); 181b09121f9SPawel Jakub Dawidek } 182b09121f9SPawel Jakub Dawidek 183b09121f9SPawel Jakub Dawidek static void 184b09121f9SPawel Jakub Dawidek g_stripe_orphan(struct g_consumer *cp) 185b09121f9SPawel Jakub Dawidek { 186b09121f9SPawel Jakub Dawidek struct g_stripe_softc *sc; 187b09121f9SPawel Jakub Dawidek struct g_geom *gp; 188b09121f9SPawel Jakub Dawidek 189b09121f9SPawel Jakub Dawidek g_topology_assert(); 190b09121f9SPawel Jakub Dawidek gp = cp->geom; 191b09121f9SPawel Jakub Dawidek sc = gp->softc; 192b09121f9SPawel Jakub Dawidek if (sc == NULL) 193b09121f9SPawel Jakub Dawidek return; 194b09121f9SPawel Jakub Dawidek 195b09121f9SPawel Jakub Dawidek g_stripe_remove_disk(cp); 196b09121f9SPawel Jakub Dawidek /* If there are no valid disks anymore, remove device. */ 197b09121f9SPawel Jakub Dawidek if (g_stripe_nvalid(sc) == 0) 198b09121f9SPawel Jakub Dawidek g_stripe_destroy(sc, 1); 199b09121f9SPawel Jakub Dawidek } 200b09121f9SPawel Jakub Dawidek 201b09121f9SPawel Jakub Dawidek static int 202b09121f9SPawel Jakub Dawidek g_stripe_access(struct g_provider *pp, int dr, int dw, int de) 203b09121f9SPawel Jakub Dawidek { 204b09121f9SPawel Jakub Dawidek struct g_consumer *cp1, *cp2; 205b09121f9SPawel Jakub Dawidek struct g_stripe_softc *sc; 206b09121f9SPawel Jakub Dawidek struct g_geom *gp; 207b09121f9SPawel Jakub Dawidek int error; 208b09121f9SPawel Jakub Dawidek 209b09121f9SPawel Jakub Dawidek gp = pp->geom; 210b09121f9SPawel Jakub Dawidek sc = gp->softc; 211b09121f9SPawel Jakub Dawidek 212b09121f9SPawel Jakub Dawidek if (sc == NULL) { 213b09121f9SPawel Jakub Dawidek /* 214b09121f9SPawel Jakub Dawidek * It looks like geom is being withered. 215b09121f9SPawel Jakub Dawidek * In that case we allow only negative requests. 216b09121f9SPawel Jakub Dawidek */ 217b09121f9SPawel Jakub Dawidek KASSERT(dr <= 0 && dw <= 0 && de <= 0, 218b09121f9SPawel Jakub Dawidek ("Positive access request (device=%s).", pp->name)); 219b09121f9SPawel Jakub Dawidek if ((pp->acr + dr) == 0 && (pp->acw + dw) == 0 && 220b09121f9SPawel Jakub Dawidek (pp->ace + de) == 0) { 221b09121f9SPawel Jakub Dawidek G_STRIPE_DEBUG(0, "Device %s definitely destroyed.", 222b09121f9SPawel Jakub Dawidek gp->name); 223b09121f9SPawel Jakub Dawidek } 224b09121f9SPawel Jakub Dawidek return (0); 225b09121f9SPawel Jakub Dawidek } 226b09121f9SPawel Jakub Dawidek 227b09121f9SPawel Jakub Dawidek /* On first open, grab an extra "exclusive" bit */ 228b09121f9SPawel Jakub Dawidek if (pp->acr == 0 && pp->acw == 0 && pp->ace == 0) 229b09121f9SPawel Jakub Dawidek de++; 230b09121f9SPawel Jakub Dawidek /* ... and let go of it on last close */ 231b09121f9SPawel Jakub Dawidek if ((pp->acr + dr) == 0 && (pp->acw + dw) == 0 && (pp->ace + de) == 0) 232b09121f9SPawel Jakub Dawidek de--; 233b09121f9SPawel Jakub Dawidek 234b09121f9SPawel Jakub Dawidek error = ENXIO; 235b09121f9SPawel Jakub Dawidek LIST_FOREACH(cp1, &gp->consumer, consumer) { 236b09121f9SPawel Jakub Dawidek error = g_access(cp1, dr, dw, de); 237b09121f9SPawel Jakub Dawidek if (error == 0) 238b09121f9SPawel Jakub Dawidek continue; 239b09121f9SPawel Jakub Dawidek /* 240b09121f9SPawel Jakub Dawidek * If we fail here, backout all previous changes. 241b09121f9SPawel Jakub Dawidek */ 242b09121f9SPawel Jakub Dawidek LIST_FOREACH(cp2, &gp->consumer, consumer) { 243b09121f9SPawel Jakub Dawidek if (cp1 == cp2) 244b09121f9SPawel Jakub Dawidek return (error); 245b09121f9SPawel Jakub Dawidek g_access(cp2, -dr, -dw, -de); 246b09121f9SPawel Jakub Dawidek } 247b09121f9SPawel Jakub Dawidek /* NOTREACHED */ 248b09121f9SPawel Jakub Dawidek } 249b09121f9SPawel Jakub Dawidek 250b09121f9SPawel Jakub Dawidek return (error); 251b09121f9SPawel Jakub Dawidek } 252b09121f9SPawel Jakub Dawidek 253b09121f9SPawel Jakub Dawidek static void 2544c55f05bSPawel Jakub Dawidek g_stripe_copy(struct g_stripe_softc *sc, char *src, char *dst, off_t offset, 2554c55f05bSPawel Jakub Dawidek off_t length, int mode) 2564c55f05bSPawel Jakub Dawidek { 2574c55f05bSPawel Jakub Dawidek u_int stripesize; 2584c55f05bSPawel Jakub Dawidek size_t len; 2594c55f05bSPawel Jakub Dawidek 2604c55f05bSPawel Jakub Dawidek stripesize = sc->sc_stripesize; 2614c55f05bSPawel Jakub Dawidek len = (size_t)(stripesize - (offset & (stripesize - 1))); 2624c55f05bSPawel Jakub Dawidek do { 2634c55f05bSPawel Jakub Dawidek bcopy(src, dst, len); 2644c55f05bSPawel Jakub Dawidek if (mode) { 2654c55f05bSPawel Jakub Dawidek dst += len + stripesize * (sc->sc_ndisks - 1); 2664c55f05bSPawel Jakub Dawidek src += len; 2674c55f05bSPawel Jakub Dawidek } else { 2684c55f05bSPawel Jakub Dawidek dst += len; 2694c55f05bSPawel Jakub Dawidek src += len + stripesize * (sc->sc_ndisks - 1); 2704c55f05bSPawel Jakub Dawidek } 2714c55f05bSPawel Jakub Dawidek length -= len; 2724c55f05bSPawel Jakub Dawidek KASSERT(length >= 0, 2734c55f05bSPawel Jakub Dawidek ("Length < 0 (stripesize=%zu, offset=%jd, length=%jd).", 2744c55f05bSPawel Jakub Dawidek (size_t)stripesize, (intmax_t)offset, (intmax_t)length)); 2754c55f05bSPawel Jakub Dawidek if (length > stripesize) 2764c55f05bSPawel Jakub Dawidek len = stripesize; 2774c55f05bSPawel Jakub Dawidek else 2784c55f05bSPawel Jakub Dawidek len = length; 2794c55f05bSPawel Jakub Dawidek } while (length > 0); 2804c55f05bSPawel Jakub Dawidek } 2814c55f05bSPawel Jakub Dawidek 2824c55f05bSPawel Jakub Dawidek static void 2834c55f05bSPawel Jakub Dawidek g_stripe_done(struct bio *bp) 2844c55f05bSPawel Jakub Dawidek { 2854c55f05bSPawel Jakub Dawidek struct g_stripe_softc *sc; 2864c55f05bSPawel Jakub Dawidek struct bio *pbp; 2874c55f05bSPawel Jakub Dawidek 2884c55f05bSPawel Jakub Dawidek pbp = bp->bio_parent; 2894c55f05bSPawel Jakub Dawidek sc = pbp->bio_to->geom->softc; 2904c55f05bSPawel Jakub Dawidek if (pbp->bio_error == 0) 2914c55f05bSPawel Jakub Dawidek pbp->bio_error = bp->bio_error; 2924c55f05bSPawel Jakub Dawidek pbp->bio_completed += bp->bio_completed; 293ec704301SPawel Jakub Dawidek if (bp->bio_cmd == BIO_READ && bp->bio_caller1 != NULL) { 294ec704301SPawel Jakub Dawidek g_stripe_copy(sc, bp->bio_data, bp->bio_caller1, bp->bio_offset, 2954c55f05bSPawel Jakub Dawidek bp->bio_length, 1); 296ec704301SPawel Jakub Dawidek bp->bio_data = bp->bio_caller1; 297ec704301SPawel Jakub Dawidek bp->bio_caller1 = NULL; 2984c55f05bSPawel Jakub Dawidek } 2994c55f05bSPawel Jakub Dawidek g_destroy_bio(bp); 3004c55f05bSPawel Jakub Dawidek pbp->bio_inbed++; 3014c55f05bSPawel Jakub Dawidek if (pbp->bio_children == pbp->bio_inbed) { 302ec704301SPawel Jakub Dawidek if (pbp->bio_driver1 != NULL) 303ec704301SPawel Jakub Dawidek uma_zfree(g_stripe_zone, pbp->bio_driver1); 3044c55f05bSPawel Jakub Dawidek g_io_deliver(pbp, pbp->bio_error); 3054c55f05bSPawel Jakub Dawidek } 3064c55f05bSPawel Jakub Dawidek } 3074c55f05bSPawel Jakub Dawidek 3084c55f05bSPawel Jakub Dawidek static int 3094c55f05bSPawel Jakub Dawidek g_stripe_start_fast(struct bio *bp, u_int no, off_t offset, off_t length) 3104c55f05bSPawel Jakub Dawidek { 3114c55f05bSPawel Jakub Dawidek TAILQ_HEAD(, bio) queue = TAILQ_HEAD_INITIALIZER(queue); 3124c55f05bSPawel Jakub Dawidek u_int nparts = 0, stripesize; 3134c55f05bSPawel Jakub Dawidek struct g_stripe_softc *sc; 3144c55f05bSPawel Jakub Dawidek char *addr, *data = NULL; 3154c55f05bSPawel Jakub Dawidek struct bio *cbp; 3164c55f05bSPawel Jakub Dawidek int error; 3174c55f05bSPawel Jakub Dawidek 3184c55f05bSPawel Jakub Dawidek sc = bp->bio_to->geom->softc; 3194c55f05bSPawel Jakub Dawidek 3204c55f05bSPawel Jakub Dawidek addr = bp->bio_data; 3214c55f05bSPawel Jakub Dawidek stripesize = sc->sc_stripesize; 3224c55f05bSPawel Jakub Dawidek 3234c55f05bSPawel Jakub Dawidek cbp = g_clone_bio(bp); 3244c55f05bSPawel Jakub Dawidek if (cbp == NULL) { 3254c55f05bSPawel Jakub Dawidek error = ENOMEM; 3264c55f05bSPawel Jakub Dawidek goto failure; 3274c55f05bSPawel Jakub Dawidek } 3284c55f05bSPawel Jakub Dawidek TAILQ_INSERT_TAIL(&queue, cbp, bio_queue); 3294c55f05bSPawel Jakub Dawidek nparts++; 3304c55f05bSPawel Jakub Dawidek /* 3314c55f05bSPawel Jakub Dawidek * Fill in the component buf structure. 3324c55f05bSPawel Jakub Dawidek */ 3334c55f05bSPawel Jakub Dawidek cbp->bio_done = g_stripe_done; 3344c55f05bSPawel Jakub Dawidek cbp->bio_offset = offset; 3354c55f05bSPawel Jakub Dawidek cbp->bio_data = addr; 336ec704301SPawel Jakub Dawidek cbp->bio_caller1 = NULL; 3374c55f05bSPawel Jakub Dawidek cbp->bio_length = length; 338ec704301SPawel Jakub Dawidek cbp->bio_caller2 = sc->sc_disks[no]; 3394c55f05bSPawel Jakub Dawidek 3404c55f05bSPawel Jakub Dawidek /* offset -= offset % stripesize; */ 3414c55f05bSPawel Jakub Dawidek offset -= offset & (stripesize - 1); 3424c55f05bSPawel Jakub Dawidek addr += length; 3434c55f05bSPawel Jakub Dawidek length = bp->bio_length - length; 3444c55f05bSPawel Jakub Dawidek for (no++; length > 0; no++, length -= stripesize, addr += stripesize) { 3454c55f05bSPawel Jakub Dawidek if (no > sc->sc_ndisks - 1) { 3464c55f05bSPawel Jakub Dawidek no = 0; 3474c55f05bSPawel Jakub Dawidek offset += stripesize; 3484c55f05bSPawel Jakub Dawidek } 3494c55f05bSPawel Jakub Dawidek if (nparts >= sc->sc_ndisks) { 3504c55f05bSPawel Jakub Dawidek cbp = TAILQ_NEXT(cbp, bio_queue); 3514c55f05bSPawel Jakub Dawidek if (cbp == NULL) 3524c55f05bSPawel Jakub Dawidek cbp = TAILQ_FIRST(&queue); 3534c55f05bSPawel Jakub Dawidek nparts++; 3544c55f05bSPawel Jakub Dawidek /* 3554c55f05bSPawel Jakub Dawidek * Update bio structure. 3564c55f05bSPawel Jakub Dawidek */ 3574c55f05bSPawel Jakub Dawidek /* 3584c55f05bSPawel Jakub Dawidek * MIN() is in case when 3594c55f05bSPawel Jakub Dawidek * (bp->bio_length % sc->sc_stripesize) != 0. 3604c55f05bSPawel Jakub Dawidek */ 3614c55f05bSPawel Jakub Dawidek cbp->bio_length += MIN(stripesize, length); 362ec704301SPawel Jakub Dawidek if (cbp->bio_caller1 == NULL) { 363ec704301SPawel Jakub Dawidek cbp->bio_caller1 = cbp->bio_data; 3644c55f05bSPawel Jakub Dawidek cbp->bio_data = NULL; 3654c55f05bSPawel Jakub Dawidek if (data == NULL) { 3664c55f05bSPawel Jakub Dawidek data = uma_zalloc(g_stripe_zone, 3674c55f05bSPawel Jakub Dawidek M_NOWAIT); 3684c55f05bSPawel Jakub Dawidek if (data == NULL) { 3694c55f05bSPawel Jakub Dawidek error = ENOMEM; 3704c55f05bSPawel Jakub Dawidek goto failure; 3714c55f05bSPawel Jakub Dawidek } 3724c55f05bSPawel Jakub Dawidek } 3734c55f05bSPawel Jakub Dawidek } 3744c55f05bSPawel Jakub Dawidek } else { 3754c55f05bSPawel Jakub Dawidek cbp = g_clone_bio(bp); 3764c55f05bSPawel Jakub Dawidek if (cbp == NULL) { 3774c55f05bSPawel Jakub Dawidek error = ENOMEM; 3784c55f05bSPawel Jakub Dawidek goto failure; 3794c55f05bSPawel Jakub Dawidek } 3804c55f05bSPawel Jakub Dawidek TAILQ_INSERT_TAIL(&queue, cbp, bio_queue); 3814c55f05bSPawel Jakub Dawidek nparts++; 3824c55f05bSPawel Jakub Dawidek /* 3834c55f05bSPawel Jakub Dawidek * Fill in the component buf structure. 3844c55f05bSPawel Jakub Dawidek */ 3854c55f05bSPawel Jakub Dawidek cbp->bio_done = g_stripe_done; 3864c55f05bSPawel Jakub Dawidek cbp->bio_offset = offset; 3874c55f05bSPawel Jakub Dawidek cbp->bio_data = addr; 388ec704301SPawel Jakub Dawidek cbp->bio_caller1 = NULL; 3894c55f05bSPawel Jakub Dawidek /* 3904c55f05bSPawel Jakub Dawidek * MIN() is in case when 3914c55f05bSPawel Jakub Dawidek * (bp->bio_length % sc->sc_stripesize) != 0. 3924c55f05bSPawel Jakub Dawidek */ 3934c55f05bSPawel Jakub Dawidek cbp->bio_length = MIN(stripesize, length); 394ec704301SPawel Jakub Dawidek cbp->bio_caller2 = sc->sc_disks[no]; 3954c55f05bSPawel Jakub Dawidek } 3964c55f05bSPawel Jakub Dawidek } 3974c55f05bSPawel Jakub Dawidek if (data != NULL) 3984c55f05bSPawel Jakub Dawidek bp->bio_caller1 = data; 3994c55f05bSPawel Jakub Dawidek /* 4004c55f05bSPawel Jakub Dawidek * Fire off all allocated requests! 4014c55f05bSPawel Jakub Dawidek */ 4024c55f05bSPawel Jakub Dawidek while ((cbp = TAILQ_FIRST(&queue)) != NULL) { 4034c55f05bSPawel Jakub Dawidek struct g_consumer *cp; 4044c55f05bSPawel Jakub Dawidek 4054c55f05bSPawel Jakub Dawidek TAILQ_REMOVE(&queue, cbp, bio_queue); 406ec704301SPawel Jakub Dawidek cp = cbp->bio_caller2; 407ec704301SPawel Jakub Dawidek cbp->bio_caller2 = NULL; 4084c55f05bSPawel Jakub Dawidek cbp->bio_to = cp->provider; 409ec704301SPawel Jakub Dawidek if (cbp->bio_caller1 != NULL) { 4104c55f05bSPawel Jakub Dawidek cbp->bio_data = data; 4114c55f05bSPawel Jakub Dawidek if (bp->bio_cmd == BIO_WRITE) { 412ec704301SPawel Jakub Dawidek g_stripe_copy(sc, cbp->bio_caller1, data, 4134c55f05bSPawel Jakub Dawidek cbp->bio_offset, cbp->bio_length, 0); 4144c55f05bSPawel Jakub Dawidek } 4154c55f05bSPawel Jakub Dawidek data += cbp->bio_length; 4164c55f05bSPawel Jakub Dawidek } 4174c55f05bSPawel Jakub Dawidek G_STRIPE_LOGREQ(cbp, "Sending request."); 4184c55f05bSPawel Jakub Dawidek g_io_request(cbp, cp); 4194c55f05bSPawel Jakub Dawidek } 4204c55f05bSPawel Jakub Dawidek return (0); 4214c55f05bSPawel Jakub Dawidek failure: 4224c55f05bSPawel Jakub Dawidek if (data != NULL) 4234c55f05bSPawel Jakub Dawidek uma_zfree(g_stripe_zone, data); 4244c55f05bSPawel Jakub Dawidek while ((cbp = TAILQ_FIRST(&queue)) != NULL) { 4254c55f05bSPawel Jakub Dawidek TAILQ_REMOVE(&queue, cbp, bio_queue); 426ec704301SPawel Jakub Dawidek if (cbp->bio_caller1 != NULL) { 427ec704301SPawel Jakub Dawidek cbp->bio_data = cbp->bio_caller1; 428ec704301SPawel Jakub Dawidek cbp->bio_caller1 = NULL; 4294c55f05bSPawel Jakub Dawidek } 43037abacd4SPawel Jakub Dawidek bp->bio_children--; 4314c55f05bSPawel Jakub Dawidek g_destroy_bio(cbp); 4324c55f05bSPawel Jakub Dawidek } 4334c55f05bSPawel Jakub Dawidek return (error); 4344c55f05bSPawel Jakub Dawidek } 4354c55f05bSPawel Jakub Dawidek 4364c55f05bSPawel Jakub Dawidek static int 4374c55f05bSPawel Jakub Dawidek g_stripe_start_economic(struct bio *bp, u_int no, off_t offset, off_t length) 4384c55f05bSPawel Jakub Dawidek { 4394c55f05bSPawel Jakub Dawidek TAILQ_HEAD(, bio) queue = TAILQ_HEAD_INITIALIZER(queue); 4404c55f05bSPawel Jakub Dawidek struct g_stripe_softc *sc; 4414c55f05bSPawel Jakub Dawidek uint32_t stripesize; 4424c55f05bSPawel Jakub Dawidek struct bio *cbp; 4434c55f05bSPawel Jakub Dawidek char *addr; 4444c55f05bSPawel Jakub Dawidek int error; 4454c55f05bSPawel Jakub Dawidek 4464c55f05bSPawel Jakub Dawidek sc = bp->bio_to->geom->softc; 4474c55f05bSPawel Jakub Dawidek 4484c55f05bSPawel Jakub Dawidek addr = bp->bio_data; 4494c55f05bSPawel Jakub Dawidek stripesize = sc->sc_stripesize; 4504c55f05bSPawel Jakub Dawidek 4514c55f05bSPawel Jakub Dawidek cbp = g_clone_bio(bp); 4524c55f05bSPawel Jakub Dawidek if (cbp == NULL) { 4534c55f05bSPawel Jakub Dawidek error = ENOMEM; 4544c55f05bSPawel Jakub Dawidek goto failure; 4554c55f05bSPawel Jakub Dawidek } 4564c55f05bSPawel Jakub Dawidek TAILQ_INSERT_TAIL(&queue, cbp, bio_queue); 4574c55f05bSPawel Jakub Dawidek /* 4584c55f05bSPawel Jakub Dawidek * Fill in the component buf structure. 4594c55f05bSPawel Jakub Dawidek */ 4604c55f05bSPawel Jakub Dawidek cbp->bio_done = g_std_done; 4614c55f05bSPawel Jakub Dawidek cbp->bio_offset = offset; 4624c55f05bSPawel Jakub Dawidek cbp->bio_data = addr; 4634c55f05bSPawel Jakub Dawidek cbp->bio_length = length; 464ec704301SPawel Jakub Dawidek cbp->bio_caller2 = sc->sc_disks[no]; 4654c55f05bSPawel Jakub Dawidek 4664c55f05bSPawel Jakub Dawidek /* offset -= offset % stripesize; */ 4674c55f05bSPawel Jakub Dawidek offset -= offset & (stripesize - 1); 4684c55f05bSPawel Jakub Dawidek addr += length; 4694c55f05bSPawel Jakub Dawidek length = bp->bio_length - length; 4704c55f05bSPawel Jakub Dawidek for (no++; length > 0; no++, length -= stripesize, addr += stripesize) { 4714c55f05bSPawel Jakub Dawidek if (no > sc->sc_ndisks - 1) { 4724c55f05bSPawel Jakub Dawidek no = 0; 4734c55f05bSPawel Jakub Dawidek offset += stripesize; 4744c55f05bSPawel Jakub Dawidek } 4754c55f05bSPawel Jakub Dawidek cbp = g_clone_bio(bp); 4764c55f05bSPawel Jakub Dawidek if (cbp == NULL) { 4774c55f05bSPawel Jakub Dawidek error = ENOMEM; 4784c55f05bSPawel Jakub Dawidek goto failure; 4794c55f05bSPawel Jakub Dawidek } 4804c55f05bSPawel Jakub Dawidek TAILQ_INSERT_TAIL(&queue, cbp, bio_queue); 4814c55f05bSPawel Jakub Dawidek 4824c55f05bSPawel Jakub Dawidek /* 4834c55f05bSPawel Jakub Dawidek * Fill in the component buf structure. 4844c55f05bSPawel Jakub Dawidek */ 4854c55f05bSPawel Jakub Dawidek cbp->bio_done = g_std_done; 4864c55f05bSPawel Jakub Dawidek cbp->bio_offset = offset; 4874c55f05bSPawel Jakub Dawidek cbp->bio_data = addr; 4884c55f05bSPawel Jakub Dawidek /* 4894c55f05bSPawel Jakub Dawidek * MIN() is in case when 4904c55f05bSPawel Jakub Dawidek * (bp->bio_length % sc->sc_stripesize) != 0. 4914c55f05bSPawel Jakub Dawidek */ 4924c55f05bSPawel Jakub Dawidek cbp->bio_length = MIN(stripesize, length); 4934c55f05bSPawel Jakub Dawidek 494ec704301SPawel Jakub Dawidek cbp->bio_caller2 = sc->sc_disks[no]; 4954c55f05bSPawel Jakub Dawidek } 4964c55f05bSPawel Jakub Dawidek /* 4974c55f05bSPawel Jakub Dawidek * Fire off all allocated requests! 4984c55f05bSPawel Jakub Dawidek */ 4994c55f05bSPawel Jakub Dawidek while ((cbp = TAILQ_FIRST(&queue)) != NULL) { 5004c55f05bSPawel Jakub Dawidek struct g_consumer *cp; 5014c55f05bSPawel Jakub Dawidek 5024c55f05bSPawel Jakub Dawidek TAILQ_REMOVE(&queue, cbp, bio_queue); 503ec704301SPawel Jakub Dawidek cp = cbp->bio_caller2; 504ec704301SPawel Jakub Dawidek cbp->bio_caller2 = NULL; 5054c55f05bSPawel Jakub Dawidek cbp->bio_to = cp->provider; 5064c55f05bSPawel Jakub Dawidek G_STRIPE_LOGREQ(cbp, "Sending request."); 5074c55f05bSPawel Jakub Dawidek g_io_request(cbp, cp); 5084c55f05bSPawel Jakub Dawidek } 5094c55f05bSPawel Jakub Dawidek return (0); 5104c55f05bSPawel Jakub Dawidek failure: 5114c55f05bSPawel Jakub Dawidek while ((cbp = TAILQ_FIRST(&queue)) != NULL) { 5124c55f05bSPawel Jakub Dawidek TAILQ_REMOVE(&queue, cbp, bio_queue); 51337abacd4SPawel Jakub Dawidek bp->bio_children--; 5144c55f05bSPawel Jakub Dawidek g_destroy_bio(cbp); 5154c55f05bSPawel Jakub Dawidek } 5164c55f05bSPawel Jakub Dawidek return (error); 5174c55f05bSPawel Jakub Dawidek } 5184c55f05bSPawel Jakub Dawidek 5194c55f05bSPawel Jakub Dawidek static void 520b09121f9SPawel Jakub Dawidek g_stripe_start(struct bio *bp) 521b09121f9SPawel Jakub Dawidek { 5224c55f05bSPawel Jakub Dawidek off_t offset, start, length, nstripe; 523b09121f9SPawel Jakub Dawidek struct g_stripe_softc *sc; 5244c55f05bSPawel Jakub Dawidek u_int no, stripesize; 5254c55f05bSPawel Jakub Dawidek int error, fast = 0; 526b09121f9SPawel Jakub Dawidek 5274c55f05bSPawel Jakub Dawidek sc = bp->bio_to->geom->softc; 528b09121f9SPawel Jakub Dawidek /* 529b09121f9SPawel Jakub Dawidek * If sc == NULL, provider's error should be set and g_stripe_start() 530b09121f9SPawel Jakub Dawidek * should not be called at all. 531b09121f9SPawel Jakub Dawidek */ 532b09121f9SPawel Jakub Dawidek KASSERT(sc != NULL, 533b09121f9SPawel Jakub Dawidek ("Provider's error should be set (error=%d)(device=%s).", 534b09121f9SPawel Jakub Dawidek bp->bio_to->error, bp->bio_to->name)); 535b09121f9SPawel Jakub Dawidek 536b09121f9SPawel Jakub Dawidek G_STRIPE_LOGREQ(bp, "Request received."); 537b09121f9SPawel Jakub Dawidek 538b09121f9SPawel Jakub Dawidek switch (bp->bio_cmd) { 539b09121f9SPawel Jakub Dawidek case BIO_READ: 540b09121f9SPawel Jakub Dawidek case BIO_WRITE: 541b09121f9SPawel Jakub Dawidek case BIO_DELETE: 542b09121f9SPawel Jakub Dawidek /* 543b09121f9SPawel Jakub Dawidek * Only those requests are supported. 544b09121f9SPawel Jakub Dawidek */ 545b09121f9SPawel Jakub Dawidek break; 546b09121f9SPawel Jakub Dawidek case BIO_GETATTR: 547b09121f9SPawel Jakub Dawidek /* To which provider it should be delivered? */ 548b09121f9SPawel Jakub Dawidek default: 549b09121f9SPawel Jakub Dawidek g_io_deliver(bp, EOPNOTSUPP); 550b09121f9SPawel Jakub Dawidek return; 551b09121f9SPawel Jakub Dawidek } 552b09121f9SPawel Jakub Dawidek 553b09121f9SPawel Jakub Dawidek stripesize = sc->sc_stripesize; 554b09121f9SPawel Jakub Dawidek 555b09121f9SPawel Jakub Dawidek /* 5564c55f05bSPawel Jakub Dawidek * Calculations are quite messy, but fast I hope. 557b09121f9SPawel Jakub Dawidek */ 558b09121f9SPawel Jakub Dawidek 559b09121f9SPawel Jakub Dawidek /* Stripe number. */ 560b09121f9SPawel Jakub Dawidek /* nstripe = bp->bio_offset / stripesize; */ 561b09121f9SPawel Jakub Dawidek nstripe = bp->bio_offset >> (off_t)sc->sc_stripebits; 562b09121f9SPawel Jakub Dawidek /* Disk number. */ 563b09121f9SPawel Jakub Dawidek no = nstripe % sc->sc_ndisks; 564b09121f9SPawel Jakub Dawidek /* Start position in stripe. */ 565b09121f9SPawel Jakub Dawidek /* start = bp->bio_offset % stripesize; */ 566b09121f9SPawel Jakub Dawidek start = bp->bio_offset & (stripesize - 1); 567b09121f9SPawel Jakub Dawidek /* Start position in disk. */ 5684c55f05bSPawel Jakub Dawidek /* offset = (nstripe / sc->sc_ndisks) * stripesize + start; */ 5694c55f05bSPawel Jakub Dawidek offset = ((nstripe / sc->sc_ndisks) << sc->sc_stripebits) + start; 570b09121f9SPawel Jakub Dawidek /* Length of data to operate. */ 571b09121f9SPawel Jakub Dawidek length = MIN(bp->bio_length, stripesize - start); 572b09121f9SPawel Jakub Dawidek 573b09121f9SPawel Jakub Dawidek /* 5744c55f05bSPawel Jakub Dawidek * Do use "fast" mode when: 5754c55f05bSPawel Jakub Dawidek * 1. "Fast" mode is ON. 5764c55f05bSPawel Jakub Dawidek * and 5774c55f05bSPawel Jakub Dawidek * 2. Request size is less than or equal to MAX_IO_SIZE (128kB), 5784c55f05bSPawel Jakub Dawidek * which should always be true. 5794c55f05bSPawel Jakub Dawidek * and 5804c55f05bSPawel Jakub Dawidek * 3. Request size is bigger than stripesize * ndisks. If it isn't, 5814c55f05bSPawel Jakub Dawidek * there will be no need to send more than one I/O request to 5824c55f05bSPawel Jakub Dawidek * a provider, so there is nothing to optmize. 583b09121f9SPawel Jakub Dawidek */ 5844c55f05bSPawel Jakub Dawidek if (g_stripe_fast && bp->bio_length <= MAX_IO_SIZE && 5854c55f05bSPawel Jakub Dawidek bp->bio_length >= stripesize * sc->sc_ndisks) { 5864c55f05bSPawel Jakub Dawidek fast = 1; 5874c55f05bSPawel Jakub Dawidek } 5884c55f05bSPawel Jakub Dawidek error = 0; 589cea36368SPawel Jakub Dawidek if (fast) { 5904c55f05bSPawel Jakub Dawidek error = g_stripe_start_fast(bp, no, offset, length); 591cea36368SPawel Jakub Dawidek if (error != 0) 592cea36368SPawel Jakub Dawidek g_stripe_fast_failed++; 593cea36368SPawel Jakub Dawidek } 5944c55f05bSPawel Jakub Dawidek /* 5954c55f05bSPawel Jakub Dawidek * Do use "economic" when: 5964c55f05bSPawel Jakub Dawidek * 1. "Economic" mode is ON. 5974c55f05bSPawel Jakub Dawidek * or 5984c55f05bSPawel Jakub Dawidek * 2. "Fast" mode failed. It can only failed if there is no memory. 5994c55f05bSPawel Jakub Dawidek */ 6004c55f05bSPawel Jakub Dawidek if (!fast || error != 0) 6014c55f05bSPawel Jakub Dawidek error = g_stripe_start_economic(bp, no, offset, length); 6024c55f05bSPawel Jakub Dawidek if (error != 0) { 603b09121f9SPawel Jakub Dawidek if (bp->bio_error == 0) 6044c55f05bSPawel Jakub Dawidek bp->bio_error = error; 605b09121f9SPawel Jakub Dawidek g_io_deliver(bp, bp->bio_error); 606b09121f9SPawel Jakub Dawidek } 607b09121f9SPawel Jakub Dawidek } 608b09121f9SPawel Jakub Dawidek 609b09121f9SPawel Jakub Dawidek static void 610b09121f9SPawel Jakub Dawidek g_stripe_check_and_run(struct g_stripe_softc *sc) 611b09121f9SPawel Jakub Dawidek { 612b09121f9SPawel Jakub Dawidek off_t mediasize, ms; 613b09121f9SPawel Jakub Dawidek u_int no, sectorsize = 0; 614b09121f9SPawel Jakub Dawidek 615b09121f9SPawel Jakub Dawidek if (g_stripe_nvalid(sc) != sc->sc_ndisks) 616b09121f9SPawel Jakub Dawidek return; 617b09121f9SPawel Jakub Dawidek 618889c5dc2SPawel Jakub Dawidek sc->sc_provider = g_new_providerf(sc->sc_geom, "stripe/%s", 619889c5dc2SPawel Jakub Dawidek sc->sc_name); 620b09121f9SPawel Jakub Dawidek /* 621b09121f9SPawel Jakub Dawidek * Find the smallest disk. 622b09121f9SPawel Jakub Dawidek */ 623b09121f9SPawel Jakub Dawidek mediasize = sc->sc_disks[0]->provider->mediasize; 624b09121f9SPawel Jakub Dawidek if (sc->sc_type == G_STRIPE_TYPE_AUTOMATIC) 625b09121f9SPawel Jakub Dawidek mediasize -= sc->sc_disks[0]->provider->sectorsize; 626b09121f9SPawel Jakub Dawidek mediasize -= mediasize % sc->sc_stripesize; 627b09121f9SPawel Jakub Dawidek sectorsize = sc->sc_disks[0]->provider->sectorsize; 628b09121f9SPawel Jakub Dawidek for (no = 1; no < sc->sc_ndisks; no++) { 629b09121f9SPawel Jakub Dawidek ms = sc->sc_disks[no]->provider->mediasize; 630b09121f9SPawel Jakub Dawidek if (sc->sc_type == G_STRIPE_TYPE_AUTOMATIC) 631b09121f9SPawel Jakub Dawidek ms -= sc->sc_disks[no]->provider->sectorsize; 632b09121f9SPawel Jakub Dawidek ms -= ms % sc->sc_stripesize; 633b09121f9SPawel Jakub Dawidek if (ms < mediasize) 634b09121f9SPawel Jakub Dawidek mediasize = ms; 635b09121f9SPawel Jakub Dawidek sectorsize = lcm(sectorsize, 636b09121f9SPawel Jakub Dawidek sc->sc_disks[no]->provider->sectorsize); 637b09121f9SPawel Jakub Dawidek } 638b09121f9SPawel Jakub Dawidek sc->sc_provider->sectorsize = sectorsize; 639b09121f9SPawel Jakub Dawidek sc->sc_provider->mediasize = mediasize * sc->sc_ndisks; 640b09121f9SPawel Jakub Dawidek g_error_provider(sc->sc_provider, 0); 641b09121f9SPawel Jakub Dawidek 642889c5dc2SPawel Jakub Dawidek G_STRIPE_DEBUG(0, "Device %s activated.", sc->sc_name); 643b09121f9SPawel Jakub Dawidek } 644b09121f9SPawel Jakub Dawidek 645b09121f9SPawel Jakub Dawidek static int 646b09121f9SPawel Jakub Dawidek g_stripe_read_metadata(struct g_consumer *cp, struct g_stripe_metadata *md) 647b09121f9SPawel Jakub Dawidek { 648b09121f9SPawel Jakub Dawidek struct g_provider *pp; 649b09121f9SPawel Jakub Dawidek u_char *buf; 650b09121f9SPawel Jakub Dawidek int error; 651b09121f9SPawel Jakub Dawidek 652b09121f9SPawel Jakub Dawidek g_topology_assert(); 653b09121f9SPawel Jakub Dawidek 654b09121f9SPawel Jakub Dawidek error = g_access(cp, 1, 0, 0); 655b09121f9SPawel Jakub Dawidek if (error != 0) 656b09121f9SPawel Jakub Dawidek return (error); 657b09121f9SPawel Jakub Dawidek pp = cp->provider; 658b09121f9SPawel Jakub Dawidek g_topology_unlock(); 659b09121f9SPawel Jakub Dawidek buf = g_read_data(cp, pp->mediasize - pp->sectorsize, pp->sectorsize, 660b09121f9SPawel Jakub Dawidek &error); 661b09121f9SPawel Jakub Dawidek g_topology_lock(); 662b09121f9SPawel Jakub Dawidek g_access(cp, -1, 0, 0); 663b09121f9SPawel Jakub Dawidek if (buf == NULL) 664b09121f9SPawel Jakub Dawidek return (error); 665b09121f9SPawel Jakub Dawidek 666b09121f9SPawel Jakub Dawidek /* Decode metadata. */ 667b09121f9SPawel Jakub Dawidek stripe_metadata_decode(buf, md); 668b09121f9SPawel Jakub Dawidek g_free(buf); 669b09121f9SPawel Jakub Dawidek 670b09121f9SPawel Jakub Dawidek return (0); 671b09121f9SPawel Jakub Dawidek } 672b09121f9SPawel Jakub Dawidek 673b09121f9SPawel Jakub Dawidek /* 674b09121f9SPawel Jakub Dawidek * Add disk to given device. 675b09121f9SPawel Jakub Dawidek */ 676b09121f9SPawel Jakub Dawidek static int 677b09121f9SPawel Jakub Dawidek g_stripe_add_disk(struct g_stripe_softc *sc, struct g_provider *pp, u_int no) 678b09121f9SPawel Jakub Dawidek { 679b09121f9SPawel Jakub Dawidek struct g_consumer *cp, *fcp; 680b09121f9SPawel Jakub Dawidek struct g_geom *gp; 681b09121f9SPawel Jakub Dawidek int error; 682b09121f9SPawel Jakub Dawidek 683b09121f9SPawel Jakub Dawidek /* Metadata corrupted? */ 684b09121f9SPawel Jakub Dawidek if (no >= sc->sc_ndisks) 685b09121f9SPawel Jakub Dawidek return (EINVAL); 686b09121f9SPawel Jakub Dawidek 687b09121f9SPawel Jakub Dawidek /* Check if disk is not already attached. */ 688b09121f9SPawel Jakub Dawidek if (sc->sc_disks[no] != NULL) 689b09121f9SPawel Jakub Dawidek return (EEXIST); 690b09121f9SPawel Jakub Dawidek 691b09121f9SPawel Jakub Dawidek gp = sc->sc_geom; 692b09121f9SPawel Jakub Dawidek fcp = LIST_FIRST(&gp->consumer); 693b09121f9SPawel Jakub Dawidek 694b09121f9SPawel Jakub Dawidek cp = g_new_consumer(gp); 695b09121f9SPawel Jakub Dawidek error = g_attach(cp, pp); 696b09121f9SPawel Jakub Dawidek if (error != 0) { 697b09121f9SPawel Jakub Dawidek g_destroy_consumer(cp); 698b09121f9SPawel Jakub Dawidek return (error); 699b09121f9SPawel Jakub Dawidek } 700b09121f9SPawel Jakub Dawidek 701b09121f9SPawel Jakub Dawidek if (fcp != NULL && (fcp->acr > 0 || fcp->acw > 0 || fcp->ace > 0)) { 702b09121f9SPawel Jakub Dawidek error = g_access(cp, fcp->acr, fcp->acw, fcp->ace); 703b09121f9SPawel Jakub Dawidek if (error != 0) { 704b09121f9SPawel Jakub Dawidek g_detach(cp); 705b09121f9SPawel Jakub Dawidek g_destroy_consumer(cp); 706b09121f9SPawel Jakub Dawidek return (error); 707b09121f9SPawel Jakub Dawidek } 708b09121f9SPawel Jakub Dawidek } 709b09121f9SPawel Jakub Dawidek if (sc->sc_type == G_STRIPE_TYPE_AUTOMATIC) { 710b09121f9SPawel Jakub Dawidek struct g_stripe_metadata md; 711b09121f9SPawel Jakub Dawidek 712b09121f9SPawel Jakub Dawidek /* Reread metadata. */ 713b09121f9SPawel Jakub Dawidek error = g_stripe_read_metadata(cp, &md); 714b09121f9SPawel Jakub Dawidek if (error != 0) 715b09121f9SPawel Jakub Dawidek goto fail; 716b09121f9SPawel Jakub Dawidek 717b09121f9SPawel Jakub Dawidek if (strcmp(md.md_magic, G_STRIPE_MAGIC) != 0 || 718b09121f9SPawel Jakub Dawidek strcmp(md.md_name, sc->sc_name) != 0 || 719b09121f9SPawel Jakub Dawidek md.md_id != sc->sc_id) { 720b09121f9SPawel Jakub Dawidek G_STRIPE_DEBUG(0, "Metadata on %s changed.", pp->name); 721b09121f9SPawel Jakub Dawidek goto fail; 722b09121f9SPawel Jakub Dawidek } 723b09121f9SPawel Jakub Dawidek } 724b09121f9SPawel Jakub Dawidek 725b09121f9SPawel Jakub Dawidek cp->private = sc; 726b09121f9SPawel Jakub Dawidek cp->index = no; 727b09121f9SPawel Jakub Dawidek sc->sc_disks[no] = cp; 728b09121f9SPawel Jakub Dawidek 729889c5dc2SPawel Jakub Dawidek G_STRIPE_DEBUG(0, "Disk %s attached to %s.", pp->name, sc->sc_name); 730b09121f9SPawel Jakub Dawidek 731b09121f9SPawel Jakub Dawidek g_stripe_check_and_run(sc); 732b09121f9SPawel Jakub Dawidek 733b09121f9SPawel Jakub Dawidek return (0); 734b09121f9SPawel Jakub Dawidek fail: 735b09121f9SPawel Jakub Dawidek if (fcp != NULL && (fcp->acr > 0 || fcp->acw > 0 || fcp->ace > 0)) 736b09121f9SPawel Jakub Dawidek g_access(cp, -fcp->acr, -fcp->acw, -fcp->ace); 737b09121f9SPawel Jakub Dawidek g_detach(cp); 738b09121f9SPawel Jakub Dawidek g_destroy_consumer(cp); 739b09121f9SPawel Jakub Dawidek return (error); 740b09121f9SPawel Jakub Dawidek } 741b09121f9SPawel Jakub Dawidek 742b09121f9SPawel Jakub Dawidek static struct g_geom * 743b09121f9SPawel Jakub Dawidek g_stripe_create(struct g_class *mp, const struct g_stripe_metadata *md, 744b09121f9SPawel Jakub Dawidek u_int type) 745b09121f9SPawel Jakub Dawidek { 746b09121f9SPawel Jakub Dawidek struct g_stripe_softc *sc; 747b09121f9SPawel Jakub Dawidek struct g_geom *gp; 748b09121f9SPawel Jakub Dawidek u_int no; 749b09121f9SPawel Jakub Dawidek 750889c5dc2SPawel Jakub Dawidek G_STRIPE_DEBUG(1, "Creating device %s (id=%u).", md->md_name, 751b09121f9SPawel Jakub Dawidek md->md_id); 752b09121f9SPawel Jakub Dawidek 753b09121f9SPawel Jakub Dawidek /* Two disks is minimum. */ 754889c5dc2SPawel Jakub Dawidek if (md->md_all < 2) { 755889c5dc2SPawel Jakub Dawidek G_STRIPE_DEBUG(0, "Too few disks defined for %s.", md->md_name); 756b09121f9SPawel Jakub Dawidek return (NULL); 757b09121f9SPawel Jakub Dawidek } 758b09121f9SPawel Jakub Dawidek #if 0 759b09121f9SPawel Jakub Dawidek /* Stripe size have to be grater than or equal to sector size. */ 760b09121f9SPawel Jakub Dawidek if (md->md_stripesize < sectorsize) { 761889c5dc2SPawel Jakub Dawidek G_STRIPE_DEBUG(0, "Invalid stripe size for %s.", md->md_name); 762b09121f9SPawel Jakub Dawidek return (NULL); 763b09121f9SPawel Jakub Dawidek } 764b09121f9SPawel Jakub Dawidek #endif 765b09121f9SPawel Jakub Dawidek /* Stripe size have to be power of 2. */ 766b09121f9SPawel Jakub Dawidek if (!powerof2(md->md_stripesize)) { 767889c5dc2SPawel Jakub Dawidek G_STRIPE_DEBUG(0, "Invalid stripe size for %s.", md->md_name); 768b09121f9SPawel Jakub Dawidek return (NULL); 769b09121f9SPawel Jakub Dawidek } 770b09121f9SPawel Jakub Dawidek 771b09121f9SPawel Jakub Dawidek /* Check for duplicate unit */ 772b09121f9SPawel Jakub Dawidek LIST_FOREACH(gp, &mp->geom, geom) { 773b09121f9SPawel Jakub Dawidek sc = gp->softc; 774b09121f9SPawel Jakub Dawidek if (sc != NULL && strcmp(sc->sc_name, md->md_name) == 0) { 775b09121f9SPawel Jakub Dawidek G_STRIPE_DEBUG(0, "Device %s already configured.", 776889c5dc2SPawel Jakub Dawidek sc->sc_name); 777b09121f9SPawel Jakub Dawidek return (NULL); 778b09121f9SPawel Jakub Dawidek } 779b09121f9SPawel Jakub Dawidek } 780889c5dc2SPawel Jakub Dawidek gp = g_new_geomf(mp, "%s", md->md_name); 781b09121f9SPawel Jakub Dawidek gp->softc = NULL; /* for a moment */ 782b09121f9SPawel Jakub Dawidek 7832017a9d3SPawel Jakub Dawidek sc = malloc(sizeof(*sc), M_STRIPE, M_WAITOK | M_ZERO); 784b09121f9SPawel Jakub Dawidek gp->start = g_stripe_start; 785b09121f9SPawel Jakub Dawidek gp->spoiled = g_stripe_orphan; 786b09121f9SPawel Jakub Dawidek gp->orphan = g_stripe_orphan; 787b09121f9SPawel Jakub Dawidek gp->access = g_stripe_access; 788b09121f9SPawel Jakub Dawidek gp->dumpconf = g_stripe_dumpconf; 789b09121f9SPawel Jakub Dawidek 790b09121f9SPawel Jakub Dawidek sc->sc_id = md->md_id; 791b09121f9SPawel Jakub Dawidek sc->sc_stripesize = md->md_stripesize; 792b09121f9SPawel Jakub Dawidek sc->sc_stripebits = BITCOUNT(sc->sc_stripesize - 1); 793b09121f9SPawel Jakub Dawidek sc->sc_ndisks = md->md_all; 794b09121f9SPawel Jakub Dawidek sc->sc_disks = malloc(sizeof(struct g_consumer *) * sc->sc_ndisks, 795b09121f9SPawel Jakub Dawidek M_STRIPE, M_WAITOK | M_ZERO); 796b09121f9SPawel Jakub Dawidek for (no = 0; no < sc->sc_ndisks; no++) 797b09121f9SPawel Jakub Dawidek sc->sc_disks[no] = NULL; 798b09121f9SPawel Jakub Dawidek sc->sc_type = type; 799b09121f9SPawel Jakub Dawidek 800b09121f9SPawel Jakub Dawidek gp->softc = sc; 801b09121f9SPawel Jakub Dawidek sc->sc_geom = gp; 802b09121f9SPawel Jakub Dawidek sc->sc_provider = NULL; 803b09121f9SPawel Jakub Dawidek 804889c5dc2SPawel Jakub Dawidek G_STRIPE_DEBUG(0, "Device %s created (id=%u).", sc->sc_name, sc->sc_id); 805b09121f9SPawel Jakub Dawidek 806b09121f9SPawel Jakub Dawidek return (gp); 807b09121f9SPawel Jakub Dawidek } 808b09121f9SPawel Jakub Dawidek 809b09121f9SPawel Jakub Dawidek static int 810b09121f9SPawel Jakub Dawidek g_stripe_destroy(struct g_stripe_softc *sc, boolean_t force) 811b09121f9SPawel Jakub Dawidek { 812b09121f9SPawel Jakub Dawidek struct g_provider *pp; 813b09121f9SPawel Jakub Dawidek struct g_geom *gp; 814b09121f9SPawel Jakub Dawidek u_int no; 815b09121f9SPawel Jakub Dawidek 816b09121f9SPawel Jakub Dawidek g_topology_assert(); 817b09121f9SPawel Jakub Dawidek 818b09121f9SPawel Jakub Dawidek if (sc == NULL) 819b09121f9SPawel Jakub Dawidek return (ENXIO); 820b09121f9SPawel Jakub Dawidek 821b09121f9SPawel Jakub Dawidek pp = sc->sc_provider; 822b09121f9SPawel Jakub Dawidek if (pp != NULL && (pp->acr != 0 || pp->acw != 0 || pp->ace != 0)) { 823b09121f9SPawel Jakub Dawidek if (force) { 824b09121f9SPawel Jakub Dawidek G_STRIPE_DEBUG(0, "Device %s is still open, so it " 825b09121f9SPawel Jakub Dawidek "can't be definitely removed.", pp->name); 826b09121f9SPawel Jakub Dawidek } else { 827b09121f9SPawel Jakub Dawidek G_STRIPE_DEBUG(1, 828b09121f9SPawel Jakub Dawidek "Device %s is still open (r%dw%de%d).", pp->name, 829b09121f9SPawel Jakub Dawidek pp->acr, pp->acw, pp->ace); 830b09121f9SPawel Jakub Dawidek return (EBUSY); 831b09121f9SPawel Jakub Dawidek } 832b09121f9SPawel Jakub Dawidek } 833b09121f9SPawel Jakub Dawidek 834b09121f9SPawel Jakub Dawidek for (no = 0; no < sc->sc_ndisks; no++) { 835b09121f9SPawel Jakub Dawidek if (sc->sc_disks[no] != NULL) 836b09121f9SPawel Jakub Dawidek g_stripe_remove_disk(sc->sc_disks[no]); 837b09121f9SPawel Jakub Dawidek } 838b09121f9SPawel Jakub Dawidek 839b09121f9SPawel Jakub Dawidek gp = sc->sc_geom; 840b09121f9SPawel Jakub Dawidek gp->softc = NULL; 841b09121f9SPawel Jakub Dawidek KASSERT(sc->sc_provider == NULL, ("Provider still exists? (device=%s)", 842b09121f9SPawel Jakub Dawidek gp->name)); 843b09121f9SPawel Jakub Dawidek free(sc->sc_disks, M_STRIPE); 844b09121f9SPawel Jakub Dawidek free(sc, M_STRIPE); 845b09121f9SPawel Jakub Dawidek 846b09121f9SPawel Jakub Dawidek pp = LIST_FIRST(&gp->provider); 847b09121f9SPawel Jakub Dawidek if (pp == NULL || (pp->acr == 0 && pp->acw == 0 && pp->ace == 0)) 848b09121f9SPawel Jakub Dawidek G_STRIPE_DEBUG(0, "Device %s destroyed.", gp->name); 849b09121f9SPawel Jakub Dawidek 850b09121f9SPawel Jakub Dawidek g_wither_geom(gp, ENXIO); 851b09121f9SPawel Jakub Dawidek 852b09121f9SPawel Jakub Dawidek return (0); 853b09121f9SPawel Jakub Dawidek } 854b09121f9SPawel Jakub Dawidek 855b09121f9SPawel Jakub Dawidek static int 856b09121f9SPawel Jakub Dawidek g_stripe_destroy_geom(struct gctl_req *req __unused, 857b09121f9SPawel Jakub Dawidek struct g_class *mp __unused, struct g_geom *gp) 858b09121f9SPawel Jakub Dawidek { 859b09121f9SPawel Jakub Dawidek struct g_stripe_softc *sc; 860b09121f9SPawel Jakub Dawidek 861b09121f9SPawel Jakub Dawidek sc = gp->softc; 862b09121f9SPawel Jakub Dawidek return (g_stripe_destroy(sc, 0)); 863b09121f9SPawel Jakub Dawidek } 864b09121f9SPawel Jakub Dawidek 865b09121f9SPawel Jakub Dawidek static struct g_geom * 866b09121f9SPawel Jakub Dawidek g_stripe_taste(struct g_class *mp, struct g_provider *pp, int flags __unused) 867b09121f9SPawel Jakub Dawidek { 868b09121f9SPawel Jakub Dawidek struct g_stripe_metadata md; 869b09121f9SPawel Jakub Dawidek struct g_stripe_softc *sc; 870b09121f9SPawel Jakub Dawidek struct g_consumer *cp; 871b09121f9SPawel Jakub Dawidek struct g_geom *gp; 872b09121f9SPawel Jakub Dawidek int error; 873b09121f9SPawel Jakub Dawidek 874b09121f9SPawel Jakub Dawidek g_trace(G_T_TOPOLOGY, "%s(%s, %s)", __func__, mp->name, pp->name); 875b09121f9SPawel Jakub Dawidek g_topology_assert(); 876b09121f9SPawel Jakub Dawidek 877b09121f9SPawel Jakub Dawidek G_STRIPE_DEBUG(3, "Tasting %s.", pp->name); 878b09121f9SPawel Jakub Dawidek 879b09121f9SPawel Jakub Dawidek gp = g_new_geomf(mp, "stripe:taste"); 880b09121f9SPawel Jakub Dawidek gp->start = g_stripe_start; 881b09121f9SPawel Jakub Dawidek gp->access = g_stripe_access; 882b09121f9SPawel Jakub Dawidek gp->orphan = g_stripe_orphan; 883b09121f9SPawel Jakub Dawidek cp = g_new_consumer(gp); 884b09121f9SPawel Jakub Dawidek g_attach(cp, pp); 885b09121f9SPawel Jakub Dawidek 886b09121f9SPawel Jakub Dawidek error = g_stripe_read_metadata(cp, &md); 887b09121f9SPawel Jakub Dawidek g_wither_geom(gp, ENXIO); 888b09121f9SPawel Jakub Dawidek if (error != 0) 889b09121f9SPawel Jakub Dawidek return (NULL); 890b09121f9SPawel Jakub Dawidek gp = NULL; 891b09121f9SPawel Jakub Dawidek 892b09121f9SPawel Jakub Dawidek if (strcmp(md.md_magic, G_STRIPE_MAGIC) != 0) 893b09121f9SPawel Jakub Dawidek return (NULL); 894b09121f9SPawel Jakub Dawidek if (md.md_version > G_STRIPE_VERSION) { 895b09121f9SPawel Jakub Dawidek printf("geom_stripe.ko module is too old to handle %s.\n", 896b09121f9SPawel Jakub Dawidek pp->name); 897b09121f9SPawel Jakub Dawidek return (NULL); 898b09121f9SPawel Jakub Dawidek } 899b09121f9SPawel Jakub Dawidek 900b09121f9SPawel Jakub Dawidek /* 901b09121f9SPawel Jakub Dawidek * Let's check if device already exists. 902b09121f9SPawel Jakub Dawidek */ 903b09121f9SPawel Jakub Dawidek sc = NULL; 904b09121f9SPawel Jakub Dawidek LIST_FOREACH(gp, &mp->geom, geom) { 905b09121f9SPawel Jakub Dawidek sc = gp->softc; 906b09121f9SPawel Jakub Dawidek if (sc == NULL) 907b09121f9SPawel Jakub Dawidek continue; 908b09121f9SPawel Jakub Dawidek if (sc->sc_type != G_STRIPE_TYPE_AUTOMATIC) 909b09121f9SPawel Jakub Dawidek continue; 910b09121f9SPawel Jakub Dawidek if (strcmp(md.md_name, sc->sc_name) != 0) 911b09121f9SPawel Jakub Dawidek continue; 912b09121f9SPawel Jakub Dawidek if (md.md_id != sc->sc_id) 913b09121f9SPawel Jakub Dawidek continue; 914b09121f9SPawel Jakub Dawidek break; 915b09121f9SPawel Jakub Dawidek } 916b09121f9SPawel Jakub Dawidek if (gp != NULL) { 917b09121f9SPawel Jakub Dawidek G_STRIPE_DEBUG(1, "Adding disk %s to %s.", pp->name, gp->name); 918b09121f9SPawel Jakub Dawidek error = g_stripe_add_disk(sc, pp, md.md_no); 919b09121f9SPawel Jakub Dawidek if (error != 0) { 920b09121f9SPawel Jakub Dawidek G_STRIPE_DEBUG(0, 921b09121f9SPawel Jakub Dawidek "Cannot add disk %s to %s (error=%d).", pp->name, 922b09121f9SPawel Jakub Dawidek gp->name, error); 923b09121f9SPawel Jakub Dawidek return (NULL); 924b09121f9SPawel Jakub Dawidek } 925b09121f9SPawel Jakub Dawidek } else { 926b09121f9SPawel Jakub Dawidek gp = g_stripe_create(mp, &md, G_STRIPE_TYPE_AUTOMATIC); 927b09121f9SPawel Jakub Dawidek if (gp == NULL) { 928889c5dc2SPawel Jakub Dawidek G_STRIPE_DEBUG(0, "Cannot create device %s.", 929b09121f9SPawel Jakub Dawidek md.md_name); 930b09121f9SPawel Jakub Dawidek return (NULL); 931b09121f9SPawel Jakub Dawidek } 932b09121f9SPawel Jakub Dawidek sc = gp->softc; 933b09121f9SPawel Jakub Dawidek G_STRIPE_DEBUG(1, "Adding disk %s to %s.", pp->name, gp->name); 934b09121f9SPawel Jakub Dawidek error = g_stripe_add_disk(sc, pp, md.md_no); 935b09121f9SPawel Jakub Dawidek if (error != 0) { 936b09121f9SPawel Jakub Dawidek G_STRIPE_DEBUG(0, 937b09121f9SPawel Jakub Dawidek "Cannot add disk %s to %s (error=%d).", pp->name, 938b09121f9SPawel Jakub Dawidek gp->name, error); 939b09121f9SPawel Jakub Dawidek g_stripe_destroy(sc, 1); 940b09121f9SPawel Jakub Dawidek return (NULL); 941b09121f9SPawel Jakub Dawidek } 942b09121f9SPawel Jakub Dawidek } 943b09121f9SPawel Jakub Dawidek 944b09121f9SPawel Jakub Dawidek return (gp); 945b09121f9SPawel Jakub Dawidek } 946b09121f9SPawel Jakub Dawidek 947b09121f9SPawel Jakub Dawidek static void 948b09121f9SPawel Jakub Dawidek g_stripe_ctl_create(struct gctl_req *req, struct g_class *mp) 949b09121f9SPawel Jakub Dawidek { 950b09121f9SPawel Jakub Dawidek u_int attached, no; 951b09121f9SPawel Jakub Dawidek struct g_stripe_metadata md; 952b09121f9SPawel Jakub Dawidek struct g_provider *pp; 953b09121f9SPawel Jakub Dawidek struct g_stripe_softc *sc; 954b09121f9SPawel Jakub Dawidek struct g_geom *gp; 955b09121f9SPawel Jakub Dawidek struct sbuf *sb; 956b09121f9SPawel Jakub Dawidek intmax_t *stripesize; 957b09121f9SPawel Jakub Dawidek const char *name; 958b09121f9SPawel Jakub Dawidek char param[16]; 959b09121f9SPawel Jakub Dawidek int *nargs; 960b09121f9SPawel Jakub Dawidek 961b09121f9SPawel Jakub Dawidek g_topology_assert(); 962b09121f9SPawel Jakub Dawidek nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs)); 963b09121f9SPawel Jakub Dawidek if (nargs == NULL) { 964b09121f9SPawel Jakub Dawidek gctl_error(req, "No '%s' argument.", "nargs"); 965b09121f9SPawel Jakub Dawidek return; 966b09121f9SPawel Jakub Dawidek } 967b09121f9SPawel Jakub Dawidek if (*nargs <= 2) { 968b09121f9SPawel Jakub Dawidek gctl_error(req, "Too few arguments."); 969b09121f9SPawel Jakub Dawidek return; 970b09121f9SPawel Jakub Dawidek } 971b09121f9SPawel Jakub Dawidek 972b09121f9SPawel Jakub Dawidek strlcpy(md.md_magic, G_STRIPE_MAGIC, sizeof(md.md_magic)); 973b09121f9SPawel Jakub Dawidek md.md_version = G_STRIPE_VERSION; 974b09121f9SPawel Jakub Dawidek name = gctl_get_asciiparam(req, "arg0"); 975b09121f9SPawel Jakub Dawidek if (name == NULL) { 976b09121f9SPawel Jakub Dawidek gctl_error(req, "No 'arg%u' argument.", 0); 977b09121f9SPawel Jakub Dawidek return; 978b09121f9SPawel Jakub Dawidek } 979b09121f9SPawel Jakub Dawidek strlcpy(md.md_name, name, sizeof(md.md_name)); 980b09121f9SPawel Jakub Dawidek md.md_id = arc4random(); 981b09121f9SPawel Jakub Dawidek md.md_no = 0; 982b09121f9SPawel Jakub Dawidek md.md_all = *nargs - 1; 983b09121f9SPawel Jakub Dawidek stripesize = gctl_get_paraml(req, "stripesize", sizeof(*stripesize)); 984b09121f9SPawel Jakub Dawidek if (stripesize == NULL) { 985b09121f9SPawel Jakub Dawidek gctl_error(req, "No '%s' argument.", "stripesize"); 986b09121f9SPawel Jakub Dawidek return; 987b09121f9SPawel Jakub Dawidek } 988b09121f9SPawel Jakub Dawidek md.md_stripesize = *stripesize; 989b09121f9SPawel Jakub Dawidek 990b09121f9SPawel Jakub Dawidek /* Check all providers are valid */ 991b09121f9SPawel Jakub Dawidek for (no = 1; no < *nargs; no++) { 992b09121f9SPawel Jakub Dawidek snprintf(param, sizeof(param), "arg%u", no); 993b09121f9SPawel Jakub Dawidek name = gctl_get_asciiparam(req, param); 994b09121f9SPawel Jakub Dawidek if (name == NULL) { 995b09121f9SPawel Jakub Dawidek gctl_error(req, "No 'arg%u' argument.", no); 996b09121f9SPawel Jakub Dawidek return; 997b09121f9SPawel Jakub Dawidek } 998b09121f9SPawel Jakub Dawidek if (strncmp(name, "/dev/", strlen("/dev/")) == 0) 999b09121f9SPawel Jakub Dawidek name += strlen("/dev/"); 1000b09121f9SPawel Jakub Dawidek pp = g_provider_by_name(name); 1001b09121f9SPawel Jakub Dawidek if (pp == NULL) { 1002b09121f9SPawel Jakub Dawidek G_STRIPE_DEBUG(1, "Disk %s is invalid.", name); 1003b09121f9SPawel Jakub Dawidek gctl_error(req, "Disk %s is invalid.", name); 1004b09121f9SPawel Jakub Dawidek return; 1005b09121f9SPawel Jakub Dawidek } 1006b09121f9SPawel Jakub Dawidek } 1007b09121f9SPawel Jakub Dawidek 1008b09121f9SPawel Jakub Dawidek gp = g_stripe_create(mp, &md, G_STRIPE_TYPE_MANUAL); 1009b09121f9SPawel Jakub Dawidek if (gp == NULL) { 1010889c5dc2SPawel Jakub Dawidek gctl_error(req, "Can't configure %s.", md.md_name); 1011b09121f9SPawel Jakub Dawidek return; 1012b09121f9SPawel Jakub Dawidek } 1013b09121f9SPawel Jakub Dawidek 1014b09121f9SPawel Jakub Dawidek sc = gp->softc; 1015b09121f9SPawel Jakub Dawidek sb = sbuf_new(NULL, NULL, 0, SBUF_AUTOEXTEND); 1016b09121f9SPawel Jakub Dawidek sbuf_printf(sb, "Can't attach disk(s) to %s:", gp->name); 1017b09121f9SPawel Jakub Dawidek for (attached = 0, no = 1; no < *nargs; no++) { 1018b09121f9SPawel Jakub Dawidek snprintf(param, sizeof(param), "arg%u", no); 1019b09121f9SPawel Jakub Dawidek name = gctl_get_asciiparam(req, param); 1020b09121f9SPawel Jakub Dawidek if (strncmp(name, "/dev/", strlen("/dev/")) == 0) 1021b09121f9SPawel Jakub Dawidek name += strlen("/dev/"); 1022b09121f9SPawel Jakub Dawidek pp = g_provider_by_name(name); 1023b09121f9SPawel Jakub Dawidek KASSERT(pp != NULL, ("Provider %s disappear?!", name)); 1024b09121f9SPawel Jakub Dawidek if (g_stripe_add_disk(sc, pp, no - 1) != 0) { 1025b09121f9SPawel Jakub Dawidek G_STRIPE_DEBUG(1, "Disk %u (%s) not attached to %s.", 1026b09121f9SPawel Jakub Dawidek no, pp->name, gp->name); 1027b09121f9SPawel Jakub Dawidek sbuf_printf(sb, " %s", pp->name); 1028b09121f9SPawel Jakub Dawidek continue; 1029b09121f9SPawel Jakub Dawidek } 1030b09121f9SPawel Jakub Dawidek attached++; 1031b09121f9SPawel Jakub Dawidek } 1032b09121f9SPawel Jakub Dawidek sbuf_finish(sb); 1033b09121f9SPawel Jakub Dawidek if (md.md_all != attached) { 1034b09121f9SPawel Jakub Dawidek g_stripe_destroy(gp->softc, 1); 1035b09121f9SPawel Jakub Dawidek gctl_error(req, "%s", sbuf_data(sb)); 1036b09121f9SPawel Jakub Dawidek } 1037b09121f9SPawel Jakub Dawidek sbuf_delete(sb); 1038b09121f9SPawel Jakub Dawidek } 1039b09121f9SPawel Jakub Dawidek 1040b09121f9SPawel Jakub Dawidek static struct g_stripe_softc * 1041b09121f9SPawel Jakub Dawidek g_stripe_find_device(struct g_class *mp, const char *name) 1042b09121f9SPawel Jakub Dawidek { 1043b09121f9SPawel Jakub Dawidek struct g_stripe_softc *sc; 1044b09121f9SPawel Jakub Dawidek struct g_geom *gp; 1045b09121f9SPawel Jakub Dawidek 1046b09121f9SPawel Jakub Dawidek LIST_FOREACH(gp, &mp->geom, geom) { 1047b09121f9SPawel Jakub Dawidek sc = gp->softc; 1048b09121f9SPawel Jakub Dawidek if (sc == NULL) 1049b09121f9SPawel Jakub Dawidek continue; 1050889c5dc2SPawel Jakub Dawidek if (strcmp(sc->sc_name, name) == 0) 1051b09121f9SPawel Jakub Dawidek return (sc); 1052b09121f9SPawel Jakub Dawidek } 1053b09121f9SPawel Jakub Dawidek return (NULL); 1054b09121f9SPawel Jakub Dawidek } 1055b09121f9SPawel Jakub Dawidek 1056b09121f9SPawel Jakub Dawidek static void 1057b09121f9SPawel Jakub Dawidek g_stripe_ctl_destroy(struct gctl_req *req, struct g_class *mp) 1058b09121f9SPawel Jakub Dawidek { 1059b09121f9SPawel Jakub Dawidek struct g_stripe_softc *sc; 1060b09121f9SPawel Jakub Dawidek int *force, *nargs, error; 1061b09121f9SPawel Jakub Dawidek const char *name; 1062b09121f9SPawel Jakub Dawidek char param[16]; 1063b09121f9SPawel Jakub Dawidek u_int i; 1064b09121f9SPawel Jakub Dawidek 1065b09121f9SPawel Jakub Dawidek g_topology_assert(); 1066b09121f9SPawel Jakub Dawidek 1067b09121f9SPawel Jakub Dawidek nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs)); 1068b09121f9SPawel Jakub Dawidek if (nargs == NULL) { 1069b09121f9SPawel Jakub Dawidek gctl_error(req, "No '%s' argument.", "nargs"); 1070b09121f9SPawel Jakub Dawidek return; 1071b09121f9SPawel Jakub Dawidek } 1072b09121f9SPawel Jakub Dawidek if (*nargs <= 0) { 1073b09121f9SPawel Jakub Dawidek gctl_error(req, "Missing device(s)."); 1074b09121f9SPawel Jakub Dawidek return; 1075b09121f9SPawel Jakub Dawidek } 1076b09121f9SPawel Jakub Dawidek force = gctl_get_paraml(req, "force", sizeof(*force)); 1077b09121f9SPawel Jakub Dawidek if (force == NULL) { 1078b09121f9SPawel Jakub Dawidek gctl_error(req, "No '%s' argument.", "force"); 1079b09121f9SPawel Jakub Dawidek return; 1080b09121f9SPawel Jakub Dawidek } 1081b09121f9SPawel Jakub Dawidek 1082b09121f9SPawel Jakub Dawidek for (i = 0; i < (u_int)*nargs; i++) { 1083b09121f9SPawel Jakub Dawidek snprintf(param, sizeof(param), "arg%u", i); 1084b09121f9SPawel Jakub Dawidek name = gctl_get_asciiparam(req, param); 1085b09121f9SPawel Jakub Dawidek if (name == NULL) { 1086b09121f9SPawel Jakub Dawidek gctl_error(req, "No 'arg%u' argument.", i); 1087b09121f9SPawel Jakub Dawidek return; 1088b09121f9SPawel Jakub Dawidek } 1089b09121f9SPawel Jakub Dawidek sc = g_stripe_find_device(mp, name); 1090b09121f9SPawel Jakub Dawidek if (sc == NULL) { 1091b09121f9SPawel Jakub Dawidek gctl_error(req, "No such device: %s.", name); 1092b09121f9SPawel Jakub Dawidek return; 1093b09121f9SPawel Jakub Dawidek } 1094b09121f9SPawel Jakub Dawidek error = g_stripe_destroy(sc, *force); 1095b09121f9SPawel Jakub Dawidek if (error != 0) { 1096b09121f9SPawel Jakub Dawidek gctl_error(req, "Cannot destroy device %s (error=%d).", 1097889c5dc2SPawel Jakub Dawidek sc->sc_name, error); 1098b09121f9SPawel Jakub Dawidek return; 1099b09121f9SPawel Jakub Dawidek } 1100b09121f9SPawel Jakub Dawidek } 1101b09121f9SPawel Jakub Dawidek } 1102b09121f9SPawel Jakub Dawidek 1103b09121f9SPawel Jakub Dawidek static void 1104b09121f9SPawel Jakub Dawidek g_stripe_config(struct gctl_req *req, struct g_class *mp, const char *verb) 1105b09121f9SPawel Jakub Dawidek { 1106b09121f9SPawel Jakub Dawidek uint32_t *version; 1107b09121f9SPawel Jakub Dawidek 1108b09121f9SPawel Jakub Dawidek g_topology_assert(); 1109b09121f9SPawel Jakub Dawidek 1110b09121f9SPawel Jakub Dawidek version = gctl_get_paraml(req, "version", sizeof(*version)); 1111b09121f9SPawel Jakub Dawidek if (version == NULL) { 1112b09121f9SPawel Jakub Dawidek gctl_error(req, "No '%s' argument.", "version"); 1113b09121f9SPawel Jakub Dawidek return; 1114b09121f9SPawel Jakub Dawidek } 1115b09121f9SPawel Jakub Dawidek if (*version != G_STRIPE_VERSION) { 1116b09121f9SPawel Jakub Dawidek gctl_error(req, "Userland and kernel parts are out of sync."); 1117b09121f9SPawel Jakub Dawidek return; 1118b09121f9SPawel Jakub Dawidek } 1119b09121f9SPawel Jakub Dawidek 1120b09121f9SPawel Jakub Dawidek if (strcmp(verb, "create") == 0) { 1121b09121f9SPawel Jakub Dawidek g_stripe_ctl_create(req, mp); 1122b09121f9SPawel Jakub Dawidek return; 1123a2e31b8bSPawel Jakub Dawidek } else if (strcmp(verb, "destroy") == 0 || 1124a2e31b8bSPawel Jakub Dawidek strcmp(verb, "stop") == 0) { 1125b09121f9SPawel Jakub Dawidek g_stripe_ctl_destroy(req, mp); 1126b09121f9SPawel Jakub Dawidek return; 1127b09121f9SPawel Jakub Dawidek } 1128b09121f9SPawel Jakub Dawidek 1129b09121f9SPawel Jakub Dawidek gctl_error(req, "Unknown verb."); 1130b09121f9SPawel Jakub Dawidek } 1131b09121f9SPawel Jakub Dawidek 1132b09121f9SPawel Jakub Dawidek static void 1133b09121f9SPawel Jakub Dawidek g_stripe_dumpconf(struct sbuf *sb, const char *indent, struct g_geom *gp, 1134b09121f9SPawel Jakub Dawidek struct g_consumer *cp, struct g_provider *pp) 1135b09121f9SPawel Jakub Dawidek { 1136b09121f9SPawel Jakub Dawidek struct g_stripe_softc *sc; 1137b09121f9SPawel Jakub Dawidek 1138b09121f9SPawel Jakub Dawidek sc = gp->softc; 11391d723f1dSPawel Jakub Dawidek if (sc == NULL) 1140b09121f9SPawel Jakub Dawidek return; 11411d723f1dSPawel Jakub Dawidek if (pp != NULL) { 11421d723f1dSPawel Jakub Dawidek /* Nothing here. */ 11431d723f1dSPawel Jakub Dawidek } else if (cp != NULL) { 11441d723f1dSPawel Jakub Dawidek /* Nothing here. */ 11451d723f1dSPawel Jakub Dawidek } else { 11461d723f1dSPawel Jakub Dawidek sbuf_printf(sb, "%s<ID>%u</ID>\n", indent, (u_int)sc->sc_id); 11471d723f1dSPawel Jakub Dawidek sbuf_printf(sb, "%s<Stripesize>%u</Stripesize>\n", indent, 1148b09121f9SPawel Jakub Dawidek (u_int)sc->sc_stripesize); 11491d723f1dSPawel Jakub Dawidek sbuf_printf(sb, "%s<Type>", indent); 1150b09121f9SPawel Jakub Dawidek switch (sc->sc_type) { 1151b09121f9SPawel Jakub Dawidek case G_STRIPE_TYPE_AUTOMATIC: 11521d723f1dSPawel Jakub Dawidek sbuf_printf(sb, "AUTOMATIC"); 1153b09121f9SPawel Jakub Dawidek break; 1154b09121f9SPawel Jakub Dawidek case G_STRIPE_TYPE_MANUAL: 11551d723f1dSPawel Jakub Dawidek sbuf_printf(sb, "MANUAL"); 1156b09121f9SPawel Jakub Dawidek break; 1157b09121f9SPawel Jakub Dawidek default: 11581d723f1dSPawel Jakub Dawidek sbuf_printf(sb, "UNKNOWN"); 1159b09121f9SPawel Jakub Dawidek break; 1160b09121f9SPawel Jakub Dawidek } 11611d723f1dSPawel Jakub Dawidek sbuf_printf(sb, "</Type>\n"); 11621d723f1dSPawel Jakub Dawidek sbuf_printf(sb, "%s<Status>Total=%u, Online=%u</Status>\n", 11631d723f1dSPawel Jakub Dawidek indent, sc->sc_ndisks, g_stripe_nvalid(sc)); 11641d723f1dSPawel Jakub Dawidek sbuf_printf(sb, "%s<State>", indent); 11651d723f1dSPawel Jakub Dawidek if (sc->sc_provider != NULL && sc->sc_provider->error == 0) 11661d723f1dSPawel Jakub Dawidek sbuf_printf(sb, "UP"); 11673fb17452SPawel Jakub Dawidek else 11681d723f1dSPawel Jakub Dawidek sbuf_printf(sb, "DOWN"); 11691d723f1dSPawel Jakub Dawidek sbuf_printf(sb, "</State>\n"); 11701d723f1dSPawel Jakub Dawidek } 1171b09121f9SPawel Jakub Dawidek } 1172b09121f9SPawel Jakub Dawidek 1173b09121f9SPawel Jakub Dawidek DECLARE_GEOM_CLASS(g_stripe_class, g_stripe); 1174