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