Convert tqdisksort to bufqdisksort. Honor the B_ORDERED buffer flag

so that meta-data writes go out to the device in the right order.
This commit is contained in:
gibbs 1997-09-21 22:10:49 +00:00
parent f935b9668d
commit df1f24e6bb
2 changed files with 112 additions and 154 deletions

View File

@ -36,7 +36,7 @@
* SUCH DAMAGE. * SUCH DAMAGE.
* *
* @(#)ufs_disksubr.c 8.5 (Berkeley) 1/21/94 * @(#)ufs_disksubr.c 8.5 (Berkeley) 1/21/94
* $Id: ufs_disksubr.c,v 1.30 1997/02/22 09:47:45 peter Exp $ * $Id: ufs_disksubr.c,v 1.31 1997/07/13 15:53:20 bde Exp $
*/ */
#include <sys/param.h> #include <sys/param.h>
@ -50,109 +50,88 @@
/* /*
* Seek sort for disks. * Seek sort for disks.
* *
* The argument ap structure holds a b_actf activity chain pointer on which we * The buf_queue keep two queues, sorted in ascending block order. The first
* keep two queues, sorted in ascending block order. The first queue holds * queue holds those requests which are positioned after the current block
* those requests which are positioned after the current block (in the first * (in the first request); the second, which starts at queue->switch_point,
* request); the second holds requests which came in after their block number * holds requests which came in after their block number was passed. Thus
* was passed. Thus we implement a one way scan, retracting after reaching the * we implement a one way scan, retracting after reaching the end of the drive
* end of the drive to the first request on the second queue, at which time it * to the first request on the second queue, at which time it becomes the
* becomes the first queue. * first queue.
* *
* A one-way scan is natural because of the way UNIX read-ahead blocks are * A one-way scan is natural because of the way UNIX read-ahead blocks are
* allocated. * allocated.
*/ */
void void
tqdisksort(ap, bp) bufqdisksort(bufq, bp)
struct buf_queue_head *ap; struct buf_queue_head *bufq;
register struct buf *bp; struct buf *bp;
{ {
register struct buf *bq; struct buf *bq;
struct buf *bn; struct buf *bn;
int count;
/* If the queue is empty, then it's easy. */ /*
if ((bq = ap->tqh_first) == NULL) { * If the queue is empty or we are an
TAILQ_INSERT_HEAD(ap, bp, b_act); * ordered transaction, then it's easy.
*/
if ((bq = bufq_first(bufq)) == NULL
|| (bp->b_flags & B_ORDERED) != 0) {
bufq_insert_tail(bufq, bp);
return;
} else if (bufq->insert_point != NULL) {
/*
* A certain portion of the list is
* "locked" to preserve ordering, so
* we can only insert after the insert
* point.
*/
bq = TAILQ_NEXT(bufq->insert_point, b_act);
if (bq == NULL) {
bufq_insert_tail(bufq, bp);
return; return;
} }
#if 1
/* Put new writes after all reads */
if ((bp->b_flags & B_READ) == 0) {
while (bn = bq->b_act.tqe_next) {
if ((bq->b_flags & B_READ) == 0)
break;
bq = bn;
} }
} else {
while (bn = bq->b_act.tqe_next) {
if ((bq->b_flags & B_READ) == 0) {
if (ap->tqh_first != bq) {
bq = *bq->b_act.tqe_prev;
}
break;
}
bq = bn;
}
goto insert;
}
#endif
/* /*
* If we lie after the first (currently active) request, then we * If we lie before the first (currently active) request, then we
* must locate the second request list and add ourselves to it. * must add ourselves to the second request list.
*/ */
if (bp->b_pblkno < bq->b_pblkno) { if (bp->b_pblkno < bq->b_pblkno) {
while (bn = bq->b_act.tqe_next) {
bq = bufq->switch_point;
/* /*
* Check for an ``inversion'' in the normally ascending * If we are starting a new secondary list, then it's easy.
* cylinder numbers, indicating the start of the second
* request list.
*/ */
if (bn->b_pblkno < bq->b_pblkno) { if (bq == NULL) {
/* bufq->switch_point = bp;
* Search the second request list for the first bufq_insert_tail(bufq, bp);
* request at a larger cylinder number. We go return;
* before that; if there is no such request, we
* go at end.
*/
do {
if (bp->b_pblkno < bn->b_pblkno)
goto insert;
bq = bn;
} while (bn = bq->b_act.tqe_next);
goto insert; /* after last */
} }
bq = bn; if (bp->b_pblkno < bq->b_pblkno) {
bufq->switch_point = bp;
TAILQ_INSERT_BEFORE(bq, bp, b_act);
return;
} }
/*
* No inversions... we will go after the last, and
* be the first request in the second request list.
*/
goto insert;
} }
/* /*
* Request is at/after the current request... * Request is at/after the current request...
* sort in the first request list. * sort in the first request list.
*/ */
while (bn = bq->b_act.tqe_next) { while ((bn = TAILQ_NEXT(bq, b_act)) != NULL) {
/* /*
* We want to go after the current request if there is an * We want to go after the current request if it is the end
* inversion after it (i.e. it is the end of the first * of the first request list, or if the next request is a
* request list), or if the next request is a larger cylinder * larger cylinder than our request.
* than our request.
*/ */
if (bn->b_pblkno < bq->b_pblkno || if (bn == bufq->switch_point
bp->b_pblkno < bn->b_pblkno) || bp->b_pblkno < bn->b_pblkno)
goto insert; break;
bq = bn; bq = bn;
} }
/* TAILQ_INSERT_AFTER(&bufq->queue, bq, bp, b_act);
* Neither a second list nor a larger request... we go at the end of
* the first list, which is the same as the end of the whole schebang.
*/
insert:
TAILQ_INSERT_AFTER(ap, bq, bp, b_act);
} }

