Home | History | Annotate | Line # | Download | only in raidframe
rf_paritylog.c revision 1.5.6.1
      1  1.5.6.1  nathanw /*	$NetBSD: rf_paritylog.c,v 1.5.6.1 2001/10/22 20:41:38 nathanw 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.5.6.1  nathanw #include <dev/raidframe/raidframevar.h>
     42  1.5.6.1  nathanw 
     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