The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/geom/geom_io.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    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: releng/5.1/sys/geom/geom_io.c 114795 2003-05-07 05:37:31Z 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 
   50 #include <vm/uma.h>
   51 
   52 static struct g_bioq g_bio_run_down;
   53 static struct g_bioq g_bio_run_up;
   54 
   55 static u_int pace;
   56 static uma_zone_t       biozone;
   57 
   58 #include <machine/atomic.h>
   59 
   60 static void
   61 g_bioq_lock(struct g_bioq *bq)
   62 {
   63 
   64         mtx_lock(&bq->bio_queue_lock);
   65 }
   66 
   67 static void
   68 g_bioq_unlock(struct g_bioq *bq)
   69 {
   70 
   71         mtx_unlock(&bq->bio_queue_lock);
   72 }
   73 
   74 #if 0
   75 static void
   76 g_bioq_destroy(struct g_bioq *bq)
   77 {
   78 
   79         mtx_destroy(&bq->bio_queue_lock);
   80 }
   81 #endif
   82 
   83 static void
   84 g_bioq_init(struct g_bioq *bq)
   85 {
   86 
   87         TAILQ_INIT(&bq->bio_queue);
   88         mtx_init(&bq->bio_queue_lock, "bio queue", NULL, MTX_DEF);
   89 }
   90 
   91 static struct bio *
   92 g_bioq_first(struct g_bioq *bq)
   93 {
   94         struct bio *bp;
   95 
   96         bp = TAILQ_FIRST(&bq->bio_queue);
   97         if (bp != NULL) {
   98                 TAILQ_REMOVE(&bq->bio_queue, bp, bio_queue);
   99                 bq->bio_queue_length--;
  100         }
  101         return (bp);
  102 }
  103 
  104 static void
  105 g_bioq_enqueue_tail(struct bio *bp, struct g_bioq *rq)
  106 {
  107 
  108         g_bioq_lock(rq);
  109         TAILQ_INSERT_TAIL(&rq->bio_queue, bp, bio_queue);
  110         rq->bio_queue_length++;
  111         g_bioq_unlock(rq);
  112 }
  113 
  114 struct bio *
  115 g_new_bio(void)
  116 {
  117         struct bio *bp;
  118 
  119         bp = uma_zalloc(biozone, M_NOWAIT | M_ZERO);
  120         return (bp);
  121 }
  122 
  123 void
  124 g_destroy_bio(struct bio *bp)
  125 {
  126 
  127         uma_zfree(biozone, bp);
  128 }
  129 
  130 struct bio *
  131 g_clone_bio(struct bio *bp)
  132 {
  133         struct bio *bp2;
  134 
  135         bp2 = uma_zalloc(biozone, M_NOWAIT | M_ZERO);
  136         if (bp2 != NULL) {
  137                 bp2->bio_parent = bp;
  138                 bp2->bio_cmd = bp->bio_cmd;
  139                 bp2->bio_length = bp->bio_length;
  140                 bp2->bio_offset = bp->bio_offset;
  141                 bp2->bio_data = bp->bio_data;
  142                 bp2->bio_attribute = bp->bio_attribute;
  143                 bp->bio_children++;
  144         }
  145         return(bp2);
  146 }
  147 
  148 void
  149 g_io_init()
  150 {
  151 
  152         g_bioq_init(&g_bio_run_down);
  153         g_bioq_init(&g_bio_run_up);
  154         biozone = uma_zcreate("g_bio", sizeof (struct bio),
  155             NULL, NULL,
  156             NULL, NULL,
  157             0, 0);
  158 }
  159 
  160 int
  161 g_io_getattr(const char *attr, struct g_consumer *cp, int *len, void *ptr)
  162 {
  163         struct bio *bp;
  164         int error;
  165 
  166         g_trace(G_T_BIO, "bio_getattr(%s)", attr);
  167         bp = g_new_bio();
  168         bp->bio_cmd = BIO_GETATTR;
  169         bp->bio_done = NULL;
  170         bp->bio_attribute = attr;
  171         bp->bio_length = *len;
  172         bp->bio_data = ptr;
  173         g_io_request(bp, cp);
  174         error = biowait(bp, "ggetattr");
  175         *len = bp->bio_completed;
  176         g_destroy_bio(bp);
  177         return (error);
  178 }
  179 
  180 static int
  181 g_io_check(struct bio *bp)
  182 {
  183         struct g_consumer *cp;
  184         struct g_provider *pp;
  185 
  186         cp = bp->bio_from;
  187         pp = bp->bio_to;
  188 
  189         /* Fail if access counters dont allow the operation */
  190         switch(bp->bio_cmd) {
  191         case BIO_READ:
  192         case BIO_GETATTR:
  193                 if (cp->acr == 0)
  194                         return (EPERM);
  195                 break;
  196         case BIO_WRITE:
  197         case BIO_DELETE:
  198                 if (cp->acw == 0)
  199                         return (EPERM);
  200                 break;
  201         default:
  202                 return (EPERM);
  203         }
  204         /* if provider is marked for error, don't disturb. */
  205         if (pp->error)
  206                 return (pp->error);
  207 
  208         switch(bp->bio_cmd) {
  209         case BIO_READ:
  210         case BIO_WRITE:
  211         case BIO_DELETE:
  212                 /* Reject I/O not on sector boundary */
  213                 if (bp->bio_offset % pp->sectorsize)
  214                         return (EINVAL);
  215                 /* Reject I/O not integral sector long */
  216                 if (bp->bio_length % pp->sectorsize)
  217                         return (EINVAL);
  218                 /* Reject requests past the end of media. */
  219                 if (bp->bio_offset > pp->mediasize)
  220                         return (EIO);
  221                 break;
  222         default:
  223                 break;
  224         }
  225         return (0);
  226 }
  227 
  228 void
  229 g_io_request(struct bio *bp, struct g_consumer *cp)
  230 {
  231         struct g_provider *pp;
  232 
  233         pp = cp->provider;
  234         KASSERT(cp != NULL, ("NULL cp in g_io_request"));
  235         KASSERT(bp != NULL, ("NULL bp in g_io_request"));
  236         KASSERT(bp->bio_data != NULL, ("NULL bp->data in g_io_request"));
  237         KASSERT(pp != NULL, ("consumer not attached in g_io_request"));
  238 
  239         bp->bio_from = cp;
  240         bp->bio_to = pp;
  241         bp->bio_error = 0;
  242         bp->bio_completed = 0;
  243 
  244         if (g_collectstats) {
  245                 devstat_start_transaction_bio(cp->stat, bp);
  246                 devstat_start_transaction_bio(pp->stat, bp);
  247         }
  248         cp->nstart++;
  249         pp->nstart++;
  250 
  251         /* Pass it on down. */
  252         g_trace(G_T_BIO, "bio_request(%p) from %p(%s) to %p(%s) cmd %d",
  253             bp, cp, cp->geom->name, pp, pp->name, bp->bio_cmd);
  254         g_bioq_enqueue_tail(bp, &g_bio_run_down);
  255         wakeup(&g_wait_down);
  256 }
  257 
  258 void
  259 g_io_deliver(struct bio *bp, int error)
  260 {
  261         struct g_consumer *cp;
  262         struct g_provider *pp;
  263 
  264         cp = bp->bio_from;
  265         pp = bp->bio_to;
  266         KASSERT(bp != NULL, ("NULL bp in g_io_deliver"));
  267         KASSERT(cp != NULL, ("NULL bio_from in g_io_deliver"));
  268         KASSERT(cp->geom != NULL, ("NULL bio_from->geom in g_io_deliver"));
  269         KASSERT(pp != NULL, ("NULL bio_to in g_io_deliver"));
  270 
  271         g_trace(G_T_BIO,
  272 "g_io_deliver(%p) from %p(%s) to %p(%s) cmd %d error %d off %jd len %jd",
  273             bp, cp, cp->geom->name, pp, pp->name, bp->bio_cmd, error,
  274             (intmax_t)bp->bio_offset, (intmax_t)bp->bio_length);
  275 
  276         bp->bio_bcount = bp->bio_length;
  277         if (g_collectstats) {
  278                 bp->bio_resid = bp->bio_bcount - bp->bio_completed;
  279                 devstat_end_transaction_bio(cp->stat, bp);
  280                 devstat_end_transaction_bio(pp->stat, bp);
  281         }
  282         cp->nend++;
  283         pp->nend++;
  284 
  285         if (error == ENOMEM) {
  286                 if (bootverbose)
  287                         printf("ENOMEM %p on %p(%s)\n", bp, pp, pp->name);
  288                 g_io_request(bp, cp);
  289                 pace++;
  290                 return;
  291         }
  292         bp->bio_error = error;
  293         g_bioq_enqueue_tail(bp, &g_bio_run_up);
  294         wakeup(&g_wait_up);
  295 }
  296 
  297 void
  298 g_io_schedule_down(struct thread *tp __unused)
  299 {
  300         struct bio *bp;
  301         off_t excess;
  302         int error;
  303         struct mtx mymutex;
  304  
  305         bzero(&mymutex, sizeof mymutex);
  306         mtx_init(&mymutex, "g_xdown", MTX_DEF, 0);
  307 
  308         for(;;) {
  309                 g_bioq_lock(&g_bio_run_down);
  310                 bp = g_bioq_first(&g_bio_run_down);
  311                 if (bp == NULL) {
  312                         msleep(&g_wait_down, &g_bio_run_down.bio_queue_lock,
  313                             PRIBIO | PDROP, "g_down", hz/10);
  314                         continue;
  315                 }
  316                 g_bioq_unlock(&g_bio_run_down);
  317                 if (pace > 0) {
  318                         msleep(&error, NULL, PRIBIO, "g_down", hz/10);
  319                         pace--;
  320                 }
  321                 error = g_io_check(bp);
  322                 if (error) {
  323                         g_io_deliver(bp, error);
  324                         continue;
  325                 }
  326                 switch (bp->bio_cmd) {
  327                 case BIO_READ:
  328                 case BIO_WRITE:
  329                 case BIO_DELETE:
  330                         /* Truncate requests to the end of providers media. */
  331                         excess = bp->bio_offset + bp->bio_length;
  332                         if (excess > bp->bio_to->mediasize) {
  333                                 excess -= bp->bio_to->mediasize;
  334                                 bp->bio_length -= excess;
  335                         }
  336                         /* Deliver zero length transfers right here. */
  337                         if (bp->bio_length == 0) {
  338                                 g_io_deliver(bp, 0);
  339                                 continue;
  340                         }
  341                         break;
  342                 default:
  343                         break;
  344                 }
  345                 mtx_lock(&mymutex);
  346                 bp->bio_to->geom->start(bp);
  347                 mtx_unlock(&mymutex);
  348         }
  349 }
  350 
  351 void
  352 g_io_schedule_up(struct thread *tp __unused)
  353 {
  354         struct bio *bp;
  355         struct mtx mymutex;
  356  
  357         bzero(&mymutex, sizeof mymutex);
  358         mtx_init(&mymutex, "g_xup", MTX_DEF, 0);
  359         for(;;) {
  360                 g_bioq_lock(&g_bio_run_up);
  361                 bp = g_bioq_first(&g_bio_run_up);
  362                 if (bp != NULL) {
  363                         g_bioq_unlock(&g_bio_run_up);
  364                         mtx_lock(&mymutex);
  365                         biodone(bp);
  366                         mtx_unlock(&mymutex);
  367                         continue;
  368                 }
  369                 msleep(&g_wait_up, &g_bio_run_up.bio_queue_lock,
  370                     PRIBIO | PDROP, "g_up", hz/10);
  371         }
  372 }
  373 
  374 void *
  375 g_read_data(struct g_consumer *cp, off_t offset, off_t length, int *error)
  376 {
  377         struct bio *bp;
  378         void *ptr;
  379         int errorc;
  380 
  381         bp = g_new_bio();
  382         bp->bio_cmd = BIO_READ;
  383         bp->bio_done = NULL;
  384         bp->bio_offset = offset;
  385         bp->bio_length = length;
  386         ptr = g_malloc(length, M_WAITOK);
  387         bp->bio_data = ptr;
  388         g_io_request(bp, cp);
  389         errorc = biowait(bp, "gread");
  390         if (error != NULL)
  391                 *error = errorc;
  392         g_destroy_bio(bp);
  393         if (errorc) {
  394                 g_free(ptr);
  395                 ptr = NULL;
  396         }
  397         return (ptr);
  398 }
  399 
  400 int
  401 g_write_data(struct g_consumer *cp, off_t offset, void *ptr, off_t length)
  402 {
  403         struct bio *bp;
  404         int error;
  405 
  406         bp = g_new_bio();
  407         bp->bio_cmd = BIO_WRITE;
  408         bp->bio_done = NULL;
  409         bp->bio_offset = offset;
  410         bp->bio_length = length;
  411         bp->bio_data = ptr;
  412         g_io_request(bp, cp);
  413         error = biowait(bp, "gwrite");
  414         g_destroy_bio(bp);
  415         return (error);
  416 }

Cache object: 7b6422e787c114e08aa38cae651643b5


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.