root/dev/raidframe/rf_paritylog.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. rf_AllocParityLogCommonData
  2. rf_FreeParityLogCommonData
  3. rf_AllocParityLogData
  4. rf_FreeParityLogData
  5. rf_EnqueueParityLogData
  6. rf_DequeueParityLogData
  7. rf_RequeueParityLogData
  8. rf_CreateParityLogData
  9. rf_SearchAndDequeueParityLogData
  10. rf_DequeueMatchingLogData
  11. rf_AcquireParityLog
  12. rf_ReleaseParityLogs
  13. rf_ReintLog
  14. rf_FlushLog
  15. rf_DumpParityLogToDisk
  16. rf_ParityLogAppend
  17. rf_EnableParityLogging

    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 */

/* [<][>][^][v][top][bottom][index][help] */