Exemplo n.º 1
0
void
rf_CommonCreateSimpleDegradedWriteDAG(RF_Raid_t *raidPtr,
				      RF_AccessStripeMap_t *asmap,
				      RF_DagHeader_t *dag_h, void *bp,
				      RF_RaidAccessFlags_t flags,
				      RF_AllocListElem_t *allocList,
				      int nfaults,
				      int (*redFunc) (RF_DagNode_t *),
				      int allowBufferRecycle)
{
	int     nNodes, nRrdNodes, nWndNodes, nXorBufs, i, j, paramNum,
	        rdnodesFaked;
	RF_DagNode_t *blockNode, *unblockNode, *wnpNode, *wnqNode, *termNode;
	RF_DagNode_t *wndNodes, *rrdNodes, *xorNode, *commitNode;
	RF_DagNode_t *tmpNode, *tmpwndNode, *tmprrdNode;
	RF_SectorCount_t sectorsPerSU;
	RF_ReconUnitNum_t which_ru;
	char   *xorTargetBuf = NULL;	/* the target buffer for the XOR
					 * operation */
	char   overlappingPDAs[RF_MAXCOL];/* a temporary array of flags */
	RF_AccessStripeMapHeader_t *new_asm_h[2];
	RF_PhysDiskAddr_t *pda, *parityPDA;
	RF_StripeNum_t parityStripeID;
	RF_PhysDiskAddr_t *failedPDA;
	RF_RaidLayout_t *layoutPtr;

	layoutPtr = &(raidPtr->Layout);
	parityStripeID = rf_RaidAddressToParityStripeID(layoutPtr, asmap->raidAddress,
	    &which_ru);
	sectorsPerSU = layoutPtr->sectorsPerStripeUnit;
	/* failedPDA points to the pda within the asm that targets the failed
	 * disk */
	failedPDA = asmap->failedPDAs[0];

#if RF_DEBUG_DAG
	if (rf_dagDebug)
		printf("[Creating degraded-write DAG]\n");
#endif

	RF_ASSERT(asmap->numDataFailed == 1);
	dag_h->creator = "SimpleDegradedWriteDAG";

	/*
         * Generate two ASMs identifying the surviving data
         * we need in order to recover the lost data.
         */
	/* overlappingPDAs array must be zero'd */
	memset(overlappingPDAs, 0, RF_MAXCOL);
	rf_GenerateFailedAccessASMs(raidPtr, asmap, failedPDA, dag_h, new_asm_h,
	    &nXorBufs, NULL, overlappingPDAs, allocList);

	/* create all the nodes at once */
	nWndNodes = asmap->numStripeUnitsAccessed - 1;	/* no access is
							 * generated for the
							 * failed pda */

	nRrdNodes = ((new_asm_h[0]) ? new_asm_h[0]->stripeMap->numStripeUnitsAccessed : 0) +
	    ((new_asm_h[1]) ? new_asm_h[1]->stripeMap->numStripeUnitsAccessed : 0);
	/*
         * XXX
         *
         * There's a bug with a complete stripe overwrite- that means 0 reads
         * of old data, and the rest of the DAG generation code doesn't like
         * that. A release is coming, and I don't wanna risk breaking a critical
         * DAG generator, so here's what I'm gonna do- if there's no read nodes,
         * I'm gonna fake there being a read node, and I'm gonna swap in a
         * no-op node in its place (to make all the link-up code happy).
         * This should be fixed at some point.  --jimz
         */
	if (nRrdNodes == 0) {
		nRrdNodes = 1;
		rdnodesFaked = 1;
	} else {
		rdnodesFaked = 0;
	}
	/* lock, unlock, xor, Wnd, Rrd, W(nfaults) */
	nNodes = 5 + nfaults + nWndNodes + nRrdNodes;

	blockNode = rf_AllocDAGNode();
	blockNode->list_next = dag_h->nodes;
	dag_h->nodes = blockNode;

	commitNode = rf_AllocDAGNode();
	commitNode->list_next = dag_h->nodes;
	dag_h->nodes = commitNode;

	unblockNode = rf_AllocDAGNode();
	unblockNode->list_next = dag_h->nodes;
	dag_h->nodes = unblockNode;

	termNode = rf_AllocDAGNode();
	termNode->list_next = dag_h->nodes;
	dag_h->nodes = termNode;

	xorNode = rf_AllocDAGNode();
	xorNode->list_next = dag_h->nodes;
	dag_h->nodes = xorNode;

	wnpNode = rf_AllocDAGNode();
	wnpNode->list_next = dag_h->nodes;
	dag_h->nodes = wnpNode;

	for (i = 0; i < nWndNodes; i++) {
		tmpNode = rf_AllocDAGNode();
		tmpNode->list_next = dag_h->nodes;
		dag_h->nodes = tmpNode;
	}
	wndNodes = dag_h->nodes;

	for (i = 0; i < nRrdNodes; i++) {
		tmpNode = rf_AllocDAGNode();
		tmpNode->list_next = dag_h->nodes;
		dag_h->nodes = tmpNode;
	}
	rrdNodes = dag_h->nodes;

#if (RF_INCLUDE_DECL_PQ > 0) || (RF_INCLUDE_RAID6 > 0)
	if (nfaults == 2) {
		wnqNode = rf_AllocDAGNode();
		wnqNode->list_next = dag_h->nodes;
		dag_h->nodes = wnqNode;
	} else {
#endif
		wnqNode = NULL;
#if (RF_INCLUDE_DECL_PQ > 0) || (RF_INCLUDE_RAID6 > 0)
	}
#endif

	/* this dag can not commit until all rrd and xor Nodes have completed */
	dag_h->numCommitNodes = 1;
	dag_h->numCommits = 0;
	dag_h->numSuccedents = 1;

	RF_ASSERT(nRrdNodes > 0);
	rf_InitNode(blockNode, rf_wait, RF_FALSE, rf_NullNodeFunc, rf_NullNodeUndoFunc,
	    NULL, nRrdNodes, 0, 0, 0, dag_h, "Nil", allocList);
	rf_InitNode(commitNode, rf_wait, RF_TRUE, rf_NullNodeFunc, rf_NullNodeUndoFunc,
	    NULL, nWndNodes + nfaults, 1, 0, 0, dag_h, "Cmt", allocList);
	rf_InitNode(unblockNode, rf_wait, RF_FALSE, rf_NullNodeFunc, rf_NullNodeUndoFunc,
	    NULL, 1, nWndNodes + nfaults, 0, 0, dag_h, "Nil", allocList);
	rf_InitNode(termNode, rf_wait, RF_FALSE, rf_TerminateFunc, rf_TerminateUndoFunc,
	    NULL, 0, 1, 0, 0, dag_h, "Trm", allocList);
	rf_InitNode(xorNode, rf_wait, RF_FALSE, redFunc, rf_NullNodeUndoFunc, NULL, 1,
	    nRrdNodes, 2 * nXorBufs + 2, nfaults, dag_h, "Xrc", allocList);

	/*
         * Fill in the Rrd nodes. If any of the rrd buffers are the same size as
         * the failed buffer, save a pointer to it so we can use it as the target
         * of the XOR. The pdas in the rrd nodes have been range-restricted, so if
         * a buffer is the same size as the failed buffer, it must also be at the
         * same alignment within the SU.
         */
	i = 0;
	tmprrdNode = rrdNodes;
	if (new_asm_h[0]) {
		for (i = 0, pda = new_asm_h[0]->stripeMap->physInfo;
		    i < new_asm_h[0]->stripeMap->numStripeUnitsAccessed;
		    i++, pda = pda->next) {
			rf_InitNode(tmprrdNode, rf_wait, RF_FALSE, rf_DiskReadFunc, rf_DiskReadUndoFunc,
			    rf_GenericWakeupFunc, 1, 1, 4, 0, dag_h, "Rrd", allocList);
			RF_ASSERT(pda);
			tmprrdNode->params[0].p = pda;
			tmprrdNode->params[1].p = pda->bufPtr;
			tmprrdNode->params[2].v = parityStripeID;
			tmprrdNode->params[3].v = RF_CREATE_PARAM3(RF_IO_NORMAL_PRIORITY, which_ru);
			tmprrdNode = tmprrdNode->list_next;
		}
	}
	/* i now equals the number of stripe units accessed in new_asm_h[0] */
	/* Note that for tmprrdNode, this means a continuation from above, so no need to
	   assign it anything.. */
	if (new_asm_h[1]) {
		for (j = 0, pda = new_asm_h[1]->stripeMap->physInfo;
		    j < new_asm_h[1]->stripeMap->numStripeUnitsAccessed;
		    j++, pda = pda->next) {
			rf_InitNode(tmprrdNode, rf_wait, RF_FALSE, rf_DiskReadFunc, rf_DiskReadUndoFunc,
			    rf_GenericWakeupFunc, 1, 1, 4, 0, dag_h, "Rrd", allocList);
			RF_ASSERT(pda);
			tmprrdNode->params[0].p = pda;
			tmprrdNode->params[1].p = pda->bufPtr;
			tmprrdNode->params[2].v = parityStripeID;
			tmprrdNode->params[3].v = RF_CREATE_PARAM3(RF_IO_NORMAL_PRIORITY, which_ru);
			if (allowBufferRecycle && (pda->numSector == failedPDA->numSector))
				xorTargetBuf = pda->bufPtr;
			tmprrdNode = tmprrdNode->list_next;
		}
	}
	if (rdnodesFaked) {
		/*
	         * This is where we'll init that fake noop read node
	         * (XXX should the wakeup func be different?)
	         */
		/* node that rrdNodes will just be a single node... */
		rf_InitNode(rrdNodes, rf_wait, RF_FALSE, rf_NullNodeFunc, rf_NullNodeUndoFunc,
		    NULL, 1, 1, 0, 0, dag_h, "RrN", allocList);
	}
	/*
         * Make a PDA for the parity unit.  The parity PDA should start at
         * the same offset into the SU as the failed PDA.
         */
	/* Danner comment: I don't think this copy is really necessary. We are
	 * in one of two cases here. (1) The entire failed unit is written.
	 * Then asmap->parityInfo will describe the entire parity. (2) We are
	 * only writing a subset of the failed unit and nothing else. Then the
	 * asmap->parityInfo describes the failed unit and the copy can also
	 * be avoided. */

	parityPDA = rf_AllocPhysDiskAddr();
	parityPDA->next = dag_h->pda_cleanup_list;
	dag_h->pda_cleanup_list = parityPDA;
	parityPDA->col = asmap->parityInfo->col;
	parityPDA->startSector = ((asmap->parityInfo->startSector / sectorsPerSU)
	    * sectorsPerSU) + (failedPDA->startSector % sectorsPerSU);
	parityPDA->numSector = failedPDA->numSector;

	if (!xorTargetBuf) {
		xorTargetBuf = rf_AllocBuffer(raidPtr, dag_h, rf_RaidAddressToByte(raidPtr, failedPDA->numSector));
	}
	/* init the Wnp node */
	rf_InitNode(wnpNode, rf_wait, RF_FALSE, rf_DiskWriteFunc, rf_DiskWriteUndoFunc,
	    rf_GenericWakeupFunc, 1, 1, 4, 0, dag_h, "Wnp", allocList);
	wnpNode->params[0].p = parityPDA;
	wnpNode->params[1].p = xorTargetBuf;
	wnpNode->params[2].v = parityStripeID;
	wnpNode->params[3].v = RF_CREATE_PARAM3(RF_IO_NORMAL_PRIORITY, which_ru);

#if (RF_INCLUDE_DECL_PQ > 0) || (RF_INCLUDE_RAID6 > 0)
	/* fill in the Wnq Node */
	if (nfaults == 2) {
		{
			RF_MallocAndAdd(parityPDA, sizeof(RF_PhysDiskAddr_t),
			    (RF_PhysDiskAddr_t *), allocList);
			parityPDA->col = asmap->qInfo->col;
			parityPDA->startSector = ((asmap->qInfo->startSector / sectorsPerSU)
			    * sectorsPerSU) + (failedPDA->startSector % sectorsPerSU);
			parityPDA->numSector = failedPDA->numSector;

			rf_InitNode(wnqNode, rf_wait, RF_FALSE, rf_DiskWriteFunc, rf_DiskWriteUndoFunc,
			    rf_GenericWakeupFunc, 1, 1, 4, 0, dag_h, "Wnq", allocList);
			wnqNode->params[0].p = parityPDA;
			RF_MallocAndAdd(xorNode->results[1],
			    rf_RaidAddressToByte(raidPtr, failedPDA->numSector), (char *), allocList);
			wnqNode->params[1].p = xorNode->results[1];
			wnqNode->params[2].v = parityStripeID;
			wnqNode->params[3].v = RF_CREATE_PARAM3(RF_IO_NORMAL_PRIORITY, which_ru);
		}
Exemplo n.º 2
0
void
rf_CreateDegradedReadDAG(RF_Raid_t *raidPtr, RF_AccessStripeMap_t *asmap,
			 RF_DagHeader_t *dag_h, void *bp,
			 RF_RaidAccessFlags_t flags,
			 RF_AllocListElem_t *allocList,
			 const RF_RedFuncs_t *recFunc)
{
	RF_DagNode_t *rudNodes, *rrdNodes, *xorNode, *blockNode;
	RF_DagNode_t *commitNode, *rpNode, *termNode;
	RF_DagNode_t *tmpNode, *tmprudNode, *tmprrdNode;
	int     nRrdNodes, nRudNodes, nXorBufs, i;
	int     j, paramNum;
	RF_SectorCount_t sectorsPerSU;
	RF_ReconUnitNum_t which_ru;
	char    overlappingPDAs[RF_MAXCOL];/* a temporary array of flags */
	RF_AccessStripeMapHeader_t *new_asm_h[2];
	RF_PhysDiskAddr_t *pda, *parityPDA;
	RF_StripeNum_t parityStripeID;
	RF_PhysDiskAddr_t *failedPDA;
	RF_RaidLayout_t *layoutPtr;
	char   *rpBuf;

	layoutPtr = &(raidPtr->Layout);
	/* failedPDA points to the pda within the asm that targets the failed
	 * disk */
	failedPDA = asmap->failedPDAs[0];
	parityStripeID = rf_RaidAddressToParityStripeID(layoutPtr,
	    asmap->raidAddress, &which_ru);
	sectorsPerSU = layoutPtr->sectorsPerStripeUnit;

#if RF_DEBUG_DAG
	if (rf_dagDebug) {
		printf("[Creating degraded read DAG]\n");
	}
#endif
	RF_ASSERT(asmap->numDataFailed == 1);
	dag_h->creator = "DegradedReadDAG";

	/*
         * generate two ASMs identifying the surviving data we need
         * in order to recover the lost data
         */

	/* overlappingPDAs array must be zero'd */
	memset(overlappingPDAs, 0, RF_MAXCOL);
	rf_GenerateFailedAccessASMs(raidPtr, asmap, failedPDA, dag_h, new_asm_h, &nXorBufs,
	    &rpBuf, overlappingPDAs, allocList);

	/*
         * create all the nodes at once
         *
         * -1 because no access is generated for the failed pda
         */
	nRudNodes = asmap->numStripeUnitsAccessed - 1;
	nRrdNodes = ((new_asm_h[0]) ? new_asm_h[0]->stripeMap->numStripeUnitsAccessed : 0) +
	    ((new_asm_h[1]) ? new_asm_h[1]->stripeMap->numStripeUnitsAccessed : 0);

	blockNode = rf_AllocDAGNode();
	blockNode->list_next = dag_h->nodes;
	dag_h->nodes = blockNode;

	commitNode = rf_AllocDAGNode();
	commitNode->list_next = dag_h->nodes;
	dag_h->nodes = commitNode;

	xorNode = rf_AllocDAGNode();
	xorNode->list_next = dag_h->nodes;
	dag_h->nodes = xorNode;

	rpNode = rf_AllocDAGNode();
	rpNode->list_next = dag_h->nodes;
	dag_h->nodes = rpNode;

	termNode = rf_AllocDAGNode();
	termNode->list_next = dag_h->nodes;
	dag_h->nodes = termNode;

	for (i = 0; i < nRudNodes; i++) {
		tmpNode = rf_AllocDAGNode();
		tmpNode->list_next = dag_h->nodes;
		dag_h->nodes = tmpNode;
	}
	rudNodes = dag_h->nodes;

	for (i = 0; i < nRrdNodes; i++) {
		tmpNode = rf_AllocDAGNode();
		tmpNode->list_next = dag_h->nodes;
		dag_h->nodes = tmpNode;
	}
	rrdNodes = dag_h->nodes;

	/* initialize nodes */
	dag_h->numCommitNodes = 1;
	dag_h->numCommits = 0;
	/* this dag can not commit until the commit node is reached errors
	 * prior to the commit point imply the dag has failed */
	dag_h->numSuccedents = 1;

	rf_InitNode(blockNode, rf_wait, RF_FALSE, rf_NullNodeFunc, rf_NullNodeUndoFunc,
	    NULL, nRudNodes + nRrdNodes + 1, 0, 0, 0, dag_h, "Nil", allocList);
	rf_InitNode(commitNode, rf_wait, RF_TRUE, rf_NullNodeFunc, rf_NullNodeUndoFunc,
	    NULL, 1, 1, 0, 0, dag_h, "Cmt", allocList);
	rf_InitNode(termNode, rf_wait, RF_FALSE, rf_TerminateFunc, rf_TerminateUndoFunc,
	    NULL, 0, 1, 0, 0, dag_h, "Trm", allocList);
	rf_InitNode(xorNode, rf_wait, RF_FALSE, recFunc->simple, rf_NullNodeUndoFunc,
	    NULL, 1, nRudNodes + nRrdNodes + 1, 2 * nXorBufs + 2, 1, dag_h,
	    recFunc->SimpleName, allocList);

	/* fill in the Rud nodes */
	tmprudNode = rudNodes;
	for (pda = asmap->physInfo, i = 0; i < nRudNodes; i++, pda = pda->next) {
		if (pda == failedPDA) {
			i--;
			continue;
		}
		rf_InitNode(tmprudNode, rf_wait, RF_FALSE, rf_DiskReadFunc,
		    rf_DiskReadUndoFunc, rf_GenericWakeupFunc, 1, 1, 4, 0, dag_h,
		    "Rud", allocList);
		RF_ASSERT(pda);
		tmprudNode->params[0].p = pda;
		tmprudNode->params[1].p = pda->bufPtr;
		tmprudNode->params[2].v = parityStripeID;
		tmprudNode->params[3].v = RF_CREATE_PARAM3(RF_IO_NORMAL_PRIORITY, which_ru);
		tmprudNode = tmprudNode->list_next;
	}

	/* fill in the Rrd nodes */
	i = 0;
	tmprrdNode = rrdNodes;
	if (new_asm_h[0]) {
		for (pda = new_asm_h[0]->stripeMap->physInfo;
		    i < new_asm_h[0]->stripeMap->numStripeUnitsAccessed;
		    i++, pda = pda->next) {
			rf_InitNode(tmprrdNode, rf_wait, RF_FALSE, rf_DiskReadFunc,
			    rf_DiskReadUndoFunc, rf_GenericWakeupFunc, 1, 1, 4, 0,
			    dag_h, "Rrd", allocList);
			RF_ASSERT(pda);
			tmprrdNode->params[0].p = pda;
			tmprrdNode->params[1].p = pda->bufPtr;
			tmprrdNode->params[2].v = parityStripeID;
			tmprrdNode->params[3].v = RF_CREATE_PARAM3(RF_IO_NORMAL_PRIORITY, which_ru);
			tmprrdNode = tmprrdNode->list_next;
		}
	}
	if (new_asm_h[1]) {
		/* tmprrdNode = rrdNodes; */ /* don't set this here -- old code was using i+j, which means
		   we need to just continue using tmprrdNode for the next 'j' elements. */
		for (j = 0, pda = new_asm_h[1]->stripeMap->physInfo;
		    j < new_asm_h[1]->stripeMap->numStripeUnitsAccessed;
		    j++, pda = pda->next) {
			rf_InitNode(tmprrdNode, rf_wait, RF_FALSE, rf_DiskReadFunc,
			    rf_DiskReadUndoFunc, rf_GenericWakeupFunc, 1, 1, 4, 0,
			    dag_h, "Rrd", allocList);
			RF_ASSERT(pda);
			tmprrdNode->params[0].p = pda;
			tmprrdNode->params[1].p = pda->bufPtr;
			tmprrdNode->params[2].v = parityStripeID;
			tmprrdNode->params[3].v = RF_CREATE_PARAM3(RF_IO_NORMAL_PRIORITY, which_ru);
			tmprrdNode = tmprrdNode->list_next;
		}
	}
	/* make a PDA for the parity unit */
	parityPDA = rf_AllocPhysDiskAddr();
	parityPDA->next = dag_h->pda_cleanup_list;
	dag_h->pda_cleanup_list = parityPDA;
	parityPDA->col = asmap->parityInfo->col;
	parityPDA->startSector = ((asmap->parityInfo->startSector / sectorsPerSU)
	    * sectorsPerSU) + (failedPDA->startSector % sectorsPerSU);
	parityPDA->numSector = failedPDA->numSector;

	/* initialize the Rp node */
	rf_InitNode(rpNode, rf_wait, RF_FALSE, rf_DiskReadFunc, rf_DiskReadUndoFunc,
	    rf_GenericWakeupFunc, 1, 1, 4, 0, dag_h, "Rp ", allocList);
	rpNode->params[0].p = parityPDA;
	rpNode->params[1].p = rpBuf;
	rpNode->params[2].v = parityStripeID;
	rpNode->params[3].v = RF_CREATE_PARAM3(RF_IO_NORMAL_PRIORITY, which_ru);

	/*
         * the last and nastiest step is to assign all
         * the parameters of the Xor node
         */
	paramNum = 0;
	tmprrdNode = rrdNodes;
	for (i = 0; i < nRrdNodes; i++) {
		/* all the Rrd nodes need to be xored together */
		xorNode->params[paramNum++] = tmprrdNode->params[0];
		xorNode->params[paramNum++] = tmprrdNode->params[1];
		tmprrdNode = tmprrdNode->list_next;
	}
	tmprudNode = rudNodes;
	for (i = 0; i < nRudNodes; i++) {
		/* any Rud nodes that overlap the failed access need to be
		 * xored in */
		if (overlappingPDAs[i]) {
			pda = rf_AllocPhysDiskAddr();
			memcpy((char *) pda, (char *) tmprudNode->params[0].p, sizeof(RF_PhysDiskAddr_t));
			/* add it into the pda_cleanup_list *after* the copy, TYVM */
			pda->next = dag_h->pda_cleanup_list;
			dag_h->pda_cleanup_list = pda;
			rf_RangeRestrictPDA(raidPtr, failedPDA, pda, RF_RESTRICT_DOBUFFER, 0);
			xorNode->params[paramNum++].p = pda;
			xorNode->params[paramNum++].p = pda->bufPtr;
		}
		tmprudNode = tmprudNode->list_next;
	}

	/* install parity pda as last set of params to be xor'd */
	xorNode->params[paramNum++].p = parityPDA;
	xorNode->params[paramNum++].p = rpBuf;

	/*
         * the last 2 params to the recovery xor node are
         * the failed PDA and the raidPtr
         */
	xorNode->params[paramNum++].p = failedPDA;
	xorNode->params[paramNum++].p = raidPtr;
	RF_ASSERT(paramNum == 2 * nXorBufs + 2);

	/*
         * The xor node uses results[0] as the target buffer.
         * Set pointer and zero the buffer. In the kernel, this
         * may be a user buffer in which case we have to remap it.
         */
	xorNode->results[0] = failedPDA->bufPtr;
	memset(failedPDA->bufPtr, 0, rf_RaidAddressToByte(raidPtr,
		failedPDA->numSector));

	/* connect nodes to form graph */
	/* connect the header to the block node */
	RF_ASSERT(dag_h->numSuccedents == 1);
	RF_ASSERT(blockNode->numAntecedents == 0);
	dag_h->succedents[0] = blockNode;

	/* connect the block node to the read nodes */
	RF_ASSERT(blockNode->numSuccedents == (1 + nRrdNodes + nRudNodes));
	RF_ASSERT(rpNode->numAntecedents == 1);
	blockNode->succedents[0] = rpNode;
	rpNode->antecedents[0] = blockNode;
	rpNode->antType[0] = rf_control;
	tmprrdNode = rrdNodes;
	for (i = 0; i < nRrdNodes; i++) {
		RF_ASSERT(tmprrdNode->numSuccedents == 1);
		blockNode->succedents[1 + i] = tmprrdNode;
		tmprrdNode->antecedents[0] = blockNode;
		tmprrdNode->antType[0] = rf_control;
		tmprrdNode = tmprrdNode->list_next;
	}
	tmprudNode = rudNodes;
	for (i = 0; i < nRudNodes; i++) {
		RF_ASSERT(tmprudNode->numSuccedents == 1);
		blockNode->succedents[1 + nRrdNodes + i] = tmprudNode;
		tmprudNode->antecedents[0] = blockNode;
		tmprudNode->antType[0] = rf_control;
		tmprudNode = tmprudNode->list_next;
	}

	/* connect the read nodes to the xor node */
	RF_ASSERT(xorNode->numAntecedents == (1 + nRrdNodes + nRudNodes));
	RF_ASSERT(rpNode->numSuccedents == 1);
	rpNode->succedents[0] = xorNode;
	xorNode->antecedents[0] = rpNode;
	xorNode->antType[0] = rf_trueData;
	tmprrdNode = rrdNodes;
	for (i = 0; i < nRrdNodes; i++) {
		RF_ASSERT(tmprrdNode->numSuccedents == 1);
		tmprrdNode->succedents[0] = xorNode;
		xorNode->antecedents[1 + i] = tmprrdNode;
		xorNode->antType[1 + i] = rf_trueData;
		tmprrdNode = tmprrdNode->list_next;
	}
	tmprudNode = rudNodes;
	for (i = 0; i < nRudNodes; i++) {
		RF_ASSERT(tmprudNode->numSuccedents == 1);
		tmprudNode->succedents[0] = xorNode;
		xorNode->antecedents[1 + nRrdNodes + i] = tmprudNode;
		xorNode->antType[1 + nRrdNodes + i] = rf_trueData;
		tmprudNode = tmprudNode->list_next;
	}

	/* connect the xor node to the commit node */
	RF_ASSERT(xorNode->numSuccedents == 1);
	RF_ASSERT(commitNode->numAntecedents == 1);
	xorNode->succedents[0] = commitNode;
	commitNode->antecedents[0] = xorNode;
	commitNode->antType[0] = rf_control;

	/* connect the termNode to the commit node */
	RF_ASSERT(commitNode->numSuccedents == 1);
	RF_ASSERT(termNode->numAntecedents == 1);
	RF_ASSERT(termNode->numSuccedents == 0);
	commitNode->succedents[0] = termNode;
	termNode->antType[0] = rf_control;
	termNode->antecedents[0] = commitNode;
}