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-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-2  -  FREEBSD-11-1  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-4  -  FREEBSD-10-3  -  FREEBSD-10-2  -  FREEBSD-10-1  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-3  -  FREEBSD-9-2  -  FREEBSD-9-1  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-4  -  FREEBSD-8-3  -  FREEBSD-8-2  -  FREEBSD-8-1  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-4  -  FREEBSD-7-3  -  FREEBSD-7-2  -  FREEBSD-7-1  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-4  -  FREEBSD-6-3  -  FREEBSD-6-2  -  FREEBSD-6-1  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-5  -  FREEBSD-5-4  -  FREEBSD-5-3  -  FREEBSD-5-2  -  FREEBSD-5-1  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  linux-2.6  -  linux-2.4.22  -  MK83  -  MK84  -  PLAN9  -  DFBSD  -  NETBSD  -  NETBSD5  -  NETBSD4  -  NETBSD3  -  NETBSD20  -  OPENBSD  -  xnu-517  -  xnu-792  -  xnu-792.6.70  -  xnu-1228  -  xnu-1456.1.26  -  xnu-1699.24.8  -  xnu-2050.18.24  -  OPENSOLARIS  -  minix-3-1-1 
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: src/sys/kern/subr_disk.c,v 1.80.4.2 2005/01/31 23:26:17 imp Exp $");
   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         head->switch_point = NULL;
   74 }
   75 
   76 void
   77 bioq_remove(struct bio_queue_head *head, struct bio *bp)
   78 {
   79         if (bp == head->switch_point)
   80                 head->switch_point = TAILQ_NEXT(bp, bio_queue);
   81         if (bp == head->insert_point) {
   82                 head->insert_point = TAILQ_PREV(bp, bio_queue, bio_queue);
   83                 if (head->insert_point == NULL)
   84                         head->last_offset = 0;
   85         } else if (bp == TAILQ_FIRST(&head->queue))
   86                 head->last_offset = bp->bio_offset;
   87         TAILQ_REMOVE(&head->queue, bp, bio_queue);
   88         if (TAILQ_FIRST(&head->queue) == head->switch_point)
   89                 head->switch_point = NULL;
   90 }
   91 
   92 void
   93 bioq_flush(struct bio_queue_head *head, struct devstat *stp, int error)
   94 {
   95         struct bio *bp;
   96 
   97         for (;;) {
   98                 bp = bioq_first(head);
   99                 if (bp == NULL)
  100                         break;
  101                 bioq_remove(head, bp);
  102                 biofinish(bp, stp, error);
  103         }
  104 }
  105 
  106 void
  107 bioq_insert_head(struct bio_queue_head *head, struct bio *bp)
  108 {
  109 
  110         TAILQ_INSERT_HEAD(&head->queue, bp, bio_queue);
  111 }
  112 
  113 void
  114 bioq_insert_tail(struct bio_queue_head *head, struct bio *bp)
  115 {
  116 
  117         TAILQ_INSERT_TAIL(&head->queue, bp, bio_queue);
  118 }
  119 
  120 struct bio *
  121 bioq_first(struct bio_queue_head *head)
  122 {
  123 
  124         return (TAILQ_FIRST(&head->queue));
  125 }
  126 
  127 
  128 /*
  129  * Seek sort for disks.
  130  *
  131  * The buf_queue keep two queues, sorted in ascending block order.  The first
  132  * queue holds those requests which are positioned after the current block
  133  * (in the first request); the second, which starts at queue->switch_point,
  134  * holds requests which came in after their block number was passed.  Thus
  135  * we implement a one way scan, retracting after reaching the end of the drive
  136  * to the first request on the second queue, at which time it becomes the
  137  * first queue.
  138  *
  139  * A one-way scan is natural because of the way UNIX read-ahead blocks are
  140  * allocated.
  141  */
  142 
  143 void
  144 bioq_disksort(bioq, bp)
  145         struct bio_queue_head *bioq;
  146         struct bio *bp;
  147 {
  148         struct bio *bq;
  149         struct bio *bn;
  150         struct bio *be;
  151 
  152         be = TAILQ_LAST(&bioq->queue, bio_queue);
  153         /*
  154          * If the queue is empty or we are an
  155          * ordered transaction, then it's easy.
  156          */
  157         if ((bq = bioq_first(bioq)) == NULL) {
  158                 bioq_insert_tail(bioq, bp);
  159                 return;
  160         } else if (bioq->insert_point != NULL) {
  161 
  162                 /*
  163                  * A certain portion of the list is
  164                  * "locked" to preserve ordering, so
  165                  * we can only insert after the insert
  166                  * point.
  167                  */
  168                 bq = bioq->insert_point;
  169         } else {
  170 
  171                 /*
  172                  * If we lie before the last removed (currently active)
  173                  * request, and are not inserting ourselves into the
  174                  * "locked" portion of the list, then we must add ourselves
  175                  * to the second request list.
  176                  */
  177                 if (bp->bio_offset < bioq->last_offset) {
  178 
  179                         bq = bioq->switch_point;
  180                         /*
  181                          * If we are starting a new secondary list,
  182                          * then it's easy.
  183                          */
  184                         if (bq == NULL) {
  185                                 bioq->switch_point = bp;
  186                                 bioq_insert_tail(bioq, bp);
  187                                 return;
  188                         }
  189                         /*
  190                          * If we lie ahead of the current switch point,
  191                          * insert us before the switch point and move
  192                          * the switch point.
  193                          */
  194                         if (bp->bio_offset < bq->bio_offset) {
  195                                 bioq->switch_point = bp;
  196                                 TAILQ_INSERT_BEFORE(bq, bp, bio_queue);
  197                                 return;
  198                         }
  199                 } else {
  200                         if (bioq->switch_point != NULL)
  201                                 be = TAILQ_PREV(bioq->switch_point,
  202                                                 bio_queue, bio_queue);
  203                         /*
  204                          * If we lie between last_offset and bq,
  205                          * insert before bq.
  206                          */
  207                         if (bp->bio_offset < bq->bio_offset) {
  208                                 TAILQ_INSERT_BEFORE(bq, bp, bio_queue);
  209                                 return;
  210                         }
  211                 }
  212         }
  213 
  214         /*
  215          * Request is at/after our current position in the list.
  216          * Optimize for sequential I/O by seeing if we go at the tail.
  217          */
  218         if (bp->bio_offset > be->bio_offset) {
  219                 TAILQ_INSERT_AFTER(&bioq->queue, be, bp, bio_queue);
  220                 return;
  221         }
  222 
  223         /* Otherwise, insertion sort */
  224         while ((bn = TAILQ_NEXT(bq, bio_queue)) != NULL) {
  225                 
  226                 /*
  227                  * We want to go after the current request if it is the end
  228                  * of the first request list, or if the next request is a
  229                  * larger cylinder than our request.
  230                  */
  231                 if (bn == bioq->switch_point
  232                  || bp->bio_offset < bn->bio_offset)
  233                         break;
  234                 bq = bn;
  235         }
  236         TAILQ_INSERT_AFTER(&bioq->queue, bq, bp, bio_queue);
  237 }
  238 
  239 

Cache object: 6663cc7047f2f8a37444b456f5bae319


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