Home | History | Annotate | Line # | Download | only in raidframe
rf_decluster.c revision 1.2
      1  1.2  oster /*	$NetBSD: rf_decluster.c,v 1.2 1999/01/26 02:33:55 oster Exp $	*/
      2  1.1  oster /*
      3  1.1  oster  * Copyright (c) 1995 Carnegie-Mellon University.
      4  1.1  oster  * All rights reserved.
      5  1.1  oster  *
      6  1.1  oster  * Author: Mark Holland
      7  1.1  oster  *
      8  1.1  oster  * Permission to use, copy, modify and distribute this software and
      9  1.1  oster  * its documentation is hereby granted, provided that both the copyright
     10  1.1  oster  * notice and this permission notice appear in all copies of the
     11  1.1  oster  * software, derivative works or modified versions, and any portions
     12  1.1  oster  * thereof, and that both notices appear in supporting documentation.
     13  1.1  oster  *
     14  1.1  oster  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
     15  1.1  oster  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
     16  1.1  oster  * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
     17  1.1  oster  *
     18  1.1  oster  * Carnegie Mellon requests users of this software to return to
     19  1.1  oster  *
     20  1.1  oster  *  Software Distribution Coordinator  or  Software.Distribution (at) CS.CMU.EDU
     21  1.1  oster  *  School of Computer Science
     22  1.1  oster  *  Carnegie Mellon University
     23  1.1  oster  *  Pittsburgh PA 15213-3890
     24  1.1  oster  *
     25  1.1  oster  * any improvements or extensions that they make and grant Carnegie the
     26  1.1  oster  * rights to redistribute these changes.
     27  1.1  oster  */
     28  1.1  oster 
     29  1.1  oster /*----------------------------------------------------------------------
     30  1.1  oster  *
     31  1.1  oster  * rf_decluster.c -- code related to the declustered layout
     32  1.1  oster  *
     33  1.1  oster  * Created 10-21-92 (MCH)
     34  1.1  oster  *
     35  1.1  oster  * Nov 93:  adding support for distributed sparing.  This code is a little
     36  1.1  oster  *          complex:  the basic layout used is as follows:
     37  1.1  oster  *          let F = (v-1)/GCD(r,v-1).  The spare space for each set of
     38  1.1  oster  *          F consecutive fulltables is grouped together and placed after
     39  1.1  oster  *          that set of tables.
     40  1.1  oster  *                   +------------------------------+
     41  1.1  oster  *                   |        F fulltables          |
     42  1.1  oster  *                   |        Spare Space           |
     43  1.1  oster  *                   |        F fulltables          |
     44  1.1  oster  *                   |        Spare Space           |
     45  1.1  oster  *                   |            ...               |
     46  1.1  oster  *                   +------------------------------+
     47  1.1  oster  *
     48  1.1  oster  *--------------------------------------------------------------------*/
     49  1.1  oster 
     50  1.1  oster #include "rf_types.h"
     51  1.1  oster #include "rf_raid.h"
     52  1.1  oster #include "rf_raidframe.h"
     53  1.1  oster #include "rf_configure.h"
     54  1.1  oster #include "rf_decluster.h"
     55  1.1  oster #include "rf_debugMem.h"
     56  1.1  oster #include "rf_utils.h"
     57  1.1  oster #include "rf_alloclist.h"
     58  1.1  oster #include "rf_general.h"
     59  1.1  oster #include "rf_shutdown.h"
     60  1.1  oster #include "rf_sys.h"
     61  1.1  oster 
     62  1.1  oster extern int rf_copyback_in_progress;                /* debug only */
     63  1.1  oster 
     64  1.1  oster /* found in rf_kintf.c */
     65  1.1  oster int rf_GetSpareTableFromDaemon(RF_SparetWait_t  *req);
     66  1.1  oster 
     67  1.1  oster /* configuration code */
     68  1.1  oster 
     69  1.1  oster int rf_ConfigureDeclustered(
     70  1.1  oster   RF_ShutdownList_t  **listp,
     71  1.1  oster   RF_Raid_t           *raidPtr,
     72  1.1  oster   RF_Config_t         *cfgPtr)
     73  1.1  oster {
     74  1.1  oster     RF_RaidLayout_t *layoutPtr = &(raidPtr->Layout);
     75  1.1  oster     int b, v, k, r, lambda;				/* block design params */
     76  1.1  oster     int i, j;
     77  1.1  oster     RF_RowCol_t *first_avail_slot;
     78  1.1  oster     RF_StripeCount_t complete_FT_count, numCompleteFullTablesPerDisk;
     79  1.1  oster     RF_DeclusteredConfigInfo_t *info;
     80  1.1  oster     RF_StripeCount_t PUsPerDisk, spareRegionDepthInPUs, numCompleteSpareRegionsPerDisk, extraPUsPerDisk;
     81  1.1  oster     RF_StripeCount_t totSparePUsPerDisk;
     82  1.1  oster     RF_SectorNum_t diskOffsetOfLastFullTableInSUs;
     83  1.1  oster     RF_SectorCount_t SpareSpaceInSUs;
     84  1.1  oster     char *cfgBuf = (char *) (cfgPtr->layoutSpecific);
     85  1.1  oster     RF_StripeNum_t l, SUID;
     86  1.1  oster 
     87  1.1  oster     SUID = l = 0;
     88  1.1  oster     numCompleteSpareRegionsPerDisk = 0;
     89  1.1  oster 
     90  1.1  oster     /* 1. create layout specific structure */
     91  1.1  oster     RF_MallocAndAdd(info, sizeof(RF_DeclusteredConfigInfo_t), (RF_DeclusteredConfigInfo_t *), raidPtr->cleanupList);
     92  1.1  oster     if (info == NULL)
     93  1.1  oster       return(ENOMEM);
     94  1.1  oster     layoutPtr->layoutSpecificInfo = (void *) info;
     95  1.1  oster     info->SpareTable = NULL;
     96  1.1  oster 
     97  1.1  oster     /* 2. extract parameters from the config structure */
     98  1.1  oster     if (layoutPtr->map->flags & RF_DISTRIBUTE_SPARE) {
     99  1.1  oster       (void) bcopy(cfgBuf, info->sparemap_fname, RF_SPAREMAP_NAME_LEN);
    100  1.1  oster     }
    101  1.1  oster     cfgBuf += RF_SPAREMAP_NAME_LEN;
    102  1.1  oster 
    103  1.1  oster     b        = *( (int *) cfgBuf);   cfgBuf += sizeof(int);
    104  1.1  oster     v        = *( (int *) cfgBuf);   cfgBuf += sizeof(int);
    105  1.1  oster     k        = *( (int *) cfgBuf);   cfgBuf += sizeof(int);
    106  1.1  oster     r        = *( (int *) cfgBuf);   cfgBuf += sizeof(int);
    107  1.1  oster     lambda   = *( (int *) cfgBuf);   cfgBuf += sizeof(int);
    108  1.1  oster     raidPtr->noRotate = *( (int *) cfgBuf);   cfgBuf += sizeof(int);
    109  1.1  oster 
    110  1.1  oster     /* the sparemaps are generated assuming that parity is rotated, so we issue
    111  1.1  oster      * a warning if both distributed sparing and no-rotate are on at the same time
    112  1.1  oster      */
    113  1.1  oster     if ((layoutPtr->map->flags & RF_DISTRIBUTE_SPARE) && raidPtr->noRotate) {
    114  1.1  oster 	RF_ERRORMSG("Warning:  distributed sparing specified without parity rotation.\n");
    115  1.1  oster     }
    116  1.1  oster 
    117  1.1  oster     if (raidPtr->numCol != v) {
    118  1.1  oster         RF_ERRORMSG2("RAID: config error: table element count (%d) not equal to no. of cols (%d)\n", v, raidPtr->numCol);
    119  1.1  oster         return(EINVAL);
    120  1.1  oster     }
    121  1.1  oster 
    122  1.1  oster     /* 3.  set up the values used in the mapping code */
    123  1.1  oster     info->BlocksPerTable = b;
    124  1.1  oster     info->Lambda = lambda;
    125  1.1  oster     info->NumParityReps = info->groupSize = k;
    126  1.1  oster     info->SUsPerTable = b * (k-1) * layoutPtr->SUsPerPU;/* b blks, k-1 SUs each */
    127  1.1  oster     info->SUsPerFullTable = k * info->SUsPerTable;	/* rot k times */
    128  1.1  oster     info->PUsPerBlock = k-1;
    129  1.1  oster     info->SUsPerBlock = info->PUsPerBlock * layoutPtr->SUsPerPU;
    130  1.1  oster     info->TableDepthInPUs = (b*k) / v;
    131  1.1  oster     info->FullTableDepthInPUs = info->TableDepthInPUs * k;		/* k repetitions */
    132  1.1  oster 
    133  1.1  oster     /* used only in distributed sparing case */
    134  1.1  oster     info->FullTablesPerSpareRegion = (v-1) / rf_gcd(r, v-1);		/* (v-1)/gcd fulltables */
    135  1.1  oster     info->TablesPerSpareRegion = k * info->FullTablesPerSpareRegion;
    136  1.1  oster     info->SpareSpaceDepthPerRegionInSUs = (r * info->TablesPerSpareRegion / (v-1)) * layoutPtr->SUsPerPU;
    137  1.1  oster 
    138  1.1  oster     /* check to make sure the block design is sufficiently small */
    139  1.1  oster     if ((raidPtr->Layout.map->flags & RF_DISTRIBUTE_SPARE)) {
    140  1.1  oster         if (info->FullTableDepthInPUs * layoutPtr->SUsPerPU + info->SpareSpaceDepthPerRegionInSUs > layoutPtr->stripeUnitsPerDisk) {
    141  1.1  oster 	    RF_ERRORMSG3("RAID: config error: Full Table depth (%d) + Spare Space (%d) larger than disk size (%d) (BD too big)\n",
    142  1.1  oster 			 (int)info->FullTableDepthInPUs,
    143  1.1  oster 			 (int)info->SpareSpaceDepthPerRegionInSUs,
    144  1.1  oster 			 (int)layoutPtr->stripeUnitsPerDisk);
    145  1.1  oster 	    return(EINVAL);
    146  1.1  oster 	}
    147  1.1  oster     } else {
    148  1.1  oster 	if (info->TableDepthInPUs * layoutPtr->SUsPerPU > layoutPtr->stripeUnitsPerDisk) {
    149  1.1  oster 	    RF_ERRORMSG2("RAID: config error: Table depth (%d) larger than disk size (%d) (BD too big)\n",
    150  1.1  oster 			 (int)(info->TableDepthInPUs * layoutPtr->SUsPerPU), \
    151  1.1  oster 			 (int)layoutPtr->stripeUnitsPerDisk);
    152  1.1  oster 	    return(EINVAL);
    153  1.1  oster 	}
    154  1.1  oster     }
    155  1.1  oster 
    156  1.1  oster 
    157  1.1  oster     /* compute the size of each disk, and the number of tables in the last fulltable (which
    158  1.1  oster      * need not be complete)
    159  1.1  oster      */
    160  1.1  oster     if (raidPtr->Layout.map->flags & RF_DISTRIBUTE_SPARE) {
    161  1.1  oster 
    162  1.1  oster 	PUsPerDisk = layoutPtr->stripeUnitsPerDisk / layoutPtr->SUsPerPU;
    163  1.1  oster 	spareRegionDepthInPUs = (info->TablesPerSpareRegion * info->TableDepthInPUs +
    164  1.1  oster 				 (info->TablesPerSpareRegion * info->TableDepthInPUs) / (v-1));
    165  1.1  oster 	info->SpareRegionDepthInSUs = spareRegionDepthInPUs * layoutPtr->SUsPerPU;
    166  1.1  oster 
    167  1.1  oster 	numCompleteSpareRegionsPerDisk = PUsPerDisk / spareRegionDepthInPUs;
    168  1.1  oster 	info->NumCompleteSRs = numCompleteSpareRegionsPerDisk;
    169  1.1  oster 	extraPUsPerDisk = PUsPerDisk % spareRegionDepthInPUs;
    170  1.1  oster 
    171  1.1  oster 	/* assume conservatively that we need the full amount of spare space in one region in order
    172  1.1  oster 	 * to provide spares for the partial spare region at the end of the array.  We set "i" to
    173  1.1  oster 	 * the number of tables in the partial spare region.  This may actually include some fulltables.
    174  1.1  oster 	 */
    175  1.1  oster 	extraPUsPerDisk -= (info->SpareSpaceDepthPerRegionInSUs / layoutPtr->SUsPerPU);
    176  1.1  oster 	if (extraPUsPerDisk <= 0) i = 0;
    177  1.1  oster 	else i = extraPUsPerDisk/info->TableDepthInPUs;
    178  1.1  oster 
    179  1.1  oster 	complete_FT_count = raidPtr->numRow * (numCompleteSpareRegionsPerDisk * (info->TablesPerSpareRegion/k) + i/k);
    180  1.1  oster         info->FullTableLimitSUID = complete_FT_count * info->SUsPerFullTable;
    181  1.1  oster 	info->ExtraTablesPerDisk = i % k;
    182  1.1  oster 
    183  1.1  oster 	/* note that in the last spare region, the spare space is complete even though data/parity space is not */
    184  1.1  oster 	totSparePUsPerDisk = (numCompleteSpareRegionsPerDisk+1) * (info->SpareSpaceDepthPerRegionInSUs / layoutPtr->SUsPerPU);
    185  1.1  oster 	info->TotSparePUsPerDisk = totSparePUsPerDisk;
    186  1.1  oster 
    187  1.1  oster 	layoutPtr->stripeUnitsPerDisk =
    188  1.1  oster 	    ((complete_FT_count/raidPtr->numRow) * info->FullTableDepthInPUs +	 	/* data & parity space */
    189  1.1  oster 	     info->ExtraTablesPerDisk * info->TableDepthInPUs +
    190  1.1  oster 	     totSparePUsPerDisk								/* spare space */
    191  1.1  oster 	    ) * layoutPtr->SUsPerPU;
    192  1.1  oster 	layoutPtr->dataStripeUnitsPerDisk =
    193  1.1  oster 	    (complete_FT_count * info->FullTableDepthInPUs + info->ExtraTablesPerDisk * info->TableDepthInPUs)
    194  1.1  oster 	    * layoutPtr->SUsPerPU * (k-1) / k;
    195  1.1  oster 
    196  1.1  oster     } else {
    197  1.1  oster         /* non-dist spare case:  force each disk to contain an integral number of tables */
    198  1.1  oster         layoutPtr->stripeUnitsPerDisk /= (info->TableDepthInPUs * layoutPtr->SUsPerPU);
    199  1.1  oster         layoutPtr->stripeUnitsPerDisk *= (info->TableDepthInPUs * layoutPtr->SUsPerPU);
    200  1.1  oster 
    201  1.1  oster 	/* compute the number of tables in the last fulltable, which need not be complete */
    202  1.1  oster         complete_FT_count =
    203  1.1  oster             ((layoutPtr->stripeUnitsPerDisk/layoutPtr->SUsPerPU) / info->FullTableDepthInPUs) * raidPtr->numRow;
    204  1.1  oster 
    205  1.1  oster         info->FullTableLimitSUID = complete_FT_count * info->SUsPerFullTable;
    206  1.1  oster         info->ExtraTablesPerDisk =
    207  1.1  oster 		((layoutPtr->stripeUnitsPerDisk/layoutPtr->SUsPerPU) / info->TableDepthInPUs) % k;
    208  1.1  oster     }
    209  1.1  oster 
    210  1.1  oster     raidPtr->sectorsPerDisk = layoutPtr->stripeUnitsPerDisk * layoutPtr->sectorsPerStripeUnit;
    211  1.1  oster 
    212  1.1  oster     /* find the disk offset of the stripe unit where the last fulltable starts */
    213  1.1  oster     numCompleteFullTablesPerDisk = complete_FT_count / raidPtr->numRow;
    214  1.1  oster     diskOffsetOfLastFullTableInSUs = numCompleteFullTablesPerDisk * info->FullTableDepthInPUs * layoutPtr->SUsPerPU;
    215  1.1  oster     if (raidPtr->Layout.map->flags & RF_DISTRIBUTE_SPARE) {
    216  1.1  oster         SpareSpaceInSUs  = numCompleteSpareRegionsPerDisk * info->SpareSpaceDepthPerRegionInSUs;
    217  1.1  oster         diskOffsetOfLastFullTableInSUs += SpareSpaceInSUs;
    218  1.1  oster         info->DiskOffsetOfLastSpareSpaceChunkInSUs =
    219  1.1  oster 	    diskOffsetOfLastFullTableInSUs + info->ExtraTablesPerDisk * info->TableDepthInPUs * layoutPtr->SUsPerPU;
    220  1.1  oster     }
    221  1.1  oster     info->DiskOffsetOfLastFullTableInSUs = diskOffsetOfLastFullTableInSUs;
    222  1.1  oster     info->numCompleteFullTablesPerDisk = numCompleteFullTablesPerDisk;
    223  1.1  oster 
    224  1.1  oster     /* 4.  create and initialize the lookup tables */
    225  1.1  oster     info->LayoutTable = rf_make_2d_array(b, k, raidPtr->cleanupList);
    226  1.1  oster     if (info->LayoutTable == NULL)
    227  1.1  oster       return(ENOMEM);
    228  1.1  oster     info->OffsetTable = rf_make_2d_array(b, k, raidPtr->cleanupList);
    229  1.1  oster     if (info->OffsetTable == NULL)
    230  1.1  oster       return(ENOMEM);
    231  1.1  oster     info->BlockTable  =	rf_make_2d_array(info->TableDepthInPUs*layoutPtr->SUsPerPU, raidPtr->numCol, raidPtr->cleanupList);
    232  1.1  oster     if (info->BlockTable == NULL)
    233  1.1  oster       return(ENOMEM);
    234  1.1  oster 
    235  1.1  oster     first_avail_slot = rf_make_1d_array(v, NULL);
    236  1.1  oster     if (first_avail_slot == NULL)
    237  1.1  oster       return(ENOMEM);
    238  1.1  oster 
    239  1.1  oster     for (i=0; i<b; i++)
    240  1.1  oster       for (j=0; j<k; j++)
    241  1.1  oster         info->LayoutTable[i][j] = *cfgBuf++;
    242  1.1  oster 
    243  1.1  oster     /* initialize offset table */
    244  1.1  oster     for (i=0; i<b; i++) for (j=0; j<k; j++) {
    245  1.1  oster         info->OffsetTable[i][j] = first_avail_slot[ info->LayoutTable[i][j] ];
    246  1.1  oster         first_avail_slot[ info->LayoutTable[i][j] ]++;
    247  1.1  oster     }
    248  1.1  oster 
    249  1.1  oster     /* initialize block table */
    250  1.1  oster     for (SUID=l=0; l<layoutPtr->SUsPerPU; l++) {
    251  1.1  oster         for (i=0; i<b; i++) {
    252  1.1  oster             for (j=0; j<k; j++) {
    253  1.1  oster                 info->BlockTable[ (info->OffsetTable[i][j] * layoutPtr->SUsPerPU) + l ]
    254  1.1  oster 		                [ info->LayoutTable[i][j] ] = SUID;
    255  1.1  oster             }
    256  1.1  oster             SUID++;
    257  1.1  oster         }
    258  1.1  oster     }
    259  1.1  oster 
    260  1.1  oster     rf_free_1d_array(first_avail_slot, v);
    261  1.1  oster 
    262  1.1  oster     /* 5.  set up the remaining redundant-but-useful parameters */
    263  1.1  oster 
    264  1.1  oster     raidPtr->totalSectors = (k*complete_FT_count + raidPtr->numRow*info->ExtraTablesPerDisk) *
    265  1.1  oster     			  info->SUsPerTable * layoutPtr->sectorsPerStripeUnit;
    266  1.1  oster     layoutPtr->numStripe = (raidPtr->totalSectors / layoutPtr->sectorsPerStripeUnit) / (k-1);
    267  1.1  oster 
    268  1.1  oster     /* strange evaluation order below to try and minimize overflow problems */
    269  1.1  oster 
    270  1.1  oster     layoutPtr->dataSectorsPerStripe = (k-1) * layoutPtr->sectorsPerStripeUnit;
    271  1.1  oster     layoutPtr->bytesPerStripeUnit = layoutPtr->sectorsPerStripeUnit << raidPtr->logBytesPerSector;
    272  1.1  oster     layoutPtr->numDataCol = k-1;
    273  1.1  oster     layoutPtr->numParityCol = 1;
    274  1.1  oster 
    275  1.1  oster     return(0);
    276  1.1  oster }
    277  1.1  oster 
    278  1.1  oster /* declustering with distributed sparing */
    279  1.1  oster static void rf_ShutdownDeclusteredDS(RF_ThreadArg_t);
    280  1.1  oster static void rf_ShutdownDeclusteredDS(arg)
    281  1.1  oster   RF_ThreadArg_t  arg;
    282  1.1  oster {
    283  1.1  oster   RF_DeclusteredConfigInfo_t *info;
    284  1.1  oster   RF_Raid_t *raidPtr;
    285  1.1  oster 
    286  1.1  oster   raidPtr = (RF_Raid_t *)arg;
    287  1.1  oster   info = (RF_DeclusteredConfigInfo_t *) raidPtr->Layout.layoutSpecificInfo;
    288  1.1  oster   if (info->SpareTable)
    289  1.1  oster     rf_FreeSpareTable(raidPtr);
    290  1.1  oster }
    291  1.1  oster 
    292  1.1  oster int rf_ConfigureDeclusteredDS(
    293  1.1  oster   RF_ShutdownList_t  **listp,
    294  1.1  oster   RF_Raid_t           *raidPtr,
    295  1.1  oster   RF_Config_t         *cfgPtr)
    296  1.1  oster {
    297  1.1  oster   int rc;
    298  1.1  oster 
    299  1.1  oster   rc = rf_ConfigureDeclustered(listp, raidPtr, cfgPtr);
    300  1.1  oster   if (rc)
    301  1.1  oster     return(rc);
    302  1.1  oster   rc = rf_ShutdownCreate(listp, rf_ShutdownDeclusteredDS, raidPtr);
    303  1.1  oster   if (rc) {
    304  1.1  oster     RF_ERRORMSG1("Got %d adding shutdown event for DeclusteredDS\n", rc);
    305  1.1  oster     rf_ShutdownDeclusteredDS(raidPtr);
    306  1.1  oster     return(rc);
    307  1.1  oster   }
    308  1.1  oster   return(0);
    309  1.1  oster }
    310  1.1  oster 
    311  1.1  oster void rf_MapSectorDeclustered(raidPtr, raidSector, row, col, diskSector, remap)
    312  1.1  oster   RF_Raid_t       *raidPtr;
    313  1.1  oster   RF_RaidAddr_t    raidSector;
    314  1.1  oster   RF_RowCol_t     *row;
    315  1.1  oster   RF_RowCol_t     *col;
    316  1.1  oster   RF_SectorNum_t  *diskSector;
    317  1.1  oster   int              remap;
    318  1.1  oster {
    319  1.1  oster     RF_RaidLayout_t *layoutPtr = &(raidPtr->Layout);
    320  1.1  oster     RF_DeclusteredConfigInfo_t *info = (RF_DeclusteredConfigInfo_t *) layoutPtr->layoutSpecificInfo;
    321  1.1  oster     RF_StripeNum_t SUID = raidSector / layoutPtr->sectorsPerStripeUnit;
    322  1.1  oster     RF_StripeNum_t FullTableID, FullTableOffset, TableID, TableOffset;
    323  1.1  oster     RF_StripeNum_t BlockID, BlockOffset, RepIndex;
    324  1.1  oster     RF_StripeCount_t sus_per_fulltable = info->SUsPerFullTable;
    325  1.1  oster     RF_StripeCount_t fulltable_depth  = info->FullTableDepthInPUs * layoutPtr->SUsPerPU;
    326  1.1  oster     RF_StripeNum_t base_suid = 0, outSU, SpareRegion=0, SpareSpace=0;
    327  1.1  oster 
    328  1.1  oster     rf_decluster_adjust_params(layoutPtr, &SUID, &sus_per_fulltable, &fulltable_depth, &base_suid);
    329  1.1  oster 
    330  1.1  oster     FullTableID     = SUID / sus_per_fulltable;		/* fulltable ID within array (across rows) */
    331  1.1  oster     if (raidPtr->numRow == 1) *row = 0;                 /* avoid a mod and a div in the common case */
    332  1.1  oster     else {
    333  1.1  oster       *row            = FullTableID % raidPtr->numRow;
    334  1.1  oster       FullTableID    /= raidPtr->numRow;			/* convert to fulltable ID on this disk */
    335  1.1  oster     }
    336  1.1  oster     if (raidPtr->Layout.map->flags & RF_DISTRIBUTE_SPARE) {
    337  1.1  oster 	SpareRegion = FullTableID / info->FullTablesPerSpareRegion;
    338  1.1  oster         SpareSpace  = SpareRegion * info->SpareSpaceDepthPerRegionInSUs;
    339  1.1  oster     }
    340  1.1  oster     FullTableOffset = SUID % sus_per_fulltable;
    341  1.1  oster     TableID         = FullTableOffset / info->SUsPerTable;
    342  1.1  oster     TableOffset     = FullTableOffset - TableID * info->SUsPerTable;
    343  1.1  oster     BlockID         = TableOffset / info->PUsPerBlock;
    344  1.1  oster     BlockOffset     = TableOffset - BlockID * info->PUsPerBlock;
    345  1.1  oster     BlockID        %= info->BlocksPerTable;
    346  1.1  oster     RepIndex        = info->PUsPerBlock - TableID;
    347  1.1  oster     if (!raidPtr->noRotate) BlockOffset    += ((BlockOffset >= RepIndex) ? 1 : 0);
    348  1.1  oster     *col            = info->LayoutTable[BlockID][BlockOffset];
    349  1.1  oster 
    350  1.1  oster     /* remap to distributed spare space if indicated */
    351  1.1  oster     if (remap) {
    352  1.1  oster       RF_ASSERT( raidPtr->Disks[*row][*col].status == rf_ds_reconstructing || raidPtr->Disks[*row][*col].status == rf_ds_dist_spared ||
    353  1.1  oster 	     (rf_copyback_in_progress && raidPtr->Disks[*row][*col].status == rf_ds_optimal));
    354  1.1  oster       rf_remap_to_spare_space(layoutPtr, info, *row, FullTableID, TableID, BlockID, (base_suid) ? 1 : 0, SpareRegion, col, &outSU);
    355  1.1  oster     } else {
    356  1.1  oster 
    357  1.1  oster         outSU	    = base_suid;
    358  1.1  oster         outSU      += FullTableID * fulltable_depth;  				        /* offs to strt of FT */
    359  1.1  oster         outSU	   += SpareSpace;						        /* skip rsvd spare space */
    360  1.1  oster         outSU      += TableID * info->TableDepthInPUs * layoutPtr->SUsPerPU;   	        /* offs to strt of tble */
    361  1.1  oster         outSU      += info->OffsetTable[BlockID][BlockOffset] * layoutPtr->SUsPerPU;	/* offs to the PU */
    362  1.1  oster     }
    363  1.1  oster     outSU          += TableOffset / (info->BlocksPerTable * info->PUsPerBlock);	        /* offs to the SU within a PU */
    364  1.1  oster 
    365  1.1  oster     /* convert SUs to sectors, and, if not aligned to SU boundary, add in offset to sector.  */
    366  1.1  oster     *diskSector     = outSU*layoutPtr->sectorsPerStripeUnit + (raidSector % layoutPtr->sectorsPerStripeUnit);
    367  1.1  oster 
    368  1.1  oster     RF_ASSERT( *col != -1 );
    369  1.1  oster }
    370  1.1  oster 
    371  1.1  oster 
    372  1.1  oster /* prototyping this inexplicably causes the compile of the layout table (rf_layout.c) to fail */
    373  1.1  oster void rf_MapParityDeclustered(
    374  1.1  oster   RF_Raid_t       *raidPtr,
    375  1.1  oster   RF_RaidAddr_t    raidSector,
    376  1.1  oster   RF_RowCol_t     *row,
    377  1.1  oster   RF_RowCol_t     *col,
    378  1.1  oster   RF_SectorNum_t  *diskSector,
    379  1.1  oster   int              remap)
    380  1.1  oster {
    381  1.1  oster     RF_RaidLayout_t *layoutPtr = &(raidPtr->Layout);
    382  1.1  oster     RF_DeclusteredConfigInfo_t *info = (RF_DeclusteredConfigInfo_t *) layoutPtr->layoutSpecificInfo;
    383  1.1  oster     RF_StripeNum_t SUID = raidSector / layoutPtr->sectorsPerStripeUnit;
    384  1.1  oster     RF_StripeNum_t FullTableID, FullTableOffset, TableID, TableOffset;
    385  1.1  oster     RF_StripeNum_t BlockID, BlockOffset, RepIndex;
    386  1.1  oster     RF_StripeCount_t sus_per_fulltable = info->SUsPerFullTable;
    387  1.1  oster     RF_StripeCount_t fulltable_depth  = info->FullTableDepthInPUs * layoutPtr->SUsPerPU;
    388  1.1  oster     RF_StripeNum_t base_suid = 0, outSU, SpareRegion=0, SpareSpace=0;
    389  1.1  oster 
    390  1.1  oster     rf_decluster_adjust_params(layoutPtr, &SUID, &sus_per_fulltable, &fulltable_depth, &base_suid);
    391  1.1  oster 
    392  1.1  oster     /* compute row & (possibly) spare space exactly as before */
    393  1.1  oster     FullTableID     = SUID / sus_per_fulltable;
    394  1.1  oster     if (raidPtr->numRow == 1) *row = 0;                         /* avoid a mod and a div in the common case */
    395  1.1  oster     else {
    396  1.1  oster       *row            = FullTableID % raidPtr->numRow;
    397  1.1  oster       FullTableID    /= raidPtr->numRow;			/* convert to fulltable ID on this disk */
    398  1.1  oster     }
    399  1.1  oster     if ((raidPtr->Layout.map->flags & RF_DISTRIBUTE_SPARE)) {
    400  1.1  oster 	SpareRegion = FullTableID / info->FullTablesPerSpareRegion;
    401  1.1  oster         SpareSpace  = SpareRegion * info->SpareSpaceDepthPerRegionInSUs;
    402  1.1  oster     }
    403  1.1  oster 
    404  1.1  oster     /* compute BlockID and RepIndex exactly as before */
    405  1.1  oster     FullTableOffset = SUID % sus_per_fulltable;
    406  1.1  oster     TableID         = FullTableOffset / info->SUsPerTable;
    407  1.1  oster     TableOffset     = FullTableOffset - TableID * info->SUsPerTable;
    408  1.1  oster     /*TableOffset     = FullTableOffset % info->SUsPerTable;*/
    409  1.1  oster     /*BlockID         = (TableOffset / info->PUsPerBlock) % info->BlocksPerTable;*/
    410  1.1  oster     BlockID         = TableOffset / info->PUsPerBlock;
    411  1.1  oster     /*BlockOffset     = TableOffset % info->PUsPerBlock;*/
    412  1.1  oster     BlockOffset     = TableOffset - BlockID * info->PUsPerBlock;
    413  1.1  oster     BlockID        %= info->BlocksPerTable;
    414  1.1  oster 
    415  1.1  oster     /* the parity block is in the position indicated by RepIndex */
    416  1.1  oster     RepIndex        = (raidPtr->noRotate) ? info->PUsPerBlock : info->PUsPerBlock - TableID;
    417  1.1  oster     *col	    = info->LayoutTable[BlockID][RepIndex];
    418  1.1  oster 
    419  1.1  oster     if (remap) {
    420  1.1  oster       RF_ASSERT( raidPtr->Disks[*row][*col].status == rf_ds_reconstructing || raidPtr->Disks[*row][*col].status == rf_ds_dist_spared ||
    421  1.1  oster 	     (rf_copyback_in_progress && raidPtr->Disks[*row][*col].status == rf_ds_optimal));
    422  1.1  oster       rf_remap_to_spare_space(layoutPtr, info, *row, FullTableID, TableID, BlockID, (base_suid) ? 1 : 0, SpareRegion, col, &outSU);
    423  1.1  oster     } else {
    424  1.1  oster 
    425  1.1  oster         /* compute sector as before, except use RepIndex instead of BlockOffset */
    426  1.1  oster         outSU        = base_suid;
    427  1.1  oster         outSU       += FullTableID * fulltable_depth;
    428  1.1  oster         outSU	    += SpareSpace;						/* skip rsvd spare space */
    429  1.1  oster         outSU       += TableID * info->TableDepthInPUs * layoutPtr->SUsPerPU;
    430  1.1  oster         outSU       += info->OffsetTable[BlockID][RepIndex] * layoutPtr->SUsPerPU;
    431  1.1  oster     }
    432  1.1  oster 
    433  1.1  oster     outSU       += TableOffset / (info->BlocksPerTable * info->PUsPerBlock);
    434  1.1  oster     *diskSector  = outSU*layoutPtr->sectorsPerStripeUnit + (raidSector % layoutPtr->sectorsPerStripeUnit);
    435  1.1  oster 
    436  1.1  oster     RF_ASSERT( *col != -1 );
    437  1.1  oster }
    438  1.1  oster 
    439  1.1  oster /* returns an array of ints identifying the disks that comprise the stripe containing the indicated address.
    440  1.1  oster  * the caller must _never_ attempt to modify this array.
    441  1.1  oster  */
    442  1.1  oster void rf_IdentifyStripeDeclustered(
    443  1.1  oster   RF_Raid_t        *raidPtr,
    444  1.1  oster   RF_RaidAddr_t     addr,
    445  1.1  oster   RF_RowCol_t     **diskids,
    446  1.1  oster   RF_RowCol_t      *outRow)
    447  1.1  oster {
    448  1.1  oster   RF_RaidLayout_t *layoutPtr           = &(raidPtr->Layout);
    449  1.1  oster   RF_DeclusteredConfigInfo_t *info     = (RF_DeclusteredConfigInfo_t *) layoutPtr->layoutSpecificInfo;
    450  1.1  oster   RF_StripeCount_t sus_per_fulltable   = info->SUsPerFullTable;
    451  1.1  oster   RF_StripeCount_t fulltable_depth     = info->FullTableDepthInPUs * layoutPtr->SUsPerPU;
    452  1.1  oster   RF_StripeNum_t  base_suid            = 0;
    453  1.1  oster   RF_StripeNum_t SUID                  = rf_RaidAddressToStripeUnitID(layoutPtr, addr);
    454  1.1  oster   RF_StripeNum_t stripeID, FullTableID;
    455  1.1  oster   int tableOffset;
    456  1.1  oster 
    457  1.1  oster   rf_decluster_adjust_params(layoutPtr, &SUID, &sus_per_fulltable, &fulltable_depth, &base_suid);
    458  1.1  oster   FullTableID     = SUID / sus_per_fulltable;		/* fulltable ID within array (across rows) */
    459  1.1  oster   *outRow         = FullTableID % raidPtr->numRow;
    460  1.1  oster   stripeID        = rf_StripeUnitIDToStripeID(layoutPtr, SUID);                     /* find stripe offset into array */
    461  1.1  oster   tableOffset     = (stripeID % info->BlocksPerTable);                        /* find offset into block design table */
    462  1.1  oster   *diskids        = info->LayoutTable[tableOffset];
    463  1.1  oster }
    464  1.1  oster 
    465  1.1  oster /* This returns the default head-separation limit, which is measured
    466  1.1  oster  * in "required units for reconstruction".  Each time a disk fetches
    467  1.1  oster  * a unit, it bumps a counter.  The head-sep code prohibits any disk
    468  1.1  oster  * from getting more than headSepLimit counter values ahead of any
    469  1.1  oster  * other.
    470  1.1  oster  *
    471  1.1  oster  * We assume here that the number of floating recon buffers is already
    472  1.1  oster  * set.  There are r stripes to be reconstructed in each table, and so
    473  1.1  oster  * if we have a total of B buffers, we can have at most B/r tables
    474  1.1  oster  * under recon at any one time.  In each table, lambda units are required
    475  1.1  oster  * from each disk, so given B buffers, the head sep limit has to be
    476  1.1  oster  * (lambda*B)/r units.  We subtract one to avoid weird boundary cases.
    477  1.1  oster  *
    478  1.1  oster  * for example, suppose were given 50 buffers, r=19, and lambda=4 as in
    479  1.1  oster  * the 20.5 design.  There are 19 stripes/table to be reconstructed, so
    480  1.1  oster  * we can have 50/19 tables concurrently under reconstruction, which means
    481  1.1  oster  * we can allow the fastest disk to get 50/19 tables ahead of the slower
    482  1.1  oster  * disk.  There are lambda "required units" for each disk, so the fastest
    483  1.1  oster  * disk can get 4*50/19 = 10 counter values ahead of the slowest.
    484  1.1  oster  *
    485  1.1  oster  * If numBufsToAccumulate is not 1, we need to limit the head sep further
    486  1.1  oster  * because multiple bufs will be required for each stripe under recon.
    487  1.1  oster  */
    488  1.1  oster RF_HeadSepLimit_t rf_GetDefaultHeadSepLimitDeclustered(
    489  1.1  oster   RF_Raid_t  *raidPtr)
    490  1.1  oster {
    491  1.1  oster   RF_DeclusteredConfigInfo_t *info = (RF_DeclusteredConfigInfo_t *) raidPtr->Layout.layoutSpecificInfo;
    492  1.1  oster 
    493  1.1  oster   return(info->Lambda * raidPtr->numFloatingReconBufs / info->TableDepthInPUs / rf_numBufsToAccumulate);
    494  1.1  oster }
    495  1.1  oster 
    496  1.1  oster /* returns the default number of recon buffers to use.  The value
    497  1.1  oster  * is somewhat arbitrary...it's intended to be large enough to allow
    498  1.1  oster  * for a reasonably large head-sep limit, but small enough that you
    499  1.1  oster  * don't use up all your system memory with buffers.
    500  1.1  oster  */
    501  1.1  oster int rf_GetDefaultNumFloatingReconBuffersDeclustered(RF_Raid_t *raidPtr)
    502  1.1  oster {
    503  1.1  oster   return(100 * rf_numBufsToAccumulate);
    504  1.1  oster }
    505  1.1  oster 
    506  1.1  oster /* sectors in the last fulltable of the array need to be handled
    507  1.1  oster  * specially since this fulltable can be incomplete.  this function
    508  1.1  oster  * changes the values of certain params to handle this.
    509  1.1  oster  *
    510  1.1  oster  * the idea here is that MapSector et. al. figure out which disk the
    511  1.1  oster  * addressed unit lives on by computing the modulos of the unit number
    512  1.1  oster  * with the number of units per fulltable, table, etc.  In the last
    513  1.1  oster  * fulltable, there are fewer units per fulltable, so we need to adjust
    514  1.1  oster  * the number of user data units per fulltable to reflect this.
    515  1.1  oster  *
    516  1.1  oster  * so, we (1) convert the fulltable size and depth parameters to
    517  1.1  oster  * the size of the partial fulltable at the end, (2) compute the
    518  1.1  oster  * disk sector offset where this fulltable starts, and (3) convert
    519  1.1  oster  * the users stripe unit number from an offset into the array to
    520  1.1  oster  * an offset into the last fulltable.
    521  1.1  oster  */
    522  1.1  oster void rf_decluster_adjust_params(
    523  1.1  oster   RF_RaidLayout_t   *layoutPtr,
    524  1.1  oster   RF_StripeNum_t    *SUID,
    525  1.1  oster   RF_StripeCount_t  *sus_per_fulltable,
    526  1.1  oster   RF_StripeCount_t  *fulltable_depth,
    527  1.1  oster   RF_StripeNum_t    *base_suid)
    528  1.1  oster {
    529  1.1  oster     RF_DeclusteredConfigInfo_t *info = (RF_DeclusteredConfigInfo_t *) layoutPtr->layoutSpecificInfo;
    530  1.1  oster #if defined(__NetBSD__) && defined(_KERNEL)
    531  1.1  oster     /* Nothing! */
    532  1.1  oster #else
    533  1.1  oster     char pc = layoutPtr->map->parityConfig;
    534  1.1  oster #endif
    535  1.1  oster 
    536  1.1  oster     if (*SUID >= info->FullTableLimitSUID) {
    537  1.1  oster 	/* new full table size is size of last full table on disk */
    538  1.1  oster 	*sus_per_fulltable = info->ExtraTablesPerDisk * info->SUsPerTable;
    539  1.1  oster 
    540  1.1  oster 	/* new full table depth is corresponding depth */
    541  1.1  oster 	*fulltable_depth = info->ExtraTablesPerDisk * info->TableDepthInPUs * layoutPtr->SUsPerPU;
    542  1.1  oster 
    543  1.1  oster 	/* set up the new base offset */
    544  1.1  oster 	*base_suid = info->DiskOffsetOfLastFullTableInSUs;
    545  1.1  oster 
    546  1.1  oster 	/* convert users array address to an offset into the last fulltable */
    547  1.1  oster 	*SUID -= info->FullTableLimitSUID;
    548  1.1  oster     }
    549  1.1  oster }
    550  1.1  oster 
    551  1.1  oster /*
    552  1.1  oster  * map a stripe ID to a parity stripe ID.
    553  1.1  oster  * See comment above RaidAddressToParityStripeID in layout.c.
    554  1.1  oster  */
    555  1.1  oster void rf_MapSIDToPSIDDeclustered(
    556  1.1  oster   RF_RaidLayout_t    *layoutPtr,
    557  1.1  oster   RF_StripeNum_t      stripeID,
    558  1.1  oster   RF_StripeNum_t     *psID,
    559  1.1  oster   RF_ReconUnitNum_t  *which_ru)
    560  1.1  oster {
    561  1.1  oster     RF_DeclusteredConfigInfo_t *info;
    562  1.1  oster 
    563  1.1  oster     info = (RF_DeclusteredConfigInfo_t *) layoutPtr->layoutSpecificInfo;
    564  1.1  oster 
    565  1.1  oster     *psID = (stripeID / (layoutPtr->SUsPerPU * info->BlocksPerTable))
    566  1.1  oster         * info->BlocksPerTable + (stripeID % info->BlocksPerTable);
    567  1.1  oster     *which_ru = (stripeID % (info->BlocksPerTable * layoutPtr->SUsPerPU))
    568  1.1  oster         / info->BlocksPerTable;
    569  1.1  oster     RF_ASSERT( (*which_ru) < layoutPtr->SUsPerPU/layoutPtr->SUsPerRU);
    570  1.1  oster }
    571  1.1  oster 
    572  1.1  oster /*
    573  1.1  oster  * Called from MapSector and MapParity to retarget an access at the spare unit.
    574  1.1  oster  * Modifies the "col" and "outSU" parameters only.
    575  1.1  oster  */
    576  1.1  oster void rf_remap_to_spare_space(
    577  1.1  oster   RF_RaidLayout_t             *layoutPtr,
    578  1.1  oster   RF_DeclusteredConfigInfo_t  *info,
    579  1.1  oster   RF_RowCol_t                  row,
    580  1.1  oster   RF_StripeNum_t               FullTableID,
    581  1.1  oster   RF_StripeNum_t               TableID,
    582  1.1  oster   RF_SectorNum_t               BlockID,
    583  1.1  oster   RF_StripeNum_t               base_suid,
    584  1.1  oster   RF_StripeNum_t               SpareRegion,
    585  1.1  oster   RF_RowCol_t                 *outCol,
    586  1.1  oster   RF_StripeNum_t              *outSU)
    587  1.1  oster {
    588  1.1  oster     RF_StripeNum_t ftID, spareTableStartSU, TableInSpareRegion, lastSROffset, which_ft;
    589  1.1  oster 
    590  1.1  oster     /*
    591  1.1  oster      * note that FullTableID and hence SpareRegion may have gotten
    592  1.1  oster      * tweaked by rf_decluster_adjust_params. We detect this by
    593  1.1  oster      * noticing that base_suid is not 0.
    594  1.1  oster      */
    595  1.1  oster     if (base_suid == 0) {
    596  1.1  oster       ftID = FullTableID;
    597  1.1  oster     }
    598  1.1  oster     else {
    599  1.1  oster       /*
    600  1.1  oster        * There may be > 1.0 full tables in the last (i.e. partial)
    601  1.1  oster        * spare region.  find out which of these we're in.
    602  1.1  oster        */
    603  1.1  oster       lastSROffset = info->NumCompleteSRs * info->SpareRegionDepthInSUs;
    604  1.1  oster       which_ft = (info->DiskOffsetOfLastFullTableInSUs - lastSROffset) / (info->FullTableDepthInPUs * layoutPtr->SUsPerPU);
    605  1.1  oster 
    606  1.1  oster       /* compute the actual full table ID */
    607  1.1  oster       ftID = info->DiskOffsetOfLastFullTableInSUs / (info->FullTableDepthInPUs * layoutPtr->SUsPerPU) + which_ft;
    608  1.1  oster       SpareRegion = info->NumCompleteSRs;
    609  1.1  oster     }
    610  1.1  oster     TableInSpareRegion = (ftID * info->NumParityReps + TableID) % info->TablesPerSpareRegion;
    611  1.1  oster 
    612  1.1  oster     *outCol = info->SpareTable[TableInSpareRegion][BlockID].spareDisk;
    613  1.1  oster     RF_ASSERT( *outCol != -1);
    614  1.1  oster 
    615  1.1  oster     spareTableStartSU = (SpareRegion == info->NumCompleteSRs) ?
    616  1.1  oster 	    info->DiskOffsetOfLastFullTableInSUs + info->ExtraTablesPerDisk * info->TableDepthInPUs * layoutPtr->SUsPerPU :
    617  1.1  oster 	    (SpareRegion+1) * info->SpareRegionDepthInSUs - info->SpareSpaceDepthPerRegionInSUs;
    618  1.1  oster     *outSU = spareTableStartSU + info->SpareTable[TableInSpareRegion][BlockID].spareBlockOffsetInSUs;
    619  1.1  oster     if (*outSU >= layoutPtr->stripeUnitsPerDisk) {
    620  1.1  oster 	printf("rf_remap_to_spare_space: invalid remapped disk SU offset %ld\n",(long)*outSU);
    621  1.1  oster     }
    622  1.1  oster }
    623  1.1  oster 
    624  1.1  oster int rf_InstallSpareTable(
    625  1.1  oster   RF_Raid_t    *raidPtr,
    626  1.1  oster   RF_RowCol_t   frow,
    627  1.1  oster   RF_RowCol_t   fcol)
    628  1.1  oster {
    629  1.1  oster   RF_DeclusteredConfigInfo_t *info = (RF_DeclusteredConfigInfo_t *) raidPtr->Layout.layoutSpecificInfo;
    630  1.1  oster   RF_SparetWait_t *req;
    631  1.1  oster   int retcode;
    632  1.1  oster 
    633  1.1  oster   RF_Malloc(req, sizeof(*req), (RF_SparetWait_t *));
    634  1.1  oster   req->C                             = raidPtr->numCol;
    635  1.1  oster   req->G                             = raidPtr->Layout.numDataCol + raidPtr->Layout.numParityCol;
    636  1.1  oster   req->fcol                          = fcol;
    637  1.1  oster   req->SUsPerPU                      = raidPtr->Layout.SUsPerPU;
    638  1.1  oster   req->TablesPerSpareRegion          = info->TablesPerSpareRegion;
    639  1.1  oster   req->BlocksPerTable                = info->BlocksPerTable;
    640  1.1  oster   req->TableDepthInPUs               = info->TableDepthInPUs;
    641  1.1  oster   req->SpareSpaceDepthPerRegionInSUs = info->SpareSpaceDepthPerRegionInSUs;
    642  1.1  oster 
    643  1.1  oster   retcode = rf_GetSpareTableFromDaemon(req);
    644  1.1  oster   RF_ASSERT(!retcode);                                     /* XXX -- fix this to recover gracefully -- XXX */
    645  1.1  oster   return(retcode);
    646  1.1  oster }
    647  1.1  oster 
    648  1.1  oster /*
    649  1.1  oster  * Invoked via ioctl to install a spare table in the kernel.
    650  1.1  oster  */
    651  1.1  oster int rf_SetSpareTable(raidPtr, data)
    652  1.1  oster   RF_Raid_t  *raidPtr;
    653  1.1  oster   void       *data;
    654  1.1  oster {
    655  1.1  oster   RF_DeclusteredConfigInfo_t *info = (RF_DeclusteredConfigInfo_t *) raidPtr->Layout.layoutSpecificInfo;
    656  1.1  oster   RF_SpareTableEntry_t **ptrs;
    657  1.1  oster   int i, retcode;
    658  1.1  oster 
    659  1.1  oster   /* what we need to copyin is a 2-d array, so first copyin the user pointers to the rows in the table */
    660  1.1  oster   RF_Malloc(ptrs, info->TablesPerSpareRegion * sizeof(RF_SpareTableEntry_t *), (RF_SpareTableEntry_t **));
    661  1.1  oster   retcode = copyin((caddr_t) data, (caddr_t) ptrs, info->TablesPerSpareRegion * sizeof(RF_SpareTableEntry_t *));
    662  1.1  oster 
    663  1.1  oster   if (retcode) return(retcode);
    664  1.1  oster 
    665  1.1  oster   /* now allocate kernel space for the row pointers */
    666  1.1  oster   RF_Malloc(info->SpareTable, info->TablesPerSpareRegion * sizeof(RF_SpareTableEntry_t *), (RF_SpareTableEntry_t **));
    667  1.1  oster 
    668  1.1  oster   /* now allocate kernel space for each row in the table, and copy it in from user space */
    669  1.1  oster   for (i=0; i<info->TablesPerSpareRegion; i++) {
    670  1.1  oster     RF_Malloc(info->SpareTable[i], info->BlocksPerTable * sizeof(RF_SpareTableEntry_t), (RF_SpareTableEntry_t *));
    671  1.1  oster     retcode = copyin(ptrs[i], info->SpareTable[i], info->BlocksPerTable * sizeof(RF_SpareTableEntry_t));
    672  1.1  oster     if (retcode) {
    673  1.1  oster       info->SpareTable = NULL;             /* blow off the memory we've allocated */
    674  1.1  oster       return(retcode);
    675  1.1  oster     }
    676  1.1  oster   }
    677  1.1  oster 
    678  1.1  oster   /* free up the temporary array we used */
    679  1.1  oster   RF_Free(ptrs, info->TablesPerSpareRegion * sizeof(RF_SpareTableEntry_t *));
    680  1.1  oster 
    681  1.1  oster   return(0);
    682  1.1  oster }
    683  1.1  oster 
    684  1.1  oster RF_ReconUnitCount_t rf_GetNumSpareRUsDeclustered(raidPtr)
    685  1.1  oster   RF_Raid_t *raidPtr;
    686  1.1  oster {
    687  1.1  oster   RF_RaidLayout_t *layoutPtr = &raidPtr->Layout;
    688  1.1  oster 
    689  1.1  oster   return( ((RF_DeclusteredConfigInfo_t *) layoutPtr->layoutSpecificInfo)->TotSparePUsPerDisk );
    690  1.1  oster }
    691  1.1  oster 
    692  1.1  oster 
    693  1.1  oster void rf_FreeSpareTable(raidPtr)
    694  1.1  oster   RF_Raid_t  *raidPtr;
    695  1.1  oster {
    696  1.1  oster   long i;
    697  1.1  oster   RF_RaidLayout_t *layoutPtr = &raidPtr->Layout;
    698  1.1  oster   RF_DeclusteredConfigInfo_t *info = (RF_DeclusteredConfigInfo_t *) layoutPtr->layoutSpecificInfo;
    699  1.1  oster   RF_SpareTableEntry_t **table = info->SpareTable;
    700  1.1  oster 
    701  1.1  oster   for (i=0; i<info->TablesPerSpareRegion; i++) {RF_Free(table[i], info->BlocksPerTable * sizeof(RF_SpareTableEntry_t));}
    702  1.1  oster   RF_Free(table, info->TablesPerSpareRegion * sizeof(RF_SpareTableEntry_t *));
    703  1.1  oster   info->SpareTable = (RF_SpareTableEntry_t **) NULL;
    704  1.1  oster }
    705