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