View File

@ -36,7 +36,7 @@
* SUCH DAMAGE. * SUCH DAMAGE.
* *
* @(#)ufs_disksubr.c 8.5 (Berkeley) 1/21/94 * @(#)ufs_disksubr.c 8.5 (Berkeley) 1/21/94
* $Id: ufs_disksubr.c,v 1.30 1997/02/22 09:47:45 peter Exp $ * $Id: ufs_disksubr.c,v 1.31 1997/07/13 15:53:20 bde Exp $
*/ */
#include <sys/param.h> #include <sys/param.h>
@ -50,109 +50,88 @@
/* /*
* Seek sort for disks. * Seek sort for disks.
* *
* The argument ap structure holds a b_actf activity chain pointer on which we * The buf_queue keep two queues, sorted in ascending block order. The first
* keep two queues, sorted in ascending block order. The first queue holds * queue holds those requests which are positioned after the current block
* those requests which are positioned after the current block (in the first * (in the first request); the second, which starts at queue->switch_point,
* request); the second holds requests which came in after their block number * holds requests which came in after their block number was passed. Thus
* was passed. Thus we implement a one way scan, retracting after reaching the * we implement a one way scan, retracting after reaching the end of the drive
* end of the drive to the first request on the second queue, at which time it * to the first request on the second queue, at which time it becomes the
* becomes the first queue. * first queue.
* *
* A one-way scan is natural because of the way UNIX read-ahead blocks are * A one-way scan is natural because of the way UNIX read-ahead blocks are
* allocated. * allocated.
*/ */
void void
tqdisksort(ap, bp) bufqdisksort(bufq, bp)
struct buf_queue_head *ap; struct buf_queue_head *bufq;
register struct buf *bp; struct buf *bp;
{ {
register struct buf *bq; struct buf *bq;
struct buf *bn; struct buf *bn;
int count;
/* If the queue is empty, then it's easy. */ /*
if ((bq = ap->tqh_first) == NULL) { * If the queue is empty or we are an
TAILQ_INSERT_HEAD(ap, bp, b_act); * ordered transaction, then it's easy.
*/
if ((bq = bufq_first(bufq)) == NULL
|| (bp->b_flags & B_ORDERED) != 0) {
bufq_insert_tail(bufq, bp);
return;
} else if (bufq->insert_point != NULL) {
/*
* A certain portion of the list is
* "locked" to preserve ordering, so
* we can only insert after the insert
* point.
*/
bq = TAILQ_NEXT(bufq->insert_point, b_act);
if (bq == NULL) {
bufq_insert_tail(bufq, bp);
return; return;
} }
#if 1
/* Put new writes after all reads */
if ((bp->b_flags & B_READ) == 0) {
while (bn = bq->b_act.tqe_next) {
if ((bq->b_flags & B_READ) == 0)
break;
bq = bn;
} }
} else {
while (bn = bq->b_act.tqe_next) {
if ((bq->b_flags & B_READ) == 0) {
if (ap->tqh_first != bq) {
bq = *bq->b_act.tqe_prev;
}
break;
}
bq = bn;
}
goto insert;
}
#endif
/* /*
* If we lie after the first (currently active) request, then we * If we lie before the first (currently active) request, then we
* must locate the second request list and add ourselves to it. * must add ourselves to the second request list.
*/ */
if (bp->b_pblkno < bq->b_pblkno) { if (bp->b_pblkno < bq->b_pblkno) {
while (bn = bq->b_act.tqe_next) {
bq = bufq->switch_point;
/* /*
* Check for an ``inversion'' in the normally ascending * If we are starting a new secondary list, then it's easy.
* cylinder numbers, indicating the start of the second
* request list.
*/ */
if (bn->b_pblkno < bq->b_pblkno) { if (bq == NULL) {
/* bufq->switch_point = bp;
* Search the second request list for the first bufq_insert_tail(bufq, bp);
* request at a larger cylinder number. We go return;
* before that; if there is no such request, we
* go at end.
*/
do {
if (bp->b_pblkno < bn->b_pblkno)
goto insert;
bq = bn;
} while (bn = bq->b_act.tqe_next);
goto insert; /* after last */
} }
bq = bn; if (bp->b_pblkno < bq->b_pblkno) {
bufq->switch_point = bp;
TAILQ_INSERT_BEFORE(bq, bp, b_act);
return;
} }
/*
* No inversions... we will go after the last, and
* be the first request in the second request list.
*/
goto insert;
} }
/* /*
* Request is at/after the current request... * Request is at/after the current request...
* sort in the first request list. * sort in the first request list.
*/ */
while (bn = bq->b_act.tqe_next) { while ((bn = TAILQ_NEXT(bq, b_act)) != NULL) {
/* /*
* We want to go after the current request if there is an * We want to go after the current request if it is the end
* inversion after it (i.e. it is the end of the first * of the first request list, or if the next request is a
* request list), or if the next request is a larger cylinder * larger cylinder than our request.
* than our request.
*/ */
if (bn->b_pblkno < bq->b_pblkno || if (bn == bufq->switch_point
bp->b_pblkno < bn->b_pblkno) || bp->b_pblkno < bn->b_pblkno)
goto insert; break;
bq = bn; bq = bn;
} }
/* TAILQ_INSERT_AFTER(&bufq->queue, bq, bp, b_act);
* Neither a second list nor a larger request... we go at the end of
* the first list, which is the same as the end of the whole schebang.
*/
insert:
TAILQ_INSERT_AFTER(ap, bq, bp, b_act);
} }