1dd84a43cSPoul-Henning Kamp /*- 2dd84a43cSPoul-Henning Kamp * Copyright (c) 2002 Poul-Henning Kamp 3dd84a43cSPoul-Henning Kamp * Copyright (c) 2002 Networks Associates Technology, Inc. 4dd84a43cSPoul-Henning Kamp * All rights reserved. 5dd84a43cSPoul-Henning Kamp * 6dd84a43cSPoul-Henning Kamp * This software was developed for the FreeBSD Project by Poul-Henning Kamp 7dd84a43cSPoul-Henning Kamp * and NAI Labs, the Security Research Division of Network Associates, Inc. 8dd84a43cSPoul-Henning Kamp * under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the 9dd84a43cSPoul-Henning Kamp * DARPA CHATS research program. 10dd84a43cSPoul-Henning Kamp * 11dd84a43cSPoul-Henning Kamp * Redistribution and use in source and binary forms, with or without 12dd84a43cSPoul-Henning Kamp * modification, are permitted provided that the following conditions 13dd84a43cSPoul-Henning Kamp * are met: 14dd84a43cSPoul-Henning Kamp * 1. Redistributions of source code must retain the above copyright 15dd84a43cSPoul-Henning Kamp * notice, this list of conditions and the following disclaimer. 16dd84a43cSPoul-Henning Kamp * 2. Redistributions in binary form must reproduce the above copyright 17dd84a43cSPoul-Henning Kamp * notice, this list of conditions and the following disclaimer in the 18dd84a43cSPoul-Henning Kamp * documentation and/or other materials provided with the distribution. 19dd84a43cSPoul-Henning Kamp * 3. The names of the authors may not be used to endorse or promote 20dd84a43cSPoul-Henning Kamp * products derived from this software without specific prior written 21dd84a43cSPoul-Henning Kamp * permission. 22dd84a43cSPoul-Henning Kamp * 23dd84a43cSPoul-Henning Kamp * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 24dd84a43cSPoul-Henning Kamp * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25dd84a43cSPoul-Henning Kamp * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26dd84a43cSPoul-Henning Kamp * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 27dd84a43cSPoul-Henning Kamp * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28dd84a43cSPoul-Henning Kamp * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29dd84a43cSPoul-Henning Kamp * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30dd84a43cSPoul-Henning Kamp * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31dd84a43cSPoul-Henning Kamp * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32dd84a43cSPoul-Henning Kamp * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33dd84a43cSPoul-Henning Kamp * SUCH DAMAGE. 34dd84a43cSPoul-Henning Kamp */ 35dd84a43cSPoul-Henning Kamp 3650b1faefSDavid E. O'Brien #include <sys/cdefs.h> 3750b1faefSDavid E. O'Brien __FBSDID("$FreeBSD$"); 38dd84a43cSPoul-Henning Kamp 39dd84a43cSPoul-Henning Kamp #include <sys/param.h> 40dd84a43cSPoul-Henning Kamp #include <sys/systm.h> 41dd84a43cSPoul-Henning Kamp #include <sys/kernel.h> 42dd84a43cSPoul-Henning Kamp #include <sys/malloc.h> 43dd84a43cSPoul-Henning Kamp #include <sys/bio.h> 4449dbb61dSRobert Watson #include <sys/ktr.h> 4551460da8SJohn Baldwin #include <sys/proc.h> 463b378147SPawel Jakub Dawidek #include <sys/stack.h> 47dd84a43cSPoul-Henning Kamp 48dd84a43cSPoul-Henning Kamp #include <sys/errno.h> 49dd84a43cSPoul-Henning Kamp #include <geom/geom.h> 50b1876192SPoul-Henning Kamp #include <geom/geom_int.h> 51e24cbd90SPoul-Henning Kamp #include <sys/devicestat.h> 52dd84a43cSPoul-Henning Kamp 535ffb2c8bSPoul-Henning Kamp #include <vm/uma.h> 545ffb2c8bSPoul-Henning Kamp 55dd84a43cSPoul-Henning Kamp static struct g_bioq g_bio_run_down; 56dd84a43cSPoul-Henning Kamp static struct g_bioq g_bio_run_up; 575fcf4e43SPoul-Henning Kamp static struct g_bioq g_bio_run_task; 58dd84a43cSPoul-Henning Kamp 593432e4fdSPoul-Henning Kamp static u_int pace; 605ffb2c8bSPoul-Henning Kamp static uma_zone_t biozone; 613432e4fdSPoul-Henning Kamp 626231f75bSLuigi Rizzo /* 636231f75bSLuigi Rizzo * The head of the list of classifiers used in g_io_request. 646231f75bSLuigi Rizzo * Use g_register_classifier() and g_unregister_classifier() 656231f75bSLuigi Rizzo * to add/remove entries to the list. 666231f75bSLuigi Rizzo * Classifiers are invoked in registration order. 676231f75bSLuigi Rizzo */ 686231f75bSLuigi Rizzo static TAILQ_HEAD(g_classifier_tailq, g_classifier_hook) 696231f75bSLuigi Rizzo g_classifier_tailq = TAILQ_HEAD_INITIALIZER(g_classifier_tailq); 706231f75bSLuigi Rizzo 71dd84a43cSPoul-Henning Kamp #include <machine/atomic.h> 72dd84a43cSPoul-Henning Kamp 73dd84a43cSPoul-Henning Kamp static void 74dd84a43cSPoul-Henning Kamp g_bioq_lock(struct g_bioq *bq) 75dd84a43cSPoul-Henning Kamp { 76dd84a43cSPoul-Henning Kamp 77dd84a43cSPoul-Henning Kamp mtx_lock(&bq->bio_queue_lock); 78dd84a43cSPoul-Henning Kamp } 79dd84a43cSPoul-Henning Kamp 80dd84a43cSPoul-Henning Kamp static void 81dd84a43cSPoul-Henning Kamp g_bioq_unlock(struct g_bioq *bq) 82dd84a43cSPoul-Henning Kamp { 83dd84a43cSPoul-Henning Kamp 84dd84a43cSPoul-Henning Kamp mtx_unlock(&bq->bio_queue_lock); 85dd84a43cSPoul-Henning Kamp } 86dd84a43cSPoul-Henning Kamp 87dd84a43cSPoul-Henning Kamp #if 0 88dd84a43cSPoul-Henning Kamp static void 89dd84a43cSPoul-Henning Kamp g_bioq_destroy(struct g_bioq *bq) 90dd84a43cSPoul-Henning Kamp { 91dd84a43cSPoul-Henning Kamp 92dd84a43cSPoul-Henning Kamp mtx_destroy(&bq->bio_queue_lock); 93dd84a43cSPoul-Henning Kamp } 94dd84a43cSPoul-Henning Kamp #endif 95dd84a43cSPoul-Henning Kamp 96dd84a43cSPoul-Henning Kamp static void 97dd84a43cSPoul-Henning Kamp g_bioq_init(struct g_bioq *bq) 98dd84a43cSPoul-Henning Kamp { 99dd84a43cSPoul-Henning Kamp 100dd84a43cSPoul-Henning Kamp TAILQ_INIT(&bq->bio_queue); 1016008862bSJohn Baldwin mtx_init(&bq->bio_queue_lock, "bio queue", NULL, MTX_DEF); 102dd84a43cSPoul-Henning Kamp } 103dd84a43cSPoul-Henning Kamp 104dd84a43cSPoul-Henning Kamp static struct bio * 105dd84a43cSPoul-Henning Kamp g_bioq_first(struct g_bioq *bq) 106dd84a43cSPoul-Henning Kamp { 107dd84a43cSPoul-Henning Kamp struct bio *bp; 108dd84a43cSPoul-Henning Kamp 109dd84a43cSPoul-Henning Kamp bp = TAILQ_FIRST(&bq->bio_queue); 110dd84a43cSPoul-Henning Kamp if (bp != NULL) { 111dcbd0fe5SPoul-Henning Kamp KASSERT((bp->bio_flags & BIO_ONQUEUE), 112dcbd0fe5SPoul-Henning Kamp ("Bio not on queue bp=%p target %p", bp, bq)); 113dcbd0fe5SPoul-Henning Kamp bp->bio_flags &= ~BIO_ONQUEUE; 114dd84a43cSPoul-Henning Kamp TAILQ_REMOVE(&bq->bio_queue, bp, bio_queue); 115dd84a43cSPoul-Henning Kamp bq->bio_queue_length--; 116dd84a43cSPoul-Henning Kamp } 117dd84a43cSPoul-Henning Kamp return (bp); 118dd84a43cSPoul-Henning Kamp } 119dd84a43cSPoul-Henning Kamp 120dd84a43cSPoul-Henning Kamp struct bio * 121dd84a43cSPoul-Henning Kamp g_new_bio(void) 122dd84a43cSPoul-Henning Kamp { 123dd84a43cSPoul-Henning Kamp struct bio *bp; 124dd84a43cSPoul-Henning Kamp 1255ffb2c8bSPoul-Henning Kamp bp = uma_zalloc(biozone, M_NOWAIT | M_ZERO); 1263b378147SPawel Jakub Dawidek #ifdef KTR 127b656c1b8SPawel Jakub Dawidek if ((KTR_COMPILE & KTR_GEOM) && (ktr_mask & KTR_GEOM)) { 1283b378147SPawel Jakub Dawidek struct stack st; 1293b378147SPawel Jakub Dawidek 1303b378147SPawel Jakub Dawidek CTR1(KTR_GEOM, "g_new_bio(): %p", bp); 1313b378147SPawel Jakub Dawidek stack_save(&st); 1323b378147SPawel Jakub Dawidek CTRSTACK(KTR_GEOM, &st, 3, 0); 1333b378147SPawel Jakub Dawidek } 1343b378147SPawel Jakub Dawidek #endif 135dd84a43cSPoul-Henning Kamp return (bp); 136dd84a43cSPoul-Henning Kamp } 137dd84a43cSPoul-Henning Kamp 138a2033c96SPoul-Henning Kamp struct bio * 139a2033c96SPoul-Henning Kamp g_alloc_bio(void) 140a2033c96SPoul-Henning Kamp { 141a2033c96SPoul-Henning Kamp struct bio *bp; 142a2033c96SPoul-Henning Kamp 143a2033c96SPoul-Henning Kamp bp = uma_zalloc(biozone, M_WAITOK | M_ZERO); 1443b378147SPawel Jakub Dawidek #ifdef KTR 145b656c1b8SPawel Jakub Dawidek if ((KTR_COMPILE & KTR_GEOM) && (ktr_mask & KTR_GEOM)) { 1463b378147SPawel Jakub Dawidek struct stack st; 1473b378147SPawel Jakub Dawidek 1483b378147SPawel Jakub Dawidek CTR1(KTR_GEOM, "g_alloc_bio(): %p", bp); 1493b378147SPawel Jakub Dawidek stack_save(&st); 1503b378147SPawel Jakub Dawidek CTRSTACK(KTR_GEOM, &st, 3, 0); 1513b378147SPawel Jakub Dawidek } 1523b378147SPawel Jakub Dawidek #endif 153a2033c96SPoul-Henning Kamp return (bp); 154a2033c96SPoul-Henning Kamp } 155a2033c96SPoul-Henning Kamp 156dd84a43cSPoul-Henning Kamp void 157dd84a43cSPoul-Henning Kamp g_destroy_bio(struct bio *bp) 158dd84a43cSPoul-Henning Kamp { 1593b378147SPawel Jakub Dawidek #ifdef KTR 160b656c1b8SPawel Jakub Dawidek if ((KTR_COMPILE & KTR_GEOM) && (ktr_mask & KTR_GEOM)) { 1613b378147SPawel Jakub Dawidek struct stack st; 162dd84a43cSPoul-Henning Kamp 1633b378147SPawel Jakub Dawidek CTR1(KTR_GEOM, "g_destroy_bio(): %p", bp); 1643b378147SPawel Jakub Dawidek stack_save(&st); 1653b378147SPawel Jakub Dawidek CTRSTACK(KTR_GEOM, &st, 3, 0); 1663b378147SPawel Jakub Dawidek } 1673b378147SPawel Jakub Dawidek #endif 1685ffb2c8bSPoul-Henning Kamp uma_zfree(biozone, bp); 169dd84a43cSPoul-Henning Kamp } 170dd84a43cSPoul-Henning Kamp 171dd84a43cSPoul-Henning Kamp struct bio * 172dd84a43cSPoul-Henning Kamp g_clone_bio(struct bio *bp) 173dd84a43cSPoul-Henning Kamp { 174dd84a43cSPoul-Henning Kamp struct bio *bp2; 175dd84a43cSPoul-Henning Kamp 1765ffb2c8bSPoul-Henning Kamp bp2 = uma_zalloc(biozone, M_NOWAIT | M_ZERO); 177a1bd3ee2SPoul-Henning Kamp if (bp2 != NULL) { 178936cc461SPoul-Henning Kamp bp2->bio_parent = bp; 179dd84a43cSPoul-Henning Kamp bp2->bio_cmd = bp->bio_cmd; 18082a6ae10SJim Harris /* 18182a6ae10SJim Harris * BIO_ORDERED flag may be used by disk drivers to enforce 18282a6ae10SJim Harris * ordering restrictions, so this flag needs to be cloned. 18382a6ae10SJim Harris * Other bio flags are not suitable for cloning. 18482a6ae10SJim Harris */ 18582a6ae10SJim Harris bp2->bio_flags = bp->bio_flags & BIO_ORDERED; 186dd84a43cSPoul-Henning Kamp bp2->bio_length = bp->bio_length; 187dd84a43cSPoul-Henning Kamp bp2->bio_offset = bp->bio_offset; 188dd84a43cSPoul-Henning Kamp bp2->bio_data = bp->bio_data; 189dd84a43cSPoul-Henning Kamp bp2->bio_attribute = bp->bio_attribute; 1906231f75bSLuigi Rizzo /* Inherit classification info from the parent */ 1916231f75bSLuigi Rizzo bp2->bio_classifier1 = bp->bio_classifier1; 1926231f75bSLuigi Rizzo bp2->bio_classifier2 = bp->bio_classifier2; 193801bb689SPoul-Henning Kamp bp->bio_children++; 194a1bd3ee2SPoul-Henning Kamp } 1953b378147SPawel Jakub Dawidek #ifdef KTR 196b656c1b8SPawel Jakub Dawidek if ((KTR_COMPILE & KTR_GEOM) && (ktr_mask & KTR_GEOM)) { 1973b378147SPawel Jakub Dawidek struct stack st; 1983b378147SPawel Jakub Dawidek 199ad572235SRuslan Ermilov CTR2(KTR_GEOM, "g_clone_bio(%p): %p", bp, bp2); 2003b378147SPawel Jakub Dawidek stack_save(&st); 2013b378147SPawel Jakub Dawidek CTRSTACK(KTR_GEOM, &st, 3, 0); 2023b378147SPawel Jakub Dawidek } 2033b378147SPawel Jakub Dawidek #endif 204dd84a43cSPoul-Henning Kamp return(bp2); 205dd84a43cSPoul-Henning Kamp } 206dd84a43cSPoul-Henning Kamp 2074bec0ff1SPawel Jakub Dawidek struct bio * 2084bec0ff1SPawel Jakub Dawidek g_duplicate_bio(struct bio *bp) 2094bec0ff1SPawel Jakub Dawidek { 2104bec0ff1SPawel Jakub Dawidek struct bio *bp2; 2114bec0ff1SPawel Jakub Dawidek 2124bec0ff1SPawel Jakub Dawidek bp2 = uma_zalloc(biozone, M_WAITOK | M_ZERO); 2134bec0ff1SPawel Jakub Dawidek bp2->bio_parent = bp; 2144bec0ff1SPawel Jakub Dawidek bp2->bio_cmd = bp->bio_cmd; 2154bec0ff1SPawel Jakub Dawidek bp2->bio_length = bp->bio_length; 2164bec0ff1SPawel Jakub Dawidek bp2->bio_offset = bp->bio_offset; 2174bec0ff1SPawel Jakub Dawidek bp2->bio_data = bp->bio_data; 2184bec0ff1SPawel Jakub Dawidek bp2->bio_attribute = bp->bio_attribute; 2194bec0ff1SPawel Jakub Dawidek bp->bio_children++; 2204bec0ff1SPawel Jakub Dawidek #ifdef KTR 221b656c1b8SPawel Jakub Dawidek if ((KTR_COMPILE & KTR_GEOM) && (ktr_mask & KTR_GEOM)) { 2224bec0ff1SPawel Jakub Dawidek struct stack st; 2234bec0ff1SPawel Jakub Dawidek 2244bec0ff1SPawel Jakub Dawidek CTR2(KTR_GEOM, "g_duplicate_bio(%p): %p", bp, bp2); 2254bec0ff1SPawel Jakub Dawidek stack_save(&st); 2264bec0ff1SPawel Jakub Dawidek CTRSTACK(KTR_GEOM, &st, 3, 0); 2274bec0ff1SPawel Jakub Dawidek } 2284bec0ff1SPawel Jakub Dawidek #endif 2294bec0ff1SPawel Jakub Dawidek return(bp2); 2304bec0ff1SPawel Jakub Dawidek } 2314bec0ff1SPawel Jakub Dawidek 232dd84a43cSPoul-Henning Kamp void 233dd84a43cSPoul-Henning Kamp g_io_init() 234dd84a43cSPoul-Henning Kamp { 235dd84a43cSPoul-Henning Kamp 236dd84a43cSPoul-Henning Kamp g_bioq_init(&g_bio_run_down); 237dd84a43cSPoul-Henning Kamp g_bioq_init(&g_bio_run_up); 2385fcf4e43SPoul-Henning Kamp g_bioq_init(&g_bio_run_task); 2395ffb2c8bSPoul-Henning Kamp biozone = uma_zcreate("g_bio", sizeof (struct bio), 2405ffb2c8bSPoul-Henning Kamp NULL, NULL, 2415ffb2c8bSPoul-Henning Kamp NULL, NULL, 2425ffb2c8bSPoul-Henning Kamp 0, 0); 243dd84a43cSPoul-Henning Kamp } 244dd84a43cSPoul-Henning Kamp 245dd84a43cSPoul-Henning Kamp int 2460d3f37a8SPoul-Henning Kamp g_io_getattr(const char *attr, struct g_consumer *cp, int *len, void *ptr) 247dd84a43cSPoul-Henning Kamp { 248dd84a43cSPoul-Henning Kamp struct bio *bp; 249dd84a43cSPoul-Henning Kamp int error; 250dd84a43cSPoul-Henning Kamp 251dd84a43cSPoul-Henning Kamp g_trace(G_T_BIO, "bio_getattr(%s)", attr); 252a2033c96SPoul-Henning Kamp bp = g_alloc_bio(); 253dd84a43cSPoul-Henning Kamp bp->bio_cmd = BIO_GETATTR; 254dd84a43cSPoul-Henning Kamp bp->bio_done = NULL; 255dd84a43cSPoul-Henning Kamp bp->bio_attribute = attr; 256dd84a43cSPoul-Henning Kamp bp->bio_length = *len; 257dd84a43cSPoul-Henning Kamp bp->bio_data = ptr; 258dd84a43cSPoul-Henning Kamp g_io_request(bp, cp); 25953706245SPoul-Henning Kamp error = biowait(bp, "ggetattr"); 260dd84a43cSPoul-Henning Kamp *len = bp->bio_completed; 261dd84a43cSPoul-Henning Kamp g_destroy_bio(bp); 262dd84a43cSPoul-Henning Kamp return (error); 263dd84a43cSPoul-Henning Kamp } 264dd84a43cSPoul-Henning Kamp 265c3618c65SPawel Jakub Dawidek int 266c3618c65SPawel Jakub Dawidek g_io_flush(struct g_consumer *cp) 267c3618c65SPawel Jakub Dawidek { 268c3618c65SPawel Jakub Dawidek struct bio *bp; 269c3618c65SPawel Jakub Dawidek int error; 270c3618c65SPawel Jakub Dawidek 271c3618c65SPawel Jakub Dawidek g_trace(G_T_BIO, "bio_flush(%s)", cp->provider->name); 272c3618c65SPawel Jakub Dawidek bp = g_alloc_bio(); 273c3618c65SPawel Jakub Dawidek bp->bio_cmd = BIO_FLUSH; 274f03f7a0cSJustin T. Gibbs bp->bio_flags |= BIO_ORDERED; 275c3618c65SPawel Jakub Dawidek bp->bio_done = NULL; 276c3618c65SPawel Jakub Dawidek bp->bio_attribute = NULL; 277c3618c65SPawel Jakub Dawidek bp->bio_offset = cp->provider->mediasize; 278c3618c65SPawel Jakub Dawidek bp->bio_length = 0; 279c3618c65SPawel Jakub Dawidek bp->bio_data = NULL; 280c3618c65SPawel Jakub Dawidek g_io_request(bp, cp); 281c3618c65SPawel Jakub Dawidek error = biowait(bp, "gflush"); 282c3618c65SPawel Jakub Dawidek g_destroy_bio(bp); 283c3618c65SPawel Jakub Dawidek return (error); 284c3618c65SPawel Jakub Dawidek } 285c3618c65SPawel Jakub Dawidek 286e39d70d4SPoul-Henning Kamp static int 287e39d70d4SPoul-Henning Kamp g_io_check(struct bio *bp) 288e39d70d4SPoul-Henning Kamp { 289e39d70d4SPoul-Henning Kamp struct g_consumer *cp; 290e39d70d4SPoul-Henning Kamp struct g_provider *pp; 291e39d70d4SPoul-Henning Kamp 292e39d70d4SPoul-Henning Kamp cp = bp->bio_from; 293e39d70d4SPoul-Henning Kamp pp = bp->bio_to; 294e39d70d4SPoul-Henning Kamp 295e39d70d4SPoul-Henning Kamp /* Fail if access counters dont allow the operation */ 296e39d70d4SPoul-Henning Kamp switch(bp->bio_cmd) { 297e39d70d4SPoul-Henning Kamp case BIO_READ: 298e39d70d4SPoul-Henning Kamp case BIO_GETATTR: 299e39d70d4SPoul-Henning Kamp if (cp->acr == 0) 300e39d70d4SPoul-Henning Kamp return (EPERM); 301e39d70d4SPoul-Henning Kamp break; 302e39d70d4SPoul-Henning Kamp case BIO_WRITE: 303e39d70d4SPoul-Henning Kamp case BIO_DELETE: 304c3618c65SPawel Jakub Dawidek case BIO_FLUSH: 305e39d70d4SPoul-Henning Kamp if (cp->acw == 0) 306e39d70d4SPoul-Henning Kamp return (EPERM); 307e39d70d4SPoul-Henning Kamp break; 308e39d70d4SPoul-Henning Kamp default: 309e39d70d4SPoul-Henning Kamp return (EPERM); 310e39d70d4SPoul-Henning Kamp } 311e39d70d4SPoul-Henning Kamp /* if provider is marked for error, don't disturb. */ 312e39d70d4SPoul-Henning Kamp if (pp->error) 313e39d70d4SPoul-Henning Kamp return (pp->error); 3143631c638SAlexander Motin if (cp->flags & G_CF_ORPHAN) 3153631c638SAlexander Motin return (ENXIO); 316e39d70d4SPoul-Henning Kamp 317e39d70d4SPoul-Henning Kamp switch(bp->bio_cmd) { 318e39d70d4SPoul-Henning Kamp case BIO_READ: 319e39d70d4SPoul-Henning Kamp case BIO_WRITE: 320e39d70d4SPoul-Henning Kamp case BIO_DELETE: 3212a842317SAndriy Gapon /* Zero sectorsize or mediasize is probably a lack of media. */ 3222a842317SAndriy Gapon if (pp->sectorsize == 0 || pp->mediasize == 0) 32343bff1a7SPoul-Henning Kamp return (ENXIO); 324e39d70d4SPoul-Henning Kamp /* Reject I/O not on sector boundary */ 325e39d70d4SPoul-Henning Kamp if (bp->bio_offset % pp->sectorsize) 326e39d70d4SPoul-Henning Kamp return (EINVAL); 327e39d70d4SPoul-Henning Kamp /* Reject I/O not integral sector long */ 328e39d70d4SPoul-Henning Kamp if (bp->bio_length % pp->sectorsize) 329e39d70d4SPoul-Henning Kamp return (EINVAL); 330d1b8bf47SPoul-Henning Kamp /* Reject requests before or past the end of media. */ 331d1b8bf47SPoul-Henning Kamp if (bp->bio_offset < 0) 332d1b8bf47SPoul-Henning Kamp return (EIO); 333e39d70d4SPoul-Henning Kamp if (bp->bio_offset > pp->mediasize) 334e39d70d4SPoul-Henning Kamp return (EIO); 335e39d70d4SPoul-Henning Kamp break; 336e39d70d4SPoul-Henning Kamp default: 337e39d70d4SPoul-Henning Kamp break; 338e39d70d4SPoul-Henning Kamp } 339e39d70d4SPoul-Henning Kamp return (0); 340e39d70d4SPoul-Henning Kamp } 341e39d70d4SPoul-Henning Kamp 3426231f75bSLuigi Rizzo /* 3436231f75bSLuigi Rizzo * bio classification support. 3446231f75bSLuigi Rizzo * 3456231f75bSLuigi Rizzo * g_register_classifier() and g_unregister_classifier() 3466231f75bSLuigi Rizzo * are used to add/remove a classifier from the list. 3476231f75bSLuigi Rizzo * The list is protected using the g_bio_run_down lock, 3486231f75bSLuigi Rizzo * because the classifiers are called in this path. 3496231f75bSLuigi Rizzo * 3506231f75bSLuigi Rizzo * g_io_request() passes bio's that are not already classified 3516231f75bSLuigi Rizzo * (i.e. those with bio_classifier1 == NULL) to g_run_classifiers(). 3526231f75bSLuigi Rizzo * Classifiers can store their result in the two fields 3536231f75bSLuigi Rizzo * bio_classifier1 and bio_classifier2. 3546231f75bSLuigi Rizzo * A classifier that updates one of the fields should 3556231f75bSLuigi Rizzo * return a non-zero value. 3566231f75bSLuigi Rizzo * If no classifier updates the field, g_run_classifiers() sets 3576231f75bSLuigi Rizzo * bio_classifier1 = BIO_NOTCLASSIFIED to avoid further calls. 3586231f75bSLuigi Rizzo */ 3596231f75bSLuigi Rizzo 3606231f75bSLuigi Rizzo int 3616231f75bSLuigi Rizzo g_register_classifier(struct g_classifier_hook *hook) 3626231f75bSLuigi Rizzo { 3636231f75bSLuigi Rizzo 3646231f75bSLuigi Rizzo g_bioq_lock(&g_bio_run_down); 3656231f75bSLuigi Rizzo TAILQ_INSERT_TAIL(&g_classifier_tailq, hook, link); 3666231f75bSLuigi Rizzo g_bioq_unlock(&g_bio_run_down); 3676231f75bSLuigi Rizzo 3686231f75bSLuigi Rizzo return (0); 3696231f75bSLuigi Rizzo } 3706231f75bSLuigi Rizzo 3716231f75bSLuigi Rizzo void 3726231f75bSLuigi Rizzo g_unregister_classifier(struct g_classifier_hook *hook) 3736231f75bSLuigi Rizzo { 3746231f75bSLuigi Rizzo struct g_classifier_hook *entry; 3756231f75bSLuigi Rizzo 3766231f75bSLuigi Rizzo g_bioq_lock(&g_bio_run_down); 3776231f75bSLuigi Rizzo TAILQ_FOREACH(entry, &g_classifier_tailq, link) { 3786231f75bSLuigi Rizzo if (entry == hook) { 3796231f75bSLuigi Rizzo TAILQ_REMOVE(&g_classifier_tailq, hook, link); 3806231f75bSLuigi Rizzo break; 3816231f75bSLuigi Rizzo } 3826231f75bSLuigi Rizzo } 3836231f75bSLuigi Rizzo g_bioq_unlock(&g_bio_run_down); 3846231f75bSLuigi Rizzo } 3856231f75bSLuigi Rizzo 3866231f75bSLuigi Rizzo static void 3876231f75bSLuigi Rizzo g_run_classifiers(struct bio *bp) 3886231f75bSLuigi Rizzo { 3896231f75bSLuigi Rizzo struct g_classifier_hook *hook; 3906231f75bSLuigi Rizzo int classified = 0; 3916231f75bSLuigi Rizzo 3926231f75bSLuigi Rizzo TAILQ_FOREACH(hook, &g_classifier_tailq, link) 3936231f75bSLuigi Rizzo classified |= hook->func(hook->arg, bp); 3946231f75bSLuigi Rizzo 3956231f75bSLuigi Rizzo if (!classified) 3966231f75bSLuigi Rizzo bp->bio_classifier1 = BIO_NOTCLASSIFIED; 3976231f75bSLuigi Rizzo } 3986231f75bSLuigi Rizzo 399dd84a43cSPoul-Henning Kamp void 400dd84a43cSPoul-Henning Kamp g_io_request(struct bio *bp, struct g_consumer *cp) 401dd84a43cSPoul-Henning Kamp { 402801bb689SPoul-Henning Kamp struct g_provider *pp; 4030d883b11SAlexander Motin int first; 404dd84a43cSPoul-Henning Kamp 405d0e17c1bSPoul-Henning Kamp KASSERT(cp != NULL, ("NULL cp in g_io_request")); 406d0e17c1bSPoul-Henning Kamp KASSERT(bp != NULL, ("NULL bp in g_io_request")); 407e060b6bdSPoul-Henning Kamp pp = cp->provider; 408801bb689SPoul-Henning Kamp KASSERT(pp != NULL, ("consumer not attached in g_io_request")); 40992ee312dSPawel Jakub Dawidek #ifdef DIAGNOSTIC 41092ee312dSPawel Jakub Dawidek KASSERT(bp->bio_driver1 == NULL, 41192ee312dSPawel Jakub Dawidek ("bio_driver1 used by the consumer (geom %s)", cp->geom->name)); 41292ee312dSPawel Jakub Dawidek KASSERT(bp->bio_driver2 == NULL, 41392ee312dSPawel Jakub Dawidek ("bio_driver2 used by the consumer (geom %s)", cp->geom->name)); 41492ee312dSPawel Jakub Dawidek KASSERT(bp->bio_pflags == 0, 41592ee312dSPawel Jakub Dawidek ("bio_pflags used by the consumer (geom %s)", cp->geom->name)); 41692ee312dSPawel Jakub Dawidek /* 41792ee312dSPawel Jakub Dawidek * Remember consumer's private fields, so we can detect if they were 41892ee312dSPawel Jakub Dawidek * modified by the provider. 41992ee312dSPawel Jakub Dawidek */ 42092ee312dSPawel Jakub Dawidek bp->_bio_caller1 = bp->bio_caller1; 42192ee312dSPawel Jakub Dawidek bp->_bio_caller2 = bp->bio_caller2; 42292ee312dSPawel Jakub Dawidek bp->_bio_cflags = bp->bio_cflags; 42392ee312dSPawel Jakub Dawidek #endif 424801bb689SPoul-Henning Kamp 4251ded77b2SPawel Jakub Dawidek if (bp->bio_cmd & (BIO_READ|BIO_WRITE|BIO_GETATTR)) { 426c3618c65SPawel Jakub Dawidek KASSERT(bp->bio_data != NULL, 4271ded77b2SPawel Jakub Dawidek ("NULL bp->data in g_io_request(cmd=%hhu)", bp->bio_cmd)); 4281ded77b2SPawel Jakub Dawidek } 4291ded77b2SPawel Jakub Dawidek if (bp->bio_cmd & (BIO_DELETE|BIO_FLUSH)) { 4301ded77b2SPawel Jakub Dawidek KASSERT(bp->bio_data == NULL, 4311ded77b2SPawel Jakub Dawidek ("non-NULL bp->data in g_io_request(cmd=%hhu)", 4321ded77b2SPawel Jakub Dawidek bp->bio_cmd)); 433c3618c65SPawel Jakub Dawidek } 434dcbd0fe5SPoul-Henning Kamp if (bp->bio_cmd & (BIO_READ|BIO_WRITE|BIO_DELETE)) { 435dcbd0fe5SPoul-Henning Kamp KASSERT(bp->bio_offset % cp->provider->sectorsize == 0, 436dcbd0fe5SPoul-Henning Kamp ("wrong offset %jd for sectorsize %u", 437dcbd0fe5SPoul-Henning Kamp bp->bio_offset, cp->provider->sectorsize)); 438dcbd0fe5SPoul-Henning Kamp KASSERT(bp->bio_length % cp->provider->sectorsize == 0, 439dcbd0fe5SPoul-Henning Kamp ("wrong length %jd for sectorsize %u", 440dcbd0fe5SPoul-Henning Kamp bp->bio_length, cp->provider->sectorsize)); 441dcbd0fe5SPoul-Henning Kamp } 442dcbd0fe5SPoul-Henning Kamp 443f7717523SStephan Uphoff g_trace(G_T_BIO, "bio_request(%p) from %p(%s) to %p(%s) cmd %d", 444f7717523SStephan Uphoff bp, cp, cp->geom->name, pp, pp->name, bp->bio_cmd); 445f7717523SStephan Uphoff 446dd84a43cSPoul-Henning Kamp bp->bio_from = cp; 447801bb689SPoul-Henning Kamp bp->bio_to = pp; 4482fccec19SPoul-Henning Kamp bp->bio_error = 0; 4492fccec19SPoul-Henning Kamp bp->bio_completed = 0; 450dd84a43cSPoul-Henning Kamp 45119fa21aaSPoul-Henning Kamp KASSERT(!(bp->bio_flags & BIO_ONQUEUE), 45219fa21aaSPoul-Henning Kamp ("Bio already on queue bp=%p", bp)); 45319fa21aaSPoul-Henning Kamp bp->bio_flags |= BIO_ONQUEUE; 45419fa21aaSPoul-Henning Kamp 455a5be8eb5SAlexander Motin if (g_collectstats) 45619fa21aaSPoul-Henning Kamp binuptime(&bp->bio_t0); 457a5be8eb5SAlexander Motin else 458a5be8eb5SAlexander Motin getbinuptime(&bp->bio_t0); 4598827c821SPoul-Henning Kamp 4608827c821SPoul-Henning Kamp /* 4618827c821SPoul-Henning Kamp * The statistics collection is lockless, as such, but we 4628827c821SPoul-Henning Kamp * can not update one instance of the statistics from more 4638827c821SPoul-Henning Kamp * than one thread at a time, so grab the lock first. 4646231f75bSLuigi Rizzo * 4656231f75bSLuigi Rizzo * We also use the lock to protect the list of classifiers. 4668827c821SPoul-Henning Kamp */ 46719fa21aaSPoul-Henning Kamp g_bioq_lock(&g_bio_run_down); 4686231f75bSLuigi Rizzo 4696231f75bSLuigi Rizzo if (!TAILQ_EMPTY(&g_classifier_tailq) && !bp->bio_classifier1) 4706231f75bSLuigi Rizzo g_run_classifiers(bp); 4716231f75bSLuigi Rizzo 472cf457284SPoul-Henning Kamp if (g_collectstats & 1) 47319fa21aaSPoul-Henning Kamp devstat_start_transaction(pp->stat, &bp->bio_t0); 474cf457284SPoul-Henning Kamp if (g_collectstats & 2) 47519fa21aaSPoul-Henning Kamp devstat_start_transaction(cp->stat, &bp->bio_t0); 47619fa21aaSPoul-Henning Kamp 47719fa21aaSPoul-Henning Kamp pp->nstart++; 478cf457284SPoul-Henning Kamp cp->nstart++; 4790d883b11SAlexander Motin first = TAILQ_EMPTY(&g_bio_run_down.bio_queue); 48019fa21aaSPoul-Henning Kamp TAILQ_INSERT_TAIL(&g_bio_run_down.bio_queue, bp, bio_queue); 48119fa21aaSPoul-Henning Kamp g_bio_run_down.bio_queue_length++; 48219fa21aaSPoul-Henning Kamp g_bioq_unlock(&g_bio_run_down); 483e39d70d4SPoul-Henning Kamp 4842fccec19SPoul-Henning Kamp /* Pass it on down. */ 4850d883b11SAlexander Motin if (first) 486dd84a43cSPoul-Henning Kamp wakeup(&g_wait_down); 487dd84a43cSPoul-Henning Kamp } 488dd84a43cSPoul-Henning Kamp 489dd84a43cSPoul-Henning Kamp void 49072840432SPoul-Henning Kamp g_io_deliver(struct bio *bp, int error) 491dd84a43cSPoul-Henning Kamp { 492801bb689SPoul-Henning Kamp struct g_consumer *cp; 493801bb689SPoul-Henning Kamp struct g_provider *pp; 4940d883b11SAlexander Motin int first; 495dd84a43cSPoul-Henning Kamp 496e060b6bdSPoul-Henning Kamp KASSERT(bp != NULL, ("NULL bp in g_io_deliver")); 497801bb689SPoul-Henning Kamp pp = bp->bio_to; 498f7eeab17SPoul-Henning Kamp KASSERT(pp != NULL, ("NULL bio_to in g_io_deliver")); 499f7eeab17SPoul-Henning Kamp cp = bp->bio_from; 500f7eeab17SPoul-Henning Kamp if (cp == NULL) { 501f7eeab17SPoul-Henning Kamp bp->bio_error = error; 502f7eeab17SPoul-Henning Kamp bp->bio_done(bp); 503f7eeab17SPoul-Henning Kamp return; 504f7eeab17SPoul-Henning Kamp } 505801bb689SPoul-Henning Kamp KASSERT(cp != NULL, ("NULL bio_from in g_io_deliver")); 506801bb689SPoul-Henning Kamp KASSERT(cp->geom != NULL, ("NULL bio_from->geom in g_io_deliver")); 507fb231f36SEdward Tomasz Napierala #ifdef DIAGNOSTIC 508fb231f36SEdward Tomasz Napierala /* 509fb231f36SEdward Tomasz Napierala * Some classes - GJournal in particular - can modify bio's 510fb231f36SEdward Tomasz Napierala * private fields while the bio is in transit; G_GEOM_VOLATILE_BIO 511fb231f36SEdward Tomasz Napierala * flag means it's an expected behaviour for that particular geom. 512fb231f36SEdward Tomasz Napierala */ 513fb231f36SEdward Tomasz Napierala if ((cp->geom->flags & G_GEOM_VOLATILE_BIO) == 0) { 514fb231f36SEdward Tomasz Napierala KASSERT(bp->bio_caller1 == bp->_bio_caller1, 515fb231f36SEdward Tomasz Napierala ("bio_caller1 used by the provider %s", pp->name)); 516fb231f36SEdward Tomasz Napierala KASSERT(bp->bio_caller2 == bp->_bio_caller2, 517fb231f36SEdward Tomasz Napierala ("bio_caller2 used by the provider %s", pp->name)); 518fb231f36SEdward Tomasz Napierala KASSERT(bp->bio_cflags == bp->_bio_cflags, 519fb231f36SEdward Tomasz Napierala ("bio_cflags used by the provider %s", pp->name)); 520fb231f36SEdward Tomasz Napierala } 521fb231f36SEdward Tomasz Napierala #endif 52246aeebecSPawel Jakub Dawidek KASSERT(bp->bio_completed >= 0, ("bio_completed can't be less than 0")); 52346aeebecSPawel Jakub Dawidek KASSERT(bp->bio_completed <= bp->bio_length, 52446aeebecSPawel Jakub Dawidek ("bio_completed can't be greater than bio_length")); 5255ab413bfSPoul-Henning Kamp 526dd84a43cSPoul-Henning Kamp g_trace(G_T_BIO, 5270355b86eSPoul-Henning Kamp "g_io_deliver(%p) from %p(%s) to %p(%s) cmd %d error %d off %jd len %jd", 528801bb689SPoul-Henning Kamp bp, cp, cp->geom->name, pp, pp->name, bp->bio_cmd, error, 5290355b86eSPoul-Henning Kamp (intmax_t)bp->bio_offset, (intmax_t)bp->bio_length); 530801bb689SPoul-Henning Kamp 53119fa21aaSPoul-Henning Kamp KASSERT(!(bp->bio_flags & BIO_ONQUEUE), 53219fa21aaSPoul-Henning Kamp ("Bio already on queue bp=%p", bp)); 53319fa21aaSPoul-Henning Kamp 534dcbd0fe5SPoul-Henning Kamp /* 535dcbd0fe5SPoul-Henning Kamp * XXX: next two doesn't belong here 536dcbd0fe5SPoul-Henning Kamp */ 537e24cbd90SPoul-Henning Kamp bp->bio_bcount = bp->bio_length; 538e24cbd90SPoul-Henning Kamp bp->bio_resid = bp->bio_bcount - bp->bio_completed; 53919fa21aaSPoul-Henning Kamp 5408827c821SPoul-Henning Kamp /* 5418827c821SPoul-Henning Kamp * The statistics collection is lockless, as such, but we 5428827c821SPoul-Henning Kamp * can not update one instance of the statistics from more 5438827c821SPoul-Henning Kamp * than one thread at a time, so grab the lock first. 5448827c821SPoul-Henning Kamp */ 54519fa21aaSPoul-Henning Kamp g_bioq_lock(&g_bio_run_up); 546cf457284SPoul-Henning Kamp if (g_collectstats & 1) 547e24cbd90SPoul-Henning Kamp devstat_end_transaction_bio(pp->stat, bp); 548cf457284SPoul-Henning Kamp if (g_collectstats & 2) 549cf457284SPoul-Henning Kamp devstat_end_transaction_bio(cp->stat, bp); 5508827c821SPoul-Henning Kamp 551c6ae9b5fSPoul-Henning Kamp cp->nend++; 552c6ae9b5fSPoul-Henning Kamp pp->nend++; 55319fa21aaSPoul-Henning Kamp if (error != ENOMEM) { 55419fa21aaSPoul-Henning Kamp bp->bio_error = error; 5550d883b11SAlexander Motin first = TAILQ_EMPTY(&g_bio_run_up.bio_queue); 55619fa21aaSPoul-Henning Kamp TAILQ_INSERT_TAIL(&g_bio_run_up.bio_queue, bp, bio_queue); 557276f72c5SPoul-Henning Kamp bp->bio_flags |= BIO_ONQUEUE; 55819fa21aaSPoul-Henning Kamp g_bio_run_up.bio_queue_length++; 55919fa21aaSPoul-Henning Kamp g_bioq_unlock(&g_bio_run_up); 5600d883b11SAlexander Motin if (first) 56119fa21aaSPoul-Henning Kamp wakeup(&g_wait_up); 56219fa21aaSPoul-Henning Kamp return; 56319fa21aaSPoul-Henning Kamp } 56419fa21aaSPoul-Henning Kamp g_bioq_unlock(&g_bio_run_up); 565dd84a43cSPoul-Henning Kamp 5662cc9686eSPoul-Henning Kamp if (bootverbose) 567801bb689SPoul-Henning Kamp printf("ENOMEM %p on %p(%s)\n", bp, pp, pp->name); 5681b949c05SPawel Jakub Dawidek bp->bio_children = 0; 5691b949c05SPawel Jakub Dawidek bp->bio_inbed = 0; 570*60114438SPawel Jakub Dawidek bp->bio_driver1 = NULL; 571*60114438SPawel Jakub Dawidek bp->bio_driver2 = NULL; 572*60114438SPawel Jakub Dawidek bp->bio_pflags = 0; 573801bb689SPoul-Henning Kamp g_io_request(bp, cp); 5743432e4fdSPoul-Henning Kamp pace++; 5753432e4fdSPoul-Henning Kamp return; 5763432e4fdSPoul-Henning Kamp } 577dd84a43cSPoul-Henning Kamp 578dd84a43cSPoul-Henning Kamp void 579dd84a43cSPoul-Henning Kamp g_io_schedule_down(struct thread *tp __unused) 580dd84a43cSPoul-Henning Kamp { 581dd84a43cSPoul-Henning Kamp struct bio *bp; 582e39d70d4SPoul-Henning Kamp off_t excess; 583e39d70d4SPoul-Henning Kamp int error; 584dd84a43cSPoul-Henning Kamp 585dd84a43cSPoul-Henning Kamp for(;;) { 586f0e185d7SPoul-Henning Kamp g_bioq_lock(&g_bio_run_down); 587dd84a43cSPoul-Henning Kamp bp = g_bioq_first(&g_bio_run_down); 588f0e185d7SPoul-Henning Kamp if (bp == NULL) { 58949dbb61dSRobert Watson CTR0(KTR_GEOM, "g_down going to sleep"); 590f0e185d7SPoul-Henning Kamp msleep(&g_wait_down, &g_bio_run_down.bio_queue_lock, 5917fc019afSAlexander Motin PRIBIO | PDROP, "-", 0); 592f0e185d7SPoul-Henning Kamp continue; 593f0e185d7SPoul-Henning Kamp } 59449dbb61dSRobert Watson CTR0(KTR_GEOM, "g_down has work to do"); 595f0e185d7SPoul-Henning Kamp g_bioq_unlock(&g_bio_run_down); 596376ceb79SPoul-Henning Kamp if (pace > 0) { 59749dbb61dSRobert Watson CTR1(KTR_GEOM, "g_down pacing self (pace %d)", pace); 5984d70511aSJohn Baldwin pause("g_down", hz/10); 599376ceb79SPoul-Henning Kamp pace--; 600376ceb79SPoul-Henning Kamp } 601e39d70d4SPoul-Henning Kamp error = g_io_check(bp); 602e39d70d4SPoul-Henning Kamp if (error) { 60349dbb61dSRobert Watson CTR3(KTR_GEOM, "g_down g_io_check on bp %p provider " 60449dbb61dSRobert Watson "%s returned %d", bp, bp->bio_to->name, error); 605e39d70d4SPoul-Henning Kamp g_io_deliver(bp, error); 606e39d70d4SPoul-Henning Kamp continue; 607e39d70d4SPoul-Henning Kamp } 60849dbb61dSRobert Watson CTR2(KTR_GEOM, "g_down processing bp %p provider %s", bp, 60949dbb61dSRobert Watson bp->bio_to->name); 610392d56b4SPoul-Henning Kamp switch (bp->bio_cmd) { 611392d56b4SPoul-Henning Kamp case BIO_READ: 612392d56b4SPoul-Henning Kamp case BIO_WRITE: 613392d56b4SPoul-Henning Kamp case BIO_DELETE: 614e39d70d4SPoul-Henning Kamp /* Truncate requests to the end of providers media. */ 61549dbb61dSRobert Watson /* 61649dbb61dSRobert Watson * XXX: What if we truncate because of offset being 61749dbb61dSRobert Watson * bad, not length? 61849dbb61dSRobert Watson */ 619e39d70d4SPoul-Henning Kamp excess = bp->bio_offset + bp->bio_length; 620e39d70d4SPoul-Henning Kamp if (excess > bp->bio_to->mediasize) { 621e39d70d4SPoul-Henning Kamp excess -= bp->bio_to->mediasize; 622e39d70d4SPoul-Henning Kamp bp->bio_length -= excess; 62349dbb61dSRobert Watson if (excess > 0) 62449dbb61dSRobert Watson CTR3(KTR_GEOM, "g_down truncated bio " 62549dbb61dSRobert Watson "%p provider %s by %d", bp, 62649dbb61dSRobert Watson bp->bio_to->name, excess); 627e39d70d4SPoul-Henning Kamp } 628e39d70d4SPoul-Henning Kamp /* Deliver zero length transfers right here. */ 629e39d70d4SPoul-Henning Kamp if (bp->bio_length == 0) { 630e39d70d4SPoul-Henning Kamp g_io_deliver(bp, 0); 63149dbb61dSRobert Watson CTR2(KTR_GEOM, "g_down terminated 0-length " 63249dbb61dSRobert Watson "bp %p provider %s", bp, bp->bio_to->name); 633e39d70d4SPoul-Henning Kamp continue; 634e39d70d4SPoul-Henning Kamp } 635392d56b4SPoul-Henning Kamp break; 636392d56b4SPoul-Henning Kamp default: 637392d56b4SPoul-Henning Kamp break; 638392d56b4SPoul-Henning Kamp } 63951460da8SJohn Baldwin THREAD_NO_SLEEPING(); 64049dbb61dSRobert Watson CTR4(KTR_GEOM, "g_down starting bp %p provider %s off %ld " 64149dbb61dSRobert Watson "len %ld", bp, bp->bio_to->name, bp->bio_offset, 64249dbb61dSRobert Watson bp->bio_length); 643dd84a43cSPoul-Henning Kamp bp->bio_to->geom->start(bp); 64451460da8SJohn Baldwin THREAD_SLEEPING_OK(); 645dd84a43cSPoul-Henning Kamp } 646dd84a43cSPoul-Henning Kamp } 647dd84a43cSPoul-Henning Kamp 648dd84a43cSPoul-Henning Kamp void 6495fcf4e43SPoul-Henning Kamp bio_taskqueue(struct bio *bp, bio_task_t *func, void *arg) 6505fcf4e43SPoul-Henning Kamp { 6515fcf4e43SPoul-Henning Kamp bp->bio_task = func; 6525fcf4e43SPoul-Henning Kamp bp->bio_task_arg = arg; 6535fcf4e43SPoul-Henning Kamp /* 6545fcf4e43SPoul-Henning Kamp * The taskqueue is actually just a second queue off the "up" 6555fcf4e43SPoul-Henning Kamp * queue, so we use the same lock. 6565fcf4e43SPoul-Henning Kamp */ 6575fcf4e43SPoul-Henning Kamp g_bioq_lock(&g_bio_run_up); 658dcbd0fe5SPoul-Henning Kamp KASSERT(!(bp->bio_flags & BIO_ONQUEUE), 659dcbd0fe5SPoul-Henning Kamp ("Bio already on queue bp=%p target taskq", bp)); 660dcbd0fe5SPoul-Henning Kamp bp->bio_flags |= BIO_ONQUEUE; 6615fcf4e43SPoul-Henning Kamp TAILQ_INSERT_TAIL(&g_bio_run_task.bio_queue, bp, bio_queue); 6625fcf4e43SPoul-Henning Kamp g_bio_run_task.bio_queue_length++; 6635fcf4e43SPoul-Henning Kamp wakeup(&g_wait_up); 6645fcf4e43SPoul-Henning Kamp g_bioq_unlock(&g_bio_run_up); 6655fcf4e43SPoul-Henning Kamp } 6665fcf4e43SPoul-Henning Kamp 6675fcf4e43SPoul-Henning Kamp 6685fcf4e43SPoul-Henning Kamp void 669dd84a43cSPoul-Henning Kamp g_io_schedule_up(struct thread *tp __unused) 670dd84a43cSPoul-Henning Kamp { 671dd84a43cSPoul-Henning Kamp struct bio *bp; 672dd84a43cSPoul-Henning Kamp for(;;) { 673f0e185d7SPoul-Henning Kamp g_bioq_lock(&g_bio_run_up); 6745fcf4e43SPoul-Henning Kamp bp = g_bioq_first(&g_bio_run_task); 6755fcf4e43SPoul-Henning Kamp if (bp != NULL) { 6765fcf4e43SPoul-Henning Kamp g_bioq_unlock(&g_bio_run_up); 67751460da8SJohn Baldwin THREAD_NO_SLEEPING(); 67849dbb61dSRobert Watson CTR1(KTR_GEOM, "g_up processing task bp %p", bp); 6795fcf4e43SPoul-Henning Kamp bp->bio_task(bp->bio_task_arg); 68051460da8SJohn Baldwin THREAD_SLEEPING_OK(); 6815fcf4e43SPoul-Henning Kamp continue; 6825fcf4e43SPoul-Henning Kamp } 683dd84a43cSPoul-Henning Kamp bp = g_bioq_first(&g_bio_run_up); 684f0e185d7SPoul-Henning Kamp if (bp != NULL) { 685f0e185d7SPoul-Henning Kamp g_bioq_unlock(&g_bio_run_up); 68651460da8SJohn Baldwin THREAD_NO_SLEEPING(); 68749dbb61dSRobert Watson CTR4(KTR_GEOM, "g_up biodone bp %p provider %s off " 688c4901b67SSean Bruno "%jd len %ld", bp, bp->bio_to->name, 68949dbb61dSRobert Watson bp->bio_offset, bp->bio_length); 69053706245SPoul-Henning Kamp biodone(bp); 69151460da8SJohn Baldwin THREAD_SLEEPING_OK(); 692f0e185d7SPoul-Henning Kamp continue; 693f0e185d7SPoul-Henning Kamp } 69449dbb61dSRobert Watson CTR0(KTR_GEOM, "g_up going to sleep"); 695f0e185d7SPoul-Henning Kamp msleep(&g_wait_up, &g_bio_run_up.bio_queue_lock, 6967fc019afSAlexander Motin PRIBIO | PDROP, "-", 0); 697dd84a43cSPoul-Henning Kamp } 698dd84a43cSPoul-Henning Kamp } 699dd84a43cSPoul-Henning Kamp 700dd84a43cSPoul-Henning Kamp void * 701dd84a43cSPoul-Henning Kamp g_read_data(struct g_consumer *cp, off_t offset, off_t length, int *error) 702dd84a43cSPoul-Henning Kamp { 703dd84a43cSPoul-Henning Kamp struct bio *bp; 704dd84a43cSPoul-Henning Kamp void *ptr; 705dd84a43cSPoul-Henning Kamp int errorc; 706dd84a43cSPoul-Henning Kamp 7078dd5480dSPawel Jakub Dawidek KASSERT(length > 0 && length >= cp->provider->sectorsize && 7088dd5480dSPawel Jakub Dawidek length <= MAXPHYS, ("g_read_data(): invalid length %jd", 7098dd5480dSPawel Jakub Dawidek (intmax_t)length)); 7103eb6ffdfSPoul-Henning Kamp 711a2033c96SPoul-Henning Kamp bp = g_alloc_bio(); 712dd84a43cSPoul-Henning Kamp bp->bio_cmd = BIO_READ; 713dd84a43cSPoul-Henning Kamp bp->bio_done = NULL; 714dd84a43cSPoul-Henning Kamp bp->bio_offset = offset; 715dd84a43cSPoul-Henning Kamp bp->bio_length = length; 716a163d034SWarner Losh ptr = g_malloc(length, M_WAITOK); 717dd84a43cSPoul-Henning Kamp bp->bio_data = ptr; 718dd84a43cSPoul-Henning Kamp g_io_request(bp, cp); 71953706245SPoul-Henning Kamp errorc = biowait(bp, "gread"); 720dd84a43cSPoul-Henning Kamp if (error != NULL) 721dd84a43cSPoul-Henning Kamp *error = errorc; 722dd84a43cSPoul-Henning Kamp g_destroy_bio(bp); 723dd84a43cSPoul-Henning Kamp if (errorc) { 724dd84a43cSPoul-Henning Kamp g_free(ptr); 725dd84a43cSPoul-Henning Kamp ptr = NULL; 726dd84a43cSPoul-Henning Kamp } 727dd84a43cSPoul-Henning Kamp return (ptr); 728dd84a43cSPoul-Henning Kamp } 72990b1cd56SPoul-Henning Kamp 73090b1cd56SPoul-Henning Kamp int 73190b1cd56SPoul-Henning Kamp g_write_data(struct g_consumer *cp, off_t offset, void *ptr, off_t length) 73290b1cd56SPoul-Henning Kamp { 73390b1cd56SPoul-Henning Kamp struct bio *bp; 73490b1cd56SPoul-Henning Kamp int error; 73590b1cd56SPoul-Henning Kamp 7368dd5480dSPawel Jakub Dawidek KASSERT(length > 0 && length >= cp->provider->sectorsize && 7378dd5480dSPawel Jakub Dawidek length <= MAXPHYS, ("g_write_data(): invalid length %jd", 7388dd5480dSPawel Jakub Dawidek (intmax_t)length)); 7393eb6ffdfSPoul-Henning Kamp 740a2033c96SPoul-Henning Kamp bp = g_alloc_bio(); 74190b1cd56SPoul-Henning Kamp bp->bio_cmd = BIO_WRITE; 74290b1cd56SPoul-Henning Kamp bp->bio_done = NULL; 74390b1cd56SPoul-Henning Kamp bp->bio_offset = offset; 74490b1cd56SPoul-Henning Kamp bp->bio_length = length; 74590b1cd56SPoul-Henning Kamp bp->bio_data = ptr; 74690b1cd56SPoul-Henning Kamp g_io_request(bp, cp); 74790b1cd56SPoul-Henning Kamp error = biowait(bp, "gwrite"); 74890b1cd56SPoul-Henning Kamp g_destroy_bio(bp); 74990b1cd56SPoul-Henning Kamp return (error); 75090b1cd56SPoul-Henning Kamp } 75172e33095SPawel Jakub Dawidek 7522b17fb95SPawel Jakub Dawidek int 7532b17fb95SPawel Jakub Dawidek g_delete_data(struct g_consumer *cp, off_t offset, off_t length) 7542b17fb95SPawel Jakub Dawidek { 7552b17fb95SPawel Jakub Dawidek struct bio *bp; 7562b17fb95SPawel Jakub Dawidek int error; 7572b17fb95SPawel Jakub Dawidek 758eed6cda9SPoul-Henning Kamp KASSERT(length > 0 && length >= cp->provider->sectorsize, 759eed6cda9SPoul-Henning Kamp ("g_delete_data(): invalid length %jd", (intmax_t)length)); 7602b17fb95SPawel Jakub Dawidek 7612b17fb95SPawel Jakub Dawidek bp = g_alloc_bio(); 7622b17fb95SPawel Jakub Dawidek bp->bio_cmd = BIO_DELETE; 7632b17fb95SPawel Jakub Dawidek bp->bio_done = NULL; 7642b17fb95SPawel Jakub Dawidek bp->bio_offset = offset; 7652b17fb95SPawel Jakub Dawidek bp->bio_length = length; 7662b17fb95SPawel Jakub Dawidek bp->bio_data = NULL; 7672b17fb95SPawel Jakub Dawidek g_io_request(bp, cp); 7682b17fb95SPawel Jakub Dawidek error = biowait(bp, "gdelete"); 7692b17fb95SPawel Jakub Dawidek g_destroy_bio(bp); 7702b17fb95SPawel Jakub Dawidek return (error); 7712b17fb95SPawel Jakub Dawidek } 7722b17fb95SPawel Jakub Dawidek 77372e33095SPawel Jakub Dawidek void 77472e33095SPawel Jakub Dawidek g_print_bio(struct bio *bp) 77572e33095SPawel Jakub Dawidek { 77672e33095SPawel Jakub Dawidek const char *pname, *cmd = NULL; 77772e33095SPawel Jakub Dawidek 77872e33095SPawel Jakub Dawidek if (bp->bio_to != NULL) 77972e33095SPawel Jakub Dawidek pname = bp->bio_to->name; 78072e33095SPawel Jakub Dawidek else 78172e33095SPawel Jakub Dawidek pname = "[unknown]"; 78272e33095SPawel Jakub Dawidek 78372e33095SPawel Jakub Dawidek switch (bp->bio_cmd) { 78472e33095SPawel Jakub Dawidek case BIO_GETATTR: 78572e33095SPawel Jakub Dawidek cmd = "GETATTR"; 78672e33095SPawel Jakub Dawidek printf("%s[%s(attr=%s)]", pname, cmd, bp->bio_attribute); 78772e33095SPawel Jakub Dawidek return; 788c3618c65SPawel Jakub Dawidek case BIO_FLUSH: 789c3618c65SPawel Jakub Dawidek cmd = "FLUSH"; 790c3618c65SPawel Jakub Dawidek printf("%s[%s]", pname, cmd); 791c3618c65SPawel Jakub Dawidek return; 79272e33095SPawel Jakub Dawidek case BIO_READ: 79372e33095SPawel Jakub Dawidek cmd = "READ"; 7947ce513a5SEdward Tomasz Napierala break; 79572e33095SPawel Jakub Dawidek case BIO_WRITE: 79672e33095SPawel Jakub Dawidek cmd = "WRITE"; 7977ce513a5SEdward Tomasz Napierala break; 79872e33095SPawel Jakub Dawidek case BIO_DELETE: 79972e33095SPawel Jakub Dawidek cmd = "DELETE"; 8007ce513a5SEdward Tomasz Napierala break; 80172e33095SPawel Jakub Dawidek default: 80272e33095SPawel Jakub Dawidek cmd = "UNKNOWN"; 80372e33095SPawel Jakub Dawidek printf("%s[%s()]", pname, cmd); 80472e33095SPawel Jakub Dawidek return; 80572e33095SPawel Jakub Dawidek } 8067ce513a5SEdward Tomasz Napierala printf("%s[%s(offset=%jd, length=%jd)]", pname, cmd, 8077ce513a5SEdward Tomasz Napierala (intmax_t)bp->bio_offset, (intmax_t)bp->bio_length); 80872e33095SPawel Jakub Dawidek } 809