root/dev/raidframe/rf_dagffwr.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. rf_CreateNonRedundantWriteDAG
  2. rf_CreateRAID0WriteDAG
  3. rf_CreateSmallWriteDAG
  4. rf_CreateLargeWriteDAG
  5. rf_CommonCreateLargeWriteDAG
  6. rf_CommonCreateSmallWriteDAG
  7. rf_CreateRaidOneWriteDAG
  8. rf_CommonCreateLargeWriteDAGFwd
  9. rf_CommonCreateSmallWriteDAGFwd
  10. rf_CreateRaidOneWriteDAGFwd

    1 /*      $OpenBSD: rf_dagffwr.c,v 1.5 2002/12/16 07:01:03 tdeval Exp $   */
    2 /*      $NetBSD: rf_dagffwr.c,v 1.5 2000/01/07 03:40:58 oster Exp $     */
    3 
    4 /*
    5  * Copyright (c) 1995 Carnegie-Mellon University.
    6  * All rights reserved.
    7  *
    8  * Author: Mark Holland, Daniel Stodolsky, William V. Courtright II
    9  *
   10  * Permission to use, copy, modify and distribute this software and
   11  * its documentation is hereby granted, provided that both the copyright
   12  * notice and this permission notice appear in all copies of the
   13  * software, derivative works or modified versions, and any portions
   14  * thereof, and that both notices appear in supporting documentation.
   15  *
   16  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
   17  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
   18  * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
   19  *
   20  * Carnegie Mellon requests users of this software to return to
   21  *
   22  *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
   23  *  School of Computer Science
   24  *  Carnegie Mellon University
   25  *  Pittsburgh PA 15213-3890
   26  *
   27  * any improvements or extensions that they make and grant Carnegie the
   28  * rights to redistribute these changes.
   29  */
   30 
   31 /*
   32  * rf_dagff.c
   33  *
   34  * Code for creating fault-free DAGs.
   35  *
   36  */
   37 
   38 #include "rf_types.h"
   39 #include "rf_raid.h"
   40 #include "rf_dag.h"
   41 #include "rf_dagutils.h"
   42 #include "rf_dagfuncs.h"
   43 #include "rf_debugMem.h"
   44 #include "rf_dagffrd.h"
   45 #include "rf_memchunk.h"
   46 #include "rf_general.h"
   47 #include "rf_dagffwr.h"
   48 
   49 /*****************************************************************************
   50  *
   51  * General comments on DAG creation:
   52  *
   53  * All DAGs in this file use roll-away error recovery. Each DAG has a single
   54  * commit node, usually called "Cmt."  If an error occurs before the Cmt node
   55  * is reached, the execution engine will halt forward execution and work
   56  * backward through the graph, executing the undo functions. Assuming that
   57  * each node in the graph prior to the Cmt node are undoable and atomic - or -
   58  * does not make changes to permanent state, the graph will fail atomically.
   59  * If an error occurs after the Cmt node executes, the engine will roll-forward
   60  * through the graph, blindly executing nodes until it reaches the end.
   61  * If a graph reaches the end, it is assumed to have completed successfully.
   62  *
   63  * A graph has only 1 Cmt node.
   64  *
   65  *****************************************************************************/
   66 
   67 
   68 /*****************************************************************************
   69  *
   70  * The following wrappers map the standard DAG creation interface to the
   71  * DAG creation routines. Additionally, these wrappers enable experimentation
   72  * with new DAG structures by providing an extra level of indirection, allowing
   73  * the DAG creation routines to be replaced at this single point.
   74  *
   75  *****************************************************************************/
   76 
   77 
   78 void
   79 rf_CreateNonRedundantWriteDAG(RF_Raid_t *raidPtr, RF_AccessStripeMap_t *asmap,
   80     RF_DagHeader_t *dag_h, void *bp, RF_RaidAccessFlags_t flags,
   81     RF_AllocListElem_t *allocList, RF_IoType_t type)
   82 {
   83         rf_CreateNonredundantDAG(raidPtr, asmap, dag_h, bp, flags, allocList,
   84             RF_IO_TYPE_WRITE);
   85 }
   86 
   87 void
   88 rf_CreateRAID0WriteDAG(RF_Raid_t *raidPtr, RF_AccessStripeMap_t *asmap,
   89     RF_DagHeader_t *dag_h, void *bp, RF_RaidAccessFlags_t flags,
   90     RF_AllocListElem_t *allocList, RF_IoType_t type)
   91 {
   92         rf_CreateNonredundantDAG(raidPtr, asmap, dag_h, bp, flags, allocList,
   93             RF_IO_TYPE_WRITE);
   94 }
   95 
   96 void
   97 rf_CreateSmallWriteDAG(RF_Raid_t *raidPtr, RF_AccessStripeMap_t *asmap,
   98     RF_DagHeader_t *dag_h, void *bp, RF_RaidAccessFlags_t flags,
   99     RF_AllocListElem_t *allocList)
  100 {
  101         /* "normal" rollaway. */
  102         rf_CommonCreateSmallWriteDAG(raidPtr, asmap, dag_h, bp, flags,
  103             allocList, &rf_xorFuncs, NULL);
  104 }
  105 
  106 void
  107 rf_CreateLargeWriteDAG(RF_Raid_t *raidPtr, RF_AccessStripeMap_t *asmap,
  108     RF_DagHeader_t *dag_h, void *bp, RF_RaidAccessFlags_t flags,
  109     RF_AllocListElem_t *allocList)
  110 {
  111         /* "normal" rollaway. */
  112         rf_CommonCreateLargeWriteDAG(raidPtr, asmap, dag_h, bp, flags,
  113             allocList, 1, rf_RegularXorFunc, RF_TRUE);
  114 }
  115 
  116 
  117 /*****************************************************************************
  118  *
  119  * DAG creation code begins here.
  120  *
  121  *****************************************************************************/
  122 
  123 
  124 /*****************************************************************************
  125  *
  126  * creates a DAG to perform a large-write operation:
  127  *
  128  *           / Rod \           / Wnd \
  129  * H -- block- Rod - Xor - Cmt - Wnd --- T
  130  *           \ Rod /          \  Wnp /
  131  *                             \[Wnq]/
  132  *
  133  * The XOR node also does the Q calculation in the P+Q architecture.
  134  * All nodes that are before the commit node (Cmt) are assumed to be atomic
  135  * and undoable - or - they make no changes to permanent state.
  136  *
  137  * Rod = read old data
  138  * Cmt = commit node
  139  * Wnp = write new parity
  140  * Wnd = write new data
  141  * Wnq = write new "q"
  142  * [] denotes optional segments in the graph.
  143  *
  144  * Parameters:  raidPtr   - description of the physical array
  145  *              asmap     - logical & physical addresses for this access
  146  *              bp        - buffer ptr (holds write data)
  147  *              flags     - general flags (e.g. disk locking)
  148  *              allocList - list of memory allocated in DAG creation
  149  *              nfaults   - number of faults array can tolerate
  150  *                          (equal to # redundancy units in stripe)
  151  *              redfuncs  - list of redundancy generating functions
  152  *
  153  *****************************************************************************/
  154 
  155 void
  156 rf_CommonCreateLargeWriteDAG(RF_Raid_t *raidPtr, RF_AccessStripeMap_t *asmap,
  157     RF_DagHeader_t *dag_h, void *bp, RF_RaidAccessFlags_t flags,
  158     RF_AllocListElem_t *allocList, int nfaults, int (*redFunc) (RF_DagNode_t *),
  159     int allowBufferRecycle)
  160 {
  161         RF_DagNode_t *nodes, *wndNodes, *rodNodes, *xorNode, *wnpNode;
  162         RF_DagNode_t *wnqNode, *blockNode, *commitNode, *termNode;
  163         int nWndNodes, nRodNodes, i, nodeNum, asmNum;
  164         RF_AccessStripeMapHeader_t *new_asm_h[2];
  165         RF_StripeNum_t parityStripeID;
  166         char *sosBuffer, *eosBuffer;
  167         RF_ReconUnitNum_t which_ru;
  168         RF_RaidLayout_t *layoutPtr;
  169         RF_PhysDiskAddr_t *pda;
  170 
  171         layoutPtr = &(raidPtr->Layout);
  172         parityStripeID = rf_RaidAddressToParityStripeID(layoutPtr,
  173             asmap->raidAddress, &which_ru);
  174 
  175         if (rf_dagDebug) {
  176                 printf("[Creating large-write DAG]\n");
  177         }
  178         dag_h->creator = "LargeWriteDAG";
  179 
  180         dag_h->numCommitNodes = 1;
  181         dag_h->numCommits = 0;
  182         dag_h->numSuccedents = 1;
  183 
  184         /* Alloc the nodes: Wnd, xor, commit, block, term, and  Wnp. */
  185         nWndNodes = asmap->numStripeUnitsAccessed;
  186         RF_CallocAndAdd(nodes, nWndNodes + 4 + nfaults, sizeof(RF_DagNode_t),
  187             (RF_DagNode_t *), allocList);
  188         i = 0;
  189         wndNodes = &nodes[i];
  190         i += nWndNodes;
  191         xorNode = &nodes[i];
  192         i += 1;
  193         wnpNode = &nodes[i];
  194         i += 1;
  195         blockNode = &nodes[i];
  196         i += 1;
  197         commitNode = &nodes[i];
  198         i += 1;
  199         termNode = &nodes[i];
  200         i += 1;
  201         if (nfaults == 2) {
  202                 wnqNode = &nodes[i];
  203                 i += 1;
  204         } else {
  205                 wnqNode = NULL;
  206         }
  207         rf_MapUnaccessedPortionOfStripe(raidPtr, layoutPtr, asmap, dag_h,
  208             new_asm_h, &nRodNodes, &sosBuffer, &eosBuffer, allocList);
  209         if (nRodNodes > 0) {
  210                 RF_CallocAndAdd(rodNodes, nRodNodes, sizeof(RF_DagNode_t),
  211                     (RF_DagNode_t *), allocList);
  212         } else {
  213                 rodNodes = NULL;
  214         }
  215 
  216         /* Begin node initialization. */
  217         if (nRodNodes > 0) {
  218                 rf_InitNode(blockNode, rf_wait, RF_FALSE, rf_NullNodeFunc,
  219                     rf_NullNodeUndoFunc, NULL, nRodNodes, 0, 0, 0, dag_h,
  220                     "Nil", allocList);
  221         } else {
  222                 rf_InitNode(blockNode, rf_wait, RF_FALSE, rf_NullNodeFunc,
  223                     rf_NullNodeUndoFunc, NULL, 1, 0, 0, 0, dag_h, "Nil",
  224                     allocList);
  225         }
  226 
  227         rf_InitNode(commitNode, rf_wait, RF_TRUE, rf_NullNodeFunc,
  228             rf_NullNodeUndoFunc, NULL, nWndNodes + nfaults, 1, 0, 0,
  229             dag_h, "Cmt", allocList);
  230         rf_InitNode(termNode, rf_wait, RF_FALSE, rf_TerminateFunc,
  231             rf_TerminateUndoFunc, NULL, 0, nWndNodes + nfaults, 0, 0,
  232             dag_h, "Trm", allocList);
  233 
  234         /* Initialize the Rod nodes. */
  235         for (nodeNum = asmNum = 0; asmNum < 2; asmNum++) {
  236                 if (new_asm_h[asmNum]) {
  237                         pda = new_asm_h[asmNum]->stripeMap->physInfo;
  238                         while (pda) {
  239                                 rf_InitNode(&rodNodes[nodeNum], rf_wait,
  240                                     RF_FALSE, rf_DiskReadFunc,
  241                                     rf_DiskReadUndoFunc, rf_GenericWakeupFunc,
  242                                     1, 1, 4, 0, dag_h, "Rod", allocList);
  243                                 rodNodes[nodeNum].params[0].p = pda;
  244                                 rodNodes[nodeNum].params[1].p = pda->bufPtr;
  245                                 rodNodes[nodeNum].params[2].v = parityStripeID;
  246                                 rodNodes[nodeNum].params[3].v =
  247                                     RF_CREATE_PARAM3(RF_IO_NORMAL_PRIORITY,
  248                                     0, 0, which_ru);
  249                                 nodeNum++;
  250                                 pda = pda->next;
  251                         }
  252                 }
  253         }
  254         RF_ASSERT(nodeNum == nRodNodes);
  255 
  256         /* Initialize the wnd nodes. */
  257         pda = asmap->physInfo;
  258         for (i = 0; i < nWndNodes; i++) {
  259                 rf_InitNode(&wndNodes[i], rf_wait, RF_FALSE, rf_DiskWriteFunc,
  260                     rf_DiskWriteUndoFunc, rf_GenericWakeupFunc, 1, 1, 4, 0,
  261                     dag_h, "Wnd", allocList);
  262                 RF_ASSERT(pda != NULL);
  263                 wndNodes[i].params[0].p = pda;
  264                 wndNodes[i].params[1].p = pda->bufPtr;
  265                 wndNodes[i].params[2].v = parityStripeID;
  266                 wndNodes[i].params[3].v =
  267                     RF_CREATE_PARAM3(RF_IO_NORMAL_PRIORITY, 0, 0, which_ru);
  268                 pda = pda->next;
  269         }
  270 
  271         /* Initialize the redundancy node. */
  272         if (nRodNodes > 0) {
  273                 rf_InitNode(xorNode, rf_wait, RF_FALSE, redFunc,
  274                     rf_NullNodeUndoFunc, NULL, 1, nRodNodes,
  275                     2 * (nWndNodes + nRodNodes) + 1, nfaults, dag_h,
  276                     "Xr ", allocList);
  277         } else {
  278                 rf_InitNode(xorNode, rf_wait, RF_FALSE, redFunc,
  279                     rf_NullNodeUndoFunc, NULL, 1, 1,
  280                     2 * (nWndNodes + nRodNodes) + 1, nfaults, dag_h,
  281                     "Xr ", allocList);
  282         }
  283         xorNode->flags |= RF_DAGNODE_FLAG_YIELD;
  284         for (i = 0; i < nWndNodes; i++) {
  285                 xorNode->params[2 * i + 0] =
  286                     wndNodes[i].params[0];      /* pda */
  287                 xorNode->params[2 * i + 1] =
  288                     wndNodes[i].params[1];      /* buf ptr */
  289         }
  290         for (i = 0; i < nRodNodes; i++) {
  291                 xorNode->params[2 * (nWndNodes + i) + 0] =
  292                     rodNodes[i].params[0];      /* pda */
  293                 xorNode->params[2 * (nWndNodes + i) + 1] =
  294                     rodNodes[i].params[1];      /* buf ptr */
  295         }
  296         /* Xor node needs to get at RAID information. */
  297         xorNode->params[2 * (nWndNodes + nRodNodes)].p = raidPtr;
  298 
  299         /*
  300          * Look for an Rod node that reads a complete SU. If none, alloc
  301          * a buffer to receive the parity info. Note that we can't use a
  302          * new data buffer because it will not have gotten written when
  303          * the xor occurs.
  304          */
  305         if (allowBufferRecycle) {
  306                 for (i = 0; i < nRodNodes; i++) {
  307                         if (((RF_PhysDiskAddr_t *) rodNodes[i].params[0].p)
  308                             ->numSector == raidPtr->Layout.sectorsPerStripeUnit)
  309                                 break;
  310                 }
  311         }
  312         if ((!allowBufferRecycle) || (i == nRodNodes)) {
  313                 RF_CallocAndAdd(xorNode->results[0], 1,
  314                     rf_RaidAddressToByte(raidPtr,
  315                     raidPtr->Layout.sectorsPerStripeUnit),
  316                     (void *), allocList);
  317         } else {
  318                 xorNode->results[0] = rodNodes[i].params[1].p;
  319         }
  320 
  321         /* Initialize the Wnp node. */
  322         rf_InitNode(wnpNode, rf_wait, RF_FALSE, rf_DiskWriteFunc,
  323             rf_DiskWriteUndoFunc, rf_GenericWakeupFunc, 1, 1, 4, 0,
  324             dag_h, "Wnp", allocList);
  325         wnpNode->params[0].p = asmap->parityInfo;
  326         wnpNode->params[1].p = xorNode->results[0];
  327         wnpNode->params[2].v = parityStripeID;
  328         wnpNode->params[3].v =
  329             RF_CREATE_PARAM3(RF_IO_NORMAL_PRIORITY, 0, 0, which_ru);
  330         /* parityInfo must describe entire parity unit. */
  331         RF_ASSERT(asmap->parityInfo->next == NULL);
  332 
  333         if (nfaults == 2) {
  334                 /*
  335                  * We never try to recycle a buffer for the Q calculation
  336                  * in addition to the parity. This would cause two buffers
  337                  * to get smashed during the P and Q calculation, guaranteeing
  338                  * one would be wrong.
  339                  */
  340                 RF_CallocAndAdd(xorNode->results[1], 1,
  341                     rf_RaidAddressToByte(raidPtr,
  342                      raidPtr->Layout.sectorsPerStripeUnit),
  343                     (void *), allocList);
  344                 rf_InitNode(wnqNode, rf_wait, RF_FALSE, rf_DiskWriteFunc,
  345                     rf_DiskWriteUndoFunc, rf_GenericWakeupFunc, 1, 1, 4, 0,
  346                     dag_h, "Wnq", allocList);
  347                 wnqNode->params[0].p = asmap->qInfo;
  348                 wnqNode->params[1].p = xorNode->results[1];
  349                 wnqNode->params[2].v = parityStripeID;
  350                 wnqNode->params[3].v =
  351                     RF_CREATE_PARAM3(RF_IO_NORMAL_PRIORITY, 0, 0, which_ru);
  352                 /* parityInfo must describe entire parity unit. */
  353                 RF_ASSERT(asmap->parityInfo->next == NULL);
  354         }
  355         /*
  356          * Connect nodes to form graph.
  357          */
  358 
  359         /* Connect dag header to block node. */
  360         RF_ASSERT(blockNode->numAntecedents == 0);
  361         dag_h->succedents[0] = blockNode;
  362 
  363         if (nRodNodes > 0) {
  364                 /* Connect the block node to the Rod nodes. */
  365                 RF_ASSERT(blockNode->numSuccedents == nRodNodes);
  366                 RF_ASSERT(xorNode->numAntecedents == nRodNodes);
  367                 for (i = 0; i < nRodNodes; i++) {
  368                         RF_ASSERT(rodNodes[i].numAntecedents == 1);
  369                         blockNode->succedents[i] = &rodNodes[i];
  370                         rodNodes[i].antecedents[0] = blockNode;
  371                         rodNodes[i].antType[0] = rf_control;
  372 
  373                         /* Connect the Rod nodes to the Xor node. */
  374                         RF_ASSERT(rodNodes[i].numSuccedents == 1);
  375                         rodNodes[i].succedents[0] = xorNode;
  376                         xorNode->antecedents[i] = &rodNodes[i];
  377                         xorNode->antType[i] = rf_trueData;
  378                 }
  379         } else {
  380                 /* Connect the block node to the Xor node. */
  381                 RF_ASSERT(blockNode->numSuccedents == 1);
  382                 RF_ASSERT(xorNode->numAntecedents == 1);
  383                 blockNode->succedents[0] = xorNode;
  384                 xorNode->antecedents[0] = blockNode;
  385                 xorNode->antType[0] = rf_control;
  386         }
  387 
  388         /* Connect the xor node to the commit node. */
  389         RF_ASSERT(xorNode->numSuccedents == 1);
  390         RF_ASSERT(commitNode->numAntecedents == 1);
  391         xorNode->succedents[0] = commitNode;
  392         commitNode->antecedents[0] = xorNode;
  393         commitNode->antType[0] = rf_control;
  394 
  395         /* Connect the commit node to the write nodes. */
  396         RF_ASSERT(commitNode->numSuccedents == nWndNodes + nfaults);
  397         for (i = 0; i < nWndNodes; i++) {
  398                 RF_ASSERT(wndNodes->numAntecedents == 1);
  399                 commitNode->succedents[i] = &wndNodes[i];
  400                 wndNodes[i].antecedents[0] = commitNode;
  401                 wndNodes[i].antType[0] = rf_control;
  402         }
  403         RF_ASSERT(wnpNode->numAntecedents == 1);
  404         commitNode->succedents[nWndNodes] = wnpNode;
  405         wnpNode->antecedents[0] = commitNode;
  406         wnpNode->antType[0] = rf_trueData;
  407         if (nfaults == 2) {
  408                 RF_ASSERT(wnqNode->numAntecedents == 1);
  409                 commitNode->succedents[nWndNodes + 1] = wnqNode;
  410                 wnqNode->antecedents[0] = commitNode;
  411                 wnqNode->antType[0] = rf_trueData;
  412         }
  413         /* Connect the write nodes to the term node. */
  414         RF_ASSERT(termNode->numAntecedents == nWndNodes + nfaults);
  415         RF_ASSERT(termNode->numSuccedents == 0);
  416         for (i = 0; i < nWndNodes; i++) {
  417                 RF_ASSERT(wndNodes->numSuccedents == 1);
  418                 wndNodes[i].succedents[0] = termNode;
  419                 termNode->antecedents[i] = &wndNodes[i];
  420                 termNode->antType[i] = rf_control;
  421         }
  422         RF_ASSERT(wnpNode->numSuccedents == 1);
  423         wnpNode->succedents[0] = termNode;
  424         termNode->antecedents[nWndNodes] = wnpNode;
  425         termNode->antType[nWndNodes] = rf_control;
  426         if (nfaults == 2) {
  427                 RF_ASSERT(wnqNode->numSuccedents == 1);
  428                 wnqNode->succedents[0] = termNode;
  429                 termNode->antecedents[nWndNodes + 1] = wnqNode;
  430                 termNode->antType[nWndNodes + 1] = rf_control;
  431         }
  432 }
  433 /*****************************************************************************
  434  *
  435  * Create a DAG to perform a small-write operation (either raid 5 or pq),
  436  * which is as follows:
  437  *
  438  * Hdr -> Nil -> Rop -> Xor -> Cmt ----> Wnp [Unp] --> Trm
  439  *            \- Rod X      /     \----> Wnd [Und]-/
  440  *           [\- Rod X     /       \---> Wnd [Und]-/]
  441  *           [\- Roq -> Q /         \--> Wnq [Unq]-/]
  442  *
  443  * Rop = read old parity
  444  * Rod = read old data
  445  * Roq = read old "q"
  446  * Cmt = commit node
  447  * Und = unlock data disk
  448  * Unp = unlock parity disk
  449  * Unq = unlock q disk
  450  * Wnp = write new parity
  451  * Wnd = write new data
  452  * Wnq = write new "q"
  453  * [ ] denotes optional segments in the graph.
  454  *
  455  * Parameters:  raidPtr   - description of the physical array
  456  *              asmap     - logical & physical addresses for this access
  457  *              bp        - buffer ptr (holds write data)
  458  *              flags     - general flags (e.g. disk locking)
  459  *              allocList - list of memory allocated in DAG creation
  460  *              pfuncs    - list of parity generating functions
  461  *              qfuncs    - list of q generating functions
  462  *
  463  * A null qfuncs indicates single fault tolerant.
  464  *****************************************************************************/
  465 
  466 void
  467 rf_CommonCreateSmallWriteDAG(RF_Raid_t *raidPtr, RF_AccessStripeMap_t *asmap,
  468     RF_DagHeader_t *dag_h, void *bp, RF_RaidAccessFlags_t flags,
  469     RF_AllocListElem_t *allocList, RF_RedFuncs_t *pfuncs, RF_RedFuncs_t *qfuncs)
  470 {
  471         RF_DagNode_t *readDataNodes, *readParityNodes, *readQNodes, *termNode;
  472         RF_DagNode_t *unlockDataNodes, *unlockParityNodes, *unlockQNodes;
  473         RF_DagNode_t *xorNodes, *qNodes, *blockNode, *commitNode, *nodes;
  474         RF_DagNode_t *writeDataNodes, *writeParityNodes, *writeQNodes;
  475         int i, j, nNodes, totalNumNodes, lu_flag;
  476         RF_ReconUnitNum_t which_ru;
  477         int (*func) (RF_DagNode_t *);
  478         int (*undoFunc) (RF_DagNode_t *);
  479         int (*qfunc) (RF_DagNode_t *);
  480         int numDataNodes, numParityNodes;
  481         RF_StripeNum_t parityStripeID;
  482         RF_PhysDiskAddr_t *pda;
  483         char *name, *qname;
  484         long nfaults;
  485 
  486         nfaults = qfuncs ? 2 : 1;
  487         lu_flag = (rf_enableAtomicRMW) ? 1 : 0; /* Lock/unlock flag. */
  488 
  489         parityStripeID = rf_RaidAddressToParityStripeID(&(raidPtr->Layout),
  490             asmap->raidAddress, &which_ru);
  491         pda = asmap->physInfo;
  492         numDataNodes = asmap->numStripeUnitsAccessed;
  493         numParityNodes = (asmap->parityInfo->next) ? 2 : 1;
  494 
  495         if (rf_dagDebug) {
  496                 printf("[Creating small-write DAG]\n");
  497         }
  498         RF_ASSERT(numDataNodes > 0);
  499         dag_h->creator = "SmallWriteDAG";
  500 
  501         dag_h->numCommitNodes = 1;
  502         dag_h->numCommits = 0;
  503         dag_h->numSuccedents = 1;
  504 
  505         /*
  506          * DAG creation occurs in four steps:
  507          * 1. Count the number of nodes in the DAG.
  508          * 2. Create the nodes.
  509          * 3. Initialize the nodes.
  510          * 4. Connect the nodes.
  511          */
  512 
  513         /*
  514          * Step 1. Compute number of nodes in the graph.
  515          */
  516 
  517         /*
  518          * Number of nodes: a read and write for each data unit, a redundancy
  519          * computation node for each parity node (nfaults * nparity), a read
  520          * and write for each parity unit, a block and commit node (2), a
  521          * terminate node if atomic RMW, an unlock node for each
  522          * data/redundancy unit.
  523          */
  524         totalNumNodes = (2 * numDataNodes) + (nfaults * numParityNodes)
  525             + (nfaults * 2 * numParityNodes) + 3;
  526         if (lu_flag) {
  527                 totalNumNodes += (numDataNodes + (nfaults * numParityNodes));
  528         }
  529         /*
  530          * Step 2. Create the nodes.
  531          */
  532         RF_CallocAndAdd(nodes, totalNumNodes, sizeof(RF_DagNode_t),
  533             (RF_DagNode_t *), allocList);
  534         i = 0;
  535         blockNode = &nodes[i];
  536         i += 1;
  537         commitNode = &nodes[i];
  538         i += 1;
  539         readDataNodes = &nodes[i];
  540         i += numDataNodes;
  541         readParityNodes = &nodes[i];
  542         i += numParityNodes;
  543         writeDataNodes = &nodes[i];
  544         i += numDataNodes;
  545         writeParityNodes = &nodes[i];
  546         i += numParityNodes;
  547         xorNodes = &nodes[i];
  548         i += numParityNodes;
  549         termNode = &nodes[i];
  550         i += 1;
  551         if (lu_flag) {
  552                 unlockDataNodes = &nodes[i];
  553                 i += numDataNodes;
  554                 unlockParityNodes = &nodes[i];
  555                 i += numParityNodes;
  556         } else {
  557                 unlockDataNodes = unlockParityNodes = NULL;
  558         }
  559         if (nfaults == 2) {
  560                 readQNodes = &nodes[i];
  561                 i += numParityNodes;
  562                 writeQNodes = &nodes[i];
  563                 i += numParityNodes;
  564                 qNodes = &nodes[i];
  565                 i += numParityNodes;
  566                 if (lu_flag) {
  567                         unlockQNodes = &nodes[i];
  568                         i += numParityNodes;
  569                 } else {
  570                         unlockQNodes = NULL;
  571                 }
  572         } else {
  573                 readQNodes = writeQNodes = qNodes = unlockQNodes = NULL;
  574         }
  575         RF_ASSERT(i == totalNumNodes);
  576 
  577         /*
  578          * Step 3. Initialize the nodes.
  579          */
  580         /* Initialize block node (Nil). */
  581         nNodes = numDataNodes + (nfaults * numParityNodes);
  582         rf_InitNode(blockNode, rf_wait, RF_FALSE, rf_NullNodeFunc,
  583             rf_NullNodeUndoFunc, NULL, nNodes, 0, 0, 0, dag_h,
  584             "Nil", allocList);
  585 
  586         /* Initialize commit node (Cmt). */
  587         rf_InitNode(commitNode, rf_wait, RF_TRUE, rf_NullNodeFunc,
  588             rf_NullNodeUndoFunc, NULL, nNodes, (nfaults * numParityNodes),
  589             0, 0, dag_h, "Cmt", allocList);
  590 
  591         /* Initialize terminate node (Trm). */
  592         rf_InitNode(termNode, rf_wait, RF_FALSE, rf_TerminateFunc,
  593             rf_TerminateUndoFunc, NULL, 0, nNodes, 0, 0, dag_h,
  594             "Trm", allocList);
  595 
  596         /* Initialize nodes which read old data (Rod). */
  597         for (i = 0; i < numDataNodes; i++) {
  598                 rf_InitNode(&readDataNodes[i], rf_wait, RF_FALSE,
  599                     rf_DiskReadFunc, rf_DiskReadUndoFunc, rf_GenericWakeupFunc,
  600                     (nfaults * numParityNodes), 1, 4, 0, dag_h, "Rod",
  601                     allocList);
  602                 RF_ASSERT(pda != NULL);
  603                 /* Physical disk addr desc. */
  604                 readDataNodes[i].params[0].p = pda;
  605                 /* Buffer to hold old data. */
  606                 readDataNodes[i].params[1].p = rf_AllocBuffer(raidPtr,
  607                     dag_h, pda, allocList);
  608                 readDataNodes[i].params[2].v = parityStripeID;
  609                 readDataNodes[i].params[3].v =
  610                     RF_CREATE_PARAM3(RF_IO_NORMAL_PRIORITY,
  611                     lu_flag, 0, which_ru);
  612                 pda = pda->next;
  613                 for (j = 0; j < readDataNodes[i].numSuccedents; j++) {
  614                         readDataNodes[i].propList[j] = NULL;
  615                 }
  616         }
  617 
  618         /* Initialize nodes which read old parity (Rop). */
  619         pda = asmap->parityInfo;
  620         i = 0;
  621         for (i = 0; i < numParityNodes; i++) {
  622                 RF_ASSERT(pda != NULL);
  623                 rf_InitNode(&readParityNodes[i], rf_wait, RF_FALSE,
  624                     rf_DiskReadFunc, rf_DiskReadUndoFunc, rf_GenericWakeupFunc,
  625                     numParityNodes, 1, 4, 0, dag_h, "Rop", allocList);
  626                 readParityNodes[i].params[0].p = pda;
  627                 /* Buffer to hold old parity. */
  628                 readParityNodes[i].params[1].p = rf_AllocBuffer(raidPtr,
  629                     dag_h, pda, allocList);
  630                 readParityNodes[i].params[2].v = parityStripeID;
  631                 readParityNodes[i].params[3].v =
  632                     RF_CREATE_PARAM3(RF_IO_NORMAL_PRIORITY,
  633                     lu_flag, 0, which_ru);
  634                 pda = pda->next;
  635                 for (j = 0; j < readParityNodes[i].numSuccedents; j++) {
  636                         readParityNodes[i].propList[0] = NULL;
  637                 }
  638         }
  639 
  640         /* Initialize nodes which read old Q (Roq). */
  641         if (nfaults == 2) {
  642                 pda = asmap->qInfo;
  643                 for (i = 0; i < numParityNodes; i++) {
  644                         RF_ASSERT(pda != NULL);
  645                         rf_InitNode(&readQNodes[i], rf_wait, RF_FALSE,
  646                             rf_DiskReadFunc, rf_DiskReadUndoFunc,
  647                             rf_GenericWakeupFunc, numParityNodes,
  648                             1, 4, 0, dag_h, "Roq", allocList);
  649                         readQNodes[i].params[0].p = pda;
  650                         /* Buffer to hold old Q. */
  651                         readQNodes[i].params[1].p = rf_AllocBuffer(raidPtr,
  652                             dag_h, pda, allocList);
  653                         readQNodes[i].params[2].v = parityStripeID;
  654                         readQNodes[i].params[3].v =
  655                             RF_CREATE_PARAM3(RF_IO_NORMAL_PRIORITY,
  656                             lu_flag, 0, which_ru);
  657                         pda = pda->next;
  658                         for (j = 0; j < readQNodes[i].numSuccedents; j++) {
  659                                 readQNodes[i].propList[0] = NULL;
  660                         }
  661                 }
  662         }
  663         /* Initialize nodes which write new data (Wnd). */
  664         pda = asmap->physInfo;
  665         for (i = 0; i < numDataNodes; i++) {
  666                 RF_ASSERT(pda != NULL);
  667                 rf_InitNode(&writeDataNodes[i], rf_wait, RF_FALSE,
  668                     rf_DiskWriteFunc, rf_DiskWriteUndoFunc,
  669                     rf_GenericWakeupFunc, 1, 1, 4, 0, dag_h,
  670                     "Wnd", allocList);
  671                 /* Physical disk addr desc. */
  672                 writeDataNodes[i].params[0].p = pda;
  673                 /* Buffer holding new data to be written. */
  674                 writeDataNodes[i].params[1].p = pda->bufPtr;
  675                 writeDataNodes[i].params[2].v = parityStripeID;
  676                 writeDataNodes[i].params[3].v =
  677                     RF_CREATE_PARAM3(RF_IO_NORMAL_PRIORITY, 0, 0, which_ru);
  678                 if (lu_flag) {
  679                         /* Initialize node to unlock the disk queue. */
  680                         rf_InitNode(&unlockDataNodes[i], rf_wait, RF_FALSE,
  681                             rf_DiskUnlockFunc, rf_DiskUnlockUndoFunc,
  682                             rf_GenericWakeupFunc, 1, 1, 2, 0, dag_h,
  683                             "Und", allocList);
  684                         /* Physical disk addr desc. */
  685                         unlockDataNodes[i].params[0].p = pda;
  686                         unlockDataNodes[i].params[1].v =
  687                             RF_CREATE_PARAM3(RF_IO_NORMAL_PRIORITY,
  688                             0, lu_flag, which_ru);
  689                 }
  690                 pda = pda->next;
  691         }
  692 
  693         /*
  694          * Initialize nodes which compute new parity and Q.
  695          */
  696         /*
  697          * We use the simple XOR func in the double-XOR case, and when
  698          * we're accessing only a portion of one stripe unit.
  699          * The distinction between the two is that the regular XOR func
  700          * assumes that the targbuf is a full SU in size, and examines
  701          * the pda associated with the buffer to decide where within
  702          * the buffer to XOR the data, whereas the simple XOR func just
  703          * XORs the data into the start of the buffer.
  704          */
  705         if ((numParityNodes == 2) || ((numDataNodes == 1) &&
  706             (asmap->totalSectorsAccessed <
  707              raidPtr->Layout.sectorsPerStripeUnit))) {
  708                 func = pfuncs->simple;
  709                 undoFunc = rf_NullNodeUndoFunc;
  710                 name = pfuncs->SimpleName;
  711                 if (qfuncs) {
  712                         qfunc = qfuncs->simple;
  713                         qname = qfuncs->SimpleName;
  714                 } else {
  715                         qfunc = NULL;
  716                         qname = NULL;
  717                 }
  718         } else {
  719                 func = pfuncs->regular;
  720                 undoFunc = rf_NullNodeUndoFunc;
  721                 name = pfuncs->RegularName;
  722                 if (qfuncs) {
  723                         qfunc = qfuncs->regular;
  724                         qname = qfuncs->RegularName;
  725                 } else {
  726                         qfunc = NULL;
  727                         qname = NULL;
  728                 }
  729         }
  730         /*
  731          * Initialize the xor nodes: params are {pda,buf}.
  732          * From {Rod,Wnd,Rop} nodes, and raidPtr.
  733          */
  734         if (numParityNodes == 2) {
  735                 /* Double-xor case. */
  736                 for (i = 0; i < numParityNodes; i++) {
  737                         /* Note: no wakeup func for xor. */
  738                         rf_InitNode(&xorNodes[i], rf_wait, RF_FALSE, func,
  739                             undoFunc, NULL, 1, (numDataNodes + numParityNodes),
  740                             7, 1, dag_h, name, allocList);
  741                         xorNodes[i].flags |= RF_DAGNODE_FLAG_YIELD;
  742                         xorNodes[i].params[0] = readDataNodes[i].params[0];
  743                         xorNodes[i].params[1] = readDataNodes[i].params[1];
  744                         xorNodes[i].params[2] = readParityNodes[i].params[0];
  745                         xorNodes[i].params[3] = readParityNodes[i].params[1];
  746                         xorNodes[i].params[4] = writeDataNodes[i].params[0];
  747                         xorNodes[i].params[5] = writeDataNodes[i].params[1];
  748                         xorNodes[i].params[6].p = raidPtr;
  749                         /* Use old parity buf as target buf. */
  750                         xorNodes[i].results[0] = readParityNodes[i].params[1].p;
  751                         if (nfaults == 2) {
  752                                 /* Note: no wakeup func for qor. */
  753                                 rf_InitNode(&qNodes[i], rf_wait, RF_FALSE,
  754                                     qfunc, undoFunc, NULL, 1,
  755                                     (numDataNodes + numParityNodes), 7, 1,
  756                                     dag_h, qname, allocList);
  757                                 qNodes[i].params[0] =
  758                                     readDataNodes[i].params[0];
  759                                 qNodes[i].params[1] =
  760                                     readDataNodes[i].params[1];
  761                                 qNodes[i].params[2] = readQNodes[i].params[0];
  762                                 qNodes[i].params[3] = readQNodes[i].params[1];
  763                                 qNodes[i].params[4] =
  764                                     writeDataNodes[i].params[0];
  765                                 qNodes[i].params[5] =
  766                                     writeDataNodes[i].params[1];
  767                                 qNodes[i].params[6].p = raidPtr;
  768                                 /* Use old Q buf as target buf. */
  769                                 qNodes[i].results[0] =
  770                                     readQNodes[i].params[1].p;
  771                         }
  772                 }
  773         } else {
  774                 /* There is only one xor node in this case. */
  775                 rf_InitNode(&xorNodes[0], rf_wait, RF_FALSE, func, undoFunc,
  776                     NULL, 1, (numDataNodes + numParityNodes),
  777                     (2 * (numDataNodes + numDataNodes + 1) + 1), 1,
  778                     dag_h, name, allocList);
  779                 xorNodes[0].flags |= RF_DAGNODE_FLAG_YIELD;
  780                 for (i = 0; i < numDataNodes + 1; i++) {
  781                         /* Set up params related to Rod and Rop nodes. */
  782                         xorNodes[0].params[2 * i + 0] =
  783                             readDataNodes[i].params[0]; /* pda */
  784                         xorNodes[0].params[2 * i + 1] =
  785                             readDataNodes[i].params[1]; /* buffer ptr */
  786                 }
  787                 for (i = 0; i < numDataNodes; i++) {
  788                         /* Set up params related to Wnd and Wnp nodes. */
  789                         xorNodes[0].params[2 * (numDataNodes + 1 + i) + 0] =
  790                             writeDataNodes[i].params[0];        /* pda */
  791                         xorNodes[0].params[2 * (numDataNodes + 1 + i) + 1] =
  792                             writeDataNodes[i].params[1];        /* buffer ptr */
  793                 }
  794                 /* Xor node needs to get at RAID information. */
  795                 xorNodes[0].params[2 * (numDataNodes + numDataNodes + 1)].p =
  796                     raidPtr;
  797                 xorNodes[0].results[0] = readParityNodes[0].params[1].p;
  798                 if (nfaults == 2) {
  799                         rf_InitNode(&qNodes[0], rf_wait, RF_FALSE, qfunc,
  800                             undoFunc, NULL, 1, (numDataNodes + numParityNodes),
  801                             (2 * (numDataNodes + numDataNodes + 1) + 1), 1,
  802                             dag_h, qname, allocList);
  803                         for (i = 0; i < numDataNodes; i++) {
  804                                 /* Set up params related to Rod. */
  805                                 qNodes[0].params[2 * i + 0] =
  806                                     readDataNodes[i].params[0]; /* pda */
  807                                 qNodes[0].params[2 * i + 1] =
  808                                     readDataNodes[i].params[1]; /* buffer ptr */
  809                         }
  810                         /* And read old q. */
  811                         qNodes[0].params[2 * numDataNodes + 0] =
  812                             readQNodes[0].params[0];    /* pda */
  813                         qNodes[0].params[2 * numDataNodes + 1] =
  814                             readQNodes[0].params[1];    /* buffer ptr */
  815                         for (i = 0; i < numDataNodes; i++) {
  816                                 /* Set up params related to Wnd nodes. */
  817                                 qNodes[0].params
  818                                     [2 * (numDataNodes + 1 + i) + 0] =
  819                                     /* pda */
  820                                     writeDataNodes[i].params[0];
  821                                 qNodes[0].params
  822                                     [2 * (numDataNodes + 1 + i) + 1] =
  823                                     /* buffer ptr */
  824                                     writeDataNodes[i].params[1];
  825                         }
  826                         /* Xor node needs to get at RAID information. */
  827                         qNodes[0].params
  828                             [2 * (numDataNodes + numDataNodes + 1)].p = raidPtr;
  829                         qNodes[0].results[0] = readQNodes[0].params[1].p;
  830                 }
  831         }
  832 
  833         /* Initialize nodes which write new parity (Wnp). */
  834         pda = asmap->parityInfo;
  835         for (i = 0; i < numParityNodes; i++) {
  836                 rf_InitNode(&writeParityNodes[i], rf_wait, RF_FALSE,
  837                     rf_DiskWriteFunc, rf_DiskWriteUndoFunc,
  838                     rf_GenericWakeupFunc, 1, 1, 4, 0, dag_h,
  839                     "Wnp", allocList);
  840                 RF_ASSERT(pda != NULL);
  841                 /* Param 1 (bufPtr) filled in by xor node. */
  842                 writeParityNodes[i].params[0].p = pda;
  843                 /* Buffer pointer for parity write operation. */
  844                 writeParityNodes[i].params[1].p = xorNodes[i].results[0];
  845                 writeParityNodes[i].params[2].v = parityStripeID;
  846                 writeParityNodes[i].params[3].v =
  847                     RF_CREATE_PARAM3(RF_IO_NORMAL_PRIORITY, 0, 0, which_ru);
  848                 if (lu_flag) {
  849                         /* Initialize node to unlock the disk queue. */
  850                         rf_InitNode(&unlockParityNodes[i], rf_wait, RF_FALSE,
  851                             rf_DiskUnlockFunc, rf_DiskUnlockUndoFunc,
  852                             rf_GenericWakeupFunc, 1, 1, 2, 0, dag_h,
  853                             "Unp", allocList);
  854                         /* Physical disk addr desc. */
  855                         unlockParityNodes[i].params[0].p = pda;
  856                         unlockParityNodes[i].params[1].v =
  857                             RF_CREATE_PARAM3(RF_IO_NORMAL_PRIORITY,
  858                             0, lu_flag, which_ru);
  859                 }
  860                 pda = pda->next;
  861         }
  862 
  863         /* Initialize nodes which write new Q (Wnq). */
  864         if (nfaults == 2) {
  865                 pda = asmap->qInfo;
  866                 for (i = 0; i < numParityNodes; i++) {
  867                         rf_InitNode(&writeQNodes[i], rf_wait, RF_FALSE,
  868                             rf_DiskWriteFunc, rf_DiskWriteUndoFunc,
  869                             rf_GenericWakeupFunc, 1, 1, 4, 0, dag_h,
  870                             "Wnq", allocList);
  871                         RF_ASSERT(pda != NULL);
  872                         /* Param 1 (bufPtr) filled in by xor node. */
  873                         writeQNodes[i].params[0].p = pda;
  874                         writeQNodes[i].params[1].p = qNodes[i].results[0];
  875                         /* Buffer pointer for parity write operation. */
  876                         writeQNodes[i].params[2].v = parityStripeID;
  877                         writeQNodes[i].params[3].v =
  878                             RF_CREATE_PARAM3(RF_IO_NORMAL_PRIORITY,
  879                             0, 0, which_ru);
  880                         if (lu_flag) {
  881                                 /* Initialize node to unlock the disk queue. */
  882                                 rf_InitNode(&unlockQNodes[i], rf_wait,
  883                                     RF_FALSE, rf_DiskUnlockFunc,
  884                                     rf_DiskUnlockUndoFunc,
  885                                     rf_GenericWakeupFunc, 1, 1, 2, 0,
  886                                     dag_h, "Unq", allocList);
  887                                 /* Physical disk addr desc. */
  888                                 unlockQNodes[i].params[0].p = pda;
  889                                 unlockQNodes[i].params[1].v =
  890                                     RF_CREATE_PARAM3(RF_IO_NORMAL_PRIORITY,
  891                                     0, lu_flag, which_ru);
  892                         }
  893                         pda = pda->next;
  894                 }
  895         }
  896         /*
  897          * Step 4. Connect the nodes.
  898          */
  899 
  900         /* Connect header to block node. */
  901         dag_h->succedents[0] = blockNode;
  902 
  903         /* Connect block node to read old data nodes. */
  904         RF_ASSERT(blockNode->numSuccedents ==
  905             (numDataNodes + (numParityNodes * nfaults)));
  906         for (i = 0; i < numDataNodes; i++) {
  907                 blockNode->succedents[i] = &readDataNodes[i];
  908                 RF_ASSERT(readDataNodes[i].numAntecedents == 1);
  909                 readDataNodes[i].antecedents[0] = blockNode;
  910                 readDataNodes[i].antType[0] = rf_control;
  911         }
  912 
  913         /* Connect block node to read old parity nodes. */
  914         for (i = 0; i < numParityNodes; i++) {
  915                 blockNode->succedents[numDataNodes + i] = &readParityNodes[i];
  916                 RF_ASSERT(readParityNodes[i].numAntecedents == 1);
  917                 readParityNodes[i].antecedents[0] = blockNode;
  918                 readParityNodes[i].antType[0] = rf_control;
  919         }
  920 
  921         /* Connect block node to read old Q nodes. */
  922         if (nfaults == 2) {
  923                 for (i = 0; i < numParityNodes; i++) {
  924                         blockNode->succedents[numDataNodes + numParityNodes + i]
  925                             = &readQNodes[i];
  926                         RF_ASSERT(readQNodes[i].numAntecedents == 1);
  927                         readQNodes[i].antecedents[0] = blockNode;
  928                         readQNodes[i].antType[0] = rf_control;
  929                 }
  930         }
  931         /* Connect read old data nodes to xor nodes. */
  932         for (i = 0; i < numDataNodes; i++) {
  933                 RF_ASSERT(readDataNodes[i].numSuccedents ==
  934                     (nfaults * numParityNodes));
  935                 for (j = 0; j < numParityNodes; j++) {
  936                         RF_ASSERT(xorNodes[j].numAntecedents ==
  937                             numDataNodes + numParityNodes);
  938                         readDataNodes[i].succedents[j] = &xorNodes[j];
  939                         xorNodes[j].antecedents[i] = &readDataNodes[i];
  940                         xorNodes[j].antType[i] = rf_trueData;
  941                 }
  942         }
  943 
  944         /* Connect read old data nodes to q nodes. */
  945         if (nfaults == 2) {
  946                 for (i = 0; i < numDataNodes; i++) {
  947                         for (j = 0; j < numParityNodes; j++) {
  948                                 RF_ASSERT(qNodes[j].numAntecedents ==
  949                                     numDataNodes + numParityNodes);
  950                                 readDataNodes[i].succedents[numParityNodes + j]
  951                                     = &qNodes[j];
  952                                 qNodes[j].antecedents[i] = &readDataNodes[i];
  953                                 qNodes[j].antType[i] = rf_trueData;
  954                         }
  955                 }
  956         }
  957         /* Connect read old parity nodes to xor nodes. */
  958         for (i = 0; i < numParityNodes; i++) {
  959                 RF_ASSERT(readParityNodes[i].numSuccedents == numParityNodes);
  960                 for (j = 0; j < numParityNodes; j++) {
  961                         readParityNodes[i].succedents[j] = &xorNodes[j];
  962                         xorNodes[j].antecedents[numDataNodes + i] =
  963                             &readParityNodes[i];
  964                         xorNodes[j].antType[numDataNodes + i] = rf_trueData;
  965                 }
  966         }
  967 
  968         /* Connect read old q nodes to q nodes. */
  969         if (nfaults == 2) {
  970                 for (i = 0; i < numParityNodes; i++) {
  971                         RF_ASSERT(readParityNodes[i].numSuccedents ==
  972                             numParityNodes);
  973                         for (j = 0; j < numParityNodes; j++) {
  974                                 readQNodes[i].succedents[j] = &qNodes[j];
  975                                 qNodes[j].antecedents[numDataNodes + i] =
  976                                     &readQNodes[i];
  977                                 qNodes[j].antType[numDataNodes + i] =
  978                                     rf_trueData;
  979                         }
  980                 }
  981         }
  982         /* Connect xor nodes to commit node. */
  983         RF_ASSERT(commitNode->numAntecedents == (nfaults * numParityNodes));
  984         for (i = 0; i < numParityNodes; i++) {
  985                 RF_ASSERT(xorNodes[i].numSuccedents == 1);
  986                 xorNodes[i].succedents[0] = commitNode;
  987                 commitNode->antecedents[i] = &xorNodes[i];
  988                 commitNode->antType[i] = rf_control;
  989         }
  990 
  991         /* Connect q nodes to commit node. */
  992         if (nfaults == 2) {
  993                 for (i = 0; i < numParityNodes; i++) {
  994                         RF_ASSERT(qNodes[i].numSuccedents == 1);
  995                         qNodes[i].succedents[0] = commitNode;
  996                         commitNode->antecedents[i + numParityNodes] =
  997                             &qNodes[i];
  998                         commitNode->antType[i + numParityNodes] = rf_control;
  999                 }
 1000         }
 1001         /* Connect commit node to write nodes. */
 1002         RF_ASSERT(commitNode->numSuccedents ==
 1003             (numDataNodes + (nfaults * numParityNodes)));
 1004         for (i = 0; i < numDataNodes; i++) {
 1005                 RF_ASSERT(writeDataNodes[i].numAntecedents == 1);
 1006                 commitNode->succedents[i] = &writeDataNodes[i];
 1007                 writeDataNodes[i].antecedents[0] = commitNode;
 1008                 writeDataNodes[i].antType[0] = rf_trueData;
 1009         }
 1010         for (i = 0; i < numParityNodes; i++) {
 1011                 RF_ASSERT(writeParityNodes[i].numAntecedents == 1);
 1012                 commitNode->succedents[i + numDataNodes] = &writeParityNodes[i];
 1013                 writeParityNodes[i].antecedents[0] = commitNode;
 1014                 writeParityNodes[i].antType[0] = rf_trueData;
 1015         }
 1016         if (nfaults == 2) {
 1017                 for (i = 0; i < numParityNodes; i++) {
 1018                         RF_ASSERT(writeQNodes[i].numAntecedents == 1);
 1019                         commitNode->succedents
 1020                             [i + numDataNodes + numParityNodes] =
 1021                             &writeQNodes[i];
 1022                         writeQNodes[i].antecedents[0] = commitNode;
 1023                         writeQNodes[i].antType[0] = rf_trueData;
 1024                 }
 1025         }
 1026         RF_ASSERT(termNode->numAntecedents ==
 1027             (numDataNodes + (nfaults * numParityNodes)));
 1028         RF_ASSERT(termNode->numSuccedents == 0);
 1029         for (i = 0; i < numDataNodes; i++) {
 1030                 if (lu_flag) {
 1031                         /* Connect write new data nodes to unlock nodes. */
 1032                         RF_ASSERT(writeDataNodes[i].numSuccedents == 1);
 1033                         RF_ASSERT(unlockDataNodes[i].numAntecedents == 1);
 1034                         writeDataNodes[i].succedents[0] = &unlockDataNodes[i];
 1035                         unlockDataNodes[i].antecedents[0] = &writeDataNodes[i];
 1036                         unlockDataNodes[i].antType[0] = rf_control;
 1037 
 1038                         /* Connect unlock nodes to term node. */
 1039                         RF_ASSERT(unlockDataNodes[i].numSuccedents == 1);
 1040                         unlockDataNodes[i].succedents[0] = termNode;
 1041                         termNode->antecedents[i] = &unlockDataNodes[i];
 1042                         termNode->antType[i] = rf_control;
 1043                 } else {
 1044                         /* Connect write new data nodes to term node. */
 1045                         RF_ASSERT(writeDataNodes[i].numSuccedents == 1);
 1046                         RF_ASSERT(termNode->numAntecedents ==
 1047                             (numDataNodes + (nfaults * numParityNodes)));
 1048                         writeDataNodes[i].succedents[0] = termNode;
 1049                         termNode->antecedents[i] = &writeDataNodes[i];
 1050                         termNode->antType[i] = rf_control;
 1051                 }
 1052         }
 1053 
 1054         for (i = 0; i < numParityNodes; i++) {
 1055                 if (lu_flag) {
 1056                         /* Connect write new parity nodes to unlock nodes. */
 1057                         RF_ASSERT(writeParityNodes[i].numSuccedents == 1);
 1058                         RF_ASSERT(unlockParityNodes[i].numAntecedents == 1);
 1059                         writeParityNodes[i].succedents[0] =
 1060                             &unlockParityNodes[i];
 1061                         unlockParityNodes[i].antecedents[0] =
 1062                             &writeParityNodes[i];
 1063                         unlockParityNodes[i].antType[0] = rf_control;
 1064 
 1065                         /* Connect unlock nodes to term node. */
 1066                         RF_ASSERT(unlockParityNodes[i].numSuccedents == 1);
 1067                         unlockParityNodes[i].succedents[0] = termNode;
 1068                         termNode->antecedents[numDataNodes + i] =
 1069                             &unlockParityNodes[i];
 1070                         termNode->antType[numDataNodes + i] = rf_control;
 1071                 } else {
 1072                         RF_ASSERT(writeParityNodes[i].numSuccedents == 1);
 1073                         writeParityNodes[i].succedents[0] = termNode;
 1074                         termNode->antecedents[numDataNodes + i] =
 1075                             &writeParityNodes[i];
 1076                         termNode->antType[numDataNodes + i] = rf_control;
 1077                 }
 1078         }
 1079 
 1080         if (nfaults == 2) {
 1081                 for (i = 0; i < numParityNodes; i++) {
 1082                         if (lu_flag) {
 1083                                 /* Connect write new Q nodes to unlock nodes. */
 1084                                 RF_ASSERT(writeQNodes[i].numSuccedents == 1);
 1085                                 RF_ASSERT(unlockQNodes[i].numAntecedents == 1);
 1086                                 writeQNodes[i].succedents[0] = &unlockQNodes[i];
 1087                                 unlockQNodes[i].antecedents[0] =
 1088                                     &writeQNodes[i];
 1089                                 unlockQNodes[i].antType[0] = rf_control;
 1090 
 1091                                 /* Connect unlock nodes to unblock node. */
 1092                                 RF_ASSERT(unlockQNodes[i].numSuccedents == 1);
 1093                                 unlockQNodes[i].succedents[0] = termNode;
 1094                                 termNode->antecedents
 1095                                     [numDataNodes + numParityNodes + i] =
 1096                                     &unlockQNodes[i];
 1097                                 termNode->antType
 1098                                     [numDataNodes + numParityNodes + i] =
 1099                                     rf_control;
 1100                         } else {
 1101                                 RF_ASSERT(writeQNodes[i].numSuccedents == 1);
 1102                                 writeQNodes[i].succedents[0] = termNode;
 1103                                 termNode->antecedents
 1104                                     [numDataNodes + numParityNodes + i] =
 1105                                     &writeQNodes[i];
 1106                                 termNode->antType
 1107                                     [numDataNodes + numParityNodes + i] =
 1108                                     rf_control;
 1109                         }
 1110                 }
 1111         }
 1112 }
 1113 
 1114 
 1115 /*****************************************************************************
 1116  * Create a write graph (fault-free or degraded) for RAID level 1.
 1117  *
 1118  * Hdr -> Commit -> Wpd -> Nil -> Trm
 1119  *               -> Wsd ->
 1120  *
 1121  * The "Wpd" node writes data to the primary copy in the mirror pair.
 1122  * The "Wsd" node writes data to the secondary copy in the mirror pair.
 1123  *
 1124  * Parameters:  raidPtr   - description of the physical array
 1125  *              asmap     - logical & physical addresses for this access
 1126  *              bp        - buffer ptr (holds write data)
 1127  *              flags     - general flags (e.g. disk locking)
 1128  *              allocList - list of memory allocated in DAG creation
 1129  *****************************************************************************/
 1130 
 1131 void
 1132 rf_CreateRaidOneWriteDAG(RF_Raid_t *raidPtr, RF_AccessStripeMap_t *asmap,
 1133     RF_DagHeader_t *dag_h, void *bp, RF_RaidAccessFlags_t flags,
 1134     RF_AllocListElem_t *allocList)
 1135 {
 1136         RF_DagNode_t *unblockNode, *termNode, *commitNode;
 1137         RF_DagNode_t *nodes, *wndNode, *wmirNode;
 1138         int nWndNodes, nWmirNodes, i;
 1139         RF_ReconUnitNum_t which_ru;
 1140         RF_PhysDiskAddr_t *pda, *pdaP;
 1141         RF_StripeNum_t parityStripeID;
 1142 
 1143         parityStripeID = rf_RaidAddressToParityStripeID(&(raidPtr->Layout),
 1144             asmap->raidAddress, &which_ru);
 1145         if (rf_dagDebug) {
 1146                 printf("[Creating RAID level 1 write DAG]\n");
 1147         }
 1148         dag_h->creator = "RaidOneWriteDAG";
 1149 
 1150         /* 2 implies access not SU aligned. */
 1151         nWmirNodes = (asmap->parityInfo->next) ? 2 : 1;
 1152         nWndNodes = (asmap->physInfo->next) ? 2 : 1;
 1153 
 1154         /* Alloc the Wnd nodes and the Wmir node. */
 1155         if (asmap->numDataFailed == 1)
 1156                 nWndNodes--;
 1157         if (asmap->numParityFailed == 1)
 1158                 nWmirNodes--;
 1159 
 1160         /*
 1161          * Total number of nodes = nWndNodes + nWmirNodes
 1162          * + (commit + unblock + terminator)
 1163          */
 1164         RF_CallocAndAdd(nodes, nWndNodes + nWmirNodes + 3, sizeof(RF_DagNode_t),
 1165             (RF_DagNode_t *), allocList);
 1166         i = 0;
 1167         wndNode = &nodes[i];
 1168         i += nWndNodes;
 1169         wmirNode = &nodes[i];
 1170         i += nWmirNodes;
 1171         commitNode = &nodes[i];
 1172         i += 1;
 1173         unblockNode = &nodes[i];
 1174         i += 1;
 1175         termNode = &nodes[i];
 1176         i += 1;
 1177         RF_ASSERT(i == (nWndNodes + nWmirNodes + 3));
 1178 
 1179         /* This dag can commit immediately. */
 1180         dag_h->numCommitNodes = 1;
 1181         dag_h->numCommits = 0;
 1182         dag_h->numSuccedents = 1;
 1183 
 1184         /* Initialize the commit, unblock, and term nodes. */
 1185         rf_InitNode(commitNode, rf_wait, RF_TRUE, rf_NullNodeFunc,
 1186             rf_NullNodeUndoFunc, NULL, (nWndNodes + nWmirNodes), 0, 0, 0,
 1187             dag_h, "Cmt", allocList);
 1188         rf_InitNode(unblockNode, rf_wait, RF_FALSE, rf_NullNodeFunc,
 1189             rf_NullNodeUndoFunc, NULL, 1, (nWndNodes + nWmirNodes), 0, 0,
 1190             dag_h, "Nil", allocList);
 1191         rf_InitNode(termNode, rf_wait, RF_FALSE, rf_TerminateFunc,
 1192             rf_TerminateUndoFunc, NULL, 0, 1, 0, 0, dag_h, "Trm", allocList);
 1193 
 1194         /* Initialize the wnd nodes. */
 1195         if (nWndNodes > 0) {
 1196                 pda = asmap->physInfo;
 1197                 for (i = 0; i < nWndNodes; i++) {
 1198                         rf_InitNode(&wndNode[i], rf_wait, RF_FALSE,
 1199                             rf_DiskWriteFunc, rf_DiskWriteUndoFunc,
 1200                             rf_GenericWakeupFunc, 1, 1, 4, 0, dag_h,
 1201                             "Wpd", allocList);
 1202                         RF_ASSERT(pda != NULL);
 1203                         wndNode[i].params[0].p = pda;
 1204                         wndNode[i].params[1].p = pda->bufPtr;
 1205                         wndNode[i].params[2].v = parityStripeID;
 1206                         wndNode[i].params[3].v =
 1207                             RF_CREATE_PARAM3(RF_IO_NORMAL_PRIORITY,
 1208                             0, 0, which_ru);
 1209                         pda = pda->next;
 1210                 }
 1211                 RF_ASSERT(pda == NULL);
 1212         }
 1213         /* Initialize the mirror nodes. */
 1214         if (nWmirNodes > 0) {
 1215                 pda = asmap->physInfo;
 1216                 pdaP = asmap->parityInfo;
 1217                 for (i = 0; i < nWmirNodes; i++) {
 1218                         rf_InitNode(&wmirNode[i], rf_wait, RF_FALSE,
 1219                             rf_DiskWriteFunc, rf_DiskWriteUndoFunc,
 1220                             rf_GenericWakeupFunc, 1, 1, 4, 0, dag_h,
 1221                             "Wsd", allocList);
 1222                         RF_ASSERT(pda != NULL);
 1223                         wmirNode[i].params[0].p = pdaP;
 1224                         wmirNode[i].params[1].p = pda->bufPtr;
 1225                         wmirNode[i].params[2].v = parityStripeID;
 1226                         wmirNode[i].params[3].v =
 1227                             RF_CREATE_PARAM3(RF_IO_NORMAL_PRIORITY,
 1228                             0, 0, which_ru);
 1229                         pda = pda->next;
 1230                         pdaP = pdaP->next;
 1231                 }
 1232                 RF_ASSERT(pda == NULL);
 1233                 RF_ASSERT(pdaP == NULL);
 1234         }
 1235         /* Link the header node to the commit node. */
 1236         RF_ASSERT(dag_h->numSuccedents == 1);
 1237         RF_ASSERT(commitNode->numAntecedents == 0);
 1238         dag_h->succedents[0] = commitNode;
 1239 
 1240         /* Link the commit node to the write nodes. */
 1241         RF_ASSERT(commitNode->numSuccedents == (nWndNodes + nWmirNodes));
 1242         for (i = 0; i < nWndNodes; i++) {
 1243                 RF_ASSERT(wndNode[i].numAntecedents == 1);
 1244                 commitNode->succedents[i] = &wndNode[i];
 1245                 wndNode[i].antecedents[0] = commitNode;
 1246                 wndNode[i].antType[0] = rf_control;
 1247         }
 1248         for (i = 0; i < nWmirNodes; i++) {
 1249                 RF_ASSERT(wmirNode[i].numAntecedents == 1);
 1250                 commitNode->succedents[i + nWndNodes] = &wmirNode[i];
 1251                 wmirNode[i].antecedents[0] = commitNode;
 1252                 wmirNode[i].antType[0] = rf_control;
 1253         }
 1254 
 1255         /* Link the write nodes to the unblock node. */
 1256         RF_ASSERT(unblockNode->numAntecedents == (nWndNodes + nWmirNodes));
 1257         for (i = 0; i < nWndNodes; i++) {
 1258                 RF_ASSERT(wndNode[i].numSuccedents == 1);
 1259                 wndNode[i].succedents[0] = unblockNode;
 1260                 unblockNode->antecedents[i] = &wndNode[i];
 1261                 unblockNode->antType[i] = rf_control;
 1262         }
 1263         for (i = 0; i < nWmirNodes; i++) {
 1264                 RF_ASSERT(wmirNode[i].numSuccedents == 1);
 1265                 wmirNode[i].succedents[0] = unblockNode;
 1266                 unblockNode->antecedents[i + nWndNodes] = &wmirNode[i];
 1267                 unblockNode->antType[i + nWndNodes] = rf_control;
 1268         }
 1269 
 1270         /* Link the unblock node to the term node. */
 1271         RF_ASSERT(unblockNode->numSuccedents == 1);
 1272         RF_ASSERT(termNode->numAntecedents == 1);
 1273         RF_ASSERT(termNode->numSuccedents == 0);
 1274         unblockNode->succedents[0] = termNode;
 1275         termNode->antecedents[0] = unblockNode;
 1276         termNode->antType[0] = rf_control;
 1277 }
 1278 
 1279 
 1280 
 1281 /*
 1282  * DAGs that have no commit points.
 1283  *
 1284  * The following DAGs are used in forward and backward error recovery
 1285  * experiments.
 1286  * They are identical to the DAGs above this comment with the exception that
 1287  * the commit points have been removed.
 1288  */
 1289 
 1290 
 1291 void
 1292 rf_CommonCreateLargeWriteDAGFwd(RF_Raid_t *raidPtr, RF_AccessStripeMap_t *asmap,
 1293     RF_DagHeader_t *dag_h, void *bp, RF_RaidAccessFlags_t flags,
 1294     RF_AllocListElem_t *allocList, int nfaults, int (*redFunc) (RF_DagNode_t *),
 1295     int allowBufferRecycle)
 1296 {
 1297         RF_DagNode_t *nodes, *wndNodes, *rodNodes, *xorNode, *wnpNode;
 1298         RF_DagNode_t *wnqNode, *blockNode, *syncNode, *termNode;
 1299         int nWndNodes, nRodNodes, i, nodeNum, asmNum;
 1300         RF_AccessStripeMapHeader_t *new_asm_h[2];
 1301         RF_StripeNum_t parityStripeID;
 1302         char *sosBuffer, *eosBuffer;
 1303         RF_ReconUnitNum_t which_ru;
 1304         RF_RaidLayout_t *layoutPtr;
 1305         RF_PhysDiskAddr_t *pda;
 1306 
 1307         layoutPtr = &(raidPtr->Layout);
 1308         parityStripeID = rf_RaidAddressToParityStripeID(&(raidPtr->Layout),
 1309             asmap->raidAddress, &which_ru);
 1310 
 1311         if (rf_dagDebug)
 1312                 printf("[Creating large-write DAG]\n");
 1313         dag_h->creator = "LargeWriteDAGFwd";
 1314 
 1315         dag_h->numCommitNodes = 0;
 1316         dag_h->numCommits = 0;
 1317         dag_h->numSuccedents = 1;
 1318 
 1319         /* Alloc the nodes: Wnd, xor, commit, block, term, and  Wnp. */
 1320         nWndNodes = asmap->numStripeUnitsAccessed;
 1321         RF_CallocAndAdd(nodes, nWndNodes + 4 + nfaults, sizeof(RF_DagNode_t),
 1322             (RF_DagNode_t *), allocList);
 1323         i = 0;
 1324         wndNodes = &nodes[i];
 1325         i += nWndNodes;
 1326         xorNode = &nodes[i];
 1327         i += 1;
 1328         wnpNode = &nodes[i];
 1329         i += 1;
 1330         blockNode = &nodes[i];
 1331         i += 1;
 1332         syncNode = &nodes[i];
 1333         i += 1;
 1334         termNode = &nodes[i];
 1335         i += 1;
 1336         if (nfaults == 2) {
 1337                 wnqNode = &nodes[i];
 1338                 i += 1;
 1339         } else {
 1340                 wnqNode = NULL;
 1341         }
 1342         rf_MapUnaccessedPortionOfStripe(raidPtr, layoutPtr, asmap, dag_h,
 1343             new_asm_h, &nRodNodes, &sosBuffer, &eosBuffer, allocList);
 1344         if (nRodNodes > 0) {
 1345                 RF_CallocAndAdd(rodNodes, nRodNodes, sizeof(RF_DagNode_t),
 1346                     (RF_DagNode_t *), allocList);
 1347         } else {
 1348                 rodNodes = NULL;
 1349         }
 1350 
 1351         /* Begin node initialization. */
 1352         if (nRodNodes > 0) {
 1353                 rf_InitNode(blockNode, rf_wait, RF_FALSE, rf_NullNodeFunc,
 1354                     rf_NullNodeUndoFunc, NULL, nRodNodes, 0, 0, 0, dag_h,
 1355                     "Nil", allocList);
 1356                 rf_InitNode(syncNode, rf_wait, RF_FALSE, rf_NullNodeFunc,
 1357                     rf_NullNodeUndoFunc, NULL, nWndNodes + 1, nRodNodes, 0, 0,
 1358                     dag_h, "Nil", allocList);
 1359         } else {
 1360                 rf_InitNode(blockNode, rf_wait, RF_FALSE, rf_NullNodeFunc,
 1361                     rf_NullNodeUndoFunc, NULL, 1, 0, 0, 0, dag_h, "Nil",
 1362                     allocList);
 1363                 rf_InitNode(syncNode, rf_wait, RF_FALSE, rf_NullNodeFunc,
 1364                     rf_NullNodeUndoFunc, NULL, nWndNodes + 1, 1, 0, 0, dag_h,
 1365                     "Nil", allocList);
 1366         }
 1367 
 1368         rf_InitNode(termNode, rf_wait, RF_FALSE, rf_TerminateFunc,
 1369             rf_TerminateUndoFunc, NULL, 0, nWndNodes + nfaults, 0, 0,
 1370             dag_h, "Trm", allocList);
 1371 
 1372         /* Initialize the Rod nodes. */
 1373         for (nodeNum = asmNum = 0; asmNum < 2; asmNum++) {
 1374                 if (new_asm_h[asmNum]) {
 1375                         pda = new_asm_h[asmNum]->stripeMap->physInfo;
 1376                         while (pda) {
 1377                                 rf_InitNode(&rodNodes[nodeNum], rf_wait,
 1378                                     RF_FALSE, rf_DiskReadFunc,
 1379                                     rf_DiskReadUndoFunc, rf_GenericWakeupFunc,
 1380                                     1, 1, 4, 0, dag_h, "Rod", allocList);
 1381                                 rodNodes[nodeNum].params[0].p = pda;
 1382                                 rodNodes[nodeNum].params[1].p = pda->bufPtr;
 1383                                 rodNodes[nodeNum].params[2].v = parityStripeID;
 1384                                 rodNodes[nodeNum].params[3].v =
 1385                                     RF_CREATE_PARAM3(RF_IO_NORMAL_PRIORITY,
 1386                                     0, 0, which_ru);
 1387                                 nodeNum++;
 1388                                 pda = pda->next;
 1389                         }
 1390                 }
 1391         }
 1392         RF_ASSERT(nodeNum == nRodNodes);
 1393 
 1394         /* Initialize the wnd nodes. */
 1395         pda = asmap->physInfo;
 1396         for (i = 0; i < nWndNodes; i++) {
 1397                 rf_InitNode(&wndNodes[i], rf_wait, RF_FALSE, rf_DiskWriteFunc,
 1398                     rf_DiskWriteUndoFunc, rf_GenericWakeupFunc, 1, 1, 4, 0,
 1399                     dag_h, "Wnd", allocList);
 1400                 RF_ASSERT(pda != NULL);
 1401                 wndNodes[i].params[0].p = pda;
 1402                 wndNodes[i].params[1].p = pda->bufPtr;
 1403                 wndNodes[i].params[2].v = parityStripeID;
 1404                 wndNodes[i].params[3].v =
 1405                     RF_CREATE_PARAM3(RF_IO_NORMAL_PRIORITY, 0, 0, which_ru);
 1406                 pda = pda->next;
 1407         }
 1408 
 1409         /* Initialize the redundancy node. */
 1410         rf_InitNode(xorNode, rf_wait, RF_FALSE, redFunc, rf_NullNodeUndoFunc,
 1411             NULL, 1, nfaults, 2 * (nWndNodes + nRodNodes) + 1, nfaults, dag_h,
 1412             "Xr ", allocList);
 1413         xorNode->flags |= RF_DAGNODE_FLAG_YIELD;
 1414         for (i = 0; i < nWndNodes; i++) {
 1415                 xorNode->params[2 * i + 0] =
 1416                     wndNodes[i].params[0];      /* pda */
 1417                 xorNode->params[2 * i + 1] =
 1418                     wndNodes[i].params[1];      /* buf ptr */
 1419         }
 1420         for (i = 0; i < nRodNodes; i++) {
 1421                 xorNode->params[2 * (nWndNodes + i) + 0] =
 1422                     rodNodes[i].params[0];      /* pda */
 1423                 xorNode->params[2 * (nWndNodes + i) + 1] =
 1424                     rodNodes[i].params[1];      /* buf ptr */
 1425         }
 1426         /* Xor node needs to get at RAID information. */
 1427         xorNode->params[2 * (nWndNodes + nRodNodes)].p = raidPtr;
 1428 
 1429         /*
 1430          * Look for an Rod node that reads a complete SU. If none, alloc a
 1431          * buffer to receive the parity info. Note that we can't use a new
 1432          * data buffer because it will not have gotten written when the xor
 1433          * occurs.
 1434          */
 1435         if (allowBufferRecycle) {
 1436                 for (i = 0; i < nRodNodes; i++)
 1437                         if (((RF_PhysDiskAddr_t *) rodNodes[i].params[0].p)
 1438                             ->numSector == raidPtr->Layout.sectorsPerStripeUnit)
 1439                                 break;
 1440         }
 1441         if ((!allowBufferRecycle) || (i == nRodNodes)) {
 1442                 RF_CallocAndAdd(xorNode->results[0], 1,
 1443                     rf_RaidAddressToByte(raidPtr,
 1444                     raidPtr->Layout.sectorsPerStripeUnit),
 1445                     (void *), allocList);
 1446         } else
 1447                 xorNode->results[0] = rodNodes[i].params[1].p;
 1448 
 1449         /* Initialize the Wnp node. */
 1450         rf_InitNode(wnpNode, rf_wait, RF_FALSE, rf_DiskWriteFunc,
 1451             rf_DiskWriteUndoFunc, rf_GenericWakeupFunc, 1, 1, 4, 0,
 1452             dag_h, "Wnp", allocList);
 1453         wnpNode->params[0].p = asmap->parityInfo;
 1454         wnpNode->params[1].p = xorNode->results[0];
 1455         wnpNode->params[2].v = parityStripeID;
 1456         wnpNode->params[3].v =
 1457             RF_CREATE_PARAM3(RF_IO_NORMAL_PRIORITY, 0, 0, which_ru);
 1458         /* parityInfo must describe entire parity unit. */
 1459         RF_ASSERT(asmap->parityInfo->next == NULL);
 1460 
 1461         if (nfaults == 2) {
 1462                 /*
 1463                  * Never try to recycle a buffer for the Q calcuation in
 1464                  * addition to the parity. This would cause two buffers to
 1465                  * get smashed during the P and Q calculation, guaranteeing
 1466                  * one would be wrong.
 1467                  */
 1468                 RF_CallocAndAdd(xorNode->results[1], 1,
 1469                     rf_RaidAddressToByte(raidPtr,
 1470                     raidPtr->Layout.sectorsPerStripeUnit),
 1471                     (void *), allocList);
 1472                 rf_InitNode(wnqNode, rf_wait, RF_FALSE, rf_DiskWriteFunc,
 1473                     rf_DiskWriteUndoFunc, rf_GenericWakeupFunc, 1, 1, 4, 0,
 1474                     dag_h, "Wnq", allocList);
 1475                 wnqNode->params[0].p = asmap->qInfo;
 1476                 wnqNode->params[1].p = xorNode->results[1];
 1477                 wnqNode->params[2].v = parityStripeID;
 1478                 wnqNode->params[3].v =
 1479                     RF_CREATE_PARAM3(RF_IO_NORMAL_PRIORITY, 0, 0, which_ru);
 1480                 /* parityInfo must describe entire parity unit. */
 1481                 RF_ASSERT(asmap->parityInfo->next == NULL);
 1482         }
 1483 
 1484         /* Connect nodes to form graph. */
 1485 
 1486         /* Connect dag header to block node. */
 1487         RF_ASSERT(blockNode->numAntecedents == 0);
 1488         dag_h->succedents[0] = blockNode;
 1489 
 1490         if (nRodNodes > 0) {
 1491                 /* Connect the block node to the Rod nodes. */
 1492                 RF_ASSERT(blockNode->numSuccedents == nRodNodes);
 1493                 RF_ASSERT(syncNode->numAntecedents == nRodNodes);
 1494                 for (i = 0; i < nRodNodes; i++) {
 1495                         RF_ASSERT(rodNodes[i].numAntecedents == 1);
 1496                         blockNode->succedents[i] = &rodNodes[i];
 1497                         rodNodes[i].antecedents[0] = blockNode;
 1498                         rodNodes[i].antType[0] = rf_control;
 1499 
 1500                         /* Connect the Rod nodes to the Nil node. */
 1501                         RF_ASSERT(rodNodes[i].numSuccedents == 1);
 1502                         rodNodes[i].succedents[0] = syncNode;
 1503                         syncNode->antecedents[i] = &rodNodes[i];
 1504                         syncNode->antType[i] = rf_trueData;
 1505                 }
 1506         } else {
 1507                 /* Connect the block node to the Nil node. */
 1508                 RF_ASSERT(blockNode->numSuccedents == 1);
 1509                 RF_ASSERT(syncNode->numAntecedents == 1);
 1510                 blockNode->succedents[0] = syncNode;
 1511                 syncNode->antecedents[0] = blockNode;
 1512                 syncNode->antType[0] = rf_control;
 1513         }
 1514 
 1515         /* Connect the sync node to the Wnd nodes. */
 1516         RF_ASSERT(syncNode->numSuccedents == (1 + nWndNodes));
 1517         for (i = 0; i < nWndNodes; i++) {
 1518                 RF_ASSERT(wndNodes->numAntecedents == 1);
 1519                 syncNode->succedents[i] = &wndNodes[i];
 1520                 wndNodes[i].antecedents[0] = syncNode;
 1521                 wndNodes[i].antType[0] = rf_control;
 1522         }
 1523 
 1524         /* Connect the sync node to the Xor node. */
 1525         RF_ASSERT(xorNode->numAntecedents == 1);
 1526         syncNode->succedents[nWndNodes] = xorNode;
 1527         xorNode->antecedents[0] = syncNode;
 1528         xorNode->antType[0] = rf_control;
 1529 
 1530         /* Connect the xor node to the write parity node. */
 1531         RF_ASSERT(xorNode->numSuccedents == nfaults);
 1532         RF_ASSERT(wnpNode->numAntecedents == 1);
 1533         xorNode->succedents[0] = wnpNode;
 1534         wnpNode->antecedents[0] = xorNode;
 1535         wnpNode->antType[0] = rf_trueData;
 1536         if (nfaults == 2) {
 1537                 RF_ASSERT(wnqNode->numAntecedents == 1);
 1538                 xorNode->succedents[1] = wnqNode;
 1539                 wnqNode->antecedents[0] = xorNode;
 1540                 wnqNode->antType[0] = rf_trueData;
 1541         }
 1542         /* Connect the write nodes to the term node. */
 1543         RF_ASSERT(termNode->numAntecedents == nWndNodes + nfaults);
 1544         RF_ASSERT(termNode->numSuccedents == 0);
 1545         for (i = 0; i < nWndNodes; i++) {
 1546                 RF_ASSERT(wndNodes->numSuccedents == 1);
 1547                 wndNodes[i].succedents[0] = termNode;
 1548                 termNode->antecedents[i] = &wndNodes[i];
 1549                 termNode->antType[i] = rf_control;
 1550         }
 1551         RF_ASSERT(wnpNode->numSuccedents == 1);
 1552         wnpNode->succedents[0] = termNode;
 1553         termNode->antecedents[nWndNodes] = wnpNode;
 1554         termNode->antType[nWndNodes] = rf_control;
 1555         if (nfaults == 2) {
 1556                 RF_ASSERT(wnqNode->numSuccedents == 1);
 1557                 wnqNode->succedents[0] = termNode;
 1558                 termNode->antecedents[nWndNodes + 1] = wnqNode;
 1559                 termNode->antType[nWndNodes + 1] = rf_control;
 1560         }
 1561 }
 1562 
 1563 
 1564 /*****************************************************************************
 1565  *
 1566  * Create a DAG to perform a small-write operation (either raid 5 or pq),
 1567  * which is as follows:
 1568  *
 1569  * Hdr -> Nil -> Rop - Xor - Wnp [Unp] -- Trm
 1570  *            \- Rod X- Wnd [Und] -------/
 1571  *           [\- Rod X- Wnd [Und] ------/]
 1572  *           [\- Roq - Q --> Wnq [Unq]-/]
 1573  *
 1574  * Rop = read old parity
 1575  * Rod = read old data
 1576  * Roq = read old "q"
 1577  * Cmt = commit node
 1578  * Und = unlock data disk
 1579  * Unp = unlock parity disk
 1580  * Unq = unlock q disk
 1581  * Wnp = write new parity
 1582  * Wnd = write new data
 1583  * Wnq = write new "q"
 1584  * [ ] denotes optional segments in the graph.
 1585  *
 1586  * Parameters:  raidPtr   - description of the physical array
 1587  *              asmap     - logical & physical addresses for this access
 1588  *              bp        - buffer ptr (holds write data)
 1589  *              flags     - general flags (e.g. disk locking)
 1590  *              allocList - list of memory allocated in DAG creation
 1591  *              pfuncs    - list of parity generating functions
 1592  *              qfuncs    - list of q generating functions
 1593  *
 1594  * A null qfuncs indicates single fault tolerant.
 1595  *****************************************************************************/
 1596 
 1597 void
 1598 rf_CommonCreateSmallWriteDAGFwd(RF_Raid_t *raidPtr, RF_AccessStripeMap_t *asmap,
 1599     RF_DagHeader_t *dag_h, void *bp, RF_RaidAccessFlags_t flags,
 1600     RF_AllocListElem_t *allocList, RF_RedFuncs_t *pfuncs, RF_RedFuncs_t *qfuncs)
 1601 {
 1602         RF_DagNode_t *readDataNodes, *readParityNodes, *readQNodes, *termNode;
 1603         RF_DagNode_t *unlockDataNodes, *unlockParityNodes, *unlockQNodes;
 1604         RF_DagNode_t *xorNodes, *qNodes, *blockNode, *nodes;
 1605         RF_DagNode_t *writeDataNodes, *writeParityNodes, *writeQNodes;
 1606         int i, j, nNodes, totalNumNodes, lu_flag;
 1607         RF_ReconUnitNum_t which_ru;
 1608         int (*func) (RF_DagNode_t *);
 1609         int (*undoFunc) (RF_DagNode_t *);
 1610         int (*qfunc) (RF_DagNode_t *);
 1611         int numDataNodes, numParityNodes;
 1612         RF_StripeNum_t parityStripeID;
 1613         RF_PhysDiskAddr_t *pda;
 1614         char *name, *qname;
 1615         long nfaults;
 1616 
 1617         nfaults = qfuncs ? 2 : 1;
 1618         lu_flag = (rf_enableAtomicRMW) ? 1 : 0; /* Lock/unlock flag. */
 1619 
 1620         parityStripeID = rf_RaidAddressToParityStripeID(&(raidPtr->Layout),
 1621             asmap->raidAddress, &which_ru);
 1622         pda = asmap->physInfo;
 1623         numDataNodes = asmap->numStripeUnitsAccessed;
 1624         numParityNodes = (asmap->parityInfo->next) ? 2 : 1;
 1625 
 1626         if (rf_dagDebug)
 1627                 printf("[Creating small-write DAG]\n");
 1628         RF_ASSERT(numDataNodes > 0);
 1629         dag_h->creator = "SmallWriteDAGFwd";
 1630 
 1631         dag_h->numCommitNodes = 0;
 1632         dag_h->numCommits = 0;
 1633         dag_h->numSuccedents = 1;
 1634 
 1635         qfunc = NULL;
 1636         qname = NULL;
 1637 
 1638         /*
 1639          * DAG creation occurs in four steps:
 1640          * 1. Count the number of nodes in the DAG.
 1641          * 2. Create the nodes.
 1642          * 3. Initialize the nodes.
 1643          * 4. Connect the nodes.
 1644          */
 1645 
 1646         /* Step 1. Compute number of nodes in the graph. */
 1647 
 1648         /*
 1649          * Number of nodes: a read and write for each data unit, a redundancy
 1650          * computation node for each parity node (nfaults * nparity), a read
 1651          * and write for each parity unit, a block node, a terminate node if
 1652          * atomic RMW, an unlock node for each data/redundancy unit.
 1653          */
 1654         totalNumNodes = (2 * numDataNodes) + (nfaults * numParityNodes)
 1655             + (nfaults * 2 * numParityNodes) + 2;
 1656         if (lu_flag)
 1657                 totalNumNodes += (numDataNodes + (nfaults * numParityNodes));
 1658 
 1659 
 1660         /* Step 2. Create the nodes. */
 1661         RF_CallocAndAdd(nodes, totalNumNodes, sizeof(RF_DagNode_t),
 1662             (RF_DagNode_t *), allocList);
 1663         i = 0;
 1664         blockNode = &nodes[i];
 1665         i += 1;
 1666         readDataNodes = &nodes[i];
 1667         i += numDataNodes;
 1668         readParityNodes = &nodes[i];
 1669         i += numParityNodes;
 1670         writeDataNodes = &nodes[i];
 1671         i += numDataNodes;
 1672         writeParityNodes = &nodes[i];
 1673         i += numParityNodes;
 1674         xorNodes = &nodes[i];
 1675         i += numParityNodes;
 1676         termNode = &nodes[i];
 1677         i += 1;
 1678         if (lu_flag) {
 1679                 unlockDataNodes = &nodes[i];
 1680                 i += numDataNodes;
 1681                 unlockParityNodes = &nodes[i];
 1682                 i += numParityNodes;
 1683         } else {
 1684                 unlockDataNodes = unlockParityNodes = NULL;
 1685         }
 1686         if (nfaults == 2) {
 1687                 readQNodes = &nodes[i];
 1688                 i += numParityNodes;
 1689                 writeQNodes = &nodes[i];
 1690                 i += numParityNodes;
 1691                 qNodes = &nodes[i];
 1692                 i += numParityNodes;
 1693                 if (lu_flag) {
 1694                         unlockQNodes = &nodes[i];
 1695                         i += numParityNodes;
 1696                 } else {
 1697                         unlockQNodes = NULL;
 1698                 }
 1699         } else {
 1700                 readQNodes = writeQNodes = qNodes = unlockQNodes = NULL;
 1701         }
 1702         RF_ASSERT(i == totalNumNodes);
 1703 
 1704         /* Step 3. Initialize the nodes. */
 1705         /* Initialize block node (Nil). */
 1706         nNodes = numDataNodes + (nfaults * numParityNodes);
 1707         rf_InitNode(blockNode, rf_wait, RF_FALSE, rf_NullNodeFunc,
 1708             rf_NullNodeUndoFunc, NULL, nNodes, 0, 0, 0, dag_h,
 1709             "Nil", allocList);
 1710 
 1711         /* Initialize terminate node (Trm). */
 1712         rf_InitNode(termNode, rf_wait, RF_FALSE, rf_TerminateFunc,
 1713             rf_TerminateUndoFunc, NULL, 0, nNodes, 0, 0, dag_h,
 1714             "Trm", allocList);
 1715 
 1716         /* Initialize nodes which read old data (Rod). */
 1717         for (i = 0; i < numDataNodes; i++) {
 1718                 rf_InitNode(&readDataNodes[i], rf_wait, RF_FALSE,
 1719                     rf_DiskReadFunc, rf_DiskReadUndoFunc, rf_GenericWakeupFunc,
 1720                     (numParityNodes * nfaults) + 1, 1, 4, 0, dag_h,
 1721                     "Rod", allocList);
 1722                 RF_ASSERT(pda != NULL);
 1723                 /* Physical disk addr desc. */
 1724                 readDataNodes[i].params[0].p = pda;
 1725                 /* Buffer to hold old data. */
 1726                 readDataNodes[i].params[1].p = rf_AllocBuffer(raidPtr, dag_h,
 1727                     pda, allocList);
 1728                 readDataNodes[i].params[2].v = parityStripeID;
 1729                 readDataNodes[i].params[3].v =
 1730                     RF_CREATE_PARAM3(RF_IO_NORMAL_PRIORITY,
 1731                     lu_flag, 0, which_ru);
 1732                 pda = pda->next;
 1733                 for (j = 0; j < readDataNodes[i].numSuccedents; j++)
 1734                         readDataNodes[i].propList[j] = NULL;
 1735         }
 1736 
 1737         /* Initialize nodes which read old parity (Rop). */
 1738         pda = asmap->parityInfo;
 1739         i = 0;
 1740         for (i = 0; i < numParityNodes; i++) {
 1741                 RF_ASSERT(pda != NULL);
 1742                 rf_InitNode(&readParityNodes[i], rf_wait, RF_FALSE,
 1743                     rf_DiskReadFunc, rf_DiskReadUndoFunc, rf_GenericWakeupFunc,
 1744                     numParityNodes, 1, 4, 0, dag_h, "Rop", allocList);
 1745                 readParityNodes[i].params[0].p = pda;
 1746                 /* Buffer to hold old parity. */
 1747                 readParityNodes[i].params[1].p = rf_AllocBuffer(raidPtr,
 1748                     dag_h, pda, allocList);
 1749                 readParityNodes[i].params[2].v = parityStripeID;
 1750                 readParityNodes[i].params[3].v =
 1751                     RF_CREATE_PARAM3(RF_IO_NORMAL_PRIORITY,
 1752                     lu_flag, 0, which_ru);
 1753                 for (j = 0; j < readParityNodes[i].numSuccedents; j++)
 1754                         readParityNodes[i].propList[0] = NULL;
 1755                 pda = pda->next;
 1756         }
 1757 
 1758         /* Initialize nodes which read old Q (Roq). */
 1759         if (nfaults == 2) {
 1760                 pda = asmap->qInfo;
 1761                 for (i = 0; i < numParityNodes; i++) {
 1762                         RF_ASSERT(pda != NULL);
 1763                         rf_InitNode(&readQNodes[i], rf_wait, RF_FALSE,
 1764                             rf_DiskReadFunc, rf_DiskReadUndoFunc,
 1765                             rf_GenericWakeupFunc, numParityNodes, 1, 4, 0,
 1766                             dag_h, "Roq", allocList);
 1767                         readQNodes[i].params[0].p = pda;
 1768                         /* Buffer to hold old Q. */
 1769                         readQNodes[i].params[1].p = rf_AllocBuffer(raidPtr,
 1770                             dag_h, pda, allocList);
 1771                         readQNodes[i].params[2].v = parityStripeID;
 1772                         readQNodes[i].params[3].v =
 1773                             RF_CREATE_PARAM3(RF_IO_NORMAL_PRIORITY,
 1774                             lu_flag, 0, which_ru);
 1775                         for (j = 0; j < readQNodes[i].numSuccedents; j++)
 1776                                 readQNodes[i].propList[0] = NULL;
 1777                         pda = pda->next;
 1778                 }
 1779         }
 1780         /* Initialize nodes which write new data (Wnd). */
 1781         pda = asmap->physInfo;
 1782         for (i = 0; i < numDataNodes; i++) {
 1783                 RF_ASSERT(pda != NULL);
 1784                 rf_InitNode(&writeDataNodes[i], rf_wait, RF_FALSE,
 1785                     rf_DiskWriteFunc, rf_DiskWriteUndoFunc,
 1786                     rf_GenericWakeupFunc, 1, 1, 4, 0,
 1787                     dag_h, "Wnd", allocList);
 1788                 /* Physical disk addr desc. */
 1789                 writeDataNodes[i].params[0].p = pda;
 1790                 /* Buffer holding new data to be written. */
 1791                 writeDataNodes[i].params[1].p = pda->bufPtr;
 1792                 writeDataNodes[i].params[2].v = parityStripeID;
 1793                 writeDataNodes[i].params[3].v =
 1794                     RF_CREATE_PARAM3(RF_IO_NORMAL_PRIORITY, 0, 0, which_ru);
 1795 
 1796                 if (lu_flag) {
 1797                         /* Initialize node to unlock the disk queue. */
 1798                         rf_InitNode(&unlockDataNodes[i], rf_wait, RF_FALSE,
 1799                             rf_DiskUnlockFunc, rf_DiskUnlockUndoFunc,
 1800                             rf_GenericWakeupFunc, 1, 1, 2, 0, dag_h,
 1801                             "Und", allocList);
 1802                         /* Physical disk addr desc. */
 1803                         unlockDataNodes[i].params[0].p = pda;
 1804                         unlockDataNodes[i].params[1].v =
 1805                             RF_CREATE_PARAM3(RF_IO_NORMAL_PRIORITY,
 1806                             0, lu_flag, which_ru);
 1807                 }
 1808                 pda = pda->next;
 1809         }
 1810 
 1811 
 1812         /* Initialize nodes which compute new parity and Q. */
 1813         /*
 1814          * Use the simple XOR func in the double-XOR case, and when
 1815          * accessing only a portion of one stripe unit. The distinction
 1816          * between the two is that the regular XOR func assumes that the
 1817          * targbuf is a full SU in size, and examines the pda associated with
 1818          * the buffer to decide where within the buffer to XOR the data,
 1819          * whereas the simple XOR func just XORs the data into the start of
 1820          * the buffer.
 1821          */
 1822         if ((numParityNodes == 2) || ((numDataNodes == 1) &&
 1823             (asmap->totalSectorsAccessed <
 1824              raidPtr->Layout.sectorsPerStripeUnit))) {
 1825                 func = pfuncs->simple;
 1826                 undoFunc = rf_NullNodeUndoFunc;
 1827                 name = pfuncs->SimpleName;
 1828                 if (qfuncs) {
 1829                         qfunc = qfuncs->simple;
 1830                         qname = qfuncs->SimpleName;
 1831                 }
 1832         } else {
 1833                 func = pfuncs->regular;
 1834                 undoFunc = rf_NullNodeUndoFunc;
 1835                 name = pfuncs->RegularName;
 1836                 if (qfuncs) {
 1837                         qfunc = qfuncs->regular;
 1838                         qname = qfuncs->RegularName;
 1839                 }
 1840         }
 1841         /*
 1842          * Initialize the xor nodes: params are {pda,buf} from {Rod,Wnd,Rop}
 1843          * nodes, and raidPtr.
 1844          */
 1845         if (numParityNodes == 2) {      /* Double-xor case. */
 1846                 for (i = 0; i < numParityNodes; i++) {
 1847                         /* No wakeup func for xor. */
 1848                         rf_InitNode(&xorNodes[i], rf_wait, RF_FALSE, func,
 1849                             undoFunc, NULL, numParityNodes, numParityNodes +
 1850                             numDataNodes, 7, 1, dag_h, name, allocList);
 1851                         xorNodes[i].flags |= RF_DAGNODE_FLAG_YIELD;
 1852                         xorNodes[i].params[0] = readDataNodes[i].params[0];
 1853                         xorNodes[i].params[1] = readDataNodes[i].params[1];
 1854                         xorNodes[i].params[2] = readParityNodes[i].params[0];
 1855                         xorNodes[i].params[3] = readParityNodes[i].params[1];
 1856                         xorNodes[i].params[4] = writeDataNodes[i].params[0];
 1857                         xorNodes[i].params[5] = writeDataNodes[i].params[1];
 1858                         xorNodes[i].params[6].p = raidPtr;
 1859                         /* Use old parity buf as target buf. */
 1860                         xorNodes[i].results[0] = readParityNodes[i].params[1].p;
 1861                         if (nfaults == 2) {
 1862                                 /* No wakeup func for xor. */
 1863                                 rf_InitNode(&qNodes[i], rf_wait, RF_FALSE,
 1864                                     qfunc, undoFunc, NULL, numParityNodes,
 1865                                     numParityNodes + numDataNodes, 7, 1,
 1866                                     dag_h, qname, allocList);
 1867                                 qNodes[i].params[0] =
 1868                                     readDataNodes[i].params[0];
 1869                                 qNodes[i].params[1] =
 1870                                     readDataNodes[i].params[1];
 1871                                 qNodes[i].params[2] = readQNodes[i].params[0];
 1872                                 qNodes[i].params[3] = readQNodes[i].params[1];
 1873                                 qNodes[i].params[4] =
 1874                                     writeDataNodes[i].params[0];
 1875                                 qNodes[i].params[5] =
 1876                                     writeDataNodes[i].params[1];
 1877                                 qNodes[i].params[6].p = raidPtr;
 1878                                 /* Use old Q buf as target buf. */
 1879                                 qNodes[i].results[0] =
 1880                                     readQNodes[i].params[1].p;
 1881                         }
 1882                 }
 1883         } else {
 1884                 /* There is only one xor node in this case. */
 1885                 rf_InitNode(&xorNodes[0], rf_wait, RF_FALSE, func, undoFunc,
 1886                     NULL, numParityNodes, numParityNodes + numDataNodes,
 1887                     (2 * (numDataNodes + numDataNodes + 1) + 1), 1, dag_h,
 1888                     name, allocList);
 1889                 xorNodes[0].flags |= RF_DAGNODE_FLAG_YIELD;
 1890                 for (i = 0; i < numDataNodes + 1; i++) {
 1891                         /* Set up params related to Rod and Rop nodes. */
 1892                         xorNodes[0].params[2 * i + 0] =
 1893                             readDataNodes[i].params[0]; /* pda */
 1894                         xorNodes[0].params[2 * i + 1] =
 1895                             readDataNodes[i].params[1]; /* buffer pointer */
 1896                 }
 1897                 for (i = 0; i < numDataNodes; i++) {
 1898                         /* Set up params related to Wnd and Wnp nodes. */
 1899                         xorNodes[0].params[2 * (numDataNodes + 1 + i) + 0] =
 1900                             writeDataNodes[i].params[0]; /* pda */
 1901                         xorNodes[0].params[2 * (numDataNodes + 1 + i) + 1] =
 1902                             writeDataNodes[i].params[1]; /* buffer pointer */
 1903                 }
 1904                 xorNodes[0].params[2 * (numDataNodes + numDataNodes + 1)].p =
 1905                     raidPtr;    /* xor node needs to get at RAID information */
 1906                 xorNodes[0].results[0] = readParityNodes[0].params[1].p;
 1907                 if (nfaults == 2) {
 1908                         rf_InitNode(&qNodes[0], rf_wait, RF_FALSE, qfunc,
 1909                             undoFunc, NULL, numParityNodes,
 1910                             numParityNodes + numDataNodes,
 1911                             (2 * (numDataNodes + numDataNodes + 1) + 1),
 1912                             1, dag_h, qname, allocList);
 1913                         for (i = 0; i < numDataNodes; i++) {
 1914                                 /* Set up params related to Rod. */
 1915                                 /* pda */
 1916                                 qNodes[0].params[2 * i + 0] =
 1917                                     readDataNodes[i].params[0];
 1918                                 /* buffer pointer */
 1919                                 qNodes[0].params[2 * i + 1] =
 1920                                     readDataNodes[i].params[1];
 1921                         }
 1922                         /* And read old q. */
 1923                         qNodes[0].params[2 * numDataNodes + 0] =
 1924                             readQNodes[0].params[0];    /* pda */
 1925                         qNodes[0].params[2 * numDataNodes + 1] =
 1926                             readQNodes[0].params[1];    /* buffer pointer */
 1927                         for (i = 0; i < numDataNodes; i++) {
 1928                                 /* Set up params related to Wnd nodes. */
 1929                                 /* pda */
 1930                                 qNodes[0].params
 1931                                     [2 * (numDataNodes + 1 + i) + 0] =
 1932                                     writeDataNodes[i].params[0];
 1933                                 /* buffer pointer */
 1934                                 qNodes[0].params
 1935                                     [2 * (numDataNodes + 1 + i) + 1] =
 1936                                     writeDataNodes[i].params[1];
 1937                         }
 1938                         /* Xor node needs to get at RAID information. */
 1939                         qNodes[0].params
 1940                             [2 * (numDataNodes + numDataNodes + 1)].p =
 1941                             raidPtr;
 1942                         qNodes[0].results[0] = readQNodes[0].params[1].p;
 1943                 }
 1944         }
 1945 
 1946         /* Initialize nodes which write new parity (Wnp). */
 1947         pda = asmap->parityInfo;
 1948         for (i = 0; i < numParityNodes; i++) {
 1949                 rf_InitNode(&writeParityNodes[i], rf_wait, RF_FALSE,
 1950                     rf_DiskWriteFunc, rf_DiskWriteUndoFunc,
 1951                     rf_GenericWakeupFunc, 1, numParityNodes,
 1952                     4, 0, dag_h, "Wnp", allocList);
 1953                 RF_ASSERT(pda != NULL);
 1954                 /* Param 1 (bufPtr) filled in by xor node. */
 1955                 writeParityNodes[i].params[0].p = pda;
 1956                 /* Buffer pointer for parity write operation. */
 1957                 writeParityNodes[i].params[1].p = xorNodes[i].results[0];
 1958                 writeParityNodes[i].params[2].v = parityStripeID;
 1959                 writeParityNodes[i].params[3].v =
 1960                     RF_CREATE_PARAM3(RF_IO_NORMAL_PRIORITY, 0, 0, which_ru);
 1961 
 1962                 if (lu_flag) {
 1963                         /* Initialize node to unlock the disk queue. */
 1964                         rf_InitNode(&unlockParityNodes[i], rf_wait, RF_FALSE,
 1965                             rf_DiskUnlockFunc, rf_DiskUnlockUndoFunc,
 1966                             rf_GenericWakeupFunc, 1, 1, 2, 0, dag_h,
 1967                             "Unp", allocList);
 1968                         unlockParityNodes[i].params[0].p =
 1969                             pda;        /* Physical disk addr desc. */
 1970                         unlockParityNodes[i].params[1].v =
 1971                             RF_CREATE_PARAM3(RF_IO_NORMAL_PRIORITY,
 1972                             0, lu_flag, which_ru);
 1973                 }
 1974                 pda = pda->next;
 1975         }
 1976 
 1977         /* Initialize nodes which write new Q (Wnq). */
 1978         if (nfaults == 2) {
 1979                 pda = asmap->qInfo;
 1980                 for (i = 0; i < numParityNodes; i++) {
 1981                         rf_InitNode(&writeQNodes[i], rf_wait, RF_FALSE,
 1982                             rf_DiskWriteFunc, rf_DiskWriteUndoFunc,
 1983                             rf_GenericWakeupFunc, 1, numParityNodes,
 1984                             4, 0, dag_h, "Wnq", allocList);
 1985                         RF_ASSERT(pda != NULL);
 1986                         /* Param 1 (bufPtr) filled in by xor node. */
 1987                         writeQNodes[i].params[0].p = pda;
 1988                         /* Buffer pointer for parity write operation. */
 1989                         writeQNodes[i].params[1].p = qNodes[i].results[0];
 1990                         writeQNodes[i].params[2].v = parityStripeID;
 1991                         writeQNodes[i].params[3].v =
 1992                             RF_CREATE_PARAM3(RF_IO_NORMAL_PRIORITY,
 1993                             0, 0, which_ru);
 1994 
 1995                         if (lu_flag) {
 1996                                 /* Initialize node to unlock the disk queue. */
 1997                                 rf_InitNode(&unlockQNodes[i], rf_wait,
 1998                                     RF_FALSE, rf_DiskUnlockFunc,
 1999                                     rf_DiskUnlockUndoFunc,
 2000                                     rf_GenericWakeupFunc, 1, 1, 2, 0,
 2001                                     dag_h, "Unq", allocList);
 2002                                 /* Physical disk addr desc. */
 2003                                 unlockQNodes[i].params[0].p = pda;
 2004                                 unlockQNodes[i].params[1].v =
 2005                                     RF_CREATE_PARAM3(RF_IO_NORMAL_PRIORITY,
 2006                                     0, lu_flag, which_ru);
 2007                         }
 2008                         pda = pda->next;
 2009                 }
 2010         }
 2011         /* Step 4. Connect the nodes. */
 2012 
 2013         /* Connect header to block node. */
 2014         dag_h->succedents[0] = blockNode;
 2015 
 2016         /* Connect block node to read old data nodes. */
 2017         RF_ASSERT(blockNode->numSuccedents ==
 2018             (numDataNodes + (numParityNodes * nfaults)));
 2019         for (i = 0; i < numDataNodes; i++) {
 2020                 blockNode->succedents[i] = &readDataNodes[i];
 2021                 RF_ASSERT(readDataNodes[i].numAntecedents == 1);
 2022                 readDataNodes[i].antecedents[0] = blockNode;
 2023                 readDataNodes[i].antType[0] = rf_control;
 2024         }
 2025 
 2026         /* Connect block node to read old parity nodes. */
 2027         for (i = 0; i < numParityNodes; i++) {
 2028                 blockNode->succedents[numDataNodes + i] = &readParityNodes[i];
 2029                 RF_ASSERT(readParityNodes[i].numAntecedents == 1);
 2030                 readParityNodes[i].antecedents[0] = blockNode;
 2031                 readParityNodes[i].antType[0] = rf_control;
 2032         }
 2033 
 2034         /* Connect block node to read old Q nodes. */
 2035         if (nfaults == 2)
 2036                 for (i = 0; i < numParityNodes; i++) {
 2037                         blockNode->succedents[numDataNodes +
 2038                             numParityNodes + i] = &readQNodes[i];
 2039                         RF_ASSERT(readQNodes[i].numAntecedents == 1);
 2040                         readQNodes[i].antecedents[0] = blockNode;
 2041                         readQNodes[i].antType[0] = rf_control;
 2042                 }
 2043 
 2044         /* Connect read old data nodes to write new data nodes. */
 2045         for (i = 0; i < numDataNodes; i++) {
 2046                 RF_ASSERT(readDataNodes[i].numSuccedents ==
 2047                     ((nfaults * numParityNodes) + 1));
 2048                 RF_ASSERT(writeDataNodes[i].numAntecedents == 1);
 2049                 readDataNodes[i].succedents[0] = &writeDataNodes[i];
 2050                 writeDataNodes[i].antecedents[0] = &readDataNodes[i];
 2051                 writeDataNodes[i].antType[0] = rf_antiData;
 2052         }
 2053 
 2054         /* Connect read old data nodes to xor nodes. */
 2055         for (i = 0; i < numDataNodes; i++) {
 2056                 for (j = 0; j < numParityNodes; j++) {
 2057                         RF_ASSERT(xorNodes[j].numAntecedents ==
 2058                             numDataNodes + numParityNodes);
 2059                         readDataNodes[i].succedents[1 + j] = &xorNodes[j];
 2060                         xorNodes[j].antecedents[i] = &readDataNodes[i];
 2061                         xorNodes[j].antType[i] = rf_trueData;
 2062                 }
 2063         }
 2064 
 2065         /* Connect read old data nodes to q nodes. */
 2066         if (nfaults == 2)
 2067                 for (i = 0; i < numDataNodes; i++)
 2068                         for (j = 0; j < numParityNodes; j++) {
 2069                                 RF_ASSERT(qNodes[j].numAntecedents ==
 2070                                     numDataNodes + numParityNodes);
 2071                                 readDataNodes[i].succedents
 2072                                     [1 + numParityNodes + j] = &qNodes[j];
 2073                                 qNodes[j].antecedents[i] = &readDataNodes[i];
 2074                                 qNodes[j].antType[i] = rf_trueData;
 2075                         }
 2076 
 2077         /* Connect read old parity nodes to xor nodes. */
 2078         for (i = 0; i < numParityNodes; i++) {
 2079                 for (j = 0; j < numParityNodes; j++) {
 2080                         RF_ASSERT(readParityNodes[i].numSuccedents ==
 2081                             numParityNodes);
 2082                         readParityNodes[i].succedents[j] = &xorNodes[j];
 2083                         xorNodes[j].antecedents[numDataNodes + i] =
 2084                             &readParityNodes[i];
 2085                         xorNodes[j].antType[numDataNodes + i] = rf_trueData;
 2086                 }
 2087         }
 2088 
 2089         /* Connect read old q nodes to q nodes. */
 2090         if (nfaults == 2)
 2091                 for (i = 0; i < numParityNodes; i++) {
 2092                         for (j = 0; j < numParityNodes; j++) {
 2093                                 RF_ASSERT(readQNodes[i].numSuccedents ==
 2094                                     numParityNodes);
 2095                                 readQNodes[i].succedents[j] = &qNodes[j];
 2096                                 qNodes[j].antecedents[numDataNodes + i] =
 2097                                     &readQNodes[i];
 2098                                 qNodes[j].antType[numDataNodes + i] =
 2099                                     rf_trueData;
 2100                         }
 2101                 }
 2102 
 2103         /* Connect xor nodes to the write new parity nodes. */
 2104         for (i = 0; i < numParityNodes; i++) {
 2105                 RF_ASSERT(writeParityNodes[i].numAntecedents == numParityNodes);
 2106                 for (j = 0; j < numParityNodes; j++) {
 2107                         RF_ASSERT(xorNodes[j].numSuccedents == numParityNodes);
 2108                         xorNodes[i].succedents[j] = &writeParityNodes[j];
 2109                         writeParityNodes[j].antecedents[i] = &xorNodes[i];
 2110                         writeParityNodes[j].antType[i] = rf_trueData;
 2111                 }
 2112         }
 2113 
 2114         /* Connect q nodes to the write new q nodes. */
 2115         if (nfaults == 2)
 2116                 for (i = 0; i < numParityNodes; i++) {
 2117                         RF_ASSERT(writeQNodes[i].numAntecedents ==
 2118                             numParityNodes);
 2119                         for (j = 0; j < numParityNodes; j++) {
 2120                                 RF_ASSERT(qNodes[j].numSuccedents == 1);
 2121                                 qNodes[i].succedents[j] = &writeQNodes[j];
 2122                                 writeQNodes[j].antecedents[i] = &qNodes[i];
 2123                                 writeQNodes[j].antType[i] = rf_trueData;
 2124                         }
 2125                 }
 2126 
 2127         RF_ASSERT(termNode->numAntecedents ==
 2128             (numDataNodes + (nfaults * numParityNodes)));
 2129         RF_ASSERT(termNode->numSuccedents == 0);
 2130         for (i = 0; i < numDataNodes; i++) {
 2131                 if (lu_flag) {
 2132                         /* Connect write new data nodes to unlock nodes. */
 2133                         RF_ASSERT(writeDataNodes[i].numSuccedents == 1);
 2134                         RF_ASSERT(unlockDataNodes[i].numAntecedents == 1);
 2135                         writeDataNodes[i].succedents[0] = &unlockDataNodes[i];
 2136                         unlockDataNodes[i].antecedents[0] = &writeDataNodes[i];
 2137                         unlockDataNodes[i].antType[0] = rf_control;
 2138 
 2139                         /* Connect unlock nodes to term nodes. */
 2140                         RF_ASSERT(unlockDataNodes[i].numSuccedents == 1);
 2141                         unlockDataNodes[i].succedents[0] = termNode;
 2142                         termNode->antecedents[i] = &unlockDataNodes[i];
 2143                         termNode->antType[i] = rf_control;
 2144                 } else {
 2145                         /* Connect write new data nodes to term node. */
 2146                         RF_ASSERT(writeDataNodes[i].numSuccedents == 1);
 2147                         RF_ASSERT(termNode->numAntecedents ==
 2148                             (numDataNodes + (nfaults * numParityNodes)));
 2149                         writeDataNodes[i].succedents[0] = termNode;
 2150                         termNode->antecedents[i] = &writeDataNodes[i];
 2151                         termNode->antType[i] = rf_control;
 2152                 }
 2153         }
 2154 
 2155         for (i = 0; i < numParityNodes; i++) {
 2156                 if (lu_flag) {
 2157                         /* Connect write new parity nodes to unlock nodes. */
 2158                         RF_ASSERT(writeParityNodes[i].numSuccedents == 1);
 2159                         RF_ASSERT(unlockParityNodes[i].numAntecedents == 1);
 2160                         writeParityNodes[i].succedents[0] =
 2161                             &unlockParityNodes[i];
 2162                         unlockParityNodes[i].antecedents[0] =
 2163                             &writeParityNodes[i];
 2164                         unlockParityNodes[i].antType[0] = rf_control;
 2165 
 2166                         /* Connect unlock nodes to term node. */
 2167                         RF_ASSERT(unlockParityNodes[i].numSuccedents == 1);
 2168                         unlockParityNodes[i].succedents[0] = termNode;
 2169                         termNode->antecedents[numDataNodes + i] =
 2170                             &unlockParityNodes[i];
 2171                         termNode->antType[numDataNodes + i] = rf_control;
 2172                 } else {
 2173                         RF_ASSERT(writeParityNodes[i].numSuccedents == 1);
 2174                         writeParityNodes[i].succedents[0] = termNode;
 2175                         termNode->antecedents[numDataNodes + i] =
 2176                             &writeParityNodes[i];
 2177                         termNode->antType[numDataNodes + i] = rf_control;
 2178                 }
 2179         }
 2180 
 2181         if (nfaults == 2)
 2182                 for (i = 0; i < numParityNodes; i++) {
 2183                         if (lu_flag) {
 2184                                 /* Connect write new Q nodes to unlock nodes. */
 2185                                 RF_ASSERT(writeQNodes[i].numSuccedents == 1);
 2186                                 RF_ASSERT(unlockQNodes[i].numAntecedents == 1);
 2187                                 writeQNodes[i].succedents[0] = &unlockQNodes[i];
 2188                                 unlockQNodes[i].antecedents[0] =
 2189                                     &writeQNodes[i];
 2190                                 unlockQNodes[i].antType[0] = rf_control;
 2191 
 2192                                 /* Connect unlock nodes to unblock node. */
 2193                                 RF_ASSERT(unlockQNodes[i].numSuccedents == 1);
 2194                                 unlockQNodes[i].succedents[0] = termNode;
 2195                                 termNode->antecedents[numDataNodes +
 2196                                     numParityNodes + i] = &unlockQNodes[i];
 2197                                 termNode->antType[numDataNodes +
 2198                                     numParityNodes + i] = rf_control;
 2199                         } else {
 2200                                 RF_ASSERT(writeQNodes[i].numSuccedents == 1);
 2201                                 writeQNodes[i].succedents[0] = termNode;
 2202                                 termNode->antecedents[numDataNodes +
 2203                                     numParityNodes + i] = &writeQNodes[i];
 2204                                 termNode->antType[numDataNodes +
 2205                                     numParityNodes + i] = rf_control;
 2206                         }
 2207                 }
 2208 }
 2209 
 2210 
 2211 
 2212 /*****************************************************************************
 2213  * Create a write graph (fault-free or degraded) for RAID level 1.
 2214  *
 2215  * Hdr  Nil -> Wpd -> Nil -> Trm
 2216  *      Nil -> Wsd ->
 2217  *
 2218  * The "Wpd" node writes data to the primary copy in the mirror pair.
 2219  * The "Wsd" node writes data to the secondary copy in the mirror pair.
 2220  *
 2221  * Parameters:  raidPtr   - description of the physical array
 2222  *              asmap     - logical & physical addresses for this access
 2223  *              bp        - buffer ptr (holds write data)
 2224  *              flags     - general flags (e.g. disk locking)
 2225  *              allocList - list of memory allocated in DAG creation
 2226  *****************************************************************************/
 2227 
 2228 void
 2229 rf_CreateRaidOneWriteDAGFwd(RF_Raid_t *raidPtr, RF_AccessStripeMap_t *asmap,
 2230     RF_DagHeader_t *dag_h, void *bp, RF_RaidAccessFlags_t flags,
 2231     RF_AllocListElem_t *allocList)
 2232 {
 2233         RF_DagNode_t *blockNode, *unblockNode, *termNode;
 2234         RF_DagNode_t *nodes, *wndNode, *wmirNode;
 2235         int nWndNodes, nWmirNodes, i;
 2236         RF_ReconUnitNum_t which_ru;
 2237         RF_PhysDiskAddr_t *pda, *pdaP;
 2238         RF_StripeNum_t parityStripeID;
 2239 
 2240         parityStripeID = rf_RaidAddressToParityStripeID(&(raidPtr->Layout),
 2241             asmap->raidAddress, &which_ru);
 2242         if (rf_dagDebug) {
 2243                 printf("[Creating RAID level 1 write DAG]\n");
 2244         }
 2245         /* 2 implies access not SU aligned. */
 2246         nWmirNodes = (asmap->parityInfo->next) ? 2 : 1;
 2247         nWndNodes = (asmap->physInfo->next) ? 2 : 1;
 2248 
 2249         /* Alloc the Wnd nodes and the Wmir node. */
 2250         if (asmap->numDataFailed == 1)
 2251                 nWndNodes--;
 2252         if (asmap->numParityFailed == 1)
 2253                 nWmirNodes--;
 2254 
 2255         /*
 2256          * Total number of nodes = nWndNodes + nWmirNodes +
 2257          *                         (block + unblock + terminator)
 2258          */
 2259         RF_CallocAndAdd(nodes, nWndNodes + nWmirNodes + 3,
 2260             sizeof(RF_DagNode_t), (RF_DagNode_t *), allocList);
 2261         i = 0;
 2262         wndNode = &nodes[i];
 2263         i += nWndNodes;
 2264         wmirNode = &nodes[i];
 2265         i += nWmirNodes;
 2266         blockNode = &nodes[i];
 2267         i += 1;
 2268         unblockNode = &nodes[i];
 2269         i += 1;
 2270         termNode = &nodes[i];
 2271         i += 1;
 2272         RF_ASSERT(i == (nWndNodes + nWmirNodes + 3));
 2273 
 2274         /* This dag can commit immediately. */
 2275         dag_h->numCommitNodes = 0;
 2276         dag_h->numCommits = 0;
 2277         dag_h->numSuccedents = 1;
 2278 
 2279         /* Initialize the unblock and term nodes. */
 2280         rf_InitNode(blockNode, rf_wait, RF_FALSE, rf_NullNodeFunc,
 2281             rf_NullNodeUndoFunc, NULL, (nWndNodes + nWmirNodes),
 2282             0, 0, 0, dag_h, "Nil", allocList);
 2283         rf_InitNode(unblockNode, rf_wait, RF_FALSE, rf_NullNodeFunc,
 2284             rf_NullNodeUndoFunc, NULL, 1, (nWndNodes + nWmirNodes),
 2285             0, 0, dag_h, "Nil", allocList);
 2286         rf_InitNode(termNode, rf_wait, RF_FALSE, rf_TerminateFunc,
 2287             rf_TerminateUndoFunc, NULL, 0, 1, 0, 0, dag_h, "Trm", allocList);
 2288 
 2289         /* Initialize the wnd nodes. */
 2290         if (nWndNodes > 0) {
 2291                 pda = asmap->physInfo;
 2292                 for (i = 0; i < nWndNodes; i++) {
 2293                         rf_InitNode(&wndNode[i], rf_wait, RF_FALSE,
 2294                             rf_DiskWriteFunc, rf_DiskWriteUndoFunc,
 2295                             rf_GenericWakeupFunc, 1, 1, 4, 0, dag_h,
 2296                             "Wpd", allocList);
 2297                         RF_ASSERT(pda != NULL);
 2298                         wndNode[i].params[0].p = pda;
 2299                         wndNode[i].params[1].p = pda->bufPtr;
 2300                         wndNode[i].params[2].v = parityStripeID;
 2301                         wndNode[i].params[3].v =
 2302                             RF_CREATE_PARAM3(RF_IO_NORMAL_PRIORITY,
 2303                             0, 0, which_ru);
 2304                         pda = pda->next;
 2305                 }
 2306                 RF_ASSERT(pda == NULL);
 2307         }
 2308         /* Initialize the mirror nodes. */
 2309         if (nWmirNodes > 0) {
 2310                 pda = asmap->physInfo;
 2311                 pdaP = asmap->parityInfo;
 2312                 for (i = 0; i < nWmirNodes; i++) {
 2313                         rf_InitNode(&wmirNode[i], rf_wait, RF_FALSE,
 2314                             rf_DiskWriteFunc, rf_DiskWriteUndoFunc,
 2315                             rf_GenericWakeupFunc, 1, 1, 4, 0, dag_h,
 2316                             "Wsd", allocList);
 2317                         RF_ASSERT(pda != NULL);
 2318                         wmirNode[i].params[0].p = pdaP;
 2319                         wmirNode[i].params[1].p = pda->bufPtr;
 2320                         wmirNode[i].params[2].v = parityStripeID;
 2321                         wmirNode[i].params[3].v =
 2322                             RF_CREATE_PARAM3(RF_IO_NORMAL_PRIORITY,
 2323                             0, 0, which_ru);
 2324                         pda = pda->next;
 2325                         pdaP = pdaP->next;
 2326                 }
 2327                 RF_ASSERT(pda == NULL);
 2328                 RF_ASSERT(pdaP == NULL);
 2329         }
 2330         /* Link the header node to the block node. */
 2331         RF_ASSERT(dag_h->numSuccedents == 1);
 2332         RF_ASSERT(blockNode->numAntecedents == 0);
 2333         dag_h->succedents[0] = blockNode;
 2334 
 2335         /* Link the block node to the write nodes. */
 2336         RF_ASSERT(blockNode->numSuccedents == (nWndNodes + nWmirNodes));
 2337         for (i = 0; i < nWndNodes; i++) {
 2338                 RF_ASSERT(wndNode[i].numAntecedents == 1);
 2339                 blockNode->succedents[i] = &wndNode[i];
 2340                 wndNode[i].antecedents[0] = blockNode;
 2341                 wndNode[i].antType[0] = rf_control;
 2342         }
 2343         for (i = 0; i < nWmirNodes; i++) {
 2344                 RF_ASSERT(wmirNode[i].numAntecedents == 1);
 2345                 blockNode->succedents[i + nWndNodes] = &wmirNode[i];
 2346                 wmirNode[i].antecedents[0] = blockNode;
 2347                 wmirNode[i].antType[0] = rf_control;
 2348         }
 2349 
 2350         /* Link the write nodes to the unblock node. */
 2351         RF_ASSERT(unblockNode->numAntecedents == (nWndNodes + nWmirNodes));
 2352         for (i = 0; i < nWndNodes; i++) {
 2353                 RF_ASSERT(wndNode[i].numSuccedents == 1);
 2354                 wndNode[i].succedents[0] = unblockNode;
 2355                 unblockNode->antecedents[i] = &wndNode[i];
 2356                 unblockNode->antType[i] = rf_control;
 2357         }
 2358         for (i = 0; i < nWmirNodes; i++) {
 2359                 RF_ASSERT(wmirNode[i].numSuccedents == 1);
 2360                 wmirNode[i].succedents[0] = unblockNode;
 2361                 unblockNode->antecedents[i + nWndNodes] = &wmirNode[i];
 2362                 unblockNode->antType[i + nWndNodes] = rf_control;
 2363         }
 2364 
 2365         /* Link the unblock node to the term node. */
 2366         RF_ASSERT(unblockNode->numSuccedents == 1);
 2367         RF_ASSERT(termNode->numAntecedents == 1);
 2368         RF_ASSERT(termNode->numSuccedents == 0);
 2369         unblockNode->succedents[0] = termNode;
 2370         termNode->antecedents[0] = unblockNode;
 2371         termNode->antType[0] = rf_control;
 2372 
 2373         return;
 2374 }

/* [<][>][^][v][top][bottom][index][help] */