geom_io.c revision 110517
115885Sjulian/*- 215885Sjulian * Copyright (c) 2002 Poul-Henning Kamp 315885Sjulian * Copyright (c) 2002 Networks Associates Technology, Inc. 415885Sjulian * All rights reserved. 515885Sjulian * 615885Sjulian * This software was developed for the FreeBSD Project by Poul-Henning Kamp 715885Sjulian * and NAI Labs, the Security Research Division of Network Associates, Inc. 815885Sjulian * under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the 915885Sjulian * DARPA CHATS research program. 1015885Sjulian * 1115885Sjulian * Redistribution and use in source and binary forms, with or without 1215885Sjulian * modification, are permitted provided that the following conditions 1315885Sjulian * are met: 1415885Sjulian * 1. Redistributions of source code must retain the above copyright 1515885Sjulian * notice, this list of conditions and the following disclaimer. 1615885Sjulian * 2. Redistributions in binary form must reproduce the above copyright 1715885Sjulian * notice, this list of conditions and the following disclaimer in the 1815885Sjulian * documentation and/or other materials provided with the distribution. 1915885Sjulian * 3. The names of the authors may not be used to endorse or promote 2015885Sjulian * products derived from this software without specific prior written 2115885Sjulian * permission. 2218207Sbde * 2318207Sbde * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 2418207Sbde * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2518207Sbde * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2615885Sjulian * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2715885Sjulian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2817967Sjulian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2917967Sjulian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 3017254Sjulian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 3117254Sjulian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3217254Sjulian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3317254Sjulian * SUCH DAMAGE. 3417254Sjulian * 3517254Sjulian * $FreeBSD: head/sys/geom/geom_io.c 110517 2003-02-07 21:09:51Z phk $ 3615885Sjulian */ 3715885Sjulian 3815885Sjulian 3915885Sjulian#include <sys/param.h> 4015885Sjulian#include <sys/stdint.h> 4115885Sjulian#ifndef _KERNEL 4215885Sjulian#include <stdio.h> 4315885Sjulian#include <string.h> 4415885Sjulian#include <stdlib.h> 4515885Sjulian#include <signal.h> 4615885Sjulian#include <err.h> 4715885Sjulian#include <sched.h> 4815885Sjulian#else 4915885Sjulian#include <sys/systm.h> 5015885Sjulian#include <sys/kernel.h> 5115885Sjulian#include <sys/malloc.h> 5215885Sjulian#include <sys/bio.h> 5315885Sjulian#endif 5418240Sjulian 5515885Sjulian#include <sys/errno.h> 5617921Sjulian#include <geom/geom.h> 5717921Sjulian#include <geom/geom_int.h> 5817921Sjulian 5915885Sjulianstatic struct g_bioq g_bio_run_down; 6015885Sjulianstatic struct g_bioq g_bio_run_up; 6115885Sjulianstatic struct g_bioq g_bio_idle; 6215885Sjulian 6315885Sjulianstatic u_int pace; 6415885Sjulian 6517921Sjulian#include <machine/atomic.h> 6617921Sjulian 6717921Sjulianstatic void 6817921Sjuliang_bioq_lock(struct g_bioq *bq) 6917921Sjulian{ 7017921Sjulian 7115885Sjulian mtx_lock(&bq->bio_queue_lock); 7215885Sjulian} 7315885Sjulian 7417921Sjulianstatic void 7517921Sjuliang_bioq_unlock(struct g_bioq *bq) 7617921Sjulian{ 7717921Sjulian 7817921Sjulian mtx_unlock(&bq->bio_queue_lock); 7917921Sjulian} 8017921Sjulian 8115885Sjulian#if 0 8215885Sjulianstatic void 8315885Sjuliang_bioq_destroy(struct g_bioq *bq) 8415885Sjulian{ 8515885Sjulian 8615885Sjulian mtx_destroy(&bq->bio_queue_lock); 8715885Sjulian} 8815885Sjulian#endif 8917921Sjulian 9017921Sjulianstatic void 9117921Sjuliang_bioq_init(struct g_bioq *bq) 9217921Sjulian{ 9315885Sjulian 9415885Sjulian TAILQ_INIT(&bq->bio_queue); 9515885Sjulian mtx_init(&bq->bio_queue_lock, "bio queue", NULL, MTX_DEF); 9615885Sjulian} 9715885Sjulian 9815885Sjulianstatic struct bio * 9917921Sjuliang_bioq_first(struct g_bioq *bq) 10017921Sjulian{ 10117921Sjulian struct bio *bp; 10215885Sjulian 10315885Sjulian g_bioq_lock(bq); 10415885Sjulian bp = TAILQ_FIRST(&bq->bio_queue); 10515885Sjulian if (bp != NULL) { 10615885Sjulian TAILQ_REMOVE(&bq->bio_queue, bp, bio_queue); 10715885Sjulian bq->bio_queue_length--; 10815885Sjulian } 10917921Sjulian g_bioq_unlock(bq); 11017921Sjulian return (bp); 11117921Sjulian} 11217921Sjulian 11317921Sjulianstatic void 11415885Sjuliang_bioq_enqueue_tail(struct bio *bp, struct g_bioq *rq) 11515885Sjulian{ 11615885Sjulian 11715885Sjulian g_bioq_lock(rq); 11815885Sjulian TAILQ_INSERT_TAIL(&rq->bio_queue, bp, bio_queue); 11915885Sjulian rq->bio_queue_length++; 12015885Sjulian g_bioq_unlock(rq); 12117921Sjulian} 12217921Sjulian 12317921Sjulianstruct bio * 12417921Sjuliang_new_bio(void) 12517921Sjulian{ 12615885Sjulian struct bio *bp; 12715885Sjulian 12815885Sjulian bp = g_bioq_first(&g_bio_idle); 12915885Sjulian if (bp == NULL) 13015885Sjulian bp = g_malloc(sizeof *bp, M_NOWAIT | M_ZERO); 13115885Sjulian /* g_trace(G_T_BIO, "g_new_bio() = %p", bp); */ 13215885Sjulian return (bp); 13315885Sjulian} 13415885Sjulian 13515885Sjulianvoid 13617921Sjuliang_destroy_bio(struct bio *bp) 13717921Sjulian{ 13817921Sjulian 13917921Sjulian /* g_trace(G_T_BIO, "g_destroy_bio(%p)", bp); */ 14017921Sjulian bzero(bp, sizeof *bp); 14115885Sjulian g_bioq_enqueue_tail(bp, &g_bio_idle); 14218240Sjulian} 14318244Sjulian 14415885Sjulianstruct bio * 14515885Sjuliang_clone_bio(struct bio *bp) 14615885Sjulian{ 14715885Sjulian struct bio *bp2; 14815885Sjulian 14917921Sjulian bp2 = g_new_bio(); 15017921Sjulian if (bp2 != NULL) { 15115885Sjulian bp2->bio_parent = bp; 15215885Sjulian bp2->bio_cmd = bp->bio_cmd; 15318240Sjulian bp2->bio_length = bp->bio_length; 15415885Sjulian bp2->bio_offset = bp->bio_offset; 15515885Sjulian bp2->bio_data = bp->bio_data; 15615885Sjulian bp2->bio_attribute = bp->bio_attribute; 15715885Sjulian bp->bio_children++; /* XXX: atomic ? */ 15815885Sjulian } 15918240Sjulian /* g_trace(G_T_BIO, "g_clone_bio(%p) = %p", bp, bp2); */ 16015885Sjulian return(bp2); 16115885Sjulian} 16218240Sjulian 16315885Sjulianvoid 16418240Sjuliang_io_init() 16518240Sjulian{ 16618240Sjulian 16718240Sjulian g_bioq_init(&g_bio_run_down); 16818240Sjulian g_bioq_init(&g_bio_run_up); 16918240Sjulian g_bioq_init(&g_bio_idle); 17018240Sjulian} 17115885Sjulian 17217921Sjulianint 17317921Sjuliang_io_setattr(const char *attr, struct g_consumer *cp, int len, void *ptr) 17417921Sjulian{ 17517921Sjulian struct bio *bp; 17620407Swollman int error; 17720407Swollman 17820407Swollman g_trace(G_T_BIO, "bio_setattr(%s)", attr); 17918240Sjulian bp = g_new_bio(); 18018240Sjulian bp->bio_cmd = BIO_SETATTR; 18118240Sjulian bp->bio_done = NULL; 18220407Swollman bp->bio_attribute = attr; 18315885Sjulian bp->bio_length = len; 18417921Sjulian bp->bio_data = ptr; 18517921Sjulian g_io_request(bp, cp); 18617921Sjulian error = biowait(bp, "gsetattr"); 18717921Sjulian g_destroy_bio(bp); 18820407Swollman return (error); 18920407Swollman} 19020407Swollman 19115885Sjulian 19215885Sjulianint 19315885Sjuliang_io_getattr(const char *attr, struct g_consumer *cp, int *len, void *ptr) 19415885Sjulian{ 19515885Sjulian struct bio *bp; 19615885Sjulian int error; 19715885Sjulian 19815885Sjulian g_trace(G_T_BIO, "bio_getattr(%s)", attr); 19915885Sjulian bp = g_new_bio(); 20017921Sjulian bp->bio_cmd = BIO_GETATTR; 20117921Sjulian bp->bio_done = NULL; 20217921Sjulian bp->bio_attribute = attr; 20317921Sjulian bp->bio_length = *len; 20415885Sjulian bp->bio_data = ptr; 20515885Sjulian g_io_request(bp, cp); 20617921Sjulian error = biowait(bp, "ggetattr"); 20717921Sjulian *len = bp->bio_completed; 20817921Sjulian g_destroy_bio(bp); 20915885Sjulian return (error); 21015885Sjulian} 21115885Sjulian 21215885Sjulianstatic int 21315885Sjuliang_io_check(struct bio *bp) 21415885Sjulian{ 21515885Sjulian struct g_consumer *cp; 21615885Sjulian struct g_provider *pp; 21717921Sjulian 21817921Sjulian cp = bp->bio_from; 21917921Sjulian pp = bp->bio_to; 22017921Sjulian 22115885Sjulian /* Fail if access counters dont allow the operation */ 22215885Sjulian switch(bp->bio_cmd) { 22315885Sjulian case BIO_READ: 22415885Sjulian case BIO_GETATTR: 22515885Sjulian if (cp->acr == 0) 22615885Sjulian return (EPERM); 22717921Sjulian break; 22817921Sjulian case BIO_WRITE: 22917921Sjulian case BIO_DELETE: 23017921Sjulian case BIO_SETATTR: 23115885Sjulian if (cp->acw == 0) 23215885Sjulian return (EPERM); 23315885Sjulian break; 23415885Sjulian default: 23515885Sjulian return (EPERM); 23615885Sjulian } 23715885Sjulian /* if provider is marked for error, don't disturb. */ 23815885Sjulian if (pp->error) 23915885Sjulian return (pp->error); 24015885Sjulian 24115885Sjulian switch(bp->bio_cmd) { 24215885Sjulian case BIO_READ: 24317921Sjulian case BIO_WRITE: 24417921Sjulian case BIO_DELETE: 24517921Sjulian /* Reject I/O not on sector boundary */ 24617921Sjulian if (bp->bio_offset % pp->sectorsize) 24715885Sjulian return (EINVAL); 24815885Sjulian /* Reject I/O not integral sector long */ 24917921Sjulian if (bp->bio_length % pp->sectorsize) 25017921Sjulian return (EINVAL); 25117921Sjulian /* Reject requests past the end of media. */ 25217921Sjulian if (bp->bio_offset > pp->mediasize) 25317254Sjulian return (EIO); 25417254Sjulian break; 25517921Sjulian default: 25617921Sjulian break; 25717921Sjulian } 25817921Sjulian return (0); 25917254Sjulian} 26017254Sjulian 26117254Sjulianvoid 26217254Sjuliang_io_request(struct bio *bp, struct g_consumer *cp) 26315885Sjulian{ 26415885Sjulian 26515885Sjulian KASSERT(cp != NULL, ("NULL cp in g_io_request")); 26615885Sjulian KASSERT(bp != NULL, ("NULL bp in g_io_request")); 26715885Sjulian KASSERT(bp->bio_data != NULL, ("NULL bp->data in g_io_request")); 26815885Sjulian KASSERT(bp->bio_to == NULL, ("consumer not attached in g_io_request")); 26915885Sjulian bp->bio_from = cp; 27015885Sjulian bp->bio_to = cp->provider; 27115885Sjulian bp->bio_error = 0; 27215885Sjulian bp->bio_completed = 0; 27315885Sjulian 27415885Sjulian /* begin_stats(&bp->stats); */ 27517921Sjulian 27617921Sjulian atomic_add_int(&cp->biocount, 1); 27717921Sjulian 27815885Sjulian /* Pass it on down. */ 27917921Sjulian g_trace(G_T_BIO, "bio_request(%p) from %p(%s) to %p(%s) cmd %d", 28017921Sjulian bp, bp->bio_from, bp->bio_from->geom->name, 28117921Sjulian bp->bio_to, bp->bio_to->name, bp->bio_cmd); 28217921Sjulian g_bioq_enqueue_tail(bp, &g_bio_run_down); 28318240Sjulian wakeup(&g_wait_down); 28420407Swollman} 28517921Sjulian 28618240Sjulianvoid 28718240Sjuliang_io_deliver(struct bio *bp, int error) 28818240Sjulian{ 28918240Sjulian 29018240Sjulian KASSERT(bp != NULL, ("NULL bp in g_io_deliver")); 29115885Sjulian KASSERT(bp->bio_from != NULL, ("NULL bio_from in g_io_deliver")); 29217921Sjulian KASSERT(bp->bio_from->geom != NULL, 29317921Sjulian ("NULL bio_from->geom in g_io_deliver")); 29417921Sjulian KASSERT(bp->bio_to != NULL, ("NULL bio_to in g_io_deliver")); 29517921Sjulian 29615885Sjulian g_trace(G_T_BIO, 29715885Sjulian"g_io_deliver(%p) from %p(%s) to %p(%s) cmd %d error %d off %jd len %jd", 29815885Sjulian bp, bp->bio_from, bp->bio_from->geom->name, 29915885Sjulian bp->bio_to, bp->bio_to->name, bp->bio_cmd, error, 30015885Sjulian (intmax_t)bp->bio_offset, (intmax_t)bp->bio_length); 30115885Sjulian /* finish_stats(&bp->stats); */ 30215885Sjulian 30317921Sjulian if (error == ENOMEM) { 30417921Sjulian printf("ENOMEM %p on %p(%s)\n", 30517921Sjulian bp, bp->bio_to, bp->bio_to->name); 30617921Sjulian g_io_request(bp, bp->bio_from); 30715885Sjulian pace++; 30815885Sjulian return; 30915885Sjulian } 31015885Sjulian 31115885Sjulian bp->bio_error = error; 31215885Sjulian 31317921Sjulian g_bioq_enqueue_tail(bp, &g_bio_run_up); 31417921Sjulian 31518240Sjulian wakeup(&g_wait_up); 31618240Sjulian} 31718240Sjulian 31818240Sjulianvoid 31918240Sjuliang_io_schedule_down(struct thread *tp __unused) 32017921Sjulian{ 32118240Sjulian struct bio *bp; 32215885Sjulian off_t excess; 32315885Sjulian int error; 32415885Sjulian 32515885Sjulian for(;;) { 32615885Sjulian bp = g_bioq_first(&g_bio_run_down); 32715885Sjulian if (bp == NULL) 32815885Sjulian break; 32915885Sjulian error = g_io_check(bp); 33015885Sjulian if (error) { 33117254Sjulian g_io_deliver(bp, error); 33217921Sjulian continue; 33317921Sjulian } 33417921Sjulian /* Truncate requests to the end of providers media. */ 33517921Sjulian excess = bp->bio_offset + bp->bio_length; 33617921Sjulian if (excess > bp->bio_to->mediasize) { 33717921Sjulian excess -= bp->bio_to->mediasize; 33815885Sjulian bp->bio_length -= excess; 33915885Sjulian } 34015885Sjulian /* Deliver zero length transfers right here. */ 34115885Sjulian if (bp->bio_length == 0) { 34215885Sjulian g_io_deliver(bp, 0); 34315885Sjulian continue; 34415885Sjulian } 34515885Sjulian bp->bio_to->geom->start(bp); 34617967Sjulian if (pace) { 34718005Sjulian pace--; 34818005Sjulian break; 34918005Sjulian } 35018005Sjulian } 35118005Sjulian} 35217967Sjulian 35317967Sjulianvoid 35417967Sjuliang_io_schedule_up(struct thread *tp __unused) 35517967Sjulian{ 35617967Sjulian struct bio *bp; 35717967Sjulian struct g_consumer *cp; 35817967Sjulian 35917967Sjulian for(;;) { 36015885Sjulian bp = g_bioq_first(&g_bio_run_up); 36115885Sjulian if (bp == NULL) 36215885Sjulian break; 36315885Sjulian 36415885Sjulian cp = bp->bio_from; 36515885Sjulian 36615885Sjulian atomic_add_int(&cp->biocount, -1); 36717921Sjulian biodone(bp); 36817921Sjulian } 36917921Sjulian} 37017921Sjulian 37115885Sjulianvoid * 37215885Sjuliang_read_data(struct g_consumer *cp, off_t offset, off_t length, int *error) 37315885Sjulian{ 37415885Sjulian struct bio *bp; 37515885Sjulian void *ptr; 37615885Sjulian int errorc; 37715885Sjulian 37815885Sjulian bp = g_new_bio(); 37917254Sjulian bp->bio_cmd = BIO_READ; 38017967Sjulian bp->bio_done = NULL; 38115885Sjulian bp->bio_offset = offset; 38215885Sjulian bp->bio_length = length; 38317921Sjulian ptr = g_malloc(length, 0); 38417921Sjulian bp->bio_data = ptr; 38517921Sjulian g_io_request(bp, cp); 38615885Sjulian errorc = biowait(bp, "gread"); 38717921Sjulian if (error != NULL) 38817921Sjulian *error = errorc; 38917921Sjulian g_destroy_bio(bp); 39017921Sjulian if (errorc) { 39117921Sjulian g_free(ptr); 39217921Sjulian ptr = NULL; 39317921Sjulian } 39417921Sjulian return (ptr); 39515885Sjulian} 39615885Sjulian 39717254Sjulianint 39815885Sjuliang_write_data(struct g_consumer *cp, off_t offset, void *ptr, off_t length) 39915885Sjulian{ 40015885Sjulian struct bio *bp; 40115885Sjulian int error; 40217254Sjulian 40317964Sjulian bp = g_new_bio(); 40417254Sjulian bp->bio_cmd = BIO_WRITE; 40517254Sjulian bp->bio_done = NULL; 40617254Sjulian bp->bio_offset = offset; 40717254Sjulian bp->bio_length = length; 40817254Sjulian bp->bio_data = ptr; 40917964Sjulian g_io_request(bp, cp); 41017254Sjulian error = biowait(bp, "gwrite"); 41115885Sjulian g_destroy_bio(bp); 41215885Sjulian return (error); 41315885Sjulian} 41415885Sjulian