Home | History | Annotate | Line # | Download | only in raidframe
rf_states.c revision 1.5
      1 /*	$NetBSD: rf_states.c,v 1.5 1999/01/26 04:40:03 oster Exp $	*/
      2 /*
      3  * Copyright (c) 1995 Carnegie-Mellon University.
      4  * All rights reserved.
      5  *
      6  * Author: Mark Holland, William V. Courtright II, Robby Findler
      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 #include <sys/errno.h>
     30 
     31 #include "rf_archs.h"
     32 #include "rf_threadstuff.h"
     33 #include "rf_raid.h"
     34 #include "rf_dag.h"
     35 #include "rf_desc.h"
     36 #include "rf_aselect.h"
     37 #include "rf_threadid.h"
     38 #include "rf_general.h"
     39 #include "rf_states.h"
     40 #include "rf_dagutils.h"
     41 #include "rf_driver.h"
     42 #include "rf_engine.h"
     43 #include "rf_map.h"
     44 #include "rf_etimer.h"
     45 
     46 #if defined(KERNEL) && (DKUSAGE > 0)
     47 #include <sys/dkusage.h>
     48 #include <io/common/iotypes.h>
     49 #include <io/cam/dec_cam.h>
     50 #include <io/cam/cam.h>
     51 #include <io/cam/pdrv.h>
     52 #endif /* KERNEL && DKUSAGE > 0 */
     53 
     54 /* prototypes for some of the available states.
     55 
     56    States must:
     57 
     58      - not block.
     59 
     60      - either schedule rf_ContinueRaidAccess as a callback and return
     61        RF_TRUE, or complete all of their work and return RF_FALSE.
     62 
     63      - increment desc->state when they have finished their work.
     64 */
     65 
     66 static char *StateName(RF_AccessState_t state)
     67 {
     68   switch (state) {
     69     case rf_QuiesceState:            return "QuiesceState";
     70     case rf_MapState:                return "MapState";
     71     case rf_LockState:               return "LockState";
     72     case rf_CreateDAGState:          return "CreateDAGState";
     73     case rf_ExecuteDAGState:         return "ExecuteDAGState";
     74     case rf_ProcessDAGState:         return "ProcessDAGState";
     75     case rf_CleanupState:            return "CleanupState";
     76     case rf_LastState:               return "LastState";
     77     case rf_IncrAccessesCountState:  return "IncrAccessesCountState";
     78     case rf_DecrAccessesCountState:  return "DecrAccessesCountState";
     79     default:                         return "!!! UnnamedState !!!";
     80   }
     81 }
     82 
     83 void rf_ContinueRaidAccess(RF_RaidAccessDesc_t *desc)
     84 {
     85   int suspended = RF_FALSE;
     86   int current_state_index = desc->state;
     87   RF_AccessState_t current_state = desc->states[current_state_index];
     88 
     89   do {
     90 
     91     current_state_index = desc->state;
     92     current_state = desc->states [current_state_index];
     93 
     94     switch (current_state) {
     95 
     96     case rf_QuiesceState: 		 suspended = rf_State_Quiesce(desc);
     97 				 break;
     98     case rf_IncrAccessesCountState: suspended = rf_State_IncrAccessCount(desc);
     99 				 break;
    100     case rf_MapState:		 suspended = rf_State_Map(desc);
    101 				 break;
    102     case rf_LockState:		 suspended = rf_State_Lock(desc);
    103 				 break;
    104     case rf_CreateDAGState:	 suspended = rf_State_CreateDAG(desc);
    105 				 break;
    106     case rf_ExecuteDAGState:	 suspended = rf_State_ExecuteDAG(desc);
    107 				 break;
    108     case rf_ProcessDAGState:	 suspended = rf_State_ProcessDAG(desc);
    109 				 break;
    110     case rf_CleanupState: 	 suspended = rf_State_Cleanup(desc);
    111 				 break;
    112     case rf_DecrAccessesCountState: suspended = rf_State_DecrAccessCount(desc);
    113 				 break;
    114     case rf_LastState:		 suspended = rf_State_LastState(desc);
    115 				 break;
    116     }
    117 
    118     /* after this point, we cannot dereference desc since desc may
    119        have been freed. desc is only freed in LastState, so if we
    120        renter this function or loop back up, desc should be valid. */
    121 
    122     if (rf_printStatesDebug) {
    123       int tid;
    124       rf_get_threadid (tid);
    125 
    126       printf ("[%d] State: %-24s StateIndex: %3i desc: 0x%ld %s\n",
    127 	      tid, StateName(current_state), current_state_index, (long)desc,
    128 	      suspended ? "callback scheduled" : "looping");
    129     }
    130   } while (!suspended && current_state != rf_LastState);
    131 
    132   return;
    133 }
    134 
    135 
    136 void rf_ContinueDagAccess (RF_DagList_t *dagList)
    137 {
    138   RF_AccTraceEntry_t *tracerec = &(dagList->desc->tracerec);
    139   RF_RaidAccessDesc_t *desc;
    140   RF_DagHeader_t *dag_h;
    141   RF_Etimer_t timer;
    142   int i;
    143 
    144   desc = dagList->desc;
    145 
    146   timer = tracerec->timer;
    147   RF_ETIMER_STOP(timer);
    148   RF_ETIMER_EVAL(timer);
    149   tracerec->specific.user.exec_us = RF_ETIMER_VAL_US(timer);
    150   RF_ETIMER_START(tracerec->timer);
    151 
    152   /* skip to dag which just finished */
    153   dag_h = dagList->dags;
    154   for (i = 0; i < dagList->numDagsDone; i++) {
    155     dag_h = dag_h->next;
    156   }
    157 
    158   /* check to see if retry is required */
    159   if (dag_h->status == rf_rollBackward) {
    160     /* when a dag fails, mark desc status as bad and allow all other dags
    161      * in the desc to execute to completion.  then, free all dags and start over */
    162     desc->status = 1;  /* bad status */
    163     {
    164       printf("[%d] DAG failure: %c addr 0x%lx (%ld) nblk 0x%x (%d) buf 0x%lx\n",
    165 	     desc->tid, desc->type, (long)desc->raidAddress,
    166 	     (long)desc->raidAddress,(int)desc->numBlocks,
    167 	     (int)desc->numBlocks, (unsigned long) (desc->bufPtr));
    168     }
    169   }
    170 
    171   dagList->numDagsDone++;
    172   rf_ContinueRaidAccess(desc);
    173 }
    174 
    175 
    176 int rf_State_LastState(RF_RaidAccessDesc_t *desc)
    177 {
    178   void (*callbackFunc)(RF_CBParam_t) = desc->callbackFunc;
    179   RF_CBParam_t callbackArg;
    180 
    181   callbackArg.p = desc->callbackArg;
    182 
    183   if (!(desc->flags & RF_DAG_TEST_ACCESS)) {/* don't biodone if this */
    184 #if DKUSAGE > 0
    185     RF_DKU_END_IO(((RF_Raid_t *)desc->raidPtr)->raidid,(struct buf *)desc->bp);
    186 #else
    187     RF_DKU_END_IO(((RF_Raid_t *)desc->raidPtr)->raidid);
    188 #endif /* DKUSAGE > 0 */
    189 
    190     /*
    191      * If this is not an async request, wake up the caller
    192      */
    193     if (desc->async_flag == 0)
    194     	wakeup(desc->bp);
    195 
    196     /*     printf("Calling biodone on 0x%x\n",desc->bp); */
    197     biodone(desc->bp); 			/* access came through ioctl */
    198   }
    199 
    200   if (callbackFunc) callbackFunc(callbackArg);
    201   rf_FreeRaidAccDesc(desc);
    202 
    203   return RF_FALSE;
    204 }
    205 
    206 int rf_State_IncrAccessCount(RF_RaidAccessDesc_t *desc)
    207 {
    208   RF_Raid_t *raidPtr;
    209 
    210   raidPtr = desc->raidPtr;
    211   /* Bummer. We have to do this to be 100% safe w.r.t. the increment below */
    212   RF_LOCK_MUTEX(raidPtr->access_suspend_mutex);
    213   raidPtr->accs_in_flight++; /* used to detect quiescence */
    214   RF_UNLOCK_MUTEX(raidPtr->access_suspend_mutex);
    215 
    216   desc->state++;
    217   return RF_FALSE;
    218 }
    219 
    220 int rf_State_DecrAccessCount(RF_RaidAccessDesc_t *desc)
    221 {
    222   RF_Raid_t *raidPtr;
    223 
    224   raidPtr = desc->raidPtr;
    225 
    226   RF_LOCK_MUTEX(raidPtr->access_suspend_mutex);
    227   raidPtr->accs_in_flight--;
    228   if (raidPtr->accesses_suspended && raidPtr->accs_in_flight == 0)  {
    229     rf_SignalQuiescenceLock(raidPtr, raidPtr->reconDesc);
    230   }
    231   rf_UpdateUserStats(raidPtr, RF_ETIMER_VAL_US(desc->timer), desc->numBlocks);
    232   RF_UNLOCK_MUTEX(raidPtr->access_suspend_mutex);
    233 
    234   desc->state++;
    235   return RF_FALSE;
    236 }
    237 
    238 int rf_State_Quiesce(RF_RaidAccessDesc_t *desc)
    239 {
    240   RF_AccTraceEntry_t *tracerec     = &desc->tracerec;
    241   RF_Etimer_t timer;
    242   int suspended = RF_FALSE;
    243   RF_Raid_t *raidPtr;
    244 
    245   raidPtr = desc->raidPtr;
    246 
    247   RF_ETIMER_START(timer);
    248   RF_ETIMER_START(desc->timer);
    249 
    250   RF_LOCK_MUTEX(raidPtr->access_suspend_mutex);
    251   if (raidPtr->accesses_suspended) {
    252     RF_CallbackDesc_t *cb;
    253     cb = rf_AllocCallbackDesc();
    254     /* XXX the following cast is quite bogus...  rf_ContinueRaidAccess
    255        takes a (RF_RaidAccessDesc_t *) as an argument..  GO */
    256     cb->callbackFunc = (void (*)(RF_CBParam_t))rf_ContinueRaidAccess;
    257     cb->callbackArg.p  = (void *) desc;
    258     cb->next = raidPtr->quiesce_wait_list;
    259     raidPtr->quiesce_wait_list = cb;
    260     suspended = RF_TRUE;
    261   }
    262 
    263   RF_UNLOCK_MUTEX(raidPtr->access_suspend_mutex);
    264 
    265   RF_ETIMER_STOP(timer);
    266   RF_ETIMER_EVAL(timer);
    267   tracerec->specific.user.suspend_ovhd_us += RF_ETIMER_VAL_US(timer);
    268 
    269   if (suspended && rf_quiesceDebug)
    270     printf("Stalling access due to quiescence lock\n");
    271 
    272   desc->state++;
    273   return suspended;
    274 }
    275 
    276 int rf_State_Map(RF_RaidAccessDesc_t *desc)
    277 {
    278   RF_Raid_t *raidPtr               = desc->raidPtr;
    279   RF_AccTraceEntry_t *tracerec     = &desc->tracerec;
    280   RF_Etimer_t timer;
    281 
    282   RF_ETIMER_START(timer);
    283 
    284   if (!(desc->asmap = rf_MapAccess(raidPtr, desc->raidAddress, desc->numBlocks,
    285 			      desc->bufPtr, RF_DONT_REMAP)))
    286     RF_PANIC();
    287 
    288   RF_ETIMER_STOP(timer);
    289   RF_ETIMER_EVAL(timer);
    290   tracerec->specific.user.map_us = RF_ETIMER_VAL_US(timer);
    291 
    292   desc->state ++;
    293   return RF_FALSE;
    294 }
    295 
    296 int rf_State_Lock(RF_RaidAccessDesc_t *desc)
    297 {
    298   RF_AccTraceEntry_t *tracerec     = &desc->tracerec;
    299   RF_Raid_t *raidPtr               = desc->raidPtr;
    300   RF_AccessStripeMapHeader_t *asmh = desc->asmap;
    301   RF_AccessStripeMap_t *asm_p;
    302   RF_Etimer_t timer;
    303   int suspended = RF_FALSE;
    304 
    305   RF_ETIMER_START(timer);
    306   if (!(raidPtr->Layout.map->flags & RF_NO_STRIPE_LOCKS)) {
    307     RF_StripeNum_t lastStripeID = -1;
    308 
    309     /* acquire each lock that we don't already hold */
    310     for (asm_p = asmh->stripeMap; asm_p; asm_p = asm_p->next) {
    311       RF_ASSERT(RF_IO_IS_R_OR_W(desc->type));
    312       if (!rf_suppressLocksAndLargeWrites &&
    313           asm_p->parityInfo &&
    314           !(desc->flags& RF_DAG_SUPPRESS_LOCKS) &&
    315           !(asm_p->flags & RF_ASM_FLAGS_LOCK_TRIED))
    316       {
    317         asm_p->flags |= RF_ASM_FLAGS_LOCK_TRIED;
    318         RF_ASSERT(asm_p->stripeID > lastStripeID); /* locks must be acquired
    319 						   hierarchically */
    320         lastStripeID = asm_p->stripeID;
    321 	/* XXX the cast to (void (*)(RF_CBParam_t)) below is bogus!  GO */
    322         RF_INIT_LOCK_REQ_DESC(asm_p->lockReqDesc, desc->type,
    323             (void (*)(struct buf *))rf_ContinueRaidAccess, desc, asm_p,
    324             raidPtr->Layout.dataSectorsPerStripe);
    325         if (rf_AcquireStripeLock(raidPtr->lockTable, asm_p->stripeID,
    326             &asm_p->lockReqDesc))
    327         {
    328           suspended = RF_TRUE;
    329           break;
    330         }
    331       }
    332 
    333       if (desc->type == RF_IO_TYPE_WRITE &&
    334           raidPtr->status[asm_p->physInfo->row] == rf_rs_reconstructing)
    335       {
    336         if (! (asm_p->flags & RF_ASM_FLAGS_FORCE_TRIED) ) {
    337           int val;
    338 
    339           asm_p->flags |= RF_ASM_FLAGS_FORCE_TRIED;
    340 	  /* XXX the cast below is quite bogus!!! XXX  GO */
    341           val = rf_ForceOrBlockRecon(raidPtr, asm_p,
    342 		 (void (*)(RF_Raid_t *,void *))rf_ContinueRaidAccess, desc);
    343           if (val == 0) {
    344             asm_p->flags |= RF_ASM_FLAGS_RECON_BLOCKED;
    345           }
    346           else {
    347             suspended = RF_TRUE;
    348             break;
    349           }
    350         }
    351         else {
    352           if (rf_pssDebug) {
    353             printf("[%d] skipping force/block because already done, psid %ld\n",
    354                 desc->tid,(long)asm_p->stripeID);
    355           }
    356         }
    357       }
    358       else {
    359         if (rf_pssDebug) {
    360           printf("[%d] skipping force/block because not write or not under recon, psid %ld\n",
    361               desc->tid,(long)asm_p->stripeID);
    362         }
    363       }
    364     }
    365 
    366     RF_ETIMER_STOP(timer);
    367     RF_ETIMER_EVAL(timer);
    368     tracerec->specific.user.lock_us += RF_ETIMER_VAL_US(timer);
    369 
    370     if (suspended)
    371       return(RF_TRUE);
    372   }
    373 
    374   desc->state++;
    375   return(RF_FALSE);
    376 }
    377 
    378 /*
    379  * the following three states create, execute, and post-process dags
    380  * the error recovery unit is a single dag.
    381  * by default, SelectAlgorithm creates an array of dags, one per parity stripe
    382  * in some tricky cases, multiple dags per stripe are created
    383  *   - dags within a parity stripe are executed sequentially (arbitrary order)
    384  *   - dags for distinct parity stripes are executed concurrently
    385  *
    386  * repeat until all dags complete successfully -or- dag selection fails
    387  *
    388  * while !done
    389  *   create dag(s) (SelectAlgorithm)
    390  *   if dag
    391  *     execute dag (DispatchDAG)
    392  *     if dag successful
    393  *       done (SUCCESS)
    394  *     else
    395  *       !done (RETRY - start over with new dags)
    396  *   else
    397  *     done (FAIL)
    398  */
    399 int rf_State_CreateDAG (RF_RaidAccessDesc_t *desc)
    400 {
    401   RF_AccTraceEntry_t *tracerec     = &desc->tracerec;
    402   RF_Etimer_t timer;
    403   RF_DagHeader_t *dag_h;
    404   int i, selectStatus;
    405 
    406   /* generate a dag for the access, and fire it off.  When the dag
    407      completes, we'll get re-invoked in the next state. */
    408   RF_ETIMER_START(timer);
    409   /* SelectAlgorithm returns one or more dags */
    410   selectStatus = rf_SelectAlgorithm(desc, desc->flags|RF_DAG_SUPPRESS_LOCKS);
    411   if (rf_printDAGsDebug)
    412     for (i = 0; i < desc->numStripes; i++)
    413       rf_PrintDAGList(desc->dagArray[i].dags);
    414   RF_ETIMER_STOP(timer);
    415   RF_ETIMER_EVAL(timer);
    416   /* update time to create all dags */
    417   tracerec->specific.user.dag_create_us = RF_ETIMER_VAL_US(timer);
    418 
    419   desc->status = 0; /* good status */
    420 
    421   if (selectStatus) {
    422     /* failed to create a dag */
    423     /* this happens when there are too many faults or incomplete dag libraries */
    424     printf("[Failed to create a DAG\n]");
    425     RF_PANIC();
    426   }
    427   else {
    428     /* bind dags to desc */
    429     for (i = 0; i < desc->numStripes; i++) {
    430       dag_h = desc->dagArray[i].dags;
    431       while (dag_h) {
    432 	dag_h->bp = (struct buf *) desc->bp;
    433 	dag_h->tracerec = tracerec;
    434 	dag_h = dag_h->next;
    435       }
    436     }
    437     desc->flags |= RF_DAG_DISPATCH_RETURNED;
    438     desc->state++;  /* next state should be rf_State_ExecuteDAG */
    439   }
    440   return RF_FALSE;
    441 }
    442 
    443 
    444 
    445 /* the access has an array of dagLists, one dagList per parity stripe.
    446  * fire the first dag in each parity stripe (dagList).
    447  * dags within a stripe (dagList) must be executed sequentially
    448  *  - this preserves atomic parity update
    449  * dags for independents parity groups (stripes) are fired concurrently */
    450 
    451 int rf_State_ExecuteDAG(RF_RaidAccessDesc_t *desc)
    452 {
    453   int i;
    454   RF_DagHeader_t *dag_h;
    455   RF_DagList_t *dagArray = desc->dagArray;
    456 
    457   /* next state is always rf_State_ProcessDAG
    458    * important to do this before firing the first dag
    459    * (it may finish before we leave this routine) */
    460   desc->state++;
    461 
    462   /* sweep dag array, a stripe at a time, firing the first dag in each stripe */
    463   for (i = 0; i < desc->numStripes; i++) {
    464     RF_ASSERT(dagArray[i].numDags > 0);
    465     RF_ASSERT(dagArray[i].numDagsDone == 0);
    466     RF_ASSERT(dagArray[i].numDagsFired == 0);
    467     RF_ETIMER_START(dagArray[i].tracerec.timer);
    468     /* fire first dag in this stripe */
    469     dag_h = dagArray[i].dags;
    470     RF_ASSERT(dag_h);
    471     dagArray[i].numDagsFired++;
    472     /* XXX Yet another case where we pass in a conflicting function pointer
    473        :-(  XXX  GO */
    474     rf_DispatchDAG(dag_h, (void (*)(void *))rf_ContinueDagAccess, &dagArray[i]);
    475   }
    476 
    477   /* the DAG will always call the callback, even if there was no
    478    * blocking, so we are always suspended in this state */
    479   return RF_TRUE;
    480 }
    481 
    482 
    483 
    484 /* rf_State_ProcessDAG is entered when a dag completes.
    485  * first, check to all dags in the access have completed
    486  * if not, fire as many dags as possible */
    487 
    488 int rf_State_ProcessDAG(RF_RaidAccessDesc_t *desc)
    489 {
    490   RF_AccessStripeMapHeader_t *asmh = desc->asmap;
    491   RF_Raid_t *raidPtr               = desc->raidPtr;
    492   RF_DagHeader_t *dag_h;
    493   int i, j, done = RF_TRUE;
    494   RF_DagList_t *dagArray = desc->dagArray;
    495   RF_Etimer_t timer;
    496 
    497   /* check to see if this is the last dag */
    498   for (i = 0; i < desc->numStripes; i++)
    499     if (dagArray[i].numDags != dagArray[i].numDagsDone)
    500       done = RF_FALSE;
    501 
    502   if (done) {
    503     if (desc->status) {
    504       /* a dag failed, retry */
    505       RF_ETIMER_START(timer);
    506       /* free all dags */
    507       for (i = 0; i < desc->numStripes; i++) {
    508 	rf_FreeDAG(desc->dagArray[i].dags);
    509       }
    510       rf_MarkFailuresInASMList(raidPtr, asmh);
    511       /* back up to rf_State_CreateDAG */
    512       desc->state = desc->state - 2;
    513       return RF_FALSE;
    514     }
    515     else {
    516       /* move on to rf_State_Cleanup */
    517       desc->state++;
    518     }
    519     return RF_FALSE;
    520   }
    521   else {
    522     /* more dags to execute */
    523     /* see if any are ready to be fired.  if so, fire them */
    524     /* don't fire the initial dag in a list, it's fired in rf_State_ExecuteDAG */
    525     for (i = 0; i < desc->numStripes; i++) {
    526       if ((dagArray[i].numDagsDone < dagArray[i].numDags)
    527 	  && (dagArray[i].numDagsDone == dagArray[i].numDagsFired)
    528 	  && (dagArray[i].numDagsFired > 0)) {
    529 	RF_ETIMER_START(dagArray[i].tracerec.timer);
    530 	/* fire next dag in this stripe */
    531 	/* first, skip to next dag awaiting execution */
    532 	dag_h = dagArray[i].dags;
    533 	for (j = 0; j < dagArray[i].numDagsDone; j++)
    534 	  dag_h = dag_h->next;
    535 	dagArray[i].numDagsFired++;
    536 	/* XXX and again we pass a different function pointer.. GO */
    537 	rf_DispatchDAG(dag_h, (void (*)(void *))rf_ContinueDagAccess,
    538 		       &dagArray[i]);
    539       }
    540     }
    541     return RF_TRUE;
    542   }
    543 }
    544 
    545 /* only make it this far if all dags complete successfully */
    546 int rf_State_Cleanup(RF_RaidAccessDesc_t *desc)
    547 {
    548   RF_AccTraceEntry_t *tracerec     = &desc->tracerec;
    549   RF_AccessStripeMapHeader_t *asmh = desc->asmap;
    550   RF_Raid_t *raidPtr               = desc->raidPtr;
    551   RF_AccessStripeMap_t *asm_p;
    552   RF_DagHeader_t *dag_h;
    553   RF_Etimer_t timer;
    554   int tid, i;
    555 
    556   desc->state ++;
    557 
    558   rf_get_threadid(tid);
    559 
    560   timer = tracerec->timer;
    561   RF_ETIMER_STOP(timer);
    562   RF_ETIMER_EVAL(timer);
    563   tracerec->specific.user.dag_retry_us = RF_ETIMER_VAL_US(timer);
    564 
    565   /* the RAID I/O is complete.  Clean up. */
    566   tracerec->specific.user.dag_retry_us = 0;
    567 
    568   RF_ETIMER_START(timer);
    569   if (desc->flags & RF_DAG_RETURN_DAG) {
    570     /* copy dags into paramDAG */
    571     *(desc->paramDAG) = desc->dagArray[0].dags;
    572     dag_h = *(desc->paramDAG);
    573     for (i = 1; i < desc->numStripes; i++) {
    574       /* concatenate dags from remaining stripes */
    575       RF_ASSERT(dag_h);
    576       while (dag_h->next)
    577 	dag_h = dag_h->next;
    578       dag_h->next = desc->dagArray[i].dags;
    579     }
    580   }
    581   else {
    582     /* free all dags */
    583     for (i = 0; i < desc->numStripes; i++) {
    584       rf_FreeDAG(desc->dagArray[i].dags);
    585     }
    586   }
    587 
    588   RF_ETIMER_STOP(timer);
    589   RF_ETIMER_EVAL(timer);
    590   tracerec->specific.user.cleanup_us = RF_ETIMER_VAL_US(timer);
    591 
    592   RF_ETIMER_START(timer);
    593   if (!(raidPtr->Layout.map->flags & RF_NO_STRIPE_LOCKS)) {
    594     for (asm_p = asmh->stripeMap; asm_p; asm_p = asm_p->next) {
    595       if (!rf_suppressLocksAndLargeWrites &&
    596           asm_p->parityInfo &&
    597           !(desc->flags&RF_DAG_SUPPRESS_LOCKS))
    598       {
    599         RF_ASSERT_VALID_LOCKREQ(&asm_p->lockReqDesc);
    600         rf_ReleaseStripeLock(raidPtr->lockTable, asm_p->stripeID,
    601             &asm_p->lockReqDesc);
    602       }
    603       if (asm_p->flags & RF_ASM_FLAGS_RECON_BLOCKED) {
    604         rf_UnblockRecon(raidPtr, asm_p);
    605       }
    606     }
    607   }
    608 
    609   RF_ETIMER_STOP(timer);
    610   RF_ETIMER_EVAL(timer);
    611   tracerec->specific.user.lock_us += RF_ETIMER_VAL_US(timer);
    612 
    613   RF_ETIMER_START(timer);
    614   if (desc->flags & RF_DAG_RETURN_ASM)
    615     *(desc->paramASM) = asmh;
    616   else
    617     rf_FreeAccessStripeMap(asmh);
    618   RF_ETIMER_STOP(timer);
    619   RF_ETIMER_EVAL(timer);
    620   tracerec->specific.user.cleanup_us += RF_ETIMER_VAL_US(timer);
    621 
    622   RF_ETIMER_STOP(desc->timer);
    623   RF_ETIMER_EVAL(desc->timer);
    624 
    625   timer = desc->tracerec.tot_timer;
    626   RF_ETIMER_STOP(timer);
    627   RF_ETIMER_EVAL(timer);
    628   desc->tracerec.total_us = RF_ETIMER_VAL_US(timer);
    629 
    630   rf_LogTraceRec(raidPtr, tracerec);
    631 
    632   desc->flags |= RF_DAG_ACCESS_COMPLETE;
    633 
    634   return RF_FALSE;
    635 }
    636