1da9e4f55SPoul-Henning Kamp /* 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 * $FreeBSD$ 10da9e4f55SPoul-Henning Kamp * 11da9e4f55SPoul-Henning Kamp */ 12da9e4f55SPoul-Henning Kamp 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> 207812d86fSPoul-Henning Kamp #include <sys/disklabel.h> 2181750927SPoul-Henning Kamp #include <geom/geom_disk.h> 22f90c382cSPoul-Henning Kamp 23f90c382cSPoul-Henning Kamp /*- 24f90c382cSPoul-Henning Kamp * Disk error is the preface to plaintive error messages 25f90c382cSPoul-Henning Kamp * about failing disk transfers. It prints messages of the form 26f90c382cSPoul-Henning Kamp * "hp0g: BLABLABLA cmd=read fsbn 12345 of 12344-12347" 27f90c382cSPoul-Henning Kamp * blkdone should be -1 if the position of the error is unknown. 28f90c382cSPoul-Henning Kamp * The message is printed with printf. 29f90c382cSPoul-Henning Kamp */ 30f90c382cSPoul-Henning Kamp void 31f90c382cSPoul-Henning Kamp disk_err(struct bio *bp, const char *what, int blkdone, int nl) 32f90c382cSPoul-Henning Kamp { 33f90c382cSPoul-Henning Kamp daddr_t sn; 34f90c382cSPoul-Henning Kamp 35a9463ba8SPoul-Henning Kamp if (bp->bio_dev != NULL) 36f90c382cSPoul-Henning Kamp printf("%s: %s ", devtoname(bp->bio_dev), what); 37a9463ba8SPoul-Henning Kamp else if (bp->bio_disk != NULL) 38a9463ba8SPoul-Henning Kamp printf("%s%d: %s ", 39a9463ba8SPoul-Henning Kamp bp->bio_disk->d_name, bp->bio_disk->d_unit, what); 40a9463ba8SPoul-Henning Kamp else 41a9463ba8SPoul-Henning Kamp printf("disk??: %s ", what); 42f90c382cSPoul-Henning Kamp switch(bp->bio_cmd) { 43f90c382cSPoul-Henning Kamp case BIO_READ: printf("cmd=read "); break; 44f90c382cSPoul-Henning Kamp case BIO_WRITE: printf("cmd=write "); break; 45f90c382cSPoul-Henning Kamp case BIO_DELETE: printf("cmd=delete "); break; 46f90c382cSPoul-Henning Kamp case BIO_GETATTR: printf("cmd=getattr "); break; 47f90c382cSPoul-Henning Kamp case BIO_SETATTR: printf("cmd=setattr "); break; 48f90c382cSPoul-Henning Kamp default: printf("cmd=%x ", bp->bio_cmd); break; 49f90c382cSPoul-Henning Kamp } 50f90c382cSPoul-Henning Kamp sn = bp->bio_blkno; 51f90c382cSPoul-Henning Kamp if (bp->bio_bcount <= DEV_BSIZE) { 52f90c382cSPoul-Henning Kamp printf("fsbn %jd%s", (intmax_t)sn, nl ? "\n" : ""); 53f90c382cSPoul-Henning Kamp return; 54f90c382cSPoul-Henning Kamp } 55f90c382cSPoul-Henning Kamp if (blkdone >= 0) { 56f90c382cSPoul-Henning Kamp sn += blkdone; 57f90c382cSPoul-Henning Kamp printf("fsbn %jd of ", (intmax_t)sn); 58f90c382cSPoul-Henning Kamp } 59f90c382cSPoul-Henning Kamp printf("%jd-%jd", (intmax_t)bp->bio_blkno, 60f90c382cSPoul-Henning Kamp (intmax_t)(bp->bio_blkno + (bp->bio_bcount - 1) / DEV_BSIZE)); 61f90c382cSPoul-Henning Kamp if (nl) 62f90c382cSPoul-Henning Kamp printf("\n"); 63f90c382cSPoul-Henning Kamp } 642382fb0aSPoul-Henning Kamp 652382fb0aSPoul-Henning Kamp /* 66d086f85aSPoul-Henning Kamp * BIO queue implementation 67d086f85aSPoul-Henning Kamp */ 68d086f85aSPoul-Henning Kamp 69d086f85aSPoul-Henning Kamp void 70d086f85aSPoul-Henning Kamp bioq_init(struct bio_queue_head *head) 71d086f85aSPoul-Henning Kamp { 72d086f85aSPoul-Henning Kamp TAILQ_INIT(&head->queue); 73d086f85aSPoul-Henning Kamp head->last_pblkno = 0; 74d086f85aSPoul-Henning Kamp head->insert_point = NULL; 75d086f85aSPoul-Henning Kamp head->switch_point = NULL; 76d086f85aSPoul-Henning Kamp } 77d086f85aSPoul-Henning Kamp 78d086f85aSPoul-Henning Kamp void 79d086f85aSPoul-Henning Kamp bioq_remove(struct bio_queue_head *head, struct bio *bp) 80d086f85aSPoul-Henning Kamp { 81d086f85aSPoul-Henning Kamp if (bp == head->switch_point) 82d086f85aSPoul-Henning Kamp head->switch_point = TAILQ_NEXT(bp, bio_queue); 83d086f85aSPoul-Henning Kamp if (bp == head->insert_point) { 84d086f85aSPoul-Henning Kamp head->insert_point = TAILQ_PREV(bp, bio_queue, bio_queue); 85d086f85aSPoul-Henning Kamp if (head->insert_point == NULL) 86d086f85aSPoul-Henning Kamp head->last_pblkno = 0; 87d086f85aSPoul-Henning Kamp } else if (bp == TAILQ_FIRST(&head->queue)) 88d086f85aSPoul-Henning Kamp head->last_pblkno = bp->bio_pblkno; 89d086f85aSPoul-Henning Kamp TAILQ_REMOVE(&head->queue, bp, bio_queue); 90d086f85aSPoul-Henning Kamp if (TAILQ_FIRST(&head->queue) == head->switch_point) 91d086f85aSPoul-Henning Kamp head->switch_point = NULL; 92d086f85aSPoul-Henning Kamp } 93af6ca7f4SPoul-Henning Kamp 94af6ca7f4SPoul-Henning Kamp void 95af6ca7f4SPoul-Henning Kamp bioq_flush(struct bio_queue_head *head, struct devstat *stp, int error) 96af6ca7f4SPoul-Henning Kamp { 97af6ca7f4SPoul-Henning Kamp struct bio *bp; 98af6ca7f4SPoul-Henning Kamp 99af6ca7f4SPoul-Henning Kamp for (;;) { 100af6ca7f4SPoul-Henning Kamp bp = bioq_first(head); 101af6ca7f4SPoul-Henning Kamp if (bp == NULL) 102af6ca7f4SPoul-Henning Kamp break; 103af6ca7f4SPoul-Henning Kamp bioq_remove(head, bp); 104af6ca7f4SPoul-Henning Kamp biofinish(bp, stp, ENXIO); 105af6ca7f4SPoul-Henning Kamp } 106af6ca7f4SPoul-Henning Kamp } 107af6ca7f4SPoul-Henning Kamp 108d086f85aSPoul-Henning Kamp void 109d086f85aSPoul-Henning Kamp bioq_insert_tail(struct bio_queue_head *head, struct bio *bp) 110d086f85aSPoul-Henning Kamp { 111d086f85aSPoul-Henning Kamp 112d086f85aSPoul-Henning Kamp TAILQ_INSERT_TAIL(&head->queue, bp, bio_queue); 113d086f85aSPoul-Henning Kamp } 114d086f85aSPoul-Henning Kamp 115d086f85aSPoul-Henning Kamp struct bio * 116d086f85aSPoul-Henning Kamp bioq_first(struct bio_queue_head *head) 117d086f85aSPoul-Henning Kamp { 118d086f85aSPoul-Henning Kamp 119d086f85aSPoul-Henning Kamp return (TAILQ_FIRST(&head->queue)); 120d086f85aSPoul-Henning Kamp } 121d086f85aSPoul-Henning Kamp 122d086f85aSPoul-Henning Kamp 123d086f85aSPoul-Henning Kamp /* 1242382fb0aSPoul-Henning Kamp * Seek sort for disks. 1252382fb0aSPoul-Henning Kamp * 1262382fb0aSPoul-Henning Kamp * The buf_queue keep two queues, sorted in ascending block order. The first 1272382fb0aSPoul-Henning Kamp * queue holds those requests which are positioned after the current block 1282382fb0aSPoul-Henning Kamp * (in the first request); the second, which starts at queue->switch_point, 1292382fb0aSPoul-Henning Kamp * holds requests which came in after their block number was passed. Thus 1302382fb0aSPoul-Henning Kamp * we implement a one way scan, retracting after reaching the end of the drive 1312382fb0aSPoul-Henning Kamp * to the first request on the second queue, at which time it becomes the 1322382fb0aSPoul-Henning Kamp * first queue. 1332382fb0aSPoul-Henning Kamp * 1342382fb0aSPoul-Henning Kamp * A one-way scan is natural because of the way UNIX read-ahead blocks are 1352382fb0aSPoul-Henning Kamp * allocated. 1362382fb0aSPoul-Henning Kamp */ 1372382fb0aSPoul-Henning Kamp 1382382fb0aSPoul-Henning Kamp void 1392382fb0aSPoul-Henning Kamp bioq_disksort(bioq, bp) 1402382fb0aSPoul-Henning Kamp struct bio_queue_head *bioq; 1412382fb0aSPoul-Henning Kamp struct bio *bp; 1422382fb0aSPoul-Henning Kamp { 1432382fb0aSPoul-Henning Kamp struct bio *bq; 1442382fb0aSPoul-Henning Kamp struct bio *bn; 1452382fb0aSPoul-Henning Kamp struct bio *be; 1462382fb0aSPoul-Henning Kamp 1472382fb0aSPoul-Henning Kamp be = TAILQ_LAST(&bioq->queue, bio_queue); 1482382fb0aSPoul-Henning Kamp /* 1492382fb0aSPoul-Henning Kamp * If the queue is empty or we are an 1502382fb0aSPoul-Henning Kamp * ordered transaction, then it's easy. 1512382fb0aSPoul-Henning Kamp */ 1522382fb0aSPoul-Henning Kamp if ((bq = bioq_first(bioq)) == NULL) { 1532382fb0aSPoul-Henning Kamp bioq_insert_tail(bioq, bp); 1542382fb0aSPoul-Henning Kamp return; 1552382fb0aSPoul-Henning Kamp } else if (bioq->insert_point != NULL) { 1562382fb0aSPoul-Henning Kamp 1572382fb0aSPoul-Henning Kamp /* 1582382fb0aSPoul-Henning Kamp * A certain portion of the list is 1592382fb0aSPoul-Henning Kamp * "locked" to preserve ordering, so 1602382fb0aSPoul-Henning Kamp * we can only insert after the insert 1612382fb0aSPoul-Henning Kamp * point. 1622382fb0aSPoul-Henning Kamp */ 1632382fb0aSPoul-Henning Kamp bq = bioq->insert_point; 1642382fb0aSPoul-Henning Kamp } else { 1652382fb0aSPoul-Henning Kamp 1662382fb0aSPoul-Henning Kamp /* 1672382fb0aSPoul-Henning Kamp * If we lie before the last removed (currently active) 1682382fb0aSPoul-Henning Kamp * request, and are not inserting ourselves into the 1692382fb0aSPoul-Henning Kamp * "locked" portion of the list, then we must add ourselves 1702382fb0aSPoul-Henning Kamp * to the second request list. 1712382fb0aSPoul-Henning Kamp */ 1722382fb0aSPoul-Henning Kamp if (bp->bio_pblkno < bioq->last_pblkno) { 1732382fb0aSPoul-Henning Kamp 1742382fb0aSPoul-Henning Kamp bq = bioq->switch_point; 1752382fb0aSPoul-Henning Kamp /* 1762382fb0aSPoul-Henning Kamp * If we are starting a new secondary list, 1772382fb0aSPoul-Henning Kamp * then it's easy. 1782382fb0aSPoul-Henning Kamp */ 1792382fb0aSPoul-Henning Kamp if (bq == NULL) { 1802382fb0aSPoul-Henning Kamp bioq->switch_point = bp; 1812382fb0aSPoul-Henning Kamp bioq_insert_tail(bioq, bp); 1822382fb0aSPoul-Henning Kamp return; 1832382fb0aSPoul-Henning Kamp } 1842382fb0aSPoul-Henning Kamp /* 1852382fb0aSPoul-Henning Kamp * If we lie ahead of the current switch point, 1862382fb0aSPoul-Henning Kamp * insert us before the switch point and move 1872382fb0aSPoul-Henning Kamp * the switch point. 1882382fb0aSPoul-Henning Kamp */ 1892382fb0aSPoul-Henning Kamp if (bp->bio_pblkno < bq->bio_pblkno) { 1902382fb0aSPoul-Henning Kamp bioq->switch_point = bp; 1912382fb0aSPoul-Henning Kamp TAILQ_INSERT_BEFORE(bq, bp, bio_queue); 1922382fb0aSPoul-Henning Kamp return; 1932382fb0aSPoul-Henning Kamp } 1942382fb0aSPoul-Henning Kamp } else { 1952382fb0aSPoul-Henning Kamp if (bioq->switch_point != NULL) 1962382fb0aSPoul-Henning Kamp be = TAILQ_PREV(bioq->switch_point, 1972382fb0aSPoul-Henning Kamp bio_queue, bio_queue); 1982382fb0aSPoul-Henning Kamp /* 1992382fb0aSPoul-Henning Kamp * If we lie between last_pblkno and bq, 2002382fb0aSPoul-Henning Kamp * insert before bq. 2012382fb0aSPoul-Henning Kamp */ 2022382fb0aSPoul-Henning Kamp if (bp->bio_pblkno < bq->bio_pblkno) { 2032382fb0aSPoul-Henning Kamp TAILQ_INSERT_BEFORE(bq, bp, bio_queue); 2042382fb0aSPoul-Henning Kamp return; 2052382fb0aSPoul-Henning Kamp } 2062382fb0aSPoul-Henning Kamp } 2072382fb0aSPoul-Henning Kamp } 2082382fb0aSPoul-Henning Kamp 2092382fb0aSPoul-Henning Kamp /* 2102382fb0aSPoul-Henning Kamp * Request is at/after our current position in the list. 2112382fb0aSPoul-Henning Kamp * Optimize for sequential I/O by seeing if we go at the tail. 2122382fb0aSPoul-Henning Kamp */ 2132382fb0aSPoul-Henning Kamp if (bp->bio_pblkno > be->bio_pblkno) { 2142382fb0aSPoul-Henning Kamp TAILQ_INSERT_AFTER(&bioq->queue, be, bp, bio_queue); 2152382fb0aSPoul-Henning Kamp return; 2162382fb0aSPoul-Henning Kamp } 2172382fb0aSPoul-Henning Kamp 2182382fb0aSPoul-Henning Kamp /* Otherwise, insertion sort */ 2192382fb0aSPoul-Henning Kamp while ((bn = TAILQ_NEXT(bq, bio_queue)) != NULL) { 2202382fb0aSPoul-Henning Kamp 2212382fb0aSPoul-Henning Kamp /* 2222382fb0aSPoul-Henning Kamp * We want to go after the current request if it is the end 2232382fb0aSPoul-Henning Kamp * of the first request list, or if the next request is a 2242382fb0aSPoul-Henning Kamp * larger cylinder than our request. 2252382fb0aSPoul-Henning Kamp */ 2262382fb0aSPoul-Henning Kamp if (bn == bioq->switch_point 2272382fb0aSPoul-Henning Kamp || bp->bio_pblkno < bn->bio_pblkno) 2282382fb0aSPoul-Henning Kamp break; 2292382fb0aSPoul-Henning Kamp bq = bn; 2302382fb0aSPoul-Henning Kamp } 2312382fb0aSPoul-Henning Kamp TAILQ_INSERT_AFTER(&bioq->queue, bq, bp, bio_queue); 2322382fb0aSPoul-Henning Kamp } 2332382fb0aSPoul-Henning Kamp 2342382fb0aSPoul-Henning Kamp 235