Home | History | Annotate | Line # | Download | only in raidframe
rf_paritylog.c revision 1.2
      1  1.2  oster /*	$NetBSD: rf_paritylog.c,v 1.2 1999/01/26 02:33:59 oster Exp $	*/
      2  1.1  oster /*
      3  1.1  oster  * Copyright (c) 1995 Carnegie-Mellon University.
      4  1.1  oster  * All rights reserved.
      5  1.1  oster  *
      6  1.1  oster  * Author: William V. Courtright II
      7  1.1  oster  *
      8  1.1  oster  * Permission to use, copy, modify and distribute this software and
      9  1.1  oster  * its documentation is hereby granted, provided that both the copyright
     10  1.1  oster  * notice and this permission notice appear in all copies of the
     11  1.1  oster  * software, derivative works or modified versions, and any portions
     12  1.1  oster  * thereof, and that both notices appear in supporting documentation.
     13  1.1  oster  *
     14  1.1  oster  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
     15  1.1  oster  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
     16  1.1  oster  * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
     17  1.1  oster  *
     18  1.1  oster  * Carnegie Mellon requests users of this software to return to
     19  1.1  oster  *
     20  1.1  oster  *  Software Distribution Coordinator  or  Software.Distribution (at) CS.CMU.EDU
     21  1.1  oster  *  School of Computer Science
     22  1.1  oster  *  Carnegie Mellon University
     23  1.1  oster  *  Pittsburgh PA 15213-3890
     24  1.1  oster  *
     25  1.1  oster  * any improvements or extensions that they make and grant Carnegie the
     26  1.1  oster  * rights to redistribute these changes.
     27  1.1  oster  */
     28  1.1  oster 
     29  1.1  oster /* Code for manipulating in-core parity logs
     30  1.1  oster  *
     31  1.1  oster  */
     32  1.1  oster 
     33  1.1  oster #include "rf_archs.h"
     34  1.1  oster 
     35  1.1  oster #if RF_INCLUDE_PARITYLOGGING > 0
     36  1.1  oster 
     37  1.1  oster /*
     38  1.1  oster  * Append-only log for recording parity "update" and "overwrite" records
     39  1.1  oster  */
     40  1.1  oster 
     41  1.1  oster #include "rf_types.h"
     42  1.1  oster #include "rf_threadstuff.h"
     43  1.1  oster #include "rf_mcpair.h"
     44  1.1  oster #include "rf_raid.h"
     45  1.1  oster #include "rf_dag.h"
     46  1.1  oster #include "rf_dagfuncs.h"
     47  1.1  oster #include "rf_desc.h"
     48  1.1  oster #include "rf_layout.h"
     49  1.1  oster #include "rf_diskqueue.h"
     50  1.1  oster #include "rf_etimer.h"
     51  1.1  oster #include "rf_paritylog.h"
     52  1.1  oster #include "rf_general.h"
     53  1.1  oster #include "rf_threadid.h"
     54  1.1  oster #include "rf_map.h"
     55  1.1  oster #include "rf_paritylogging.h"
     56  1.1  oster #include "rf_paritylogDiskMgr.h"
     57  1.1  oster #include "rf_sys.h"
     58  1.1  oster 
     59  1.1  oster static RF_CommonLogData_t *AllocParityLogCommonData(RF_Raid_t *raidPtr)
     60  1.1  oster {
     61  1.1  oster   RF_CommonLogData_t *common = NULL;
     62  1.1  oster   int rc;
     63  1.1  oster 
     64  1.1  oster   /* Return a struct for holding common parity log information from the free
     65  1.1  oster      list (rf_parityLogDiskQueue.freeCommonList).  If the free list is empty, call
     66  1.1  oster      RF_Malloc to create a new structure.
     67  1.1  oster      NON-BLOCKING */
     68  1.1  oster 
     69  1.1  oster   RF_LOCK_MUTEX(raidPtr->parityLogDiskQueue.mutex);
     70  1.1  oster   if (raidPtr->parityLogDiskQueue.freeCommonList)
     71  1.1  oster     {
     72  1.1  oster       common = raidPtr->parityLogDiskQueue.freeCommonList;
     73  1.1  oster       raidPtr->parityLogDiskQueue.freeCommonList = raidPtr->parityLogDiskQueue.freeCommonList->next;
     74  1.1  oster       RF_UNLOCK_MUTEX(raidPtr->parityLogDiskQueue.mutex);
     75  1.1  oster     }
     76  1.1  oster   else
     77  1.1  oster     {
     78  1.1  oster       RF_UNLOCK_MUTEX(raidPtr->parityLogDiskQueue.mutex);
     79  1.1  oster       RF_Malloc(common, sizeof(RF_CommonLogData_t), (RF_CommonLogData_t *));
     80  1.1  oster       rc = rf_mutex_init(&common->mutex);
     81  1.1  oster       if (rc) {
     82  1.1  oster         RF_ERRORMSG3("Unable to init mutex file %s line %d rc=%d\n", __FILE__,
     83  1.1  oster           __LINE__, rc);
     84  1.1  oster         RF_Free(common, sizeof(RF_CommonLogData_t));
     85  1.1  oster         common = NULL;
     86  1.1  oster       }
     87  1.1  oster     }
     88  1.1  oster   common->next = NULL;
     89  1.1  oster   return(common);
     90  1.1  oster }
     91  1.1  oster 
     92  1.1  oster static void FreeParityLogCommonData(RF_CommonLogData_t *common)
     93  1.1  oster {
     94  1.1  oster   RF_Raid_t *raidPtr;
     95  1.1  oster 
     96  1.1  oster   /* Insert a single struct for holding parity log information
     97  1.1  oster      (data) into the free list (rf_parityLogDiskQueue.freeCommonList).
     98  1.1  oster      NON-BLOCKING */
     99  1.1  oster 
    100  1.1  oster   raidPtr = common->raidPtr;
    101  1.1  oster   RF_LOCK_MUTEX(raidPtr->parityLogDiskQueue.mutex);
    102  1.1  oster   common->next = raidPtr->parityLogDiskQueue.freeCommonList;
    103  1.1  oster   raidPtr->parityLogDiskQueue.freeCommonList = common;
    104  1.1  oster   RF_UNLOCK_MUTEX(raidPtr->parityLogDiskQueue.mutex);
    105  1.1  oster }
    106  1.1  oster 
    107  1.1  oster static RF_ParityLogData_t *AllocParityLogData(RF_Raid_t *raidPtr)
    108  1.1  oster {
    109  1.1  oster   RF_ParityLogData_t *data = NULL;
    110  1.1  oster 
    111  1.1  oster   /* Return a struct for holding parity log information from the free
    112  1.1  oster      list (rf_parityLogDiskQueue.freeList).  If the free list is empty, call
    113  1.1  oster      RF_Malloc to create a new structure.
    114  1.1  oster      NON-BLOCKING */
    115  1.1  oster 
    116  1.1  oster   RF_LOCK_MUTEX(raidPtr->parityLogDiskQueue.mutex);
    117  1.1  oster   if (raidPtr->parityLogDiskQueue.freeDataList)
    118  1.1  oster     {
    119  1.1  oster       data = raidPtr->parityLogDiskQueue.freeDataList;
    120  1.1  oster       raidPtr->parityLogDiskQueue.freeDataList = raidPtr->parityLogDiskQueue.freeDataList->next;
    121  1.1  oster       RF_UNLOCK_MUTEX(raidPtr->parityLogDiskQueue.mutex);
    122  1.1  oster     }
    123  1.1  oster   else
    124  1.1  oster     {
    125  1.1  oster       RF_UNLOCK_MUTEX(raidPtr->parityLogDiskQueue.mutex);
    126  1.1  oster       RF_Malloc(data, sizeof(RF_ParityLogData_t), (RF_ParityLogData_t *));
    127  1.1  oster     }
    128  1.1  oster   data->next = NULL;
    129  1.1  oster   data->prev = NULL;
    130  1.1  oster   return(data);
    131  1.1  oster }
    132  1.1  oster 
    133  1.1  oster 
    134  1.1  oster static void FreeParityLogData(RF_ParityLogData_t *data)
    135  1.1  oster {
    136  1.1  oster   RF_ParityLogData_t *nextItem;
    137  1.1  oster   RF_Raid_t *raidPtr;
    138  1.1  oster 
    139  1.1  oster   /* Insert a linked list of structs for holding parity log
    140  1.1  oster      information (data) into the free list (parityLogDiskQueue.freeList).
    141  1.1  oster      NON-BLOCKING */
    142  1.1  oster 
    143  1.1  oster   raidPtr = data->common->raidPtr;
    144  1.1  oster   RF_LOCK_MUTEX(raidPtr->parityLogDiskQueue.mutex);
    145  1.1  oster   while (data)
    146  1.1  oster     {
    147  1.1  oster       nextItem = data->next;
    148  1.1  oster       data->next = raidPtr->parityLogDiskQueue.freeDataList;
    149  1.1  oster       raidPtr->parityLogDiskQueue.freeDataList = data;
    150  1.1  oster       data = nextItem;
    151  1.1  oster     }
    152  1.1  oster   RF_UNLOCK_MUTEX(raidPtr->parityLogDiskQueue.mutex);
    153  1.1  oster }
    154  1.1  oster 
    155  1.1  oster 
    156  1.1  oster static void EnqueueParityLogData(
    157  1.1  oster   RF_ParityLogData_t   *data,
    158  1.1  oster   RF_ParityLogData_t  **head,
    159  1.1  oster   RF_ParityLogData_t  **tail)
    160  1.1  oster {
    161  1.1  oster   RF_Raid_t *raidPtr;
    162  1.1  oster 
    163  1.1  oster   /* Insert an in-core parity log (*data) into the head of
    164  1.1  oster      a disk queue (*head, *tail).
    165  1.1  oster      NON-BLOCKING */
    166  1.1  oster 
    167  1.1  oster   raidPtr = data->common->raidPtr;
    168  1.1  oster   if (rf_parityLogDebug)
    169  1.1  oster     printf("[enqueueing parity log data, region %d, raidAddress %d, numSector %d]\n",data->regionID,(int)data->diskAddress.raidAddress, (int)data->diskAddress.numSector);
    170  1.1  oster   RF_ASSERT(data->prev == NULL);
    171  1.1  oster   RF_ASSERT(data->next == NULL);
    172  1.1  oster   RF_LOCK_MUTEX(raidPtr->parityLogDiskQueue.mutex);
    173  1.1  oster   if (*head)
    174  1.1  oster     {
    175  1.1  oster       /* insert into head of queue */
    176  1.1  oster       RF_ASSERT((*head)->prev == NULL);
    177  1.1  oster       RF_ASSERT((*tail)->next == NULL);
    178  1.1  oster       data->next = *head;
    179  1.1  oster       (*head)->prev = data;
    180  1.1  oster       *head = data;
    181  1.1  oster     }
    182  1.1  oster   else
    183  1.1  oster     {
    184  1.1  oster       /* insert into empty list */
    185  1.1  oster       RF_ASSERT(*head == NULL);
    186  1.1  oster       RF_ASSERT(*tail == NULL);
    187  1.1  oster       *head = data;
    188  1.1  oster       *tail = data;
    189  1.1  oster     }
    190  1.1  oster   RF_ASSERT((*head)->prev == NULL);
    191  1.1  oster   RF_ASSERT((*tail)->next == NULL);
    192  1.1  oster   RF_UNLOCK_MUTEX(raidPtr->parityLogDiskQueue.mutex);
    193  1.1  oster }
    194  1.1  oster 
    195  1.1  oster static RF_ParityLogData_t *DequeueParityLogData(
    196  1.1  oster   RF_Raid_t            *raidPtr,
    197  1.1  oster   RF_ParityLogData_t  **head,
    198  1.1  oster   RF_ParityLogData_t  **tail,
    199  1.1  oster   int                   ignoreLocks)
    200  1.1  oster {
    201  1.1  oster   RF_ParityLogData_t *data;
    202  1.1  oster 
    203  1.1  oster   /* Remove and return an in-core parity log from the tail of
    204  1.1  oster      a disk queue (*head, *tail).
    205  1.1  oster      NON-BLOCKING */
    206  1.1  oster 
    207  1.1  oster   /* remove from tail, preserving FIFO order */
    208  1.1  oster   if (!ignoreLocks)
    209  1.1  oster     RF_LOCK_MUTEX(raidPtr->parityLogDiskQueue.mutex);
    210  1.1  oster   data = *tail;
    211  1.1  oster   if (data)
    212  1.1  oster     {
    213  1.1  oster       if (*head == *tail)
    214  1.1  oster 	{
    215  1.1  oster 	  /* removing last item from queue */
    216  1.1  oster 	  *head = NULL;
    217  1.1  oster 	  *tail = NULL;
    218  1.1  oster 	}
    219  1.1  oster       else
    220  1.1  oster 	{
    221  1.1  oster 	  *tail = (*tail)->prev;
    222  1.1  oster 	  (*tail)->next = NULL;
    223  1.1  oster 	  RF_ASSERT((*head)->prev == NULL);
    224  1.1  oster 	  RF_ASSERT((*tail)->next == NULL);
    225  1.1  oster 	}
    226  1.1  oster       data->next = NULL;
    227  1.1  oster       data->prev = NULL;
    228  1.1  oster       if (rf_parityLogDebug)
    229  1.1  oster 	printf("[dequeueing parity log data, region %d, raidAddress %d, numSector %d]\n",data->regionID,(int)data->diskAddress.raidAddress, (int)data->diskAddress.numSector);
    230  1.1  oster     }
    231  1.1  oster   if (*head)
    232  1.1  oster     {
    233  1.1  oster       RF_ASSERT((*head)->prev == NULL);
    234  1.1  oster       RF_ASSERT((*tail)->next == NULL);
    235  1.1  oster     }
    236  1.1  oster   if (!ignoreLocks)
    237  1.1  oster     RF_UNLOCK_MUTEX(raidPtr->parityLogDiskQueue.mutex);
    238  1.1  oster   return(data);
    239  1.1  oster }
    240  1.1  oster 
    241  1.1  oster 
    242  1.1  oster static void RequeueParityLogData(
    243  1.1  oster   RF_ParityLogData_t   *data,
    244  1.1  oster   RF_ParityLogData_t  **head,
    245  1.1  oster   RF_ParityLogData_t  **tail)
    246  1.1  oster {
    247  1.1  oster   RF_Raid_t *raidPtr;
    248  1.1  oster 
    249  1.1  oster   /* Insert an in-core parity log (*data) into the tail of
    250  1.1  oster      a disk queue (*head, *tail).
    251  1.1  oster      NON-BLOCKING */
    252  1.1  oster 
    253  1.1  oster   raidPtr = data->common->raidPtr;
    254  1.1  oster   RF_ASSERT(data);
    255  1.1  oster   if (rf_parityLogDebug)
    256  1.1  oster     printf("[requeueing parity log data, region %d, raidAddress %d, numSector %d]\n",data->regionID,(int)data->diskAddress.raidAddress, (int) data->diskAddress.numSector);
    257  1.1  oster   RF_LOCK_MUTEX(raidPtr->parityLogDiskQueue.mutex);
    258  1.1  oster   if (*tail)
    259  1.1  oster     {
    260  1.1  oster       /* append to tail of list */
    261  1.1  oster       data->prev = *tail;
    262  1.1  oster       data->next = NULL;
    263  1.1  oster       (*tail)->next = data;
    264  1.1  oster       *tail = data;
    265  1.1  oster     }
    266  1.1  oster   else
    267  1.1  oster     {
    268  1.1  oster       /* inserting into an empty list */
    269  1.1  oster       *head = data;
    270  1.1  oster       *tail = data;
    271  1.1  oster       (*head)->prev = NULL;
    272  1.1  oster       (*tail)->next = NULL;
    273  1.1  oster     }
    274  1.1  oster   RF_ASSERT((*head)->prev == NULL);
    275  1.1  oster   RF_ASSERT((*tail)->next == NULL);
    276  1.1  oster   RF_UNLOCK_MUTEX(raidPtr->parityLogDiskQueue.mutex);
    277  1.1  oster }
    278  1.1  oster 
    279  1.1  oster RF_ParityLogData_t *rf_CreateParityLogData(
    280  1.1  oster   RF_ParityRecordType_t    operation,
    281  1.1  oster   RF_PhysDiskAddr_t       *pda,
    282  1.1  oster   caddr_t                  bufPtr,
    283  1.1  oster   RF_Raid_t               *raidPtr,
    284  1.1  oster   int                    (*wakeFunc)(RF_DagNode_t *node, int status),
    285  1.1  oster   void                    *wakeArg,
    286  1.1  oster   RF_AccTraceEntry_t      *tracerec,
    287  1.1  oster   RF_Etimer_t              startTime)
    288  1.1  oster {
    289  1.1  oster   RF_ParityLogData_t *data, *resultHead = NULL, *resultTail = NULL;
    290  1.1  oster   RF_CommonLogData_t *common;
    291  1.1  oster   RF_PhysDiskAddr_t *diskAddress;
    292  1.1  oster   int boundary, offset = 0;
    293  1.1  oster 
    294  1.1  oster   /* Return an initialized struct of info to be logged.
    295  1.1  oster      Build one item per physical disk address, one item per region.
    296  1.1  oster 
    297  1.1  oster      NON-BLOCKING */
    298  1.1  oster 
    299  1.1  oster   diskAddress = pda;
    300  1.1  oster   common = AllocParityLogCommonData(raidPtr);
    301  1.1  oster   RF_ASSERT(common);
    302  1.1  oster 
    303  1.1  oster   common->operation = operation;
    304  1.1  oster   common->bufPtr = bufPtr;
    305  1.1  oster   common->raidPtr = raidPtr;
    306  1.1  oster   common->wakeFunc = wakeFunc;
    307  1.1  oster   common->wakeArg = wakeArg;
    308  1.1  oster   common->tracerec = tracerec;
    309  1.1  oster   common->startTime = startTime;
    310  1.1  oster   common->cnt = 0;
    311  1.1  oster 
    312  1.1  oster   if (rf_parityLogDebug)
    313  1.1  oster     printf("[entering CreateParityLogData]\n");
    314  1.1  oster   while (diskAddress)
    315  1.1  oster     {
    316  1.1  oster       common->cnt++;
    317  1.1  oster       data = AllocParityLogData(raidPtr);
    318  1.1  oster       RF_ASSERT(data);
    319  1.1  oster       data->common = common;
    320  1.1  oster       data->next = NULL;
    321  1.1  oster       data->prev = NULL;
    322  1.1  oster       data->regionID = rf_MapRegionIDParityLogging(raidPtr, diskAddress->startSector);
    323  1.1  oster       if (data->regionID == rf_MapRegionIDParityLogging(raidPtr, diskAddress->startSector + diskAddress->numSector - 1))
    324  1.1  oster 	{
    325  1.1  oster 	  /* disk address does not cross a region boundary */
    326  1.1  oster 	  data->diskAddress = *diskAddress;
    327  1.1  oster 	  data->bufOffset = offset;
    328  1.1  oster 	  offset = offset + diskAddress->numSector;
    329  1.1  oster 	  EnqueueParityLogData(data, &resultHead, &resultTail);
    330  1.1  oster 	  /* adjust disk address */
    331  1.1  oster 	  diskAddress = diskAddress->next;
    332  1.1  oster 	}
    333  1.1  oster       else
    334  1.1  oster 	{
    335  1.1  oster 	  /* disk address crosses a region boundary */
    336  1.1  oster 	  /* find address where region is crossed */
    337  1.1  oster 	  boundary = 0;
    338  1.1  oster 	  while (data->regionID == rf_MapRegionIDParityLogging(raidPtr, diskAddress->startSector + boundary))
    339  1.1  oster 	    boundary++;
    340  1.1  oster 
    341  1.1  oster 	  /* enter data before the boundary */
    342  1.1  oster 	  data->diskAddress = *diskAddress;
    343  1.1  oster 	  data->diskAddress.numSector = boundary;
    344  1.1  oster 	  data->bufOffset = offset;
    345  1.1  oster 	  offset += boundary;
    346  1.1  oster 	  EnqueueParityLogData(data, &resultHead, &resultTail);
    347  1.1  oster 	  /* adjust disk address */
    348  1.1  oster 	  diskAddress->startSector += boundary;
    349  1.1  oster 	  diskAddress->numSector -= boundary;
    350  1.1  oster 	}
    351  1.1  oster     }
    352  1.1  oster   if (rf_parityLogDebug)
    353  1.1  oster     printf("[leaving CreateParityLogData]\n");
    354  1.1  oster   return(resultHead);
    355  1.1  oster }
    356  1.1  oster 
    357  1.1  oster 
    358  1.1  oster RF_ParityLogData_t *rf_SearchAndDequeueParityLogData(
    359  1.1  oster   RF_Raid_t            *raidPtr,
    360  1.1  oster   int                   regionID,
    361  1.1  oster   RF_ParityLogData_t  **head,
    362  1.1  oster   RF_ParityLogData_t  **tail,
    363  1.1  oster   int                   ignoreLocks)
    364  1.1  oster {
    365  1.1  oster   RF_ParityLogData_t *w;
    366  1.1  oster 
    367  1.1  oster   /* Remove and return an in-core parity log from a specified region (regionID).
    368  1.1  oster      If a matching log is not found, return NULL.
    369  1.1  oster 
    370  1.1  oster      NON-BLOCKING.
    371  1.1  oster      */
    372  1.1  oster 
    373  1.1  oster   /* walk backward through a list, looking for an entry with a matching region ID */
    374  1.1  oster   if (!ignoreLocks)
    375  1.1  oster     RF_LOCK_MUTEX(raidPtr->parityLogDiskQueue.mutex);
    376  1.1  oster   w = (*tail);
    377  1.1  oster   while (w)
    378  1.1  oster     {
    379  1.1  oster       if (w->regionID == regionID)
    380  1.1  oster 	{
    381  1.1  oster 	  /* remove an element from the list */
    382  1.1  oster 	  if (w == *tail)
    383  1.1  oster 	    {
    384  1.1  oster 	      if (*head == *tail)
    385  1.1  oster 		{
    386  1.1  oster 		  /* removing only element in the list */
    387  1.1  oster 		  *head = NULL;
    388  1.1  oster 		  *tail = NULL;
    389  1.1  oster 		}
    390  1.1  oster 	      else
    391  1.1  oster 		{
    392  1.1  oster 		  /* removing last item in the list */
    393  1.1  oster 		  *tail = (*tail)->prev;
    394  1.1  oster 		  (*tail)->next = NULL;
    395  1.1  oster 		  RF_ASSERT((*head)->prev == NULL);
    396  1.1  oster 		  RF_ASSERT((*tail)->next == NULL);
    397  1.1  oster 		}
    398  1.1  oster 	    }
    399  1.1  oster 	  else
    400  1.1  oster 	    {
    401  1.1  oster 	      if (w == *head)
    402  1.1  oster 		{
    403  1.1  oster 		  /* removing first item in the list */
    404  1.1  oster 		  *head = (*head)->next;
    405  1.1  oster 		  (*head)->prev = NULL;
    406  1.1  oster 		  RF_ASSERT((*head)->prev == NULL);
    407  1.1  oster 		  RF_ASSERT((*tail)->next == NULL);
    408  1.1  oster 		}
    409  1.1  oster 	      else
    410  1.1  oster 		{
    411  1.1  oster 		  /* removing an item from the middle of the list */
    412  1.1  oster 		  w->prev->next = w->next;
    413  1.1  oster 		  w->next->prev = w->prev;
    414  1.1  oster 		  RF_ASSERT((*head)->prev == NULL);
    415  1.1  oster 		  RF_ASSERT((*tail)->next == NULL);
    416  1.1  oster 		}
    417  1.1  oster 	    }
    418  1.1  oster 	  w->prev = NULL;
    419  1.1  oster 	  w->next = NULL;
    420  1.1  oster 	  if (rf_parityLogDebug)
    421  1.1  oster 	    printf("[dequeueing parity log data, region %d, raidAddress %d, numSector %d]\n",w->regionID,(int)w->diskAddress.raidAddress,(int) w->diskAddress.numSector);
    422  1.1  oster 	  return(w);
    423  1.1  oster 	}
    424  1.1  oster       else
    425  1.1  oster 	w = w->prev;
    426  1.1  oster     }
    427  1.1  oster   if (!ignoreLocks)
    428  1.1  oster     RF_UNLOCK_MUTEX(raidPtr->parityLogDiskQueue.mutex);
    429  1.1  oster   return(NULL);
    430  1.1  oster }
    431  1.1  oster 
    432  1.1  oster static RF_ParityLogData_t *DequeueMatchingLogData(
    433  1.1  oster   RF_Raid_t            *raidPtr,
    434  1.1  oster   RF_ParityLogData_t  **head,
    435  1.1  oster   RF_ParityLogData_t  **tail)
    436  1.1  oster {
    437  1.1  oster   RF_ParityLogData_t *logDataList, *logData;
    438  1.1  oster   int regionID;
    439  1.1  oster 
    440  1.1  oster   /* Remove and return an in-core parity log from the tail of
    441  1.1  oster      a disk queue (*head, *tail).  Then remove all matching
    442  1.1  oster      (identical regionIDs) logData and return as a linked list.
    443  1.1  oster 
    444  1.1  oster      NON-BLOCKING
    445  1.1  oster      */
    446  1.1  oster 
    447  1.1  oster   logDataList = DequeueParityLogData(raidPtr, head, tail, RF_TRUE);
    448  1.1  oster   if (logDataList)
    449  1.1  oster     {
    450  1.1  oster       regionID = logDataList->regionID;
    451  1.1  oster       logData = logDataList;
    452  1.1  oster       logData->next = rf_SearchAndDequeueParityLogData(raidPtr, regionID, head, tail, RF_TRUE);
    453  1.1  oster       while (logData->next)
    454  1.1  oster 	{
    455  1.1  oster 	  logData = logData->next;
    456  1.1  oster 	  logData->next = rf_SearchAndDequeueParityLogData(raidPtr, regionID, head, tail, RF_TRUE);
    457  1.1  oster 	}
    458  1.1  oster     }
    459  1.1  oster   return(logDataList);
    460  1.1  oster }
    461  1.1  oster 
    462  1.1  oster 
    463  1.1  oster static RF_ParityLog_t *AcquireParityLog(
    464  1.1  oster   RF_ParityLogData_t  *logData,
    465  1.1  oster   int                  finish)
    466  1.1  oster {
    467  1.1  oster   RF_ParityLog_t *log = NULL;
    468  1.1  oster   RF_Raid_t *raidPtr;
    469  1.1  oster 
    470  1.1  oster   /* Grab a log buffer from the pool and return it.
    471  1.1  oster      If no buffers are available, return NULL.
    472  1.1  oster      NON-BLOCKING
    473  1.1  oster      */
    474  1.1  oster   raidPtr = logData->common->raidPtr;
    475  1.1  oster   RF_LOCK_MUTEX(raidPtr->parityLogPool.mutex);
    476  1.1  oster   if (raidPtr->parityLogPool.parityLogs)
    477  1.1  oster     {
    478  1.1  oster       log = raidPtr->parityLogPool.parityLogs;
    479  1.1  oster       raidPtr->parityLogPool.parityLogs = raidPtr->parityLogPool.parityLogs->next;
    480  1.1  oster       log->regionID = logData->regionID;
    481  1.1  oster       log->numRecords = 0;
    482  1.1  oster       log->next = NULL;
    483  1.1  oster       raidPtr->logsInUse++;
    484  1.1  oster       RF_ASSERT(raidPtr->logsInUse >= 0 && raidPtr->logsInUse <= raidPtr->numParityLogs);
    485  1.1  oster     }
    486  1.1  oster   else
    487  1.1  oster     {
    488  1.1  oster       /* no logs available, so place ourselves on the queue of work waiting on log buffers
    489  1.1  oster 	 this is done while parityLogPool.mutex is held, to ensure synchronization
    490  1.1  oster 	 with ReleaseParityLogs.
    491  1.1  oster 	 */
    492  1.1  oster       if (rf_parityLogDebug)
    493  1.1  oster 	printf("[blocked on log, region %d, finish %d]\n", logData->regionID, finish);
    494  1.1  oster       if (finish)
    495  1.1  oster 	RequeueParityLogData(logData, &raidPtr->parityLogDiskQueue.logBlockHead, &raidPtr->parityLogDiskQueue.logBlockTail);
    496  1.1  oster       else
    497  1.1  oster 	EnqueueParityLogData(logData, &raidPtr->parityLogDiskQueue.logBlockHead, &raidPtr->parityLogDiskQueue.logBlockTail);
    498  1.1  oster     }
    499  1.1  oster   RF_UNLOCK_MUTEX(raidPtr->parityLogPool.mutex);
    500  1.1  oster   return(log);
    501  1.1  oster }
    502  1.1  oster 
    503  1.1  oster void rf_ReleaseParityLogs(
    504  1.1  oster   RF_Raid_t       *raidPtr,
    505  1.1  oster   RF_ParityLog_t  *firstLog)
    506  1.1  oster {
    507  1.1  oster   RF_ParityLogData_t *logDataList;
    508  1.1  oster   RF_ParityLog_t *log, *lastLog;
    509  1.1  oster   int cnt;
    510  1.1  oster 
    511  1.1  oster   /* Insert a linked list of parity logs (firstLog) to
    512  1.1  oster      the free list (parityLogPool.parityLogPool)
    513  1.1  oster 
    514  1.1  oster      NON-BLOCKING.
    515  1.1  oster      */
    516  1.1  oster 
    517  1.1  oster   RF_ASSERT(firstLog);
    518  1.1  oster 
    519  1.1  oster   /* Before returning logs to global free list, service all
    520  1.1  oster      requests which are blocked on logs.  Holding mutexes for parityLogPool and parityLogDiskQueue
    521  1.1  oster      forces synchronization with AcquireParityLog().
    522  1.1  oster      */
    523  1.1  oster   RF_LOCK_MUTEX(raidPtr->parityLogPool.mutex);
    524  1.1  oster   RF_LOCK_MUTEX(raidPtr->parityLogDiskQueue.mutex);
    525  1.1  oster   logDataList = DequeueMatchingLogData(raidPtr, &raidPtr->parityLogDiskQueue.logBlockHead, &raidPtr->parityLogDiskQueue.logBlockTail);
    526  1.1  oster   log = firstLog;
    527  1.1  oster   if (firstLog)
    528  1.1  oster     firstLog = firstLog->next;
    529  1.1  oster   log->numRecords = 0;
    530  1.1  oster   log->next = NULL;
    531  1.1  oster   while (logDataList && log)
    532  1.1  oster     {
    533  1.1  oster       RF_UNLOCK_MUTEX(raidPtr->parityLogPool.mutex);
    534  1.1  oster       RF_UNLOCK_MUTEX(raidPtr->parityLogDiskQueue.mutex);
    535  1.1  oster       rf_ParityLogAppend(logDataList, RF_TRUE, &log, RF_FALSE);
    536  1.1  oster       if (rf_parityLogDebug)
    537  1.1  oster 	printf("[finishing up buf-blocked log data, region %d]\n", logDataList->regionID);
    538  1.1  oster       if (log == NULL)
    539  1.1  oster 	{
    540  1.1  oster 	  log = firstLog;
    541  1.1  oster 	  if (firstLog)
    542  1.1  oster 	    {
    543  1.1  oster 	      firstLog = firstLog->next;
    544  1.1  oster 	      log->numRecords = 0;
    545  1.1  oster 	      log->next = NULL;
    546  1.1  oster 	    }
    547  1.1  oster 	}
    548  1.1  oster       RF_LOCK_MUTEX(raidPtr->parityLogPool.mutex);
    549  1.1  oster       RF_LOCK_MUTEX(raidPtr->parityLogDiskQueue.mutex);
    550  1.1  oster       if (log)
    551  1.1  oster 	logDataList = DequeueMatchingLogData(raidPtr, &raidPtr->parityLogDiskQueue.logBlockHead, &raidPtr->parityLogDiskQueue.logBlockTail);
    552  1.1  oster     }
    553  1.1  oster   /* return remaining logs to pool */
    554  1.1  oster   if (log)
    555  1.1  oster     {
    556  1.1  oster       log->next = firstLog;
    557  1.1  oster       firstLog = log;
    558  1.1  oster     }
    559  1.1  oster   if (firstLog)
    560  1.1  oster     {
    561  1.1  oster       lastLog = firstLog;
    562  1.1  oster       raidPtr->logsInUse--;
    563  1.1  oster       RF_ASSERT(raidPtr->logsInUse >= 0 && raidPtr->logsInUse <= raidPtr->numParityLogs);
    564  1.1  oster       while (lastLog->next)
    565  1.1  oster 	{
    566  1.1  oster 	  lastLog = lastLog->next;
    567  1.1  oster 	  raidPtr->logsInUse--;
    568  1.1  oster 	  RF_ASSERT(raidPtr->logsInUse >= 0 && raidPtr->logsInUse <= raidPtr->numParityLogs);
    569  1.1  oster 	}
    570  1.1  oster       lastLog->next = raidPtr->parityLogPool.parityLogs;
    571  1.1  oster       raidPtr->parityLogPool.parityLogs = firstLog;
    572  1.1  oster       cnt = 0;
    573  1.1  oster       log = raidPtr->parityLogPool.parityLogs;
    574  1.1  oster       while (log)
    575  1.1  oster 	{
    576  1.1  oster 	  cnt++;
    577  1.1  oster 	  log = log->next;
    578  1.1  oster 	}
    579  1.1  oster       RF_ASSERT(cnt + raidPtr->logsInUse == raidPtr->numParityLogs);
    580  1.1  oster     }
    581  1.1  oster   RF_UNLOCK_MUTEX(raidPtr->parityLogPool.mutex);
    582  1.1  oster   RF_UNLOCK_MUTEX(raidPtr->parityLogDiskQueue.mutex);
    583  1.1  oster }
    584  1.1  oster 
    585  1.1  oster static void ReintLog(
    586  1.1  oster   RF_Raid_t       *raidPtr,
    587  1.1  oster   int              regionID,
    588  1.1  oster   RF_ParityLog_t  *log)
    589  1.1  oster {
    590  1.1  oster   RF_ASSERT(log);
    591  1.1  oster 
    592  1.1  oster   /* Insert an in-core parity log (log) into the disk queue of reintegration
    593  1.1  oster      work.  Set the flag (reintInProgress) for the specified region (regionID)
    594  1.1  oster      to indicate that reintegration is in progress for this region.
    595  1.1  oster      NON-BLOCKING
    596  1.1  oster      */
    597  1.1  oster 
    598  1.1  oster   RF_LOCK_MUTEX(raidPtr->regionInfo[regionID].reintMutex);
    599  1.1  oster   raidPtr->regionInfo[regionID].reintInProgress = RF_TRUE;  /* cleared when reint complete */
    600  1.1  oster 
    601  1.1  oster   if (rf_parityLogDebug)
    602  1.1  oster     printf("[requesting reintegration of region %d]\n", log->regionID);
    603  1.1  oster   /* move record to reintegration queue */
    604  1.1  oster   RF_LOCK_MUTEX(raidPtr->parityLogDiskQueue.mutex);
    605  1.1  oster   log->next = raidPtr->parityLogDiskQueue.reintQueue;
    606  1.1  oster   raidPtr->parityLogDiskQueue.reintQueue = log;
    607  1.1  oster   RF_UNLOCK_MUTEX(raidPtr->regionInfo[regionID].reintMutex);
    608  1.1  oster   RF_UNLOCK_MUTEX(raidPtr->parityLogDiskQueue.mutex);
    609  1.1  oster   RF_SIGNAL_COND(raidPtr->parityLogDiskQueue.cond);
    610  1.1  oster }
    611  1.1  oster 
    612  1.1  oster static void FlushLog(
    613  1.1  oster   RF_Raid_t       *raidPtr,
    614  1.1  oster   RF_ParityLog_t  *log)
    615  1.1  oster {
    616  1.1  oster   /* insert a core log (log) into a list of logs (parityLogDiskQueue.flushQueue)
    617  1.1  oster      waiting to be written to disk.
    618  1.1  oster      NON-BLOCKING
    619  1.1  oster      */
    620  1.1  oster 
    621  1.1  oster   RF_ASSERT(log);
    622  1.1  oster   RF_ASSERT(log->numRecords == raidPtr->numSectorsPerLog);
    623  1.1  oster   RF_ASSERT(log->next == NULL);
    624  1.1  oster   /* move log to flush queue */
    625  1.1  oster   RF_LOCK_MUTEX(raidPtr->parityLogDiskQueue.mutex);
    626  1.1  oster   log->next = raidPtr->parityLogDiskQueue.flushQueue;
    627  1.1  oster   raidPtr->parityLogDiskQueue.flushQueue = log;
    628  1.1  oster   RF_UNLOCK_MUTEX(raidPtr->parityLogDiskQueue.mutex);
    629  1.1  oster   RF_SIGNAL_COND(raidPtr->parityLogDiskQueue.cond);
    630  1.1  oster }
    631  1.1  oster 
    632  1.1  oster static int DumpParityLogToDisk(
    633  1.1  oster   int                  finish,
    634  1.1  oster   RF_ParityLogData_t  *logData)
    635  1.1  oster {
    636  1.1  oster   int i, diskCount, regionID = logData->regionID;
    637  1.1  oster   RF_ParityLog_t *log;
    638  1.1  oster   RF_Raid_t *raidPtr;
    639  1.1  oster 
    640  1.1  oster   raidPtr = logData->common->raidPtr;
    641  1.1  oster 
    642  1.1  oster   /* Move a core log to disk.  If the log disk is full, initiate
    643  1.1  oster      reintegration.
    644  1.1  oster 
    645  1.1  oster      Return (0) if we can enqueue the dump immediately, otherwise
    646  1.1  oster      return (1) to indicate we are blocked on reintegration and
    647  1.1  oster      control of the thread should be relinquished.
    648  1.1  oster 
    649  1.1  oster      Caller must hold regionInfo[regionID].mutex
    650  1.1  oster 
    651  1.1  oster      NON-BLOCKING
    652  1.1  oster      */
    653  1.1  oster 
    654  1.1  oster   if (rf_parityLogDebug)
    655  1.1  oster     printf("[dumping parity log to disk, region %d]\n", regionID);
    656  1.1  oster   log = raidPtr->regionInfo[regionID].coreLog;
    657  1.1  oster   RF_ASSERT(log->numRecords == raidPtr->numSectorsPerLog);
    658  1.1  oster   RF_ASSERT(log->next == NULL);
    659  1.1  oster 
    660  1.1  oster   /* if reintegration is in progress, must queue work */
    661  1.1  oster   RF_LOCK_MUTEX(raidPtr->regionInfo[regionID].reintMutex);
    662  1.1  oster   if (raidPtr->regionInfo[regionID].reintInProgress)
    663  1.1  oster     {
    664  1.1  oster       /* Can not proceed since this region is currently being reintegrated.
    665  1.1  oster 	 We can not block, so queue remaining work and return */
    666  1.1  oster       if (rf_parityLogDebug)
    667  1.1  oster 	printf("[region %d waiting on reintegration]\n",regionID);
    668  1.1  oster       /* XXX not sure about the use of finish - shouldn't this always be "Enqueue"? */
    669  1.1  oster       if (finish)
    670  1.1  oster 	RequeueParityLogData(logData, &raidPtr->parityLogDiskQueue.reintBlockHead, &raidPtr->parityLogDiskQueue.reintBlockTail);
    671  1.1  oster       else
    672  1.1  oster 	EnqueueParityLogData(logData, &raidPtr->parityLogDiskQueue.reintBlockHead, &raidPtr->parityLogDiskQueue.reintBlockTail);
    673  1.1  oster       RF_UNLOCK_MUTEX(raidPtr->regionInfo[regionID].reintMutex);
    674  1.1  oster       return(1);  /* relenquish control of this thread */
    675  1.1  oster     }
    676  1.1  oster   RF_UNLOCK_MUTEX(raidPtr->regionInfo[regionID].reintMutex);
    677  1.1  oster   raidPtr->regionInfo[regionID].coreLog = NULL;
    678  1.1  oster   if ((raidPtr->regionInfo[regionID].diskCount) < raidPtr->regionInfo[regionID].capacity)
    679  1.1  oster     /* IMPORTANT!! this loop bound assumes region disk holds an integral number of core logs */
    680  1.1  oster     {
    681  1.1  oster       /* update disk map for this region */
    682  1.1  oster       diskCount = raidPtr->regionInfo[regionID].diskCount;
    683  1.1  oster       for (i = 0; i < raidPtr->numSectorsPerLog; i++)
    684  1.1  oster 	{
    685  1.1  oster 	  raidPtr->regionInfo[regionID].diskMap[i + diskCount].operation = log->records[i].operation;
    686  1.1  oster 	  raidPtr->regionInfo[regionID].diskMap[i + diskCount].parityAddr = log->records[i].parityAddr;
    687  1.1  oster 	}
    688  1.1  oster       log->diskOffset = diskCount;
    689  1.1  oster       raidPtr->regionInfo[regionID].diskCount += raidPtr->numSectorsPerLog;
    690  1.1  oster       FlushLog(raidPtr, log);
    691  1.1  oster     }
    692  1.1  oster   else
    693  1.1  oster     {
    694  1.1  oster       /* no room for log on disk, send it to disk manager and request reintegration */
    695  1.1  oster       RF_ASSERT(raidPtr->regionInfo[regionID].diskCount == raidPtr->regionInfo[regionID].capacity);
    696  1.1  oster       ReintLog(raidPtr, regionID, log);
    697  1.1  oster     }
    698  1.1  oster   if (rf_parityLogDebug)
    699  1.1  oster     printf("[finished dumping parity log to disk, region %d]\n", regionID);
    700  1.1  oster   return(0);
    701  1.1  oster }
    702  1.1  oster 
    703  1.1  oster int rf_ParityLogAppend(
    704  1.1  oster   RF_ParityLogData_t   *logData,
    705  1.1  oster   int                   finish,
    706  1.1  oster   RF_ParityLog_t      **incomingLog,
    707  1.1  oster   int                   clearReintFlag)
    708  1.1  oster {
    709  1.1  oster   int regionID, logItem, itemDone;
    710  1.1  oster   RF_ParityLogData_t *item;
    711  1.1  oster   int punt, done = RF_FALSE;
    712  1.1  oster   RF_ParityLog_t *log;
    713  1.1  oster   RF_Raid_t *raidPtr;
    714  1.1  oster   RF_Etimer_t timer;
    715  1.1  oster   int (*wakeFunc)(RF_DagNode_t *node, int status);
    716  1.1  oster   void *wakeArg;
    717  1.1  oster 
    718  1.1  oster   /* Add parity to the appropriate log, one sector at a time.
    719  1.1  oster      This routine is called is called by dag functions ParityLogUpdateFunc
    720  1.1  oster      and ParityLogOverwriteFunc and therefore MUST BE NONBLOCKING.
    721  1.1  oster 
    722  1.1  oster      Parity to be logged is contained in a linked-list (logData).  When
    723  1.1  oster      this routine returns, every sector in the list will be in one of
    724  1.1  oster      three places:
    725  1.1  oster        1) entered into the parity log
    726  1.1  oster        2) queued, waiting on reintegration
    727  1.1  oster        3) queued, waiting on a core log
    728  1.1  oster 
    729  1.1  oster      Blocked work is passed to the ParityLoggingDiskManager for completion.
    730  1.1  oster      Later, as conditions which required the block are removed, the work
    731  1.1  oster      reenters this routine with the "finish" parameter set to "RF_TRUE."
    732  1.1  oster 
    733  1.1  oster      NON-BLOCKING
    734  1.1  oster      */
    735  1.1  oster 
    736  1.1  oster   raidPtr = logData->common->raidPtr;
    737  1.1  oster   /* lock the region for the first item in logData */
    738  1.1  oster   RF_ASSERT(logData != NULL);
    739  1.1  oster   regionID = logData->regionID;
    740  1.1  oster   RF_LOCK_MUTEX(raidPtr->regionInfo[regionID].mutex);
    741  1.1  oster   RF_ASSERT(raidPtr->regionInfo[regionID].loggingEnabled);
    742  1.1  oster 
    743  1.1  oster   if (clearReintFlag)
    744  1.1  oster     {
    745  1.1  oster       /* Enable flushing for this region.  Holding both locks provides
    746  1.1  oster 	 a synchronization barrier with DumpParityLogToDisk
    747  1.1  oster 	 */
    748  1.1  oster       RF_LOCK_MUTEX(raidPtr->regionInfo[regionID].reintMutex);
    749  1.1  oster       RF_LOCK_MUTEX(raidPtr->parityLogDiskQueue.mutex);
    750  1.1  oster       RF_ASSERT(raidPtr->regionInfo[regionID].reintInProgress == RF_TRUE);
    751  1.1  oster       raidPtr->regionInfo[regionID].diskCount = 0;
    752  1.1  oster       raidPtr->regionInfo[regionID].reintInProgress = RF_FALSE;
    753  1.1  oster       RF_UNLOCK_MUTEX(raidPtr->regionInfo[regionID].reintMutex); /* flushing is now enabled */
    754  1.1  oster       RF_UNLOCK_MUTEX(raidPtr->parityLogDiskQueue.mutex);
    755  1.1  oster     }
    756  1.1  oster 
    757  1.1  oster   /* process each item in logData */
    758  1.1  oster   while (logData)
    759  1.1  oster     {
    760  1.1  oster       /* remove an item from logData */
    761  1.1  oster       item = logData;
    762  1.1  oster       logData = logData->next;
    763  1.1  oster       item->next = NULL;
    764  1.1  oster       item->prev = NULL;
    765  1.1  oster 
    766  1.1  oster       if (rf_parityLogDebug)
    767  1.1  oster 	printf("[appending parity log data, region %d, raidAddress %d, numSector %d]\n",item->regionID,(int)item->diskAddress.raidAddress, (int)item->diskAddress.numSector);
    768  1.1  oster 
    769  1.1  oster       /* see if we moved to a new region */
    770  1.1  oster       if (regionID != item->regionID)
    771  1.1  oster 	{
    772  1.1  oster 	  RF_UNLOCK_MUTEX(raidPtr->regionInfo[regionID].mutex);
    773  1.1  oster 	  regionID = item->regionID;
    774  1.1  oster 	  RF_LOCK_MUTEX(raidPtr->regionInfo[regionID].mutex);
    775  1.1  oster 	  RF_ASSERT(raidPtr->regionInfo[regionID].loggingEnabled);
    776  1.1  oster 	}
    777  1.1  oster 
    778  1.1  oster       punt = RF_FALSE;  /* Set to RF_TRUE if work is blocked.  This can happen in one of two ways:
    779  1.1  oster 		          1) no core log (AcquireParityLog)
    780  1.1  oster 			  2) waiting on reintegration (DumpParityLogToDisk)
    781  1.1  oster 			If punt is RF_TRUE, the dataItem was queued, so skip to next item.
    782  1.1  oster 			*/
    783  1.1  oster 
    784  1.1  oster       /* process item, one sector at a time, until all sectors processed or we punt */
    785  1.1  oster       if (item->diskAddress.numSector > 0)
    786  1.1  oster 	done = RF_FALSE;
    787  1.1  oster       else
    788  1.1  oster 	RF_ASSERT(0);
    789  1.1  oster       while (!punt && !done)
    790  1.1  oster 	{
    791  1.1  oster 	  /* verify that a core log exists for this region */
    792  1.1  oster 	  if (!raidPtr->regionInfo[regionID].coreLog)
    793  1.1  oster 	    {
    794  1.1  oster 	      /* Attempt to acquire a parity log.
    795  1.1  oster 		 If acquisition fails, queue remaining work in data item and move to nextItem.
    796  1.1  oster 		 */
    797  1.1  oster 	      if (incomingLog)
    798  1.1  oster 		if (*incomingLog)
    799  1.1  oster 		  {
    800  1.1  oster 		    RF_ASSERT((*incomingLog)->next == NULL);
    801  1.1  oster 		    raidPtr->regionInfo[regionID].coreLog = *incomingLog;
    802  1.1  oster 		    raidPtr->regionInfo[regionID].coreLog->regionID = regionID;
    803  1.1  oster 		    *incomingLog = NULL;
    804  1.1  oster 		  }
    805  1.1  oster 		else
    806  1.1  oster 		  raidPtr->regionInfo[regionID].coreLog = AcquireParityLog(item, finish);
    807  1.1  oster 	      else
    808  1.1  oster 		raidPtr->regionInfo[regionID].coreLog = AcquireParityLog(item, finish);
    809  1.1  oster 	      /* Note: AcquireParityLog either returns a log or enqueues currentItem */
    810  1.1  oster 	    }
    811  1.1  oster 	  if (!raidPtr->regionInfo[regionID].coreLog)
    812  1.1  oster 	    punt = RF_TRUE; /* failed to find a core log */
    813  1.1  oster 	  else
    814  1.1  oster 	    {
    815  1.1  oster 	      RF_ASSERT(raidPtr->regionInfo[regionID].coreLog->next == NULL);
    816  1.1  oster 	      /* verify that the log has room for new entries */
    817  1.1  oster 	      /* if log is full, dump it to disk and grab a new log */
    818  1.1  oster 	      if (raidPtr->regionInfo[regionID].coreLog->numRecords == raidPtr->numSectorsPerLog)
    819  1.1  oster 		{
    820  1.1  oster 		  /* log is full, dump it to disk */
    821  1.1  oster 		  if (DumpParityLogToDisk(finish, item))
    822  1.1  oster 		    punt = RF_TRUE; /* dump unsuccessful, blocked on reintegration */
    823  1.1  oster 		  else
    824  1.1  oster 		    {
    825  1.1  oster 		      /* dump was successful */
    826  1.1  oster 		      if (incomingLog)
    827  1.1  oster 			if (*incomingLog)
    828  1.1  oster 			  {
    829  1.1  oster 			    RF_ASSERT((*incomingLog)->next == NULL);
    830  1.1  oster 			    raidPtr->regionInfo[regionID].coreLog = *incomingLog;
    831  1.1  oster 			    raidPtr->regionInfo[regionID].coreLog->regionID = regionID;
    832  1.1  oster 			    *incomingLog = NULL;
    833  1.1  oster 			  }
    834  1.1  oster 			else
    835  1.1  oster 			  raidPtr->regionInfo[regionID].coreLog = AcquireParityLog(item, finish);
    836  1.1  oster 		      else
    837  1.1  oster 			raidPtr->regionInfo[regionID].coreLog = AcquireParityLog(item, finish);
    838  1.1  oster 		      /* if a core log is not available, must queue work and return */
    839  1.1  oster 		      if (!raidPtr->regionInfo[regionID].coreLog)
    840  1.1  oster 			punt = RF_TRUE; /* blocked on log availability */
    841  1.1  oster 		    }
    842  1.1  oster 		}
    843  1.1  oster 	    }
    844  1.1  oster 	  /* if we didn't punt on this item, attempt to add a sector to the core log */
    845  1.1  oster 	  if (!punt)
    846  1.1  oster 	    {
    847  1.1  oster 	      RF_ASSERT(raidPtr->regionInfo[regionID].coreLog->next == NULL);
    848  1.1  oster 	      /* at this point, we have a core log with enough room for a sector */
    849  1.1  oster 	      /* copy a sector into the log */
    850  1.1  oster 	      log = raidPtr->regionInfo[regionID].coreLog;
    851  1.1  oster 	      RF_ASSERT(log->numRecords < raidPtr->numSectorsPerLog);
    852  1.1  oster 	      logItem = log->numRecords++;
    853  1.1  oster 	      log->records[logItem].parityAddr = item->diskAddress;
    854  1.1  oster 	      RF_ASSERT(log->records[logItem].parityAddr.startSector >= raidPtr->regionInfo[regionID].parityStartAddr);
    855  1.1  oster 	      RF_ASSERT(log->records[logItem].parityAddr.startSector < raidPtr->regionInfo[regionID].parityStartAddr + raidPtr->regionInfo[regionID].numSectorsParity);
    856  1.1  oster 	      log->records[logItem].parityAddr.numSector = 1;
    857  1.1  oster 	      log->records[logItem].operation = item->common->operation;
    858  1.1  oster 	      bcopy((item->common->bufPtr + (item->bufOffset++ * (1<<item->common->raidPtr->logBytesPerSector))), log->bufPtr + (logItem * (1<<item->common->raidPtr->logBytesPerSector)), (1<<item->common->raidPtr->logBytesPerSector));
    859  1.1  oster 	      item->diskAddress.numSector--;
    860  1.1  oster 	      item->diskAddress.startSector++;
    861  1.1  oster 	      if (item->diskAddress.numSector == 0)
    862  1.1  oster 		done = RF_TRUE;
    863  1.1  oster 	    }
    864  1.1  oster 	}
    865  1.1  oster 
    866  1.1  oster       if (!punt)
    867  1.1  oster 	{
    868  1.1  oster 	  /* Processed this item completely, decrement count of items
    869  1.1  oster 	     to be processed.
    870  1.1  oster 	     */
    871  1.1  oster 	  RF_ASSERT(item->diskAddress.numSector == 0);
    872  1.1  oster 	  RF_LOCK_MUTEX(item->common->mutex);
    873  1.1  oster 	  item->common->cnt--;
    874  1.1  oster 	  if (item->common->cnt == 0)
    875  1.1  oster 	    itemDone = RF_TRUE;
    876  1.1  oster 	  else
    877  1.1  oster 	    itemDone = RF_FALSE;
    878  1.1  oster 	  RF_UNLOCK_MUTEX(item->common->mutex);
    879  1.1  oster 	  if (itemDone)
    880  1.1  oster 	    {
    881  1.1  oster 	      /* Finished processing all log data for this IO
    882  1.1  oster 		 Return structs to free list and invoke wakeup function.
    883  1.1  oster 		 */
    884  1.1  oster 	      timer = item->common->startTime;  /* grab initial value of timer */
    885  1.1  oster 	      RF_ETIMER_STOP(timer);
    886  1.1  oster 	      RF_ETIMER_EVAL(timer);
    887  1.1  oster 	      item->common->tracerec->plog_us += RF_ETIMER_VAL_US(timer);
    888  1.1  oster 	      if (rf_parityLogDebug)
    889  1.1  oster 		printf("[waking process for region %d]\n", item->regionID);
    890  1.1  oster 	      wakeFunc = item->common->wakeFunc;
    891  1.1  oster 	      wakeArg = item->common->wakeArg;
    892  1.1  oster 	      FreeParityLogCommonData(item->common);
    893  1.1  oster 	      FreeParityLogData(item);
    894  1.1  oster 	      (wakeFunc)(wakeArg, 0);
    895  1.1  oster 	    }
    896  1.1  oster 	  else
    897  1.1  oster 	    FreeParityLogData(item);
    898  1.1  oster 	}
    899  1.1  oster     }
    900  1.1  oster   RF_UNLOCK_MUTEX(raidPtr->regionInfo[regionID].mutex);
    901  1.1  oster   if (rf_parityLogDebug)
    902  1.1  oster     printf("[exiting ParityLogAppend]\n");
    903  1.1  oster   return(0);
    904  1.1  oster }
    905  1.1  oster 
    906  1.1  oster 
    907  1.1  oster void rf_EnableParityLogging(RF_Raid_t *raidPtr)
    908  1.1  oster {
    909  1.1  oster   int regionID;
    910  1.1  oster 
    911  1.1  oster   for (regionID = 0; regionID < rf_numParityRegions; regionID++) {
    912  1.1  oster     RF_LOCK_MUTEX(raidPtr->regionInfo[regionID].mutex);
    913  1.1  oster     raidPtr->regionInfo[regionID].loggingEnabled = RF_TRUE;
    914  1.1  oster     RF_UNLOCK_MUTEX(raidPtr->regionInfo[regionID].mutex);
    915  1.1  oster   }
    916  1.1  oster   if (rf_parityLogDebug)
    917  1.1  oster     printf("[parity logging enabled]\n");
    918  1.1  oster }
    919  1.1  oster 
    920  1.1  oster #endif /* RF_INCLUDE_PARITYLOGGING > 0 */
    921