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