rf_fifo.c revision 1.2 1 /* $NetBSD: rf_fifo.c,v 1.2 1999/01/26 02:33:57 oster Exp $ */
2 /*
3 * Copyright (c) 1995 Carnegie-Mellon University.
4 * All rights reserved.
5 *
6 * Author: Mark Holland
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 * rf_fifo.c -- prioritized fifo queue code.
32 * There are only two priority levels: hi and lo.
33 *
34 * Aug 4, 1994, adapted from raidSim version (MCH)
35 *
36 ***************************************************/
37
38 #include "rf_types.h"
39 #include "rf_alloclist.h"
40 #include "rf_stripelocks.h"
41 #include "rf_layout.h"
42 #include "rf_diskqueue.h"
43 #include "rf_fifo.h"
44 #include "rf_debugMem.h"
45 #include "rf_general.h"
46 #include "rf_threadid.h"
47 #include "rf_options.h"
48
49 /* just malloc a header, zero it (via calloc), and return it */
50 /*ARGSUSED*/
51 void *rf_FifoCreate(sectPerDisk, clList, listp)
52 RF_SectorCount_t sectPerDisk;
53 RF_AllocListElem_t *clList;
54 RF_ShutdownList_t **listp;
55 {
56 RF_FifoHeader_t *q;
57
58 RF_CallocAndAdd(q, 1, sizeof(RF_FifoHeader_t), (RF_FifoHeader_t *), clList);
59 q->hq_count = q->lq_count = 0;
60 return((void *)q);
61 }
62
63 void rf_FifoEnqueue(q_in, elem, priority)
64 void *q_in;
65 RF_DiskQueueData_t *elem;
66 int priority;
67 {
68 RF_FifoHeader_t *q = (RF_FifoHeader_t *)q_in;
69
70 RF_ASSERT(priority == RF_IO_NORMAL_PRIORITY || priority == RF_IO_LOW_PRIORITY);
71
72 elem->next = NULL;
73 if (priority == RF_IO_NORMAL_PRIORITY) {
74 if (!q->hq_tail) {
75 RF_ASSERT(q->hq_count == 0 && q->hq_head == NULL);
76 q->hq_head = q->hq_tail = elem;
77 } else {
78 RF_ASSERT(q->hq_count != 0 && q->hq_head != NULL);
79 q->hq_tail->next = elem;
80 q->hq_tail = elem;
81 }
82 q->hq_count++;
83 }
84 else {
85 RF_ASSERT(elem->next == NULL);
86 if (rf_fifoDebug) {
87 int tid;
88 rf_get_threadid(tid);
89 printf("[%d] fifo: ENQ lopri\n", tid);
90 }
91 if (!q->lq_tail) {
92 RF_ASSERT(q->lq_count == 0 && q->lq_head == NULL);
93 q->lq_head = q->lq_tail = elem;
94 } else {
95 RF_ASSERT(q->lq_count != 0 && q->lq_head != NULL);
96 q->lq_tail->next = elem;
97 q->lq_tail = elem;
98 }
99 q->lq_count++;
100 }
101 if ((q->hq_count + q->lq_count)!= elem->queue->queueLength) {
102 printf("Queue lengths differ!: %d %d %d\n",
103 q->hq_count, q->lq_count, (int)elem->queue->queueLength);
104 printf("%d %d %d %d\n",
105 (int)elem->queue->numOutstanding,
106 (int)elem->queue->maxOutstanding,
107 (int)elem->queue->row,
108 (int)elem->queue->col);
109 }
110 RF_ASSERT((q->hq_count + q->lq_count) == elem->queue->queueLength);
111 }
112
113 RF_DiskQueueData_t *rf_FifoDequeue(q_in)
114 void *q_in;
115 {
116 RF_FifoHeader_t *q = (RF_FifoHeader_t *) q_in;
117 RF_DiskQueueData_t *nd;
118
119 RF_ASSERT(q);
120 if (q->hq_head) {
121 RF_ASSERT(q->hq_count != 0 && q->hq_tail != NULL);
122 nd = q->hq_head; q->hq_head = q->hq_head->next;
123 if (!q->hq_head) q->hq_tail = NULL;
124 nd->next = NULL;
125 q->hq_count--;
126 } else if (q->lq_head) {
127 RF_ASSERT(q->lq_count != 0 && q->lq_tail != NULL);
128 nd = q->lq_head; q->lq_head = q->lq_head->next;
129 if (!q->lq_head) q->lq_tail = NULL;
130 nd->next = NULL;
131 q->lq_count--;
132 if (rf_fifoDebug) {
133 int tid;
134 rf_get_threadid(tid);
135 printf("[%d] fifo: DEQ lopri %lx\n", tid, (long)nd);
136 }
137 } else {
138 RF_ASSERT(q->hq_count == 0 && q->lq_count == 0 && q->hq_tail == NULL && q->lq_tail == NULL);
139 nd = NULL;
140 }
141 return(nd);
142 }
143
144 /* This never gets used!! No loss (I hope) if we don't include it... GO */
145 #if !defined(__NetBSD__) && !defined(_KERNEL)
146
147 static RF_DiskQueueData_t *n_in_q(headp, tailp, countp, n, deq)
148 RF_DiskQueueData_t **headp;
149 RF_DiskQueueData_t **tailp;
150 int *countp;
151 int n;
152 int deq;
153 {
154 RF_DiskQueueData_t *r, *s;
155 int i;
156
157 for(s=NULL,i=n,r=*headp;r;s=r,r=r->next) {
158 if (i == 0)
159 break;
160 i--;
161 }
162 RF_ASSERT(r != NULL);
163 if (deq == 0)
164 return(r);
165 if (s) {
166 s->next = r->next;
167 }
168 else {
169 *headp = r->next;
170 }
171 if (*tailp == r)
172 *tailp = s;
173 (*countp)--;
174 return(r);
175 }
176 #endif
177
178 #if !defined(KERNEL) && RF_INCLUDE_QUEUE_RANDOM > 0
179 RF_DiskQueueData_t *rf_RandomPeek(q_in)
180 void *q_in;
181 {
182 RF_FifoHeader_t *q = (RF_FifoHeader_t *) q_in;
183 RF_DiskQueueData_t *req;
184 int n;
185
186 if (q->hq_head) {
187 n = q->rval % q->hq_count;
188 req = n_in_q(&q->hq_head, &q->hq_tail, &q->hq_count, n, 0);
189 }
190 else {
191 RF_ASSERT(q->hq_count == 0);
192 if (q->lq_head == NULL) {
193 RF_ASSERT(q->lq_count == 0);
194 return(NULL);
195 }
196 n = q->rval % q->lq_count;
197 req = n_in_q(&q->lq_head, &q->lq_tail, &q->lq_count, n, 0);
198 }
199 RF_ASSERT((q->hq_count + q->lq_count) == req->queue->queueLength);
200 RF_ASSERT(req != NULL);
201 return(req);
202 }
203
204 RF_DiskQueueData_t *rf_RandomDequeue(q_in)
205 void *q_in;
206 {
207 RF_FifoHeader_t *q = (RF_FifoHeader_t *) q_in;
208 RF_DiskQueueData_t *req;
209 int n;
210
211 if (q->hq_head) {
212 n = q->rval % q->hq_count;
213 q->rval = (long)RF_STATIC_RANDOM();
214 req = n_in_q(&q->hq_head, &q->hq_tail, &q->hq_count, n, 1);
215 }
216 else {
217 RF_ASSERT(q->hq_count == 0);
218 if (q->lq_head == NULL) {
219 RF_ASSERT(q->lq_count == 0);
220 return(NULL);
221 }
222 n = q->rval % q->lq_count;
223 q->rval = (long)RF_STATIC_RANDOM();
224 req = n_in_q(&q->lq_head, &q->lq_tail, &q->lq_count, n, 1);
225 }
226 RF_ASSERT((q->hq_count + q->lq_count) == (req->queue->queueLength-1));
227 return(req);
228 }
229 #endif /* !KERNEL && RF_INCLUDE_QUEUE_RANDOM > 0 */
230
231 /* Return ptr to item at head of queue. Used to examine request
232 * info without actually dequeueing the request.
233 */
234 RF_DiskQueueData_t *rf_FifoPeek(void *q_in)
235 {
236 RF_DiskQueueData_t *headElement = NULL;
237 RF_FifoHeader_t *q = (RF_FifoHeader_t *) q_in;
238
239 RF_ASSERT(q);
240 if (q->hq_head)
241 headElement = q->hq_head;
242 else if (q->lq_head)
243 headElement = q->lq_head;
244 return(headElement);
245 }
246
247 /* We sometimes need to promote a low priority access to a regular priority access.
248 * Currently, this is only used when the user wants to write a stripe which is currently
249 * under reconstruction.
250 * This routine will promote all accesses tagged with the indicated parityStripeID from
251 * the low priority queue to the end of the normal priority queue.
252 * We assume the queue is locked upon entry.
253 */
254 int rf_FifoPromote(q_in, parityStripeID, which_ru)
255 void *q_in;
256 RF_StripeNum_t parityStripeID;
257 RF_ReconUnitNum_t which_ru;
258 {
259 RF_FifoHeader_t *q = (RF_FifoHeader_t *) q_in;
260 RF_DiskQueueData_t *lp = q->lq_head, *pt = NULL; /* lp = lo-pri queue pointer, pt = trailer */
261 int retval = 0;
262
263 while (lp) {
264
265 /* search for the indicated parity stripe in the low-pri queue */
266 if (lp->parityStripeID == parityStripeID && lp->which_ru == which_ru) {
267 /*printf("FifoPromote: promoting access for psid %ld\n",parityStripeID);*/
268 if (pt) pt->next = lp->next; /* delete an entry other than the first */
269 else q->lq_head = lp->next; /* delete the head entry */
270
271 if (!q->lq_head) q->lq_tail = NULL; /* we deleted the only entry */
272 else if (lp == q->lq_tail) q->lq_tail = pt; /* we deleted the tail entry */
273
274 lp->next = NULL;
275 q->lq_count--;
276
277 if (q->hq_tail) {q->hq_tail->next = lp; q->hq_tail = lp;} /* append to hi-priority queue */
278 else {q->hq_head = q->hq_tail = lp;}
279 q->hq_count++;
280
281 /*UpdateShortestSeekFinishTimeForced(lp->requestPtr, lp->diskState);*/ /* deal with this later, if ever */
282
283 lp = (pt) ? pt->next : q->lq_head; /* reset low-pri pointer and continue */
284 retval++;
285
286 } else {pt = lp; lp = lp->next;}
287 }
288
289 /* sanity check. delete this if you ever put more than one entry in the low-pri queue */
290 RF_ASSERT(retval == 0 || retval == 1);
291 if (rf_fifoDebug) {
292 int tid;
293 rf_get_threadid(tid);
294 printf("[%d] fifo: promote %d\n", tid, retval);
295 }
296 return(retval);
297 }
298