1 /* $NetBSD: rf_sstf.c,v 1.15 2006/11/16 01:33:23 christos Exp $ */
3 * Copyright (c) 1995 Carnegie-Mellon University.
8 * Permission to use, copy, modify and distribute this software and
9 * its documentation is hereby granted, provided that both the copyright
10 * notice and this permission notice appear in all copies of the
11 * software, derivative works or modified versions, and any portions
12 * thereof, and that both notices appear in supporting documentation.
14 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
15 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
16 * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
18 * Carnegie Mellon requests users of this software to return to
20 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
21 * School of Computer Science
22 * Carnegie Mellon University
23 * Pittsburgh PA 15213-3890
25 * any improvements or extensions that they make and grant Carnegie the
26 * rights to redistribute these changes.
29 /*******************************************************************************
31 * sstf.c -- prioritized shortest seek time first disk queueing code
33 ******************************************************************************/
35 #include <sys/cdefs.h>
36 __KERNEL_RCSID(0, "$NetBSD: rf_sstf.c,v 1.15 2006/11/16 01:33:23 christos Exp $");
38 #include <dev/raidframe/raidframevar.h>
40 #include "rf_alloclist.h"
41 #include "rf_stripelocks.h"
42 #include "rf_layout.h"
43 #include "rf_diskqueue.h"
45 #include "rf_debugMem.h"
46 #include "rf_general.h"
47 #include "rf_options.h"
54 #define SNUM_DIFF(_a_,_b_) (((_a_)>(_b_))?((_a_)-(_b_)):((_b_)-(_a_)))
56 #define QSUM(_sstfq_) (((_sstfq_)->lopri.qlen)+((_sstfq_)->left.qlen)+((_sstfq_)->right.qlen))
60 do_sstf_ord_q(RF_DiskQueueData_t
**,
61 RF_DiskQueueData_t
**,
62 RF_DiskQueueData_t
*);
64 static RF_DiskQueueData_t
*
65 closest_to_arm(RF_SstfQ_t
*,
69 static void do_dequeue(RF_SstfQ_t
*, RF_DiskQueueData_t
*);
73 do_sstf_ord_q(RF_DiskQueueData_t
**queuep
, RF_DiskQueueData_t
**tailp
, RF_DiskQueueData_t
*req
)
75 RF_DiskQueueData_t
*r
, *s
;
77 if (*queuep
== NULL
) {
84 if (req
->sectorOffset
<= (*queuep
)->sectorOffset
) {
87 (*queuep
)->prev
= req
;
91 if (req
->sectorOffset
> (*tailp
)->sectorOffset
) {
97 for (s
= NULL
, r
= *queuep
; r
; s
= r
, r
= r
->next
) {
98 if (r
->sectorOffset
>= req
->sectorOffset
) {
99 /* insert after s, before r */
109 /* insert after s, at end of queue */
110 RF_ASSERT(r
== NULL
);
112 RF_ASSERT(s
== (*tailp
));
118 /* for removing from head-of-queue */
119 #define DO_HEAD_DEQ(_r_,_q_) { \
120 _r_ = (_q_)->queue; \
121 RF_ASSERT((_r_) != NULL); \
122 (_q_)->queue = (_r_)->next; \
124 if ((_q_)->qlen == 0) { \
125 RF_ASSERT((_r_) == (_q_)->qtail); \
126 RF_ASSERT((_q_)->queue == NULL); \
127 (_q_)->qtail = NULL; \
130 RF_ASSERT((_q_)->queue->prev == (_r_)); \
131 (_q_)->queue->prev = NULL; \
135 /* for removing from end-of-queue */
136 #define DO_TAIL_DEQ(_r_,_q_) { \
137 _r_ = (_q_)->qtail; \
138 RF_ASSERT((_r_) != NULL); \
139 (_q_)->qtail = (_r_)->prev; \
141 if ((_q_)->qlen == 0) { \
142 RF_ASSERT((_r_) == (_q_)->queue); \
143 RF_ASSERT((_q_)->qtail == NULL); \
144 (_q_)->queue = NULL; \
147 RF_ASSERT((_q_)->qtail->next == (_r_)); \
148 (_q_)->qtail->next = NULL; \
152 #define DO_BEST_DEQ(_l_,_r_,_q_) { \
153 if (SNUM_DIFF((_q_)->queue->sectorOffset,_l_) \
154 < SNUM_DIFF((_q_)->qtail->sectorOffset,_l_)) \
156 DO_HEAD_DEQ(_r_,_q_); \
159 DO_TAIL_DEQ(_r_,_q_); \
163 static RF_DiskQueueData_t
*
164 closest_to_arm(RF_SstfQ_t
*queue
, RF_SectorNum_t arm_pos
, int *dir
, int allow_reverse
)
166 RF_SectorNum_t best_pos_l
= 0, this_pos_l
= 0, last_pos
= 0;
167 RF_SectorNum_t best_pos_r
= 0, this_pos_r
= 0;
168 RF_DiskQueueData_t
*r
, *best_l
, *best_r
;
170 best_r
= best_l
= NULL
;
171 for (r
= queue
->queue
; r
; r
= r
->next
) {
172 if (r
->sectorOffset
< arm_pos
) {
173 if (best_l
== NULL
) {
175 last_pos
= best_pos_l
= this_pos_l
;
177 this_pos_l
= arm_pos
- r
->sectorOffset
;
178 if (this_pos_l
< best_pos_l
) {
180 last_pos
= best_pos_l
= this_pos_l
;
182 last_pos
= this_pos_l
;
186 if (best_r
== NULL
) {
188 last_pos
= best_pos_r
= this_pos_r
;
190 this_pos_r
= r
->sectorOffset
- arm_pos
;
191 if (this_pos_r
< best_pos_r
) {
193 last_pos
= best_pos_r
= this_pos_r
;
195 last_pos
= this_pos_r
;
197 if (this_pos_r
> last_pos
) {
198 /* getting farther away */
204 if ((best_r
== NULL
) && (best_l
== NULL
))
206 if ((*dir
== DIR_RIGHT
) && best_r
)
208 if ((*dir
== DIR_LEFT
) && best_l
)
210 if (*dir
== DIR_EITHER
) {
215 if (best_pos_r
< best_pos_l
)
221 * Nothing in the direction we want to go. Reverse or
222 * reset the arm. We know we have an I/O in the other
226 if (*dir
== DIR_RIGHT
) {
235 * Reset (beginning of queue).
237 RF_ASSERT(*dir
== DIR_RIGHT
);
238 return (queue
->queue
);
243 RF_SectorCount_t sect_per_disk
,
244 RF_AllocListElem_t
*cl_list
,
245 RF_ShutdownList_t
**listp
)
249 RF_MallocAndAdd(sstfq
, sizeof(RF_Sstf_t
), (RF_Sstf_t
*), cl_list
);
250 sstfq
->dir
= DIR_EITHER
;
251 sstfq
->allow_reverse
= 1;
252 return ((void *) sstfq
);
257 RF_SectorCount_t sect_per_disk
,
258 RF_AllocListElem_t
*cl_list
,
259 RF_ShutdownList_t
**listp
)
263 RF_MallocAndAdd(scanq
, sizeof(RF_Sstf_t
), (RF_Sstf_t
*), cl_list
);
264 scanq
->dir
= DIR_RIGHT
;
265 scanq
->allow_reverse
= 1;
266 return ((void *) scanq
);
271 RF_SectorCount_t sect_per_disk
,
272 RF_AllocListElem_t
*cl_list
,
273 RF_ShutdownList_t
**listp
)
277 RF_MallocAndAdd(cscanq
, sizeof(RF_Sstf_t
), (RF_Sstf_t
*), cl_list
);
278 cscanq
->dir
= DIR_RIGHT
;
279 return ((void *) cscanq
);
283 rf_SstfEnqueue(void *qptr
, RF_DiskQueueData_t
*req
, int priority
)
287 sstfq
= (RF_Sstf_t
*) qptr
;
289 if (priority
== RF_IO_LOW_PRIORITY
) {
291 if (rf_sstfDebug
|| rf_scanDebug
|| rf_cscanDebug
) {
293 dq
= (RF_DiskQueue_t
*) req
->queue
;
294 printf("raid%d: ENQ lopri %d queues are %d,%d,%d\n",
295 req
->raidPtr
->raidid
,
297 sstfq
->left
.qlen
, sstfq
->right
.qlen
,
301 do_sstf_ord_q(&sstfq
->lopri
.queue
, &sstfq
->lopri
.qtail
, req
);
304 if (req
->sectorOffset
< sstfq
->last_sector
) {
305 do_sstf_ord_q(&sstfq
->left
.queue
, &sstfq
->left
.qtail
, req
);
308 do_sstf_ord_q(&sstfq
->right
.queue
, &sstfq
->right
.qtail
, req
);
315 do_dequeue(RF_SstfQ_t
*queue
, RF_DiskQueueData_t
*req
)
317 RF_DiskQueueData_t
*req2
;
320 if (rf_sstfDebug
|| rf_scanDebug
|| rf_cscanDebug
) {
321 printf("raid%d: do_dequeue\n", req
->raidPtr
->raidid
);
324 if (req
== queue
->queue
) {
325 DO_HEAD_DEQ(req2
, queue
);
326 RF_ASSERT(req2
== req
);
328 if (req
== queue
->qtail
) {
329 DO_TAIL_DEQ(req2
, queue
);
330 RF_ASSERT(req2
== req
);
332 /* dequeue from middle of list */
333 RF_ASSERT(req
->next
);
334 RF_ASSERT(req
->prev
);
336 req
->next
->prev
= req
->prev
;
337 req
->prev
->next
= req
->next
;
338 req
->next
= req
->prev
= NULL
;
343 rf_SstfDequeue(void *qptr
)
345 RF_DiskQueueData_t
*req
= NULL
;
348 sstfq
= (RF_Sstf_t
*) qptr
;
353 dq
= (RF_DiskQueue_t
*) req
->queue
;
354 RF_ASSERT(QSUM(sstfq
) == dq
->queueLength
);
355 printf("raid%d: sstf: Dequeue %d queues are %d,%d,%d\n",
356 req
->raidPtr
->raidid
, dq
->col
,
357 sstfq
->left
.qlen
, sstfq
->right
.qlen
, sstfq
->lopri
.qlen
);
360 if (sstfq
->left
.queue
== NULL
) {
361 RF_ASSERT(sstfq
->left
.qlen
== 0);
362 if (sstfq
->right
.queue
== NULL
) {
363 RF_ASSERT(sstfq
->right
.qlen
== 0);
364 if (sstfq
->lopri
.queue
== NULL
) {
365 RF_ASSERT(sstfq
->lopri
.qlen
== 0);
370 printf("raid%d: sstf: check for close lopri",
371 req
->raidPtr
->raidid
);
374 req
= closest_to_arm(&sstfq
->lopri
, sstfq
->last_sector
,
375 &sstfq
->dir
, sstfq
->allow_reverse
);
378 printf("raid%d: sstf: closest_to_arm said %lx",
379 req
->raidPtr
->raidid
, (long) req
);
384 do_dequeue(&sstfq
->lopri
, req
);
386 DO_BEST_DEQ(sstfq
->last_sector
, req
, &sstfq
->right
);
389 if (sstfq
->right
.queue
== NULL
) {
390 RF_ASSERT(sstfq
->right
.qlen
== 0);
391 DO_BEST_DEQ(sstfq
->last_sector
, req
, &sstfq
->left
);
393 if (SNUM_DIFF(sstfq
->last_sector
, sstfq
->right
.queue
->sectorOffset
)
394 < SNUM_DIFF(sstfq
->last_sector
, sstfq
->left
.qtail
->sectorOffset
)) {
395 DO_HEAD_DEQ(req
, &sstfq
->right
);
397 DO_TAIL_DEQ(req
, &sstfq
->left
);
402 sstfq
->last_sector
= req
->sectorOffset
;
407 rf_ScanDequeue(void *qptr
)
409 RF_DiskQueueData_t
*req
= NULL
;
412 scanq
= (RF_Sstf_t
*) qptr
;
417 dq
= (RF_DiskQueue_t
*) req
->queue
;
418 RF_ASSERT(QSUM(scanq
) == dq
->queueLength
);
419 printf("raid%d: scan: Dequeue %d queues are %d,%d,%d\n",
420 req
->raidPtr
->raidid
, dq
->col
,
421 scanq
->left
.qlen
, scanq
->right
.qlen
, scanq
->lopri
.qlen
);
424 if (scanq
->left
.queue
== NULL
) {
425 RF_ASSERT(scanq
->left
.qlen
== 0);
426 if (scanq
->right
.queue
== NULL
) {
427 RF_ASSERT(scanq
->right
.qlen
== 0);
428 if (scanq
->lopri
.queue
== NULL
) {
429 RF_ASSERT(scanq
->lopri
.qlen
== 0);
432 req
= closest_to_arm(&scanq
->lopri
, scanq
->last_sector
,
433 &scanq
->dir
, scanq
->allow_reverse
);
436 do_dequeue(&scanq
->lopri
, req
);
438 scanq
->dir
= DIR_RIGHT
;
439 DO_HEAD_DEQ(req
, &scanq
->right
);
442 if (scanq
->right
.queue
== NULL
) {
443 RF_ASSERT(scanq
->right
.qlen
== 0);
444 RF_ASSERT(scanq
->left
.queue
);
445 scanq
->dir
= DIR_LEFT
;
446 DO_TAIL_DEQ(req
, &scanq
->left
);
448 RF_ASSERT(scanq
->right
.queue
);
449 RF_ASSERT(scanq
->left
.queue
);
450 if (scanq
->dir
== DIR_RIGHT
) {
451 DO_HEAD_DEQ(req
, &scanq
->right
);
453 DO_TAIL_DEQ(req
, &scanq
->left
);
457 scanq
->last_sector
= req
->sectorOffset
;
462 rf_CscanDequeue(void *qptr
)
464 RF_DiskQueueData_t
*req
= NULL
;
467 cscanq
= (RF_Sstf_t
*) qptr
;
469 RF_ASSERT(cscanq
->dir
== DIR_RIGHT
);
473 dq
= (RF_DiskQueue_t
*) req
->queue
;
474 RF_ASSERT(QSUM(cscanq
) == dq
->queueLength
);
475 printf("raid%d: scan: Dequeue %d queues are %d,%d,%d\n",
476 req
->raidPtr
->raidid
, dq
->col
,
477 cscanq
->left
.qlen
, cscanq
->right
.qlen
,
481 if (cscanq
->right
.queue
) {
482 DO_HEAD_DEQ(req
, &cscanq
->right
);
484 RF_ASSERT(cscanq
->right
.qlen
== 0);
485 if (cscanq
->left
.queue
== NULL
) {
486 RF_ASSERT(cscanq
->left
.qlen
== 0);
487 if (cscanq
->lopri
.queue
== NULL
) {
488 RF_ASSERT(cscanq
->lopri
.qlen
== 0);
491 req
= closest_to_arm(&cscanq
->lopri
, cscanq
->last_sector
,
492 &cscanq
->dir
, cscanq
->allow_reverse
);
495 do_dequeue(&cscanq
->lopri
, req
);
498 * There's I/Os to the left of the arm. Swing
499 * on back (swap queues).
501 cscanq
->right
= cscanq
->left
;
502 cscanq
->left
.qlen
= 0;
503 cscanq
->left
.queue
= cscanq
->left
.qtail
= NULL
;
504 DO_HEAD_DEQ(req
, &cscanq
->right
);
508 cscanq
->last_sector
= req
->sectorOffset
;
513 rf_SstfPeek(void *qptr
)
515 RF_DiskQueueData_t
*req
;
518 sstfq
= (RF_Sstf_t
*) qptr
;
520 if ((sstfq
->left
.queue
== NULL
) && (sstfq
->right
.queue
== NULL
)) {
521 req
= closest_to_arm(&sstfq
->lopri
, sstfq
->last_sector
, &sstfq
->dir
,
522 sstfq
->allow_reverse
);
524 if (sstfq
->left
.queue
== NULL
)
525 req
= sstfq
->right
.queue
;
527 if (sstfq
->right
.queue
== NULL
)
528 req
= sstfq
->left
.queue
;
530 if (SNUM_DIFF(sstfq
->last_sector
, sstfq
->right
.queue
->sectorOffset
)
531 < SNUM_DIFF(sstfq
->last_sector
, sstfq
->left
.qtail
->sectorOffset
)) {
532 req
= sstfq
->right
.queue
;
534 req
= sstfq
->left
.qtail
;
540 RF_ASSERT(QSUM(sstfq
) == 0);
546 rf_ScanPeek(void *qptr
)
548 RF_DiskQueueData_t
*req
;
552 scanq
= (RF_Sstf_t
*) qptr
;
555 if (scanq
->left
.queue
== NULL
) {
556 RF_ASSERT(scanq
->left
.qlen
== 0);
557 if (scanq
->right
.queue
== NULL
) {
558 RF_ASSERT(scanq
->right
.qlen
== 0);
559 if (scanq
->lopri
.queue
== NULL
) {
560 RF_ASSERT(scanq
->lopri
.qlen
== 0);
563 req
= closest_to_arm(&scanq
->lopri
, scanq
->last_sector
,
564 &dir
, scanq
->allow_reverse
);
566 req
= scanq
->right
.queue
;
569 if (scanq
->right
.queue
== NULL
) {
570 RF_ASSERT(scanq
->right
.qlen
== 0);
571 RF_ASSERT(scanq
->left
.queue
);
572 req
= scanq
->left
.qtail
;
574 RF_ASSERT(scanq
->right
.queue
);
575 RF_ASSERT(scanq
->left
.queue
);
576 if (scanq
->dir
== DIR_RIGHT
) {
577 req
= scanq
->right
.queue
;
579 req
= scanq
->left
.qtail
;
583 RF_ASSERT(QSUM(scanq
) == 0);
589 rf_CscanPeek(void *qptr
)
591 RF_DiskQueueData_t
*req
;
594 cscanq
= (RF_Sstf_t
*) qptr
;
596 RF_ASSERT(cscanq
->dir
== DIR_RIGHT
);
597 if (cscanq
->right
.queue
) {
598 req
= cscanq
->right
.queue
;
600 RF_ASSERT(cscanq
->right
.qlen
== 0);
601 if (cscanq
->left
.queue
== NULL
) {
602 RF_ASSERT(cscanq
->left
.qlen
== 0);
603 if (cscanq
->lopri
.queue
== NULL
) {
604 RF_ASSERT(cscanq
->lopri
.qlen
== 0);
607 req
= closest_to_arm(&cscanq
->lopri
, cscanq
->last_sector
,
608 &cscanq
->dir
, cscanq
->allow_reverse
);
611 * There's I/Os to the left of the arm. We'll end
612 * up swinging on back.
614 req
= cscanq
->left
.queue
;
618 RF_ASSERT(QSUM(cscanq
) == 0);
624 rf_SstfPromote(void *qptr
, RF_StripeNum_t parityStripeID
, RF_ReconUnitNum_t which_ru
)
626 RF_DiskQueueData_t
*r
, *next
;
630 sstfq
= (RF_Sstf_t
*) qptr
;
633 for (r
= sstfq
->lopri
.queue
; r
; r
= next
) {
636 if (rf_sstfDebug
|| rf_scanDebug
|| rf_cscanDebug
) {
637 printf("raid%d: check promote %lx\n",
638 r
->raidPtr
->raidid
, (long) r
);
641 if ((r
->parityStripeID
== parityStripeID
)
642 && (r
->which_ru
== which_ru
)) {
643 do_dequeue(&sstfq
->lopri
, r
);
644 rf_SstfEnqueue(qptr
, r
, RF_IO_NORMAL_PRIORITY
);
649 if (rf_sstfDebug
|| rf_scanDebug
|| rf_cscanDebug
) {
650 printf("raid%d: promoted %d matching I/Os queues are %d,%d,%d\n",
651 r
->raidPtr
->raidid
, n
, sstfq
->left
.qlen
,
652 sstfq
->right
.qlen
, sstfq
->lopri
.qlen
);