Home | History | Annotate | Line # | Download | only in raidframe
rf_paritylog.c revision 1.5.10.1
      1  1.5.10.1   fvdl /*	$NetBSD: rf_paritylog.c,v 1.5.10.1 2001/10/11 00:02:21 fvdl 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.10.1   fvdl #include <dev/raidframe/raidframevar.h>
     42  1.5.10.1   fvdl 
     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