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