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