19454b2d8SWarner Losh /*- 2da9e4f55SPoul-Henning Kamp * ---------------------------------------------------------------------------- 3da9e4f55SPoul-Henning Kamp * "THE BEER-WARE LICENSE" (Revision 42): 4da9e4f55SPoul-Henning Kamp * <phk@FreeBSD.ORG> wrote this file. As long as you retain this notice you 5da9e4f55SPoul-Henning Kamp * can do whatever you want with this stuff. If we meet some day, and you think 6da9e4f55SPoul-Henning Kamp * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp 7da9e4f55SPoul-Henning Kamp * ---------------------------------------------------------------------------- 8da9e4f55SPoul-Henning Kamp */ 9da9e4f55SPoul-Henning Kamp 10677b542eSDavid E. O'Brien #include <sys/cdefs.h> 11677b542eSDavid E. O'Brien __FBSDID("$FreeBSD$"); 12677b542eSDavid E. O'Brien 13417fb7f6SPoul-Henning Kamp #include "opt_geom.h" 14417fb7f6SPoul-Henning Kamp 15da9e4f55SPoul-Henning Kamp #include <sys/param.h> 16da9e4f55SPoul-Henning Kamp #include <sys/systm.h> 179626b608SPoul-Henning Kamp #include <sys/bio.h> 18da9e4f55SPoul-Henning Kamp #include <sys/conf.h> 19da9e4f55SPoul-Henning Kamp #include <sys/disk.h> 2081750927SPoul-Henning Kamp #include <geom/geom_disk.h> 21f90c382cSPoul-Henning Kamp 22f90c382cSPoul-Henning Kamp /*- 23f90c382cSPoul-Henning Kamp * Disk error is the preface to plaintive error messages 24f90c382cSPoul-Henning Kamp * about failing disk transfers. It prints messages of the form 25f90c382cSPoul-Henning Kamp * "hp0g: BLABLABLA cmd=read fsbn 12345 of 12344-12347" 26f90c382cSPoul-Henning Kamp * blkdone should be -1 if the position of the error is unknown. 27f90c382cSPoul-Henning Kamp * The message is printed with printf. 28f90c382cSPoul-Henning Kamp */ 29f90c382cSPoul-Henning Kamp void 30f90c382cSPoul-Henning Kamp disk_err(struct bio *bp, const char *what, int blkdone, int nl) 31f90c382cSPoul-Henning Kamp { 32f90c382cSPoul-Henning Kamp daddr_t sn; 33f90c382cSPoul-Henning Kamp 34a9463ba8SPoul-Henning Kamp if (bp->bio_dev != NULL) 35f90c382cSPoul-Henning Kamp printf("%s: %s ", devtoname(bp->bio_dev), what); 36a9463ba8SPoul-Henning Kamp else if (bp->bio_disk != NULL) 37a9463ba8SPoul-Henning Kamp printf("%s%d: %s ", 38a9463ba8SPoul-Henning Kamp bp->bio_disk->d_name, bp->bio_disk->d_unit, what); 39a9463ba8SPoul-Henning Kamp else 40a9463ba8SPoul-Henning Kamp printf("disk??: %s ", what); 41f90c382cSPoul-Henning Kamp switch(bp->bio_cmd) { 42f90c382cSPoul-Henning Kamp case BIO_READ: printf("cmd=read "); break; 43f90c382cSPoul-Henning Kamp case BIO_WRITE: printf("cmd=write "); break; 44f90c382cSPoul-Henning Kamp case BIO_DELETE: printf("cmd=delete "); break; 45f90c382cSPoul-Henning Kamp case BIO_GETATTR: printf("cmd=getattr "); break; 46c3618c65SPawel Jakub Dawidek case BIO_FLUSH: printf("cmd=flush "); break; 47f90c382cSPoul-Henning Kamp default: printf("cmd=%x ", bp->bio_cmd); break; 48f90c382cSPoul-Henning Kamp } 491ad9172fSPoul-Henning Kamp sn = bp->bio_pblkno; 50f90c382cSPoul-Henning Kamp if (bp->bio_bcount <= DEV_BSIZE) { 51f90c382cSPoul-Henning Kamp printf("fsbn %jd%s", (intmax_t)sn, nl ? "\n" : ""); 52f90c382cSPoul-Henning Kamp return; 53f90c382cSPoul-Henning Kamp } 54f90c382cSPoul-Henning Kamp if (blkdone >= 0) { 55f90c382cSPoul-Henning Kamp sn += blkdone; 56f90c382cSPoul-Henning Kamp printf("fsbn %jd of ", (intmax_t)sn); 57f90c382cSPoul-Henning Kamp } 581ad9172fSPoul-Henning Kamp printf("%jd-%jd", (intmax_t)bp->bio_pblkno, 591ad9172fSPoul-Henning Kamp (intmax_t)(bp->bio_pblkno + (bp->bio_bcount - 1) / DEV_BSIZE)); 60f90c382cSPoul-Henning Kamp if (nl) 61f90c382cSPoul-Henning Kamp printf("\n"); 62f90c382cSPoul-Henning Kamp } 632382fb0aSPoul-Henning Kamp 642382fb0aSPoul-Henning Kamp /* 65d086f85aSPoul-Henning Kamp * BIO queue implementation 66d086f85aSPoul-Henning Kamp */ 67d086f85aSPoul-Henning Kamp 68d086f85aSPoul-Henning Kamp void 69d086f85aSPoul-Henning Kamp bioq_init(struct bio_queue_head *head) 70d086f85aSPoul-Henning Kamp { 71d086f85aSPoul-Henning Kamp TAILQ_INIT(&head->queue); 724cb4df48SPoul-Henning Kamp head->last_offset = 0; 73d086f85aSPoul-Henning Kamp head->insert_point = NULL; 74d086f85aSPoul-Henning Kamp } 75d086f85aSPoul-Henning Kamp 76d086f85aSPoul-Henning Kamp void 77d086f85aSPoul-Henning Kamp bioq_remove(struct bio_queue_head *head, struct bio *bp) 78d086f85aSPoul-Henning Kamp { 79d086f85aSPoul-Henning Kamp if (bp == head->insert_point) { 804cb4df48SPoul-Henning Kamp head->last_offset = bp->bio_offset; 81f19f6869SJeff Roberson head->insert_point = TAILQ_NEXT(bp, bio_queue); 82f19f6869SJeff Roberson if (head->insert_point == NULL) { 83f19f6869SJeff Roberson head->last_offset = 0; 84f19f6869SJeff Roberson head->insert_point = TAILQ_FIRST(&head->queue); 85f19f6869SJeff Roberson } 86f19f6869SJeff Roberson } 87d086f85aSPoul-Henning Kamp TAILQ_REMOVE(&head->queue, bp, bio_queue); 88d086f85aSPoul-Henning Kamp } 89af6ca7f4SPoul-Henning Kamp 90af6ca7f4SPoul-Henning Kamp void 91af6ca7f4SPoul-Henning Kamp bioq_flush(struct bio_queue_head *head, struct devstat *stp, int error) 92af6ca7f4SPoul-Henning Kamp { 93af6ca7f4SPoul-Henning Kamp struct bio *bp; 94af6ca7f4SPoul-Henning Kamp 95d298f919SPoul-Henning Kamp while ((bp = bioq_takefirst(head)) != NULL) 96b8404473SPoul-Henning Kamp biofinish(bp, stp, error); 97af6ca7f4SPoul-Henning Kamp } 98af6ca7f4SPoul-Henning Kamp 99d086f85aSPoul-Henning Kamp void 100bf484316SPawel Jakub Dawidek bioq_insert_head(struct bio_queue_head *head, struct bio *bp) 101bf484316SPawel Jakub Dawidek { 102bf484316SPawel Jakub Dawidek 10356e26c3eSXin LI if (TAILQ_EMPTY(&head->queue)) 104f19f6869SJeff Roberson head->insert_point = bp; 105bf484316SPawel Jakub Dawidek TAILQ_INSERT_HEAD(&head->queue, bp, bio_queue); 106bf484316SPawel Jakub Dawidek } 107bf484316SPawel Jakub Dawidek 108bf484316SPawel Jakub Dawidek void 109d086f85aSPoul-Henning Kamp bioq_insert_tail(struct bio_queue_head *head, struct bio *bp) 110d086f85aSPoul-Henning Kamp { 111d086f85aSPoul-Henning Kamp 11256e26c3eSXin LI if (TAILQ_EMPTY(&head->queue)) 113f19f6869SJeff Roberson head->insert_point = bp; 114d086f85aSPoul-Henning Kamp TAILQ_INSERT_TAIL(&head->queue, bp, bio_queue); 115d086f85aSPoul-Henning Kamp } 116d086f85aSPoul-Henning Kamp 117d086f85aSPoul-Henning Kamp struct bio * 118d086f85aSPoul-Henning Kamp bioq_first(struct bio_queue_head *head) 119d086f85aSPoul-Henning Kamp { 120d086f85aSPoul-Henning Kamp 121d086f85aSPoul-Henning Kamp return (TAILQ_FIRST(&head->queue)); 122d086f85aSPoul-Henning Kamp } 123d086f85aSPoul-Henning Kamp 124d298f919SPoul-Henning Kamp struct bio * 125d298f919SPoul-Henning Kamp bioq_takefirst(struct bio_queue_head *head) 126d298f919SPoul-Henning Kamp { 127d298f919SPoul-Henning Kamp struct bio *bp; 128d298f919SPoul-Henning Kamp 129d298f919SPoul-Henning Kamp bp = TAILQ_FIRST(&head->queue); 130d298f919SPoul-Henning Kamp if (bp != NULL) 131d298f919SPoul-Henning Kamp bioq_remove(head, bp); 132d298f919SPoul-Henning Kamp return (bp); 133d298f919SPoul-Henning Kamp } 134d086f85aSPoul-Henning Kamp 135d086f85aSPoul-Henning Kamp /* 1362382fb0aSPoul-Henning Kamp * Seek sort for disks. 1372382fb0aSPoul-Henning Kamp * 138f19f6869SJeff Roberson * The disksort algorithm sorts all requests in a single queue while keeping 139f19f6869SJeff Roberson * track of the current position of the disk with insert_point and 140f19f6869SJeff Roberson * last_offset. last_offset is the offset of the last block sent to disk, or 141f19f6869SJeff Roberson * 0 once we reach the end. insert_point points to the first buf after 142f19f6869SJeff Roberson * last_offset, and is used to slightly speed up insertions. Blocks are 143f19f6869SJeff Roberson * always sorted in ascending order and the queue always restarts at 0. 144f19f6869SJeff Roberson * This implements the one-way scan which optimizes disk seek times. 1452382fb0aSPoul-Henning Kamp */ 1462382fb0aSPoul-Henning Kamp void 1472382fb0aSPoul-Henning Kamp bioq_disksort(bioq, bp) 1482382fb0aSPoul-Henning Kamp struct bio_queue_head *bioq; 1492382fb0aSPoul-Henning Kamp struct bio *bp; 1502382fb0aSPoul-Henning Kamp { 1512382fb0aSPoul-Henning Kamp struct bio *bq; 1522382fb0aSPoul-Henning Kamp struct bio *bn; 1532382fb0aSPoul-Henning Kamp 1542382fb0aSPoul-Henning Kamp /* 155f19f6869SJeff Roberson * If the queue is empty then it's easy. 1562382fb0aSPoul-Henning Kamp */ 157bc03ea7fSRobert Watson if (bioq_first(bioq) == NULL) { 1582382fb0aSPoul-Henning Kamp bioq_insert_tail(bioq, bp); 1592382fb0aSPoul-Henning Kamp return; 1602382fb0aSPoul-Henning Kamp } 1612382fb0aSPoul-Henning Kamp /* 1622382fb0aSPoul-Henning Kamp * Optimize for sequential I/O by seeing if we go at the tail. 1632382fb0aSPoul-Henning Kamp */ 164f19f6869SJeff Roberson bq = TAILQ_LAST(&bioq->queue, bio_queue); 165f19f6869SJeff Roberson if (bp->bio_offset > bq->bio_offset) { 166f19f6869SJeff Roberson TAILQ_INSERT_AFTER(&bioq->queue, bq, bp, bio_queue); 1672382fb0aSPoul-Henning Kamp return; 1682382fb0aSPoul-Henning Kamp } 169f19f6869SJeff Roberson /* 170f19f6869SJeff Roberson * Pick our scan start based on the last request. A poor man's 171f19f6869SJeff Roberson * binary search. 172f19f6869SJeff Roberson */ 173f19f6869SJeff Roberson if (bp->bio_offset >= bioq->last_offset) { 174f19f6869SJeff Roberson bq = bioq->insert_point; 175f19f6869SJeff Roberson /* 176f19f6869SJeff Roberson * If we're before the next bio and after the last offset, 177f19f6869SJeff Roberson * update insert_point; 178f19f6869SJeff Roberson */ 179f19f6869SJeff Roberson if (bp->bio_offset < bq->bio_offset) { 180f19f6869SJeff Roberson bioq->insert_point = bp; 181f19f6869SJeff Roberson TAILQ_INSERT_BEFORE(bq, bp, bio_queue); 182f19f6869SJeff Roberson return; 183f19f6869SJeff Roberson } 184f19f6869SJeff Roberson } else 185f19f6869SJeff Roberson bq = TAILQ_FIRST(&bioq->queue); 186bdcd9f26SJeff Roberson if (bp->bio_offset < bq->bio_offset) { 187bdcd9f26SJeff Roberson TAILQ_INSERT_BEFORE(bq, bp, bio_queue); 188bdcd9f26SJeff Roberson return; 189bdcd9f26SJeff Roberson } 190f19f6869SJeff Roberson /* Insertion sort */ 1912382fb0aSPoul-Henning Kamp while ((bn = TAILQ_NEXT(bq, bio_queue)) != NULL) { 192f19f6869SJeff Roberson if (bp->bio_offset < bn->bio_offset) 1932382fb0aSPoul-Henning Kamp break; 1942382fb0aSPoul-Henning Kamp bq = bn; 1952382fb0aSPoul-Henning Kamp } 1962382fb0aSPoul-Henning Kamp TAILQ_INSERT_AFTER(&bioq->queue, bq, bp, bio_queue); 1972382fb0aSPoul-Henning Kamp } 198