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