| 1 | /* $NetBSD: rf_reconutil.c,v 1.35 2013/09/15 12:48:58 martin 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@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_reconutil.c -- reconstruction utilities |
| 31 | ********************************************/ |
| 32 | |
| 33 | #include <sys/cdefs.h> |
| 34 | __KERNEL_RCSID(0, "$NetBSD: rf_reconutil.c,v 1.35 2013/09/15 12:48:58 martin Exp $" ); |
| 35 | |
| 36 | #include <dev/raidframe/raidframevar.h> |
| 37 | |
| 38 | #include "rf_raid.h" |
| 39 | #include "rf_desc.h" |
| 40 | #include "rf_reconutil.h" |
| 41 | #include "rf_reconbuffer.h" |
| 42 | #include "rf_general.h" |
| 43 | #include "rf_decluster.h" |
| 44 | #include "rf_raid5_rotatedspare.h" |
| 45 | #include "rf_interdecluster.h" |
| 46 | #include "rf_chaindecluster.h" |
| 47 | |
| 48 | /******************************************************************* |
| 49 | * allocates/frees the reconstruction control information structures |
| 50 | *******************************************************************/ |
| 51 | |
| 52 | /* fcol - failed column |
| 53 | * scol - identifies which spare we are using |
| 54 | */ |
| 55 | |
| 56 | RF_ReconCtrl_t * |
| 57 | rf_MakeReconControl(RF_RaidReconDesc_t *reconDesc, |
| 58 | RF_RowCol_t fcol, RF_RowCol_t scol) |
| 59 | { |
| 60 | RF_Raid_t *raidPtr = reconDesc->raidPtr; |
| 61 | RF_RaidLayout_t *layoutPtr = &raidPtr->Layout; |
| 62 | RF_ReconUnitCount_t RUsPerPU = layoutPtr->SUsPerPU / layoutPtr->SUsPerRU; |
| 63 | RF_ReconUnitCount_t numSpareRUs; |
| 64 | RF_ReconCtrl_t *reconCtrlPtr; |
| 65 | RF_ReconBuffer_t *rbuf; |
| 66 | const RF_LayoutSW_t *lp; |
| 67 | #if (RF_INCLUDE_PARITY_DECLUSTERING_DS > 0) |
| 68 | int retcode; |
| 69 | #endif |
| 70 | RF_RowCol_t i; |
| 71 | |
| 72 | lp = raidPtr->Layout.map; |
| 73 | |
| 74 | /* make and zero the global reconstruction structure and the per-disk |
| 75 | * structure */ |
| 76 | RF_Malloc(reconCtrlPtr, sizeof(RF_ReconCtrl_t), (RF_ReconCtrl_t *)); |
| 77 | |
| 78 | /* note: this zeros the perDiskInfo */ |
| 79 | RF_Malloc(reconCtrlPtr->perDiskInfo, raidPtr->numCol * |
| 80 | sizeof(RF_PerDiskReconCtrl_t), (RF_PerDiskReconCtrl_t *)); |
| 81 | reconCtrlPtr->reconDesc = reconDesc; |
| 82 | reconCtrlPtr->fcol = fcol; |
| 83 | reconCtrlPtr->spareCol = scol; |
| 84 | reconCtrlPtr->lastPSID = layoutPtr->numStripe / layoutPtr->SUsPerPU; |
| 85 | reconCtrlPtr->percentComplete = 0; |
| 86 | reconCtrlPtr->error = 0; |
| 87 | reconCtrlPtr->pending_writes = 0; |
| 88 | |
| 89 | /* initialize each per-disk recon information structure */ |
| 90 | for (i = 0; i < raidPtr->numCol; i++) { |
| 91 | reconCtrlPtr->perDiskInfo[i].reconCtrl = reconCtrlPtr; |
| 92 | reconCtrlPtr->perDiskInfo[i].col = i; |
| 93 | /* make it appear as if we just finished an RU */ |
| 94 | reconCtrlPtr->perDiskInfo[i].curPSID = -1; |
| 95 | reconCtrlPtr->perDiskInfo[i].ru_count = RUsPerPU - 1; |
| 96 | } |
| 97 | |
| 98 | /* Get the number of spare units per disk and the sparemap in case |
| 99 | * spare is distributed */ |
| 100 | |
| 101 | if (lp->GetNumSpareRUs) { |
| 102 | numSpareRUs = lp->GetNumSpareRUs(raidPtr); |
| 103 | } else { |
| 104 | numSpareRUs = 0; |
| 105 | } |
| 106 | |
| 107 | #if (RF_INCLUDE_PARITY_DECLUSTERING_DS > 0) |
| 108 | /* |
| 109 | * Not all distributed sparing archs need dynamic mappings |
| 110 | */ |
| 111 | if (lp->InstallSpareTable) { |
| 112 | retcode = rf_InstallSpareTable(raidPtr, 0, fcol); |
| 113 | if (retcode) { |
| 114 | RF_PANIC(); /* XXX fix this */ |
| 115 | } |
| 116 | } |
| 117 | #endif |
| 118 | /* make the reconstruction map */ |
| 119 | reconCtrlPtr->reconMap = rf_MakeReconMap(raidPtr, (int) (layoutPtr->SUsPerRU * layoutPtr->sectorsPerStripeUnit), |
| 120 | raidPtr->sectorsPerDisk, numSpareRUs); |
| 121 | |
| 122 | /* make the per-disk reconstruction buffers */ |
| 123 | for (i = 0; i < raidPtr->numCol; i++) { |
| 124 | reconCtrlPtr->perDiskInfo[i].rbuf = (i == fcol) ? NULL : rf_MakeReconBuffer(raidPtr, i, RF_RBUF_TYPE_EXCLUSIVE); |
| 125 | } |
| 126 | |
| 127 | /* initialize the event queue */ |
| 128 | rf_init_mutex2(reconCtrlPtr->eq_mutex, IPL_VM); |
| 129 | rf_init_cond2(reconCtrlPtr->eq_cv, "rfevq" ); |
| 130 | |
| 131 | reconCtrlPtr->eventQueue = NULL; |
| 132 | reconCtrlPtr->eq_count = 0; |
| 133 | |
| 134 | /* make the floating recon buffers and append them to the free list */ |
| 135 | rf_init_mutex2(reconCtrlPtr->rb_mutex, IPL_VM); |
| 136 | rf_init_cond2(reconCtrlPtr->rb_cv, "rfrcw" ); |
| 137 | |
| 138 | reconCtrlPtr->fullBufferList = NULL; |
| 139 | reconCtrlPtr->floatingRbufs = NULL; |
| 140 | reconCtrlPtr->committedRbufs = NULL; |
| 141 | for (i = 0; i < raidPtr->numFloatingReconBufs; i++) { |
| 142 | rbuf = rf_MakeReconBuffer(raidPtr, fcol, |
| 143 | RF_RBUF_TYPE_FLOATING); |
| 144 | rbuf->next = reconCtrlPtr->floatingRbufs; |
| 145 | reconCtrlPtr->floatingRbufs = rbuf; |
| 146 | } |
| 147 | |
| 148 | /* create the parity stripe status table */ |
| 149 | reconCtrlPtr->pssTable = rf_MakeParityStripeStatusTable(raidPtr); |
| 150 | |
| 151 | /* set the initial min head sep counter val */ |
| 152 | reconCtrlPtr->minHeadSepCounter = 0; |
| 153 | |
| 154 | return (reconCtrlPtr); |
| 155 | } |
| 156 | |
| 157 | void |
| 158 | rf_FreeReconControl(RF_Raid_t *raidPtr) |
| 159 | { |
| 160 | RF_ReconCtrl_t *reconCtrlPtr = raidPtr->reconControl; |
| 161 | RF_ReconBuffer_t *t; |
| 162 | RF_ReconUnitNum_t i; |
| 163 | |
| 164 | RF_ASSERT(reconCtrlPtr); |
| 165 | for (i = 0; i < raidPtr->numCol; i++) |
| 166 | if (reconCtrlPtr->perDiskInfo[i].rbuf) |
| 167 | rf_FreeReconBuffer(reconCtrlPtr->perDiskInfo[i].rbuf); |
| 168 | |
| 169 | t = reconCtrlPtr->floatingRbufs; |
| 170 | while (t) { |
| 171 | reconCtrlPtr->floatingRbufs = t->next; |
| 172 | rf_FreeReconBuffer(t); |
| 173 | t = reconCtrlPtr->floatingRbufs; |
| 174 | } |
| 175 | |
| 176 | rf_destroy_mutex2(reconCtrlPtr->eq_mutex); |
| 177 | rf_destroy_cond2(reconCtrlPtr->eq_cv); |
| 178 | |
| 179 | rf_destroy_mutex2(reconCtrlPtr->rb_mutex); |
| 180 | rf_destroy_cond2(reconCtrlPtr->rb_cv); |
| 181 | |
| 182 | rf_FreeReconMap(reconCtrlPtr->reconMap); |
| 183 | rf_FreeParityStripeStatusTable(raidPtr, reconCtrlPtr->pssTable); |
| 184 | RF_Free(reconCtrlPtr->perDiskInfo, |
| 185 | raidPtr->numCol * sizeof(RF_PerDiskReconCtrl_t)); |
| 186 | RF_Free(reconCtrlPtr, sizeof(*reconCtrlPtr)); |
| 187 | } |
| 188 | |
| 189 | |
| 190 | /****************************************************************************** |
| 191 | * computes the default head separation limit |
| 192 | *****************************************************************************/ |
| 193 | RF_HeadSepLimit_t |
| 194 | rf_GetDefaultHeadSepLimit(RF_Raid_t *raidPtr) |
| 195 | { |
| 196 | RF_HeadSepLimit_t hsl; |
| 197 | const RF_LayoutSW_t *lp; |
| 198 | |
| 199 | lp = raidPtr->Layout.map; |
| 200 | if (lp->GetDefaultHeadSepLimit == NULL) |
| 201 | return (-1); |
| 202 | hsl = lp->GetDefaultHeadSepLimit(raidPtr); |
| 203 | return (hsl); |
| 204 | } |
| 205 | |
| 206 | |
| 207 | /****************************************************************************** |
| 208 | * computes the default number of floating recon buffers |
| 209 | *****************************************************************************/ |
| 210 | int |
| 211 | rf_GetDefaultNumFloatingReconBuffers(RF_Raid_t *raidPtr) |
| 212 | { |
| 213 | const RF_LayoutSW_t *lp; |
| 214 | int nrb; |
| 215 | |
| 216 | lp = raidPtr->Layout.map; |
| 217 | if (lp->GetDefaultNumFloatingReconBuffers == NULL) |
| 218 | return (3 * raidPtr->numCol); |
| 219 | nrb = lp->GetDefaultNumFloatingReconBuffers(raidPtr); |
| 220 | return (nrb); |
| 221 | } |
| 222 | |
| 223 | |
| 224 | /****************************************************************************** |
| 225 | * creates and initializes a reconstruction buffer |
| 226 | *****************************************************************************/ |
| 227 | RF_ReconBuffer_t * |
| 228 | rf_MakeReconBuffer(RF_Raid_t *raidPtr, RF_RowCol_t col, RF_RbufType_t type) |
| 229 | { |
| 230 | RF_RaidLayout_t *layoutPtr = &raidPtr->Layout; |
| 231 | RF_ReconBuffer_t *t; |
| 232 | u_int recon_buffer_size = rf_RaidAddressToByte(raidPtr, layoutPtr->SUsPerRU * layoutPtr->sectorsPerStripeUnit); |
| 233 | |
| 234 | t = pool_get(&rf_pools.reconbuffer, PR_WAITOK); |
| 235 | RF_Malloc(t->buffer, recon_buffer_size, (void *)); |
| 236 | t->raidPtr = raidPtr; |
| 237 | t->col = col; |
| 238 | t->priority = RF_IO_RECON_PRIORITY; |
| 239 | t->type = type; |
| 240 | t->pssPtr = NULL; |
| 241 | t->next = NULL; |
| 242 | return (t); |
| 243 | } |
| 244 | /****************************************************************************** |
| 245 | * frees a reconstruction buffer |
| 246 | *****************************************************************************/ |
| 247 | void |
| 248 | rf_FreeReconBuffer(RF_ReconBuffer_t *rbuf) |
| 249 | { |
| 250 | RF_Raid_t *raidPtr = rbuf->raidPtr; |
| 251 | u_int recon_buffer_size __unused; |
| 252 | |
| 253 | recon_buffer_size = rf_RaidAddressToByte(raidPtr, raidPtr->Layout.SUsPerRU * raidPtr->Layout.sectorsPerStripeUnit); |
| 254 | |
| 255 | RF_Free(rbuf->buffer, recon_buffer_size); |
| 256 | pool_put(&rf_pools.reconbuffer, rbuf); |
| 257 | } |
| 258 | |
| 259 | #if RF_DEBUG_RECON |
| 260 | XXXX IF you use this, you really want to fix the locking in here. |
| 261 | /****************************************************************************** |
| 262 | * debug only: sanity check the number of floating recon bufs in use |
| 263 | *****************************************************************************/ |
| 264 | void |
| 265 | rf_CheckFloatingRbufCount(RF_Raid_t *raidPtr, int dolock) |
| 266 | { |
| 267 | RF_ReconParityStripeStatus_t *p; |
| 268 | RF_PSStatusHeader_t *pssTable; |
| 269 | RF_ReconBuffer_t *rbuf; |
| 270 | int i, j, sum = 0; |
| 271 | |
| 272 | if (dolock) |
| 273 | rf_lock_mutex2(raidPtr->reconControl->rb_mutex); |
| 274 | pssTable = raidPtr->reconControl->pssTable; |
| 275 | |
| 276 | for (i = 0; i < raidPtr->pssTableSize; i++) { |
| 277 | rf_lock_mutex2(pssTable[i].mutex); |
| 278 | for (p = pssTable[i].chain; p; p = p->next) { |
| 279 | rbuf = (RF_ReconBuffer_t *) p->rbuf; |
| 280 | if (rbuf && rbuf->type == RF_RBUF_TYPE_FLOATING) |
| 281 | sum++; |
| 282 | |
| 283 | rbuf = (RF_ReconBuffer_t *) p->writeRbuf; |
| 284 | if (rbuf && rbuf->type == RF_RBUF_TYPE_FLOATING) |
| 285 | sum++; |
| 286 | |
| 287 | for (j = 0; j < p->xorBufCount; j++) { |
| 288 | rbuf = (RF_ReconBuffer_t *) p->rbufsForXor[j]; |
| 289 | RF_ASSERT(rbuf); |
| 290 | if (rbuf->type == RF_RBUF_TYPE_FLOATING) |
| 291 | sum++; |
| 292 | } |
| 293 | } |
| 294 | rf_unlock_mutex2(pssTable[i].mutex); |
| 295 | } |
| 296 | |
| 297 | for (rbuf = raidPtr->reconControl->floatingRbufs; rbuf; |
| 298 | rbuf = rbuf->next) { |
| 299 | if (rbuf->type == RF_RBUF_TYPE_FLOATING) |
| 300 | sum++; |
| 301 | } |
| 302 | for (rbuf = raidPtr->reconControl->committedRbufs; rbuf; |
| 303 | rbuf = rbuf->next) { |
| 304 | if (rbuf->type == RF_RBUF_TYPE_FLOATING) |
| 305 | sum++; |
| 306 | } |
| 307 | for (rbuf = raidPtr->reconControl->fullBufferList; rbuf; |
| 308 | rbuf = rbuf->next) { |
| 309 | if (rbuf->type == RF_RBUF_TYPE_FLOATING) |
| 310 | sum++; |
| 311 | } |
| 312 | RF_ASSERT(sum == raidPtr->numFloatingReconBufs); |
| 313 | |
| 314 | if (dolock) |
| 315 | rf_unlock_mutex2(raidPtr->reconControl->rb_mutex); |
| 316 | } |
| 317 | #endif |
| 318 | |
| 319 | |