rf_aselect.c revision 1.6 1 /* $NetBSD: rf_aselect.c,v 1.6 2002/08/02 00:24:56 oster Exp $ */
2 /*
3 * Copyright (c) 1995 Carnegie-Mellon University.
4 * All rights reserved.
5 *
6 * Author: Mark Holland, William V. Courtright II
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 * aselect.c -- algorithm selection code
32 *
33 *****************************************************************************/
34
35 #include <sys/cdefs.h>
36 __KERNEL_RCSID(0, "$NetBSD: rf_aselect.c,v 1.6 2002/08/02 00:24:56 oster Exp $");
37
38 #include <dev/raidframe/raidframevar.h>
39
40 #include "rf_archs.h"
41 #include "rf_raid.h"
42 #include "rf_dag.h"
43 #include "rf_dagutils.h"
44 #include "rf_dagfuncs.h"
45 #include "rf_general.h"
46 #include "rf_desc.h"
47 #include "rf_map.h"
48
49 #if defined(__NetBSD__) && defined(_KERNEL)
50 /* the function below is not used... so don't define it! */
51 #else
52 static void TransferDagMemory(RF_DagHeader_t *, RF_DagHeader_t *);
53 #endif
54
55 static int InitHdrNode(RF_DagHeader_t **, RF_Raid_t *, int);
56 static void UpdateNodeHdrPtr(RF_DagHeader_t *, RF_DagNode_t *);
57 int rf_SelectAlgorithm(RF_RaidAccessDesc_t *, RF_RaidAccessFlags_t);
58
59
60 /******************************************************************************
61 *
62 * Create and Initialiaze a dag header and termination node
63 *
64 *****************************************************************************/
65 static int
66 InitHdrNode(hdr, raidPtr, memChunkEnable)
67 RF_DagHeader_t **hdr;
68 RF_Raid_t *raidPtr;
69 int memChunkEnable;
70 {
71 /* create and initialize dag hdr */
72 *hdr = rf_AllocDAGHeader();
73 rf_MakeAllocList((*hdr)->allocList);
74 if ((*hdr)->allocList == NULL) {
75 rf_FreeDAGHeader(*hdr);
76 return (ENOMEM);
77 }
78 (*hdr)->status = rf_enable;
79 (*hdr)->numSuccedents = 0;
80 (*hdr)->raidPtr = raidPtr;
81 (*hdr)->next = NULL;
82 return (0);
83 }
84
85 /*****************************************************************************************
86 *
87 * Ensure that all node->dagHdr fields in a dag are consistent
88 *
89 * IMPORTANT: This routine recursively searches all succedents of the node. If a
90 * succedent is encountered whose dagHdr ptr does not require adjusting, that node's
91 * succedents WILL NOT BE EXAMINED.
92 *
93 ****************************************************************************************/
94 static void
95 UpdateNodeHdrPtr(hdr, node)
96 RF_DagHeader_t *hdr;
97 RF_DagNode_t *node;
98 {
99 int i;
100 RF_ASSERT(hdr != NULL && node != NULL);
101 for (i = 0; i < node->numSuccedents; i++)
102 if (node->succedents[i]->dagHdr != hdr)
103 UpdateNodeHdrPtr(hdr, node->succedents[i]);
104 node->dagHdr = hdr;
105 }
106 /******************************************************************************
107 *
108 * Create a DAG to do a read or write operation.
109 *
110 * create an array of dagLists, one list per parity stripe.
111 * return the lists in the array desc->dagArray.
112 *
113 * Normally, each list contains one dag for the entire stripe. In some
114 * tricky cases, we break this into multiple dags, either one per stripe
115 * unit or one per block (sector). When this occurs, these dags are returned
116 * as a linked list (dagList) which is executed sequentially (to preserve
117 * atomic parity updates in the stripe).
118 *
119 * dags which operate on independent parity goups (stripes) are returned in
120 * independent dagLists (distinct elements in desc->dagArray) and may be
121 * executed concurrently.
122 *
123 * Finally, if the SelectionFunc fails to create a dag for a block, we punt
124 * and return 1.
125 *
126 * The above process is performed in two phases:
127 * 1) create an array(s) of creation functions (eg stripeFuncs)
128 * 2) create dags and concatenate/merge to form the final dag.
129 *
130 * Because dag's are basic blocks (single entry, single exit, unconditional
131 * control flow, we can add the following optimizations (future work):
132 * first-pass optimizer to allow max concurrency (need all data dependencies)
133 * second-pass optimizer to eliminate common subexpressions (need true
134 * data dependencies)
135 * third-pass optimizer to eliminate dead code (need true data dependencies)
136 *****************************************************************************/
137
138 #define MAXNSTRIPES 50
139
140 int
141 rf_SelectAlgorithm(desc, flags)
142 RF_RaidAccessDesc_t *desc;
143 RF_RaidAccessFlags_t flags;
144 {
145 RF_AccessStripeMapHeader_t *asm_h = desc->asmap;
146 RF_IoType_t type = desc->type;
147 RF_Raid_t *raidPtr = desc->raidPtr;
148 void *bp = desc->bp;
149
150 RF_AccessStripeMap_t *asmap = asm_h->stripeMap;
151 RF_AccessStripeMap_t *asm_p;
152 RF_DagHeader_t *dag_h = NULL, *tempdag_h, *lastdag_h;
153 int i, j, k;
154 RF_VoidFuncPtr *stripeFuncs, normalStripeFuncs[MAXNSTRIPES];
155 RF_AccessStripeMap_t *asm_up, *asm_bp;
156 RF_AccessStripeMapHeader_t ***asmh_u, *endASMList;
157 RF_AccessStripeMapHeader_t ***asmh_b;
158 RF_VoidFuncPtr **stripeUnitFuncs, uFunc;
159 RF_VoidFuncPtr **blockFuncs, bFunc;
160 int numStripesBailed = 0, cantCreateDAGs = RF_FALSE;
161 int numStripeUnitsBailed = 0;
162 int stripeNum, numUnitDags = 0, stripeUnitNum, numBlockDags = 0;
163 RF_StripeNum_t numStripeUnits;
164 RF_SectorNum_t numBlocks;
165 RF_RaidAddr_t address;
166 int length;
167 RF_PhysDiskAddr_t *physPtr;
168 caddr_t buffer;
169
170 lastdag_h = NULL;
171 asmh_u = asmh_b = NULL;
172 stripeUnitFuncs = NULL;
173 blockFuncs = NULL;
174
175 /* get an array of dag-function creation pointers, try to avoid
176 * calling malloc */
177 if (asm_h->numStripes <= MAXNSTRIPES)
178 stripeFuncs = normalStripeFuncs;
179 else
180 RF_Calloc(stripeFuncs, asm_h->numStripes, sizeof(RF_VoidFuncPtr), (RF_VoidFuncPtr *));
181
182 /* walk through the asm list once collecting information */
183 /* attempt to find a single creation function for each stripe */
184 desc->numStripes = 0;
185 for (i = 0, asm_p = asmap; asm_p; asm_p = asm_p->next, i++) {
186 desc->numStripes++;
187 (raidPtr->Layout.map->SelectionFunc) (raidPtr, type, asm_p, &stripeFuncs[i]);
188 /* check to see if we found a creation func for this stripe */
189 if (stripeFuncs[i] == (RF_VoidFuncPtr) NULL) {
190 /* could not find creation function for entire stripe
191 * so, let's see if we can find one for each stripe
192 * unit in the stripe */
193
194 if (numStripesBailed == 0) {
195 /* one stripe map header for each stripe we
196 * bail on */
197 RF_Malloc(asmh_u, sizeof(RF_AccessStripeMapHeader_t **) * asm_h->numStripes, (RF_AccessStripeMapHeader_t ***));
198 /* create an array of ptrs to arrays of
199 * stripeFuncs */
200 RF_Calloc(stripeUnitFuncs, asm_h->numStripes, sizeof(RF_VoidFuncPtr), (RF_VoidFuncPtr **));
201 }
202 /* create an array of creation funcs (called
203 * stripeFuncs) for this stripe */
204 numStripeUnits = asm_p->numStripeUnitsAccessed;
205 RF_Calloc(stripeUnitFuncs[numStripesBailed], numStripeUnits, sizeof(RF_VoidFuncPtr), (RF_VoidFuncPtr *));
206 RF_Malloc(asmh_u[numStripesBailed], numStripeUnits * sizeof(RF_AccessStripeMapHeader_t *), (RF_AccessStripeMapHeader_t **));
207
208 /* lookup array of stripeUnitFuncs for this stripe */
209 for (j = 0, physPtr = asm_p->physInfo; physPtr; physPtr = physPtr->next, j++) {
210 /* remap for series of single stripe-unit
211 * accesses */
212 address = physPtr->raidAddress;
213 length = physPtr->numSector;
214 buffer = physPtr->bufPtr;
215
216 asmh_u[numStripesBailed][j] = rf_MapAccess(raidPtr, address, length, buffer, RF_DONT_REMAP);
217 asm_up = asmh_u[numStripesBailed][j]->stripeMap;
218
219 /* get the creation func for this stripe unit */
220 (raidPtr->Layout.map->SelectionFunc) (raidPtr, type, asm_up, &(stripeUnitFuncs[numStripesBailed][j]));
221
222 /* check to see if we found a creation func
223 * for this stripe unit */
224 if (stripeUnitFuncs[numStripesBailed][j] == (RF_VoidFuncPtr) NULL) {
225 /* could not find creation function
226 * for stripe unit so, let's see if we
227 * can find one for each block in the
228 * stripe unit */
229 if (numStripeUnitsBailed == 0) {
230 /* one stripe map header for
231 * each stripe unit we bail on */
232 RF_Malloc(asmh_b, sizeof(RF_AccessStripeMapHeader_t **) * asm_h->numStripes * raidPtr->Layout.numDataCol, (RF_AccessStripeMapHeader_t ***));
233 /* create an array of ptrs to
234 * arrays of blockFuncs */
235 RF_Calloc(blockFuncs, asm_h->numStripes * raidPtr->Layout.numDataCol, sizeof(RF_VoidFuncPtr), (RF_VoidFuncPtr **));
236 }
237 /* create an array of creation funcs
238 * (called blockFuncs) for this stripe
239 * unit */
240 numBlocks = physPtr->numSector;
241 numBlockDags += numBlocks;
242 RF_Calloc(blockFuncs[numStripeUnitsBailed], numBlocks, sizeof(RF_VoidFuncPtr), (RF_VoidFuncPtr *));
243 RF_Malloc(asmh_b[numStripeUnitsBailed], numBlocks * sizeof(RF_AccessStripeMapHeader_t *), (RF_AccessStripeMapHeader_t **));
244
245 /* lookup array of blockFuncs for this
246 * stripe unit */
247 for (k = 0; k < numBlocks; k++) {
248 /* remap for series of single
249 * stripe-unit accesses */
250 address = physPtr->raidAddress + k;
251 length = 1;
252 buffer = physPtr->bufPtr + (k * (1 << raidPtr->logBytesPerSector));
253
254 asmh_b[numStripeUnitsBailed][k] = rf_MapAccess(raidPtr, address, length, buffer, RF_DONT_REMAP);
255 asm_bp = asmh_b[numStripeUnitsBailed][k]->stripeMap;
256
257 /* get the creation func for
258 * this stripe unit */
259 (raidPtr->Layout.map->SelectionFunc) (raidPtr, type, asm_bp, &(blockFuncs[numStripeUnitsBailed][k]));
260
261 /* check to see if we found a
262 * creation func for this
263 * stripe unit */
264 if (blockFuncs[numStripeUnitsBailed][k] == NULL)
265 cantCreateDAGs = RF_TRUE;
266 }
267 numStripeUnitsBailed++;
268 } else {
269 numUnitDags++;
270 }
271 }
272 RF_ASSERT(j == numStripeUnits);
273 numStripesBailed++;
274 }
275 }
276
277 if (cantCreateDAGs) {
278 /* free memory and punt */
279 if (asm_h->numStripes > MAXNSTRIPES)
280 RF_Free(stripeFuncs, asm_h->numStripes * sizeof(RF_VoidFuncPtr));
281 if (numStripesBailed > 0) {
282 stripeNum = 0;
283 for (i = 0, asm_p = asmap; asm_p; asm_p = asm_p->next, i++)
284 if (stripeFuncs[i] == NULL) {
285 numStripeUnits = asm_p->numStripeUnitsAccessed;
286 for (j = 0; j < numStripeUnits; j++)
287 rf_FreeAccessStripeMap(asmh_u[stripeNum][j]);
288 RF_Free(asmh_u[stripeNum], numStripeUnits * sizeof(RF_AccessStripeMapHeader_t *));
289 RF_Free(stripeUnitFuncs[stripeNum], numStripeUnits * sizeof(RF_VoidFuncPtr));
290 stripeNum++;
291 }
292 RF_ASSERT(stripeNum == numStripesBailed);
293 RF_Free(stripeUnitFuncs, asm_h->numStripes * sizeof(RF_VoidFuncPtr));
294 RF_Free(asmh_u, asm_h->numStripes * sizeof(RF_AccessStripeMapHeader_t **));
295 }
296 return (1);
297 } else {
298 /* begin dag creation */
299 stripeNum = 0;
300 stripeUnitNum = 0;
301
302 /* create an array of dagLists and fill them in */
303 RF_CallocAndAdd(desc->dagArray, desc->numStripes, sizeof(RF_DagList_t), (RF_DagList_t *), desc->cleanupList);
304
305 for (i = 0, asm_p = asmap; asm_p; asm_p = asm_p->next, i++) {
306 /* grab dag header for this stripe */
307 dag_h = NULL;
308 desc->dagArray[i].desc = desc;
309
310 if (stripeFuncs[i] == (RF_VoidFuncPtr) NULL) {
311 /* use bailout functions for this stripe */
312 for (j = 0, physPtr = asm_p->physInfo; physPtr; physPtr = physPtr->next, j++) {
313 uFunc = stripeUnitFuncs[stripeNum][j];
314 if (uFunc == (RF_VoidFuncPtr) NULL) {
315 /* use bailout functions for
316 * this stripe unit */
317 for (k = 0; k < physPtr->numSector; k++) {
318 /* create a dag for
319 * this block */
320 InitHdrNode(&tempdag_h, raidPtr, rf_useMemChunks);
321 desc->dagArray[i].numDags++;
322 if (dag_h == NULL) {
323 dag_h = tempdag_h;
324 } else {
325 lastdag_h->next = tempdag_h;
326 }
327 lastdag_h = tempdag_h;
328
329 bFunc = blockFuncs[stripeUnitNum][k];
330 RF_ASSERT(bFunc);
331 asm_bp = asmh_b[stripeUnitNum][k]->stripeMap;
332 (*bFunc) (raidPtr, asm_bp, tempdag_h, bp, flags, tempdag_h->allocList);
333 }
334 stripeUnitNum++;
335 } else {
336 /* create a dag for this unit */
337 InitHdrNode(&tempdag_h, raidPtr, rf_useMemChunks);
338 desc->dagArray[i].numDags++;
339 if (dag_h == NULL) {
340 dag_h = tempdag_h;
341 } else {
342 lastdag_h->next = tempdag_h;
343 }
344 lastdag_h = tempdag_h;
345
346 asm_up = asmh_u[stripeNum][j]->stripeMap;
347 (*uFunc) (raidPtr, asm_up, tempdag_h, bp, flags, tempdag_h->allocList);
348 }
349 }
350 RF_ASSERT(j == asm_p->numStripeUnitsAccessed);
351 /* merge linked bailout dag to existing dag
352 * collection */
353 stripeNum++;
354 } else {
355 /* Create a dag for this parity stripe */
356 InitHdrNode(&tempdag_h, raidPtr, rf_useMemChunks);
357 desc->dagArray[i].numDags++;
358 if (dag_h == NULL) {
359 dag_h = tempdag_h;
360 } else {
361 lastdag_h->next = tempdag_h;
362 }
363 lastdag_h = tempdag_h;
364
365 (stripeFuncs[i]) (raidPtr, asm_p, tempdag_h, bp, flags, tempdag_h->allocList);
366 }
367 desc->dagArray[i].dags = dag_h;
368 }
369 RF_ASSERT(i == desc->numStripes);
370
371 /* free memory */
372 if (asm_h->numStripes > MAXNSTRIPES)
373 RF_Free(stripeFuncs, asm_h->numStripes * sizeof(RF_VoidFuncPtr));
374 if ((numStripesBailed > 0) || (numStripeUnitsBailed > 0)) {
375 stripeNum = 0;
376 stripeUnitNum = 0;
377 if (dag_h->asmList) {
378 endASMList = dag_h->asmList;
379 while (endASMList->next)
380 endASMList = endASMList->next;
381 } else
382 endASMList = NULL;
383 /* walk through io, stripe by stripe */
384 for (i = 0, asm_p = asmap; asm_p; asm_p = asm_p->next, i++)
385 if (stripeFuncs[i] == NULL) {
386 numStripeUnits = asm_p->numStripeUnitsAccessed;
387 /* walk through stripe, stripe unit by
388 * stripe unit */
389 for (j = 0, physPtr = asm_p->physInfo; physPtr; physPtr = physPtr->next, j++) {
390 if (stripeUnitFuncs[stripeNum][j] == NULL) {
391 numBlocks = physPtr->numSector;
392 /* walk through stripe
393 * unit, block by
394 * block */
395 for (k = 0; k < numBlocks; k++)
396 if (dag_h->asmList == NULL) {
397 dag_h->asmList = asmh_b[stripeUnitNum][k];
398 endASMList = dag_h->asmList;
399 } else {
400 endASMList->next = asmh_b[stripeUnitNum][k];
401 endASMList = endASMList->next;
402 }
403 RF_Free(asmh_b[stripeUnitNum], numBlocks * sizeof(RF_AccessStripeMapHeader_t *));
404 RF_Free(blockFuncs[stripeUnitNum], numBlocks * sizeof(RF_VoidFuncPtr));
405 stripeUnitNum++;
406 }
407 if (dag_h->asmList == NULL) {
408 dag_h->asmList = asmh_u[stripeNum][j];
409 endASMList = dag_h->asmList;
410 } else {
411 endASMList->next = asmh_u[stripeNum][j];
412 endASMList = endASMList->next;
413 }
414 }
415 RF_Free(asmh_u[stripeNum], numStripeUnits * sizeof(RF_AccessStripeMapHeader_t *));
416 RF_Free(stripeUnitFuncs[stripeNum], numStripeUnits * sizeof(RF_VoidFuncPtr));
417 stripeNum++;
418 }
419 RF_ASSERT(stripeNum == numStripesBailed);
420 RF_Free(stripeUnitFuncs, asm_h->numStripes * sizeof(RF_VoidFuncPtr));
421 RF_Free(asmh_u, asm_h->numStripes * sizeof(RF_AccessStripeMapHeader_t **));
422 if (numStripeUnitsBailed > 0) {
423 RF_ASSERT(stripeUnitNum == numStripeUnitsBailed);
424 RF_Free(blockFuncs, raidPtr->Layout.numDataCol * asm_h->numStripes * sizeof(RF_VoidFuncPtr));
425 RF_Free(asmh_b, raidPtr->Layout.numDataCol * asm_h->numStripes * sizeof(RF_AccessStripeMapHeader_t **));
426 }
427 }
428 return (0);
429 }
430 }
431