geom_io.c revision 103283
1167514Skmacy/*- 2167514Skmacy * Copyright (c) 2002 Poul-Henning Kamp 3177340Skmacy * Copyright (c) 2002 Networks Associates Technology, Inc. 4167514Skmacy * All rights reserved. 5167514Skmacy * 6167514Skmacy * This software was developed for the FreeBSD Project by Poul-Henning Kamp 7167514Skmacy * and NAI Labs, the Security Research Division of Network Associates, Inc. 8167514Skmacy * under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the 9167514Skmacy * DARPA CHATS research program. 10167514Skmacy * 11167514Skmacy * Redistribution and use in source and binary forms, with or without 12170076Skmacy * modification, are permitted provided that the following conditions 13167514Skmacy * are met: 14167514Skmacy * 1. Redistributions of source code must retain the above copyright 15167514Skmacy * notice, this list of conditions and the following disclaimer. 16167514Skmacy * 2. Redistributions in binary form must reproduce the above copyright 17167514Skmacy * notice, this list of conditions and the following disclaimer in the 18167514Skmacy * documentation and/or other materials provided with the distribution. 19167514Skmacy * 3. The names of the authors may not be used to endorse or promote 20167514Skmacy * products derived from this software without specific prior written 21167514Skmacy * permission. 22167514Skmacy * 23167514Skmacy * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 24167514Skmacy * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25167514Skmacy * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26167514Skmacy * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 27167514Skmacy * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28167514Skmacy * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29167514Skmacy * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30167514Skmacy * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31167514Skmacy * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32167514Skmacy * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33170076Skmacy * SUCH DAMAGE. 34167514Skmacy * 35176472Skmacy * $FreeBSD: head/sys/geom/geom_io.c 103283 2002-09-13 11:39:11Z phk $ 36176472Skmacy */ 37176472Skmacy 38167514Skmacy 39181614Skmacy#include <sys/param.h> 40181614Skmacy#ifndef _KERNEL 41181614Skmacy#include <stdio.h> 42181614Skmacy#include <string.h> 43181614Skmacy#include <stdlib.h> 44181614Skmacy#include <signal.h> 45181614Skmacy#include <err.h> 46167514Skmacy#include <sched.h> 47167514Skmacy#else 48167514Skmacy#include <sys/systm.h> 49167514Skmacy#include <sys/kernel.h> 50167514Skmacy#include <sys/malloc.h> 51167514Skmacy#include <sys/bio.h> 52180583Skmacy#endif 53181614Skmacy 54181614Skmacy#include <sys/errno.h> 55181614Skmacy#include <geom/geom.h> 56181614Skmacy#include <geom/geom_int.h> 57181614Skmacy 58180583Skmacystatic struct g_bioq g_bio_run_down; 59167514Skmacystatic struct g_bioq g_bio_run_up; 60181614Skmacystatic struct g_bioq g_bio_idle; 61181614Skmacy 62181614Skmacy#include <machine/atomic.h> 63181614Skmacy 64181614Skmacystatic void 65181614Skmacyg_bioq_lock(struct g_bioq *bq) 66181614Skmacy{ 67180583Skmacy 68180583Skmacy mtx_lock(&bq->bio_queue_lock); 69180583Skmacy} 70180583Skmacy 71180583Skmacystatic void 72167514Skmacyg_bioq_unlock(struct g_bioq *bq) 73167514Skmacy{ 74186282Sgnn 75186282Sgnn mtx_unlock(&bq->bio_queue_lock); 76186282Sgnn} 77186282Sgnn 78186282Sgnn#if 0 79186282Sgnnstatic void 80186282Sgnng_bioq_destroy(struct g_bioq *bq) 81186282Sgnn{ 82186282Sgnn 83186282Sgnn mtx_destroy(&bq->bio_queue_lock); 84186282Sgnn} 85186282Sgnn#endif 86186282Sgnn 87186282Sgnnstatic void 88186282Sgnng_bioq_init(struct g_bioq *bq) 89186282Sgnn{ 90186282Sgnn 91186282Sgnn TAILQ_INIT(&bq->bio_queue); 92186282Sgnn mtx_init(&bq->bio_queue_lock, "bio queue", NULL, MTX_DEF); 93186282Sgnn} 94186282Sgnn 95186282Sgnnstatic struct bio * 96186282Sgnng_bioq_first(struct g_bioq *bq) 97186282Sgnn{ 98186282Sgnn struct bio *bp; 99186282Sgnn 100186282Sgnn g_bioq_lock(bq); 101186282Sgnn bp = TAILQ_FIRST(&bq->bio_queue); 102186282Sgnn if (bp != NULL) { 103186282Sgnn TAILQ_REMOVE(&bq->bio_queue, bp, bio_queue); 104186282Sgnn bq->bio_queue_length--; 105186282Sgnn } 106186282Sgnn g_bioq_unlock(bq); 107186282Sgnn return (bp); 108186282Sgnn} 109186282Sgnn 110186282Sgnnstatic void 111186282Sgnng_bioq_enqueue_tail(struct bio *bp, struct g_bioq *rq) 112186282Sgnn{ 113186282Sgnn 114186282Sgnn g_bioq_lock(rq); 115186282Sgnn TAILQ_INSERT_TAIL(&rq->bio_queue, bp, bio_queue); 116186282Sgnn rq->bio_queue_length++; 117186282Sgnn g_bioq_unlock(rq); 118186282Sgnn} 119186282Sgnn 120186282Sgnnstruct bio * 121186282Sgnng_new_bio(void) 122186282Sgnn{ 123186282Sgnn struct bio *bp; 124186282Sgnn 125186282Sgnn bp = g_bioq_first(&g_bio_idle); 126186282Sgnn if (bp == NULL) 127186282Sgnn bp = g_malloc(sizeof *bp, M_WAITOK | M_ZERO); 128186282Sgnn g_trace(G_T_BIO, "g_new_bio() = %p", bp); 129186282Sgnn return (bp); 130186282Sgnn} 131186282Sgnn 132186282Sgnnvoid 133186282Sgnng_destroy_bio(struct bio *bp) 134186282Sgnn{ 135186282Sgnn 136186282Sgnn g_trace(G_T_BIO, "g_destroy_bio(%p)", bp); 137186282Sgnn bzero(bp, sizeof *bp); 138186282Sgnn g_bioq_enqueue_tail(bp, &g_bio_idle); 139186282Sgnn} 140186282Sgnn 141186282Sgnnstruct bio * 142180583Skmacyg_clone_bio(struct bio *bp) 143180583Skmacy{ 144180583Skmacy struct bio *bp2; 145180583Skmacy 146180583Skmacy bp2 = g_new_bio(); 147180583Skmacy bp2->bio_linkage = bp; 148180583Skmacy bp2->bio_cmd = bp->bio_cmd; 149180583Skmacy bp2->bio_length = bp->bio_length; 150180583Skmacy bp2->bio_offset = bp->bio_offset; 151180583Skmacy bp2->bio_data = bp->bio_data; 152180583Skmacy bp2->bio_attribute = bp->bio_attribute; 153180583Skmacy g_trace(G_T_BIO, "g_clone_bio(%p) = %p", bp, bp2); 154180583Skmacy return(bp2); 155180583Skmacy} 156180583Skmacy 157180583Skmacyvoid 158167514Skmacyg_io_init() 159167514Skmacy{ 160167514Skmacy 161167514Skmacy g_bioq_init(&g_bio_run_down); 162176472Skmacy g_bioq_init(&g_bio_run_up); 163167514Skmacy g_bioq_init(&g_bio_idle); 164176472Skmacy} 165167514Skmacy 166167514Skmacyint 167167514Skmacyg_io_setattr(const char *attr, struct g_consumer *cp, int len, void *ptr) 168167514Skmacy{ 169167514Skmacy struct bio *bp; 170167514Skmacy int error; 171167514Skmacy 172167514Skmacy g_trace(G_T_BIO, "bio_setattr(%s)", attr); 173167514Skmacy do { 174167514Skmacy bp = g_new_bio(); 175167514Skmacy bp->bio_cmd = BIO_SETATTR; 176167514Skmacy bp->bio_done = NULL; 177167514Skmacy bp->bio_attribute = attr; 178186282Sgnn bp->bio_length = len; 179186282Sgnn bp->bio_data = ptr; 180186282Sgnn g_io_request(bp, cp); 181186282Sgnn error = biowait(bp, "gsetattr"); 182186282Sgnn g_destroy_bio(bp); 183186282Sgnn if (error == EBUSY) 184186282Sgnn tsleep(&error, 0, "setattr_busy", hz); 185186282Sgnn } while(error == EBUSY); 186186282Sgnn return (error); 187186282Sgnn} 188186282Sgnn 189186282Sgnn 190167514Skmacyint 191167514Skmacyg_io_getattr(const char *attr, struct g_consumer *cp, int *len, void *ptr) 192167514Skmacy{ 193167514Skmacy struct bio *bp; 194167514Skmacy int error; 195167514Skmacy 196167514Skmacy g_trace(G_T_BIO, "bio_getattr(%s)", attr); 197167514Skmacy do { 198167514Skmacy bp = g_new_bio(); 199167514Skmacy bp->bio_cmd = BIO_GETATTR; 200167514Skmacy bp->bio_done = NULL; 201167514Skmacy bp->bio_attribute = attr; 202186282Sgnn bp->bio_length = *len; 203186282Sgnn bp->bio_data = ptr; 204186282Sgnn g_io_request(bp, cp); 205186282Sgnn error = biowait(bp, "ggetattr"); 206186282Sgnn *len = bp->bio_completed; 207167514Skmacy g_destroy_bio(bp); 208167514Skmacy if (error == EBUSY) 209167514Skmacy tsleep(&error, 0, "getattr_busy", hz); 210167514Skmacy 211167514Skmacy } while(error == EBUSY); 212167514Skmacy return (error); 213167514Skmacy} 214167514Skmacy 215181614Skmacyvoid 216181614Skmacyg_io_fail(struct bio *bp, int error) 217181614Skmacy{ 218181614Skmacy 219181614Skmacy bp->bio_error = error; 220167514Skmacy 221167514Skmacy g_trace(G_T_BIO, 222181614Skmacy "bio_fail(%p) from %p(%s) to %p(%s) cmd %d error %d\n", 223181614Skmacy bp, bp->bio_from, bp->bio_from->geom->name, 224167514Skmacy bp->bio_to, bp->bio_to->name, bp->bio_cmd, bp->bio_error); 225181614Skmacy g_io_deliver(bp); 226181614Skmacy return; 227181614Skmacy} 228181614Skmacy 229167514Skmacyvoid 230167514Skmacyg_io_request(struct bio *bp, struct g_consumer *cp) 231181614Skmacy{ 232167514Skmacy int error; 233167514Skmacy off_t excess; 234167514Skmacy 235167514Skmacy KASSERT(cp != NULL, ("bio_request on thin air")); 236167514Skmacy error = 0; 237167514Skmacy bp->bio_from = cp; 238167514Skmacy bp->bio_to = cp->provider; 239167514Skmacy bp->bio_error = 0; 240167514Skmacy bp->bio_completed = 0; 241167514Skmacy 242167514Skmacy /* begin_stats(&bp->stats); */ 243167514Skmacy 244167514Skmacy atomic_add_int(&cp->biocount, 1); 245167514Skmacy /* Fail on unattached consumers */ 246167514Skmacy if (bp->bio_to == NULL) 247167514Skmacy return (g_io_fail(bp, ENXIO)); 248167514Skmacy /* Fail if access doesn't allow operation */ 249167514Skmacy switch(bp->bio_cmd) { 250167514Skmacy case BIO_READ: 251167514Skmacy case BIO_GETATTR: 252181614Skmacy if (cp->acr == 0) 253167514Skmacy return (g_io_fail(bp, EPERM)); 254167514Skmacy break; 255167514Skmacy case BIO_WRITE: 256167514Skmacy case BIO_DELETE: 257167514Skmacy if (cp->acw == 0) 258167514Skmacy return (g_io_fail(bp, EPERM)); 259167514Skmacy break; 260167514Skmacy case BIO_SETATTR: 261167514Skmacy if ((cp->acw == 0) || (cp->ace == 0)) 262181614Skmacy return (g_io_fail(bp, EPERM)); 263167514Skmacy break; 264167514Skmacy default: 265167514Skmacy return (g_io_fail(bp, EPERM)); 266167514Skmacy } 267176472Skmacy /* if provider is marked for error, don't disturb. */ 268176472Skmacy if (bp->bio_to->error) 269167514Skmacy return (g_io_fail(bp, bp->bio_to->error)); 270186282Sgnn switch(bp->bio_cmd) { 271186282Sgnn case BIO_READ: 272176472Skmacy case BIO_WRITE: 273176472Skmacy case BIO_DELETE: 274177340Skmacy /* Reject requests past the end of media. */ 275167514Skmacy if (bp->bio_offset > bp->bio_to->mediasize) 276186282Sgnn return (g_io_fail(bp, EIO)); 277186282Sgnn /* Truncate requests to the end of providers media. */ 278186282Sgnn excess = bp->bio_offset + bp->bio_length; 279186282Sgnn if (excess > bp->bio_to->mediasize) { 280186282Sgnn excess -= bp->bio_to->mediasize; 281176472Skmacy bp->bio_length -= excess; 282167514Skmacy } 283167514Skmacy /* Deliver zero length transfers right here. */ 284167514Skmacy if (bp->bio_length == 0) 285167514Skmacy return (g_io_deliver(bp)); 286185157Sgnn break; 287185157Sgnn default: 288185157Sgnn break; 289185157Sgnn } 290185157Sgnn /* Pass it on down. */ 291185157Sgnn g_trace(G_T_BIO, "bio_request(%p) from %p(%s) to %p(%s) cmd %d", 292185157Sgnn bp, bp->bio_from, bp->bio_from->geom->name, 293185157Sgnn bp->bio_to, bp->bio_to->name, bp->bio_cmd); 294185157Sgnn g_bioq_enqueue_tail(bp, &g_bio_run_down); 295185157Sgnn wakeup(&g_wait_down); 296185157Sgnn} 297185157Sgnn 298185157Sgnnvoid 299185157Sgnng_io_deliver(struct bio *bp) 300185620Sgnn{ 301185620Sgnn 302185620Sgnn g_trace(G_T_BIO, 303185620Sgnn "g_io_deliver(%p) from %p(%s) to %p(%s) cmd %d error %d", 304185620Sgnn bp, bp->bio_from, bp->bio_from->geom->name, 305185620Sgnn bp->bio_to, bp->bio_to->name, bp->bio_cmd, bp->bio_error); 306185620Sgnn /* finish_stats(&bp->stats); */ 307185620Sgnn 308185620Sgnn g_bioq_enqueue_tail(bp, &g_bio_run_up); 309185620Sgnn 310185157Sgnn wakeup(&g_wait_up); 311167514Skmacy} 312167514Skmacy 313167514Skmacyvoid 314167514Skmacyg_io_schedule_down(struct thread *tp __unused) 315167514Skmacy{ 316167514Skmacy struct bio *bp; 317167514Skmacy 318167514Skmacy for(;;) { 319167514Skmacy bp = g_bioq_first(&g_bio_run_down); 320167514Skmacy if (bp == NULL) 321167514Skmacy break; 322180583Skmacy bp->bio_to->geom->start(bp); 323180583Skmacy } 324180583Skmacy} 325180583Skmacy 326167514Skmacyvoid 327167514Skmacyg_io_schedule_up(struct thread *tp __unused) 328167514Skmacy{ 329167514Skmacy struct bio *bp; 330167514Skmacy struct g_consumer *cp; 331181614Skmacy 332167514Skmacy for(;;) { 333167514Skmacy bp = g_bioq_first(&g_bio_run_up); 334167514Skmacy if (bp == NULL) 335167514Skmacy break; 336167514Skmacy 337180583Skmacy cp = bp->bio_from; 338180583Skmacy 339180583Skmacy atomic_add_int(&cp->biocount, -1); 340180583Skmacy biodone(bp); 341181614Skmacy } 342167514Skmacy} 343167514Skmacy 344167514Skmacyvoid * 345167514Skmacyg_read_data(struct g_consumer *cp, off_t offset, off_t length, int *error) 346176472Skmacy{ 347176472Skmacy struct bio *bp; 348167514Skmacy void *ptr; 349176472Skmacy int errorc; 350176472Skmacy 351176472Skmacy do { 352167514Skmacy bp = g_new_bio(); 353176472Skmacy bp->bio_cmd = BIO_READ; 354167514Skmacy bp->bio_done = NULL; 355167514Skmacy bp->bio_offset = offset; 356180583Skmacy bp->bio_length = length; 357180583Skmacy ptr = g_malloc(length, M_WAITOK); 358181614Skmacy bp->bio_data = ptr; 359181614Skmacy g_io_request(bp, cp); 360181614Skmacy errorc = biowait(bp, "gread"); 361181614Skmacy if (error != NULL) 362181614Skmacy *error = errorc; 363181614Skmacy g_destroy_bio(bp); 364180583Skmacy if (errorc) { 365180583Skmacy g_free(ptr); 366180583Skmacy ptr = NULL; 367180583Skmacy } 368180583Skmacy if (errorc == EBUSY) 369180583Skmacy tsleep(&errorc, 0, "g_read_data_busy", hz); 370180583Skmacy } while (errorc == EBUSY); 371180583Skmacy return (ptr); 372180583Skmacy} 373180583Skmacy