xref: /csrg-svn/sys/ufs/ffs/ufs_disksubr.c (revision 2626)
1*2626Swnj /*	ufs_disksubr.c	4.2	02/23/81	*/
216Sbill 
316Sbill /*
4*2626Swnj  * Seek sort for disks.  We depend on the driver
5*2626Swnj  * which calls us using b_resid as the current cylinder number.
6*2626Swnj  *
7*2626Swnj  * The argument dp structure holds a b_actf activity chain pointer
8*2626Swnj  * on which we keep two queues, sorted in ascending cylinder order.
9*2626Swnj  * The first queue holds those requests which are positioned after
10*2626Swnj  * the current cylinder (in the first request); the second holds
11*2626Swnj  * requests which came in after their cylinder number was passed.
12*2626Swnj  * Thus we implement a one way scan, retracting after reaching the
13*2626Swnj  * end of the drive to the first request on the second queue,
14*2626Swnj  * at which time it becomes the first queue.
15*2626Swnj  *
16*2626Swnj  * A one-way scan is natural because of the way UNIX read-ahead
17*2626Swnj  * blocks are allocated.
1816Sbill  */
1916Sbill 
2016Sbill #include "../h/param.h"
2116Sbill #include "../h/systm.h"
2216Sbill #include "../h/buf.h"
2316Sbill 
2416Sbill #define	b_cylin	b_resid
2516Sbill 
2616Sbill disksort(dp, bp)
27*2626Swnj 	register struct buf *dp, *bp;
2816Sbill {
2916Sbill 	register struct buf *ap;
3016Sbill 
31*2626Swnj 	/*
32*2626Swnj 	 * If nothing on the activity queue, then
33*2626Swnj 	 * we become the only thing.
34*2626Swnj 	 */
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 	}
42*2626Swnj 	/*
43*2626Swnj 	 * If we lie after the first (currently active)
44*2626Swnj 	 * request, then we must locate the second request list
45*2626Swnj 	 * and add ourselves to it.
46*2626Swnj 	 */
47*2626Swnj 	if (bp->b_cylin < ap->b_cylin) {
48*2626Swnj 		while (ap->av_forw) {
49*2626Swnj 			/*
50*2626Swnj 			 * Check for an ``inversion'' in the
51*2626Swnj 			 * normally ascending cylinder numbers,
52*2626Swnj 			 * indicating the start of the second request list.
53*2626Swnj 			 */
54*2626Swnj 			if (ap->av_forw->b_cylin < ap->b_cylin) {
55*2626Swnj 				/*
56*2626Swnj 				 * Search the second request list
57*2626Swnj 				 * for the first request at a larger
58*2626Swnj 				 * cylinder number.  We go before that;
59*2626Swnj 				 * if there is no such request, we go at end.
60*2626Swnj 				 */
61*2626Swnj 				do {
62*2626Swnj 					if (bp->b_cylin < ap->av_forw->b_cylin)
63*2626Swnj 						goto insert;
64*2626Swnj 					ap = ap->av_forw;
65*2626Swnj 				} while (ap->av_forw);
66*2626Swnj 				goto insert;		/* after last */
67*2626Swnj 			}
68*2626Swnj 			ap = ap->av_forw;
6916Sbill 		}
70*2626Swnj 		/*
71*2626Swnj 		 * No inversions... we will go after the last, and
72*2626Swnj 		 * be the first request in the second request list.
73*2626Swnj 		 */
74*2626Swnj 		goto insert;
7516Sbill 	}
76*2626Swnj 	/*
77*2626Swnj 	 * Request is at/after the current request...
78*2626Swnj 	 * sort in the first request list.
79*2626Swnj 	 */
80*2626Swnj 	while (ap->av_forw) {
81*2626Swnj 		/*
82*2626Swnj 		 * We want to go after the current request
83*2626Swnj 		 * if there is an inversion after it (i.e. it is
84*2626Swnj 		 * the end of the first request list), or if
85*2626Swnj 		 * the next request is a larger cylinder than our request.
86*2626Swnj 		 */
87*2626Swnj 		if (ap->av_forw->b_cylin < ap->b_cylin ||
88*2626Swnj 		    bp->b_cylin < ap->av_forw->b_cylin)
89*2626Swnj 			goto insert;
90*2626Swnj 		ap = ap->av_forw;
91*2626Swnj 	}
92*2626Swnj 	/*
93*2626Swnj 	 * Neither a second list nor a larger
94*2626Swnj 	 * request... we go at the end of the first list,
95*2626Swnj 	 * which is the same as the end of the whole schebang.
96*2626Swnj 	 */
97*2626Swnj insert:
98*2626Swnj 	bp->av_forw = ap->av_forw;
99*2626Swnj 	ap->av_forw = bp;
100*2626Swnj 	if (ap == dp->b_actl)
10116Sbill 		dp->b_actl = bp;
10216Sbill }
103