fkvm_get_regs: missing break in switch statement
[freebsd-src/fkvm-freebsd.git] / sys / kern / subr_disk.c
blobc8ed9ced60726cd769a1ff05fb7960c7d700ea7f
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 */
10 #include <sys/cdefs.h>
11 __FBSDID("$FreeBSD$");
13 #include "opt_geom.h"
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>
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.
29 void
30 disk_err(struct bio *bp, const char *what, int blkdone, int nl)
32 daddr_t sn;
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 case BIO_FLUSH: printf("cmd=flush "); break;
47 default: printf("cmd=%x ", bp->bio_cmd); break;
49 sn = bp->bio_pblkno;
50 if (bp->bio_bcount <= DEV_BSIZE) {
51 printf("fsbn %jd%s", (intmax_t)sn, nl ? "\n" : "");
52 return;
54 if (blkdone >= 0) {
55 sn += blkdone;
56 printf("fsbn %jd of ", (intmax_t)sn);
58 printf("%jd-%jd", (intmax_t)bp->bio_pblkno,
59 (intmax_t)(bp->bio_pblkno + (bp->bio_bcount - 1) / DEV_BSIZE));
60 if (nl)
61 printf("\n");
65 * BIO queue implementation
68 void
69 bioq_init(struct bio_queue_head *head)
71 TAILQ_INIT(&head->queue);
72 head->last_offset = 0;
73 head->insert_point = NULL;
76 void
77 bioq_remove(struct bio_queue_head *head, struct bio *bp)
79 if (bp == head->insert_point) {
80 head->last_offset = bp->bio_offset;
81 head->insert_point = TAILQ_NEXT(bp, bio_queue);
82 if (head->insert_point == NULL) {
83 head->last_offset = 0;
84 head->insert_point = TAILQ_FIRST(&head->queue);
87 TAILQ_REMOVE(&head->queue, bp, bio_queue);
90 void
91 bioq_flush(struct bio_queue_head *head, struct devstat *stp, int error)
93 struct bio *bp;
95 while ((bp = bioq_takefirst(head)) != NULL)
96 biofinish(bp, stp, error);
99 void
100 bioq_insert_head(struct bio_queue_head *head, struct bio *bp)
103 if (TAILQ_EMPTY(&head->queue))
104 head->insert_point = bp;
105 TAILQ_INSERT_HEAD(&head->queue, bp, bio_queue);
108 void
109 bioq_insert_tail(struct bio_queue_head *head, struct bio *bp)
112 if (TAILQ_EMPTY(&head->queue))
113 head->insert_point = bp;
114 TAILQ_INSERT_TAIL(&head->queue, bp, bio_queue);
117 struct bio *
118 bioq_first(struct bio_queue_head *head)
121 return (TAILQ_FIRST(&head->queue));
124 struct bio *
125 bioq_takefirst(struct bio_queue_head *head)
127 struct bio *bp;
129 bp = TAILQ_FIRST(&head->queue);
130 if (bp != NULL)
131 bioq_remove(head, bp);
132 return (bp);
136 * Seek sort for disks.
138 * The disksort algorithm sorts all requests in a single queue while keeping
139 * track of the current position of the disk with insert_point and
140 * last_offset. last_offset is the offset of the last block sent to disk, or
141 * 0 once we reach the end. insert_point points to the first buf after
142 * last_offset, and is used to slightly speed up insertions. Blocks are
143 * always sorted in ascending order and the queue always restarts at 0.
144 * This implements the one-way scan which optimizes disk seek times.
146 void
147 bioq_disksort(bioq, bp)
148 struct bio_queue_head *bioq;
149 struct bio *bp;
151 struct bio *bq;
152 struct bio *bn;
155 * If the queue is empty then it's easy.
157 if (bioq_first(bioq) == NULL) {
158 bioq_insert_tail(bioq, bp);
159 return;
162 * Optimize for sequential I/O by seeing if we go at the tail.
164 bq = TAILQ_LAST(&bioq->queue, bio_queue);
165 if (bp->bio_offset > bq->bio_offset) {
166 TAILQ_INSERT_AFTER(&bioq->queue, bq, bp, bio_queue);
167 return;
170 * Pick our scan start based on the last request. A poor man's
171 * binary search.
173 if (bp->bio_offset >= bioq->last_offset) {
174 bq = bioq->insert_point;
176 * If we're before the next bio and after the last offset,
177 * update insert_point;
179 if (bp->bio_offset < bq->bio_offset) {
180 bioq->insert_point = bp;
181 TAILQ_INSERT_BEFORE(bq, bp, bio_queue);
182 return;
184 } else
185 bq = TAILQ_FIRST(&bioq->queue);
186 if (bp->bio_offset < bq->bio_offset) {
187 TAILQ_INSERT_BEFORE(bq, bp, bio_queue);
188 return;
190 /* Insertion sort */
191 while ((bn = TAILQ_NEXT(bq, bio_queue)) != NULL) {
192 if (bp->bio_offset < bn->bio_offset)
193 break;
194 bq = bn;
196 TAILQ_INSERT_AFTER(&bioq->queue, bq, bp, bio_queue);