rf_sstf.c revision 1.3 1 /* $NetBSD: rf_sstf.c,v 1.3 1999/02/05 00:06:17 oster Exp $ */
2 /*
3 * Copyright (c) 1995 Carnegie-Mellon University.
4 * All rights reserved.
5 *
6 * Author: Jim Zelenka
7 *
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.
13 *
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.
17 *
18 * Carnegie Mellon requests users of this software to return to
19 *
20 * Software Distribution Coordinator or Software.Distribution (at) CS.CMU.EDU
21 * School of Computer Science
22 * Carnegie Mellon University
23 * Pittsburgh PA 15213-3890
24 *
25 * any improvements or extensions that they make and grant Carnegie the
26 * rights to redistribute these changes.
27 */
28
29 /*******************************************************************************
30 *
31 * sstf.c -- prioritized shortest seek time first disk queueing code
32 *
33 ******************************************************************************/
34
35 #include "rf_alloclist.h"
36 #include "rf_stripelocks.h"
37 #include "rf_layout.h"
38 #include "rf_diskqueue.h"
39 #include "rf_sstf.h"
40 #include "rf_debugMem.h"
41 #include "rf_general.h"
42 #include "rf_threadid.h"
43 #include "rf_options.h"
44
45 #define DIR_LEFT 1
46 #define DIR_RIGHT 2
47 #define DIR_EITHER 3
48
49 #define SNUM_DIFF(_a_,_b_) (((_a_)>(_b_))?((_a_)-(_b_)):((_b_)-(_a_)))
50
51 #define QSUM(_sstfq_) (((_sstfq_)->lopri.qlen)+((_sstfq_)->left.qlen)+((_sstfq_)->right.qlen))
52
53
54 static void
55 do_sstf_ord_q(RF_DiskQueueData_t **,
56 RF_DiskQueueData_t **,
57 RF_DiskQueueData_t *);
58
59 static RF_DiskQueueData_t *
60 closest_to_arm(RF_SstfQ_t *,
61 RF_SectorNum_t,
62 int *,
63 int);
64 static void do_dequeue(RF_SstfQ_t *, RF_DiskQueueData_t *);
65
66
67 static void
68 do_sstf_ord_q(queuep, tailp, req)
69 RF_DiskQueueData_t **queuep;
70 RF_DiskQueueData_t **tailp;
71 RF_DiskQueueData_t *req;
72 {
73 RF_DiskQueueData_t *r, *s;
74
75 if (*queuep == NULL) {
76 *queuep = req;
77 *tailp = req;
78 req->next = NULL;
79 req->prev = NULL;
80 return;
81 }
82 if (req->sectorOffset <= (*queuep)->sectorOffset) {
83 req->next = *queuep;
84 req->prev = NULL;
85 (*queuep)->prev = req;
86 *queuep = req;
87 return;
88 }
89 if (req->sectorOffset > (*tailp)->sectorOffset) {
90 /* optimization */
91 r = NULL;
92 s = *tailp;
93 goto q_at_end;
94 }
95 for (s = NULL, r = *queuep; r; s = r, r = r->next) {
96 if (r->sectorOffset >= req->sectorOffset) {
97 /* insert after s, before r */
98 RF_ASSERT(s);
99 req->next = r;
100 r->prev = req;
101 s->next = req;
102 req->prev = s;
103 return;
104 }
105 }
106 q_at_end:
107 /* insert after s, at end of queue */
108 RF_ASSERT(r == NULL);
109 RF_ASSERT(s);
110 RF_ASSERT(s == (*tailp));
111 req->next = NULL;
112 req->prev = s;
113 s->next = req;
114 *tailp = req;
115 }
116 /* for removing from head-of-queue */
117 #define DO_HEAD_DEQ(_r_,_q_) { \
118 _r_ = (_q_)->queue; \
119 RF_ASSERT((_r_) != NULL); \
120 (_q_)->queue = (_r_)->next; \
121 (_q_)->qlen--; \
122 if ((_q_)->qlen == 0) { \
123 RF_ASSERT((_r_) == (_q_)->qtail); \
124 RF_ASSERT((_q_)->queue == NULL); \
125 (_q_)->qtail = NULL; \
126 } \
127 else { \
128 RF_ASSERT((_q_)->queue->prev == (_r_)); \
129 (_q_)->queue->prev = NULL; \
130 } \
131 }
132
133 /* for removing from end-of-queue */
134 #define DO_TAIL_DEQ(_r_,_q_) { \
135 _r_ = (_q_)->qtail; \
136 RF_ASSERT((_r_) != NULL); \
137 (_q_)->qtail = (_r_)->prev; \
138 (_q_)->qlen--; \
139 if ((_q_)->qlen == 0) { \
140 RF_ASSERT((_r_) == (_q_)->queue); \
141 RF_ASSERT((_q_)->qtail == NULL); \
142 (_q_)->queue = NULL; \
143 } \
144 else { \
145 RF_ASSERT((_q_)->qtail->next == (_r_)); \
146 (_q_)->qtail->next = NULL; \
147 } \
148 }
149
150 #define DO_BEST_DEQ(_l_,_r_,_q_) { \
151 if (SNUM_DIFF((_q_)->queue->sectorOffset,_l_) \
152 < SNUM_DIFF((_q_)->qtail->sectorOffset,_l_)) \
153 { \
154 DO_HEAD_DEQ(_r_,_q_); \
155 } \
156 else { \
157 DO_TAIL_DEQ(_r_,_q_); \
158 } \
159 }
160
161 static RF_DiskQueueData_t *
162 closest_to_arm(queue, arm_pos, dir, allow_reverse)
163 RF_SstfQ_t *queue;
164 RF_SectorNum_t arm_pos;
165 int *dir;
166 int allow_reverse;
167 {
168 RF_SectorNum_t best_pos_l = 0, this_pos_l = 0, last_pos = 0;
169 RF_SectorNum_t best_pos_r = 0, this_pos_r = 0;
170 RF_DiskQueueData_t *r, *best_l, *best_r;
171
172 best_r = best_l = NULL;
173 for (r = queue->queue; r; r = r->next) {
174 if (r->sectorOffset < arm_pos) {
175 if (best_l == NULL) {
176 best_l = r;
177 last_pos = best_pos_l = this_pos_l;
178 } else {
179 this_pos_l = arm_pos - r->sectorOffset;
180 if (this_pos_l < best_pos_l) {
181 best_l = r;
182 last_pos = best_pos_l = this_pos_l;
183 } else {
184 last_pos = this_pos_l;
185 }
186 }
187 } else {
188 if (best_r == NULL) {
189 best_r = r;
190 last_pos = best_pos_r = this_pos_r;
191 } else {
192 this_pos_r = r->sectorOffset - arm_pos;
193 if (this_pos_r < best_pos_r) {
194 best_r = r;
195 last_pos = best_pos_r = this_pos_r;
196 } else {
197 last_pos = this_pos_r;
198 }
199 if (this_pos_r > last_pos) {
200 /* getting farther away */
201 break;
202 }
203 }
204 }
205 }
206 if ((best_r == NULL) && (best_l == NULL))
207 return (NULL);
208 if ((*dir == DIR_RIGHT) && best_r)
209 return (best_r);
210 if ((*dir == DIR_LEFT) && best_l)
211 return (best_l);
212 if (*dir == DIR_EITHER) {
213 if (best_l == NULL)
214 return (best_r);
215 if (best_r == NULL)
216 return (best_l);
217 if (best_pos_r < best_pos_l)
218 return (best_r);
219 else
220 return (best_l);
221 }
222 /*
223 * Nothing in the direction we want to go. Reverse or
224 * reset the arm. We know we have an I/O in the other
225 * direction.
226 */
227 if (allow_reverse) {
228 if (*dir == DIR_RIGHT) {
229 *dir = DIR_LEFT;
230 return (best_l);
231 } else {
232 *dir = DIR_RIGHT;
233 return (best_r);
234 }
235 }
236 /*
237 * Reset (beginning of queue).
238 */
239 RF_ASSERT(*dir == DIR_RIGHT);
240 return (queue->queue);
241 }
242
243 void *
244 rf_SstfCreate(sect_per_disk, cl_list, listp)
245 RF_SectorCount_t sect_per_disk;
246 RF_AllocListElem_t *cl_list;
247 RF_ShutdownList_t **listp;
248 {
249 RF_Sstf_t *sstfq;
250
251 RF_CallocAndAdd(sstfq, 1, sizeof(RF_Sstf_t), (RF_Sstf_t *), cl_list);
252 sstfq->dir = DIR_EITHER;
253 sstfq->allow_reverse = 1;
254 return ((void *) sstfq);
255 }
256
257 void *
258 rf_ScanCreate(sect_per_disk, cl_list, listp)
259 RF_SectorCount_t sect_per_disk;
260 RF_AllocListElem_t *cl_list;
261 RF_ShutdownList_t **listp;
262 {
263 RF_Sstf_t *scanq;
264
265 RF_CallocAndAdd(scanq, 1, sizeof(RF_Sstf_t), (RF_Sstf_t *), cl_list);
266 scanq->dir = DIR_RIGHT;
267 scanq->allow_reverse = 1;
268 return ((void *) scanq);
269 }
270
271 void *
272 rf_CscanCreate(sect_per_disk, cl_list, listp)
273 RF_SectorCount_t sect_per_disk;
274 RF_AllocListElem_t *cl_list;
275 RF_ShutdownList_t **listp;
276 {
277 RF_Sstf_t *cscanq;
278
279 RF_CallocAndAdd(cscanq, 1, sizeof(RF_Sstf_t), (RF_Sstf_t *), cl_list);
280 cscanq->dir = DIR_RIGHT;
281 return ((void *) cscanq);
282 }
283
284 void
285 rf_SstfEnqueue(qptr, req, priority)
286 void *qptr;
287 RF_DiskQueueData_t *req;
288 int priority;
289 {
290 RF_Sstf_t *sstfq;
291
292 sstfq = (RF_Sstf_t *) qptr;
293
294 if (priority == RF_IO_LOW_PRIORITY) {
295 if (rf_sstfDebug || rf_scanDebug || rf_cscanDebug) {
296 RF_DiskQueue_t *dq;
297 int tid;
298 rf_get_threadid(tid);
299 dq = (RF_DiskQueue_t *) req->queue;
300 printf("[%d] ENQ lopri %d,%d queues are %d,%d,%d\n",
301 tid, dq->row, dq->col, sstfq->left.qlen, sstfq->right.qlen,
302 sstfq->lopri.qlen);
303 }
304 do_sstf_ord_q(&sstfq->lopri.queue, &sstfq->lopri.qtail, req);
305 sstfq->lopri.qlen++;
306 } else {
307 if (req->sectorOffset < sstfq->last_sector) {
308 do_sstf_ord_q(&sstfq->left.queue, &sstfq->left.qtail, req);
309 sstfq->left.qlen++;
310 } else {
311 do_sstf_ord_q(&sstfq->right.queue, &sstfq->right.qtail, req);
312 sstfq->right.qlen++;
313 }
314 }
315 }
316
317 static void
318 do_dequeue(queue, req)
319 RF_SstfQ_t *queue;
320 RF_DiskQueueData_t *req;
321 {
322 RF_DiskQueueData_t *req2;
323
324 if (rf_sstfDebug || rf_scanDebug || rf_cscanDebug) {
325 int tid;
326 rf_get_threadid(tid);
327 printf("[%d] do_dequeue\n", tid);
328 }
329 if (req == queue->queue) {
330 DO_HEAD_DEQ(req2, queue);
331 RF_ASSERT(req2 == req);
332 } else
333 if (req == queue->qtail) {
334 DO_TAIL_DEQ(req2, queue);
335 RF_ASSERT(req2 == req);
336 } else {
337 /* dequeue from middle of list */
338 RF_ASSERT(req->next);
339 RF_ASSERT(req->prev);
340 queue->qlen--;
341 req->next->prev = req->prev;
342 req->prev->next = req->next;
343 req->next = req->prev = NULL;
344 }
345 }
346
347 RF_DiskQueueData_t *
348 rf_SstfDequeue(qptr)
349 void *qptr;
350 {
351 RF_DiskQueueData_t *req = NULL;
352 RF_Sstf_t *sstfq;
353
354 sstfq = (RF_Sstf_t *) qptr;
355
356 if (rf_sstfDebug) {
357 RF_DiskQueue_t *dq;
358 int tid;
359 rf_get_threadid(tid);
360 dq = (RF_DiskQueue_t *) req->queue;
361 RF_ASSERT(QSUM(sstfq) == dq->queueLength);
362 printf("[%d] sstf: Dequeue %d,%d queues are %d,%d,%d\n", tid,
363 dq->row, dq->col, sstfq->left.qlen, sstfq->right.qlen,
364 sstfq->lopri.qlen);
365 }
366 if (sstfq->left.queue == NULL) {
367 RF_ASSERT(sstfq->left.qlen == 0);
368 if (sstfq->right.queue == NULL) {
369 RF_ASSERT(sstfq->right.qlen == 0);
370 if (sstfq->lopri.queue == NULL) {
371 RF_ASSERT(sstfq->lopri.qlen == 0);
372 return (NULL);
373 }
374 if (rf_sstfDebug) {
375 int tid;
376 rf_get_threadid(tid);
377 printf("[%d] sstf: check for close lopri", tid);
378 }
379 req = closest_to_arm(&sstfq->lopri, sstfq->last_sector,
380 &sstfq->dir, sstfq->allow_reverse);
381 if (rf_sstfDebug) {
382 int tid;
383 rf_get_threadid(tid);
384 printf("[%d] sstf: closest_to_arm said %lx", tid, (long) req);
385 }
386 if (req == NULL)
387 return (NULL);
388 do_dequeue(&sstfq->lopri, req);
389 } else {
390 DO_BEST_DEQ(sstfq->last_sector, req, &sstfq->right);
391 }
392 } else {
393 if (sstfq->right.queue == NULL) {
394 RF_ASSERT(sstfq->right.qlen == 0);
395 DO_BEST_DEQ(sstfq->last_sector, req, &sstfq->left);
396 } else {
397 if (SNUM_DIFF(sstfq->last_sector, sstfq->right.queue->sectorOffset)
398 < SNUM_DIFF(sstfq->last_sector, sstfq->left.qtail->sectorOffset)) {
399 DO_HEAD_DEQ(req, &sstfq->right);
400 } else {
401 DO_TAIL_DEQ(req, &sstfq->left);
402 }
403 }
404 }
405 RF_ASSERT(req);
406 sstfq->last_sector = req->sectorOffset;
407 return (req);
408 }
409
410 RF_DiskQueueData_t *
411 rf_ScanDequeue(qptr)
412 void *qptr;
413 {
414 RF_DiskQueueData_t *req = NULL;
415 RF_Sstf_t *scanq;
416
417 scanq = (RF_Sstf_t *) qptr;
418
419 if (rf_scanDebug) {
420 RF_DiskQueue_t *dq;
421 int tid;
422 rf_get_threadid(tid);
423 dq = (RF_DiskQueue_t *) req->queue;
424 RF_ASSERT(QSUM(scanq) == dq->queueLength);
425 printf("[%d] scan: Dequeue %d,%d queues are %d,%d,%d\n", tid,
426 dq->row, dq->col, scanq->left.qlen, scanq->right.qlen,
427 scanq->lopri.qlen);
428 }
429 if (scanq->left.queue == NULL) {
430 RF_ASSERT(scanq->left.qlen == 0);
431 if (scanq->right.queue == NULL) {
432 RF_ASSERT(scanq->right.qlen == 0);
433 if (scanq->lopri.queue == NULL) {
434 RF_ASSERT(scanq->lopri.qlen == 0);
435 return (NULL);
436 }
437 req = closest_to_arm(&scanq->lopri, scanq->last_sector,
438 &scanq->dir, scanq->allow_reverse);
439 if (req == NULL)
440 return (NULL);
441 do_dequeue(&scanq->lopri, req);
442 } else {
443 scanq->dir = DIR_RIGHT;
444 DO_HEAD_DEQ(req, &scanq->right);
445 }
446 } else
447 if (scanq->right.queue == NULL) {
448 RF_ASSERT(scanq->right.qlen == 0);
449 RF_ASSERT(scanq->left.queue);
450 scanq->dir = DIR_LEFT;
451 DO_TAIL_DEQ(req, &scanq->left);
452 } else {
453 RF_ASSERT(scanq->right.queue);
454 RF_ASSERT(scanq->left.queue);
455 if (scanq->dir == DIR_RIGHT) {
456 DO_HEAD_DEQ(req, &scanq->right);
457 } else {
458 DO_TAIL_DEQ(req, &scanq->left);
459 }
460 }
461 RF_ASSERT(req);
462 scanq->last_sector = req->sectorOffset;
463 return (req);
464 }
465
466 RF_DiskQueueData_t *
467 rf_CscanDequeue(qptr)
468 void *qptr;
469 {
470 RF_DiskQueueData_t *req = NULL;
471 RF_Sstf_t *cscanq;
472
473 cscanq = (RF_Sstf_t *) qptr;
474
475 RF_ASSERT(cscanq->dir == DIR_RIGHT);
476 if (rf_cscanDebug) {
477 RF_DiskQueue_t *dq;
478 int tid;
479 rf_get_threadid(tid);
480 dq = (RF_DiskQueue_t *) req->queue;
481 RF_ASSERT(QSUM(cscanq) == dq->queueLength);
482 printf("[%d] scan: Dequeue %d,%d queues are %d,%d,%d\n", tid,
483 dq->row, dq->col, cscanq->left.qlen, cscanq->right.qlen,
484 cscanq->lopri.qlen);
485 }
486 if (cscanq->right.queue) {
487 DO_HEAD_DEQ(req, &cscanq->right);
488 } else {
489 RF_ASSERT(cscanq->right.qlen == 0);
490 if (cscanq->left.queue == NULL) {
491 RF_ASSERT(cscanq->left.qlen == 0);
492 if (cscanq->lopri.queue == NULL) {
493 RF_ASSERT(cscanq->lopri.qlen == 0);
494 return (NULL);
495 }
496 req = closest_to_arm(&cscanq->lopri, cscanq->last_sector,
497 &cscanq->dir, cscanq->allow_reverse);
498 if (req == NULL)
499 return (NULL);
500 do_dequeue(&cscanq->lopri, req);
501 } else {
502 /*
503 * There's I/Os to the left of the arm. Swing
504 * on back (swap queues).
505 */
506 cscanq->right = cscanq->left;
507 cscanq->left.qlen = 0;
508 cscanq->left.queue = cscanq->left.qtail = NULL;
509 DO_HEAD_DEQ(req, &cscanq->right);
510 }
511 }
512 RF_ASSERT(req);
513 cscanq->last_sector = req->sectorOffset;
514 return (req);
515 }
516
517 RF_DiskQueueData_t *
518 rf_SstfPeek(qptr)
519 void *qptr;
520 {
521 RF_DiskQueueData_t *req;
522 RF_Sstf_t *sstfq;
523
524 sstfq = (RF_Sstf_t *) qptr;
525
526 if ((sstfq->left.queue == NULL) && (sstfq->right.queue == NULL)) {
527 req = closest_to_arm(&sstfq->lopri, sstfq->last_sector, &sstfq->dir,
528 sstfq->allow_reverse);
529 } else {
530 if (sstfq->left.queue == NULL)
531 req = sstfq->right.queue;
532 else {
533 if (sstfq->right.queue == NULL)
534 req = sstfq->left.queue;
535 else {
536 if (SNUM_DIFF(sstfq->last_sector, sstfq->right.queue->sectorOffset)
537 < SNUM_DIFF(sstfq->last_sector, sstfq->left.qtail->sectorOffset)) {
538 req = sstfq->right.queue;
539 } else {
540 req = sstfq->left.qtail;
541 }
542 }
543 }
544 }
545 if (req == NULL) {
546 RF_ASSERT(QSUM(sstfq) == 0);
547 }
548 return (req);
549 }
550
551 RF_DiskQueueData_t *
552 rf_ScanPeek(qptr)
553 void *qptr;
554 {
555 RF_DiskQueueData_t *req;
556 RF_Sstf_t *scanq;
557 int dir;
558
559 scanq = (RF_Sstf_t *) qptr;
560 dir = scanq->dir;
561
562 if (scanq->left.queue == NULL) {
563 RF_ASSERT(scanq->left.qlen == 0);
564 if (scanq->right.queue == NULL) {
565 RF_ASSERT(scanq->right.qlen == 0);
566 if (scanq->lopri.queue == NULL) {
567 RF_ASSERT(scanq->lopri.qlen == 0);
568 return (NULL);
569 }
570 req = closest_to_arm(&scanq->lopri, scanq->last_sector,
571 &dir, scanq->allow_reverse);
572 } else {
573 req = scanq->right.queue;
574 }
575 } else
576 if (scanq->right.queue == NULL) {
577 RF_ASSERT(scanq->right.qlen == 0);
578 RF_ASSERT(scanq->left.queue);
579 req = scanq->left.qtail;
580 } else {
581 RF_ASSERT(scanq->right.queue);
582 RF_ASSERT(scanq->left.queue);
583 if (scanq->dir == DIR_RIGHT) {
584 req = scanq->right.queue;
585 } else {
586 req = scanq->left.qtail;
587 }
588 }
589 if (req == NULL) {
590 RF_ASSERT(QSUM(scanq) == 0);
591 }
592 return (req);
593 }
594
595 RF_DiskQueueData_t *
596 rf_CscanPeek(qptr)
597 void *qptr;
598 {
599 RF_DiskQueueData_t *req;
600 RF_Sstf_t *cscanq;
601
602 cscanq = (RF_Sstf_t *) qptr;
603
604 RF_ASSERT(cscanq->dir == DIR_RIGHT);
605 if (cscanq->right.queue) {
606 req = cscanq->right.queue;
607 } else {
608 RF_ASSERT(cscanq->right.qlen == 0);
609 if (cscanq->left.queue == NULL) {
610 RF_ASSERT(cscanq->left.qlen == 0);
611 if (cscanq->lopri.queue == NULL) {
612 RF_ASSERT(cscanq->lopri.qlen == 0);
613 return (NULL);
614 }
615 req = closest_to_arm(&cscanq->lopri, cscanq->last_sector,
616 &cscanq->dir, cscanq->allow_reverse);
617 } else {
618 /*
619 * There's I/Os to the left of the arm. We'll end
620 * up swinging on back.
621 */
622 req = cscanq->left.queue;
623 }
624 }
625 if (req == NULL) {
626 RF_ASSERT(QSUM(cscanq) == 0);
627 }
628 return (req);
629 }
630
631 int
632 rf_SstfPromote(qptr, parityStripeID, which_ru)
633 void *qptr;
634 RF_StripeNum_t parityStripeID;
635 RF_ReconUnitNum_t which_ru;
636 {
637 RF_DiskQueueData_t *r, *next;
638 RF_Sstf_t *sstfq;
639 int n;
640
641 sstfq = (RF_Sstf_t *) qptr;
642
643 n = 0;
644 if (rf_sstfDebug || rf_scanDebug || rf_cscanDebug) {
645 int tid;
646 rf_get_threadid(tid);
647 printf("[%d] promote %ld %d queues are %d,%d,%d\n",
648 tid, (long) parityStripeID, (int) which_ru,
649 sstfq->left.qlen,
650 sstfq->right.qlen,
651 sstfq->lopri.qlen);
652 }
653 for (r = sstfq->lopri.queue; r; r = next) {
654 next = r->next;
655 if (rf_sstfDebug || rf_scanDebug || rf_cscanDebug) {
656 int tid;
657 rf_get_threadid(tid);
658 printf("[%d] check promote %lx\n", tid, (long) r);
659 }
660 if ((r->parityStripeID == parityStripeID)
661 && (r->which_ru == which_ru)) {
662 do_dequeue(&sstfq->lopri, r);
663 rf_SstfEnqueue(qptr, r, RF_IO_NORMAL_PRIORITY);
664 n++;
665 }
666 }
667 if (rf_sstfDebug || rf_scanDebug || rf_cscanDebug) {
668 int tid;
669 rf_get_threadid(tid);
670 printf("[%d] promoted %d matching I/Os queues are %d,%d,%d\n",
671 tid, n, sstfq->left.qlen, sstfq->right.qlen, sstfq->lopri.qlen);
672 }
673 return (n);
674 }
675