xref: /csrg-svn/sys/ufs/ffs/ufs_disksubr.c (revision 17099)
1*17099Sbloom /*	ufs_disksubr.c	6.2	84/08/29	*/
216Sbill 
316Sbill /*
42626Swnj  * Seek sort for disks.  We depend on the driver
52626Swnj  * which calls us using b_resid as the current cylinder number.
62626Swnj  *
72626Swnj  * The argument dp structure holds a b_actf activity chain pointer
82626Swnj  * on which we keep two queues, sorted in ascending cylinder order.
92626Swnj  * The first queue holds those requests which are positioned after
102626Swnj  * the current cylinder (in the first request); the second holds
112626Swnj  * requests which came in after their cylinder number was passed.
122626Swnj  * Thus we implement a one way scan, retracting after reaching the
132626Swnj  * end of the drive to the first request on the second queue,
142626Swnj  * at which time it becomes the first queue.
152626Swnj  *
162626Swnj  * A one-way scan is natural because of the way UNIX read-ahead
172626Swnj  * blocks are allocated.
1816Sbill  */
1916Sbill 
20*17099Sbloom #include "param.h"
21*17099Sbloom #include "systm.h"
22*17099Sbloom #include "buf.h"
2316Sbill 
2416Sbill #define	b_cylin	b_resid
2516Sbill 
2616Sbill disksort(dp, bp)
272626Swnj 	register struct buf *dp, *bp;
2816Sbill {
2916Sbill 	register struct buf *ap;
3016Sbill 
312626Swnj 	/*
322626Swnj 	 * If nothing on the activity queue, then
332626Swnj 	 * we become the only thing.
342626Swnj 	 */
3516Sbill 	ap = dp->b_actf;
3616Sbill 	if(ap == NULL) {
3716Sbill 		dp->b_actf = bp;
3816Sbill 		dp->b_actl = bp;
3916Sbill 		bp->av_forw = NULL;
4016Sbill 		return;
4116Sbill 	}
422626Swnj 	/*
432626Swnj 	 * If we lie after the first (currently active)
442626Swnj 	 * request, then we must locate the second request list
452626Swnj 	 * and add ourselves to it.
462626Swnj 	 */
472626Swnj 	if (bp->b_cylin < ap->b_cylin) {
482626Swnj 		while (ap->av_forw) {
492626Swnj 			/*
502626Swnj 			 * Check for an ``inversion'' in the
512626Swnj 			 * normally ascending cylinder numbers,
522626Swnj 			 * indicating the start of the second request list.
532626Swnj 			 */
542626Swnj 			if (ap->av_forw->b_cylin < ap->b_cylin) {
552626Swnj 				/*
562626Swnj 				 * Search the second request list
572626Swnj 				 * for the first request at a larger
582626Swnj 				 * cylinder number.  We go before that;
592626Swnj 				 * if there is no such request, we go at end.
602626Swnj 				 */
612626Swnj 				do {
622626Swnj 					if (bp->b_cylin < ap->av_forw->b_cylin)
632626Swnj 						goto insert;
642626Swnj 					ap = ap->av_forw;
652626Swnj 				} while (ap->av_forw);
662626Swnj 				goto insert;		/* after last */
672626Swnj 			}
682626Swnj 			ap = ap->av_forw;
6916Sbill 		}
702626Swnj 		/*
712626Swnj 		 * No inversions... we will go after the last, and
722626Swnj 		 * be the first request in the second request list.
732626Swnj 		 */
742626Swnj 		goto insert;
7516Sbill 	}
762626Swnj 	/*
772626Swnj 	 * Request is at/after the current request...
782626Swnj 	 * sort in the first request list.
792626Swnj 	 */
802626Swnj 	while (ap->av_forw) {
812626Swnj 		/*
822626Swnj 		 * We want to go after the current request
832626Swnj 		 * if there is an inversion after it (i.e. it is
842626Swnj 		 * the end of the first request list), or if
852626Swnj 		 * the next request is a larger cylinder than our request.
862626Swnj 		 */
872626Swnj 		if (ap->av_forw->b_cylin < ap->b_cylin ||
882626Swnj 		    bp->b_cylin < ap->av_forw->b_cylin)
892626Swnj 			goto insert;
902626Swnj 		ap = ap->av_forw;
912626Swnj 	}
922626Swnj 	/*
932626Swnj 	 * Neither a second list nor a larger
942626Swnj 	 * request... we go at the end of the first list,
952626Swnj 	 * which is the same as the end of the whole schebang.
962626Swnj 	 */
972626Swnj insert:
982626Swnj 	bp->av_forw = ap->av_forw;
992626Swnj 	ap->av_forw = bp;
1002626Swnj 	if (ap == dp->b_actl)
10116Sbill 		dp->b_actl = bp;
10216Sbill }
103