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