g_stripe.c revision 227309
1183863Snwhitehorn/*- 2183863Snwhitehorn * Copyright (c) 2004-2005 Pawel Jakub Dawidek <pjd@FreeBSD.org> 3183863Snwhitehorn * All rights reserved. 4183863Snwhitehorn * 5183863Snwhitehorn * Redistribution and use in source and binary forms, with or without 6183863Snwhitehorn * modification, are permitted provided that the following conditions 7183863Snwhitehorn * are met: 8183863Snwhitehorn * 1. Redistributions of source code must retain the above copyright 9183863Snwhitehorn * notice, this list of conditions and the following disclaimer. 10183863Snwhitehorn * 2. Redistributions in binary form must reproduce the above copyright 11183863Snwhitehorn * notice, this list of conditions and the following disclaimer in the 12183863Snwhitehorn * documentation and/or other materials provided with the distribution. 13183863Snwhitehorn * 14183863Snwhitehorn * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 15183863Snwhitehorn * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16183863Snwhitehorn * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17183863Snwhitehorn * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 18183863Snwhitehorn * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19183863Snwhitehorn * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20183863Snwhitehorn * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21183863Snwhitehorn * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22183863Snwhitehorn * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23183863Snwhitehorn * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24183863Snwhitehorn * SUCH DAMAGE. 25183863Snwhitehorn */ 26295453Semaste 27183863Snwhitehorn#include <sys/cdefs.h> 28183863Snwhitehorn__FBSDID("$FreeBSD: head/sys/geom/stripe/g_stripe.c 227309 2011-11-07 15:43:11Z ed $"); 29183863Snwhitehorn 30183863Snwhitehorn#include <sys/param.h> 31183863Snwhitehorn#include <sys/systm.h> 32183863Snwhitehorn#include <sys/kernel.h> 33183863Snwhitehorn#include <sys/module.h> 34183863Snwhitehorn#include <sys/lock.h> 35183863Snwhitehorn#include <sys/mutex.h> 36183863Snwhitehorn#include <sys/bio.h> 37183863Snwhitehorn#include <sys/sbuf.h> 38183863Snwhitehorn#include <sys/sysctl.h> 39183863Snwhitehorn#include <sys/malloc.h> 40183863Snwhitehorn#include <vm/uma.h> 41183863Snwhitehorn#include <geom/geom.h> 42183863Snwhitehorn#include <geom/stripe/g_stripe.h> 43183863Snwhitehorn 44183863SnwhitehornFEATURE(geom_stripe, "GEOM striping support"); 45183863Snwhitehorn 46183863Snwhitehornstatic MALLOC_DEFINE(M_STRIPE, "stripe_data", "GEOM_STRIPE Data"); 47183863Snwhitehorn 48183863Snwhitehornstatic uma_zone_t g_stripe_zone; 49183863Snwhitehorn 50183863Snwhitehornstatic int g_stripe_destroy(struct g_stripe_softc *sc, boolean_t force); 51183863Snwhitehornstatic int g_stripe_destroy_geom(struct gctl_req *req, struct g_class *mp, 52183863Snwhitehorn struct g_geom *gp); 53183863Snwhitehorn 54183863Snwhitehornstatic g_taste_t g_stripe_taste; 55183863Snwhitehornstatic g_ctl_req_t g_stripe_config; 56183863Snwhitehornstatic g_dumpconf_t g_stripe_dumpconf; 57183863Snwhitehornstatic g_init_t g_stripe_init; 58183863Snwhitehornstatic g_fini_t g_stripe_fini; 59183863Snwhitehorn 60183863Snwhitehornstruct g_class g_stripe_class = { 61183863Snwhitehorn .name = G_STRIPE_CLASS_NAME, 62183863Snwhitehorn .version = G_VERSION, 63243254Strasz .ctlreq = g_stripe_config, 64183863Snwhitehorn .taste = g_stripe_taste, 65183863Snwhitehorn .destroy_geom = g_stripe_destroy_geom, 66183863Snwhitehorn .init = g_stripe_init, 67183863Snwhitehorn .fini = g_stripe_fini 68183863Snwhitehorn}; 69183863Snwhitehorn 70183863SnwhitehornSYSCTL_DECL(_kern_geom); 71183863Snwhitehornstatic SYSCTL_NODE(_kern_geom, OID_AUTO, stripe, CTLFLAG_RW, 0, 72183863Snwhitehorn "GEOM_STRIPE stuff"); 73183863Snwhitehornstatic u_int g_stripe_debug = 0; 74183863SnwhitehornTUNABLE_INT("kern.geom.stripe.debug", &g_stripe_debug); 75183863SnwhitehornSYSCTL_UINT(_kern_geom_stripe, OID_AUTO, debug, CTLFLAG_RW, &g_stripe_debug, 0, 76183863Snwhitehorn "Debug level"); 77183863Snwhitehornstatic int g_stripe_fast = 0; 78231810SnwhitehornTUNABLE_INT("kern.geom.stripe.fast", &g_stripe_fast); 79231810Snwhitehornstatic int 80183863Snwhitehorng_sysctl_stripe_fast(SYSCTL_HANDLER_ARGS) 81183863Snwhitehorn{ 82183863Snwhitehorn int error, fast; 83183863Snwhitehorn 84183863Snwhitehorn fast = g_stripe_fast; 85183863Snwhitehorn error = sysctl_handle_int(oidp, &fast, 0, req); 86183863Snwhitehorn if (error == 0 && req->newptr != NULL) 87183863Snwhitehorn g_stripe_fast = fast; 88183863Snwhitehorn return (error); 89183863Snwhitehorn} 90183863SnwhitehornSYSCTL_PROC(_kern_geom_stripe, OID_AUTO, fast, CTLTYPE_INT | CTLFLAG_RW, 91183863Snwhitehorn NULL, 0, g_sysctl_stripe_fast, "I", "Fast, but memory-consuming, mode"); 92183863Snwhitehornstatic u_int g_stripe_maxmem = MAXPHYS * 100; 93183863SnwhitehornTUNABLE_INT("kern.geom.stripe.maxmem", &g_stripe_maxmem); 94183863SnwhitehornSYSCTL_UINT(_kern_geom_stripe, OID_AUTO, maxmem, CTLFLAG_RD, &g_stripe_maxmem, 95183863Snwhitehorn 0, "Maximum memory that can be allocated in \"fast\" mode (in bytes)"); 96183863Snwhitehornstatic u_int g_stripe_fast_failed = 0; 97183863SnwhitehornSYSCTL_UINT(_kern_geom_stripe, OID_AUTO, fast_failed, CTLFLAG_RD, 98183863Snwhitehorn &g_stripe_fast_failed, 0, "How many times \"fast\" mode failed"); 99183863Snwhitehorn 100183863Snwhitehorn/* 101183863Snwhitehorn * Greatest Common Divisor. 102183863Snwhitehorn */ 103183863Snwhitehornstatic u_int 104183863Snwhitehorngcd(u_int a, u_int b) 105183863Snwhitehorn{ 106218822Sdim u_int c; 107183863Snwhitehorn 108183863Snwhitehorn while (b != 0) { 109183863Snwhitehorn c = a; 110183863Snwhitehorn a = b; 111183863Snwhitehorn b = (c % b); 112183863Snwhitehorn } 113183863Snwhitehorn return (a); 114183863Snwhitehorn} 115183863Snwhitehorn 116183863Snwhitehorn/* 117183863Snwhitehorn * Least Common Multiple. 118183863Snwhitehorn */ 119183863Snwhitehornstatic u_int 120183863Snwhitehornlcm(u_int a, u_int b) 121183863Snwhitehorn{ 122183863Snwhitehorn 123183863Snwhitehorn return ((a * b) / gcd(a, b)); 124183863Snwhitehorn} 125183863Snwhitehorn 126183863Snwhitehornstatic void 127183863Snwhitehorng_stripe_init(struct g_class *mp __unused) 128183863Snwhitehorn{ 129183863Snwhitehorn 130183863Snwhitehorn g_stripe_zone = uma_zcreate("g_stripe_zone", MAXPHYS, NULL, NULL, 131183863Snwhitehorn NULL, NULL, 0, 0); 132183863Snwhitehorn g_stripe_maxmem -= g_stripe_maxmem % MAXPHYS; 133183863Snwhitehorn uma_zone_set_max(g_stripe_zone, g_stripe_maxmem / MAXPHYS); 134183863Snwhitehorn} 135183863Snwhitehorn 136183863Snwhitehornstatic void 137183863Snwhitehorng_stripe_fini(struct g_class *mp __unused) 138183863Snwhitehorn{ 139183863Snwhitehorn 140183863Snwhitehorn uma_zdestroy(g_stripe_zone); 141183863Snwhitehorn} 142183863Snwhitehorn 143183863Snwhitehorn/* 144183863Snwhitehorn * Return the number of valid disks. 145183863Snwhitehorn */ 146183863Snwhitehornstatic u_int 147183863Snwhitehorng_stripe_nvalid(struct g_stripe_softc *sc) 148183863Snwhitehorn{ 149183863Snwhitehorn u_int i, no; 150183863Snwhitehorn 151183863Snwhitehorn no = 0; 152183863Snwhitehorn for (i = 0; i < sc->sc_ndisks; i++) { 153183863Snwhitehorn if (sc->sc_disks[i] != NULL) 154183863Snwhitehorn no++; 155183863Snwhitehorn } 156183863Snwhitehorn 157183863Snwhitehorn return (no); 158183863Snwhitehorn} 159183863Snwhitehorn 160183863Snwhitehornstatic void 161183863Snwhitehorng_stripe_remove_disk(struct g_consumer *cp) 162183863Snwhitehorn{ 163183863Snwhitehorn struct g_stripe_softc *sc; 164183863Snwhitehorn 165183863Snwhitehorn g_topology_assert(); 166183863Snwhitehorn KASSERT(cp != NULL, ("Non-valid disk in %s.", __func__)); 167183863Snwhitehorn sc = (struct g_stripe_softc *)cp->geom->softc; 168183863Snwhitehorn KASSERT(sc != NULL, ("NULL sc in %s.", __func__)); 169183863Snwhitehorn 170183863Snwhitehorn if (cp->private == NULL) { 171183863Snwhitehorn G_STRIPE_DEBUG(0, "Disk %s removed from %s.", 172183863Snwhitehorn cp->provider->name, sc->sc_name); 173183863Snwhitehorn cp->private = (void *)(uintptr_t)-1; 174183863Snwhitehorn } 175183863Snwhitehorn 176183863Snwhitehorn if (sc->sc_provider != NULL) { 177183863Snwhitehorn sc->sc_provider->flags |= G_PF_WITHER; 178183863Snwhitehorn G_STRIPE_DEBUG(0, "Device %s deactivated.", 179183863Snwhitehorn sc->sc_provider->name); 180183863Snwhitehorn g_orphan_provider(sc->sc_provider, ENXIO); 181183863Snwhitehorn sc->sc_provider = NULL; 182183863Snwhitehorn } 183183863Snwhitehorn 184183863Snwhitehorn if (cp->acr > 0 || cp->acw > 0 || cp->ace > 0) 185183863Snwhitehorn return; 186183863Snwhitehorn sc->sc_disks[cp->index] = NULL; 187183863Snwhitehorn cp->index = 0; 188183863Snwhitehorn g_detach(cp); 189183863Snwhitehorn g_destroy_consumer(cp); 190183863Snwhitehorn /* If there are no valid disks anymore, remove device. */ 191183863Snwhitehorn if (LIST_EMPTY(&sc->sc_geom->consumer)) 192183863Snwhitehorn g_stripe_destroy(sc, 1); 193183863Snwhitehorn} 194183863Snwhitehorn 195183863Snwhitehornstatic void 196183863Snwhitehorng_stripe_orphan(struct g_consumer *cp) 197183863Snwhitehorn{ 198183863Snwhitehorn struct g_stripe_softc *sc; 199183863Snwhitehorn struct g_geom *gp; 200183863Snwhitehorn 201183863Snwhitehorn g_topology_assert(); 202183863Snwhitehorn gp = cp->geom; 203183863Snwhitehorn sc = gp->softc; 204183863Snwhitehorn if (sc == NULL) 205183863Snwhitehorn return; 206183863Snwhitehorn 207183863Snwhitehorn g_stripe_remove_disk(cp); 208183863Snwhitehorn} 209183863Snwhitehorn 210183863Snwhitehornstatic int 211183863Snwhitehorng_stripe_access(struct g_provider *pp, int dr, int dw, int de) 212183863Snwhitehorn{ 213183863Snwhitehorn struct g_consumer *cp1, *cp2, *tmp; 214183863Snwhitehorn struct g_stripe_softc *sc; 215183863Snwhitehorn struct g_geom *gp; 216183863Snwhitehorn int error; 217183863Snwhitehorn 218183863Snwhitehorn g_topology_assert(); 219183863Snwhitehorn gp = pp->geom; 220183863Snwhitehorn sc = gp->softc; 221183863Snwhitehorn KASSERT(sc != NULL, ("NULL sc in %s.", __func__)); 222183863Snwhitehorn 223183863Snwhitehorn /* On first open, grab an extra "exclusive" bit */ 224183863Snwhitehorn if (pp->acr == 0 && pp->acw == 0 && pp->ace == 0) 225183863Snwhitehorn de++; 226183863Snwhitehorn /* ... and let go of it on last close */ 227183863Snwhitehorn if ((pp->acr + dr) == 0 && (pp->acw + dw) == 0 && (pp->ace + de) == 0) 228183863Snwhitehorn de--; 229183863Snwhitehorn 230183863Snwhitehorn LIST_FOREACH_SAFE(cp1, &gp->consumer, consumer, tmp) { 231183863Snwhitehorn error = g_access(cp1, dr, dw, de); 232183863Snwhitehorn if (error != 0) 233183863Snwhitehorn goto fail; 234183863Snwhitehorn if (cp1->acr == 0 && cp1->acw == 0 && cp1->ace == 0 && 235183863Snwhitehorn cp1->private != NULL) { 236183863Snwhitehorn g_stripe_remove_disk(cp1); /* May destroy geom. */ 237183863Snwhitehorn } 238183863Snwhitehorn } 239183863Snwhitehorn return (0); 240183863Snwhitehorn 241183863Snwhitehornfail: 242183863Snwhitehorn LIST_FOREACH(cp2, &gp->consumer, consumer) { 243183863Snwhitehorn if (cp1 == cp2) 244183863Snwhitehorn break; 245183863Snwhitehorn g_access(cp2, -dr, -dw, -de); 246183863Snwhitehorn } 247183863Snwhitehorn return (error); 248183863Snwhitehorn} 249183863Snwhitehorn 250183863Snwhitehornstatic void 251183863Snwhitehorng_stripe_copy(struct g_stripe_softc *sc, char *src, char *dst, off_t offset, 252183863Snwhitehorn off_t length, int mode) 253183863Snwhitehorn{ 254183863Snwhitehorn u_int stripesize; 255183863Snwhitehorn size_t len; 256183863Snwhitehorn 257183863Snwhitehorn stripesize = sc->sc_stripesize; 258183863Snwhitehorn len = (size_t)(stripesize - (offset & (stripesize - 1))); 259183863Snwhitehorn do { 260183863Snwhitehorn bcopy(src, dst, len); 261183863Snwhitehorn if (mode) { 262183863Snwhitehorn dst += len + stripesize * (sc->sc_ndisks - 1); 263183863Snwhitehorn src += len; 264183863Snwhitehorn } else { 265183863Snwhitehorn dst += len; 266183863Snwhitehorn src += len + stripesize * (sc->sc_ndisks - 1); 267183863Snwhitehorn } 268183863Snwhitehorn length -= len; 269183863Snwhitehorn KASSERT(length >= 0, 270183863Snwhitehorn ("Length < 0 (stripesize=%zu, offset=%jd, length=%jd).", 271183863Snwhitehorn (size_t)stripesize, (intmax_t)offset, (intmax_t)length)); 272183863Snwhitehorn if (length > stripesize) 273183863Snwhitehorn len = stripesize; 274183863Snwhitehorn else 275183863Snwhitehorn len = length; 276183863Snwhitehorn } while (length > 0); 277183863Snwhitehorn} 278183863Snwhitehorn 279183863Snwhitehornstatic void 280183863Snwhitehorng_stripe_done(struct bio *bp) 281183863Snwhitehorn{ 282183863Snwhitehorn struct g_stripe_softc *sc; 283183863Snwhitehorn struct bio *pbp; 284183863Snwhitehorn 285183863Snwhitehorn pbp = bp->bio_parent; 286183863Snwhitehorn sc = pbp->bio_to->geom->softc; 287183863Snwhitehorn if (pbp->bio_error == 0) 288183863Snwhitehorn pbp->bio_error = bp->bio_error; 289183863Snwhitehorn pbp->bio_completed += bp->bio_completed; 290183863Snwhitehorn if (bp->bio_cmd == BIO_READ && bp->bio_caller1 != NULL) { 291183863Snwhitehorn g_stripe_copy(sc, bp->bio_data, bp->bio_caller1, bp->bio_offset, 292183863Snwhitehorn bp->bio_length, 1); 293183863Snwhitehorn bp->bio_data = bp->bio_caller1; 294183863Snwhitehorn bp->bio_caller1 = NULL; 295183863Snwhitehorn } 296183863Snwhitehorn g_destroy_bio(bp); 297183863Snwhitehorn pbp->bio_inbed++; 298183863Snwhitehorn if (pbp->bio_children == pbp->bio_inbed) { 299183863Snwhitehorn if (pbp->bio_driver1 != NULL) 300183863Snwhitehorn uma_zfree(g_stripe_zone, pbp->bio_driver1); 301183863Snwhitehorn g_io_deliver(pbp, pbp->bio_error); 302183863Snwhitehorn } 303183863Snwhitehorn} 304183863Snwhitehorn 305183863Snwhitehornstatic int 306183863Snwhitehorng_stripe_start_fast(struct bio *bp, u_int no, off_t offset, off_t length) 307183863Snwhitehorn{ 308183863Snwhitehorn TAILQ_HEAD(, bio) queue = TAILQ_HEAD_INITIALIZER(queue); 309183863Snwhitehorn u_int nparts = 0, stripesize; 310183863Snwhitehorn struct g_stripe_softc *sc; 311183863Snwhitehorn char *addr, *data = NULL; 312183863Snwhitehorn struct bio *cbp; 313183863Snwhitehorn int error; 314183863Snwhitehorn 315183863Snwhitehorn sc = bp->bio_to->geom->softc; 316183863Snwhitehorn 317183863Snwhitehorn addr = bp->bio_data; 318183863Snwhitehorn stripesize = sc->sc_stripesize; 319183863Snwhitehorn 320183863Snwhitehorn cbp = g_clone_bio(bp); 321183863Snwhitehorn if (cbp == NULL) { 322183863Snwhitehorn error = ENOMEM; 323183863Snwhitehorn goto failure; 324183863Snwhitehorn } 325183863Snwhitehorn TAILQ_INSERT_TAIL(&queue, cbp, bio_queue); 326183863Snwhitehorn nparts++; 327183863Snwhitehorn /* 328183863Snwhitehorn * Fill in the component buf structure. 329183863Snwhitehorn */ 330183863Snwhitehorn cbp->bio_done = g_stripe_done; 331183863Snwhitehorn cbp->bio_offset = offset; 332183863Snwhitehorn cbp->bio_data = addr; 333183863Snwhitehorn cbp->bio_caller1 = NULL; 334183863Snwhitehorn cbp->bio_length = length; 335183863Snwhitehorn cbp->bio_caller2 = sc->sc_disks[no]; 336183863Snwhitehorn 337183863Snwhitehorn /* offset -= offset % stripesize; */ 338183863Snwhitehorn offset -= offset & (stripesize - 1); 339183863Snwhitehorn addr += length; 340183863Snwhitehorn length = bp->bio_length - length; 341183863Snwhitehorn for (no++; length > 0; no++, length -= stripesize, addr += stripesize) { 342183863Snwhitehorn if (no > sc->sc_ndisks - 1) { 343183863Snwhitehorn no = 0; 344183863Snwhitehorn offset += stripesize; 345183863Snwhitehorn } 346183863Snwhitehorn if (nparts >= sc->sc_ndisks) { 347183863Snwhitehorn cbp = TAILQ_NEXT(cbp, bio_queue); 348183863Snwhitehorn if (cbp == NULL) 349183863Snwhitehorn cbp = TAILQ_FIRST(&queue); 350183863Snwhitehorn nparts++; 351183863Snwhitehorn /* 352183863Snwhitehorn * Update bio structure. 353183863Snwhitehorn */ 354183863Snwhitehorn /* 355183863Snwhitehorn * MIN() is in case when 356183863Snwhitehorn * (bp->bio_length % sc->sc_stripesize) != 0. 357183863Snwhitehorn */ 358183863Snwhitehorn cbp->bio_length += MIN(stripesize, length); 359183863Snwhitehorn if (cbp->bio_caller1 == NULL) { 360183863Snwhitehorn cbp->bio_caller1 = cbp->bio_data; 361183863Snwhitehorn cbp->bio_data = NULL; 362183863Snwhitehorn if (data == NULL) { 363183863Snwhitehorn data = uma_zalloc(g_stripe_zone, 364183863Snwhitehorn M_NOWAIT); 365183863Snwhitehorn if (data == NULL) { 366183863Snwhitehorn error = ENOMEM; 367183863Snwhitehorn goto failure; 368183863Snwhitehorn } 369183863Snwhitehorn } 370183863Snwhitehorn } 371183863Snwhitehorn } else { 372183863Snwhitehorn cbp = g_clone_bio(bp); 373183863Snwhitehorn if (cbp == NULL) { 374183863Snwhitehorn error = ENOMEM; 375183863Snwhitehorn goto failure; 376183863Snwhitehorn } 377183863Snwhitehorn TAILQ_INSERT_TAIL(&queue, cbp, bio_queue); 378183863Snwhitehorn nparts++; 379183863Snwhitehorn /* 380183863Snwhitehorn * Fill in the component buf structure. 381183863Snwhitehorn */ 382183863Snwhitehorn cbp->bio_done = g_stripe_done; 383183863Snwhitehorn cbp->bio_offset = offset; 384183863Snwhitehorn cbp->bio_data = addr; 385183863Snwhitehorn cbp->bio_caller1 = NULL; 386183863Snwhitehorn /* 387183863Snwhitehorn * MIN() is in case when 388183863Snwhitehorn * (bp->bio_length % sc->sc_stripesize) != 0. 389183863Snwhitehorn */ 390183863Snwhitehorn cbp->bio_length = MIN(stripesize, length); 391183863Snwhitehorn cbp->bio_caller2 = sc->sc_disks[no]; 392183863Snwhitehorn } 393183863Snwhitehorn } 394183863Snwhitehorn if (data != NULL) 395183863Snwhitehorn bp->bio_driver1 = data; 396183863Snwhitehorn /* 397183863Snwhitehorn * Fire off all allocated requests! 398295453Semaste */ 399183863Snwhitehorn while ((cbp = TAILQ_FIRST(&queue)) != NULL) { 400183863Snwhitehorn struct g_consumer *cp; 401183863Snwhitehorn 402183863Snwhitehorn TAILQ_REMOVE(&queue, cbp, bio_queue); 403183863Snwhitehorn cp = cbp->bio_caller2; 404183863Snwhitehorn cbp->bio_caller2 = NULL; 405183863Snwhitehorn cbp->bio_to = cp->provider; 406183863Snwhitehorn if (cbp->bio_caller1 != NULL) { 407183863Snwhitehorn cbp->bio_data = data; 408183863Snwhitehorn if (bp->bio_cmd == BIO_WRITE) { 409183863Snwhitehorn g_stripe_copy(sc, cbp->bio_caller1, data, 410183863Snwhitehorn cbp->bio_offset, cbp->bio_length, 0); 411183863Snwhitehorn } 412183863Snwhitehorn data += cbp->bio_length; 413183863Snwhitehorn } 414183863Snwhitehorn G_STRIPE_LOGREQ(cbp, "Sending request."); 415183863Snwhitehorn g_io_request(cbp, cp); 416183863Snwhitehorn } 417183863Snwhitehorn return (0); 418183863Snwhitehornfailure: 419183863Snwhitehorn if (data != NULL) 420183863Snwhitehorn uma_zfree(g_stripe_zone, data); 421183863Snwhitehorn while ((cbp = TAILQ_FIRST(&queue)) != NULL) { 422183863Snwhitehorn TAILQ_REMOVE(&queue, cbp, bio_queue); 423183863Snwhitehorn if (cbp->bio_caller1 != NULL) { 424183863Snwhitehorn cbp->bio_data = cbp->bio_caller1; 425183863Snwhitehorn cbp->bio_caller1 = NULL; 426183863Snwhitehorn } 427183863Snwhitehorn bp->bio_children--; 428183863Snwhitehorn g_destroy_bio(cbp); 429183863Snwhitehorn } 430183863Snwhitehorn return (error); 431183863Snwhitehorn} 432183863Snwhitehorn 433243254Straszstatic int 434183863Snwhitehorng_stripe_start_economic(struct bio *bp, u_int no, off_t offset, off_t length) 435183863Snwhitehorn{ 436183863Snwhitehorn TAILQ_HEAD(, bio) queue = TAILQ_HEAD_INITIALIZER(queue); 437183863Snwhitehorn struct g_stripe_softc *sc; 438183863Snwhitehorn uint32_t stripesize; 439183863Snwhitehorn struct bio *cbp; 440183863Snwhitehorn char *addr; 441243254Strasz int error; 442183863Snwhitehorn 443243254Strasz sc = bp->bio_to->geom->softc; 444243254Strasz 445183863Snwhitehorn addr = bp->bio_data; 446183863Snwhitehorn stripesize = sc->sc_stripesize; 447183863Snwhitehorn 448183863Snwhitehorn cbp = g_clone_bio(bp); 449183863Snwhitehorn if (cbp == NULL) { 450183863Snwhitehorn error = ENOMEM; 451183863Snwhitehorn goto failure; 452183863Snwhitehorn } 453183863Snwhitehorn TAILQ_INSERT_TAIL(&queue, cbp, bio_queue); 454183863Snwhitehorn /* 455183863Snwhitehorn * Fill in the component buf structure. 456183863Snwhitehorn */ 457183863Snwhitehorn cbp->bio_done = g_std_done; 458183863Snwhitehorn cbp->bio_offset = offset; 459183863Snwhitehorn cbp->bio_data = addr; 460183863Snwhitehorn cbp->bio_length = length; 461183863Snwhitehorn cbp->bio_caller2 = sc->sc_disks[no]; 462183863Snwhitehorn 463183863Snwhitehorn /* offset -= offset % stripesize; */ 464183863Snwhitehorn offset -= offset & (stripesize - 1); 465183863Snwhitehorn addr += length; 466183863Snwhitehorn length = bp->bio_length - length; 467183863Snwhitehorn for (no++; length > 0; no++, length -= stripesize, addr += stripesize) { 468183863Snwhitehorn if (no > sc->sc_ndisks - 1) { 469183863Snwhitehorn no = 0; 470183863Snwhitehorn offset += stripesize; 471243254Strasz } 472183863Snwhitehorn cbp = g_clone_bio(bp); 473183863Snwhitehorn if (cbp == NULL) { 474183863Snwhitehorn error = ENOMEM; 475183863Snwhitehorn goto failure; 476243254Strasz } 477183863Snwhitehorn TAILQ_INSERT_TAIL(&queue, cbp, bio_queue); 478183863Snwhitehorn 479183863Snwhitehorn /* 480183863Snwhitehorn * Fill in the component buf structure. 481243254Strasz */ 482183863Snwhitehorn cbp->bio_done = g_std_done; 483183863Snwhitehorn cbp->bio_offset = offset; 484183863Snwhitehorn cbp->bio_data = addr; 485183863Snwhitehorn /* 486183863Snwhitehorn * MIN() is in case when 487183863Snwhitehorn * (bp->bio_length % sc->sc_stripesize) != 0. 488183863Snwhitehorn */ 489183863Snwhitehorn cbp->bio_length = MIN(stripesize, length); 490183863Snwhitehorn 491183863Snwhitehorn cbp->bio_caller2 = sc->sc_disks[no]; 492183863Snwhitehorn } 493235988Sgleb /* 494183863Snwhitehorn * Fire off all allocated requests! 495183863Snwhitehorn */ 496183863Snwhitehorn while ((cbp = TAILQ_FIRST(&queue)) != NULL) { 497183863Snwhitehorn struct g_consumer *cp; 498183863Snwhitehorn 499183863Snwhitehorn TAILQ_REMOVE(&queue, cbp, bio_queue); 500183863Snwhitehorn cp = cbp->bio_caller2; 501183863Snwhitehorn cbp->bio_caller2 = NULL; 502183863Snwhitehorn cbp->bio_to = cp->provider; 503183863Snwhitehorn G_STRIPE_LOGREQ(cbp, "Sending request."); 504183863Snwhitehorn g_io_request(cbp, cp); 505183863Snwhitehorn } 506183863Snwhitehorn return (0); 507183863Snwhitehornfailure: 508183863Snwhitehorn while ((cbp = TAILQ_FIRST(&queue)) != NULL) { 509183863Snwhitehorn TAILQ_REMOVE(&queue, cbp, bio_queue); 510183863Snwhitehorn bp->bio_children--; 511183863Snwhitehorn g_destroy_bio(cbp); 512183863Snwhitehorn } 513183863Snwhitehorn return (error); 514183863Snwhitehorn} 515183863Snwhitehorn 516183863Snwhitehornstatic void 517183863Snwhitehorng_stripe_flush(struct g_stripe_softc *sc, struct bio *bp) 518183863Snwhitehorn{ 519183863Snwhitehorn struct bio_queue_head queue; 520183863Snwhitehorn struct g_consumer *cp; 521183863Snwhitehorn struct bio *cbp; 522183863Snwhitehorn u_int no; 523183863Snwhitehorn 524183863Snwhitehorn bioq_init(&queue); 525183863Snwhitehorn for (no = 0; no < sc->sc_ndisks; no++) { 526231810Snwhitehorn cbp = g_clone_bio(bp); 527183863Snwhitehorn if (cbp == NULL) { 528183863Snwhitehorn for (cbp = bioq_first(&queue); cbp != NULL; 529183863Snwhitehorn cbp = bioq_first(&queue)) { 530183863Snwhitehorn bioq_remove(&queue, cbp); 531183863Snwhitehorn g_destroy_bio(cbp); 532183863Snwhitehorn } 533183863Snwhitehorn if (bp->bio_error == 0) 534183863Snwhitehorn bp->bio_error = ENOMEM; 535183863Snwhitehorn g_io_deliver(bp, bp->bio_error); 536183863Snwhitehorn return; 537183863Snwhitehorn } 538183863Snwhitehorn bioq_insert_tail(&queue, cbp); 539183863Snwhitehorn cbp->bio_done = g_std_done; 540183863Snwhitehorn cbp->bio_caller1 = sc->sc_disks[no]; 541183863Snwhitehorn cbp->bio_to = sc->sc_disks[no]->provider; 542183863Snwhitehorn } 543183863Snwhitehorn for (cbp = bioq_first(&queue); cbp != NULL; cbp = bioq_first(&queue)) { 544183863Snwhitehorn bioq_remove(&queue, cbp); 545183863Snwhitehorn G_STRIPE_LOGREQ(cbp, "Sending request."); 546183863Snwhitehorn cp = cbp->bio_caller1; 547183863Snwhitehorn cbp->bio_caller1 = NULL; 548183863Snwhitehorn g_io_request(cbp, cp); 549183863Snwhitehorn } 550183863Snwhitehorn} 551183863Snwhitehorn 552183863Snwhitehornstatic void 553183863Snwhitehorng_stripe_start(struct bio *bp) 554183863Snwhitehorn{ 555183863Snwhitehorn off_t offset, start, length, nstripe; 556183863Snwhitehorn struct g_stripe_softc *sc; 557183863Snwhitehorn u_int no, stripesize; 558183863Snwhitehorn int error, fast = 0; 559183863Snwhitehorn 560183863Snwhitehorn sc = bp->bio_to->geom->softc; 561183863Snwhitehorn /* 562183863Snwhitehorn * If sc == NULL, provider's error should be set and g_stripe_start() 563183863Snwhitehorn * should not be called at all. 564183863Snwhitehorn */ 565183863Snwhitehorn KASSERT(sc != NULL, 566183863Snwhitehorn ("Provider's error should be set (error=%d)(device=%s).", 567183863Snwhitehorn bp->bio_to->error, bp->bio_to->name)); 568183863Snwhitehorn 569183863Snwhitehorn G_STRIPE_LOGREQ(bp, "Request received."); 570183863Snwhitehorn 571183863Snwhitehorn switch (bp->bio_cmd) { 572183863Snwhitehorn case BIO_READ: 573183863Snwhitehorn case BIO_WRITE: 574183863Snwhitehorn case BIO_DELETE: 575183863Snwhitehorn break; 576183863Snwhitehorn case BIO_FLUSH: 577183863Snwhitehorn g_stripe_flush(sc, bp); 578183863Snwhitehorn return; 579183863Snwhitehorn case BIO_GETATTR: 580183863Snwhitehorn /* To which provider it should be delivered? */ 581183863Snwhitehorn default: 582183863Snwhitehorn g_io_deliver(bp, EOPNOTSUPP); 583183863Snwhitehorn return; 584183863Snwhitehorn } 585183863Snwhitehorn 586183863Snwhitehorn stripesize = sc->sc_stripesize; 587183863Snwhitehorn 588183863Snwhitehorn /* 589183863Snwhitehorn * Calculations are quite messy, but fast I hope. 590183863Snwhitehorn */ 591183863Snwhitehorn 592183863Snwhitehorn /* Stripe number. */ 593183863Snwhitehorn /* nstripe = bp->bio_offset / stripesize; */ 594183863Snwhitehorn nstripe = bp->bio_offset >> (off_t)sc->sc_stripebits; 595183863Snwhitehorn /* Disk number. */ 596183863Snwhitehorn no = nstripe % sc->sc_ndisks; 597183863Snwhitehorn /* Start position in stripe. */ 598183863Snwhitehorn /* start = bp->bio_offset % stripesize; */ 599183863Snwhitehorn start = bp->bio_offset & (stripesize - 1); 600183863Snwhitehorn /* Start position in disk. */ 601183863Snwhitehorn /* offset = (nstripe / sc->sc_ndisks) * stripesize + start; */ 602183863Snwhitehorn offset = ((nstripe / sc->sc_ndisks) << sc->sc_stripebits) + start; 603183863Snwhitehorn /* Length of data to operate. */ 604183863Snwhitehorn length = MIN(bp->bio_length, stripesize - start); 605183863Snwhitehorn 606183863Snwhitehorn /* 607183863Snwhitehorn * Do use "fast" mode when: 608183863Snwhitehorn * 1. "Fast" mode is ON. 609183863Snwhitehorn * and 610183863Snwhitehorn * 2. Request size is less than or equal to MAXPHYS, 611183863Snwhitehorn * which should always be true. 612183863Snwhitehorn * and 613183863Snwhitehorn * 3. Request size is bigger than stripesize * ndisks. If it isn't, 614183863Snwhitehorn * there will be no need to send more than one I/O request to 615183863Snwhitehorn * a provider, so there is nothing to optmize. 616183863Snwhitehorn */ 617183863Snwhitehorn if (g_stripe_fast && bp->bio_length <= MAXPHYS && 618183863Snwhitehorn bp->bio_length >= stripesize * sc->sc_ndisks) { 619183863Snwhitehorn fast = 1; 620183863Snwhitehorn } 621183863Snwhitehorn error = 0; 622183863Snwhitehorn if (fast) { 623183863Snwhitehorn error = g_stripe_start_fast(bp, no, offset, length); 624183863Snwhitehorn if (error != 0) 625183863Snwhitehorn g_stripe_fast_failed++; 626183863Snwhitehorn } 627183863Snwhitehorn /* 628183863Snwhitehorn * Do use "economic" when: 629183863Snwhitehorn * 1. "Economic" mode is ON. 630183863Snwhitehorn * or 631183863Snwhitehorn * 2. "Fast" mode failed. It can only fail if there is no memory. 632183863Snwhitehorn */ 633183863Snwhitehorn if (!fast || error != 0) 634183863Snwhitehorn error = g_stripe_start_economic(bp, no, offset, length); 635183863Snwhitehorn if (error != 0) { 636183863Snwhitehorn if (bp->bio_error == 0) 637183863Snwhitehorn bp->bio_error = error; 638183863Snwhitehorn g_io_deliver(bp, bp->bio_error); 639183863Snwhitehorn } 640183863Snwhitehorn} 641183863Snwhitehorn 642183863Snwhitehornstatic void 643183863Snwhitehorng_stripe_check_and_run(struct g_stripe_softc *sc) 644183863Snwhitehorn{ 645183863Snwhitehorn off_t mediasize, ms; 646183863Snwhitehorn u_int no, sectorsize = 0; 647183863Snwhitehorn 648183863Snwhitehorn g_topology_assert(); 649183863Snwhitehorn if (g_stripe_nvalid(sc) != sc->sc_ndisks) 650183863Snwhitehorn return; 651183863Snwhitehorn 652183863Snwhitehorn sc->sc_provider = g_new_providerf(sc->sc_geom, "stripe/%s", 653183863Snwhitehorn sc->sc_name); 654183863Snwhitehorn /* 655183863Snwhitehorn * Find the smallest disk. 656183863Snwhitehorn */ 657183863Snwhitehorn mediasize = sc->sc_disks[0]->provider->mediasize; 658183863Snwhitehorn if (sc->sc_type == G_STRIPE_TYPE_AUTOMATIC) 659183863Snwhitehorn mediasize -= sc->sc_disks[0]->provider->sectorsize; 660183863Snwhitehorn mediasize -= mediasize % sc->sc_stripesize; 661183863Snwhitehorn sectorsize = sc->sc_disks[0]->provider->sectorsize; 662183863Snwhitehorn for (no = 1; no < sc->sc_ndisks; no++) { 663183863Snwhitehorn ms = sc->sc_disks[no]->provider->mediasize; 664183863Snwhitehorn if (sc->sc_type == G_STRIPE_TYPE_AUTOMATIC) 665183863Snwhitehorn ms -= sc->sc_disks[no]->provider->sectorsize; 666183863Snwhitehorn ms -= ms % sc->sc_stripesize; 667183863Snwhitehorn if (ms < mediasize) 668183863Snwhitehorn mediasize = ms; 669183863Snwhitehorn sectorsize = lcm(sectorsize, 670183863Snwhitehorn sc->sc_disks[no]->provider->sectorsize); 671183863Snwhitehorn } 672183863Snwhitehorn sc->sc_provider->sectorsize = sectorsize; 673183863Snwhitehorn sc->sc_provider->mediasize = mediasize * sc->sc_ndisks; 674183863Snwhitehorn sc->sc_provider->stripesize = sc->sc_stripesize; 675183863Snwhitehorn sc->sc_provider->stripeoffset = 0; 676183863Snwhitehorn g_error_provider(sc->sc_provider, 0); 677183863Snwhitehorn 678183863Snwhitehorn G_STRIPE_DEBUG(0, "Device %s activated.", sc->sc_provider->name); 679183863Snwhitehorn} 680183863Snwhitehorn 681183863Snwhitehornstatic int 682183863Snwhitehorng_stripe_read_metadata(struct g_consumer *cp, struct g_stripe_metadata *md) 683183863Snwhitehorn{ 684183863Snwhitehorn struct g_provider *pp; 685183863Snwhitehorn u_char *buf; 686183863Snwhitehorn int error; 687183863Snwhitehorn 688183863Snwhitehorn g_topology_assert(); 689183863Snwhitehorn 690183863Snwhitehorn error = g_access(cp, 1, 0, 0); 691183863Snwhitehorn if (error != 0) 692183863Snwhitehorn return (error); 693183863Snwhitehorn pp = cp->provider; 694183863Snwhitehorn g_topology_unlock(); 695183863Snwhitehorn buf = g_read_data(cp, pp->mediasize - pp->sectorsize, pp->sectorsize, 696183863Snwhitehorn &error); 697183863Snwhitehorn g_topology_lock(); 698183863Snwhitehorn g_access(cp, -1, 0, 0); 699183863Snwhitehorn if (buf == NULL) 700183863Snwhitehorn return (error); 701183863Snwhitehorn 702183863Snwhitehorn /* Decode metadata. */ 703183863Snwhitehorn stripe_metadata_decode(buf, md); 704183863Snwhitehorn g_free(buf); 705183863Snwhitehorn 706183863Snwhitehorn return (0); 707183863Snwhitehorn} 708183863Snwhitehorn 709183863Snwhitehorn/* 710183863Snwhitehorn * Add disk to given device. 711183863Snwhitehorn */ 712183863Snwhitehornstatic int 713183863Snwhitehorng_stripe_add_disk(struct g_stripe_softc *sc, struct g_provider *pp, u_int no) 714183863Snwhitehorn{ 715183863Snwhitehorn struct g_consumer *cp, *fcp; 716183863Snwhitehorn struct g_geom *gp; 717183863Snwhitehorn int error; 718183863Snwhitehorn 719183863Snwhitehorn g_topology_assert(); 720183863Snwhitehorn /* Metadata corrupted? */ 721183863Snwhitehorn if (no >= sc->sc_ndisks) 722183863Snwhitehorn return (EINVAL); 723183863Snwhitehorn 724183863Snwhitehorn /* Check if disk is not already attached. */ 725183863Snwhitehorn if (sc->sc_disks[no] != NULL) 726183863Snwhitehorn return (EEXIST); 727183863Snwhitehorn 728183863Snwhitehorn gp = sc->sc_geom; 729183863Snwhitehorn fcp = LIST_FIRST(&gp->consumer); 730183863Snwhitehorn 731183863Snwhitehorn cp = g_new_consumer(gp); 732183863Snwhitehorn cp->private = NULL; 733183863Snwhitehorn cp->index = no; 734183863Snwhitehorn error = g_attach(cp, pp); 735183863Snwhitehorn if (error != 0) { 736183863Snwhitehorn g_destroy_consumer(cp); 737183863Snwhitehorn return (error); 738183863Snwhitehorn } 739183863Snwhitehorn 740183863Snwhitehorn if (fcp != NULL && (fcp->acr > 0 || fcp->acw > 0 || fcp->ace > 0)) { 741183863Snwhitehorn error = g_access(cp, fcp->acr, fcp->acw, fcp->ace); 742183863Snwhitehorn if (error != 0) { 743183863Snwhitehorn g_detach(cp); 744183863Snwhitehorn g_destroy_consumer(cp); 745183863Snwhitehorn return (error); 746183863Snwhitehorn } 747183863Snwhitehorn } 748183863Snwhitehorn if (sc->sc_type == G_STRIPE_TYPE_AUTOMATIC) { 749183863Snwhitehorn struct g_stripe_metadata md; 750183863Snwhitehorn 751183863Snwhitehorn /* Reread metadata. */ 752183863Snwhitehorn error = g_stripe_read_metadata(cp, &md); 753183863Snwhitehorn if (error != 0) 754183863Snwhitehorn goto fail; 755183863Snwhitehorn 756183863Snwhitehorn if (strcmp(md.md_magic, G_STRIPE_MAGIC) != 0 || 757183863Snwhitehorn strcmp(md.md_name, sc->sc_name) != 0 || 758183863Snwhitehorn md.md_id != sc->sc_id) { 759183863Snwhitehorn G_STRIPE_DEBUG(0, "Metadata on %s changed.", pp->name); 760183863Snwhitehorn goto fail; 761183863Snwhitehorn } 762183863Snwhitehorn } 763183863Snwhitehorn 764183863Snwhitehorn sc->sc_disks[no] = cp; 765183863Snwhitehorn G_STRIPE_DEBUG(0, "Disk %s attached to %s.", pp->name, sc->sc_name); 766183863Snwhitehorn g_stripe_check_and_run(sc); 767 768 return (0); 769fail: 770 if (fcp != NULL && (fcp->acr > 0 || fcp->acw > 0 || fcp->ace > 0)) 771 g_access(cp, -fcp->acr, -fcp->acw, -fcp->ace); 772 g_detach(cp); 773 g_destroy_consumer(cp); 774 return (error); 775} 776 777static struct g_geom * 778g_stripe_create(struct g_class *mp, const struct g_stripe_metadata *md, 779 u_int type) 780{ 781 struct g_stripe_softc *sc; 782 struct g_geom *gp; 783 u_int no; 784 785 g_topology_assert(); 786 G_STRIPE_DEBUG(1, "Creating device %s (id=%u).", md->md_name, 787 md->md_id); 788 789 /* Two disks is minimum. */ 790 if (md->md_all < 2) { 791 G_STRIPE_DEBUG(0, "Too few disks defined for %s.", md->md_name); 792 return (NULL); 793 } 794#if 0 795 /* Stripe size have to be grater than or equal to sector size. */ 796 if (md->md_stripesize < sectorsize) { 797 G_STRIPE_DEBUG(0, "Invalid stripe size for %s.", md->md_name); 798 return (NULL); 799 } 800#endif 801 /* Stripe size have to be power of 2. */ 802 if (!powerof2(md->md_stripesize)) { 803 G_STRIPE_DEBUG(0, "Invalid stripe size for %s.", md->md_name); 804 return (NULL); 805 } 806 807 /* Check for duplicate unit */ 808 LIST_FOREACH(gp, &mp->geom, geom) { 809 sc = gp->softc; 810 if (sc != NULL && strcmp(sc->sc_name, md->md_name) == 0) { 811 G_STRIPE_DEBUG(0, "Device %s already configured.", 812 sc->sc_name); 813 return (NULL); 814 } 815 } 816 gp = g_new_geomf(mp, "%s", md->md_name); 817 sc = malloc(sizeof(*sc), M_STRIPE, M_WAITOK | M_ZERO); 818 gp->start = g_stripe_start; 819 gp->spoiled = g_stripe_orphan; 820 gp->orphan = g_stripe_orphan; 821 gp->access = g_stripe_access; 822 gp->dumpconf = g_stripe_dumpconf; 823 824 sc->sc_id = md->md_id; 825 sc->sc_stripesize = md->md_stripesize; 826 sc->sc_stripebits = bitcount32(sc->sc_stripesize - 1); 827 sc->sc_ndisks = md->md_all; 828 sc->sc_disks = malloc(sizeof(struct g_consumer *) * sc->sc_ndisks, 829 M_STRIPE, M_WAITOK | M_ZERO); 830 for (no = 0; no < sc->sc_ndisks; no++) 831 sc->sc_disks[no] = NULL; 832 sc->sc_type = type; 833 834 gp->softc = sc; 835 sc->sc_geom = gp; 836 sc->sc_provider = NULL; 837 838 G_STRIPE_DEBUG(0, "Device %s created (id=%u).", sc->sc_name, sc->sc_id); 839 840 return (gp); 841} 842 843static int 844g_stripe_destroy(struct g_stripe_softc *sc, boolean_t force) 845{ 846 struct g_provider *pp; 847 struct g_consumer *cp, *cp1; 848 struct g_geom *gp; 849 850 g_topology_assert(); 851 852 if (sc == NULL) 853 return (ENXIO); 854 855 pp = sc->sc_provider; 856 if (pp != NULL && (pp->acr != 0 || pp->acw != 0 || pp->ace != 0)) { 857 if (force) { 858 G_STRIPE_DEBUG(0, "Device %s is still open, so it " 859 "can't be definitely removed.", pp->name); 860 } else { 861 G_STRIPE_DEBUG(1, 862 "Device %s is still open (r%dw%de%d).", pp->name, 863 pp->acr, pp->acw, pp->ace); 864 return (EBUSY); 865 } 866 } 867 868 gp = sc->sc_geom; 869 LIST_FOREACH_SAFE(cp, &gp->consumer, consumer, cp1) { 870 g_stripe_remove_disk(cp); 871 if (cp1 == NULL) 872 return (0); /* Recursion happened. */ 873 } 874 if (!LIST_EMPTY(&gp->consumer)) 875 return (EINPROGRESS); 876 877 gp->softc = NULL; 878 KASSERT(sc->sc_provider == NULL, ("Provider still exists? (device=%s)", 879 gp->name)); 880 free(sc->sc_disks, M_STRIPE); 881 free(sc, M_STRIPE); 882 G_STRIPE_DEBUG(0, "Device %s destroyed.", gp->name); 883 g_wither_geom(gp, ENXIO); 884 return (0); 885} 886 887static int 888g_stripe_destroy_geom(struct gctl_req *req __unused, 889 struct g_class *mp __unused, struct g_geom *gp) 890{ 891 struct g_stripe_softc *sc; 892 893 sc = gp->softc; 894 return (g_stripe_destroy(sc, 0)); 895} 896 897static struct g_geom * 898g_stripe_taste(struct g_class *mp, struct g_provider *pp, int flags __unused) 899{ 900 struct g_stripe_metadata md; 901 struct g_stripe_softc *sc; 902 struct g_consumer *cp; 903 struct g_geom *gp; 904 int error; 905 906 g_trace(G_T_TOPOLOGY, "%s(%s, %s)", __func__, mp->name, pp->name); 907 g_topology_assert(); 908 909 /* Skip providers that are already open for writing. */ 910 if (pp->acw > 0) 911 return (NULL); 912 913 G_STRIPE_DEBUG(3, "Tasting %s.", pp->name); 914 915 gp = g_new_geomf(mp, "stripe:taste"); 916 gp->start = g_stripe_start; 917 gp->access = g_stripe_access; 918 gp->orphan = g_stripe_orphan; 919 cp = g_new_consumer(gp); 920 g_attach(cp, pp); 921 error = g_stripe_read_metadata(cp, &md); 922 g_detach(cp); 923 g_destroy_consumer(cp); 924 g_destroy_geom(gp); 925 if (error != 0) 926 return (NULL); 927 gp = NULL; 928 929 if (strcmp(md.md_magic, G_STRIPE_MAGIC) != 0) 930 return (NULL); 931 if (md.md_version > G_STRIPE_VERSION) { 932 printf("geom_stripe.ko module is too old to handle %s.\n", 933 pp->name); 934 return (NULL); 935 } 936 /* 937 * Backward compatibility: 938 */ 939 /* There was no md_provider field in earlier versions of metadata. */ 940 if (md.md_version < 2) 941 bzero(md.md_provider, sizeof(md.md_provider)); 942 /* There was no md_provsize field in earlier versions of metadata. */ 943 if (md.md_version < 3) 944 md.md_provsize = pp->mediasize; 945 946 if (md.md_provider[0] != '\0' && 947 !g_compare_names(md.md_provider, pp->name)) 948 return (NULL); 949 if (md.md_provsize != pp->mediasize) 950 return (NULL); 951 952 /* 953 * Let's check if device already exists. 954 */ 955 sc = NULL; 956 LIST_FOREACH(gp, &mp->geom, geom) { 957 sc = gp->softc; 958 if (sc == NULL) 959 continue; 960 if (sc->sc_type != G_STRIPE_TYPE_AUTOMATIC) 961 continue; 962 if (strcmp(md.md_name, sc->sc_name) != 0) 963 continue; 964 if (md.md_id != sc->sc_id) 965 continue; 966 break; 967 } 968 if (gp != NULL) { 969 G_STRIPE_DEBUG(1, "Adding disk %s to %s.", pp->name, gp->name); 970 error = g_stripe_add_disk(sc, pp, md.md_no); 971 if (error != 0) { 972 G_STRIPE_DEBUG(0, 973 "Cannot add disk %s to %s (error=%d).", pp->name, 974 gp->name, error); 975 return (NULL); 976 } 977 } else { 978 gp = g_stripe_create(mp, &md, G_STRIPE_TYPE_AUTOMATIC); 979 if (gp == NULL) { 980 G_STRIPE_DEBUG(0, "Cannot create device %s.", 981 md.md_name); 982 return (NULL); 983 } 984 sc = gp->softc; 985 G_STRIPE_DEBUG(1, "Adding disk %s to %s.", pp->name, gp->name); 986 error = g_stripe_add_disk(sc, pp, md.md_no); 987 if (error != 0) { 988 G_STRIPE_DEBUG(0, 989 "Cannot add disk %s to %s (error=%d).", pp->name, 990 gp->name, error); 991 g_stripe_destroy(sc, 1); 992 return (NULL); 993 } 994 } 995 996 return (gp); 997} 998 999static void 1000g_stripe_ctl_create(struct gctl_req *req, struct g_class *mp) 1001{ 1002 u_int attached, no; 1003 struct g_stripe_metadata md; 1004 struct g_provider *pp; 1005 struct g_stripe_softc *sc; 1006 struct g_geom *gp; 1007 struct sbuf *sb; 1008 intmax_t *stripesize; 1009 const char *name; 1010 char param[16]; 1011 int *nargs; 1012 1013 g_topology_assert(); 1014 nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs)); 1015 if (nargs == NULL) { 1016 gctl_error(req, "No '%s' argument.", "nargs"); 1017 return; 1018 } 1019 if (*nargs <= 2) { 1020 gctl_error(req, "Too few arguments."); 1021 return; 1022 } 1023 1024 strlcpy(md.md_magic, G_STRIPE_MAGIC, sizeof(md.md_magic)); 1025 md.md_version = G_STRIPE_VERSION; 1026 name = gctl_get_asciiparam(req, "arg0"); 1027 if (name == NULL) { 1028 gctl_error(req, "No 'arg%u' argument.", 0); 1029 return; 1030 } 1031 strlcpy(md.md_name, name, sizeof(md.md_name)); 1032 md.md_id = arc4random(); 1033 md.md_no = 0; 1034 md.md_all = *nargs - 1; 1035 stripesize = gctl_get_paraml(req, "stripesize", sizeof(*stripesize)); 1036 if (stripesize == NULL) { 1037 gctl_error(req, "No '%s' argument.", "stripesize"); 1038 return; 1039 } 1040 md.md_stripesize = *stripesize; 1041 bzero(md.md_provider, sizeof(md.md_provider)); 1042 /* This field is not important here. */ 1043 md.md_provsize = 0; 1044 1045 /* Check all providers are valid */ 1046 for (no = 1; no < *nargs; no++) { 1047 snprintf(param, sizeof(param), "arg%u", no); 1048 name = gctl_get_asciiparam(req, param); 1049 if (name == NULL) { 1050 gctl_error(req, "No 'arg%u' argument.", no); 1051 return; 1052 } 1053 if (strncmp(name, "/dev/", strlen("/dev/")) == 0) 1054 name += strlen("/dev/"); 1055 pp = g_provider_by_name(name); 1056 if (pp == NULL) { 1057 G_STRIPE_DEBUG(1, "Disk %s is invalid.", name); 1058 gctl_error(req, "Disk %s is invalid.", name); 1059 return; 1060 } 1061 } 1062 1063 gp = g_stripe_create(mp, &md, G_STRIPE_TYPE_MANUAL); 1064 if (gp == NULL) { 1065 gctl_error(req, "Can't configure %s.", md.md_name); 1066 return; 1067 } 1068 1069 sc = gp->softc; 1070 sb = sbuf_new_auto(); 1071 sbuf_printf(sb, "Can't attach disk(s) to %s:", gp->name); 1072 for (attached = 0, no = 1; no < *nargs; no++) { 1073 snprintf(param, sizeof(param), "arg%u", no); 1074 name = gctl_get_asciiparam(req, param); 1075 if (name == NULL) { 1076 gctl_error(req, "No 'arg%u' argument.", no); 1077 continue; 1078 } 1079 if (strncmp(name, "/dev/", strlen("/dev/")) == 0) 1080 name += strlen("/dev/"); 1081 pp = g_provider_by_name(name); 1082 KASSERT(pp != NULL, ("Provider %s disappear?!", name)); 1083 if (g_stripe_add_disk(sc, pp, no - 1) != 0) { 1084 G_STRIPE_DEBUG(1, "Disk %u (%s) not attached to %s.", 1085 no, pp->name, gp->name); 1086 sbuf_printf(sb, " %s", pp->name); 1087 continue; 1088 } 1089 attached++; 1090 } 1091 sbuf_finish(sb); 1092 if (md.md_all != attached) { 1093 g_stripe_destroy(gp->softc, 1); 1094 gctl_error(req, "%s", sbuf_data(sb)); 1095 } 1096 sbuf_delete(sb); 1097} 1098 1099static struct g_stripe_softc * 1100g_stripe_find_device(struct g_class *mp, const char *name) 1101{ 1102 struct g_stripe_softc *sc; 1103 struct g_geom *gp; 1104 1105 LIST_FOREACH(gp, &mp->geom, geom) { 1106 sc = gp->softc; 1107 if (sc == NULL) 1108 continue; 1109 if (strcmp(sc->sc_name, name) == 0) 1110 return (sc); 1111 } 1112 return (NULL); 1113} 1114 1115static void 1116g_stripe_ctl_destroy(struct gctl_req *req, struct g_class *mp) 1117{ 1118 struct g_stripe_softc *sc; 1119 int *force, *nargs, error; 1120 const char *name; 1121 char param[16]; 1122 u_int i; 1123 1124 g_topology_assert(); 1125 1126 nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs)); 1127 if (nargs == NULL) { 1128 gctl_error(req, "No '%s' argument.", "nargs"); 1129 return; 1130 } 1131 if (*nargs <= 0) { 1132 gctl_error(req, "Missing device(s)."); 1133 return; 1134 } 1135 force = gctl_get_paraml(req, "force", sizeof(*force)); 1136 if (force == NULL) { 1137 gctl_error(req, "No '%s' argument.", "force"); 1138 return; 1139 } 1140 1141 for (i = 0; i < (u_int)*nargs; i++) { 1142 snprintf(param, sizeof(param), "arg%u", i); 1143 name = gctl_get_asciiparam(req, param); 1144 if (name == NULL) { 1145 gctl_error(req, "No 'arg%u' argument.", i); 1146 return; 1147 } 1148 sc = g_stripe_find_device(mp, name); 1149 if (sc == NULL) { 1150 gctl_error(req, "No such device: %s.", name); 1151 return; 1152 } 1153 error = g_stripe_destroy(sc, *force); 1154 if (error != 0) { 1155 gctl_error(req, "Cannot destroy device %s (error=%d).", 1156 sc->sc_name, error); 1157 return; 1158 } 1159 } 1160} 1161 1162static void 1163g_stripe_config(struct gctl_req *req, struct g_class *mp, const char *verb) 1164{ 1165 uint32_t *version; 1166 1167 g_topology_assert(); 1168 1169 version = gctl_get_paraml(req, "version", sizeof(*version)); 1170 if (version == NULL) { 1171 gctl_error(req, "No '%s' argument.", "version"); 1172 return; 1173 } 1174 if (*version != G_STRIPE_VERSION) { 1175 gctl_error(req, "Userland and kernel parts are out of sync."); 1176 return; 1177 } 1178 1179 if (strcmp(verb, "create") == 0) { 1180 g_stripe_ctl_create(req, mp); 1181 return; 1182 } else if (strcmp(verb, "destroy") == 0 || 1183 strcmp(verb, "stop") == 0) { 1184 g_stripe_ctl_destroy(req, mp); 1185 return; 1186 } 1187 1188 gctl_error(req, "Unknown verb."); 1189} 1190 1191static void 1192g_stripe_dumpconf(struct sbuf *sb, const char *indent, struct g_geom *gp, 1193 struct g_consumer *cp, struct g_provider *pp) 1194{ 1195 struct g_stripe_softc *sc; 1196 1197 sc = gp->softc; 1198 if (sc == NULL) 1199 return; 1200 if (pp != NULL) { 1201 /* Nothing here. */ 1202 } else if (cp != NULL) { 1203 sbuf_printf(sb, "%s<Number>%u</Number>\n", indent, 1204 (u_int)cp->index); 1205 } else { 1206 sbuf_printf(sb, "%s<ID>%u</ID>\n", indent, (u_int)sc->sc_id); 1207 sbuf_printf(sb, "%s<Stripesize>%u</Stripesize>\n", indent, 1208 (u_int)sc->sc_stripesize); 1209 sbuf_printf(sb, "%s<Type>", indent); 1210 switch (sc->sc_type) { 1211 case G_STRIPE_TYPE_AUTOMATIC: 1212 sbuf_printf(sb, "AUTOMATIC"); 1213 break; 1214 case G_STRIPE_TYPE_MANUAL: 1215 sbuf_printf(sb, "MANUAL"); 1216 break; 1217 default: 1218 sbuf_printf(sb, "UNKNOWN"); 1219 break; 1220 } 1221 sbuf_printf(sb, "</Type>\n"); 1222 sbuf_printf(sb, "%s<Status>Total=%u, Online=%u</Status>\n", 1223 indent, sc->sc_ndisks, g_stripe_nvalid(sc)); 1224 sbuf_printf(sb, "%s<State>", indent); 1225 if (sc->sc_provider != NULL && sc->sc_provider->error == 0) 1226 sbuf_printf(sb, "UP"); 1227 else 1228 sbuf_printf(sb, "DOWN"); 1229 sbuf_printf(sb, "</State>\n"); 1230 } 1231} 1232 1233DECLARE_GEOM_CLASS(g_stripe_class, g_stripe); 1234