rf_evenodd_dagfuncs.c revision 1.11
1/* $NetBSD: rf_evenodd_dagfuncs.c,v 1.11 2001/11/13 07:11:14 lukem Exp $ */ 2/* 3 * Copyright (c) 1995 Carnegie-Mellon University. 4 * All rights reserved. 5 * 6 * Author: ChangMing Wu 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@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 * Code for RAID-EVENODD architecture. 31 */ 32 33#include <sys/cdefs.h> 34__KERNEL_RCSID(0, "$NetBSD: rf_evenodd_dagfuncs.c,v 1.11 2001/11/13 07:11:14 lukem Exp $"); 35 36#include "rf_archs.h" 37 38#if RF_INCLUDE_EVENODD > 0 39 40#include <dev/raidframe/raidframevar.h> 41 42#include "rf_raid.h" 43#include "rf_dag.h" 44#include "rf_dagffrd.h" 45#include "rf_dagffwr.h" 46#include "rf_dagdegrd.h" 47#include "rf_dagdegwr.h" 48#include "rf_dagutils.h" 49#include "rf_dagfuncs.h" 50#include "rf_etimer.h" 51#include "rf_general.h" 52#include "rf_parityscan.h" 53#include "rf_evenodd.h" 54#include "rf_evenodd_dagfuncs.h" 55 56/* These redundant functions are for small write */ 57RF_RedFuncs_t rf_EOSmallWritePFuncs = {rf_RegularXorFunc, "Regular Old-New P", rf_SimpleXorFunc, "Simple Old-New P"}; 58RF_RedFuncs_t rf_EOSmallWriteEFuncs = {rf_RegularONEFunc, "Regular Old-New E", rf_SimpleONEFunc, "Regular Old-New E"}; 59/* These redundant functions are for degraded read */ 60RF_RedFuncs_t rf_eoPRecoveryFuncs = {rf_RecoveryXorFunc, "Recovery Xr", rf_RecoveryXorFunc, "Recovery Xr"}; 61RF_RedFuncs_t rf_eoERecoveryFuncs = {rf_RecoveryEFunc, "Recovery E Func", rf_RecoveryEFunc, "Recovery E Func"}; 62/********************************************************************************************** 63 * the following encoding node functions is used in EO_000_CreateLargeWriteDAG 64 **********************************************************************************************/ 65int 66rf_RegularPEFunc(node) 67 RF_DagNode_t *node; 68{ 69 rf_RegularESubroutine(node, node->results[1]); 70 rf_RegularXorFunc(node);/* does the wakeup here! */ 71#if 1 72 return (0); /* XXX This was missing... GO */ 73#endif 74} 75 76 77/************************************************************************************************ 78 * For EO_001_CreateSmallWriteDAG, there are (i)RegularONEFunc() and (ii)SimpleONEFunc() to 79 * be used. The previous case is when write access at least sectors of full stripe unit. 80 * The later function is used when the write access two stripe units but with total sectors 81 * less than sectors per SU. In this case, the access of parity and 'E' are shown as disconnected 82 * areas in their stripe unit and parity write and 'E' write are both devided into two distinct 83 * writes( totally four). This simple old-new write and regular old-new write happen as in RAID-5 84 ************************************************************************************************/ 85 86/* Algorithm: 87 1. Store the difference of old data and new data in the Rod buffer. 88 2. then encode this buffer into the buffer which already have old 'E' information inside it, 89 the result can be shown to be the new 'E' information. 90 3. xor the Wnd buffer into the difference buffer to recover the original old data. 91 Here we have another alternative: to allocate a temporary buffer for storing the difference of 92 old data and new data, then encode temp buf into old 'E' buf to form new 'E', but this approach 93 take the same speed as the previous, and need more memory. 94*/ 95int 96rf_RegularONEFunc(node) 97 RF_DagNode_t *node; 98{ 99 RF_Raid_t *raidPtr = (RF_Raid_t *) node->params[node->numParams - 1].p; 100 RF_RaidLayout_t *layoutPtr = (RF_RaidLayout_t *) & raidPtr->Layout; 101 int EpdaIndex = (node->numParams - 1) / 2 - 1; /* the parameter of node 102 * where you can find 103 * e-pda */ 104 int i, k, retcode = 0; 105 int suoffset, length; 106 RF_RowCol_t scol; 107 char *srcbuf, *destbuf; 108 RF_AccTraceEntry_t *tracerec = node->dagHdr->tracerec; 109 RF_Etimer_t timer; 110 RF_PhysDiskAddr_t *pda; 111#ifdef RAID_DIAGNOSTIC 112 RF_PhysDiskAddr_t *EPDA = 113 (RF_PhysDiskAddr_t *) node->params[EpdaIndex].p; 114 int ESUOffset = rf_StripeUnitOffset(layoutPtr, EPDA->startSector); 115#endif /* RAID_DIAGNOSTIC */ 116 117 RF_ASSERT(EPDA->type == RF_PDA_TYPE_Q); 118 RF_ASSERT(ESUOffset == 0); 119 120 RF_ETIMER_START(timer); 121 122 /* Xor the Wnd buffer into Rod buffer, the difference of old data and 123 * new data is stored in Rod buffer */ 124 for (k = 0; k < EpdaIndex; k += 2) { 125 length = rf_RaidAddressToByte(raidPtr, ((RF_PhysDiskAddr_t *) node->params[k].p)->numSector); 126 retcode = rf_bxor(node->params[k + EpdaIndex + 3].p, node->params[k + 1].p, length, node->dagHdr->bp); 127 } 128 /* Start to encoding the buffer storing the difference of old data and 129 * new data into 'E' buffer */ 130 for (i = 0; i < EpdaIndex; i += 2) 131 if (node->params[i + 1].p != node->results[0]) { /* results[0] is buf ptr 132 * of E */ 133 pda = (RF_PhysDiskAddr_t *) node->params[i].p; 134 srcbuf = (char *) node->params[i + 1].p; 135 scol = rf_EUCol(layoutPtr, pda->raidAddress); 136 suoffset = rf_StripeUnitOffset(layoutPtr, pda->startSector); 137 destbuf = ((char *) node->results[0]) + rf_RaidAddressToByte(raidPtr, suoffset); 138 rf_e_encToBuf(raidPtr, scol, srcbuf, RF_EO_MATRIX_DIM - 2, destbuf, pda->numSector); 139 } 140 /* Recover the original old data to be used by parity encoding 141 * function in XorNode */ 142 for (k = 0; k < EpdaIndex; k += 2) { 143 length = rf_RaidAddressToByte(raidPtr, ((RF_PhysDiskAddr_t *) node->params[k].p)->numSector); 144 retcode = rf_bxor(node->params[k + EpdaIndex + 3].p, node->params[k + 1].p, length, node->dagHdr->bp); 145 } 146 RF_ETIMER_STOP(timer); 147 RF_ETIMER_EVAL(timer); 148 tracerec->q_us += RF_ETIMER_VAL_US(timer); 149 rf_GenericWakeupFunc(node, 0); 150#if 1 151 return (0); /* XXX this was missing.. GO */ 152#endif 153} 154 155int 156rf_SimpleONEFunc(node) 157 RF_DagNode_t *node; 158{ 159 RF_Raid_t *raidPtr = (RF_Raid_t *) node->params[node->numParams - 1].p; 160 RF_RaidLayout_t *layoutPtr = (RF_RaidLayout_t *) & raidPtr->Layout; 161 RF_PhysDiskAddr_t *pda = (RF_PhysDiskAddr_t *) node->params[0].p; 162 int retcode = 0; 163 char *srcbuf, *destbuf; 164 RF_AccTraceEntry_t *tracerec = node->dagHdr->tracerec; 165 int length; 166 RF_RowCol_t scol; 167 RF_Etimer_t timer; 168 169 RF_ASSERT(((RF_PhysDiskAddr_t *) node->params[2].p)->type == RF_PDA_TYPE_Q); 170 if (node->dagHdr->status == rf_enable) { 171 RF_ETIMER_START(timer); 172 length = rf_RaidAddressToByte(raidPtr, ((RF_PhysDiskAddr_t *) node->params[4].p)->numSector); /* this is a pda of 173 * writeDataNodes */ 174 /* bxor to buffer of readDataNodes */ 175 retcode = rf_bxor(node->params[5].p, node->params[1].p, length, node->dagHdr->bp); 176 /* find out the corresponding colume in encoding matrix for 177 * write colume to be encoded into redundant disk 'E' */ 178 scol = rf_EUCol(layoutPtr, pda->raidAddress); 179 srcbuf = node->params[1].p; 180 destbuf = node->params[3].p; 181 /* Start encoding process */ 182 rf_e_encToBuf(raidPtr, scol, srcbuf, RF_EO_MATRIX_DIM - 2, destbuf, pda->numSector); 183 rf_bxor(node->params[5].p, node->params[1].p, length, node->dagHdr->bp); 184 RF_ETIMER_STOP(timer); 185 RF_ETIMER_EVAL(timer); 186 tracerec->q_us += RF_ETIMER_VAL_US(timer); 187 188 } 189 return (rf_GenericWakeupFunc(node, retcode)); /* call wake func 190 * explicitly since no 191 * I/O in this node */ 192} 193 194 195/****** called by rf_RegularPEFunc(node) and rf_RegularEFunc(node) in f.f. large write ********/ 196void 197rf_RegularESubroutine(node, ebuf) 198 RF_DagNode_t *node; 199 char *ebuf; 200{ 201 RF_Raid_t *raidPtr = (RF_Raid_t *) node->params[node->numParams - 1].p; 202 RF_RaidLayout_t *layoutPtr = (RF_RaidLayout_t *) & raidPtr->Layout; 203 RF_PhysDiskAddr_t *pda; 204 int i, suoffset; 205 RF_RowCol_t scol; 206 char *srcbuf, *destbuf; 207 RF_AccTraceEntry_t *tracerec = node->dagHdr->tracerec; 208 RF_Etimer_t timer; 209 210 RF_ETIMER_START(timer); 211 for (i = 0; i < node->numParams - 2; i += 2) { 212 RF_ASSERT(node->params[i + 1].p != ebuf); 213 pda = (RF_PhysDiskAddr_t *) node->params[i].p; 214 suoffset = rf_StripeUnitOffset(layoutPtr, pda->startSector); 215 scol = rf_EUCol(layoutPtr, pda->raidAddress); 216 srcbuf = (char *) node->params[i + 1].p; 217 destbuf = ebuf + rf_RaidAddressToByte(raidPtr, suoffset); 218 rf_e_encToBuf(raidPtr, scol, srcbuf, RF_EO_MATRIX_DIM - 2, destbuf, pda->numSector); 219 } 220 RF_ETIMER_STOP(timer); 221 RF_ETIMER_EVAL(timer); 222 tracerec->xor_us += RF_ETIMER_VAL_US(timer); 223} 224 225 226/******************************************************************************************* 227 * Used in EO_001_CreateLargeWriteDAG 228 ******************************************************************************************/ 229int 230rf_RegularEFunc(node) 231 RF_DagNode_t *node; 232{ 233 rf_RegularESubroutine(node, node->results[0]); 234 rf_GenericWakeupFunc(node, 0); 235#if 1 236 return (0); /* XXX this was missing?.. GO */ 237#endif 238} 239/******************************************************************************************* 240 * This degraded function allow only two case: 241 * 1. when write access the full failed stripe unit, then the access can be more than 242 * one tripe units. 243 * 2. when write access only part of the failed SU, we assume accesses of more than 244 * one stripe unit is not allowed so that the write can be dealt with like a 245 * large write. 246 * The following function is based on these assumptions. So except in the second case, 247 * it looks the same as a large write encodeing function. But this is not exactly the 248 * normal way for doing a degraded write, since raidframe have to break cases of access 249 * other than the above two into smaller accesses. We may have to change 250 * DegrESubroutin in the future. 251 *******************************************************************************************/ 252void 253rf_DegrESubroutine(node, ebuf) 254 RF_DagNode_t *node; 255 char *ebuf; 256{ 257 RF_Raid_t *raidPtr = (RF_Raid_t *) node->params[node->numParams - 1].p; 258 RF_RaidLayout_t *layoutPtr = (RF_RaidLayout_t *) & raidPtr->Layout; 259 RF_PhysDiskAddr_t *failedPDA = (RF_PhysDiskAddr_t *) node->params[node->numParams - 2].p; 260 RF_PhysDiskAddr_t *pda; 261 int i, suoffset, failedSUOffset = rf_StripeUnitOffset(layoutPtr, failedPDA->startSector); 262 RF_RowCol_t scol; 263 char *srcbuf, *destbuf; 264 RF_AccTraceEntry_t *tracerec = node->dagHdr->tracerec; 265 RF_Etimer_t timer; 266 267 RF_ETIMER_START(timer); 268 for (i = 0; i < node->numParams - 2; i += 2) { 269 RF_ASSERT(node->params[i + 1].p != ebuf); 270 pda = (RF_PhysDiskAddr_t *) node->params[i].p; 271 suoffset = rf_StripeUnitOffset(layoutPtr, pda->startSector); 272 scol = rf_EUCol(layoutPtr, pda->raidAddress); 273 srcbuf = (char *) node->params[i + 1].p; 274 destbuf = ebuf + rf_RaidAddressToByte(raidPtr, suoffset - failedSUOffset); 275 rf_e_encToBuf(raidPtr, scol, srcbuf, RF_EO_MATRIX_DIM - 2, destbuf, pda->numSector); 276 } 277 278 RF_ETIMER_STOP(timer); 279 RF_ETIMER_EVAL(timer); 280 tracerec->q_us += RF_ETIMER_VAL_US(timer); 281} 282 283 284/************************************************************************************** 285 * This function is used in case where one data disk failed and both redundant disks 286 * alive. It is used in the EO_100_CreateWriteDAG. Note: if there is another disk 287 * failed in the stripe but not accessed at this time, then we should, instead, use 288 * the rf_EOWriteDoubleRecoveryFunc(). 289 **************************************************************************************/ 290int 291rf_Degraded_100_EOFunc(node) 292 RF_DagNode_t *node; 293{ 294 rf_DegrESubroutine(node, node->results[1]); 295 rf_RecoveryXorFunc(node); /* does the wakeup here! */ 296#if 1 297 return (0); /* XXX this was missing... SHould these be 298 * void functions??? GO */ 299#endif 300} 301/************************************************************************************** 302 * This function is to encode one sector in one of the data disks to the E disk. 303 * However, in evenodd this function can also be used as decoding function to recover 304 * data from dead disk in the case of parity failure and a single data failure. 305 **************************************************************************************/ 306void 307rf_e_EncOneSect( 308 RF_RowCol_t srcLogicCol, 309 char *srcSecbuf, 310 RF_RowCol_t destLogicCol, 311 char *destSecbuf, 312 int bytesPerSector) 313{ 314 int S_index; /* index of the EU in the src col which need 315 * be Xored into all EUs in a dest sector */ 316 int numRowInEncMatix = (RF_EO_MATRIX_DIM) - 1; 317 RF_RowCol_t j, indexInDest, /* row index of an encoding unit in 318 * the destination colume of encoding 319 * matrix */ 320 indexInSrc; /* row index of an encoding unit in the source 321 * colume used for recovery */ 322 int bytesPerEU = bytesPerSector / numRowInEncMatix; 323 324#if RF_EO_MATRIX_DIM > 17 325 int shortsPerEU = bytesPerEU / sizeof(short); 326 short *destShortBuf, *srcShortBuf1, *srcShortBuf2; 327 short temp1; 328#elif RF_EO_MATRIX_DIM == 17 329 int longsPerEU = bytesPerEU / sizeof(long); 330 long *destLongBuf, *srcLongBuf1, *srcLongBuf2; 331 long temp1; 332#endif 333 334#if RF_EO_MATRIX_DIM > 17 335 RF_ASSERT(sizeof(short) == 2 || sizeof(short) == 1); 336 RF_ASSERT(bytesPerEU % sizeof(short) == 0); 337#elif RF_EO_MATRIX_DIM == 17 338 RF_ASSERT(sizeof(long) == 8 || sizeof(long) == 4); 339 RF_ASSERT(bytesPerEU % sizeof(long) == 0); 340#endif 341 342 S_index = rf_EO_Mod((RF_EO_MATRIX_DIM - 1 + destLogicCol - srcLogicCol), RF_EO_MATRIX_DIM); 343#if RF_EO_MATRIX_DIM > 17 344 srcShortBuf1 = (short *) (srcSecbuf + S_index * bytesPerEU); 345#elif RF_EO_MATRIX_DIM == 17 346 srcLongBuf1 = (long *) (srcSecbuf + S_index * bytesPerEU); 347#endif 348 349 for (indexInDest = 0; indexInDest < numRowInEncMatix; indexInDest++) { 350 indexInSrc = rf_EO_Mod((indexInDest + destLogicCol - srcLogicCol), RF_EO_MATRIX_DIM); 351 352#if RF_EO_MATRIX_DIM > 17 353 destShortBuf = (short *) (destSecbuf + indexInDest * bytesPerEU); 354 srcShortBuf2 = (short *) (srcSecbuf + indexInSrc * bytesPerEU); 355 for (j = 0; j < shortsPerEU; j++) { 356 temp1 = destShortBuf[j] ^ srcShortBuf1[j]; 357 /* note: S_index won't be at the end row for any src 358 * col! */ 359 if (indexInSrc != RF_EO_MATRIX_DIM - 1) 360 destShortBuf[j] = (srcShortBuf2[j]) ^ temp1; 361 /* if indexInSrc is at the end row, ie. 362 * RF_EO_MATRIX_DIM -1, then all elements are zero! */ 363 else 364 destShortBuf[j] = temp1; 365 } 366 367#elif RF_EO_MATRIX_DIM == 17 368 destLongBuf = (long *) (destSecbuf + indexInDest * bytesPerEU); 369 srcLongBuf2 = (long *) (srcSecbuf + indexInSrc * bytesPerEU); 370 for (j = 0; j < longsPerEU; j++) { 371 temp1 = destLongBuf[j] ^ srcLongBuf1[j]; 372 if (indexInSrc != RF_EO_MATRIX_DIM - 1) 373 destLongBuf[j] = (srcLongBuf2[j]) ^ temp1; 374 else 375 destLongBuf[j] = temp1; 376 } 377#endif 378 } 379} 380 381void 382rf_e_encToBuf( 383 RF_Raid_t * raidPtr, 384 RF_RowCol_t srcLogicCol, 385 char *srcbuf, 386 RF_RowCol_t destLogicCol, 387 char *destbuf, 388 int numSector) 389{ 390 int i, bytesPerSector = rf_RaidAddressToByte(raidPtr, 1); 391 392 for (i = 0; i < numSector; i++) { 393 rf_e_EncOneSect(srcLogicCol, srcbuf, destLogicCol, destbuf, bytesPerSector); 394 srcbuf += bytesPerSector; 395 destbuf += bytesPerSector; 396 } 397} 398/************************************************************************************** 399 * when parity die and one data die, We use second redundant information, 'E', 400 * to recover the data in dead disk. This function is used in the recovery node of 401 * for EO_110_CreateReadDAG 402 **************************************************************************************/ 403int 404rf_RecoveryEFunc(node) 405 RF_DagNode_t *node; 406{ 407 RF_Raid_t *raidPtr = (RF_Raid_t *) node->params[node->numParams - 1].p; 408 RF_RaidLayout_t *layoutPtr = (RF_RaidLayout_t *) & raidPtr->Layout; 409 RF_PhysDiskAddr_t *failedPDA = (RF_PhysDiskAddr_t *) node->params[node->numParams - 2].p; 410 RF_RowCol_t scol, /* source logical column */ 411 fcol = rf_EUCol(layoutPtr, failedPDA->raidAddress); /* logical column of 412 * failed SU */ 413 int i; 414 RF_PhysDiskAddr_t *pda; 415 int suoffset, failedSUOffset = rf_StripeUnitOffset(layoutPtr, failedPDA->startSector); 416 char *srcbuf, *destbuf; 417 RF_AccTraceEntry_t *tracerec = node->dagHdr->tracerec; 418 RF_Etimer_t timer; 419 420 memset((char *) node->results[0], 0, 421 rf_RaidAddressToByte(raidPtr, failedPDA->numSector)); 422 if (node->dagHdr->status == rf_enable) { 423 RF_ETIMER_START(timer); 424 for (i = 0; i < node->numParams - 2; i += 2) 425 if (node->params[i + 1].p != node->results[0]) { 426 pda = (RF_PhysDiskAddr_t *) node->params[i].p; 427 if (i == node->numParams - 4) 428 scol = RF_EO_MATRIX_DIM - 2; /* the colume of 429 * redundant E */ 430 else 431 scol = rf_EUCol(layoutPtr, pda->raidAddress); 432 srcbuf = (char *) node->params[i + 1].p; 433 suoffset = rf_StripeUnitOffset(layoutPtr, pda->startSector); 434 destbuf = ((char *) node->results[0]) + rf_RaidAddressToByte(raidPtr, suoffset - failedSUOffset); 435 rf_e_encToBuf(raidPtr, scol, srcbuf, fcol, destbuf, pda->numSector); 436 } 437 RF_ETIMER_STOP(timer); 438 RF_ETIMER_EVAL(timer); 439 tracerec->xor_us += RF_ETIMER_VAL_US(timer); 440 } 441 return (rf_GenericWakeupFunc(node, 0)); /* node execute successfully */ 442} 443/************************************************************************************** 444 * This function is used in the case where one data and the parity have filed. 445 * (in EO_110_CreateWriteDAG ) 446 **************************************************************************************/ 447int 448rf_EO_DegradedWriteEFunc(RF_DagNode_t * node) 449{ 450 rf_DegrESubroutine(node, node->results[0]); 451 rf_GenericWakeupFunc(node, 0); 452#if 1 453 return (0); /* XXX Yet another one!! GO */ 454#endif 455} 456 457 458 459/************************************************************************************** 460 * THE FUNCTION IS FOR DOUBLE DEGRADED READ AND WRITE CASES 461 **************************************************************************************/ 462 463void 464rf_doubleEOdecode( 465 RF_Raid_t * raidPtr, 466 char **rrdbuf, 467 char **dest, 468 RF_RowCol_t * fcol, 469 char *pbuf, 470 char *ebuf) 471{ 472 RF_RaidLayout_t *layoutPtr = (RF_RaidLayout_t *) & (raidPtr->Layout); 473 int i, j, k, f1, f2, row; 474 int rrdrow, erow, count = 0; 475 int bytesPerSector = rf_RaidAddressToByte(raidPtr, 1); 476 int numRowInEncMatix = (RF_EO_MATRIX_DIM) - 1; 477#if 0 478 int pcol = (RF_EO_MATRIX_DIM) - 1; 479#endif 480 int ecol = (RF_EO_MATRIX_DIM) - 2; 481 int bytesPerEU = bytesPerSector / numRowInEncMatix; 482 int numDataCol = layoutPtr->numDataCol; 483#if RF_EO_MATRIX_DIM > 17 484 int shortsPerEU = bytesPerEU / sizeof(short); 485 short *rrdbuf_current, *pbuf_current, *ebuf_current; 486 short *dest_smaller, *dest_smaller_current, *dest_larger, *dest_larger_current; 487 short *temp; 488 short *P; 489 490 RF_ASSERT(bytesPerEU % sizeof(short) == 0); 491 RF_Malloc(P, bytesPerEU, (short *)); 492 RF_Malloc(temp, bytesPerEU, (short *)); 493#elif RF_EO_MATRIX_DIM == 17 494 int longsPerEU = bytesPerEU / sizeof(long); 495 long *rrdbuf_current, *pbuf_current, *ebuf_current; 496 long *dest_smaller, *dest_smaller_current, *dest_larger, *dest_larger_current; 497 long *temp; 498 long *P; 499 500 RF_ASSERT(bytesPerEU % sizeof(long) == 0); 501 RF_Malloc(P, bytesPerEU, (long *)); 502 RF_Malloc(temp, bytesPerEU, (long *)); 503#endif 504 RF_ASSERT(*((long *) dest[0]) == 0); 505 RF_ASSERT(*((long *) dest[1]) == 0); 506 memset((char *) P, 0, bytesPerEU); 507 memset((char *) temp, 0, bytesPerEU); 508 RF_ASSERT(*P == 0); 509 /* calculate the 'P' parameter, which, not parity, is the Xor of all 510 * elements in the last two column, ie. 'E' and 'parity' colume, see 511 * the Ref. paper by Blaum, et al 1993 */ 512 for (i = 0; i < numRowInEncMatix; i++) 513 for (k = 0; k < longsPerEU; k++) { 514#if RF_EO_MATRIX_DIM > 17 515 ebuf_current = ((short *) ebuf) + i * shortsPerEU + k; 516 pbuf_current = ((short *) pbuf) + i * shortsPerEU + k; 517#elif RF_EO_MATRIX_DIM == 17 518 ebuf_current = ((long *) ebuf) + i * longsPerEU + k; 519 pbuf_current = ((long *) pbuf) + i * longsPerEU + k; 520#endif 521 P[k] ^= *ebuf_current; 522 P[k] ^= *pbuf_current; 523 } 524 RF_ASSERT(fcol[0] != fcol[1]); 525 if (fcol[0] < fcol[1]) { 526#if RF_EO_MATRIX_DIM > 17 527 dest_smaller = (short *) (dest[0]); 528 dest_larger = (short *) (dest[1]); 529#elif RF_EO_MATRIX_DIM == 17 530 dest_smaller = (long *) (dest[0]); 531 dest_larger = (long *) (dest[1]); 532#endif 533 f1 = fcol[0]; 534 f2 = fcol[1]; 535 } else { 536#if RF_EO_MATRIX_DIM > 17 537 dest_smaller = (short *) (dest[1]); 538 dest_larger = (short *) (dest[0]); 539#elif RF_EO_MATRIX_DIM == 17 540 dest_smaller = (long *) (dest[1]); 541 dest_larger = (long *) (dest[0]); 542#endif 543 f1 = fcol[1]; 544 f2 = fcol[0]; 545 } 546 row = (RF_EO_MATRIX_DIM) - 1; 547 while ((row = rf_EO_Mod((row + f1 - f2), RF_EO_MATRIX_DIM)) != ((RF_EO_MATRIX_DIM) - 1)) { 548#if RF_EO_MATRIX_DIM > 17 549 dest_larger_current = dest_larger + row * shortsPerEU; 550 dest_smaller_current = dest_smaller + row * shortsPerEU; 551#elif RF_EO_MATRIX_DIM == 17 552 dest_larger_current = dest_larger + row * longsPerEU; 553 dest_smaller_current = dest_smaller + row * longsPerEU; 554#endif 555 /** Do the diagonal recovery. Initially, temp[k] = (failed 1), 556 which is the failed data in the colume which has smaller col index. **/ 557 /* step 1: ^(SUM of nonfailed in-diagonal A(rrdrow,0..m-3)) */ 558 for (j = 0; j < numDataCol; j++) { 559 if (j == f1 || j == f2) 560 continue; 561 rrdrow = rf_EO_Mod((row + f2 - j), RF_EO_MATRIX_DIM); 562 if (rrdrow != (RF_EO_MATRIX_DIM) - 1) { 563#if RF_EO_MATRIX_DIM > 17 564 rrdbuf_current = (short *) (rrdbuf[j]) + rrdrow * shortsPerEU; 565 for (k = 0; k < shortsPerEU; k++) 566 temp[k] ^= *(rrdbuf_current + k); 567#elif RF_EO_MATRIX_DIM == 17 568 rrdbuf_current = (long *) (rrdbuf[j]) + rrdrow * longsPerEU; 569 for (k = 0; k < longsPerEU; k++) 570 temp[k] ^= *(rrdbuf_current + k); 571#endif 572 } 573 } 574 /* step 2: ^E(erow,m-2), If erow is at the buttom row, don't 575 * Xor into it E(erow,m-2) = (principle diagonal) ^ (failed 576 * 1) ^ (failed 2) ^ ( SUM of nonfailed in-diagonal 577 * A(rrdrow,0..m-3) ) After this step, temp[k] = (principle 578 * diagonal) ^ (failed 2) */ 579 580 erow = rf_EO_Mod((row + f2 - ecol), (RF_EO_MATRIX_DIM)); 581 if (erow != (RF_EO_MATRIX_DIM) - 1) { 582#if RF_EO_MATRIX_DIM > 17 583 ebuf_current = (short *) ebuf + shortsPerEU * erow; 584 for (k = 0; k < shortsPerEU; k++) 585 temp[k] ^= *(ebuf_current + k); 586#elif RF_EO_MATRIX_DIM == 17 587 ebuf_current = (long *) ebuf + longsPerEU * erow; 588 for (k = 0; k < longsPerEU; k++) 589 temp[k] ^= *(ebuf_current + k); 590#endif 591 } 592 /* step 3: ^P to obtain the failed data (failed 2). P can be 593 * proved to be actually (principle diagonal) After this 594 * step, temp[k] = (failed 2), the failed data to be recovered */ 595#if RF_EO_MATRIX_DIM > 17 596 for (k = 0; k < shortsPerEU; k++) 597 temp[k] ^= P[k]; 598 /* Put the data to the destination buffer */ 599 for (k = 0; k < shortsPerEU; k++) 600 dest_larger_current[k] = temp[k]; 601#elif RF_EO_MATRIX_DIM == 17 602 for (k = 0; k < longsPerEU; k++) 603 temp[k] ^= P[k]; 604 /* Put the data to the destination buffer */ 605 for (k = 0; k < longsPerEU; k++) 606 dest_larger_current[k] = temp[k]; 607#endif 608 609 /** THE FOLLOWING DO THE HORIZONTAL XOR **/ 610 /* step 1: ^(SUM of A(row,0..m-3)), ie. all nonfailed data 611 * columes */ 612 for (j = 0; j < numDataCol; j++) { 613 if (j == f1 || j == f2) 614 continue; 615#if RF_EO_MATRIX_DIM > 17 616 rrdbuf_current = (short *) (rrdbuf[j]) + row * shortsPerEU; 617 for (k = 0; k < shortsPerEU; k++) 618 temp[k] ^= *(rrdbuf_current + k); 619#elif RF_EO_MATRIX_DIM == 17 620 rrdbuf_current = (long *) (rrdbuf[j]) + row * longsPerEU; 621 for (k = 0; k < longsPerEU; k++) 622 temp[k] ^= *(rrdbuf_current + k); 623#endif 624 } 625 /* step 2: ^A(row,m-1) */ 626 /* step 3: Put the data to the destination buffer */ 627#if RF_EO_MATRIX_DIM > 17 628 pbuf_current = (short *) pbuf + shortsPerEU * row; 629 for (k = 0; k < shortsPerEU; k++) 630 temp[k] ^= *(pbuf_current + k); 631 for (k = 0; k < shortsPerEU; k++) 632 dest_smaller_current[k] = temp[k]; 633#elif RF_EO_MATRIX_DIM == 17 634 pbuf_current = (long *) pbuf + longsPerEU * row; 635 for (k = 0; k < longsPerEU; k++) 636 temp[k] ^= *(pbuf_current + k); 637 for (k = 0; k < longsPerEU; k++) 638 dest_smaller_current[k] = temp[k]; 639#endif 640 count++; 641 } 642 /* Check if all Encoding Unit in the data buffer have been decoded, 643 * according EvenOdd theory, if "RF_EO_MATRIX_DIM" is a prime number, 644 * this algorithm will covered all buffer */ 645 RF_ASSERT(count == numRowInEncMatix); 646 RF_Free((char *) P, bytesPerEU); 647 RF_Free((char *) temp, bytesPerEU); 648} 649 650 651/*************************************************************************************** 652* This function is called by double degragded read 653* EO_200_CreateReadDAG 654* 655***************************************************************************************/ 656int 657rf_EvenOddDoubleRecoveryFunc(node) 658 RF_DagNode_t *node; 659{ 660 int ndataParam = 0; 661 int np = node->numParams; 662 RF_AccessStripeMap_t *asmap = (RF_AccessStripeMap_t *) node->params[np - 1].p; 663 RF_Raid_t *raidPtr = (RF_Raid_t *) node->params[np - 2].p; 664 RF_RaidLayout_t *layoutPtr = (RF_RaidLayout_t *) & (raidPtr->Layout); 665 int i, prm, sector, nresults = node->numResults; 666 RF_SectorCount_t secPerSU = layoutPtr->sectorsPerStripeUnit; 667 unsigned sosAddr; 668 int two = 0, mallc_one = 0, mallc_two = 0; /* flags to indicate if 669 * memory is allocated */ 670 int bytesPerSector = rf_RaidAddressToByte(raidPtr, 1); 671 RF_PhysDiskAddr_t *ppda, *ppda2, *epda, *epda2, *pda, *pda0, *pda1, 672 npda; 673 RF_RowCol_t fcol[2], fsuoff[2], fsuend[2], numDataCol = layoutPtr->numDataCol; 674 char **buf, *ebuf, *pbuf, *dest[2]; 675 long *suoff = NULL, *suend = NULL, *prmToCol = NULL, psuoff, esuoff; 676 RF_SectorNum_t startSector, endSector; 677 RF_Etimer_t timer; 678 RF_AccTraceEntry_t *tracerec = node->dagHdr->tracerec; 679 680 RF_ETIMER_START(timer); 681 682 /* Find out the number of parameters which are pdas for data 683 * information */ 684 for (i = 0; i <= np; i++) 685 if (((RF_PhysDiskAddr_t *) node->params[i].p)->type != RF_PDA_TYPE_DATA) { 686 ndataParam = i; 687 break; 688 } 689 RF_Malloc(buf, numDataCol * sizeof(char *), (char **)); 690 if (ndataParam != 0) { 691 RF_Malloc(suoff, ndataParam * sizeof(long), (long *)); 692 RF_Malloc(suend, ndataParam * sizeof(long), (long *)); 693 RF_Malloc(prmToCol, ndataParam * sizeof(long), (long *)); 694 } 695 if (asmap->failedPDAs[1] && 696 (asmap->failedPDAs[1]->numSector + asmap->failedPDAs[0]->numSector < secPerSU)) { 697 RF_ASSERT(0); /* currently, no support for this situation */ 698 ppda = node->params[np - 6].p; 699 ppda2 = node->params[np - 5].p; 700 RF_ASSERT(ppda2->type == RF_PDA_TYPE_PARITY); 701 epda = node->params[np - 4].p; 702 epda2 = node->params[np - 3].p; 703 RF_ASSERT(epda2->type == RF_PDA_TYPE_Q); 704 two = 1; 705 } else { 706 ppda = node->params[np - 4].p; 707 epda = node->params[np - 3].p; 708 psuoff = rf_StripeUnitOffset(layoutPtr, ppda->startSector); 709 esuoff = rf_StripeUnitOffset(layoutPtr, epda->startSector); 710 RF_ASSERT(psuoff == esuoff); 711 } 712 /* 713 the followings have three goals: 714 1. determine the startSector to begin decoding and endSector to end decoding. 715 2. determine the colume numbers of the two failed disks. 716 3. determine the offset and end offset of the access within each failed stripe unit. 717 */ 718 if (nresults == 1) { 719 /* find the startSector to begin decoding */ 720 pda = node->results[0]; 721 memset(pda->bufPtr, 0, bytesPerSector * pda->numSector); 722 fsuoff[0] = rf_StripeUnitOffset(layoutPtr, pda->startSector); 723 fsuend[0] = fsuoff[0] + pda->numSector; 724 startSector = fsuoff[0]; 725 endSector = fsuend[0]; 726 727 /* find out the column of failed disk being accessed */ 728 fcol[0] = rf_EUCol(layoutPtr, pda->raidAddress); 729 730 /* find out the other failed colume not accessed */ 731 sosAddr = rf_RaidAddressOfPrevStripeBoundary(layoutPtr, asmap->raidAddress); 732 for (i = 0; i < numDataCol; i++) { 733 npda.raidAddress = sosAddr + (i * secPerSU); 734 (raidPtr->Layout.map->MapSector) (raidPtr, npda.raidAddress, &(npda.row), &(npda.col), &(npda.startSector), 0); 735 /* skip over dead disks */ 736 if (RF_DEAD_DISK(raidPtr->Disks[npda.row][npda.col].status)) 737 if (i != fcol[0]) 738 break; 739 } 740 RF_ASSERT(i < numDataCol); 741 fcol[1] = i; 742 } else { 743 RF_ASSERT(nresults == 2); 744 pda0 = node->results[0]; 745 memset(pda0->bufPtr, 0, bytesPerSector * pda0->numSector); 746 pda1 = node->results[1]; 747 memset(pda1->bufPtr, 0, bytesPerSector * pda1->numSector); 748 /* determine the failed colume numbers of the two failed 749 * disks. */ 750 fcol[0] = rf_EUCol(layoutPtr, pda0->raidAddress); 751 fcol[1] = rf_EUCol(layoutPtr, pda1->raidAddress); 752 /* determine the offset and end offset of the access within 753 * each failed stripe unit. */ 754 fsuoff[0] = rf_StripeUnitOffset(layoutPtr, pda0->startSector); 755 fsuend[0] = fsuoff[0] + pda0->numSector; 756 fsuoff[1] = rf_StripeUnitOffset(layoutPtr, pda1->startSector); 757 fsuend[1] = fsuoff[1] + pda1->numSector; 758 /* determine the startSector to begin decoding */ 759 startSector = RF_MIN(pda0->startSector, pda1->startSector); 760 /* determine the endSector to end decoding */ 761 endSector = RF_MAX(fsuend[0], fsuend[1]); 762 } 763 /* 764 assign the beginning sector and the end sector for each parameter 765 find out the corresponding colume # for each parameter 766 */ 767 for (prm = 0; prm < ndataParam; prm++) { 768 pda = node->params[prm].p; 769 suoff[prm] = rf_StripeUnitOffset(layoutPtr, pda->startSector); 770 suend[prm] = suoff[prm] + pda->numSector; 771 prmToCol[prm] = rf_EUCol(layoutPtr, pda->raidAddress); 772 } 773 /* 'sector' is the sector for the current decoding algorithm. For each 774 * sector in the failed SU, find out the corresponding parameters that 775 * cover the current sector and that are needed for decoding of this 776 * sector in failed SU. 2. Find out if sector is in the shadow of any 777 * accessed failed SU. If not, malloc a temporary space of a sector in 778 * size. */ 779 for (sector = startSector; sector < endSector; sector++) { 780 if (nresults == 2) 781 if (!(fsuoff[0] <= sector && sector < fsuend[0]) && !(fsuoff[1] <= sector && sector < fsuend[1])) 782 continue; 783 for (prm = 0; prm < ndataParam; prm++) 784 if (suoff[prm] <= sector && sector < suend[prm]) 785 buf[(prmToCol[prm])] = ((RF_PhysDiskAddr_t *) node->params[prm].p)->bufPtr + 786 rf_RaidAddressToByte(raidPtr, sector - suoff[prm]); 787 /* find out if sector is in the shadow of any accessed failed 788 * SU. If yes, assign dest[0], dest[1] to point at suitable 789 * position of the buffer corresponding to failed SUs. if no, 790 * malloc a temporary space of a sector in size for 791 * destination of decoding. */ 792 RF_ASSERT(nresults == 1 || nresults == 2); 793 if (nresults == 1) { 794 dest[0] = ((RF_PhysDiskAddr_t *) node->results[0])->bufPtr + rf_RaidAddressToByte(raidPtr, sector - fsuoff[0]); 795 /* Always malloc temp buffer to dest[1] */ 796 RF_Malloc(dest[1], bytesPerSector, (char *)); 797 memset(dest[1], 0, bytesPerSector); 798 mallc_two = 1; 799 } else { 800 if (fsuoff[0] <= sector && sector < fsuend[0]) 801 dest[0] = ((RF_PhysDiskAddr_t *) node->results[0])->bufPtr + rf_RaidAddressToByte(raidPtr, sector - fsuoff[0]); 802 else { 803 RF_Malloc(dest[0], bytesPerSector, (char *)); 804 memset(dest[0], 0, bytesPerSector); 805 mallc_one = 1; 806 } 807 if (fsuoff[1] <= sector && sector < fsuend[1]) 808 dest[1] = ((RF_PhysDiskAddr_t *) node->results[1])->bufPtr + rf_RaidAddressToByte(raidPtr, sector - fsuoff[1]); 809 else { 810 RF_Malloc(dest[1], bytesPerSector, (char *)); 811 memset(dest[1], 0, bytesPerSector); 812 mallc_two = 1; 813 } 814 RF_ASSERT(mallc_one == 0 || mallc_two == 0); 815 } 816 pbuf = ppda->bufPtr + rf_RaidAddressToByte(raidPtr, sector - psuoff); 817 ebuf = epda->bufPtr + rf_RaidAddressToByte(raidPtr, sector - esuoff); 818 /* 819 * After finish finding all needed sectors, call doubleEOdecode function for decoding 820 * one sector to destination. 821 */ 822 rf_doubleEOdecode(raidPtr, buf, dest, fcol, pbuf, ebuf); 823 /* free all allocated memory, and mark flag to indicate no 824 * memory is being allocated */ 825 if (mallc_one == 1) 826 RF_Free(dest[0], bytesPerSector); 827 if (mallc_two == 1) 828 RF_Free(dest[1], bytesPerSector); 829 mallc_one = mallc_two = 0; 830 } 831 RF_Free(buf, numDataCol * sizeof(char *)); 832 if (ndataParam != 0) { 833 RF_Free(suoff, ndataParam * sizeof(long)); 834 RF_Free(suend, ndataParam * sizeof(long)); 835 RF_Free(prmToCol, ndataParam * sizeof(long)); 836 } 837 RF_ETIMER_STOP(timer); 838 RF_ETIMER_EVAL(timer); 839 if (tracerec) { 840 tracerec->q_us += RF_ETIMER_VAL_US(timer); 841 } 842 rf_GenericWakeupFunc(node, 0); 843#if 1 844 return (0); /* XXX is this even close!!?!?!!? GO */ 845#endif 846} 847 848 849/* currently, only access of one of the two failed SU is allowed in this function. 850 * also, asmap->numStripeUnitsAccessed is limited to be one, the RaidFrame will break large access into 851 * many accesses of single stripe unit. 852 */ 853 854int 855rf_EOWriteDoubleRecoveryFunc(node) 856 RF_DagNode_t *node; 857{ 858 int np = node->numParams; 859 RF_AccessStripeMap_t *asmap = (RF_AccessStripeMap_t *) node->params[np - 1].p; 860 RF_Raid_t *raidPtr = (RF_Raid_t *) node->params[np - 2].p; 861 RF_RaidLayout_t *layoutPtr = (RF_RaidLayout_t *) & (raidPtr->Layout); 862 RF_SectorNum_t sector; 863 RF_RowCol_t col, scol; 864 int prm, i, j; 865 RF_SectorCount_t secPerSU = layoutPtr->sectorsPerStripeUnit; 866 unsigned sosAddr; 867 unsigned bytesPerSector = rf_RaidAddressToByte(raidPtr, 1); 868 RF_int64 numbytes; 869 RF_SectorNum_t startSector, endSector; 870 RF_PhysDiskAddr_t *ppda, *epda, *pda, *fpda, npda; 871 RF_RowCol_t fcol[2], numDataCol = layoutPtr->numDataCol; 872 char **buf; /* buf[0], buf[1], buf[2], ...etc. point to 873 * buffer storing data read from col0, col1, 874 * col2 */ 875 char *ebuf, *pbuf, *dest[2], *olddata[2]; 876 RF_Etimer_t timer; 877 RF_AccTraceEntry_t *tracerec = node->dagHdr->tracerec; 878 879 RF_ASSERT(asmap->numDataFailed == 1); /* currently only support this 880 * case, the other failed SU 881 * is not being accessed */ 882 RF_ETIMER_START(timer); 883 RF_Malloc(buf, numDataCol * sizeof(char *), (char **)); 884 885 ppda = node->results[0];/* Instead of being buffers, node->results[0] 886 * and [1] are Ppda and Epda */ 887 epda = node->results[1]; 888 fpda = asmap->failedPDAs[0]; 889 890 /* First, recovery the failed old SU using EvenOdd double decoding */ 891 /* determine the startSector and endSector for decoding */ 892 startSector = rf_StripeUnitOffset(layoutPtr, fpda->startSector); 893 endSector = startSector + fpda->numSector; 894 /* Assign buf[col] pointers to point to each non-failed colume and 895 * initialize the pbuf and ebuf to point at the beginning of each 896 * source buffers and destination buffers */ 897 for (prm = 0; prm < numDataCol - 2; prm++) { 898 pda = (RF_PhysDiskAddr_t *) node->params[prm].p; 899 col = rf_EUCol(layoutPtr, pda->raidAddress); 900 buf[col] = pda->bufPtr; 901 } 902 /* pbuf and ebuf: they will change values as double recovery decoding 903 * goes on */ 904 pbuf = ppda->bufPtr; 905 ebuf = epda->bufPtr; 906 /* find out the logical colume numbers in the encoding matrix of the 907 * two failed columes */ 908 fcol[0] = rf_EUCol(layoutPtr, fpda->raidAddress); 909 910 /* find out the other failed colume not accessed this time */ 911 sosAddr = rf_RaidAddressOfPrevStripeBoundary(layoutPtr, asmap->raidAddress); 912 for (i = 0; i < numDataCol; i++) { 913 npda.raidAddress = sosAddr + (i * secPerSU); 914 (raidPtr->Layout.map->MapSector) (raidPtr, npda.raidAddress, &(npda.row), &(npda.col), &(npda.startSector), 0); 915 /* skip over dead disks */ 916 if (RF_DEAD_DISK(raidPtr->Disks[npda.row][npda.col].status)) 917 if (i != fcol[0]) 918 break; 919 } 920 RF_ASSERT(i < numDataCol); 921 fcol[1] = i; 922 /* assign temporary space to put recovered failed SU */ 923 numbytes = fpda->numSector * bytesPerSector; 924 RF_Malloc(olddata[0], numbytes, (char *)); 925 RF_Malloc(olddata[1], numbytes, (char *)); 926 dest[0] = olddata[0]; 927 dest[1] = olddata[1]; 928 memset(olddata[0], 0, numbytes); 929 memset(olddata[1], 0, numbytes); 930 /* Begin the recovery decoding, initially buf[j], ebuf, pbuf, dest[j] 931 * have already pointed at the beginning of each source buffers and 932 * destination buffers */ 933 for (sector = startSector, i = 0; sector < endSector; sector++, i++) { 934 rf_doubleEOdecode(raidPtr, buf, dest, fcol, pbuf, ebuf); 935 for (j = 0; j < numDataCol; j++) 936 if ((j != fcol[0]) && (j != fcol[1])) 937 buf[j] += bytesPerSector; 938 dest[0] += bytesPerSector; 939 dest[1] += bytesPerSector; 940 ebuf += bytesPerSector; 941 pbuf += bytesPerSector; 942 } 943 /* after recovery, the buffer pointed by olddata[0] is the old failed 944 * data. With new writing data and this old data, use small write to 945 * calculate the new redundant informations */ 946 /* node->params[ 0, ... PDAPerDisk * (numDataCol - 2)-1 ] are Pdas of 947 * Rrd; params[ PDAPerDisk*(numDataCol - 2), ... PDAPerDisk*numDataCol 948 * -1 ] are Pdas of Rp, ( Rp2 ), Re, ( Re2 ) ; params[ 949 * PDAPerDisk*numDataCol, ... PDAPerDisk*numDataCol 950 * +asmap->numStripeUnitsAccessed -asmap->numDataFailed-1] are Pdas of 951 * wudNodes; For current implementation, we assume the simplest case: 952 * asmap->numStripeUnitsAccessed == 1 and asmap->numDataFailed == 1 953 * ie. PDAPerDisk = 1 then node->params[numDataCol] must be the new 954 * data to be writen to the failed disk. We first bxor the new data 955 * into the old recovered data, then do the same things as small 956 * write. */ 957 958 rf_bxor(((RF_PhysDiskAddr_t *) node->params[numDataCol].p)->bufPtr, olddata[0], numbytes, node->dagHdr->bp); 959 /* do new 'E' calculation */ 960 /* find out the corresponding colume in encoding matrix for write 961 * colume to be encoded into redundant disk 'E' */ 962 scol = rf_EUCol(layoutPtr, fpda->raidAddress); 963 /* olddata[0] now is source buffer pointer; epda->bufPtr is the dest 964 * buffer pointer */ 965 rf_e_encToBuf(raidPtr, scol, olddata[0], RF_EO_MATRIX_DIM - 2, epda->bufPtr, fpda->numSector); 966 967 /* do new 'P' calculation */ 968 rf_bxor(olddata[0], ppda->bufPtr, numbytes, node->dagHdr->bp); 969 /* Free the allocated buffer */ 970 RF_Free(olddata[0], numbytes); 971 RF_Free(olddata[1], numbytes); 972 RF_Free(buf, numDataCol * sizeof(char *)); 973 974 RF_ETIMER_STOP(timer); 975 RF_ETIMER_EVAL(timer); 976 if (tracerec) { 977 tracerec->q_us += RF_ETIMER_VAL_US(timer); 978 } 979 rf_GenericWakeupFunc(node, 0); 980 return (0); 981} 982#endif /* RF_INCLUDE_EVENODD > 0 */ 983