diff options
author | Niklas Hallqvist <niklas@cvs.openbsd.org> | 1999-01-11 14:29:56 +0000 |
---|---|---|
committer | Niklas Hallqvist <niklas@cvs.openbsd.org> | 1999-01-11 14:29:56 +0000 |
commit | 5a29b52d01b420bb61a3112d2d44740a0fa99601 (patch) | |
tree | 7d6238740f53a56f5c76ba8256c785b13caaa24a /sys/dev/raidframe/rf_sstf.c | |
parent | 799a3ea9a9c07e091f5f4e62273c6f105cf86191 (diff) |
Import of CMU's RAIDframe via NetBSD.
Diffstat (limited to 'sys/dev/raidframe/rf_sstf.c')
-rw-r--r-- | sys/dev/raidframe/rf_sstf.c | 717 |
1 files changed, 717 insertions, 0 deletions
diff --git a/sys/dev/raidframe/rf_sstf.c b/sys/dev/raidframe/rf_sstf.c new file mode 100644 index 00000000000..21d97eef046 --- /dev/null +++ b/sys/dev/raidframe/rf_sstf.c @@ -0,0 +1,717 @@ +/* $OpenBSD: rf_sstf.c,v 1.1 1999/01/11 14:29:50 niklas Exp $ */ +/* $NetBSD: rf_sstf.c,v 1.1 1998/11/13 04:20:34 oster Exp $ */ +/* + * Copyright (c) 1995 Carnegie-Mellon University. + * All rights reserved. + * + * Author: Jim Zelenka + * + * Permission to use, copy, modify and distribute this software and + * its documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND + * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie the + * rights to redistribute these changes. + */ + +/******************************************************************************* + * + * sstf.c -- prioritized shortest seek time first disk queueing code + * + ******************************************************************************/ + +/* + * : + * Log: rf_sstf.c,v + * Revision 1.7 1996/06/19 14:09:56 jimz + * SstfPeek wasn't calling closest_to_arm() properly- would bogart + * low priority I/Os + * + * Revision 1.6 1996/06/18 20:53:11 jimz + * fix up disk queueing (remove configure routine, + * add shutdown list arg to create routines) + * + * Revision 1.5 1996/06/13 20:42:13 jimz + * add scan, cscan + * + * Revision 1.4 1996/06/07 22:26:27 jimz + * type-ify which_ru (RF_ReconUnitNum_t) + * + * Revision 1.3 1996/06/07 21:33:04 jimz + * begin using consistent types for sector numbers, + * stripe numbers, row+col numbers, recon unit numbers + * + * Revision 1.2 1996/06/06 01:11:35 jimz + * fixed many priority-related bugs + * + * Revision 1.1 1996/06/05 19:17:40 jimz + * Initial revision + * + */ + +#include "rf_alloclist.h" +#include "rf_stripelocks.h" +#include "rf_layout.h" +#include "rf_diskqueue.h" +#include "rf_sstf.h" +#include "rf_debugMem.h" +#include "rf_general.h" +#include "rf_threadid.h" +#include "rf_options.h" + +#define DIR_LEFT 1 +#define DIR_RIGHT 2 +#define DIR_EITHER 3 + +#define SNUM_DIFF(_a_,_b_) (((_a_)>(_b_))?((_a_)-(_b_)):((_b_)-(_a_))) + +#define QSUM(_sstfq_) (((_sstfq_)->lopri.qlen)+((_sstfq_)->left.qlen)+((_sstfq_)->right.qlen)) + + +static void do_sstf_ord_q(RF_DiskQueueData_t **, + RF_DiskQueueData_t **, + RF_DiskQueueData_t *); + +static RF_DiskQueueData_t *closest_to_arm(RF_SstfQ_t *, + RF_SectorNum_t, + int *, + int); +static void do_dequeue(RF_SstfQ_t *, RF_DiskQueueData_t *); + + +static void do_sstf_ord_q(queuep, tailp, req) + RF_DiskQueueData_t **queuep; + RF_DiskQueueData_t **tailp; + RF_DiskQueueData_t *req; +{ + RF_DiskQueueData_t *r, *s; + + if (*queuep == NULL) { + *queuep = req; + *tailp = req; + req->next = NULL; + req->prev = NULL; + return; + } + if (req->sectorOffset <= (*queuep)->sectorOffset) { + req->next = *queuep; + req->prev = NULL; + (*queuep)->prev = req; + *queuep = req; + return; + } + if (req->sectorOffset > (*tailp)->sectorOffset) { + /* optimization */ + r = NULL; + s = *tailp; + goto q_at_end; + } + for(s=NULL,r=*queuep;r;s=r,r=r->next) { + if (r->sectorOffset >= req->sectorOffset) { + /* insert after s, before r */ + RF_ASSERT(s); + req->next = r; + r->prev = req; + s->next = req; + req->prev = s; + return; + } + } +q_at_end: + /* insert after s, at end of queue */ + RF_ASSERT(r == NULL); + RF_ASSERT(s); + RF_ASSERT(s == (*tailp)); + req->next = NULL; + req->prev = s; + s->next = req; + *tailp = req; +} + +/* for removing from head-of-queue */ +#define DO_HEAD_DEQ(_r_,_q_) { \ + _r_ = (_q_)->queue; \ + RF_ASSERT((_r_) != NULL); \ + (_q_)->queue = (_r_)->next; \ + (_q_)->qlen--; \ + if ((_q_)->qlen == 0) { \ + RF_ASSERT((_r_) == (_q_)->qtail); \ + RF_ASSERT((_q_)->queue == NULL); \ + (_q_)->qtail = NULL; \ + } \ + else { \ + RF_ASSERT((_q_)->queue->prev == (_r_)); \ + (_q_)->queue->prev = NULL; \ + } \ +} + +/* for removing from end-of-queue */ +#define DO_TAIL_DEQ(_r_,_q_) { \ + _r_ = (_q_)->qtail; \ + RF_ASSERT((_r_) != NULL); \ + (_q_)->qtail = (_r_)->prev; \ + (_q_)->qlen--; \ + if ((_q_)->qlen == 0) { \ + RF_ASSERT((_r_) == (_q_)->queue); \ + RF_ASSERT((_q_)->qtail == NULL); \ + (_q_)->queue = NULL; \ + } \ + else { \ + RF_ASSERT((_q_)->qtail->next == (_r_)); \ + (_q_)->qtail->next = NULL; \ + } \ +} + +#define DO_BEST_DEQ(_l_,_r_,_q_) { \ + if (SNUM_DIFF((_q_)->queue->sectorOffset,_l_) \ + < SNUM_DIFF((_q_)->qtail->sectorOffset,_l_)) \ + { \ + DO_HEAD_DEQ(_r_,_q_); \ + } \ + else { \ + DO_TAIL_DEQ(_r_,_q_); \ + } \ +} + +static RF_DiskQueueData_t *closest_to_arm(queue, arm_pos, dir, allow_reverse) + RF_SstfQ_t *queue; + RF_SectorNum_t arm_pos; + int *dir; + int allow_reverse; +{ + RF_SectorNum_t best_pos_l=0, this_pos_l=0, last_pos=0; + RF_SectorNum_t best_pos_r=0, this_pos_r=0; + RF_DiskQueueData_t *r, *best_l, *best_r; + + best_r = best_l = NULL; + for(r=queue->queue;r;r=r->next) { + if (r->sectorOffset < arm_pos) { + if (best_l == NULL) { + best_l = r; + last_pos = best_pos_l = this_pos_l; + } + else { + this_pos_l = arm_pos - r->sectorOffset; + if (this_pos_l < best_pos_l) { + best_l = r; + last_pos = best_pos_l = this_pos_l; + } + else { + last_pos = this_pos_l; + } + } + } + else { + if (best_r == NULL) { + best_r = r; + last_pos = best_pos_r = this_pos_r; + } + else { + this_pos_r = r->sectorOffset - arm_pos; + if (this_pos_r < best_pos_r) { + best_r = r; + last_pos = best_pos_r = this_pos_r; + } + else { + last_pos = this_pos_r; + } + if (this_pos_r > last_pos) { + /* getting farther away */ + break; + } + } + } + } + if ((best_r == NULL) && (best_l == NULL)) + return(NULL); + if ((*dir == DIR_RIGHT) && best_r) + return(best_r); + if ((*dir == DIR_LEFT) && best_l) + return(best_l); + if (*dir == DIR_EITHER) { + if (best_l == NULL) + return(best_r); + if (best_r == NULL) + return(best_l); + if (best_pos_r < best_pos_l) + return(best_r); + else + return(best_l); + } + /* + * Nothing in the direction we want to go. Reverse or + * reset the arm. We know we have an I/O in the other + * direction. + */ + if (allow_reverse) { + if (*dir == DIR_RIGHT) { + *dir = DIR_LEFT; + return(best_l); + } + else { + *dir = DIR_RIGHT; + return(best_r); + } + } + /* + * Reset (beginning of queue). + */ + RF_ASSERT(*dir == DIR_RIGHT); + return(queue->queue); +} + +void *rf_SstfCreate(sect_per_disk, cl_list, listp) + RF_SectorCount_t sect_per_disk; + RF_AllocListElem_t *cl_list; + RF_ShutdownList_t **listp; +{ + RF_Sstf_t *sstfq; + + RF_CallocAndAdd(sstfq, 1, sizeof(RF_Sstf_t), (RF_Sstf_t *), cl_list); + sstfq->dir = DIR_EITHER; + sstfq->allow_reverse = 1; + return((void *)sstfq); +} + +void *rf_ScanCreate(sect_per_disk, cl_list, listp) + RF_SectorCount_t sect_per_disk; + RF_AllocListElem_t *cl_list; + RF_ShutdownList_t **listp; +{ + RF_Sstf_t *scanq; + + RF_CallocAndAdd(scanq, 1, sizeof(RF_Sstf_t), (RF_Sstf_t *), cl_list); + scanq->dir = DIR_RIGHT; + scanq->allow_reverse = 1; + return((void *)scanq); +} + +void *rf_CscanCreate(sect_per_disk, cl_list, listp) + RF_SectorCount_t sect_per_disk; + RF_AllocListElem_t *cl_list; + RF_ShutdownList_t **listp; +{ + RF_Sstf_t *cscanq; + + RF_CallocAndAdd(cscanq, 1, sizeof(RF_Sstf_t), (RF_Sstf_t *), cl_list); + cscanq->dir = DIR_RIGHT; + return((void *)cscanq); +} + +void rf_SstfEnqueue(qptr, req, priority) + void *qptr; + RF_DiskQueueData_t *req; + int priority; +{ + RF_Sstf_t *sstfq; + + sstfq = (RF_Sstf_t *)qptr; + + if (priority == RF_IO_LOW_PRIORITY) { + if (rf_sstfDebug || rf_scanDebug || rf_cscanDebug) { + RF_DiskQueue_t *dq; + int tid; + rf_get_threadid(tid); + dq = (RF_DiskQueue_t *)req->queue; + printf("[%d] ENQ lopri %d,%d queues are %d,%d,%d\n", + tid, dq->row, dq->col, sstfq->left.qlen, sstfq->right.qlen, + sstfq->lopri.qlen); + } + do_sstf_ord_q(&sstfq->lopri.queue, &sstfq->lopri.qtail, req); + sstfq->lopri.qlen++; + } + else { + if (req->sectorOffset < sstfq->last_sector) { + do_sstf_ord_q(&sstfq->left.queue, &sstfq->left.qtail, req); + sstfq->left.qlen++; + } + else { + do_sstf_ord_q(&sstfq->right.queue, &sstfq->right.qtail, req); + sstfq->right.qlen++; + } + } +} + +static void do_dequeue(queue, req) + RF_SstfQ_t *queue; + RF_DiskQueueData_t *req; +{ + RF_DiskQueueData_t *req2; + + if (rf_sstfDebug || rf_scanDebug || rf_cscanDebug) { + int tid; + rf_get_threadid(tid); + printf("[%d] do_dequeue\n", tid); + } + if (req == queue->queue) { + DO_HEAD_DEQ(req2,queue); + RF_ASSERT(req2 == req); + } + else if (req == queue->qtail) { + DO_TAIL_DEQ(req2,queue); + RF_ASSERT(req2 == req); + } + else { + /* dequeue from middle of list */ + RF_ASSERT(req->next); + RF_ASSERT(req->prev); + queue->qlen--; + req->next->prev = req->prev; + req->prev->next = req->next; + req->next = req->prev = NULL; + } +} + +RF_DiskQueueData_t *rf_SstfDequeue(qptr) + void *qptr; +{ + RF_DiskQueueData_t *req=NULL; + RF_Sstf_t *sstfq; + + sstfq = (RF_Sstf_t *)qptr; + + if (rf_sstfDebug) { + RF_DiskQueue_t *dq; + int tid; + rf_get_threadid(tid); + dq = (RF_DiskQueue_t *)req->queue; + RF_ASSERT(QSUM(sstfq)==dq->queueLength); + printf("[%d] sstf: Dequeue %d,%d queues are %d,%d,%d\n", tid, + dq->row, dq->col, sstfq->left.qlen, sstfq->right.qlen, + sstfq->lopri.qlen); + } + if (sstfq->left.queue == NULL) { + RF_ASSERT(sstfq->left.qlen == 0); + if (sstfq->right.queue == NULL) { + RF_ASSERT(sstfq->right.qlen == 0); + if (sstfq->lopri.queue == NULL) { + RF_ASSERT(sstfq->lopri.qlen == 0); + return(NULL); + } + if (rf_sstfDebug) { + int tid; + rf_get_threadid(tid); + printf("[%d] sstf: check for close lopri", tid); + } + req = closest_to_arm(&sstfq->lopri, sstfq->last_sector, + &sstfq->dir, sstfq->allow_reverse); + if (rf_sstfDebug) { + int tid; + rf_get_threadid(tid); + printf("[%d] sstf: closest_to_arm said %lx", tid, (long)req); + } + if (req == NULL) + return(NULL); + do_dequeue(&sstfq->lopri, req); + } + else { + DO_BEST_DEQ(sstfq->last_sector,req,&sstfq->right); + } + } + else { + if (sstfq->right.queue == NULL) { + RF_ASSERT(sstfq->right.qlen == 0); + DO_BEST_DEQ(sstfq->last_sector,req,&sstfq->left); + } + else { + if (SNUM_DIFF(sstfq->last_sector,sstfq->right.queue->sectorOffset) + < SNUM_DIFF(sstfq->last_sector,sstfq->left.qtail->sectorOffset)) + { + DO_HEAD_DEQ(req,&sstfq->right); + } + else { + DO_TAIL_DEQ(req,&sstfq->left); + } + } + } + RF_ASSERT(req); + sstfq->last_sector = req->sectorOffset; + return(req); +} + +RF_DiskQueueData_t *rf_ScanDequeue(qptr) + void *qptr; +{ + RF_DiskQueueData_t *req=NULL; + RF_Sstf_t *scanq; + + scanq = (RF_Sstf_t *)qptr; + + if (rf_scanDebug) { + RF_DiskQueue_t *dq; + int tid; + rf_get_threadid(tid); + dq = (RF_DiskQueue_t *)req->queue; + RF_ASSERT(QSUM(scanq)==dq->queueLength); + printf("[%d] scan: Dequeue %d,%d queues are %d,%d,%d\n", tid, + dq->row, dq->col, scanq->left.qlen, scanq->right.qlen, + scanq->lopri.qlen); + } + if (scanq->left.queue == NULL) { + RF_ASSERT(scanq->left.qlen == 0); + if (scanq->right.queue == NULL) { + RF_ASSERT(scanq->right.qlen == 0); + if (scanq->lopri.queue == NULL) { + RF_ASSERT(scanq->lopri.qlen == 0); + return(NULL); + } + req = closest_to_arm(&scanq->lopri, scanq->last_sector, + &scanq->dir, scanq->allow_reverse); + if (req == NULL) + return(NULL); + do_dequeue(&scanq->lopri, req); + } + else { + scanq->dir = DIR_RIGHT; + DO_HEAD_DEQ(req,&scanq->right); + } + } + else if (scanq->right.queue == NULL) { + RF_ASSERT(scanq->right.qlen == 0); + RF_ASSERT(scanq->left.queue); + scanq->dir = DIR_LEFT; + DO_TAIL_DEQ(req,&scanq->left); + } + else { + RF_ASSERT(scanq->right.queue); + RF_ASSERT(scanq->left.queue); + if (scanq->dir == DIR_RIGHT) { + DO_HEAD_DEQ(req,&scanq->right); + } + else { + DO_TAIL_DEQ(req,&scanq->left); + } + } + RF_ASSERT(req); + scanq->last_sector = req->sectorOffset; + return(req); +} + +RF_DiskQueueData_t *rf_CscanDequeue(qptr) + void *qptr; +{ + RF_DiskQueueData_t *req=NULL; + RF_Sstf_t *cscanq; + + cscanq = (RF_Sstf_t *)qptr; + + RF_ASSERT(cscanq->dir == DIR_RIGHT); + if (rf_cscanDebug) { + RF_DiskQueue_t *dq; + int tid; + rf_get_threadid(tid); + dq = (RF_DiskQueue_t *)req->queue; + RF_ASSERT(QSUM(cscanq)==dq->queueLength); + printf("[%d] scan: Dequeue %d,%d queues are %d,%d,%d\n", tid, + dq->row, dq->col, cscanq->left.qlen, cscanq->right.qlen, + cscanq->lopri.qlen); + } + if (cscanq->right.queue) { + DO_HEAD_DEQ(req,&cscanq->right); + } + else { + RF_ASSERT(cscanq->right.qlen == 0); + if (cscanq->left.queue == NULL) { + RF_ASSERT(cscanq->left.qlen == 0); + if (cscanq->lopri.queue == NULL) { + RF_ASSERT(cscanq->lopri.qlen == 0); + return(NULL); + } + req = closest_to_arm(&cscanq->lopri, cscanq->last_sector, + &cscanq->dir, cscanq->allow_reverse); + if (req == NULL) + return(NULL); + do_dequeue(&cscanq->lopri, req); + } + else { + /* + * There's I/Os to the left of the arm. Swing + * on back (swap queues). + */ + cscanq->right = cscanq->left; + cscanq->left.qlen = 0; + cscanq->left.queue = cscanq->left.qtail = NULL; + DO_HEAD_DEQ(req,&cscanq->right); + } + } + RF_ASSERT(req); + cscanq->last_sector = req->sectorOffset; + return(req); +} + +RF_DiskQueueData_t *rf_SstfPeek(qptr) + void *qptr; +{ + RF_DiskQueueData_t *req; + RF_Sstf_t *sstfq; + + sstfq = (RF_Sstf_t *)qptr; + + if ((sstfq->left.queue == NULL) && (sstfq->right.queue == NULL)) { + req = closest_to_arm(&sstfq->lopri, sstfq->last_sector, &sstfq->dir, + sstfq->allow_reverse); + } + else { + if (sstfq->left.queue == NULL) + req = sstfq->right.queue; + else { + if (sstfq->right.queue == NULL) + req = sstfq->left.queue; + else { + if (SNUM_DIFF(sstfq->last_sector,sstfq->right.queue->sectorOffset) + <SNUM_DIFF(sstfq->last_sector,sstfq->left.qtail->sectorOffset)) + { + req = sstfq->right.queue; + } + else { + req = sstfq->left.qtail; + } + } + } + } + if (req == NULL) { + RF_ASSERT(QSUM(sstfq) == 0); + } + return(req); +} + +RF_DiskQueueData_t *rf_ScanPeek(qptr) + void *qptr; +{ + RF_DiskQueueData_t *req; + RF_Sstf_t *scanq; + int dir; + + scanq = (RF_Sstf_t *)qptr; + dir = scanq->dir; + + if (scanq->left.queue == NULL) { + RF_ASSERT(scanq->left.qlen == 0); + if (scanq->right.queue == NULL) { + RF_ASSERT(scanq->right.qlen == 0); + if (scanq->lopri.queue == NULL) { + RF_ASSERT(scanq->lopri.qlen == 0); + return(NULL); + } + req = closest_to_arm(&scanq->lopri, scanq->last_sector, + &dir, scanq->allow_reverse); + } + else { + req = scanq->right.queue; + } + } + else if (scanq->right.queue == NULL) { + RF_ASSERT(scanq->right.qlen == 0); + RF_ASSERT(scanq->left.queue); + req = scanq->left.qtail; + } + else { + RF_ASSERT(scanq->right.queue); + RF_ASSERT(scanq->left.queue); + if (scanq->dir == DIR_RIGHT) { + req = scanq->right.queue; + } + else { + req = scanq->left.qtail; + } + } + if (req == NULL) { + RF_ASSERT(QSUM(scanq) == 0); + } + return(req); +} + +RF_DiskQueueData_t *rf_CscanPeek(qptr) + void *qptr; +{ + RF_DiskQueueData_t *req; + RF_Sstf_t *cscanq; + + cscanq = (RF_Sstf_t *)qptr; + + RF_ASSERT(cscanq->dir == DIR_RIGHT); + if (cscanq->right.queue) { + req = cscanq->right.queue; + } + else { + RF_ASSERT(cscanq->right.qlen == 0); + if (cscanq->left.queue == NULL) { + RF_ASSERT(cscanq->left.qlen == 0); + if (cscanq->lopri.queue == NULL) { + RF_ASSERT(cscanq->lopri.qlen == 0); + return(NULL); + } + req = closest_to_arm(&cscanq->lopri, cscanq->last_sector, + &cscanq->dir, cscanq->allow_reverse); + } + else { + /* + * There's I/Os to the left of the arm. We'll end + * up swinging on back. + */ + req = cscanq->left.queue; + } + } + if (req == NULL) { + RF_ASSERT(QSUM(cscanq) == 0); + } + return(req); +} + +int rf_SstfPromote(qptr, parityStripeID, which_ru) + void *qptr; + RF_StripeNum_t parityStripeID; + RF_ReconUnitNum_t which_ru; +{ + RF_DiskQueueData_t *r, *next; + RF_Sstf_t *sstfq; + int n; + + sstfq = (RF_Sstf_t *)qptr; + + n = 0; + if (rf_sstfDebug || rf_scanDebug || rf_cscanDebug) { + int tid; + rf_get_threadid(tid); + printf("[%d] promote %ld %d queues are %d,%d,%d\n", + tid, (long)parityStripeID, (int)which_ru, + sstfq->left.qlen, + sstfq->right.qlen, + sstfq->lopri.qlen); + } + for(r=sstfq->lopri.queue;r;r=next) { + next = r->next; + if (rf_sstfDebug || rf_scanDebug || rf_cscanDebug) { + int tid; + rf_get_threadid(tid); + printf("[%d] check promote %lx\n", tid, (long)r); + } + if ((r->parityStripeID == parityStripeID) + && (r->which_ru == which_ru)) + { + do_dequeue(&sstfq->lopri, r); + rf_SstfEnqueue(qptr, r, RF_IO_NORMAL_PRIORITY); + n++; + } + } + if (rf_sstfDebug || rf_scanDebug || rf_cscanDebug) { + int tid; + rf_get_threadid(tid); + printf("[%d] promoted %d matching I/Os queues are %d,%d,%d\n", + tid, n, sstfq->left.qlen, sstfq->right.qlen, sstfq->lopri.qlen); + } + return(n); +} |