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/5.3/sys/kern/subr_disk.c 136588 2004-10-16 08:43:07Z cvs2svn $");
   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_tail(struct bio_queue_head *head, struct bio *bp)
  108 {
  109 
  110         TAILQ_INSERT_TAIL(&head->queue, bp, bio_queue);
  111 }
  112 
  113 struct bio *
  114 bioq_first(struct bio_queue_head *head)
  115 {
  116 
  117         return (TAILQ_FIRST(&head->queue));
  118 }
  119 
  120 
  121 /*
  122  * Seek sort for disks.
  123  *
  124  * The buf_queue keep two queues, sorted in ascending block order.  The first
  125  * queue holds those requests which are positioned after the current block
  126  * (in the first request); the second, which starts at queue->switch_point,
  127  * holds requests which came in after their block number was passed.  Thus
  128  * we implement a one way scan, retracting after reaching the end of the drive
  129  * to the first request on the second queue, at which time it becomes the
  130  * first queue.
  131  *
  132  * A one-way scan is natural because of the way UNIX read-ahead blocks are
  133  * allocated.
  134  */
  135 
  136 void
  137 bioq_disksort(bioq, bp)
  138         struct bio_queue_head *bioq;
  139         struct bio *bp;
  140 {
  141         struct bio *bq;
  142         struct bio *bn;
  143         struct bio *be;
  144 
  145         be = TAILQ_LAST(&bioq->queue, bio_queue);
  146         /*
  147          * If the queue is empty or we are an
  148          * ordered transaction, then it's easy.
  149          */
  150         if ((bq = bioq_first(bioq)) == NULL) {
  151                 bioq_insert_tail(bioq, bp);
  152                 return;
  153         } else if (bioq->insert_point != NULL) {
  154 
  155                 /*
  156                  * A certain portion of the list is
  157                  * "locked" to preserve ordering, so
  158                  * we can only insert after the insert
  159                  * point.
  160                  */
  161                 bq = bioq->insert_point;
  162         } else {
  163 
  164                 /*
  165                  * If we lie before the last removed (currently active)
  166                  * request, and are not inserting ourselves into the
  167                  * "locked" portion of the list, then we must add ourselves
  168                  * to the second request list.
  169                  */
  170                 if (bp->bio_offset < bioq->last_offset) {
  171 
  172                         bq = bioq->switch_point;
  173                         /*
  174                          * If we are starting a new secondary list,
  175                          * then it's easy.
  176                          */
  177                         if (bq == NULL) {
  178                                 bioq->switch_point = bp;
  179                                 bioq_insert_tail(bioq, bp);
  180                                 return;
  181                         }
  182                         /*
  183                          * If we lie ahead of the current switch point,
  184                          * insert us before the switch point and move
  185                          * the switch point.
  186                          */
  187                         if (bp->bio_offset < bq->bio_offset) {
  188                                 bioq->switch_point = bp;
  189                                 TAILQ_INSERT_BEFORE(bq, bp, bio_queue);
  190                                 return;
  191                         }
  192                 } else {
  193                         if (bioq->switch_point != NULL)
  194                                 be = TAILQ_PREV(bioq->switch_point,
  195                                                 bio_queue, bio_queue);
  196                         /*
  197                          * If we lie between last_offset and bq,
  198                          * insert before bq.
  199                          */
  200                         if (bp->bio_offset < bq->bio_offset) {
  201                                 TAILQ_INSERT_BEFORE(bq, bp, bio_queue);
  202                                 return;
  203                         }
  204                 }
  205         }
  206 
  207         /*
  208          * Request is at/after our current position in the list.
  209          * Optimize for sequential I/O by seeing if we go at the tail.
  210          */
  211         if (bp->bio_offset > be->bio_offset) {
  212                 TAILQ_INSERT_AFTER(&bioq->queue, be, bp, bio_queue);
  213                 return;
  214         }
  215 
  216         /* Otherwise, insertion sort */
  217         while ((bn = TAILQ_NEXT(bq, bio_queue)) != NULL) {
  218                 
  219                 /*
  220                  * We want to go after the current request if it is the end
  221                  * of the first request list, or if the next request is a
  222                  * larger cylinder than our request.
  223                  */
  224                 if (bn == bioq->switch_point
  225                  || bp->bio_offset < bn->bio_offset)
  226                         break;
  227                 bq = bn;
  228         }
  229         TAILQ_INSERT_AFTER(&bioq->queue, bq, bp, bio_queue);
  230 }
  231 
  232 

Cache object: 6beccaaeae50b7d42549416d99ef2686


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