geom_vinum_plex.c revision 140590
10Sstevel@tonic-gate/*- 20Sstevel@tonic-gate * Copyright (c) 2004 Lukas Ertl 30Sstevel@tonic-gate * All rights reserved. 40Sstevel@tonic-gate * 50Sstevel@tonic-gate * Redistribution and use in source and binary forms, with or without 60Sstevel@tonic-gate * modification, are permitted provided that the following conditions 70Sstevel@tonic-gate * are met: 80Sstevel@tonic-gate * 1. Redistributions of source code must retain the above copyright 90Sstevel@tonic-gate * notice, this list of conditions and the following disclaimer. 100Sstevel@tonic-gate * 2. Redistributions in binary form must reproduce the above copyright 110Sstevel@tonic-gate * notice, this list of conditions and the following disclaimer in the 120Sstevel@tonic-gate * documentation and/or other materials provided with the distribution. 130Sstevel@tonic-gate * 140Sstevel@tonic-gate * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 150Sstevel@tonic-gate * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 160Sstevel@tonic-gate * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 170Sstevel@tonic-gate * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 180Sstevel@tonic-gate * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 190Sstevel@tonic-gate * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 200Sstevel@tonic-gate * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 210Sstevel@tonic-gate * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 220Sstevel@tonic-gate * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 230Sstevel@tonic-gate * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 240Sstevel@tonic-gate * SUCH DAMAGE. 250Sstevel@tonic-gate */ 260Sstevel@tonic-gate 270Sstevel@tonic-gate#include <sys/cdefs.h> 280Sstevel@tonic-gate__FBSDID("$FreeBSD: head/sys/geom/vinum/geom_vinum_plex.c 140590 2005-01-21 18:24:20Z le $"); 290Sstevel@tonic-gate 300Sstevel@tonic-gate#include <sys/param.h> 310Sstevel@tonic-gate#include <sys/bio.h> 320Sstevel@tonic-gate#include <sys/kernel.h> 330Sstevel@tonic-gate#include <sys/kthread.h> 340Sstevel@tonic-gate#include <sys/libkern.h> 350Sstevel@tonic-gate#include <sys/lock.h> 360Sstevel@tonic-gate#include <sys/malloc.h> 370Sstevel@tonic-gate#include <sys/module.h> 380Sstevel@tonic-gate#include <sys/mutex.h> 390Sstevel@tonic-gate#include <sys/systm.h> 400Sstevel@tonic-gate 410Sstevel@tonic-gate#include <geom/geom.h> 420Sstevel@tonic-gate#include <geom/vinum/geom_vinum_var.h> 430Sstevel@tonic-gate#include <geom/vinum/geom_vinum_raid5.h> 440Sstevel@tonic-gate#include <geom/vinum/geom_vinum.h> 450Sstevel@tonic-gate 460Sstevel@tonic-gatestatic void gv_plex_completed_request(struct gv_plex *, struct bio *); 470Sstevel@tonic-gatestatic void gv_plex_normal_request(struct gv_plex *, struct bio *); 480Sstevel@tonic-gatestatic void gv_plex_worker(void *); 490Sstevel@tonic-gatestatic int gv_check_parity(struct gv_plex *, struct bio *, 500Sstevel@tonic-gate struct gv_raid5_packet *); 510Sstevel@tonic-gatestatic int gv_normal_parity(struct gv_plex *, struct bio *, 520Sstevel@tonic-gate struct gv_raid5_packet *); 530Sstevel@tonic-gate 540Sstevel@tonic-gate/* XXX: is this the place to catch dying subdisks? */ 550Sstevel@tonic-gatestatic void 560Sstevel@tonic-gategv_plex_orphan(struct g_consumer *cp) 570Sstevel@tonic-gate{ 580Sstevel@tonic-gate struct g_geom *gp; 590Sstevel@tonic-gate struct gv_plex *p; 600Sstevel@tonic-gate int error; 610Sstevel@tonic-gate 620Sstevel@tonic-gate g_topology_assert(); 630Sstevel@tonic-gate gp = cp->geom; 640Sstevel@tonic-gate g_trace(G_T_TOPOLOGY, "gv_plex_orphan(%s)", gp->name); 650Sstevel@tonic-gate 660Sstevel@tonic-gate if (cp->acr != 0 || cp->acw != 0 || cp->ace != 0) 670Sstevel@tonic-gate g_access(cp, -cp->acr, -cp->acw, -cp->ace); 680Sstevel@tonic-gate error = cp->provider->error; 690Sstevel@tonic-gate if (error == 0) 700Sstevel@tonic-gate error = ENXIO; 710Sstevel@tonic-gate g_detach(cp); 720Sstevel@tonic-gate g_destroy_consumer(cp); 730Sstevel@tonic-gate if (!LIST_EMPTY(&gp->consumer)) 740Sstevel@tonic-gate return; 750Sstevel@tonic-gate 760Sstevel@tonic-gate p = gp->softc; 770Sstevel@tonic-gate if (p != NULL) { 780Sstevel@tonic-gate gv_kill_plex_thread(p); 790Sstevel@tonic-gate p->geom = NULL; 800Sstevel@tonic-gate p->provider = NULL; 810Sstevel@tonic-gate p->consumer = NULL; 820Sstevel@tonic-gate } 830Sstevel@tonic-gate gp->softc = NULL; 840Sstevel@tonic-gate g_wither_geom(gp, error); 850Sstevel@tonic-gate} 860Sstevel@tonic-gate 870Sstevel@tonic-gatevoid 880Sstevel@tonic-gategv_plex_done(struct bio *bp) 890Sstevel@tonic-gate{ 900Sstevel@tonic-gate struct gv_plex *p; 910Sstevel@tonic-gate struct gv_bioq *bq; 920Sstevel@tonic-gate 930Sstevel@tonic-gate p = bp->bio_from->geom->softc; 940Sstevel@tonic-gate bp->bio_cflags |= GV_BIO_DONE; 950Sstevel@tonic-gate bq = g_malloc(sizeof(*bq), M_NOWAIT | M_ZERO); 960Sstevel@tonic-gate bq->bp = bp; 970Sstevel@tonic-gate mtx_lock(&p->bqueue_mtx); 980Sstevel@tonic-gate TAILQ_INSERT_TAIL(&p->bqueue, bq, queue); 990Sstevel@tonic-gate wakeup(p); 1000Sstevel@tonic-gate mtx_unlock(&p->bqueue_mtx); 1010Sstevel@tonic-gate} 1020Sstevel@tonic-gate 1030Sstevel@tonic-gate/* Find the correct subdisk to send the bio to and build a bio to send. */ 1040Sstevel@tonic-gatestatic int 1050Sstevel@tonic-gategv_plexbuffer(struct gv_plex *p, struct bio *bp, caddr_t addr, off_t boff, off_t bcount) 1060Sstevel@tonic-gate{ 1070Sstevel@tonic-gate struct g_geom *gp; 1080Sstevel@tonic-gate struct gv_sd *s; 1090Sstevel@tonic-gate struct bio *cbp, *pbp; 1100Sstevel@tonic-gate int i, sdno; 1110Sstevel@tonic-gate off_t len_left, real_len, real_off; 1120Sstevel@tonic-gate off_t stripeend, stripeno, stripestart; 1130Sstevel@tonic-gate 1140Sstevel@tonic-gate if (p == NULL || LIST_EMPTY(&p->subdisks)) 1150Sstevel@tonic-gate return (ENXIO); 1160Sstevel@tonic-gate 1170Sstevel@tonic-gate s = NULL; 1180Sstevel@tonic-gate gp = bp->bio_to->geom; 1190Sstevel@tonic-gate 1200Sstevel@tonic-gate /* 1210Sstevel@tonic-gate * We only handle concatenated and striped plexes here. RAID5 plexes 1220Sstevel@tonic-gate * are handled in build_raid5_request(). 1230Sstevel@tonic-gate */ 1240Sstevel@tonic-gate switch (p->org) { 1250Sstevel@tonic-gate case GV_PLEX_CONCAT: 1260Sstevel@tonic-gate /* 1270Sstevel@tonic-gate * Find the subdisk where this request starts. The subdisks in 1280Sstevel@tonic-gate * this list must be ordered by plex_offset. 1290Sstevel@tonic-gate */ 1300Sstevel@tonic-gate LIST_FOREACH(s, &p->subdisks, in_plex) { 1310Sstevel@tonic-gate if (s->plex_offset <= boff && 1320Sstevel@tonic-gate s->plex_offset + s->size > boff) 1330Sstevel@tonic-gate break; 1340Sstevel@tonic-gate } 1350Sstevel@tonic-gate /* Subdisk not found. */ 1360Sstevel@tonic-gate if (s == NULL) 1370Sstevel@tonic-gate return (ENXIO); 1380Sstevel@tonic-gate 1390Sstevel@tonic-gate /* Calculate corresponding offsets on disk. */ 1400Sstevel@tonic-gate real_off = boff - s->plex_offset; 1410Sstevel@tonic-gate len_left = s->size - real_off; 1420Sstevel@tonic-gate real_len = (bcount > len_left) ? len_left : bcount; 1430Sstevel@tonic-gate break; 1440Sstevel@tonic-gate 1450Sstevel@tonic-gate case GV_PLEX_STRIPED: 1460Sstevel@tonic-gate /* The number of the stripe where the request starts. */ 1470Sstevel@tonic-gate stripeno = boff / p->stripesize; 1480Sstevel@tonic-gate 1490Sstevel@tonic-gate /* The number of the subdisk where the stripe resides. */ 1500Sstevel@tonic-gate sdno = stripeno % p->sdcount; 1510Sstevel@tonic-gate 1520Sstevel@tonic-gate /* Find the right subdisk. */ 1530Sstevel@tonic-gate i = 0; 1540Sstevel@tonic-gate LIST_FOREACH(s, &p->subdisks, in_plex) { 1550Sstevel@tonic-gate if (i == sdno) 1560Sstevel@tonic-gate break; 1570Sstevel@tonic-gate i++; 1580Sstevel@tonic-gate } 1590Sstevel@tonic-gate 1600Sstevel@tonic-gate /* Subdisk not found. */ 1610Sstevel@tonic-gate if (s == NULL) 1620Sstevel@tonic-gate return (ENXIO); 1630Sstevel@tonic-gate 1640Sstevel@tonic-gate /* The offset of the stripe from the start of the subdisk. */ 1650Sstevel@tonic-gate stripestart = (stripeno / p->sdcount) * 1660Sstevel@tonic-gate p->stripesize; 1670Sstevel@tonic-gate 1680Sstevel@tonic-gate /* The offset at the end of the stripe. */ 1690Sstevel@tonic-gate stripeend = stripestart + p->stripesize; 1700Sstevel@tonic-gate 1710Sstevel@tonic-gate /* The offset of the request on this subdisk. */ 1720Sstevel@tonic-gate real_off = boff - (stripeno * p->stripesize) + 1730Sstevel@tonic-gate stripestart; 1740Sstevel@tonic-gate 1750Sstevel@tonic-gate /* The length left in this stripe. */ 1760Sstevel@tonic-gate len_left = stripeend - real_off; 1770Sstevel@tonic-gate 1780Sstevel@tonic-gate real_len = (bcount <= len_left) ? bcount : len_left; 1790Sstevel@tonic-gate break; 1800Sstevel@tonic-gate 1810Sstevel@tonic-gate default: 1820Sstevel@tonic-gate return (EINVAL); 1830Sstevel@tonic-gate } 1840Sstevel@tonic-gate 1850Sstevel@tonic-gate /* Now check if we can handle the request on this subdisk. */ 1860Sstevel@tonic-gate switch (s->state) { 1870Sstevel@tonic-gate case GV_SD_UP: 1880Sstevel@tonic-gate /* If the subdisk is up, just continue. */ 1890Sstevel@tonic-gate break; 1900Sstevel@tonic-gate 1910Sstevel@tonic-gate case GV_SD_STALE: 1920Sstevel@tonic-gate if (!(bp->bio_cflags & GV_BIO_SYNCREQ)) 1930Sstevel@tonic-gate return (ENXIO); 1940Sstevel@tonic-gate 1950Sstevel@tonic-gate printf("GEOM_VINUM: sd %s is initializing\n", s->name); 1960Sstevel@tonic-gate gv_set_sd_state(s, GV_SD_INITIALIZING, GV_SETSTATE_FORCE); 1970Sstevel@tonic-gate break; 1980Sstevel@tonic-gate 1990Sstevel@tonic-gate case GV_SD_INITIALIZING: 2000Sstevel@tonic-gate if (bp->bio_cmd == BIO_READ) 2010Sstevel@tonic-gate return (ENXIO); 2020Sstevel@tonic-gate break; 2030Sstevel@tonic-gate 2040Sstevel@tonic-gate default: 2050Sstevel@tonic-gate /* All other subdisk states mean it's not accessible. */ 2060Sstevel@tonic-gate return (ENXIO); 2070Sstevel@tonic-gate } 2080Sstevel@tonic-gate 2090Sstevel@tonic-gate /* Clone the bio and adjust the offsets and sizes. */ 2100Sstevel@tonic-gate cbp = g_clone_bio(bp); 2110Sstevel@tonic-gate if (cbp == NULL) 2120Sstevel@tonic-gate return (ENOMEM); 2130Sstevel@tonic-gate cbp->bio_offset = real_off; 2140Sstevel@tonic-gate cbp->bio_length = real_len; 2150Sstevel@tonic-gate cbp->bio_data = addr; 2160Sstevel@tonic-gate cbp->bio_done = g_std_done; 2170Sstevel@tonic-gate cbp->bio_caller2 = s->consumer; 2180Sstevel@tonic-gate if ((bp->bio_cflags & GV_BIO_SYNCREQ)) { 2190Sstevel@tonic-gate cbp->bio_cflags |= GV_BIO_SYNCREQ; 2200Sstevel@tonic-gate cbp->bio_done = gv_plex_done; 2210Sstevel@tonic-gate } 2220Sstevel@tonic-gate 2230Sstevel@tonic-gate if (bp->bio_driver1 == NULL) { 2240Sstevel@tonic-gate bp->bio_driver1 = cbp; 2250Sstevel@tonic-gate } else { 2260Sstevel@tonic-gate pbp = bp->bio_driver1; 2270Sstevel@tonic-gate while (pbp->bio_caller1 != NULL) 2280Sstevel@tonic-gate pbp = pbp->bio_caller1; 2290Sstevel@tonic-gate pbp->bio_caller1 = cbp; 2300Sstevel@tonic-gate } 2310Sstevel@tonic-gate 2320Sstevel@tonic-gate return (0); 2330Sstevel@tonic-gate} 2340Sstevel@tonic-gate 2350Sstevel@tonic-gatestatic void 2360Sstevel@tonic-gategv_plex_start(struct bio *bp) 2370Sstevel@tonic-gate{ 2380Sstevel@tonic-gate struct gv_plex *p; 2390Sstevel@tonic-gate struct gv_bioq *bq; 2400Sstevel@tonic-gate 2410Sstevel@tonic-gate switch(bp->bio_cmd) { 2420Sstevel@tonic-gate case BIO_READ: 2430Sstevel@tonic-gate case BIO_WRITE: 2440Sstevel@tonic-gate case BIO_DELETE: 2450Sstevel@tonic-gate break; 2460Sstevel@tonic-gate case BIO_GETATTR: 2470Sstevel@tonic-gate default: 2480Sstevel@tonic-gate g_io_deliver(bp, EOPNOTSUPP); 2490Sstevel@tonic-gate return; 2500Sstevel@tonic-gate } 2510Sstevel@tonic-gate 2520Sstevel@tonic-gate /* 2530Sstevel@tonic-gate * We cannot handle this request if too many of our subdisks are 2540Sstevel@tonic-gate * inaccessible. 2550Sstevel@tonic-gate */ 2560Sstevel@tonic-gate p = bp->bio_to->geom->softc; 2570Sstevel@tonic-gate if ((p->state < GV_PLEX_DEGRADED) && 2580Sstevel@tonic-gate !(bp->bio_cflags & GV_BIO_SYNCREQ)) { 2590Sstevel@tonic-gate g_io_deliver(bp, ENXIO); 2600Sstevel@tonic-gate return; 2610Sstevel@tonic-gate } 2620Sstevel@tonic-gate 2630Sstevel@tonic-gate bq = g_malloc(sizeof(*bq), M_NOWAIT | M_ZERO); 2640Sstevel@tonic-gate bq->bp = bp; 2650Sstevel@tonic-gate mtx_lock(&p->bqueue_mtx); 2660Sstevel@tonic-gate TAILQ_INSERT_TAIL(&p->bqueue, bq, queue); 2670Sstevel@tonic-gate wakeup(p); 2680Sstevel@tonic-gate mtx_unlock(&p->bqueue_mtx); 2690Sstevel@tonic-gate} 2700Sstevel@tonic-gate 2710Sstevel@tonic-gatestatic void 2720Sstevel@tonic-gategv_plex_worker(void *arg) 2730Sstevel@tonic-gate{ 2740Sstevel@tonic-gate struct bio *bp; 2750Sstevel@tonic-gate struct gv_plex *p; 2760Sstevel@tonic-gate struct gv_sd *s; 2770Sstevel@tonic-gate struct gv_bioq *bq; 2780Sstevel@tonic-gate 2790Sstevel@tonic-gate p = arg; 2800Sstevel@tonic-gate KASSERT(p != NULL, ("NULL p")); 2810Sstevel@tonic-gate 2820Sstevel@tonic-gate mtx_lock(&p->bqueue_mtx); 2830Sstevel@tonic-gate for (;;) { 2840Sstevel@tonic-gate /* We were signaled to exit. */ 2850Sstevel@tonic-gate if (p->flags & GV_PLEX_THREAD_DIE) 2860Sstevel@tonic-gate break; 2870Sstevel@tonic-gate 2880Sstevel@tonic-gate /* Take the first BIO from our queue. */ 2890Sstevel@tonic-gate bq = TAILQ_FIRST(&p->bqueue); 2900Sstevel@tonic-gate if (bq == NULL) { 2910Sstevel@tonic-gate msleep(p, &p->bqueue_mtx, PRIBIO, "-", hz/10); 2920Sstevel@tonic-gate continue; 2930Sstevel@tonic-gate } 2940Sstevel@tonic-gate TAILQ_REMOVE(&p->bqueue, bq, queue); 2950Sstevel@tonic-gate mtx_unlock(&p->bqueue_mtx); 2960Sstevel@tonic-gate 2970Sstevel@tonic-gate bp = bq->bp; 2980Sstevel@tonic-gate 2990Sstevel@tonic-gate /* A completed request. */ 3000Sstevel@tonic-gate if (bp->bio_cflags & GV_BIO_DONE) { 3010Sstevel@tonic-gate g_free(bq); 3020Sstevel@tonic-gate 3030Sstevel@tonic-gate if (bp->bio_cflags & GV_BIO_SYNCREQ || 3040Sstevel@tonic-gate bp->bio_cflags & GV_BIO_REBUILD) { 3050Sstevel@tonic-gate s = bp->bio_to->private; 3060Sstevel@tonic-gate if (bp->bio_error == 0) 3070Sstevel@tonic-gate s->initialized += bp->bio_length; 3080Sstevel@tonic-gate if (s->initialized >= s->size) { 3090Sstevel@tonic-gate g_topology_lock(); 3100Sstevel@tonic-gate gv_set_sd_state(s, GV_SD_UP, 3110Sstevel@tonic-gate GV_SETSTATE_CONFIG); 3120Sstevel@tonic-gate g_topology_unlock(); 3130Sstevel@tonic-gate s->initialized = 0; 3140Sstevel@tonic-gate } 3150Sstevel@tonic-gate } 3160Sstevel@tonic-gate 3170Sstevel@tonic-gate if (bp->bio_cflags & GV_BIO_SYNCREQ) 3180Sstevel@tonic-gate g_std_done(bp); 3190Sstevel@tonic-gate else 3200Sstevel@tonic-gate gv_plex_completed_request(p, bp); 3210Sstevel@tonic-gate /* 3220Sstevel@tonic-gate * A sub-request that was hold back because it interfered with 3230Sstevel@tonic-gate * another sub-request. 3240Sstevel@tonic-gate */ 3250Sstevel@tonic-gate } else if (bp->bio_cflags & GV_BIO_ONHOLD) { 3260Sstevel@tonic-gate /* Is it still locked out? */ 3270Sstevel@tonic-gate if (gv_stripe_active(p, bp)) { 3280Sstevel@tonic-gate /* Park the bio on the waiting queue. */ 3290Sstevel@tonic-gate mtx_lock(&p->bqueue_mtx); 3300Sstevel@tonic-gate TAILQ_INSERT_TAIL(&p->wqueue, bq, queue); 3310Sstevel@tonic-gate mtx_unlock(&p->bqueue_mtx); 3320Sstevel@tonic-gate } else { 3330Sstevel@tonic-gate g_free(bq); 3340Sstevel@tonic-gate bp->bio_cflags &= ~GV_BIO_ONHOLD; 3350Sstevel@tonic-gate g_io_request(bp, bp->bio_caller2); 3360Sstevel@tonic-gate } 3370Sstevel@tonic-gate 3380Sstevel@tonic-gate /* A normal request to this plex. */ 3390Sstevel@tonic-gate } else { 3400Sstevel@tonic-gate g_free(bq); 3410Sstevel@tonic-gate gv_plex_normal_request(p, bp); 3420Sstevel@tonic-gate } 3430Sstevel@tonic-gate 3440Sstevel@tonic-gate mtx_lock(&p->bqueue_mtx); 3450Sstevel@tonic-gate } 3460Sstevel@tonic-gate mtx_unlock(&p->bqueue_mtx); 3470Sstevel@tonic-gate p->flags |= GV_PLEX_THREAD_DEAD; 3480Sstevel@tonic-gate wakeup(p); 3490Sstevel@tonic-gate 3500Sstevel@tonic-gate kthread_exit(ENXIO); 3510Sstevel@tonic-gate} 3520Sstevel@tonic-gate 3530Sstevel@tonic-gatestatic int 3540Sstevel@tonic-gategv_normal_parity(struct gv_plex *p, struct bio *bp, struct gv_raid5_packet *wp) 3550Sstevel@tonic-gate{ 3560Sstevel@tonic-gate struct bio *cbp, *pbp; 3570Sstevel@tonic-gate int finished, i; 3580Sstevel@tonic-gate 3590Sstevel@tonic-gate finished = 1; 3600Sstevel@tonic-gate 3610Sstevel@tonic-gate if (wp->waiting != NULL) { 3620Sstevel@tonic-gate pbp = wp->waiting; 3630Sstevel@tonic-gate wp->waiting = NULL; 3640Sstevel@tonic-gate cbp = wp->parity; 3650Sstevel@tonic-gate for (i = 0; i < wp->length; i++) 3660Sstevel@tonic-gate cbp->bio_data[i] ^= pbp->bio_data[i]; 3670Sstevel@tonic-gate g_io_request(pbp, pbp->bio_caller2); 3680Sstevel@tonic-gate finished = 0; 3690Sstevel@tonic-gate 3700Sstevel@tonic-gate } else if (wp->parity != NULL) { 3710Sstevel@tonic-gate cbp = wp->parity; 3720Sstevel@tonic-gate wp->parity = NULL; 3730Sstevel@tonic-gate g_io_request(cbp, cbp->bio_caller2); 3740Sstevel@tonic-gate finished = 0; 3750Sstevel@tonic-gate } 3760Sstevel@tonic-gate 3770Sstevel@tonic-gate return (finished); 3780Sstevel@tonic-gate} 3790Sstevel@tonic-gate 3800Sstevel@tonic-gatestatic int 3810Sstevel@tonic-gategv_check_parity(struct gv_plex *p, struct bio *bp, struct gv_raid5_packet *wp) 3820Sstevel@tonic-gate{ 3830Sstevel@tonic-gate struct bio *cbp, *pbp; 3840Sstevel@tonic-gate int err, finished, i; 3850Sstevel@tonic-gate 3860Sstevel@tonic-gate err = 0; 3870Sstevel@tonic-gate finished = 1; 3880Sstevel@tonic-gate 3890Sstevel@tonic-gate if (wp->waiting != NULL) { 3900Sstevel@tonic-gate pbp = wp->waiting; 3910Sstevel@tonic-gate wp->waiting = NULL; 3920Sstevel@tonic-gate g_io_request(pbp, pbp->bio_caller2); 3930Sstevel@tonic-gate finished = 0; 3940Sstevel@tonic-gate 3950Sstevel@tonic-gate } else if (wp->parity != NULL) { 3960Sstevel@tonic-gate cbp = wp->parity; 3970Sstevel@tonic-gate wp->parity = NULL; 3980Sstevel@tonic-gate 3990Sstevel@tonic-gate /* Check if the parity is correct. */ 4000Sstevel@tonic-gate for (i = 0; i < wp->length; i++) { 4010Sstevel@tonic-gate if (bp->bio_data[i] != cbp->bio_data[i]) { 4020Sstevel@tonic-gate err = 1; 4030Sstevel@tonic-gate break; 4040Sstevel@tonic-gate } 4050Sstevel@tonic-gate } 4060Sstevel@tonic-gate 4070Sstevel@tonic-gate /* The parity is not correct... */ 4080Sstevel@tonic-gate if (err) { 4090Sstevel@tonic-gate bp->bio_parent->bio_error = EAGAIN; 4100Sstevel@tonic-gate 4110Sstevel@tonic-gate /* ... but we rebuild it. */ 4120Sstevel@tonic-gate if (bp->bio_parent->bio_cflags & GV_BIO_PARITY) { 4130Sstevel@tonic-gate g_io_request(cbp, cbp->bio_caller2); 4140Sstevel@tonic-gate finished = 0; 4150Sstevel@tonic-gate } 4160Sstevel@tonic-gate } 4170Sstevel@tonic-gate 4180Sstevel@tonic-gate /* 4190Sstevel@tonic-gate * Clean up the BIO we would have used for rebuilding the 4200Sstevel@tonic-gate * parity. 4210Sstevel@tonic-gate */ 4220Sstevel@tonic-gate if (finished) { 4230Sstevel@tonic-gate bp->bio_parent->bio_inbed++; 4240Sstevel@tonic-gate g_destroy_bio(cbp); 4250Sstevel@tonic-gate } 4260Sstevel@tonic-gate 4270Sstevel@tonic-gate } 4280Sstevel@tonic-gate 4290Sstevel@tonic-gate return (finished); 4300Sstevel@tonic-gate} 4310Sstevel@tonic-gate 4320Sstevel@tonic-gatevoid 4330Sstevel@tonic-gategv_plex_completed_request(struct gv_plex *p, struct bio *bp) 4340Sstevel@tonic-gate{ 4350Sstevel@tonic-gate struct bio *cbp, *pbp; 4360Sstevel@tonic-gate struct gv_bioq *bq, *bq2; 4370Sstevel@tonic-gate struct gv_raid5_packet *wp; 4380Sstevel@tonic-gate int i; 4390Sstevel@tonic-gate 4400Sstevel@tonic-gate wp = bp->bio_driver1; 4410Sstevel@tonic-gate 4420Sstevel@tonic-gate switch (bp->bio_parent->bio_cmd) { 4430Sstevel@tonic-gate case BIO_READ: 4440Sstevel@tonic-gate if (wp == NULL) 4450Sstevel@tonic-gate break; 4460Sstevel@tonic-gate 4470Sstevel@tonic-gate TAILQ_FOREACH_SAFE(bq, &wp->bits, queue, bq2) { 4480Sstevel@tonic-gate if (bq->bp == bp) { 4490Sstevel@tonic-gate TAILQ_REMOVE(&wp->bits, bq, queue); 4500Sstevel@tonic-gate g_free(bq); 4510Sstevel@tonic-gate for (i = 0; i < wp->length; i++) 4520Sstevel@tonic-gate wp->data[i] ^= bp->bio_data[i]; 4530Sstevel@tonic-gate break; 4540Sstevel@tonic-gate } 4550Sstevel@tonic-gate } 4560Sstevel@tonic-gate if (TAILQ_EMPTY(&wp->bits)) { 4570Sstevel@tonic-gate bp->bio_parent->bio_completed += wp->length; 4580Sstevel@tonic-gate if (wp->lockbase != -1) { 4590Sstevel@tonic-gate TAILQ_REMOVE(&p->packets, wp, list); 4600Sstevel@tonic-gate /* Bring the waiting bios back into the game. */ 4610Sstevel@tonic-gate mtx_lock(&p->bqueue_mtx); 4620Sstevel@tonic-gate TAILQ_CONCAT(&p->bqueue, &p->wqueue, queue); 4630Sstevel@tonic-gate mtx_unlock(&p->bqueue_mtx); 4640Sstevel@tonic-gate } 4650Sstevel@tonic-gate g_free(wp); 4660Sstevel@tonic-gate } 4670Sstevel@tonic-gate 4680Sstevel@tonic-gate break; 4690Sstevel@tonic-gate 4700Sstevel@tonic-gate case BIO_WRITE: 4710Sstevel@tonic-gate if (wp == NULL) 4720Sstevel@tonic-gate break; 4730Sstevel@tonic-gate 4740Sstevel@tonic-gate /* Check if we need to handle parity data. */ 4750Sstevel@tonic-gate TAILQ_FOREACH_SAFE(bq, &wp->bits, queue, bq2) { 4760Sstevel@tonic-gate if (bq->bp == bp) { 4770Sstevel@tonic-gate TAILQ_REMOVE(&wp->bits, bq, queue); 4780Sstevel@tonic-gate g_free(bq); 4790Sstevel@tonic-gate cbp = wp->parity; 4800Sstevel@tonic-gate if (cbp != NULL) { 4810Sstevel@tonic-gate for (i = 0; i < wp->length; i++) 4820Sstevel@tonic-gate cbp->bio_data[i] ^= 4830Sstevel@tonic-gate bp->bio_data[i]; 4840Sstevel@tonic-gate } 4850Sstevel@tonic-gate break; 4860Sstevel@tonic-gate } 4870Sstevel@tonic-gate } 4880Sstevel@tonic-gate 4890Sstevel@tonic-gate /* Handle parity data. */ 4900Sstevel@tonic-gate if (TAILQ_EMPTY(&wp->bits)) { 4910Sstevel@tonic-gate if (bp->bio_parent->bio_cflags & GV_BIO_CHECK) 4920Sstevel@tonic-gate i = gv_check_parity(p, bp, wp); 4930Sstevel@tonic-gate else 4940Sstevel@tonic-gate i = gv_normal_parity(p, bp, wp); 4950Sstevel@tonic-gate 4960Sstevel@tonic-gate /* All of our sub-requests have finished. */ 4970Sstevel@tonic-gate if (i) { 4980Sstevel@tonic-gate bp->bio_parent->bio_completed += wp->length; 4990Sstevel@tonic-gate TAILQ_REMOVE(&p->packets, wp, list); 5000Sstevel@tonic-gate /* Bring the waiting bios back into the game. */ 5010Sstevel@tonic-gate mtx_lock(&p->bqueue_mtx); 5020Sstevel@tonic-gate TAILQ_CONCAT(&p->bqueue, &p->wqueue, queue); 5030Sstevel@tonic-gate mtx_unlock(&p->bqueue_mtx); 5040Sstevel@tonic-gate g_free(wp); 5050Sstevel@tonic-gate } 5060Sstevel@tonic-gate } 5070Sstevel@tonic-gate 5080Sstevel@tonic-gate break; 5090Sstevel@tonic-gate } 5100Sstevel@tonic-gate 5110Sstevel@tonic-gate pbp = bp->bio_parent; 5120Sstevel@tonic-gate if (pbp->bio_error == 0) 5130Sstevel@tonic-gate pbp->bio_error = bp->bio_error; 5140Sstevel@tonic-gate 5150Sstevel@tonic-gate /* When the original request is finished, we deliver it. */ 5160Sstevel@tonic-gate pbp->bio_inbed++; 5170Sstevel@tonic-gate if (pbp->bio_inbed == pbp->bio_children) 5180Sstevel@tonic-gate g_io_deliver(pbp, pbp->bio_error); 5190Sstevel@tonic-gate 5200Sstevel@tonic-gate /* Clean up what we allocated. */ 5210Sstevel@tonic-gate if (bp->bio_cflags & GV_BIO_MALLOC) 5220Sstevel@tonic-gate g_free(bp->bio_data); 5230Sstevel@tonic-gate g_destroy_bio(bp); 5240Sstevel@tonic-gate} 5250Sstevel@tonic-gate 5260Sstevel@tonic-gatevoid 5270Sstevel@tonic-gategv_plex_normal_request(struct gv_plex *p, struct bio *bp) 5280Sstevel@tonic-gate{ 5290Sstevel@tonic-gate struct bio *cbp, *pbp; 5300Sstevel@tonic-gate struct gv_bioq *bq, *bq2; 5310Sstevel@tonic-gate struct gv_raid5_packet *wp, *wp2; 5320Sstevel@tonic-gate caddr_t addr; 5330Sstevel@tonic-gate off_t bcount, boff; 5340Sstevel@tonic-gate int err; 5350Sstevel@tonic-gate 5360Sstevel@tonic-gate bcount = bp->bio_length; 5370Sstevel@tonic-gate addr = bp->bio_data; 5380Sstevel@tonic-gate boff = bp->bio_offset; 5390Sstevel@tonic-gate 5400Sstevel@tonic-gate /* Walk over the whole length of the request, we might split it up. */ 5410Sstevel@tonic-gate while (bcount > 0) { 5420Sstevel@tonic-gate wp = NULL; 5430Sstevel@tonic-gate 5440Sstevel@tonic-gate /* 5450Sstevel@tonic-gate * RAID5 plexes need special treatment, as a single write 5460Sstevel@tonic-gate * request involves several read/write sub-requests. 5470Sstevel@tonic-gate */ 5480Sstevel@tonic-gate if (p->org == GV_PLEX_RAID5) { 5490Sstevel@tonic-gate wp = g_malloc(sizeof(*wp), M_WAITOK | M_ZERO); 5500Sstevel@tonic-gate wp->bio = bp; 5510Sstevel@tonic-gate TAILQ_INIT(&wp->bits); 5520Sstevel@tonic-gate 5530Sstevel@tonic-gate if (bp->bio_cflags & GV_BIO_REBUILD) 5540Sstevel@tonic-gate err = gv_rebuild_raid5(p, wp, bp, addr, 5550Sstevel@tonic-gate boff, bcount); 5560Sstevel@tonic-gate else if (bp->bio_cflags & GV_BIO_CHECK) 5570Sstevel@tonic-gate err = gv_check_raid5(p, wp, bp, addr, 5580Sstevel@tonic-gate boff, bcount); 5590Sstevel@tonic-gate else 5600Sstevel@tonic-gate err = gv_build_raid5_req(p, wp, bp, addr, 5610Sstevel@tonic-gate boff, bcount); 5620Sstevel@tonic-gate 5630Sstevel@tonic-gate /* 5640Sstevel@tonic-gate * Building the sub-request failed, we probably need to 5650Sstevel@tonic-gate * clean up a lot. 5660Sstevel@tonic-gate */ 5670Sstevel@tonic-gate if (err) { 5680Sstevel@tonic-gate printf("GEOM_VINUM: plex request failed for "); 5690Sstevel@tonic-gate g_print_bio(bp); 5700Sstevel@tonic-gate printf("\n"); 5710Sstevel@tonic-gate TAILQ_FOREACH_SAFE(bq, &wp->bits, queue, bq2) { 5720Sstevel@tonic-gate TAILQ_REMOVE(&wp->bits, bq, queue); 5730Sstevel@tonic-gate g_free(bq); 5740Sstevel@tonic-gate } 5750Sstevel@tonic-gate if (wp->waiting != NULL) { 5760Sstevel@tonic-gate if (wp->waiting->bio_cflags & 5770Sstevel@tonic-gate GV_BIO_MALLOC) 5780Sstevel@tonic-gate g_free(wp->waiting->bio_data); 5790Sstevel@tonic-gate g_destroy_bio(wp->waiting); 5800Sstevel@tonic-gate } 5810Sstevel@tonic-gate if (wp->parity != NULL) { 5820Sstevel@tonic-gate if (wp->parity->bio_cflags & 5830Sstevel@tonic-gate GV_BIO_MALLOC) 5840Sstevel@tonic-gate g_free(wp->parity->bio_data); 5850Sstevel@tonic-gate g_destroy_bio(wp->parity); 5860Sstevel@tonic-gate } 5870Sstevel@tonic-gate g_free(wp); 5880Sstevel@tonic-gate 5890Sstevel@tonic-gate TAILQ_FOREACH_SAFE(wp, &p->packets, list, wp2) { 5900Sstevel@tonic-gate if (wp->bio == bp) { 5910Sstevel@tonic-gate TAILQ_REMOVE(&p->packets, wp, 5920Sstevel@tonic-gate list); 5930Sstevel@tonic-gate TAILQ_FOREACH_SAFE(bq, 5940Sstevel@tonic-gate &wp->bits, queue, bq2) { 5950Sstevel@tonic-gate TAILQ_REMOVE(&wp->bits, 5960Sstevel@tonic-gate bq, queue); 5970Sstevel@tonic-gate g_free(bq); 5980Sstevel@tonic-gate } 5990Sstevel@tonic-gate g_free(wp); 6000Sstevel@tonic-gate } 6010Sstevel@tonic-gate } 6020Sstevel@tonic-gate 6030Sstevel@tonic-gate cbp = bp->bio_driver1; 6040Sstevel@tonic-gate while (cbp != NULL) { 6050Sstevel@tonic-gate pbp = cbp->bio_caller1; 6060Sstevel@tonic-gate if (cbp->bio_cflags & GV_BIO_MALLOC) 6070Sstevel@tonic-gate g_free(cbp->bio_data); 6080Sstevel@tonic-gate g_destroy_bio(cbp); 6090Sstevel@tonic-gate cbp = pbp; 6100Sstevel@tonic-gate } 6110Sstevel@tonic-gate 6120Sstevel@tonic-gate g_io_deliver(bp, err); 6130Sstevel@tonic-gate return; 6140Sstevel@tonic-gate } 6150Sstevel@tonic-gate 6160Sstevel@tonic-gate if (TAILQ_EMPTY(&wp->bits)) 6170Sstevel@tonic-gate g_free(wp); 6180Sstevel@tonic-gate else if (wp->lockbase != -1) 6190Sstevel@tonic-gate TAILQ_INSERT_TAIL(&p->packets, wp, list); 6200Sstevel@tonic-gate 6210Sstevel@tonic-gate /* 6220Sstevel@tonic-gate * Requests to concatenated and striped plexes go straight 6230Sstevel@tonic-gate * through. 6240Sstevel@tonic-gate */ 6250Sstevel@tonic-gate } else { 6260Sstevel@tonic-gate err = gv_plexbuffer(p, bp, addr, boff, bcount); 6270Sstevel@tonic-gate 6280Sstevel@tonic-gate /* Building the sub-request failed. */ 6290Sstevel@tonic-gate if (err) { 6300Sstevel@tonic-gate printf("GEOM_VINUM: plex request failed for "); 6310Sstevel@tonic-gate g_print_bio(bp); 6320Sstevel@tonic-gate printf("\n"); 6330Sstevel@tonic-gate cbp = bp->bio_driver1; 6340Sstevel@tonic-gate while (cbp != NULL) { 6350Sstevel@tonic-gate pbp = cbp->bio_caller1; 6360Sstevel@tonic-gate g_destroy_bio(cbp); 6370Sstevel@tonic-gate cbp = pbp; 6380Sstevel@tonic-gate } 6390Sstevel@tonic-gate g_io_deliver(bp, err); 6400Sstevel@tonic-gate return; 6410Sstevel@tonic-gate } 6420Sstevel@tonic-gate } 6430Sstevel@tonic-gate 6440Sstevel@tonic-gate /* Abuse bio_caller1 as linked list. */ 6450Sstevel@tonic-gate pbp = bp->bio_driver1; 6460Sstevel@tonic-gate while (pbp->bio_caller1 != NULL) 6470Sstevel@tonic-gate pbp = pbp->bio_caller1; 6480Sstevel@tonic-gate bcount -= pbp->bio_length; 6490Sstevel@tonic-gate addr += pbp->bio_length; 6500Sstevel@tonic-gate boff += pbp->bio_length; 6510Sstevel@tonic-gate } 6520Sstevel@tonic-gate 6530Sstevel@tonic-gate /* Fire off all sub-requests. */ 6540Sstevel@tonic-gate pbp = bp->bio_driver1; 6550Sstevel@tonic-gate while (pbp != NULL) { 6560Sstevel@tonic-gate /* 6570Sstevel@tonic-gate * RAID5 sub-requests need to come in correct order, otherwise 6580Sstevel@tonic-gate * we trip over the parity, as it might be overwritten by 6590Sstevel@tonic-gate * another sub-request. 6600Sstevel@tonic-gate */ 6610Sstevel@tonic-gate if (pbp->bio_driver1 != NULL && 6620Sstevel@tonic-gate gv_stripe_active(p, pbp)) { 6630Sstevel@tonic-gate /* Park the bio on the waiting queue. */ 6640Sstevel@tonic-gate pbp->bio_cflags |= GV_BIO_ONHOLD; 6650Sstevel@tonic-gate bq = g_malloc(sizeof(*bq), M_WAITOK | M_ZERO); 6660Sstevel@tonic-gate bq->bp = pbp; 6670Sstevel@tonic-gate mtx_lock(&p->bqueue_mtx); 6680Sstevel@tonic-gate TAILQ_INSERT_TAIL(&p->wqueue, bq, queue); 6690Sstevel@tonic-gate mtx_unlock(&p->bqueue_mtx); 6700Sstevel@tonic-gate } else 6710Sstevel@tonic-gate g_io_request(pbp, pbp->bio_caller2); 6720Sstevel@tonic-gate pbp = pbp->bio_caller1; 6730Sstevel@tonic-gate } 6740Sstevel@tonic-gate} 6750Sstevel@tonic-gate 6760Sstevel@tonic-gatestatic int 6770Sstevel@tonic-gategv_plex_access(struct g_provider *pp, int dr, int dw, int de) 6780Sstevel@tonic-gate{ 6790Sstevel@tonic-gate struct g_geom *gp; 6800Sstevel@tonic-gate struct g_consumer *cp, *cp2; 6810Sstevel@tonic-gate int error; 6820Sstevel@tonic-gate 6830Sstevel@tonic-gate gp = pp->geom; 6840Sstevel@tonic-gate 6850Sstevel@tonic-gate LIST_FOREACH(cp, &gp->consumer, consumer) { 6860Sstevel@tonic-gate error = g_access(cp, dr, dw, de); 6870Sstevel@tonic-gate if (error) { 6880Sstevel@tonic-gate LIST_FOREACH(cp2, &gp->consumer, consumer) { 6890Sstevel@tonic-gate if (cp == cp2) 6900Sstevel@tonic-gate break; 6910Sstevel@tonic-gate g_access(cp2, -dr, -dw, -de); 6920Sstevel@tonic-gate } 6930Sstevel@tonic-gate return (error); 6940Sstevel@tonic-gate } 6950Sstevel@tonic-gate } 6960Sstevel@tonic-gate return (0); 6970Sstevel@tonic-gate} 6980Sstevel@tonic-gate 6990Sstevel@tonic-gatestatic struct g_geom * 7000Sstevel@tonic-gategv_plex_taste(struct g_class *mp, struct g_provider *pp, int flags __unused) 7010Sstevel@tonic-gate{ 7020Sstevel@tonic-gate struct g_geom *gp; 7030Sstevel@tonic-gate struct g_consumer *cp, *cp2; 7040Sstevel@tonic-gate struct g_provider *pp2; 7050Sstevel@tonic-gate struct gv_plex *p; 7060Sstevel@tonic-gate struct gv_sd *s; 7070Sstevel@tonic-gate struct gv_softc *sc; 7080Sstevel@tonic-gate int error; 7090Sstevel@tonic-gate 7100Sstevel@tonic-gate g_trace(G_T_TOPOLOGY, "gv_plex_taste(%s, %s)", mp->name, pp->name); 7110Sstevel@tonic-gate g_topology_assert(); 7120Sstevel@tonic-gate 7130Sstevel@tonic-gate /* We only want to attach to subdisks. */ 7140Sstevel@tonic-gate if (strcmp(pp->geom->class->name, "VINUMDRIVE")) 7150Sstevel@tonic-gate return (NULL); 7160Sstevel@tonic-gate 7170Sstevel@tonic-gate /* Find the VINUM class and its associated geom. */ 7180Sstevel@tonic-gate gp = find_vinum_geom(); 7190Sstevel@tonic-gate if (gp == NULL) 7200Sstevel@tonic-gate return (NULL); 7210Sstevel@tonic-gate sc = gp->softc; 7220Sstevel@tonic-gate KASSERT(sc != NULL, ("gv_plex_taste: NULL sc")); 7230Sstevel@tonic-gate 7240Sstevel@tonic-gate /* Find out which subdisk the offered provider corresponds to. */ 7250Sstevel@tonic-gate s = pp->private; 7260Sstevel@tonic-gate KASSERT(s != NULL, ("gv_plex_taste: NULL s")); 7270Sstevel@tonic-gate 7280Sstevel@tonic-gate /* Now find the correct plex where this subdisk belongs to. */ 7290Sstevel@tonic-gate p = gv_find_plex(sc, s->plex); 7300Sstevel@tonic-gate KASSERT(p != NULL, ("gv_plex_taste: NULL p")); 7310Sstevel@tonic-gate 7320Sstevel@tonic-gate /* 7330Sstevel@tonic-gate * Add this subdisk to this plex. Since we trust the on-disk 7340Sstevel@tonic-gate * configuration, we don't check the given value (should we?). 7350Sstevel@tonic-gate * XXX: shouldn't be done here 7360Sstevel@tonic-gate */ 7370Sstevel@tonic-gate gv_sd_to_plex(p, s, 0); 7380Sstevel@tonic-gate 7390Sstevel@tonic-gate /* Now check if there's already a geom for this plex. */ 7400Sstevel@tonic-gate gp = p->geom; 7410Sstevel@tonic-gate 7420Sstevel@tonic-gate /* Yes, there is already a geom, so we just add the consumer. */ 7430Sstevel@tonic-gate if (gp != NULL) { 7440Sstevel@tonic-gate cp2 = LIST_FIRST(&gp->consumer); 7450Sstevel@tonic-gate /* Need to attach a new consumer to this subdisk. */ 7460Sstevel@tonic-gate cp = g_new_consumer(gp); 7470Sstevel@tonic-gate error = g_attach(cp, pp); 7480Sstevel@tonic-gate if (error) { 7490Sstevel@tonic-gate printf("geom_vinum: couldn't attach consumer to %s\n", 7500Sstevel@tonic-gate pp->name); 7510Sstevel@tonic-gate g_destroy_consumer(cp); 7520Sstevel@tonic-gate return (NULL); 7530Sstevel@tonic-gate } 7540Sstevel@tonic-gate /* Adjust the access counts of the new consumer. */ 7550Sstevel@tonic-gate if ((cp2 != NULL) && (cp2->acr || cp2->acw || cp2->ace)) { 7560Sstevel@tonic-gate error = g_access(cp, cp2->acr, cp2->acw, cp2->ace); 7570Sstevel@tonic-gate if (error) { 7580Sstevel@tonic-gate printf("geom_vinum: couldn't set access counts" 7590Sstevel@tonic-gate " for consumer on %s\n", pp->name); 7600Sstevel@tonic-gate g_detach(cp); 7610Sstevel@tonic-gate g_destroy_consumer(cp); 7620Sstevel@tonic-gate return (NULL); 7630Sstevel@tonic-gate } 7640Sstevel@tonic-gate } 7650Sstevel@tonic-gate s->consumer = cp; 7660Sstevel@tonic-gate 7670Sstevel@tonic-gate /* Adjust the size of the providers this plex has. */ 7680Sstevel@tonic-gate LIST_FOREACH(pp2, &gp->provider, provider) 7690Sstevel@tonic-gate pp2->mediasize = p->size; 7700Sstevel@tonic-gate 7710Sstevel@tonic-gate /* Update the size of the volume this plex is attached to. */ 7720Sstevel@tonic-gate if (p->vol_sc != NULL) 7730Sstevel@tonic-gate gv_update_vol_size(p->vol_sc, p->size); 7740Sstevel@tonic-gate 7750Sstevel@tonic-gate /* 7760Sstevel@tonic-gate * If necessary, create a bio queue mutex and a worker thread. 7770Sstevel@tonic-gate */ 7780Sstevel@tonic-gate if (mtx_initialized(&p->bqueue_mtx) == 0) 7790Sstevel@tonic-gate mtx_init(&p->bqueue_mtx, "gv_plex", NULL, MTX_DEF); 7800Sstevel@tonic-gate if (!(p->flags & GV_PLEX_THREAD_ACTIVE)) { 7810Sstevel@tonic-gate kthread_create(gv_plex_worker, p, NULL, 0, 0, "gv_p %s", 7820Sstevel@tonic-gate p->name); 7830Sstevel@tonic-gate p->flags |= GV_PLEX_THREAD_ACTIVE; 7840Sstevel@tonic-gate } 7850Sstevel@tonic-gate 7860Sstevel@tonic-gate return (NULL); 7870Sstevel@tonic-gate 7880Sstevel@tonic-gate /* We need to create a new geom. */ 7890Sstevel@tonic-gate } else { 7900Sstevel@tonic-gate gp = g_new_geomf(mp, "%s", p->name); 7910Sstevel@tonic-gate gp->start = gv_plex_start; 7920Sstevel@tonic-gate gp->orphan = gv_plex_orphan; 7930Sstevel@tonic-gate gp->access = gv_plex_access; 7940Sstevel@tonic-gate gp->softc = p; 7950Sstevel@tonic-gate p->geom = gp; 7960Sstevel@tonic-gate 7970Sstevel@tonic-gate TAILQ_INIT(&p->packets); 7980Sstevel@tonic-gate TAILQ_INIT(&p->bqueue); 7990Sstevel@tonic-gate TAILQ_INIT(&p->wqueue); 8000Sstevel@tonic-gate mtx_init(&p->bqueue_mtx, "gv_plex", NULL, MTX_DEF); 8010Sstevel@tonic-gate kthread_create(gv_plex_worker, p, NULL, 0, 0, "gv_p %s", 8020Sstevel@tonic-gate p->name); 8030Sstevel@tonic-gate p->flags |= GV_PLEX_THREAD_ACTIVE; 8040Sstevel@tonic-gate 8050Sstevel@tonic-gate /* Attach a consumer to this provider. */ 8060Sstevel@tonic-gate cp = g_new_consumer(gp); 8070Sstevel@tonic-gate g_attach(cp, pp); 8080Sstevel@tonic-gate s->consumer = cp; 8090Sstevel@tonic-gate 8100Sstevel@tonic-gate /* Create a provider for the outside world. */ 8110Sstevel@tonic-gate pp2 = g_new_providerf(gp, "gvinum/plex/%s", p->name); 8120Sstevel@tonic-gate pp2->mediasize = p->size; 8130Sstevel@tonic-gate pp2->sectorsize = pp->sectorsize; 8140Sstevel@tonic-gate p->provider = pp2; 8150Sstevel@tonic-gate g_error_provider(pp2, 0); 8160Sstevel@tonic-gate return (gp); 8170Sstevel@tonic-gate } 8180Sstevel@tonic-gate} 8190Sstevel@tonic-gate 8200Sstevel@tonic-gatestatic int 8210Sstevel@tonic-gategv_plex_destroy_geom(struct gctl_req *req, struct g_class *mp, 8220Sstevel@tonic-gate struct g_geom *gp) 8230Sstevel@tonic-gate{ 8240Sstevel@tonic-gate struct gv_plex *p; 8250Sstevel@tonic-gate 8260Sstevel@tonic-gate g_trace(G_T_TOPOLOGY, "gv_plex_destroy_geom: %s", gp->name); 8270Sstevel@tonic-gate g_topology_assert(); 8280Sstevel@tonic-gate 8290Sstevel@tonic-gate p = gp->softc; 8300Sstevel@tonic-gate 8310Sstevel@tonic-gate KASSERT(p != NULL, ("gv_plex_destroy_geom: null p of '%s'", gp->name)); 8320Sstevel@tonic-gate 8330Sstevel@tonic-gate /* 8340Sstevel@tonic-gate * If this is a RAID5 plex, check if its worker thread is still active 8350Sstevel@tonic-gate * and signal it to self destruct. 8360Sstevel@tonic-gate */ 8370Sstevel@tonic-gate gv_kill_plex_thread(p); 8380Sstevel@tonic-gate /* g_free(sc); */ 8390Sstevel@tonic-gate g_wither_geom(gp, ENXIO); 8400Sstevel@tonic-gate return (0); 841} 842 843#define VINUMPLEX_CLASS_NAME "VINUMPLEX" 844 845static struct g_class g_vinum_plex_class = { 846 .name = VINUMPLEX_CLASS_NAME, 847 .version = G_VERSION, 848 .taste = gv_plex_taste, 849 .destroy_geom = gv_plex_destroy_geom, 850}; 851 852DECLARE_GEOM_CLASS(g_vinum_plex_class, g_vinum_plex); 853