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/kern/subr_disk.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  * ----------------------------------------------------------------------------
    3  * "THE BEER-WARE LICENSE" (Revision 42):
    4  * <phk@FreeBSD.ORG> wrote this file.  As long as you retain this notice you
    5  * can do whatever you want with this stuff. If we meet some day, and you think
    6  * this stuff is worth it, you can buy me a beer in return.   Poul-Henning Kamp
    7  * ----------------------------------------------------------------------------
    8  */
    9 
   10 #include <sys/cdefs.h>
   11 __FBSDID("$FreeBSD: releng/6.4/sys/kern/subr_disk.c 155642 2006-02-14 03:29:31Z rwatson $");
   12 
   13 #include "opt_geom.h"
   14 
   15 #include <sys/param.h>
   16 #include <sys/systm.h>
   17 #include <sys/bio.h>
   18 #include <sys/conf.h>
   19 #include <sys/disk.h>
   20 #include <geom/geom_disk.h>
   21 
   22 /*-
   23  * Disk error is the preface to plaintive error messages
   24  * about failing disk transfers.  It prints messages of the form
   25  *      "hp0g: BLABLABLA cmd=read fsbn 12345 of 12344-12347"
   26  * blkdone should be -1 if the position of the error is unknown.
   27  * The message is printed with printf.
   28  */
   29 void
   30 disk_err(struct bio *bp, const char *what, int blkdone, int nl)
   31 {
   32         daddr_t sn;
   33 
   34         if (bp->bio_dev != NULL)
   35                 printf("%s: %s ", devtoname(bp->bio_dev), what);
   36         else if (bp->bio_disk != NULL)
   37                 printf("%s%d: %s ",
   38                     bp->bio_disk->d_name, bp->bio_disk->d_unit, what);
   39         else
   40                 printf("disk??: %s ", what);
   41         switch(bp->bio_cmd) {
   42         case BIO_READ:          printf("cmd=read "); break;
   43         case BIO_WRITE:         printf("cmd=write "); break;
   44         case BIO_DELETE:        printf("cmd=delete "); break;
   45         case BIO_GETATTR:       printf("cmd=getattr "); break;
   46         default:                printf("cmd=%x ", bp->bio_cmd); break;
   47         }
   48         sn = bp->bio_pblkno;
   49         if (bp->bio_bcount <= DEV_BSIZE) {
   50                 printf("fsbn %jd%s", (intmax_t)sn, nl ? "\n" : "");
   51                 return;
   52         }
   53         if (blkdone >= 0) {
   54                 sn += blkdone;
   55                 printf("fsbn %jd of ", (intmax_t)sn);
   56         }
   57         printf("%jd-%jd", (intmax_t)bp->bio_pblkno,
   58             (intmax_t)(bp->bio_pblkno + (bp->bio_bcount - 1) / DEV_BSIZE));
   59         if (nl)
   60                 printf("\n");
   61 }
   62 
   63 /*
   64  * BIO queue implementation
   65  */
   66 
   67 void
   68 bioq_init(struct bio_queue_head *head)
   69 {
   70         TAILQ_INIT(&head->queue);
   71         head->last_offset = 0;
   72         head->insert_point = NULL;
   73 }
   74 
   75 void
   76 bioq_remove(struct bio_queue_head *head, struct bio *bp)
   77 {
   78         if (bp == head->insert_point) {
   79                 head->last_offset = bp->bio_offset;
   80                 head->insert_point = TAILQ_NEXT(bp, bio_queue);
   81                 if (head->insert_point == NULL) {
   82                         head->last_offset = 0;
   83                         head->insert_point = TAILQ_FIRST(&head->queue);
   84                 }
   85         }
   86         TAILQ_REMOVE(&head->queue, bp, bio_queue);
   87 }
   88 
   89 void
   90 bioq_flush(struct bio_queue_head *head, struct devstat *stp, int error)
   91 {
   92         struct bio *bp;
   93 
   94         while ((bp = bioq_takefirst(head)) != NULL)
   95                 biofinish(bp, stp, error);
   96 }
   97 
   98 void
   99 bioq_insert_head(struct bio_queue_head *head, struct bio *bp)
  100 {
  101 
  102         if (TAILQ_FIRST(&head->queue) == NULL)
  103                 head->insert_point = bp;
  104         TAILQ_INSERT_HEAD(&head->queue, bp, bio_queue);
  105 }
  106 
  107 void
  108 bioq_insert_tail(struct bio_queue_head *head, struct bio *bp)
  109 {
  110 
  111         if (TAILQ_FIRST(&head->queue) == NULL)
  112                 head->insert_point = bp;
  113         TAILQ_INSERT_TAIL(&head->queue, bp, bio_queue);
  114 }
  115 
  116 struct bio *
  117 bioq_first(struct bio_queue_head *head)
  118 {
  119 
  120         return (TAILQ_FIRST(&head->queue));
  121 }
  122 
  123 struct bio *
  124 bioq_takefirst(struct bio_queue_head *head)
  125 {
  126         struct bio *bp;
  127 
  128         bp = TAILQ_FIRST(&head->queue);
  129         if (bp != NULL)
  130                 bioq_remove(head, bp);
  131         return (bp);
  132 }
  133 
  134 /*
  135  * Seek sort for disks.
  136  *
  137  * The disksort algorithm sorts all requests in a single queue while keeping
  138  * track of the current position of the disk with insert_point and
  139  * last_offset.  last_offset is the offset of the last block sent to disk, or
  140  * 0 once we reach the end.  insert_point points to the first buf after
  141  * last_offset, and is used to slightly speed up insertions.  Blocks are
  142  * always sorted in ascending order and the queue always restarts at 0.
  143  * This implements the one-way scan which optimizes disk seek times.
  144  */
  145 void
  146 bioq_disksort(bioq, bp)
  147         struct bio_queue_head *bioq;
  148         struct bio *bp;
  149 {
  150         struct bio *bq;
  151         struct bio *bn;
  152 
  153         /*
  154          * If the queue is empty then it's easy.
  155          */
  156         if (bioq_first(bioq) == NULL) {
  157                 bioq_insert_tail(bioq, bp);
  158                 return;
  159         }
  160         /*
  161          * Optimize for sequential I/O by seeing if we go at the tail.
  162          */
  163         bq = TAILQ_LAST(&bioq->queue, bio_queue);
  164         if (bp->bio_offset > bq->bio_offset) {
  165                 TAILQ_INSERT_AFTER(&bioq->queue, bq, bp, bio_queue);
  166                 return;
  167         }
  168         /*
  169          * Pick our scan start based on the last request.  A poor man's
  170          * binary search.
  171          */
  172         if (bp->bio_offset >= bioq->last_offset) { 
  173                 bq = bioq->insert_point;
  174                 /*
  175                  * If we're before the next bio and after the last offset,
  176                  * update insert_point;
  177                  */
  178                 if (bp->bio_offset < bq->bio_offset) {
  179                         bioq->insert_point = bp;
  180                         TAILQ_INSERT_BEFORE(bq, bp, bio_queue);
  181                         return;
  182                 }
  183         } else
  184                 bq = TAILQ_FIRST(&bioq->queue);
  185         if (bp->bio_offset < bq->bio_offset) {
  186                 TAILQ_INSERT_BEFORE(bq, bp, bio_queue);
  187                 return;
  188         }
  189         /* Insertion sort */
  190         while ((bn = TAILQ_NEXT(bq, bio_queue)) != NULL) {
  191                 if (bp->bio_offset < bn->bio_offset)
  192                         break;
  193                 bq = bn;
  194         }
  195         TAILQ_INSERT_AFTER(&bioq->queue, bq, bp, bio_queue);
  196 }

Cache object: d5303080aae883b1847c4cf421cb1e77


[ 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.