Home | History | Annotate | Line # | Download | only in raidframe
rf_reconmap.c revision 1.2
      1 /*	$NetBSD: rf_reconmap.c,v 1.2 1999/01/26 02:34:01 oster Exp $	*/
      2 /*
      3  * Copyright (c) 1995 Carnegie-Mellon University.
      4  * All rights reserved.
      5  *
      6  * Author: Mark Holland
      7  *
      8  * Permission to use, copy, modify and distribute this software and
      9  * its documentation is hereby granted, provided that both the copyright
     10  * notice and this permission notice appear in all copies of the
     11  * software, derivative works or modified versions, and any portions
     12  * thereof, and that both notices appear in supporting documentation.
     13  *
     14  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
     15  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
     16  * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
     17  *
     18  * Carnegie Mellon requests users of this software to return to
     19  *
     20  *  Software Distribution Coordinator  or  Software.Distribution (at) CS.CMU.EDU
     21  *  School of Computer Science
     22  *  Carnegie Mellon University
     23  *  Pittsburgh PA 15213-3890
     24  *
     25  * any improvements or extensions that they make and grant Carnegie the
     26  * rights to redistribute these changes.
     27  */
     28 
     29 /*************************************************************************
     30  * rf_reconmap.c
     31  *
     32  * code to maintain a map of what sectors have/have not been reconstructed
     33  *
     34  *************************************************************************/
     35 
     36 #include "rf_raid.h"
     37 #include <sys/time.h>
     38 #include "rf_general.h"
     39 #include "rf_utils.h"
     40 #if RF_DEMO > 0
     41 #include "rf_demo.h"
     42 #endif /* RF_DEMO > 0 */
     43 #include "rf_sys.h"
     44 
     45 /* special pointer values indicating that a reconstruction unit
     46  * has been either totally reconstructed or not at all.  Both
     47  * are illegal pointer values, so you have to be careful not to
     48  * dereference through them.  RU_NOTHING must be zero, since
     49  * MakeReconMap uses bzero to initialize the structure.  These are used
     50  * only at the head of the list.
     51  */
     52 #define RU_ALL      ((RF_ReconMapListElem_t *) -1)
     53 #define RU_NOTHING  ((RF_ReconMapListElem_t *) 0)
     54 
     55 /* used to mark the end of the list */
     56 #define RU_NIL      ((RF_ReconMapListElem_t *) 0)
     57 
     58 
     59 static void compact_stat_entry(RF_Raid_t *raidPtr, RF_ReconMap_t *mapPtr,
     60 	int i);
     61 static void crunch_list(RF_ReconMap_t *mapPtr, RF_ReconMapListElem_t *listPtr);
     62 static RF_ReconMapListElem_t *MakeReconMapListElem(RF_SectorNum_t startSector,
     63 	RF_SectorNum_t stopSector, RF_ReconMapListElem_t *next);
     64 static void FreeReconMapListElem(RF_ReconMap_t *mapPtr,
     65 	RF_ReconMapListElem_t *p);
     66 static void update_size(RF_ReconMap_t *mapPtr, int size);
     67 static void PrintList(RF_ReconMapListElem_t *listPtr);
     68 
     69 /*-----------------------------------------------------------------------------
     70  *
     71  * Creates and initializes new Reconstruction map
     72  *
     73  *-----------------------------------------------------------------------------*/
     74 
     75 RF_ReconMap_t *rf_MakeReconMap(raidPtr, ru_sectors, disk_sectors, spareUnitsPerDisk)
     76   RF_Raid_t            *raidPtr;
     77   RF_SectorCount_t      ru_sectors;        /* size of reconstruction unit in sectors */
     78   RF_SectorCount_t      disk_sectors;      /* size of disk in sectors */
     79   RF_ReconUnitCount_t   spareUnitsPerDisk; /* zero unless distributed sparing */
     80 {
     81   RF_RaidLayout_t *layoutPtr = &raidPtr->Layout;
     82   RF_ReconUnitCount_t num_rus = layoutPtr->stripeUnitsPerDisk / layoutPtr->SUsPerRU;
     83   RF_ReconMap_t *p;
     84   int rc;
     85 
     86   RF_Malloc(p, sizeof(RF_ReconMap_t), (RF_ReconMap_t *));
     87   p->sectorsPerReconUnit = ru_sectors;
     88   p->sectorsInDisk = disk_sectors;
     89 
     90   p->totalRUs = num_rus;
     91   p->spareRUs = spareUnitsPerDisk;
     92   p->unitsLeft = num_rus - spareUnitsPerDisk;
     93 
     94   RF_Malloc(p->status, num_rus * sizeof(RF_ReconMapListElem_t *), (RF_ReconMapListElem_t **));
     95   RF_ASSERT(p->status != (RF_ReconMapListElem_t **) NULL);
     96 
     97   (void) bzero((char *) p->status, num_rus * sizeof(RF_ReconMapListElem_t *));
     98 
     99   p->size = sizeof(RF_ReconMap_t) + num_rus * sizeof(RF_ReconMapListElem_t *);
    100   p->maxSize = p->size;
    101 
    102   rc = rf_mutex_init(&p->mutex);
    103   if (rc) {
    104     RF_ERRORMSG3("Unable to init mutex file %s line %d rc=%d\n", __FILE__,
    105       __LINE__, rc);
    106     RF_Free(p->status, num_rus * sizeof(RF_ReconMapListElem_t *));
    107     RF_Free(p, sizeof(RF_ReconMap_t));
    108     return(NULL);
    109   }
    110   return(p);
    111 }
    112 
    113 
    114 /*-----------------------------------------------------------------------------
    115  *
    116  * marks a new set of sectors as reconstructed.  All the possible mergings get
    117  * complicated.  To simplify matters, the approach I take is to just dump
    118  * something into the list, and then clean it up (i.e. merge elements and
    119  * eliminate redundant ones) in a second pass over the list (compact_stat_entry()).
    120  * Not 100% efficient, since a structure can be allocated and then immediately
    121  * freed, but it keeps this code from becoming (more of) a nightmare of
    122  * special cases.  The only thing that compact_stat_entry() assumes is that the
    123  * list is sorted by startSector, and so this is the only condition I maintain
    124  * here.  (MCH)
    125  *
    126  *-----------------------------------------------------------------------------*/
    127 
    128 void rf_ReconMapUpdate(raidPtr, mapPtr, startSector, stopSector)
    129   RF_Raid_t       *raidPtr;
    130   RF_ReconMap_t   *mapPtr;
    131   RF_SectorNum_t   startSector;
    132   RF_SectorNum_t   stopSector;
    133 {
    134   RF_SectorCount_t sectorsPerReconUnit = mapPtr->sectorsPerReconUnit;
    135   RF_SectorNum_t i, first_in_RU, last_in_RU;
    136   RF_ReconMapListElem_t *p, *pt;
    137 
    138   RF_LOCK_MUTEX(mapPtr->mutex);
    139   RF_ASSERT(startSector >=0 && stopSector < mapPtr->sectorsInDisk && stopSector > startSector);
    140 
    141   while (startSector <= stopSector) {
    142     i = startSector/mapPtr->sectorsPerReconUnit;
    143     first_in_RU = i*sectorsPerReconUnit;
    144     last_in_RU  = first_in_RU + sectorsPerReconUnit -1 ;
    145     p = mapPtr->status[i];
    146     if (p!=RU_ALL) {
    147       if (p==RU_NOTHING || p->startSector > startSector ) {	/* insert at front of list */
    148 
    149 	mapPtr->status[i] = MakeReconMapListElem(startSector, RF_MIN(stopSector,last_in_RU), (p==RU_NOTHING) ? NULL : p);
    150 	update_size(mapPtr, sizeof(RF_ReconMapListElem_t));
    151 
    152       } else {						/* general case */
    153 	do {						/* search for place to insert */
    154 	  pt = p; p = p->next;
    155 	} while (p && (p->startSector < startSector));
    156 	pt->next = MakeReconMapListElem(startSector,RF_MIN(stopSector,last_in_RU),p);
    157 	update_size(mapPtr, sizeof(RF_ReconMapListElem_t));
    158       }
    159       compact_stat_entry(raidPtr, mapPtr, i);
    160     }
    161     startSector = RF_MIN(stopSector, last_in_RU) +1;
    162   }
    163   RF_UNLOCK_MUTEX(mapPtr->mutex);
    164 }
    165 
    166 
    167 
    168 /*-----------------------------------------------------------------------------
    169  *
    170  * performs whatever list compactions can be done, and frees any space
    171  * that is no longer necessary.  Assumes only that the list is sorted
    172  * by startSector.  crunch_list() compacts a single list as much as possible,
    173  * and the second block of code deletes the entire list if possible.
    174  * crunch_list() is also called from MakeReconMapAccessList().
    175  *
    176  * When a recon unit is detected to be fully reconstructed, we set the
    177  * corresponding bit in the parity stripe map so that the head follow
    178  * code will not select this parity stripe again.  This is redundant (but
    179  * harmless) when compact_stat_entry is called from the reconstruction code,
    180  * but necessary when called from the user-write code.
    181  *
    182  *-----------------------------------------------------------------------------*/
    183 
    184 static void compact_stat_entry(raidPtr, mapPtr, i)
    185   RF_Raid_t      *raidPtr;
    186   RF_ReconMap_t  *mapPtr;
    187   int             i;
    188 {
    189   RF_SectorCount_t sectorsPerReconUnit = mapPtr->sectorsPerReconUnit;
    190   RF_ReconMapListElem_t *p = mapPtr->status[i];
    191 
    192   crunch_list(mapPtr, p);
    193 
    194   if ((p->startSector == i*sectorsPerReconUnit) &&
    195       (p->stopSector == i*sectorsPerReconUnit +sectorsPerReconUnit -1)) {
    196     mapPtr->status[i] = RU_ALL;
    197     mapPtr->unitsLeft--;
    198     FreeReconMapListElem(mapPtr,p);
    199   }
    200 }
    201 
    202 static void crunch_list(mapPtr, listPtr)
    203   RF_ReconMap_t          *mapPtr;
    204   RF_ReconMapListElem_t  *listPtr;
    205 {
    206   RF_ReconMapListElem_t *pt, *p = listPtr;
    207 
    208   if (!p) return;
    209   pt = p;  p = p->next;
    210   while (p) {
    211     if (pt->stopSector >= p->startSector-1) {
    212       pt->stopSector = RF_MAX(pt->stopSector, p->stopSector);
    213       pt->next = p->next;
    214       FreeReconMapListElem(mapPtr, p);
    215       p = pt->next;
    216     }
    217     else {
    218       pt = p;
    219       p = p->next;
    220     }
    221   }
    222 }
    223 
    224 /*-----------------------------------------------------------------------------
    225  *
    226  * Allocate and fill a new list element
    227  *
    228  *-----------------------------------------------------------------------------*/
    229 
    230 static RF_ReconMapListElem_t *MakeReconMapListElem(
    231   RF_SectorNum_t          startSector,
    232   RF_SectorNum_t          stopSector,
    233   RF_ReconMapListElem_t  *next)
    234 {
    235   RF_ReconMapListElem_t *p;
    236 
    237   RF_Malloc(p, sizeof(RF_ReconMapListElem_t), (RF_ReconMapListElem_t *));
    238   if (p == NULL)
    239     return(NULL);
    240   p->startSector = startSector;
    241   p->stopSector = stopSector;
    242   p->next = next;
    243   return(p);
    244 }
    245 
    246 /*-----------------------------------------------------------------------------
    247  *
    248  * Free a list element
    249  *
    250  *-----------------------------------------------------------------------------*/
    251 
    252 static void FreeReconMapListElem(mapPtr,p)
    253   RF_ReconMap_t          *mapPtr;
    254   RF_ReconMapListElem_t  *p;
    255 {
    256   int delta;
    257 
    258   if (mapPtr) {
    259     delta = 0 - (int)sizeof(RF_ReconMapListElem_t);
    260     update_size(mapPtr, delta);
    261   }
    262   RF_Free(p, sizeof(*p));
    263 }
    264 
    265 /*-----------------------------------------------------------------------------
    266  *
    267  * Free an entire status structure.  Inefficient, but can be called at any time.
    268  *
    269  *-----------------------------------------------------------------------------*/
    270 void rf_FreeReconMap(mapPtr)
    271   RF_ReconMap_t  *mapPtr;
    272 {
    273   RF_ReconMapListElem_t *p, *q;
    274   RF_ReconUnitCount_t numRUs;
    275   RF_ReconUnitNum_t i;
    276 
    277   numRUs = mapPtr->sectorsInDisk / mapPtr->sectorsPerReconUnit;
    278   if (mapPtr->sectorsInDisk % mapPtr->sectorsPerReconUnit)
    279     numRUs++;
    280 
    281   for (i=0; i<numRUs; i++) {
    282     p = mapPtr->status[i];
    283     while (p != RU_NOTHING && p != RU_ALL) {
    284       q = p; p = p->next;
    285       RF_Free(q, sizeof(*q));
    286     }
    287   }
    288   rf_mutex_destroy(&mapPtr->mutex);
    289   RF_Free(mapPtr->status, mapPtr->totalRUs * sizeof(RF_ReconMapListElem_t *));
    290   RF_Free(mapPtr, sizeof(RF_ReconMap_t));
    291 }
    292 
    293 /*-----------------------------------------------------------------------------
    294  *
    295  * returns nonzero if the indicated RU has been reconstructed already
    296  *
    297  *---------------------------------------------------------------------------*/
    298 
    299 int rf_CheckRUReconstructed(mapPtr, startSector)
    300   RF_ReconMap_t   *mapPtr;
    301   RF_SectorNum_t   startSector;
    302 {
    303   RF_ReconMapListElem_t *l;		/* used for searching */
    304   RF_ReconUnitNum_t i;
    305 
    306   i = startSector / mapPtr->sectorsPerReconUnit;
    307   l = mapPtr->status[i];
    308   return( (l == RU_ALL) ? 1 : 0 );
    309 }
    310 
    311 RF_ReconUnitCount_t rf_UnitsLeftToReconstruct(mapPtr)
    312   RF_ReconMap_t  *mapPtr;
    313 {
    314   RF_ASSERT(mapPtr != NULL);
    315   return( mapPtr->unitsLeft );
    316 }
    317 
    318 /* updates the size fields of a status descriptor */
    319 static void update_size(mapPtr, size)
    320   RF_ReconMap_t  *mapPtr;
    321   int             size;
    322 {
    323   mapPtr->size += size;
    324   mapPtr->maxSize = RF_MAX(mapPtr->size, mapPtr->maxSize);
    325 }
    326 
    327 static void PrintList(listPtr)
    328   RF_ReconMapListElem_t  *listPtr;
    329 {
    330   while (listPtr) {
    331     printf("%d,%d -> ",(int)listPtr->startSector,(int)listPtr->stopSector);
    332     listPtr = listPtr->next;
    333   }
    334   printf("\n");
    335 }
    336 
    337 void rf_PrintReconMap(raidPtr, mapPtr, frow, fcol)
    338   RF_Raid_t      *raidPtr;
    339   RF_ReconMap_t  *mapPtr;
    340   RF_RowCol_t     frow;
    341   RF_RowCol_t     fcol;
    342 {
    343   RF_ReconUnitCount_t numRUs;
    344   RF_ReconMapListElem_t *p;
    345   RF_ReconUnitNum_t i;
    346 
    347   numRUs = mapPtr->totalRUs;
    348   if (mapPtr->sectorsInDisk % mapPtr->sectorsPerReconUnit)
    349     numRUs++;
    350 
    351   for (i=0; i<numRUs; i++) {
    352     p = mapPtr->status[i];
    353     if (p==RU_ALL) /*printf("[%d] ALL\n",i)*/;
    354     else if (p == RU_NOTHING) {
    355       printf("%d: Unreconstructed\n",i);
    356     } else {
    357       printf("%d: ", i);
    358       PrintList(p);
    359     }
    360   }
    361 }
    362 
    363 void rf_PrintReconSchedule(mapPtr, starttime)
    364   RF_ReconMap_t   *mapPtr;
    365   struct timeval  *starttime;
    366 {
    367   static int old_pctg = -1;
    368   struct timeval tv, diff;
    369   int new_pctg;
    370 
    371   new_pctg = 100 - (rf_UnitsLeftToReconstruct(mapPtr) * 100 / mapPtr->totalRUs);
    372   if (new_pctg != old_pctg) {
    373     RF_GETTIME(tv);
    374     RF_TIMEVAL_DIFF(starttime, &tv, &diff);
    375 #if RF_DEMO > 0
    376     if (rf_demoMode) {
    377       rf_update_recon_meter(new_pctg);
    378     }
    379     else {
    380       printf("%d %d.%06d\n",new_pctg, diff.tv_sec, diff.tv_usec);
    381     }
    382 #else /* RF_DEMO > 0 */
    383     printf("%d %d.%06d\n",(int)new_pctg, (int)diff.tv_sec, (int)diff.tv_usec);
    384 #endif /* RF_DEMO > 0 */
    385     old_pctg = new_pctg;
    386   }
    387 }
    388