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