geom_io.c revision 113432
1/*- 2 * Copyright (c) 2002 Poul-Henning Kamp 3 * Copyright (c) 2002 Networks Associates Technology, Inc. 4 * All rights reserved. 5 * 6 * This software was developed for the FreeBSD Project by Poul-Henning Kamp 7 * and NAI Labs, the Security Research Division of Network Associates, Inc. 8 * under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the 9 * DARPA CHATS research program. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 3. The names of the authors may not be used to endorse or promote 20 * products derived from this software without specific prior written 21 * permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 * 35 * $FreeBSD: head/sys/geom/geom_io.c 113432 2003-04-13 09:02:06Z phk $ 36 */ 37 38 39#include <sys/param.h> 40#include <sys/systm.h> 41#include <sys/kernel.h> 42#include <sys/malloc.h> 43#include <sys/bio.h> 44 45#include <sys/errno.h> 46#include <geom/geom.h> 47#include <geom/geom_int.h> 48#include <sys/devicestat.h> 49 50static struct g_bioq g_bio_run_down; 51static struct g_bioq g_bio_run_up; 52static struct g_bioq g_bio_idle; 53 54static u_int pace; 55 56#include <machine/atomic.h> 57 58static void 59g_bioq_lock(struct g_bioq *bq) 60{ 61 62 mtx_lock(&bq->bio_queue_lock); 63} 64 65static void 66g_bioq_unlock(struct g_bioq *bq) 67{ 68 69 mtx_unlock(&bq->bio_queue_lock); 70} 71 72#if 0 73static void 74g_bioq_destroy(struct g_bioq *bq) 75{ 76 77 mtx_destroy(&bq->bio_queue_lock); 78} 79#endif 80 81static void 82g_bioq_init(struct g_bioq *bq) 83{ 84 85 TAILQ_INIT(&bq->bio_queue); 86 mtx_init(&bq->bio_queue_lock, "bio queue", NULL, MTX_DEF); 87} 88 89static struct bio * 90g_bioq_first(struct g_bioq *bq) 91{ 92 struct bio *bp; 93 94 bp = TAILQ_FIRST(&bq->bio_queue); 95 if (bp != NULL) { 96 TAILQ_REMOVE(&bq->bio_queue, bp, bio_queue); 97 bq->bio_queue_length--; 98 } 99 return (bp); 100} 101 102static void 103g_bioq_enqueue_tail(struct bio *bp, struct g_bioq *rq) 104{ 105 106 g_bioq_lock(rq); 107 TAILQ_INSERT_TAIL(&rq->bio_queue, bp, bio_queue); 108 rq->bio_queue_length++; 109 g_bioq_unlock(rq); 110} 111 112struct bio * 113g_new_bio(void) 114{ 115 struct bio *bp; 116 117 g_bioq_lock(&g_bio_idle); 118 bp = g_bioq_first(&g_bio_idle); 119 g_bioq_unlock(&g_bio_idle); 120 if (bp == NULL) 121 bp = g_malloc(sizeof *bp, M_NOWAIT | M_ZERO); 122 /* g_trace(G_T_BIO, "g_new_bio() = %p", bp); */ 123 return (bp); 124} 125 126void 127g_destroy_bio(struct bio *bp) 128{ 129 130 /* g_trace(G_T_BIO, "g_destroy_bio(%p)", bp); */ 131 bzero(bp, sizeof *bp); 132 g_bioq_enqueue_tail(bp, &g_bio_idle); 133} 134 135struct bio * 136g_clone_bio(struct bio *bp) 137{ 138 struct bio *bp2; 139 140 bp2 = g_new_bio(); 141 if (bp2 != NULL) { 142 bp2->bio_parent = bp; 143 bp2->bio_cmd = bp->bio_cmd; 144 bp2->bio_length = bp->bio_length; 145 bp2->bio_offset = bp->bio_offset; 146 bp2->bio_data = bp->bio_data; 147 bp2->bio_attribute = bp->bio_attribute; 148 bp->bio_children++; 149 } 150 /* g_trace(G_T_BIO, "g_clone_bio(%p) = %p", bp, bp2); */ 151 return(bp2); 152} 153 154void 155g_io_init() 156{ 157 158 g_bioq_init(&g_bio_run_down); 159 g_bioq_init(&g_bio_run_up); 160 g_bioq_init(&g_bio_idle); 161} 162 163int 164g_io_getattr(const char *attr, struct g_consumer *cp, int *len, void *ptr) 165{ 166 struct bio *bp; 167 int error; 168 169 g_trace(G_T_BIO, "bio_getattr(%s)", attr); 170 bp = g_new_bio(); 171 bp->bio_cmd = BIO_GETATTR; 172 bp->bio_done = NULL; 173 bp->bio_attribute = attr; 174 bp->bio_length = *len; 175 bp->bio_data = ptr; 176 g_io_request(bp, cp); 177 error = biowait(bp, "ggetattr"); 178 *len = bp->bio_completed; 179 g_destroy_bio(bp); 180 return (error); 181} 182 183static int 184g_io_check(struct bio *bp) 185{ 186 struct g_consumer *cp; 187 struct g_provider *pp; 188 189 cp = bp->bio_from; 190 pp = bp->bio_to; 191 192 /* Fail if access counters dont allow the operation */ 193 switch(bp->bio_cmd) { 194 case BIO_READ: 195 case BIO_GETATTR: 196 if (cp->acr == 0) 197 return (EPERM); 198 break; 199 case BIO_WRITE: 200 case BIO_DELETE: 201 if (cp->acw == 0) 202 return (EPERM); 203 break; 204 default: 205 return (EPERM); 206 } 207 /* if provider is marked for error, don't disturb. */ 208 if (pp->error) 209 return (pp->error); 210 211 switch(bp->bio_cmd) { 212 case BIO_READ: 213 case BIO_WRITE: 214 case BIO_DELETE: 215 /* Reject I/O not on sector boundary */ 216 if (bp->bio_offset % pp->sectorsize) 217 return (EINVAL); 218 /* Reject I/O not integral sector long */ 219 if (bp->bio_length % pp->sectorsize) 220 return (EINVAL); 221 /* Reject requests past the end of media. */ 222 if (bp->bio_offset > pp->mediasize) 223 return (EIO); 224 break; 225 default: 226 break; 227 } 228 return (0); 229} 230 231void 232g_io_request(struct bio *bp, struct g_consumer *cp) 233{ 234 struct g_provider *pp; 235 236 pp = cp->provider; 237 KASSERT(cp != NULL, ("NULL cp in g_io_request")); 238 KASSERT(bp != NULL, ("NULL bp in g_io_request")); 239 KASSERT(bp->bio_data != NULL, ("NULL bp->data in g_io_request")); 240 KASSERT(pp != NULL, ("consumer not attached in g_io_request")); 241 242 bp->bio_from = cp; 243 bp->bio_to = pp; 244 bp->bio_error = 0; 245 bp->bio_completed = 0; 246 247 if (g_collectstats) { 248 devstat_start_transaction_bio(cp->stat, bp); 249 devstat_start_transaction_bio(pp->stat, bp); 250 } 251 cp->nstart++; 252 pp->nstart++; 253 254 /* Pass it on down. */ 255 g_trace(G_T_BIO, "bio_request(%p) from %p(%s) to %p(%s) cmd %d", 256 bp, cp, cp->geom->name, pp, pp->name, bp->bio_cmd); 257 g_bioq_enqueue_tail(bp, &g_bio_run_down); 258 wakeup(&g_wait_down); 259} 260 261void 262g_io_deliver(struct bio *bp, int error) 263{ 264 struct g_consumer *cp; 265 struct g_provider *pp; 266 267 cp = bp->bio_from; 268 pp = bp->bio_to; 269 KASSERT(bp != NULL, ("NULL bp in g_io_deliver")); 270 KASSERT(cp != NULL, ("NULL bio_from in g_io_deliver")); 271 KASSERT(cp->geom != NULL, ("NULL bio_from->geom in g_io_deliver")); 272 KASSERT(pp != NULL, ("NULL bio_to in g_io_deliver")); 273 274 g_trace(G_T_BIO, 275"g_io_deliver(%p) from %p(%s) to %p(%s) cmd %d error %d off %jd len %jd", 276 bp, cp, cp->geom->name, pp, pp->name, bp->bio_cmd, error, 277 (intmax_t)bp->bio_offset, (intmax_t)bp->bio_length); 278 279 bp->bio_bcount = bp->bio_length; 280 if (g_collectstats) { 281 bp->bio_resid = bp->bio_bcount - bp->bio_completed; 282 devstat_end_transaction_bio(cp->stat, bp); 283 devstat_end_transaction_bio(pp->stat, bp); 284 } 285 cp->nend++; 286 pp->nend++; 287 288 if (error == ENOMEM) { 289 printf("ENOMEM %p on %p(%s)\n", bp, pp, pp->name); 290 g_io_request(bp, cp); 291 pace++; 292 return; 293 } 294 bp->bio_error = error; 295 g_bioq_enqueue_tail(bp, &g_bio_run_up); 296 wakeup(&g_wait_up); 297} 298 299void 300g_io_schedule_down(struct thread *tp __unused) 301{ 302 struct bio *bp; 303 off_t excess; 304 int error; 305 struct mtx mymutex; 306 307 bzero(&mymutex, sizeof mymutex); 308 mtx_init(&mymutex, "g_xdown", MTX_DEF, 0); 309 310 for(;;) { 311 g_bioq_lock(&g_bio_run_down); 312 bp = g_bioq_first(&g_bio_run_down); 313 if (bp == NULL) { 314 msleep(&g_wait_down, &g_bio_run_down.bio_queue_lock, 315 PRIBIO | PDROP, "g_down", hz/10); 316 continue; 317 } 318 g_bioq_unlock(&g_bio_run_down); 319 if (pace > 0) { 320 msleep(&error, NULL, PRIBIO, "g_down", hz/10); 321 pace--; 322 } 323 error = g_io_check(bp); 324 if (error) { 325 g_io_deliver(bp, error); 326 continue; 327 } 328 switch (bp->bio_cmd) { 329 case BIO_READ: 330 case BIO_WRITE: 331 case BIO_DELETE: 332 /* Truncate requests to the end of providers media. */ 333 excess = bp->bio_offset + bp->bio_length; 334 if (excess > bp->bio_to->mediasize) { 335 excess -= bp->bio_to->mediasize; 336 bp->bio_length -= excess; 337 } 338 /* Deliver zero length transfers right here. */ 339 if (bp->bio_length == 0) { 340 g_io_deliver(bp, 0); 341 continue; 342 } 343 break; 344 default: 345 break; 346 } 347 mtx_lock(&mymutex); 348 bp->bio_to->geom->start(bp); 349 mtx_unlock(&mymutex); 350 } 351} 352 353void 354g_io_schedule_up(struct thread *tp __unused) 355{ 356 struct bio *bp; 357 struct mtx mymutex; 358 359 bzero(&mymutex, sizeof mymutex); 360 mtx_init(&mymutex, "g_xup", MTX_DEF, 0); 361 for(;;) { 362 g_bioq_lock(&g_bio_run_up); 363 bp = g_bioq_first(&g_bio_run_up); 364 if (bp != NULL) { 365 g_bioq_unlock(&g_bio_run_up); 366 mtx_lock(&mymutex); 367 biodone(bp); 368 mtx_unlock(&mymutex); 369 continue; 370 } 371 msleep(&g_wait_up, &g_bio_run_up.bio_queue_lock, 372 PRIBIO | PDROP, "g_up", hz/10); 373 } 374} 375 376void * 377g_read_data(struct g_consumer *cp, off_t offset, off_t length, int *error) 378{ 379 struct bio *bp; 380 void *ptr; 381 int errorc; 382 383 bp = g_new_bio(); 384 bp->bio_cmd = BIO_READ; 385 bp->bio_done = NULL; 386 bp->bio_offset = offset; 387 bp->bio_length = length; 388 ptr = g_malloc(length, M_WAITOK); 389 bp->bio_data = ptr; 390 g_io_request(bp, cp); 391 errorc = biowait(bp, "gread"); 392 if (error != NULL) 393 *error = errorc; 394 g_destroy_bio(bp); 395 if (errorc) { 396 g_free(ptr); 397 ptr = NULL; 398 } 399 return (ptr); 400} 401 402int 403g_write_data(struct g_consumer *cp, off_t offset, void *ptr, off_t length) 404{ 405 struct bio *bp; 406 int error; 407 408 bp = g_new_bio(); 409 bp->bio_cmd = BIO_WRITE; 410 bp->bio_done = NULL; 411 bp->bio_offset = offset; 412 bp->bio_length = length; 413 bp->bio_data = ptr; 414 g_io_request(bp, cp); 415 error = biowait(bp, "gwrite"); 416 g_destroy_bio(bp); 417 return (error); 418} 419