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; 180dd84a43cSPoul-Henning Kamp bp2->bio_length = bp->bio_length; 181dd84a43cSPoul-Henning Kamp bp2->bio_offset = bp->bio_offset; 182dd84a43cSPoul-Henning Kamp bp2->bio_data = bp->bio_data; 183dd84a43cSPoul-Henning Kamp bp2->bio_attribute = bp->bio_attribute; 1846231f75bSLuigi Rizzo /* Inherit classification info from the parent */ 1856231f75bSLuigi Rizzo bp2->bio_classifier1 = bp->bio_classifier1; 1866231f75bSLuigi Rizzo bp2->bio_classifier2 = bp->bio_classifier2; 187801bb689SPoul-Henning Kamp bp->bio_children++; 188a1bd3ee2SPoul-Henning Kamp } 1893b378147SPawel Jakub Dawidek #ifdef KTR 190b656c1b8SPawel Jakub Dawidek if ((KTR_COMPILE & KTR_GEOM) && (ktr_mask & KTR_GEOM)) { 1913b378147SPawel Jakub Dawidek struct stack st; 1923b378147SPawel Jakub Dawidek 193ad572235SRuslan Ermilov CTR2(KTR_GEOM, "g_clone_bio(%p): %p", bp, bp2); 1943b378147SPawel Jakub Dawidek stack_save(&st); 1953b378147SPawel Jakub Dawidek CTRSTACK(KTR_GEOM, &st, 3, 0); 1963b378147SPawel Jakub Dawidek } 1973b378147SPawel Jakub Dawidek #endif 198dd84a43cSPoul-Henning Kamp return(bp2); 199dd84a43cSPoul-Henning Kamp } 200dd84a43cSPoul-Henning Kamp 2014bec0ff1SPawel Jakub Dawidek struct bio * 2024bec0ff1SPawel Jakub Dawidek g_duplicate_bio(struct bio *bp) 2034bec0ff1SPawel Jakub Dawidek { 2044bec0ff1SPawel Jakub Dawidek struct bio *bp2; 2054bec0ff1SPawel Jakub Dawidek 2064bec0ff1SPawel Jakub Dawidek bp2 = uma_zalloc(biozone, M_WAITOK | M_ZERO); 2074bec0ff1SPawel Jakub Dawidek bp2->bio_parent = bp; 2084bec0ff1SPawel Jakub Dawidek bp2->bio_cmd = bp->bio_cmd; 2094bec0ff1SPawel Jakub Dawidek bp2->bio_length = bp->bio_length; 2104bec0ff1SPawel Jakub Dawidek bp2->bio_offset = bp->bio_offset; 2114bec0ff1SPawel Jakub Dawidek bp2->bio_data = bp->bio_data; 2124bec0ff1SPawel Jakub Dawidek bp2->bio_attribute = bp->bio_attribute; 2134bec0ff1SPawel Jakub Dawidek bp->bio_children++; 2144bec0ff1SPawel Jakub Dawidek #ifdef KTR 215b656c1b8SPawel Jakub Dawidek if ((KTR_COMPILE & KTR_GEOM) && (ktr_mask & KTR_GEOM)) { 2164bec0ff1SPawel Jakub Dawidek struct stack st; 2174bec0ff1SPawel Jakub Dawidek 2184bec0ff1SPawel Jakub Dawidek CTR2(KTR_GEOM, "g_duplicate_bio(%p): %p", bp, bp2); 2194bec0ff1SPawel Jakub Dawidek stack_save(&st); 2204bec0ff1SPawel Jakub Dawidek CTRSTACK(KTR_GEOM, &st, 3, 0); 2214bec0ff1SPawel Jakub Dawidek } 2224bec0ff1SPawel Jakub Dawidek #endif 2234bec0ff1SPawel Jakub Dawidek return(bp2); 2244bec0ff1SPawel Jakub Dawidek } 2254bec0ff1SPawel Jakub Dawidek 226dd84a43cSPoul-Henning Kamp void 227dd84a43cSPoul-Henning Kamp g_io_init() 228dd84a43cSPoul-Henning Kamp { 229dd84a43cSPoul-Henning Kamp 230dd84a43cSPoul-Henning Kamp g_bioq_init(&g_bio_run_down); 231dd84a43cSPoul-Henning Kamp g_bioq_init(&g_bio_run_up); 2325fcf4e43SPoul-Henning Kamp g_bioq_init(&g_bio_run_task); 2335ffb2c8bSPoul-Henning Kamp biozone = uma_zcreate("g_bio", sizeof (struct bio), 2345ffb2c8bSPoul-Henning Kamp NULL, NULL, 2355ffb2c8bSPoul-Henning Kamp NULL, NULL, 2365ffb2c8bSPoul-Henning Kamp 0, 0); 237dd84a43cSPoul-Henning Kamp } 238dd84a43cSPoul-Henning Kamp 239dd84a43cSPoul-Henning Kamp int 2400d3f37a8SPoul-Henning Kamp g_io_getattr(const char *attr, struct g_consumer *cp, int *len, void *ptr) 241dd84a43cSPoul-Henning Kamp { 242dd84a43cSPoul-Henning Kamp struct bio *bp; 243dd84a43cSPoul-Henning Kamp int error; 244dd84a43cSPoul-Henning Kamp 245dd84a43cSPoul-Henning Kamp g_trace(G_T_BIO, "bio_getattr(%s)", attr); 246a2033c96SPoul-Henning Kamp bp = g_alloc_bio(); 247dd84a43cSPoul-Henning Kamp bp->bio_cmd = BIO_GETATTR; 248dd84a43cSPoul-Henning Kamp bp->bio_done = NULL; 249dd84a43cSPoul-Henning Kamp bp->bio_attribute = attr; 250dd84a43cSPoul-Henning Kamp bp->bio_length = *len; 251dd84a43cSPoul-Henning Kamp bp->bio_data = ptr; 252dd84a43cSPoul-Henning Kamp g_io_request(bp, cp); 25353706245SPoul-Henning Kamp error = biowait(bp, "ggetattr"); 254dd84a43cSPoul-Henning Kamp *len = bp->bio_completed; 255dd84a43cSPoul-Henning Kamp g_destroy_bio(bp); 256dd84a43cSPoul-Henning Kamp return (error); 257dd84a43cSPoul-Henning Kamp } 258dd84a43cSPoul-Henning Kamp 259c3618c65SPawel Jakub Dawidek int 260c3618c65SPawel Jakub Dawidek g_io_flush(struct g_consumer *cp) 261c3618c65SPawel Jakub Dawidek { 262c3618c65SPawel Jakub Dawidek struct bio *bp; 263c3618c65SPawel Jakub Dawidek int error; 264c3618c65SPawel Jakub Dawidek 265c3618c65SPawel Jakub Dawidek g_trace(G_T_BIO, "bio_flush(%s)", cp->provider->name); 266c3618c65SPawel Jakub Dawidek bp = g_alloc_bio(); 267c3618c65SPawel Jakub Dawidek bp->bio_cmd = BIO_FLUSH; 268*f03f7a0cSJustin T. Gibbs bp->bio_flags |= BIO_ORDERED; 269c3618c65SPawel Jakub Dawidek bp->bio_done = NULL; 270c3618c65SPawel Jakub Dawidek bp->bio_attribute = NULL; 271c3618c65SPawel Jakub Dawidek bp->bio_offset = cp->provider->mediasize; 272c3618c65SPawel Jakub Dawidek bp->bio_length = 0; 273c3618c65SPawel Jakub Dawidek bp->bio_data = NULL; 274c3618c65SPawel Jakub Dawidek g_io_request(bp, cp); 275c3618c65SPawel Jakub Dawidek error = biowait(bp, "gflush"); 276c3618c65SPawel Jakub Dawidek g_destroy_bio(bp); 277c3618c65SPawel Jakub Dawidek return (error); 278c3618c65SPawel Jakub Dawidek } 279c3618c65SPawel Jakub Dawidek 280e39d70d4SPoul-Henning Kamp static int 281e39d70d4SPoul-Henning Kamp g_io_check(struct bio *bp) 282e39d70d4SPoul-Henning Kamp { 283e39d70d4SPoul-Henning Kamp struct g_consumer *cp; 284e39d70d4SPoul-Henning Kamp struct g_provider *pp; 285e39d70d4SPoul-Henning Kamp 286e39d70d4SPoul-Henning Kamp cp = bp->bio_from; 287e39d70d4SPoul-Henning Kamp pp = bp->bio_to; 288e39d70d4SPoul-Henning Kamp 289e39d70d4SPoul-Henning Kamp /* Fail if access counters dont allow the operation */ 290e39d70d4SPoul-Henning Kamp switch(bp->bio_cmd) { 291e39d70d4SPoul-Henning Kamp case BIO_READ: 292e39d70d4SPoul-Henning Kamp case BIO_GETATTR: 293e39d70d4SPoul-Henning Kamp if (cp->acr == 0) 294e39d70d4SPoul-Henning Kamp return (EPERM); 295e39d70d4SPoul-Henning Kamp break; 296e39d70d4SPoul-Henning Kamp case BIO_WRITE: 297e39d70d4SPoul-Henning Kamp case BIO_DELETE: 298c3618c65SPawel Jakub Dawidek case BIO_FLUSH: 299e39d70d4SPoul-Henning Kamp if (cp->acw == 0) 300e39d70d4SPoul-Henning Kamp return (EPERM); 301e39d70d4SPoul-Henning Kamp break; 302e39d70d4SPoul-Henning Kamp default: 303e39d70d4SPoul-Henning Kamp return (EPERM); 304e39d70d4SPoul-Henning Kamp } 305e39d70d4SPoul-Henning Kamp /* if provider is marked for error, don't disturb. */ 306e39d70d4SPoul-Henning Kamp if (pp->error) 307e39d70d4SPoul-Henning Kamp return (pp->error); 308e39d70d4SPoul-Henning Kamp 309e39d70d4SPoul-Henning Kamp switch(bp->bio_cmd) { 310e39d70d4SPoul-Henning Kamp case BIO_READ: 311e39d70d4SPoul-Henning Kamp case BIO_WRITE: 312e39d70d4SPoul-Henning Kamp case BIO_DELETE: 3132a842317SAndriy Gapon /* Zero sectorsize or mediasize is probably a lack of media. */ 3142a842317SAndriy Gapon if (pp->sectorsize == 0 || pp->mediasize == 0) 31543bff1a7SPoul-Henning Kamp return (ENXIO); 316e39d70d4SPoul-Henning Kamp /* Reject I/O not on sector boundary */ 317e39d70d4SPoul-Henning Kamp if (bp->bio_offset % pp->sectorsize) 318e39d70d4SPoul-Henning Kamp return (EINVAL); 319e39d70d4SPoul-Henning Kamp /* Reject I/O not integral sector long */ 320e39d70d4SPoul-Henning Kamp if (bp->bio_length % pp->sectorsize) 321e39d70d4SPoul-Henning Kamp return (EINVAL); 322d1b8bf47SPoul-Henning Kamp /* Reject requests before or past the end of media. */ 323d1b8bf47SPoul-Henning Kamp if (bp->bio_offset < 0) 324d1b8bf47SPoul-Henning Kamp return (EIO); 325e39d70d4SPoul-Henning Kamp if (bp->bio_offset > pp->mediasize) 326e39d70d4SPoul-Henning Kamp return (EIO); 327e39d70d4SPoul-Henning Kamp break; 328e39d70d4SPoul-Henning Kamp default: 329e39d70d4SPoul-Henning Kamp break; 330e39d70d4SPoul-Henning Kamp } 331e39d70d4SPoul-Henning Kamp return (0); 332e39d70d4SPoul-Henning Kamp } 333e39d70d4SPoul-Henning Kamp 3346231f75bSLuigi Rizzo /* 3356231f75bSLuigi Rizzo * bio classification support. 3366231f75bSLuigi Rizzo * 3376231f75bSLuigi Rizzo * g_register_classifier() and g_unregister_classifier() 3386231f75bSLuigi Rizzo * are used to add/remove a classifier from the list. 3396231f75bSLuigi Rizzo * The list is protected using the g_bio_run_down lock, 3406231f75bSLuigi Rizzo * because the classifiers are called in this path. 3416231f75bSLuigi Rizzo * 3426231f75bSLuigi Rizzo * g_io_request() passes bio's that are not already classified 3436231f75bSLuigi Rizzo * (i.e. those with bio_classifier1 == NULL) to g_run_classifiers(). 3446231f75bSLuigi Rizzo * Classifiers can store their result in the two fields 3456231f75bSLuigi Rizzo * bio_classifier1 and bio_classifier2. 3466231f75bSLuigi Rizzo * A classifier that updates one of the fields should 3476231f75bSLuigi Rizzo * return a non-zero value. 3486231f75bSLuigi Rizzo * If no classifier updates the field, g_run_classifiers() sets 3496231f75bSLuigi Rizzo * bio_classifier1 = BIO_NOTCLASSIFIED to avoid further calls. 3506231f75bSLuigi Rizzo */ 3516231f75bSLuigi Rizzo 3526231f75bSLuigi Rizzo int 3536231f75bSLuigi Rizzo g_register_classifier(struct g_classifier_hook *hook) 3546231f75bSLuigi Rizzo { 3556231f75bSLuigi Rizzo 3566231f75bSLuigi Rizzo g_bioq_lock(&g_bio_run_down); 3576231f75bSLuigi Rizzo TAILQ_INSERT_TAIL(&g_classifier_tailq, hook, link); 3586231f75bSLuigi Rizzo g_bioq_unlock(&g_bio_run_down); 3596231f75bSLuigi Rizzo 3606231f75bSLuigi Rizzo return (0); 3616231f75bSLuigi Rizzo } 3626231f75bSLuigi Rizzo 3636231f75bSLuigi Rizzo void 3646231f75bSLuigi Rizzo g_unregister_classifier(struct g_classifier_hook *hook) 3656231f75bSLuigi Rizzo { 3666231f75bSLuigi Rizzo struct g_classifier_hook *entry; 3676231f75bSLuigi Rizzo 3686231f75bSLuigi Rizzo g_bioq_lock(&g_bio_run_down); 3696231f75bSLuigi Rizzo TAILQ_FOREACH(entry, &g_classifier_tailq, link) { 3706231f75bSLuigi Rizzo if (entry == hook) { 3716231f75bSLuigi Rizzo TAILQ_REMOVE(&g_classifier_tailq, hook, link); 3726231f75bSLuigi Rizzo break; 3736231f75bSLuigi Rizzo } 3746231f75bSLuigi Rizzo } 3756231f75bSLuigi Rizzo g_bioq_unlock(&g_bio_run_down); 3766231f75bSLuigi Rizzo } 3776231f75bSLuigi Rizzo 3786231f75bSLuigi Rizzo static void 3796231f75bSLuigi Rizzo g_run_classifiers(struct bio *bp) 3806231f75bSLuigi Rizzo { 3816231f75bSLuigi Rizzo struct g_classifier_hook *hook; 3826231f75bSLuigi Rizzo int classified = 0; 3836231f75bSLuigi Rizzo 3846231f75bSLuigi Rizzo TAILQ_FOREACH(hook, &g_classifier_tailq, link) 3856231f75bSLuigi Rizzo classified |= hook->func(hook->arg, bp); 3866231f75bSLuigi Rizzo 3876231f75bSLuigi Rizzo if (!classified) 3886231f75bSLuigi Rizzo bp->bio_classifier1 = BIO_NOTCLASSIFIED; 3896231f75bSLuigi Rizzo } 3906231f75bSLuigi Rizzo 391dd84a43cSPoul-Henning Kamp void 392dd84a43cSPoul-Henning Kamp g_io_request(struct bio *bp, struct g_consumer *cp) 393dd84a43cSPoul-Henning Kamp { 394801bb689SPoul-Henning Kamp struct g_provider *pp; 3950d883b11SAlexander Motin int first; 396dd84a43cSPoul-Henning Kamp 397d0e17c1bSPoul-Henning Kamp KASSERT(cp != NULL, ("NULL cp in g_io_request")); 398d0e17c1bSPoul-Henning Kamp KASSERT(bp != NULL, ("NULL bp in g_io_request")); 399e060b6bdSPoul-Henning Kamp pp = cp->provider; 400801bb689SPoul-Henning Kamp KASSERT(pp != NULL, ("consumer not attached in g_io_request")); 40192ee312dSPawel Jakub Dawidek #ifdef DIAGNOSTIC 40292ee312dSPawel Jakub Dawidek KASSERT(bp->bio_driver1 == NULL, 40392ee312dSPawel Jakub Dawidek ("bio_driver1 used by the consumer (geom %s)", cp->geom->name)); 40492ee312dSPawel Jakub Dawidek KASSERT(bp->bio_driver2 == NULL, 40592ee312dSPawel Jakub Dawidek ("bio_driver2 used by the consumer (geom %s)", cp->geom->name)); 40692ee312dSPawel Jakub Dawidek KASSERT(bp->bio_pflags == 0, 40792ee312dSPawel Jakub Dawidek ("bio_pflags used by the consumer (geom %s)", cp->geom->name)); 40892ee312dSPawel Jakub Dawidek /* 40992ee312dSPawel Jakub Dawidek * Remember consumer's private fields, so we can detect if they were 41092ee312dSPawel Jakub Dawidek * modified by the provider. 41192ee312dSPawel Jakub Dawidek */ 41292ee312dSPawel Jakub Dawidek bp->_bio_caller1 = bp->bio_caller1; 41392ee312dSPawel Jakub Dawidek bp->_bio_caller2 = bp->bio_caller2; 41492ee312dSPawel Jakub Dawidek bp->_bio_cflags = bp->bio_cflags; 41592ee312dSPawel Jakub Dawidek #endif 416801bb689SPoul-Henning Kamp 4171ded77b2SPawel Jakub Dawidek if (bp->bio_cmd & (BIO_READ|BIO_WRITE|BIO_GETATTR)) { 418c3618c65SPawel Jakub Dawidek KASSERT(bp->bio_data != NULL, 4191ded77b2SPawel Jakub Dawidek ("NULL bp->data in g_io_request(cmd=%hhu)", bp->bio_cmd)); 4201ded77b2SPawel Jakub Dawidek } 4211ded77b2SPawel Jakub Dawidek if (bp->bio_cmd & (BIO_DELETE|BIO_FLUSH)) { 4221ded77b2SPawel Jakub Dawidek KASSERT(bp->bio_data == NULL, 4231ded77b2SPawel Jakub Dawidek ("non-NULL bp->data in g_io_request(cmd=%hhu)", 4241ded77b2SPawel Jakub Dawidek bp->bio_cmd)); 425c3618c65SPawel Jakub Dawidek } 426dcbd0fe5SPoul-Henning Kamp if (bp->bio_cmd & (BIO_READ|BIO_WRITE|BIO_DELETE)) { 427dcbd0fe5SPoul-Henning Kamp KASSERT(bp->bio_offset % cp->provider->sectorsize == 0, 428dcbd0fe5SPoul-Henning Kamp ("wrong offset %jd for sectorsize %u", 429dcbd0fe5SPoul-Henning Kamp bp->bio_offset, cp->provider->sectorsize)); 430dcbd0fe5SPoul-Henning Kamp KASSERT(bp->bio_length % cp->provider->sectorsize == 0, 431dcbd0fe5SPoul-Henning Kamp ("wrong length %jd for sectorsize %u", 432dcbd0fe5SPoul-Henning Kamp bp->bio_length, cp->provider->sectorsize)); 433dcbd0fe5SPoul-Henning Kamp } 434dcbd0fe5SPoul-Henning Kamp 435f7717523SStephan Uphoff g_trace(G_T_BIO, "bio_request(%p) from %p(%s) to %p(%s) cmd %d", 436f7717523SStephan Uphoff bp, cp, cp->geom->name, pp, pp->name, bp->bio_cmd); 437f7717523SStephan Uphoff 438dd84a43cSPoul-Henning Kamp bp->bio_from = cp; 439801bb689SPoul-Henning Kamp bp->bio_to = pp; 4402fccec19SPoul-Henning Kamp bp->bio_error = 0; 4412fccec19SPoul-Henning Kamp bp->bio_completed = 0; 442dd84a43cSPoul-Henning Kamp 44319fa21aaSPoul-Henning Kamp KASSERT(!(bp->bio_flags & BIO_ONQUEUE), 44419fa21aaSPoul-Henning Kamp ("Bio already on queue bp=%p", bp)); 44519fa21aaSPoul-Henning Kamp bp->bio_flags |= BIO_ONQUEUE; 44619fa21aaSPoul-Henning Kamp 447a5be8eb5SAlexander Motin if (g_collectstats) 44819fa21aaSPoul-Henning Kamp binuptime(&bp->bio_t0); 449a5be8eb5SAlexander Motin else 450a5be8eb5SAlexander Motin getbinuptime(&bp->bio_t0); 4518827c821SPoul-Henning Kamp 4528827c821SPoul-Henning Kamp /* 4538827c821SPoul-Henning Kamp * The statistics collection is lockless, as such, but we 4548827c821SPoul-Henning Kamp * can not update one instance of the statistics from more 4558827c821SPoul-Henning Kamp * than one thread at a time, so grab the lock first. 4566231f75bSLuigi Rizzo * 4576231f75bSLuigi Rizzo * We also use the lock to protect the list of classifiers. 4588827c821SPoul-Henning Kamp */ 45919fa21aaSPoul-Henning Kamp g_bioq_lock(&g_bio_run_down); 4606231f75bSLuigi Rizzo 4616231f75bSLuigi Rizzo if (!TAILQ_EMPTY(&g_classifier_tailq) && !bp->bio_classifier1) 4626231f75bSLuigi Rizzo g_run_classifiers(bp); 4636231f75bSLuigi Rizzo 464cf457284SPoul-Henning Kamp if (g_collectstats & 1) 46519fa21aaSPoul-Henning Kamp devstat_start_transaction(pp->stat, &bp->bio_t0); 466cf457284SPoul-Henning Kamp if (g_collectstats & 2) 46719fa21aaSPoul-Henning Kamp devstat_start_transaction(cp->stat, &bp->bio_t0); 46819fa21aaSPoul-Henning Kamp 46919fa21aaSPoul-Henning Kamp pp->nstart++; 470cf457284SPoul-Henning Kamp cp->nstart++; 4710d883b11SAlexander Motin first = TAILQ_EMPTY(&g_bio_run_down.bio_queue); 47219fa21aaSPoul-Henning Kamp TAILQ_INSERT_TAIL(&g_bio_run_down.bio_queue, bp, bio_queue); 47319fa21aaSPoul-Henning Kamp g_bio_run_down.bio_queue_length++; 47419fa21aaSPoul-Henning Kamp g_bioq_unlock(&g_bio_run_down); 475e39d70d4SPoul-Henning Kamp 4762fccec19SPoul-Henning Kamp /* Pass it on down. */ 4770d883b11SAlexander Motin if (first) 478dd84a43cSPoul-Henning Kamp wakeup(&g_wait_down); 479dd84a43cSPoul-Henning Kamp } 480dd84a43cSPoul-Henning Kamp 481dd84a43cSPoul-Henning Kamp void 48272840432SPoul-Henning Kamp g_io_deliver(struct bio *bp, int error) 483dd84a43cSPoul-Henning Kamp { 484801bb689SPoul-Henning Kamp struct g_consumer *cp; 485801bb689SPoul-Henning Kamp struct g_provider *pp; 4860d883b11SAlexander Motin int first; 487dd84a43cSPoul-Henning Kamp 488e060b6bdSPoul-Henning Kamp KASSERT(bp != NULL, ("NULL bp in g_io_deliver")); 489801bb689SPoul-Henning Kamp pp = bp->bio_to; 490f7eeab17SPoul-Henning Kamp KASSERT(pp != NULL, ("NULL bio_to in g_io_deliver")); 491f7eeab17SPoul-Henning Kamp cp = bp->bio_from; 492f7eeab17SPoul-Henning Kamp if (cp == NULL) { 493f7eeab17SPoul-Henning Kamp bp->bio_error = error; 494f7eeab17SPoul-Henning Kamp bp->bio_done(bp); 495f7eeab17SPoul-Henning Kamp return; 496f7eeab17SPoul-Henning Kamp } 497801bb689SPoul-Henning Kamp KASSERT(cp != NULL, ("NULL bio_from in g_io_deliver")); 498801bb689SPoul-Henning Kamp KASSERT(cp->geom != NULL, ("NULL bio_from->geom in g_io_deliver")); 499fb231f36SEdward Tomasz Napierala #ifdef DIAGNOSTIC 500fb231f36SEdward Tomasz Napierala /* 501fb231f36SEdward Tomasz Napierala * Some classes - GJournal in particular - can modify bio's 502fb231f36SEdward Tomasz Napierala * private fields while the bio is in transit; G_GEOM_VOLATILE_BIO 503fb231f36SEdward Tomasz Napierala * flag means it's an expected behaviour for that particular geom. 504fb231f36SEdward Tomasz Napierala */ 505fb231f36SEdward Tomasz Napierala if ((cp->geom->flags & G_GEOM_VOLATILE_BIO) == 0) { 506fb231f36SEdward Tomasz Napierala KASSERT(bp->bio_caller1 == bp->_bio_caller1, 507fb231f36SEdward Tomasz Napierala ("bio_caller1 used by the provider %s", pp->name)); 508fb231f36SEdward Tomasz Napierala KASSERT(bp->bio_caller2 == bp->_bio_caller2, 509fb231f36SEdward Tomasz Napierala ("bio_caller2 used by the provider %s", pp->name)); 510fb231f36SEdward Tomasz Napierala KASSERT(bp->bio_cflags == bp->_bio_cflags, 511fb231f36SEdward Tomasz Napierala ("bio_cflags used by the provider %s", pp->name)); 512fb231f36SEdward Tomasz Napierala } 513fb231f36SEdward Tomasz Napierala #endif 51446aeebecSPawel Jakub Dawidek KASSERT(bp->bio_completed >= 0, ("bio_completed can't be less than 0")); 51546aeebecSPawel Jakub Dawidek KASSERT(bp->bio_completed <= bp->bio_length, 51646aeebecSPawel Jakub Dawidek ("bio_completed can't be greater than bio_length")); 5175ab413bfSPoul-Henning Kamp 518dd84a43cSPoul-Henning Kamp g_trace(G_T_BIO, 5190355b86eSPoul-Henning Kamp "g_io_deliver(%p) from %p(%s) to %p(%s) cmd %d error %d off %jd len %jd", 520801bb689SPoul-Henning Kamp bp, cp, cp->geom->name, pp, pp->name, bp->bio_cmd, error, 5210355b86eSPoul-Henning Kamp (intmax_t)bp->bio_offset, (intmax_t)bp->bio_length); 522801bb689SPoul-Henning Kamp 52319fa21aaSPoul-Henning Kamp KASSERT(!(bp->bio_flags & BIO_ONQUEUE), 52419fa21aaSPoul-Henning Kamp ("Bio already on queue bp=%p", bp)); 52519fa21aaSPoul-Henning Kamp 526dcbd0fe5SPoul-Henning Kamp /* 527dcbd0fe5SPoul-Henning Kamp * XXX: next two doesn't belong here 528dcbd0fe5SPoul-Henning Kamp */ 529e24cbd90SPoul-Henning Kamp bp->bio_bcount = bp->bio_length; 530e24cbd90SPoul-Henning Kamp bp->bio_resid = bp->bio_bcount - bp->bio_completed; 53119fa21aaSPoul-Henning Kamp 5328827c821SPoul-Henning Kamp /* 5338827c821SPoul-Henning Kamp * The statistics collection is lockless, as such, but we 5348827c821SPoul-Henning Kamp * can not update one instance of the statistics from more 5358827c821SPoul-Henning Kamp * than one thread at a time, so grab the lock first. 5368827c821SPoul-Henning Kamp */ 53719fa21aaSPoul-Henning Kamp g_bioq_lock(&g_bio_run_up); 538cf457284SPoul-Henning Kamp if (g_collectstats & 1) 539e24cbd90SPoul-Henning Kamp devstat_end_transaction_bio(pp->stat, bp); 540cf457284SPoul-Henning Kamp if (g_collectstats & 2) 541cf457284SPoul-Henning Kamp devstat_end_transaction_bio(cp->stat, bp); 5428827c821SPoul-Henning Kamp 543c6ae9b5fSPoul-Henning Kamp cp->nend++; 544c6ae9b5fSPoul-Henning Kamp pp->nend++; 54519fa21aaSPoul-Henning Kamp if (error != ENOMEM) { 54619fa21aaSPoul-Henning Kamp bp->bio_error = error; 5470d883b11SAlexander Motin first = TAILQ_EMPTY(&g_bio_run_up.bio_queue); 54819fa21aaSPoul-Henning Kamp TAILQ_INSERT_TAIL(&g_bio_run_up.bio_queue, bp, bio_queue); 549276f72c5SPoul-Henning Kamp bp->bio_flags |= BIO_ONQUEUE; 55019fa21aaSPoul-Henning Kamp g_bio_run_up.bio_queue_length++; 55119fa21aaSPoul-Henning Kamp g_bioq_unlock(&g_bio_run_up); 5520d883b11SAlexander Motin if (first) 55319fa21aaSPoul-Henning Kamp wakeup(&g_wait_up); 55419fa21aaSPoul-Henning Kamp return; 55519fa21aaSPoul-Henning Kamp } 55619fa21aaSPoul-Henning Kamp g_bioq_unlock(&g_bio_run_up); 557dd84a43cSPoul-Henning Kamp 5582cc9686eSPoul-Henning Kamp if (bootverbose) 559801bb689SPoul-Henning Kamp printf("ENOMEM %p on %p(%s)\n", bp, pp, pp->name); 5601b949c05SPawel Jakub Dawidek bp->bio_children = 0; 5611b949c05SPawel Jakub Dawidek bp->bio_inbed = 0; 562801bb689SPoul-Henning Kamp g_io_request(bp, cp); 5633432e4fdSPoul-Henning Kamp pace++; 5643432e4fdSPoul-Henning Kamp return; 5653432e4fdSPoul-Henning Kamp } 566dd84a43cSPoul-Henning Kamp 567dd84a43cSPoul-Henning Kamp void 568dd84a43cSPoul-Henning Kamp g_io_schedule_down(struct thread *tp __unused) 569dd84a43cSPoul-Henning Kamp { 570dd84a43cSPoul-Henning Kamp struct bio *bp; 571e39d70d4SPoul-Henning Kamp off_t excess; 572e39d70d4SPoul-Henning Kamp int error; 573dd84a43cSPoul-Henning Kamp 574dd84a43cSPoul-Henning Kamp for(;;) { 575f0e185d7SPoul-Henning Kamp g_bioq_lock(&g_bio_run_down); 576dd84a43cSPoul-Henning Kamp bp = g_bioq_first(&g_bio_run_down); 577f0e185d7SPoul-Henning Kamp if (bp == NULL) { 57849dbb61dSRobert Watson CTR0(KTR_GEOM, "g_down going to sleep"); 579f0e185d7SPoul-Henning Kamp msleep(&g_wait_down, &g_bio_run_down.bio_queue_lock, 5807fc019afSAlexander Motin PRIBIO | PDROP, "-", 0); 581f0e185d7SPoul-Henning Kamp continue; 582f0e185d7SPoul-Henning Kamp } 58349dbb61dSRobert Watson CTR0(KTR_GEOM, "g_down has work to do"); 584f0e185d7SPoul-Henning Kamp g_bioq_unlock(&g_bio_run_down); 585376ceb79SPoul-Henning Kamp if (pace > 0) { 58649dbb61dSRobert Watson CTR1(KTR_GEOM, "g_down pacing self (pace %d)", pace); 5874d70511aSJohn Baldwin pause("g_down", hz/10); 588376ceb79SPoul-Henning Kamp pace--; 589376ceb79SPoul-Henning Kamp } 590e39d70d4SPoul-Henning Kamp error = g_io_check(bp); 591e39d70d4SPoul-Henning Kamp if (error) { 59249dbb61dSRobert Watson CTR3(KTR_GEOM, "g_down g_io_check on bp %p provider " 59349dbb61dSRobert Watson "%s returned %d", bp, bp->bio_to->name, error); 594e39d70d4SPoul-Henning Kamp g_io_deliver(bp, error); 595e39d70d4SPoul-Henning Kamp continue; 596e39d70d4SPoul-Henning Kamp } 59749dbb61dSRobert Watson CTR2(KTR_GEOM, "g_down processing bp %p provider %s", bp, 59849dbb61dSRobert Watson bp->bio_to->name); 599392d56b4SPoul-Henning Kamp switch (bp->bio_cmd) { 600392d56b4SPoul-Henning Kamp case BIO_READ: 601392d56b4SPoul-Henning Kamp case BIO_WRITE: 602392d56b4SPoul-Henning Kamp case BIO_DELETE: 603e39d70d4SPoul-Henning Kamp /* Truncate requests to the end of providers media. */ 60449dbb61dSRobert Watson /* 60549dbb61dSRobert Watson * XXX: What if we truncate because of offset being 60649dbb61dSRobert Watson * bad, not length? 60749dbb61dSRobert Watson */ 608e39d70d4SPoul-Henning Kamp excess = bp->bio_offset + bp->bio_length; 609e39d70d4SPoul-Henning Kamp if (excess > bp->bio_to->mediasize) { 610e39d70d4SPoul-Henning Kamp excess -= bp->bio_to->mediasize; 611e39d70d4SPoul-Henning Kamp bp->bio_length -= excess; 61249dbb61dSRobert Watson if (excess > 0) 61349dbb61dSRobert Watson CTR3(KTR_GEOM, "g_down truncated bio " 61449dbb61dSRobert Watson "%p provider %s by %d", bp, 61549dbb61dSRobert Watson bp->bio_to->name, excess); 616e39d70d4SPoul-Henning Kamp } 617e39d70d4SPoul-Henning Kamp /* Deliver zero length transfers right here. */ 618e39d70d4SPoul-Henning Kamp if (bp->bio_length == 0) { 619e39d70d4SPoul-Henning Kamp g_io_deliver(bp, 0); 62049dbb61dSRobert Watson CTR2(KTR_GEOM, "g_down terminated 0-length " 62149dbb61dSRobert Watson "bp %p provider %s", bp, bp->bio_to->name); 622e39d70d4SPoul-Henning Kamp continue; 623e39d70d4SPoul-Henning Kamp } 624392d56b4SPoul-Henning Kamp break; 625392d56b4SPoul-Henning Kamp default: 626392d56b4SPoul-Henning Kamp break; 627392d56b4SPoul-Henning Kamp } 62851460da8SJohn Baldwin THREAD_NO_SLEEPING(); 62949dbb61dSRobert Watson CTR4(KTR_GEOM, "g_down starting bp %p provider %s off %ld " 63049dbb61dSRobert Watson "len %ld", bp, bp->bio_to->name, bp->bio_offset, 63149dbb61dSRobert Watson bp->bio_length); 632dd84a43cSPoul-Henning Kamp bp->bio_to->geom->start(bp); 63351460da8SJohn Baldwin THREAD_SLEEPING_OK(); 634dd84a43cSPoul-Henning Kamp } 635dd84a43cSPoul-Henning Kamp } 636dd84a43cSPoul-Henning Kamp 637dd84a43cSPoul-Henning Kamp void 6385fcf4e43SPoul-Henning Kamp bio_taskqueue(struct bio *bp, bio_task_t *func, void *arg) 6395fcf4e43SPoul-Henning Kamp { 6405fcf4e43SPoul-Henning Kamp bp->bio_task = func; 6415fcf4e43SPoul-Henning Kamp bp->bio_task_arg = arg; 6425fcf4e43SPoul-Henning Kamp /* 6435fcf4e43SPoul-Henning Kamp * The taskqueue is actually just a second queue off the "up" 6445fcf4e43SPoul-Henning Kamp * queue, so we use the same lock. 6455fcf4e43SPoul-Henning Kamp */ 6465fcf4e43SPoul-Henning Kamp g_bioq_lock(&g_bio_run_up); 647dcbd0fe5SPoul-Henning Kamp KASSERT(!(bp->bio_flags & BIO_ONQUEUE), 648dcbd0fe5SPoul-Henning Kamp ("Bio already on queue bp=%p target taskq", bp)); 649dcbd0fe5SPoul-Henning Kamp bp->bio_flags |= BIO_ONQUEUE; 6505fcf4e43SPoul-Henning Kamp TAILQ_INSERT_TAIL(&g_bio_run_task.bio_queue, bp, bio_queue); 6515fcf4e43SPoul-Henning Kamp g_bio_run_task.bio_queue_length++; 6525fcf4e43SPoul-Henning Kamp wakeup(&g_wait_up); 6535fcf4e43SPoul-Henning Kamp g_bioq_unlock(&g_bio_run_up); 6545fcf4e43SPoul-Henning Kamp } 6555fcf4e43SPoul-Henning Kamp 6565fcf4e43SPoul-Henning Kamp 6575fcf4e43SPoul-Henning Kamp void 658dd84a43cSPoul-Henning Kamp g_io_schedule_up(struct thread *tp __unused) 659dd84a43cSPoul-Henning Kamp { 660dd84a43cSPoul-Henning Kamp struct bio *bp; 661dd84a43cSPoul-Henning Kamp for(;;) { 662f0e185d7SPoul-Henning Kamp g_bioq_lock(&g_bio_run_up); 6635fcf4e43SPoul-Henning Kamp bp = g_bioq_first(&g_bio_run_task); 6645fcf4e43SPoul-Henning Kamp if (bp != NULL) { 6655fcf4e43SPoul-Henning Kamp g_bioq_unlock(&g_bio_run_up); 66651460da8SJohn Baldwin THREAD_NO_SLEEPING(); 66749dbb61dSRobert Watson CTR1(KTR_GEOM, "g_up processing task bp %p", bp); 6685fcf4e43SPoul-Henning Kamp bp->bio_task(bp->bio_task_arg); 66951460da8SJohn Baldwin THREAD_SLEEPING_OK(); 6705fcf4e43SPoul-Henning Kamp continue; 6715fcf4e43SPoul-Henning Kamp } 672dd84a43cSPoul-Henning Kamp bp = g_bioq_first(&g_bio_run_up); 673f0e185d7SPoul-Henning Kamp if (bp != NULL) { 674f0e185d7SPoul-Henning Kamp g_bioq_unlock(&g_bio_run_up); 67551460da8SJohn Baldwin THREAD_NO_SLEEPING(); 67649dbb61dSRobert Watson CTR4(KTR_GEOM, "g_up biodone bp %p provider %s off " 677c4901b67SSean Bruno "%jd len %ld", bp, bp->bio_to->name, 67849dbb61dSRobert Watson bp->bio_offset, bp->bio_length); 67953706245SPoul-Henning Kamp biodone(bp); 68051460da8SJohn Baldwin THREAD_SLEEPING_OK(); 681f0e185d7SPoul-Henning Kamp continue; 682f0e185d7SPoul-Henning Kamp } 68349dbb61dSRobert Watson CTR0(KTR_GEOM, "g_up going to sleep"); 684f0e185d7SPoul-Henning Kamp msleep(&g_wait_up, &g_bio_run_up.bio_queue_lock, 6857fc019afSAlexander Motin PRIBIO | PDROP, "-", 0); 686dd84a43cSPoul-Henning Kamp } 687dd84a43cSPoul-Henning Kamp } 688dd84a43cSPoul-Henning Kamp 689dd84a43cSPoul-Henning Kamp void * 690dd84a43cSPoul-Henning Kamp g_read_data(struct g_consumer *cp, off_t offset, off_t length, int *error) 691dd84a43cSPoul-Henning Kamp { 692dd84a43cSPoul-Henning Kamp struct bio *bp; 693dd84a43cSPoul-Henning Kamp void *ptr; 694dd84a43cSPoul-Henning Kamp int errorc; 695dd84a43cSPoul-Henning Kamp 6968dd5480dSPawel Jakub Dawidek KASSERT(length > 0 && length >= cp->provider->sectorsize && 6978dd5480dSPawel Jakub Dawidek length <= MAXPHYS, ("g_read_data(): invalid length %jd", 6988dd5480dSPawel Jakub Dawidek (intmax_t)length)); 6993eb6ffdfSPoul-Henning Kamp 700a2033c96SPoul-Henning Kamp bp = g_alloc_bio(); 701dd84a43cSPoul-Henning Kamp bp->bio_cmd = BIO_READ; 702dd84a43cSPoul-Henning Kamp bp->bio_done = NULL; 703dd84a43cSPoul-Henning Kamp bp->bio_offset = offset; 704dd84a43cSPoul-Henning Kamp bp->bio_length = length; 705a163d034SWarner Losh ptr = g_malloc(length, M_WAITOK); 706dd84a43cSPoul-Henning Kamp bp->bio_data = ptr; 707dd84a43cSPoul-Henning Kamp g_io_request(bp, cp); 70853706245SPoul-Henning Kamp errorc = biowait(bp, "gread"); 709dd84a43cSPoul-Henning Kamp if (error != NULL) 710dd84a43cSPoul-Henning Kamp *error = errorc; 711dd84a43cSPoul-Henning Kamp g_destroy_bio(bp); 712dd84a43cSPoul-Henning Kamp if (errorc) { 713dd84a43cSPoul-Henning Kamp g_free(ptr); 714dd84a43cSPoul-Henning Kamp ptr = NULL; 715dd84a43cSPoul-Henning Kamp } 716dd84a43cSPoul-Henning Kamp return (ptr); 717dd84a43cSPoul-Henning Kamp } 71890b1cd56SPoul-Henning Kamp 71990b1cd56SPoul-Henning Kamp int 72090b1cd56SPoul-Henning Kamp g_write_data(struct g_consumer *cp, off_t offset, void *ptr, off_t length) 72190b1cd56SPoul-Henning Kamp { 72290b1cd56SPoul-Henning Kamp struct bio *bp; 72390b1cd56SPoul-Henning Kamp int error; 72490b1cd56SPoul-Henning Kamp 7258dd5480dSPawel Jakub Dawidek KASSERT(length > 0 && length >= cp->provider->sectorsize && 7268dd5480dSPawel Jakub Dawidek length <= MAXPHYS, ("g_write_data(): invalid length %jd", 7278dd5480dSPawel Jakub Dawidek (intmax_t)length)); 7283eb6ffdfSPoul-Henning Kamp 729a2033c96SPoul-Henning Kamp bp = g_alloc_bio(); 73090b1cd56SPoul-Henning Kamp bp->bio_cmd = BIO_WRITE; 73190b1cd56SPoul-Henning Kamp bp->bio_done = NULL; 73290b1cd56SPoul-Henning Kamp bp->bio_offset = offset; 73390b1cd56SPoul-Henning Kamp bp->bio_length = length; 73490b1cd56SPoul-Henning Kamp bp->bio_data = ptr; 73590b1cd56SPoul-Henning Kamp g_io_request(bp, cp); 73690b1cd56SPoul-Henning Kamp error = biowait(bp, "gwrite"); 73790b1cd56SPoul-Henning Kamp g_destroy_bio(bp); 73890b1cd56SPoul-Henning Kamp return (error); 73990b1cd56SPoul-Henning Kamp } 74072e33095SPawel Jakub Dawidek 7412b17fb95SPawel Jakub Dawidek int 7422b17fb95SPawel Jakub Dawidek g_delete_data(struct g_consumer *cp, off_t offset, off_t length) 7432b17fb95SPawel Jakub Dawidek { 7442b17fb95SPawel Jakub Dawidek struct bio *bp; 7452b17fb95SPawel Jakub Dawidek int error; 7462b17fb95SPawel Jakub Dawidek 747eed6cda9SPoul-Henning Kamp KASSERT(length > 0 && length >= cp->provider->sectorsize, 748eed6cda9SPoul-Henning Kamp ("g_delete_data(): invalid length %jd", (intmax_t)length)); 7492b17fb95SPawel Jakub Dawidek 7502b17fb95SPawel Jakub Dawidek bp = g_alloc_bio(); 7512b17fb95SPawel Jakub Dawidek bp->bio_cmd = BIO_DELETE; 7522b17fb95SPawel Jakub Dawidek bp->bio_done = NULL; 7532b17fb95SPawel Jakub Dawidek bp->bio_offset = offset; 7542b17fb95SPawel Jakub Dawidek bp->bio_length = length; 7552b17fb95SPawel Jakub Dawidek bp->bio_data = NULL; 7562b17fb95SPawel Jakub Dawidek g_io_request(bp, cp); 7572b17fb95SPawel Jakub Dawidek error = biowait(bp, "gdelete"); 7582b17fb95SPawel Jakub Dawidek g_destroy_bio(bp); 7592b17fb95SPawel Jakub Dawidek return (error); 7602b17fb95SPawel Jakub Dawidek } 7612b17fb95SPawel Jakub Dawidek 76272e33095SPawel Jakub Dawidek void 76372e33095SPawel Jakub Dawidek g_print_bio(struct bio *bp) 76472e33095SPawel Jakub Dawidek { 76572e33095SPawel Jakub Dawidek const char *pname, *cmd = NULL; 76672e33095SPawel Jakub Dawidek 76772e33095SPawel Jakub Dawidek if (bp->bio_to != NULL) 76872e33095SPawel Jakub Dawidek pname = bp->bio_to->name; 76972e33095SPawel Jakub Dawidek else 77072e33095SPawel Jakub Dawidek pname = "[unknown]"; 77172e33095SPawel Jakub Dawidek 77272e33095SPawel Jakub Dawidek switch (bp->bio_cmd) { 77372e33095SPawel Jakub Dawidek case BIO_GETATTR: 77472e33095SPawel Jakub Dawidek cmd = "GETATTR"; 77572e33095SPawel Jakub Dawidek printf("%s[%s(attr=%s)]", pname, cmd, bp->bio_attribute); 77672e33095SPawel Jakub Dawidek return; 777c3618c65SPawel Jakub Dawidek case BIO_FLUSH: 778c3618c65SPawel Jakub Dawidek cmd = "FLUSH"; 779c3618c65SPawel Jakub Dawidek printf("%s[%s]", pname, cmd); 780c3618c65SPawel Jakub Dawidek return; 78172e33095SPawel Jakub Dawidek case BIO_READ: 78272e33095SPawel Jakub Dawidek cmd = "READ"; 7837ce513a5SEdward Tomasz Napierala break; 78472e33095SPawel Jakub Dawidek case BIO_WRITE: 78572e33095SPawel Jakub Dawidek cmd = "WRITE"; 7867ce513a5SEdward Tomasz Napierala break; 78772e33095SPawel Jakub Dawidek case BIO_DELETE: 78872e33095SPawel Jakub Dawidek cmd = "DELETE"; 7897ce513a5SEdward Tomasz Napierala break; 79072e33095SPawel Jakub Dawidek default: 79172e33095SPawel Jakub Dawidek cmd = "UNKNOWN"; 79272e33095SPawel Jakub Dawidek printf("%s[%s()]", pname, cmd); 79372e33095SPawel Jakub Dawidek return; 79472e33095SPawel Jakub Dawidek } 7957ce513a5SEdward Tomasz Napierala printf("%s[%s(offset=%jd, length=%jd)]", pname, cmd, 7967ce513a5SEdward Tomasz Napierala (intmax_t)bp->bio_offset, (intmax_t)bp->bio_length); 79772e33095SPawel Jakub Dawidek } 798