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 * $FreeBSD$ 36dd84a43cSPoul-Henning Kamp */ 37dd84a43cSPoul-Henning Kamp 38dd84a43cSPoul-Henning Kamp 39dd84a43cSPoul-Henning Kamp #include <sys/param.h> 40dd84a43cSPoul-Henning Kamp #ifndef _KERNEL 41dd84a43cSPoul-Henning Kamp #include <stdio.h> 42dd84a43cSPoul-Henning Kamp #include <string.h> 43dd84a43cSPoul-Henning Kamp #include <stdlib.h> 44dd84a43cSPoul-Henning Kamp #include <signal.h> 45dd84a43cSPoul-Henning Kamp #include <err.h> 46dd84a43cSPoul-Henning Kamp #include <sched.h> 47dd84a43cSPoul-Henning Kamp #else 48dd84a43cSPoul-Henning Kamp #include <sys/systm.h> 49dd84a43cSPoul-Henning Kamp #include <sys/kernel.h> 50dd84a43cSPoul-Henning Kamp #include <sys/malloc.h> 51dd84a43cSPoul-Henning Kamp #include <sys/bio.h> 52dd84a43cSPoul-Henning Kamp #endif 53dd84a43cSPoul-Henning Kamp 54dd84a43cSPoul-Henning Kamp #include <sys/errno.h> 55dd84a43cSPoul-Henning Kamp #include <geom/geom.h> 56b1876192SPoul-Henning Kamp #include <geom/geom_int.h> 57e24cbd90SPoul-Henning Kamp #include <sys/devicestat.h> 58dd84a43cSPoul-Henning Kamp 59dd84a43cSPoul-Henning Kamp static struct g_bioq g_bio_run_down; 60dd84a43cSPoul-Henning Kamp static struct g_bioq g_bio_run_up; 61f0e185d7SPoul-Henning Kamp static struct g_bioq g_bio_run_task; 62dd84a43cSPoul-Henning Kamp static struct g_bioq g_bio_idle; 63dd84a43cSPoul-Henning Kamp 643432e4fdSPoul-Henning Kamp static u_int pace; 653432e4fdSPoul-Henning Kamp 66dd84a43cSPoul-Henning Kamp #include <machine/atomic.h> 67dd84a43cSPoul-Henning Kamp 68dd84a43cSPoul-Henning Kamp static void 69dd84a43cSPoul-Henning Kamp g_bioq_lock(struct g_bioq *bq) 70dd84a43cSPoul-Henning Kamp { 71dd84a43cSPoul-Henning Kamp 72dd84a43cSPoul-Henning Kamp mtx_lock(&bq->bio_queue_lock); 73dd84a43cSPoul-Henning Kamp } 74dd84a43cSPoul-Henning Kamp 75dd84a43cSPoul-Henning Kamp static void 76dd84a43cSPoul-Henning Kamp g_bioq_unlock(struct g_bioq *bq) 77dd84a43cSPoul-Henning Kamp { 78dd84a43cSPoul-Henning Kamp 79dd84a43cSPoul-Henning Kamp mtx_unlock(&bq->bio_queue_lock); 80dd84a43cSPoul-Henning Kamp } 81dd84a43cSPoul-Henning Kamp 82dd84a43cSPoul-Henning Kamp #if 0 83dd84a43cSPoul-Henning Kamp static void 84dd84a43cSPoul-Henning Kamp g_bioq_destroy(struct g_bioq *bq) 85dd84a43cSPoul-Henning Kamp { 86dd84a43cSPoul-Henning Kamp 87dd84a43cSPoul-Henning Kamp mtx_destroy(&bq->bio_queue_lock); 88dd84a43cSPoul-Henning Kamp } 89dd84a43cSPoul-Henning Kamp #endif 90dd84a43cSPoul-Henning Kamp 91dd84a43cSPoul-Henning Kamp static void 92dd84a43cSPoul-Henning Kamp g_bioq_init(struct g_bioq *bq) 93dd84a43cSPoul-Henning Kamp { 94dd84a43cSPoul-Henning Kamp 95dd84a43cSPoul-Henning Kamp TAILQ_INIT(&bq->bio_queue); 966008862bSJohn Baldwin mtx_init(&bq->bio_queue_lock, "bio queue", NULL, MTX_DEF); 97dd84a43cSPoul-Henning Kamp } 98dd84a43cSPoul-Henning Kamp 99dd84a43cSPoul-Henning Kamp static struct bio * 100dd84a43cSPoul-Henning Kamp g_bioq_first(struct g_bioq *bq) 101dd84a43cSPoul-Henning Kamp { 102dd84a43cSPoul-Henning Kamp struct bio *bp; 103dd84a43cSPoul-Henning Kamp 104dd84a43cSPoul-Henning Kamp bp = TAILQ_FIRST(&bq->bio_queue); 105dd84a43cSPoul-Henning Kamp if (bp != NULL) { 106dd84a43cSPoul-Henning Kamp TAILQ_REMOVE(&bq->bio_queue, bp, bio_queue); 107dd84a43cSPoul-Henning Kamp bq->bio_queue_length--; 108dd84a43cSPoul-Henning Kamp } 109dd84a43cSPoul-Henning Kamp return (bp); 110dd84a43cSPoul-Henning Kamp } 111dd84a43cSPoul-Henning Kamp 112dd84a43cSPoul-Henning Kamp static void 113dd84a43cSPoul-Henning Kamp g_bioq_enqueue_tail(struct bio *bp, struct g_bioq *rq) 114dd84a43cSPoul-Henning Kamp { 115dd84a43cSPoul-Henning Kamp 116dd84a43cSPoul-Henning Kamp g_bioq_lock(rq); 117dd84a43cSPoul-Henning Kamp TAILQ_INSERT_TAIL(&rq->bio_queue, bp, bio_queue); 118dd84a43cSPoul-Henning Kamp rq->bio_queue_length++; 119dd84a43cSPoul-Henning Kamp g_bioq_unlock(rq); 120dd84a43cSPoul-Henning Kamp } 121dd84a43cSPoul-Henning Kamp 122dd84a43cSPoul-Henning Kamp struct bio * 123dd84a43cSPoul-Henning Kamp g_new_bio(void) 124dd84a43cSPoul-Henning Kamp { 125dd84a43cSPoul-Henning Kamp struct bio *bp; 126dd84a43cSPoul-Henning Kamp 127f0e185d7SPoul-Henning Kamp g_bioq_lock(&g_bio_idle); 128dd84a43cSPoul-Henning Kamp bp = g_bioq_first(&g_bio_idle); 129f0e185d7SPoul-Henning Kamp g_bioq_unlock(&g_bio_idle); 130dd84a43cSPoul-Henning Kamp if (bp == NULL) 131a1bd3ee2SPoul-Henning Kamp bp = g_malloc(sizeof *bp, M_NOWAIT | M_ZERO); 1320355b86eSPoul-Henning Kamp /* g_trace(G_T_BIO, "g_new_bio() = %p", bp); */ 133dd84a43cSPoul-Henning Kamp return (bp); 134dd84a43cSPoul-Henning Kamp } 135dd84a43cSPoul-Henning Kamp 136dd84a43cSPoul-Henning Kamp void 137dd84a43cSPoul-Henning Kamp g_destroy_bio(struct bio *bp) 138dd84a43cSPoul-Henning Kamp { 139dd84a43cSPoul-Henning Kamp 1400355b86eSPoul-Henning Kamp /* g_trace(G_T_BIO, "g_destroy_bio(%p)", bp); */ 141dd84a43cSPoul-Henning Kamp bzero(bp, sizeof *bp); 142dd84a43cSPoul-Henning Kamp g_bioq_enqueue_tail(bp, &g_bio_idle); 143dd84a43cSPoul-Henning Kamp } 144dd84a43cSPoul-Henning Kamp 145dd84a43cSPoul-Henning Kamp struct bio * 146dd84a43cSPoul-Henning Kamp g_clone_bio(struct bio *bp) 147dd84a43cSPoul-Henning Kamp { 148dd84a43cSPoul-Henning Kamp struct bio *bp2; 149dd84a43cSPoul-Henning Kamp 150dd84a43cSPoul-Henning Kamp bp2 = g_new_bio(); 151a1bd3ee2SPoul-Henning Kamp if (bp2 != NULL) { 152936cc461SPoul-Henning Kamp bp2->bio_parent = bp; 153dd84a43cSPoul-Henning Kamp bp2->bio_cmd = bp->bio_cmd; 154dd84a43cSPoul-Henning Kamp bp2->bio_length = bp->bio_length; 155dd84a43cSPoul-Henning Kamp bp2->bio_offset = bp->bio_offset; 156dd84a43cSPoul-Henning Kamp bp2->bio_data = bp->bio_data; 157dd84a43cSPoul-Henning Kamp bp2->bio_attribute = bp->bio_attribute; 158801bb689SPoul-Henning Kamp bp->bio_children++; 159a1bd3ee2SPoul-Henning Kamp } 1600355b86eSPoul-Henning Kamp /* g_trace(G_T_BIO, "g_clone_bio(%p) = %p", bp, bp2); */ 161dd84a43cSPoul-Henning Kamp return(bp2); 162dd84a43cSPoul-Henning Kamp } 163dd84a43cSPoul-Henning Kamp 164dd84a43cSPoul-Henning Kamp void 165dd84a43cSPoul-Henning Kamp g_io_init() 166dd84a43cSPoul-Henning Kamp { 167dd84a43cSPoul-Henning Kamp 168dd84a43cSPoul-Henning Kamp g_bioq_init(&g_bio_run_down); 169dd84a43cSPoul-Henning Kamp g_bioq_init(&g_bio_run_up); 170f0e185d7SPoul-Henning Kamp g_bioq_init(&g_bio_run_task); 171dd84a43cSPoul-Henning Kamp g_bioq_init(&g_bio_idle); 172dd84a43cSPoul-Henning Kamp } 173dd84a43cSPoul-Henning Kamp 174dd84a43cSPoul-Henning Kamp int 1750d3f37a8SPoul-Henning Kamp g_io_setattr(const char *attr, struct g_consumer *cp, int len, void *ptr) 176dd84a43cSPoul-Henning Kamp { 177dd84a43cSPoul-Henning Kamp struct bio *bp; 178dd84a43cSPoul-Henning Kamp int error; 179dd84a43cSPoul-Henning Kamp 180dd84a43cSPoul-Henning Kamp g_trace(G_T_BIO, "bio_setattr(%s)", attr); 181dd84a43cSPoul-Henning Kamp bp = g_new_bio(); 182dd84a43cSPoul-Henning Kamp bp->bio_cmd = BIO_SETATTR; 183dd84a43cSPoul-Henning Kamp bp->bio_done = NULL; 184dd84a43cSPoul-Henning Kamp bp->bio_attribute = attr; 185dd84a43cSPoul-Henning Kamp bp->bio_length = len; 186dd84a43cSPoul-Henning Kamp bp->bio_data = ptr; 187dd84a43cSPoul-Henning Kamp g_io_request(bp, cp); 18853706245SPoul-Henning Kamp error = biowait(bp, "gsetattr"); 189dd84a43cSPoul-Henning Kamp g_destroy_bio(bp); 190dd84a43cSPoul-Henning Kamp return (error); 191dd84a43cSPoul-Henning Kamp } 192dd84a43cSPoul-Henning Kamp 193dd84a43cSPoul-Henning Kamp 194dd84a43cSPoul-Henning Kamp int 1950d3f37a8SPoul-Henning Kamp g_io_getattr(const char *attr, struct g_consumer *cp, int *len, void *ptr) 196dd84a43cSPoul-Henning Kamp { 197dd84a43cSPoul-Henning Kamp struct bio *bp; 198dd84a43cSPoul-Henning Kamp int error; 199dd84a43cSPoul-Henning Kamp 200dd84a43cSPoul-Henning Kamp g_trace(G_T_BIO, "bio_getattr(%s)", attr); 201dd84a43cSPoul-Henning Kamp bp = g_new_bio(); 202dd84a43cSPoul-Henning Kamp bp->bio_cmd = BIO_GETATTR; 203dd84a43cSPoul-Henning Kamp bp->bio_done = NULL; 204dd84a43cSPoul-Henning Kamp bp->bio_attribute = attr; 205dd84a43cSPoul-Henning Kamp bp->bio_length = *len; 206dd84a43cSPoul-Henning Kamp bp->bio_data = ptr; 207dd84a43cSPoul-Henning Kamp g_io_request(bp, cp); 20853706245SPoul-Henning Kamp error = biowait(bp, "ggetattr"); 209dd84a43cSPoul-Henning Kamp *len = bp->bio_completed; 210dd84a43cSPoul-Henning Kamp g_destroy_bio(bp); 211dd84a43cSPoul-Henning Kamp return (error); 212dd84a43cSPoul-Henning Kamp } 213dd84a43cSPoul-Henning Kamp 214e39d70d4SPoul-Henning Kamp static int 215e39d70d4SPoul-Henning Kamp g_io_check(struct bio *bp) 216e39d70d4SPoul-Henning Kamp { 217e39d70d4SPoul-Henning Kamp struct g_consumer *cp; 218e39d70d4SPoul-Henning Kamp struct g_provider *pp; 219e39d70d4SPoul-Henning Kamp 220e39d70d4SPoul-Henning Kamp cp = bp->bio_from; 221e39d70d4SPoul-Henning Kamp pp = bp->bio_to; 222e39d70d4SPoul-Henning Kamp 223e39d70d4SPoul-Henning Kamp /* Fail if access counters dont allow the operation */ 224e39d70d4SPoul-Henning Kamp switch(bp->bio_cmd) { 225e39d70d4SPoul-Henning Kamp case BIO_READ: 226e39d70d4SPoul-Henning Kamp case BIO_GETATTR: 227e39d70d4SPoul-Henning Kamp if (cp->acr == 0) 228e39d70d4SPoul-Henning Kamp return (EPERM); 229e39d70d4SPoul-Henning Kamp break; 230e39d70d4SPoul-Henning Kamp case BIO_WRITE: 231e39d70d4SPoul-Henning Kamp case BIO_DELETE: 232e39d70d4SPoul-Henning Kamp case BIO_SETATTR: 233e39d70d4SPoul-Henning Kamp if (cp->acw == 0) 234e39d70d4SPoul-Henning Kamp return (EPERM); 235e39d70d4SPoul-Henning Kamp break; 236e39d70d4SPoul-Henning Kamp default: 237e39d70d4SPoul-Henning Kamp return (EPERM); 238e39d70d4SPoul-Henning Kamp } 239e39d70d4SPoul-Henning Kamp /* if provider is marked for error, don't disturb. */ 240e39d70d4SPoul-Henning Kamp if (pp->error) 241e39d70d4SPoul-Henning Kamp return (pp->error); 242e39d70d4SPoul-Henning Kamp 243e39d70d4SPoul-Henning Kamp switch(bp->bio_cmd) { 244e39d70d4SPoul-Henning Kamp case BIO_READ: 245e39d70d4SPoul-Henning Kamp case BIO_WRITE: 246e39d70d4SPoul-Henning Kamp case BIO_DELETE: 247e39d70d4SPoul-Henning Kamp /* Reject I/O not on sector boundary */ 248e39d70d4SPoul-Henning Kamp if (bp->bio_offset % pp->sectorsize) 249e39d70d4SPoul-Henning Kamp return (EINVAL); 250e39d70d4SPoul-Henning Kamp /* Reject I/O not integral sector long */ 251e39d70d4SPoul-Henning Kamp if (bp->bio_length % pp->sectorsize) 252e39d70d4SPoul-Henning Kamp return (EINVAL); 253e39d70d4SPoul-Henning Kamp /* Reject requests past the end of media. */ 254e39d70d4SPoul-Henning Kamp if (bp->bio_offset > pp->mediasize) 255e39d70d4SPoul-Henning Kamp return (EIO); 256e39d70d4SPoul-Henning Kamp break; 257e39d70d4SPoul-Henning Kamp default: 258e39d70d4SPoul-Henning Kamp break; 259e39d70d4SPoul-Henning Kamp } 260e39d70d4SPoul-Henning Kamp return (0); 261e39d70d4SPoul-Henning Kamp } 262e39d70d4SPoul-Henning Kamp 263dd84a43cSPoul-Henning Kamp void 264dd84a43cSPoul-Henning Kamp g_io_request(struct bio *bp, struct g_consumer *cp) 265dd84a43cSPoul-Henning Kamp { 266801bb689SPoul-Henning Kamp struct g_provider *pp; 267dd84a43cSPoul-Henning Kamp 268801bb689SPoul-Henning Kamp pp = cp->provider; 269d0e17c1bSPoul-Henning Kamp KASSERT(cp != NULL, ("NULL cp in g_io_request")); 270d0e17c1bSPoul-Henning Kamp KASSERT(bp != NULL, ("NULL bp in g_io_request")); 271d0e17c1bSPoul-Henning Kamp KASSERT(bp->bio_data != NULL, ("NULL bp->data in g_io_request")); 272801bb689SPoul-Henning Kamp KASSERT(pp != NULL, ("consumer not attached in g_io_request")); 273801bb689SPoul-Henning Kamp 274dd84a43cSPoul-Henning Kamp bp->bio_from = cp; 275801bb689SPoul-Henning Kamp bp->bio_to = pp; 2762fccec19SPoul-Henning Kamp bp->bio_error = 0; 2772fccec19SPoul-Henning Kamp bp->bio_completed = 0; 278dd84a43cSPoul-Henning Kamp 279801bb689SPoul-Henning Kamp if (g_collectstats) { 280e24cbd90SPoul-Henning Kamp devstat_start_transaction_bio(cp->stat, bp); 281e24cbd90SPoul-Henning Kamp devstat_start_transaction_bio(pp->stat, bp); 282c6ae9b5fSPoul-Henning Kamp } 283c6ae9b5fSPoul-Henning Kamp cp->nstart++; 284c6ae9b5fSPoul-Henning Kamp pp->nstart++; 285e39d70d4SPoul-Henning Kamp 2862fccec19SPoul-Henning Kamp /* Pass it on down. */ 287dd84a43cSPoul-Henning Kamp g_trace(G_T_BIO, "bio_request(%p) from %p(%s) to %p(%s) cmd %d", 288801bb689SPoul-Henning Kamp bp, cp, cp->geom->name, pp, pp->name, bp->bio_cmd); 289dd84a43cSPoul-Henning Kamp g_bioq_enqueue_tail(bp, &g_bio_run_down); 290dd84a43cSPoul-Henning Kamp wakeup(&g_wait_down); 291dd84a43cSPoul-Henning Kamp } 292dd84a43cSPoul-Henning Kamp 293dd84a43cSPoul-Henning Kamp void 29472840432SPoul-Henning Kamp g_io_deliver(struct bio *bp, int error) 295dd84a43cSPoul-Henning Kamp { 296801bb689SPoul-Henning Kamp struct g_consumer *cp; 297801bb689SPoul-Henning Kamp struct g_provider *pp; 298dd84a43cSPoul-Henning Kamp 299801bb689SPoul-Henning Kamp cp = bp->bio_from; 300801bb689SPoul-Henning Kamp pp = bp->bio_to; 301d0e17c1bSPoul-Henning Kamp KASSERT(bp != NULL, ("NULL bp in g_io_deliver")); 302801bb689SPoul-Henning Kamp KASSERT(cp != NULL, ("NULL bio_from in g_io_deliver")); 303801bb689SPoul-Henning Kamp KASSERT(cp->geom != NULL, ("NULL bio_from->geom in g_io_deliver")); 304801bb689SPoul-Henning Kamp KASSERT(pp != NULL, ("NULL bio_to in g_io_deliver")); 3055ab413bfSPoul-Henning Kamp 306dd84a43cSPoul-Henning Kamp g_trace(G_T_BIO, 3070355b86eSPoul-Henning Kamp "g_io_deliver(%p) from %p(%s) to %p(%s) cmd %d error %d off %jd len %jd", 308801bb689SPoul-Henning Kamp bp, cp, cp->geom->name, pp, pp->name, bp->bio_cmd, error, 3090355b86eSPoul-Henning Kamp (intmax_t)bp->bio_offset, (intmax_t)bp->bio_length); 310801bb689SPoul-Henning Kamp 311e24cbd90SPoul-Henning Kamp bp->bio_bcount = bp->bio_length; 312cce7303aSPoul-Henning Kamp if (g_collectstats) { 313e24cbd90SPoul-Henning Kamp bp->bio_resid = bp->bio_bcount - bp->bio_completed; 314e24cbd90SPoul-Henning Kamp devstat_end_transaction_bio(cp->stat, bp); 315e24cbd90SPoul-Henning Kamp devstat_end_transaction_bio(pp->stat, bp); 316c6ae9b5fSPoul-Henning Kamp } 317c6ae9b5fSPoul-Henning Kamp cp->nend++; 318c6ae9b5fSPoul-Henning Kamp pp->nend++; 319dd84a43cSPoul-Henning Kamp 3203432e4fdSPoul-Henning Kamp if (error == ENOMEM) { 321801bb689SPoul-Henning Kamp printf("ENOMEM %p on %p(%s)\n", bp, pp, pp->name); 322801bb689SPoul-Henning Kamp g_io_request(bp, cp); 3233432e4fdSPoul-Henning Kamp pace++; 3243432e4fdSPoul-Henning Kamp return; 3253432e4fdSPoul-Henning Kamp } 32672840432SPoul-Henning Kamp bp->bio_error = error; 327dd84a43cSPoul-Henning Kamp g_bioq_enqueue_tail(bp, &g_bio_run_up); 328dd84a43cSPoul-Henning Kamp wakeup(&g_wait_up); 329dd84a43cSPoul-Henning Kamp } 330dd84a43cSPoul-Henning Kamp 331dd84a43cSPoul-Henning Kamp void 332dd84a43cSPoul-Henning Kamp g_io_schedule_down(struct thread *tp __unused) 333dd84a43cSPoul-Henning Kamp { 334dd84a43cSPoul-Henning Kamp struct bio *bp; 335e39d70d4SPoul-Henning Kamp off_t excess; 336e39d70d4SPoul-Henning Kamp int error; 337f0e185d7SPoul-Henning Kamp struct mtx mymutex; 338f0e185d7SPoul-Henning Kamp 339f0e185d7SPoul-Henning Kamp bzero(&mymutex, sizeof mymutex); 340f0e185d7SPoul-Henning Kamp mtx_init(&mymutex, "g_xdown", MTX_DEF, 0); 341dd84a43cSPoul-Henning Kamp 342dd84a43cSPoul-Henning Kamp for(;;) { 343f0e185d7SPoul-Henning Kamp g_bioq_lock(&g_bio_run_down); 344dd84a43cSPoul-Henning Kamp bp = g_bioq_first(&g_bio_run_down); 345f0e185d7SPoul-Henning Kamp if (bp == NULL) { 346f0e185d7SPoul-Henning Kamp msleep(&g_wait_down, &g_bio_run_down.bio_queue_lock, 347f0e185d7SPoul-Henning Kamp PRIBIO | PDROP, "g_down", hz/10); 348f0e185d7SPoul-Henning Kamp continue; 349f0e185d7SPoul-Henning Kamp } 350f0e185d7SPoul-Henning Kamp g_bioq_unlock(&g_bio_run_down); 351e39d70d4SPoul-Henning Kamp error = g_io_check(bp); 352e39d70d4SPoul-Henning Kamp if (error) { 353e39d70d4SPoul-Henning Kamp g_io_deliver(bp, error); 354e39d70d4SPoul-Henning Kamp continue; 355e39d70d4SPoul-Henning Kamp } 356392d56b4SPoul-Henning Kamp switch (bp->bio_cmd) { 357392d56b4SPoul-Henning Kamp case BIO_READ: 358392d56b4SPoul-Henning Kamp case BIO_WRITE: 359392d56b4SPoul-Henning Kamp case BIO_DELETE: 360e39d70d4SPoul-Henning Kamp /* Truncate requests to the end of providers media. */ 361e39d70d4SPoul-Henning Kamp excess = bp->bio_offset + bp->bio_length; 362e39d70d4SPoul-Henning Kamp if (excess > bp->bio_to->mediasize) { 363e39d70d4SPoul-Henning Kamp excess -= bp->bio_to->mediasize; 364e39d70d4SPoul-Henning Kamp bp->bio_length -= excess; 365e39d70d4SPoul-Henning Kamp } 366e39d70d4SPoul-Henning Kamp /* Deliver zero length transfers right here. */ 367e39d70d4SPoul-Henning Kamp if (bp->bio_length == 0) { 368e39d70d4SPoul-Henning Kamp g_io_deliver(bp, 0); 369e39d70d4SPoul-Henning Kamp continue; 370e39d70d4SPoul-Henning Kamp } 371392d56b4SPoul-Henning Kamp break; 372392d56b4SPoul-Henning Kamp default: 373392d56b4SPoul-Henning Kamp break; 374392d56b4SPoul-Henning Kamp } 375f0e185d7SPoul-Henning Kamp mtx_lock(&mymutex); 376dd84a43cSPoul-Henning Kamp bp->bio_to->geom->start(bp); 377f0e185d7SPoul-Henning Kamp mtx_unlock(&mymutex); 3783432e4fdSPoul-Henning Kamp if (pace) { 3793432e4fdSPoul-Henning Kamp pace--; 3803432e4fdSPoul-Henning Kamp break; 3813432e4fdSPoul-Henning Kamp } 382dd84a43cSPoul-Henning Kamp } 383dd84a43cSPoul-Henning Kamp } 384dd84a43cSPoul-Henning Kamp 385dd84a43cSPoul-Henning Kamp void 386f0e185d7SPoul-Henning Kamp bio_taskqueue(struct bio *bp, bio_task_t *func, void *arg) 387f0e185d7SPoul-Henning Kamp { 388f0e185d7SPoul-Henning Kamp bp->bio_task = func; 389f0e185d7SPoul-Henning Kamp bp->bio_task_arg = arg; 390f0e185d7SPoul-Henning Kamp /* 391f0e185d7SPoul-Henning Kamp * The taskqueue is actually just a second queue off the "up" 392f0e185d7SPoul-Henning Kamp * queue, so we use the same lock. 393f0e185d7SPoul-Henning Kamp */ 394f0e185d7SPoul-Henning Kamp g_bioq_lock(&g_bio_run_up); 395f0e185d7SPoul-Henning Kamp TAILQ_INSERT_TAIL(&g_bio_run_task.bio_queue, bp, bio_queue); 396f0e185d7SPoul-Henning Kamp g_bio_run_task.bio_queue_length++; 397f0e185d7SPoul-Henning Kamp wakeup(&g_wait_up); 398f0e185d7SPoul-Henning Kamp g_bioq_unlock(&g_bio_run_up); 399f0e185d7SPoul-Henning Kamp } 400f0e185d7SPoul-Henning Kamp 401f0e185d7SPoul-Henning Kamp 402f0e185d7SPoul-Henning Kamp void 403dd84a43cSPoul-Henning Kamp g_io_schedule_up(struct thread *tp __unused) 404dd84a43cSPoul-Henning Kamp { 405dd84a43cSPoul-Henning Kamp struct bio *bp; 406f0e185d7SPoul-Henning Kamp struct mtx mymutex; 407dd84a43cSPoul-Henning Kamp 408f0e185d7SPoul-Henning Kamp bzero(&mymutex, sizeof mymutex); 409f0e185d7SPoul-Henning Kamp mtx_init(&mymutex, "g_xup", MTX_DEF, 0); 410dd84a43cSPoul-Henning Kamp for(;;) { 411f0e185d7SPoul-Henning Kamp g_bioq_lock(&g_bio_run_up); 412f0e185d7SPoul-Henning Kamp bp = g_bioq_first(&g_bio_run_task); 413f0e185d7SPoul-Henning Kamp if (bp != NULL) { 414f0e185d7SPoul-Henning Kamp g_bioq_unlock(&g_bio_run_up); 415f0e185d7SPoul-Henning Kamp mtx_lock(&mymutex); 416f0e185d7SPoul-Henning Kamp bp->bio_task(bp, bp->bio_task_arg); 417f0e185d7SPoul-Henning Kamp mtx_unlock(&mymutex); 418f0e185d7SPoul-Henning Kamp continue; 419f0e185d7SPoul-Henning Kamp } 420dd84a43cSPoul-Henning Kamp bp = g_bioq_first(&g_bio_run_up); 421f0e185d7SPoul-Henning Kamp if (bp != NULL) { 422f0e185d7SPoul-Henning Kamp g_bioq_unlock(&g_bio_run_up); 423f0e185d7SPoul-Henning Kamp mtx_lock(&mymutex); 42453706245SPoul-Henning Kamp biodone(bp); 425f0e185d7SPoul-Henning Kamp mtx_unlock(&mymutex); 426f0e185d7SPoul-Henning Kamp continue; 427f0e185d7SPoul-Henning Kamp } 428f0e185d7SPoul-Henning Kamp msleep(&g_wait_up, &g_bio_run_up.bio_queue_lock, 429f0e185d7SPoul-Henning Kamp PRIBIO | PDROP, "g_up", hz/10); 430dd84a43cSPoul-Henning Kamp } 431dd84a43cSPoul-Henning Kamp } 432dd84a43cSPoul-Henning Kamp 433dd84a43cSPoul-Henning Kamp void * 434dd84a43cSPoul-Henning Kamp g_read_data(struct g_consumer *cp, off_t offset, off_t length, int *error) 435dd84a43cSPoul-Henning Kamp { 436dd84a43cSPoul-Henning Kamp struct bio *bp; 437dd84a43cSPoul-Henning Kamp void *ptr; 438dd84a43cSPoul-Henning Kamp int errorc; 439dd84a43cSPoul-Henning Kamp 440dd84a43cSPoul-Henning Kamp bp = g_new_bio(); 441dd84a43cSPoul-Henning Kamp bp->bio_cmd = BIO_READ; 442dd84a43cSPoul-Henning Kamp bp->bio_done = NULL; 443dd84a43cSPoul-Henning Kamp bp->bio_offset = offset; 444dd84a43cSPoul-Henning Kamp bp->bio_length = length; 445a163d034SWarner Losh ptr = g_malloc(length, M_WAITOK); 446dd84a43cSPoul-Henning Kamp bp->bio_data = ptr; 447dd84a43cSPoul-Henning Kamp g_io_request(bp, cp); 44853706245SPoul-Henning Kamp errorc = biowait(bp, "gread"); 449dd84a43cSPoul-Henning Kamp if (error != NULL) 450dd84a43cSPoul-Henning Kamp *error = errorc; 451dd84a43cSPoul-Henning Kamp g_destroy_bio(bp); 452dd84a43cSPoul-Henning Kamp if (errorc) { 453dd84a43cSPoul-Henning Kamp g_free(ptr); 454dd84a43cSPoul-Henning Kamp ptr = NULL; 455dd84a43cSPoul-Henning Kamp } 456dd84a43cSPoul-Henning Kamp return (ptr); 457dd84a43cSPoul-Henning Kamp } 45890b1cd56SPoul-Henning Kamp 45990b1cd56SPoul-Henning Kamp int 46090b1cd56SPoul-Henning Kamp g_write_data(struct g_consumer *cp, off_t offset, void *ptr, off_t length) 46190b1cd56SPoul-Henning Kamp { 46290b1cd56SPoul-Henning Kamp struct bio *bp; 46390b1cd56SPoul-Henning Kamp int error; 46490b1cd56SPoul-Henning Kamp 46590b1cd56SPoul-Henning Kamp bp = g_new_bio(); 46690b1cd56SPoul-Henning Kamp bp->bio_cmd = BIO_WRITE; 46790b1cd56SPoul-Henning Kamp bp->bio_done = NULL; 46890b1cd56SPoul-Henning Kamp bp->bio_offset = offset; 46990b1cd56SPoul-Henning Kamp bp->bio_length = length; 47090b1cd56SPoul-Henning Kamp bp->bio_data = ptr; 47190b1cd56SPoul-Henning Kamp g_io_request(bp, cp); 47290b1cd56SPoul-Henning Kamp error = biowait(bp, "gwrite"); 47390b1cd56SPoul-Henning Kamp g_destroy_bio(bp); 47490b1cd56SPoul-Henning Kamp return (error); 47590b1cd56SPoul-Henning Kamp } 476