Home | History | Annotate | Line # | Download | only in raidframe
rf_states.c revision 1.4
      1 /*	$NetBSD: rf_states.c,v 1.4 1999/01/26 02:34:02 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 #if RF_DEMO > 0
    164     if (!rf_demoMode)
    165 #endif /* RF_DEMO > 0 */
    166     {
    167       printf("[%d] DAG failure: %c addr 0x%lx (%ld) nblk 0x%x (%d) buf 0x%lx\n",
    168 	     desc->tid, desc->type, (long)desc->raidAddress,
    169 	     (long)desc->raidAddress,(int)desc->numBlocks,
    170 	     (int)desc->numBlocks, (unsigned long) (desc->bufPtr));
    171     }
    172   }
    173 
    174   dagList->numDagsDone++;
    175   rf_ContinueRaidAccess(desc);
    176 }
    177 
    178 
    179 int rf_State_LastState(RF_RaidAccessDesc_t *desc)
    180 {
    181   void (*callbackFunc)(RF_CBParam_t) = desc->callbackFunc;
    182   RF_CBParam_t callbackArg;
    183 
    184   callbackArg.p = desc->callbackArg;
    185 
    186   if (!(desc->flags & RF_DAG_TEST_ACCESS)) {/* don't biodone if this */
    187 #if DKUSAGE > 0
    188     RF_DKU_END_IO(((RF_Raid_t *)desc->raidPtr)->raidid,(struct buf *)desc->bp);
    189 #else
    190     RF_DKU_END_IO(((RF_Raid_t *)desc->raidPtr)->raidid);
    191 #endif /* DKUSAGE > 0 */
    192 
    193     /*
    194      * If this is not an async request, wake up the caller
    195      */
    196     if (desc->async_flag == 0)
    197     	wakeup(desc->bp);
    198 
    199     /*     printf("Calling biodone on 0x%x\n",desc->bp); */
    200     biodone(desc->bp); 			/* access came through ioctl */
    201   }
    202 
    203   if (callbackFunc) callbackFunc(callbackArg);
    204   rf_FreeRaidAccDesc(desc);
    205 
    206   return RF_FALSE;
    207 }
    208 
    209 int rf_State_IncrAccessCount(RF_RaidAccessDesc_t *desc)
    210 {
    211   RF_Raid_t *raidPtr;
    212 
    213   raidPtr = desc->raidPtr;
    214   /* Bummer. We have to do this to be 100% safe w.r.t. the increment below */
    215   RF_LOCK_MUTEX(raidPtr->access_suspend_mutex);
    216   raidPtr->accs_in_flight++; /* used to detect quiescence */
    217   RF_UNLOCK_MUTEX(raidPtr->access_suspend_mutex);
    218 
    219   desc->state++;
    220   return RF_FALSE;
    221 }
    222 
    223 int rf_State_DecrAccessCount(RF_RaidAccessDesc_t *desc)
    224 {
    225   RF_Raid_t *raidPtr;
    226 
    227   raidPtr = desc->raidPtr;
    228 
    229   RF_LOCK_MUTEX(raidPtr->access_suspend_mutex);
    230   raidPtr->accs_in_flight--;
    231   if (raidPtr->accesses_suspended && raidPtr->accs_in_flight == 0)  {
    232     rf_SignalQuiescenceLock(raidPtr, raidPtr->reconDesc);
    233   }
    234   rf_UpdateUserStats(raidPtr, RF_ETIMER_VAL_US(desc->timer), desc->numBlocks);
    235   RF_UNLOCK_MUTEX(raidPtr->access_suspend_mutex);
    236 
    237   desc->state++;
    238   return RF_FALSE;
    239 }
    240 
    241 int rf_State_Quiesce(RF_RaidAccessDesc_t *desc)
    242 {
    243   RF_AccTraceEntry_t *tracerec     = &desc->tracerec;
    244   RF_Etimer_t timer;
    245   int suspended = RF_FALSE;
    246   RF_Raid_t *raidPtr;
    247 
    248   raidPtr = desc->raidPtr;
    249 
    250   RF_ETIMER_START(timer);
    251   RF_ETIMER_START(desc->timer);
    252 
    253   RF_LOCK_MUTEX(raidPtr->access_suspend_mutex);
    254   if (raidPtr->accesses_suspended) {
    255     RF_CallbackDesc_t *cb;
    256     cb = rf_AllocCallbackDesc();
    257     /* XXX the following cast is quite bogus...  rf_ContinueRaidAccess
    258        takes a (RF_RaidAccessDesc_t *) as an argument..  GO */
    259     cb->callbackFunc = (void (*)(RF_CBParam_t))rf_ContinueRaidAccess;
    260     cb->callbackArg.p  = (void *) desc;
    261     cb->next = raidPtr->quiesce_wait_list;
    262     raidPtr->quiesce_wait_list = cb;
    263     suspended = RF_TRUE;
    264   }
    265 
    266   RF_UNLOCK_MUTEX(raidPtr->access_suspend_mutex);
    267 
    268   RF_ETIMER_STOP(timer);
    269   RF_ETIMER_EVAL(timer);
    270   tracerec->specific.user.suspend_ovhd_us += RF_ETIMER_VAL_US(timer);
    271 
    272   if (suspended && rf_quiesceDebug)
    273     printf("Stalling access due to quiescence lock\n");
    274 
    275   desc->state++;
    276   return suspended;
    277 }
    278 
    279 int rf_State_Map(RF_RaidAccessDesc_t *desc)
    280 {
    281   RF_Raid_t *raidPtr               = desc->raidPtr;
    282   RF_AccTraceEntry_t *tracerec     = &desc->tracerec;
    283   RF_Etimer_t timer;
    284 
    285   RF_ETIMER_START(timer);
    286 
    287   if (!(desc->asmap = rf_MapAccess(raidPtr, desc->raidAddress, desc->numBlocks,
    288 			      desc->bufPtr, RF_DONT_REMAP)))
    289     RF_PANIC();
    290 
    291   RF_ETIMER_STOP(timer);
    292   RF_ETIMER_EVAL(timer);
    293   tracerec->specific.user.map_us = RF_ETIMER_VAL_US(timer);
    294 
    295   desc->state ++;
    296   return RF_FALSE;
    297 }
    298 
    299 int rf_State_Lock(RF_RaidAccessDesc_t *desc)
    300 {
    301   RF_AccTraceEntry_t *tracerec     = &desc->tracerec;
    302   RF_Raid_t *raidPtr               = desc->raidPtr;
    303   RF_AccessStripeMapHeader_t *asmh = desc->asmap;
    304   RF_AccessStripeMap_t *asm_p;
    305   RF_Etimer_t timer;
    306   int suspended = RF_FALSE;
    307 
    308   RF_ETIMER_START(timer);
    309   if (!(raidPtr->Layout.map->flags & RF_NO_STRIPE_LOCKS)) {
    310     RF_StripeNum_t lastStripeID = -1;
    311 
    312     /* acquire each lock that we don't already hold */
    313     for (asm_p = asmh->stripeMap; asm_p; asm_p = asm_p->next) {
    314       RF_ASSERT(RF_IO_IS_R_OR_W(desc->type));
    315       if (!rf_suppressLocksAndLargeWrites &&
    316           asm_p->parityInfo &&
    317           !(desc->flags& RF_DAG_SUPPRESS_LOCKS) &&
    318           !(asm_p->flags & RF_ASM_FLAGS_LOCK_TRIED))
    319       {
    320         asm_p->flags |= RF_ASM_FLAGS_LOCK_TRIED;
    321         RF_ASSERT(asm_p->stripeID > lastStripeID); /* locks must be acquired
    322 						   hierarchically */
    323         lastStripeID = asm_p->stripeID;
    324 	/* XXX the cast to (void (*)(RF_CBParam_t)) below is bogus!  GO */
    325         RF_INIT_LOCK_REQ_DESC(asm_p->lockReqDesc, desc->type,
    326             (void (*)(struct buf *))rf_ContinueRaidAccess, desc, asm_p,
    327             raidPtr->Layout.dataSectorsPerStripe);
    328         if (rf_AcquireStripeLock(raidPtr->lockTable, asm_p->stripeID,
    329             &asm_p->lockReqDesc))
    330         {
    331           suspended = RF_TRUE;
    332           break;
    333         }
    334       }
    335 
    336       if (desc->type == RF_IO_TYPE_WRITE &&
    337           raidPtr->status[asm_p->physInfo->row] == rf_rs_reconstructing)
    338       {
    339         if (! (asm_p->flags & RF_ASM_FLAGS_FORCE_TRIED) ) {
    340           int val;
    341 
    342           asm_p->flags |= RF_ASM_FLAGS_FORCE_TRIED;
    343 	  /* XXX the cast below is quite bogus!!! XXX  GO */
    344           val = rf_ForceOrBlockRecon(raidPtr, asm_p,
    345 		 (void (*)(RF_Raid_t *,void *))rf_ContinueRaidAccess, desc);
    346           if (val == 0) {
    347             asm_p->flags |= RF_ASM_FLAGS_RECON_BLOCKED;
    348           }
    349           else {
    350             suspended = RF_TRUE;
    351             break;
    352           }
    353         }
    354         else {
    355           if (rf_pssDebug) {
    356             printf("[%d] skipping force/block because already done, psid %ld\n",
    357                 desc->tid,(long)asm_p->stripeID);
    358           }
    359         }
    360       }
    361       else {
    362         if (rf_pssDebug) {
    363           printf("[%d] skipping force/block because not write or not under recon, psid %ld\n",
    364               desc->tid,(long)asm_p->stripeID);
    365         }
    366       }
    367     }
    368 
    369     RF_ETIMER_STOP(timer);
    370     RF_ETIMER_EVAL(timer);
    371     tracerec->specific.user.lock_us += RF_ETIMER_VAL_US(timer);
    372 
    373     if (suspended)
    374       return(RF_TRUE);
    375   }
    376 
    377   desc->state++;
    378   return(RF_FALSE);
    379 }
    380 
    381 /*
    382  * the following three states create, execute, and post-process dags
    383  * the error recovery unit is a single dag.
    384  * by default, SelectAlgorithm creates an array of dags, one per parity stripe
    385  * in some tricky cases, multiple dags per stripe are created
    386  *   - dags within a parity stripe are executed sequentially (arbitrary order)
    387  *   - dags for distinct parity stripes are executed concurrently
    388  *
    389  * repeat until all dags complete successfully -or- dag selection fails
    390  *
    391  * while !done
    392  *   create dag(s) (SelectAlgorithm)
    393  *   if dag
    394  *     execute dag (DispatchDAG)
    395  *     if dag successful
    396  *       done (SUCCESS)
    397  *     else
    398  *       !done (RETRY - start over with new dags)
    399  *   else
    400  *     done (FAIL)
    401  */
    402 int rf_State_CreateDAG (RF_RaidAccessDesc_t *desc)
    403 {
    404   RF_AccTraceEntry_t *tracerec     = &desc->tracerec;
    405   RF_Etimer_t timer;
    406   RF_DagHeader_t *dag_h;
    407   int i, selectStatus;
    408 
    409   /* generate a dag for the access, and fire it off.  When the dag
    410      completes, we'll get re-invoked in the next state. */
    411   RF_ETIMER_START(timer);
    412   /* SelectAlgorithm returns one or more dags */
    413   selectStatus = rf_SelectAlgorithm(desc, desc->flags|RF_DAG_SUPPRESS_LOCKS);
    414   if (rf_printDAGsDebug)
    415     for (i = 0; i < desc->numStripes; i++)
    416       rf_PrintDAGList(desc->dagArray[i].dags);
    417   RF_ETIMER_STOP(timer);
    418   RF_ETIMER_EVAL(timer);
    419   /* update time to create all dags */
    420   tracerec->specific.user.dag_create_us = RF_ETIMER_VAL_US(timer);
    421 
    422   desc->status = 0; /* good status */
    423 
    424   if (selectStatus) {
    425     /* failed to create a dag */
    426     /* this happens when there are too many faults or incomplete dag libraries */
    427     printf("[Failed to create a DAG\n]");
    428     RF_PANIC();
    429   }
    430   else {
    431     /* bind dags to desc */
    432     for (i = 0; i < desc->numStripes; i++) {
    433       dag_h = desc->dagArray[i].dags;
    434       while (dag_h) {
    435 	dag_h->bp = (struct buf *) desc->bp;
    436 	dag_h->tracerec = tracerec;
    437 	dag_h = dag_h->next;
    438       }
    439     }
    440     desc->flags |= RF_DAG_DISPATCH_RETURNED;
    441     desc->state++;  /* next state should be rf_State_ExecuteDAG */
    442   }
    443   return RF_FALSE;
    444 }
    445 
    446 
    447 
    448 /* the access has an array of dagLists, one dagList per parity stripe.
    449  * fire the first dag in each parity stripe (dagList).
    450  * dags within a stripe (dagList) must be executed sequentially
    451  *  - this preserves atomic parity update
    452  * dags for independents parity groups (stripes) are fired concurrently */
    453 
    454 int rf_State_ExecuteDAG(RF_RaidAccessDesc_t *desc)
    455 {
    456   int i;
    457   RF_DagHeader_t *dag_h;
    458   RF_DagList_t *dagArray = desc->dagArray;
    459 
    460   /* next state is always rf_State_ProcessDAG
    461    * important to do this before firing the first dag
    462    * (it may finish before we leave this routine) */
    463   desc->state++;
    464 
    465   /* sweep dag array, a stripe at a time, firing the first dag in each stripe */
    466   for (i = 0; i < desc->numStripes; i++) {
    467     RF_ASSERT(dagArray[i].numDags > 0);
    468     RF_ASSERT(dagArray[i].numDagsDone == 0);
    469     RF_ASSERT(dagArray[i].numDagsFired == 0);
    470     RF_ETIMER_START(dagArray[i].tracerec.timer);
    471     /* fire first dag in this stripe */
    472     dag_h = dagArray[i].dags;
    473     RF_ASSERT(dag_h);
    474     dagArray[i].numDagsFired++;
    475     /* XXX Yet another case where we pass in a conflicting function pointer
    476        :-(  XXX  GO */
    477     rf_DispatchDAG(dag_h, (void (*)(void *))rf_ContinueDagAccess, &dagArray[i]);
    478   }
    479 
    480   /* the DAG will always call the callback, even if there was no
    481    * blocking, so we are always suspended in this state */
    482   return RF_TRUE;
    483 }
    484 
    485 
    486 
    487 /* rf_State_ProcessDAG is entered when a dag completes.
    488  * first, check to all dags in the access have completed
    489  * if not, fire as many dags as possible */
    490 
    491 int rf_State_ProcessDAG(RF_RaidAccessDesc_t *desc)
    492 {
    493   RF_AccessStripeMapHeader_t *asmh = desc->asmap;
    494   RF_Raid_t *raidPtr               = desc->raidPtr;
    495   RF_DagHeader_t *dag_h;
    496   int i, j, done = RF_TRUE;
    497   RF_DagList_t *dagArray = desc->dagArray;
    498   RF_Etimer_t timer;
    499 
    500   /* check to see if this is the last dag */
    501   for (i = 0; i < desc->numStripes; i++)
    502     if (dagArray[i].numDags != dagArray[i].numDagsDone)
    503       done = RF_FALSE;
    504 
    505   if (done) {
    506     if (desc->status) {
    507       /* a dag failed, retry */
    508       RF_ETIMER_START(timer);
    509       /* free all dags */
    510       for (i = 0; i < desc->numStripes; i++) {
    511 	rf_FreeDAG(desc->dagArray[i].dags);
    512       }
    513       rf_MarkFailuresInASMList(raidPtr, asmh);
    514       /* back up to rf_State_CreateDAG */
    515       desc->state = desc->state - 2;
    516       return RF_FALSE;
    517     }
    518     else {
    519       /* move on to rf_State_Cleanup */
    520       desc->state++;
    521     }
    522     return RF_FALSE;
    523   }
    524   else {
    525     /* more dags to execute */
    526     /* see if any are ready to be fired.  if so, fire them */
    527     /* don't fire the initial dag in a list, it's fired in rf_State_ExecuteDAG */
    528     for (i = 0; i < desc->numStripes; i++) {
    529       if ((dagArray[i].numDagsDone < dagArray[i].numDags)
    530 	  && (dagArray[i].numDagsDone == dagArray[i].numDagsFired)
    531 	  && (dagArray[i].numDagsFired > 0)) {
    532 	RF_ETIMER_START(dagArray[i].tracerec.timer);
    533 	/* fire next dag in this stripe */
    534 	/* first, skip to next dag awaiting execution */
    535 	dag_h = dagArray[i].dags;
    536 	for (j = 0; j < dagArray[i].numDagsDone; j++)
    537 	  dag_h = dag_h->next;
    538 	dagArray[i].numDagsFired++;
    539 	/* XXX and again we pass a different function pointer.. GO */
    540 	rf_DispatchDAG(dag_h, (void (*)(void *))rf_ContinueDagAccess,
    541 		       &dagArray[i]);
    542       }
    543     }
    544     return RF_TRUE;
    545   }
    546 }
    547 
    548 /* only make it this far if all dags complete successfully */
    549 int rf_State_Cleanup(RF_RaidAccessDesc_t *desc)
    550 {
    551   RF_AccTraceEntry_t *tracerec     = &desc->tracerec;
    552   RF_AccessStripeMapHeader_t *asmh = desc->asmap;
    553   RF_Raid_t *raidPtr               = desc->raidPtr;
    554   RF_AccessStripeMap_t *asm_p;
    555   RF_DagHeader_t *dag_h;
    556   RF_Etimer_t timer;
    557   int tid, i;
    558 
    559   desc->state ++;
    560 
    561   rf_get_threadid(tid);
    562 
    563   timer = tracerec->timer;
    564   RF_ETIMER_STOP(timer);
    565   RF_ETIMER_EVAL(timer);
    566   tracerec->specific.user.dag_retry_us = RF_ETIMER_VAL_US(timer);
    567 
    568   /* the RAID I/O is complete.  Clean up. */
    569   tracerec->specific.user.dag_retry_us = 0;
    570 
    571   RF_ETIMER_START(timer);
    572   if (desc->flags & RF_DAG_RETURN_DAG) {
    573     /* copy dags into paramDAG */
    574     *(desc->paramDAG) = desc->dagArray[0].dags;
    575     dag_h = *(desc->paramDAG);
    576     for (i = 1; i < desc->numStripes; i++) {
    577       /* concatenate dags from remaining stripes */
    578       RF_ASSERT(dag_h);
    579       while (dag_h->next)
    580 	dag_h = dag_h->next;
    581       dag_h->next = desc->dagArray[i].dags;
    582     }
    583   }
    584   else {
    585     /* free all dags */
    586     for (i = 0; i < desc->numStripes; i++) {
    587       rf_FreeDAG(desc->dagArray[i].dags);
    588     }
    589   }
    590 
    591   RF_ETIMER_STOP(timer);
    592   RF_ETIMER_EVAL(timer);
    593   tracerec->specific.user.cleanup_us = RF_ETIMER_VAL_US(timer);
    594 
    595   RF_ETIMER_START(timer);
    596   if (!(raidPtr->Layout.map->flags & RF_NO_STRIPE_LOCKS)) {
    597     for (asm_p = asmh->stripeMap; asm_p; asm_p = asm_p->next) {
    598       if (!rf_suppressLocksAndLargeWrites &&
    599           asm_p->parityInfo &&
    600           !(desc->flags&RF_DAG_SUPPRESS_LOCKS))
    601       {
    602         RF_ASSERT_VALID_LOCKREQ(&asm_p->lockReqDesc);
    603         rf_ReleaseStripeLock(raidPtr->lockTable, asm_p->stripeID,
    604             &asm_p->lockReqDesc);
    605       }
    606       if (asm_p->flags & RF_ASM_FLAGS_RECON_BLOCKED) {
    607         rf_UnblockRecon(raidPtr, asm_p);
    608       }
    609     }
    610   }
    611 
    612   RF_ETIMER_STOP(timer);
    613   RF_ETIMER_EVAL(timer);
    614   tracerec->specific.user.lock_us += RF_ETIMER_VAL_US(timer);
    615 
    616   RF_ETIMER_START(timer);
    617   if (desc->flags & RF_DAG_RETURN_ASM)
    618     *(desc->paramASM) = asmh;
    619   else
    620     rf_FreeAccessStripeMap(asmh);
    621   RF_ETIMER_STOP(timer);
    622   RF_ETIMER_EVAL(timer);
    623   tracerec->specific.user.cleanup_us += RF_ETIMER_VAL_US(timer);
    624 
    625   RF_ETIMER_STOP(desc->timer);
    626   RF_ETIMER_EVAL(desc->timer);
    627 
    628   timer = desc->tracerec.tot_timer;
    629   RF_ETIMER_STOP(timer);
    630   RF_ETIMER_EVAL(timer);
    631   desc->tracerec.total_us = RF_ETIMER_VAL_US(timer);
    632 
    633   rf_LogTraceRec(raidPtr, tracerec);
    634 
    635   desc->flags |= RF_DAG_ACCESS_COMPLETE;
    636 
    637   return RF_FALSE;
    638 }
    639