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