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