1 /* $NetBSD: rf_reconstruct.c,v 1.132 2026/10/28 21:33:13 tls 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 * 31 * rf_reconstruct.c -- code to perform on-line reconstruction 32 * 33 ************************************************************/ 34 35 #include <sys/cdefs.h> 36 __KERNEL_RCSID(0, "$NetBSD: rf_reconstruct.c,v 1.132 2026/10/28 21:33:13 tls Exp $"); 37 38 #include <sys/param.h> 39 #include <sys/time.h> 40 #include <sys/buf.h> 41 #include <sys/errno.h> 42 #include <sys/systm.h> 43 #include <sys/proc.h> 44 #include <sys/ioctl.h> 45 #include <sys/fcntl.h> 46 #include <sys/vnode.h> 47 #include <sys/namei.h> /* for pathbuf */ 48 #include <dev/raidframe/raidframevar.h> 49 50 #include <miscfs/specfs/specdev.h> /* for v_rdev */ 51 52 #include "rf_raid.h" 53 #include "rf_reconutil.h" 54 #include "rf_revent.h" 55 #include "rf_reconbuffer.h" 56 #include "rf_acctrace.h" 57 #include "rf_etimer.h" 58 #include "rf_dag.h" 59 #include "rf_desc.h" 60 #include "rf_debugprint.h" 61 #include "rf_general.h" 62 #include "rf_driver.h" 63 #include "rf_utils.h" 64 #include "rf_shutdown.h" 65 66 #include "rf_kintf.h" 67 68 /* setting these to -1 causes them to be set to their default values if not set by debug options */ 69 70 #if RF_DEBUG_RECON 71 #define Dprintf(s) if (rf_reconDebug) rf_debug_printf(s,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL) 72 #define Dprintf1(s,a) if (rf_reconDebug) rf_debug_printf(s,(void *)((unsigned long)a),NULL,NULL,NULL,NULL,NULL,NULL,NULL) 73 #define Dprintf2(s,a,b) if (rf_reconDebug) rf_debug_printf(s,(void *)((unsigned long)a),(void *)((unsigned long)b),NULL,NULL,NULL,NULL,NULL,NULL) 74 #define Dprintf3(s,a,b,c) if (rf_reconDebug) rf_debug_printf(s,(void *)((unsigned long)a),(void *)((unsigned long)b),(void *)((unsigned long)c),NULL,NULL,NULL,NULL,NULL) 75 #define Dprintf4(s,a,b,c,d) if (rf_reconDebug) rf_debug_printf(s,(void *)((unsigned long)a),(void *)((unsigned long)b),(void *)((unsigned long)c),(void *)((unsigned long)d),NULL,NULL,NULL,NULL) 76 #define Dprintf5(s,a,b,c,d,e) if (rf_reconDebug) rf_debug_printf(s,(void *)((unsigned long)a),(void *)((unsigned long)b),(void *)((unsigned long)c),(void *)((unsigned long)d),(void *)((unsigned long)e),NULL,NULL,NULL) 77 #define Dprintf6(s,a,b,c,d,e,f) if (rf_reconDebug) rf_debug_printf(s,(void *)((unsigned long)a),(void *)((unsigned long)b),(void *)((unsigned long)c),(void *)((unsigned long)d),(void *)((unsigned long)e),(void *)((unsigned long)f),NULL,NULL) 78 #define Dprintf7(s,a,b,c,d,e,f,g) if (rf_reconDebug) rf_debug_printf(s,(void *)((unsigned long)a),(void *)((unsigned long)b),(void *)((unsigned long)c),(void *)((unsigned long)d),(void *)((unsigned long)e),(void *)((unsigned long)f),(void *)((unsigned long)g),NULL) 79 80 #define DDprintf1(s,a) if (rf_reconDebug) rf_debug_printf(s,(void *)((unsigned long)a),NULL,NULL,NULL,NULL,NULL,NULL,NULL) 81 #define DDprintf2(s,a,b) if (rf_reconDebug) rf_debug_printf(s,(void *)((unsigned long)a),(void *)((unsigned long)b),NULL,NULL,NULL,NULL,NULL,NULL) 82 83 #else /* RF_DEBUG_RECON */ 84 85 #define Dprintf(s) {} 86 #define Dprintf1(s,a) {} 87 #define Dprintf2(s,a,b) {} 88 #define Dprintf3(s,a,b,c) {} 89 #define Dprintf4(s,a,b,c,d) {} 90 #define Dprintf5(s,a,b,c,d,e) {} 91 #define Dprintf6(s,a,b,c,d,e,f) {} 92 #define Dprintf7(s,a,b,c,d,e,f,g) {} 93 94 #define DDprintf1(s,a) {} 95 #define DDprintf2(s,a,b) {} 96 97 #endif /* RF_DEBUG_RECON */ 98 99 #define RF_RECON_DONE_READS 1 100 #define RF_RECON_READ_ERROR 2 101 #define RF_RECON_WRITE_ERROR 3 102 #define RF_RECON_READ_STOPPED 4 103 #define RF_RECON_WRITE_DONE 5 104 105 static RF_RaidReconDesc_t *AllocRaidReconDesc(RF_Raid_t *, RF_RowCol_t, 106 RF_RaidDisk_t *, int, RF_RowCol_t); 107 static void FreeReconDesc(RF_RaidReconDesc_t *); 108 static int ProcessReconEvent(RF_Raid_t *, RF_ReconEvent_t *); 109 static int IssueNextReadRequest(RF_Raid_t *, RF_RowCol_t); 110 static int TryToRead(RF_Raid_t *, RF_RowCol_t); 111 static int ComputePSDiskOffsets(RF_Raid_t *, RF_StripeNum_t, RF_RowCol_t, 112 RF_SectorNum_t *, RF_SectorNum_t *, RF_RowCol_t *, 113 RF_SectorNum_t *); 114 static int IssueNextWriteRequest(RF_Raid_t *); 115 static void ReconReadDoneProc(void *, int); 116 static void ReconWriteDoneProc(void *, int); 117 static void CheckForNewMinHeadSep(RF_Raid_t *, RF_HeadSepLimit_t); 118 static int CheckHeadSeparation(RF_Raid_t *, RF_PerDiskReconCtrl_t *, 119 RF_RowCol_t, RF_HeadSepLimit_t, 120 RF_ReconUnitNum_t); 121 static int CheckForcedOrBlockedReconstruction(RF_Raid_t *, 122 RF_ReconParityStripeStatus_t *, 123 RF_PerDiskReconCtrl_t *, 124 RF_RowCol_t, RF_StripeNum_t, 125 RF_ReconUnitNum_t); 126 static void ForceReconReadDoneProc(void *, int); 127 static void rf_ShutdownReconstruction(void *); 128 129 struct RF_ReconDoneProc_s { 130 void (*proc) (RF_Raid_t *, void *); 131 void *arg; 132 RF_ReconDoneProc_t *next; 133 }; 134 135 /************************************************************************** 136 * 137 * sets up the parameters that will be used by the reconstruction process 138 * currently there are none, except for those that the layout-specific 139 * configuration (e.g. rf_ConfigureDeclustered) routine sets up. 140 * 141 * in the kernel, we fire off the recon thread. 142 * 143 **************************************************************************/ 144 static void 145 rf_ShutdownReconstruction(void *arg) 146 { 147 RF_Raid_t *raidPtr; 148 149 raidPtr = (RF_Raid_t *) arg; 150 151 pool_destroy(&raidPtr->pools.reconbuffer); 152 } 153 154 int 155 rf_ConfigureReconstruction(RF_ShutdownList_t **listp, RF_Raid_t *raidPtr, 156 RF_Config_t *cfgPtr) 157 { 158 size_t min_reconbuf, max_reconbuf; 159 u_int c; 160 161 if (raidPtr->Layout.map->SubmitReconBuffer == NULL) { 162 min_reconbuf = 0; 163 max_reconbuf = 0; 164 } else { 165 c = raidPtr->numCol; 166 /* c-1 exclusive + numFloatingReconBufs + c-1 forced rbufs. */ 167 min_reconbuf = 2 * (c - 1) + raidPtr->numFloatingReconBufs; 168 max_reconbuf = 2 * min_reconbuf; 169 } 170 171 rf_pool_init(raidPtr, raidPtr->poolNames.reconbuffer, &raidPtr->pools.reconbuffer, sizeof(RF_ReconBuffer_t), 172 "reconbuf", min_reconbuf, max_reconbuf); 173 rf_ShutdownCreate(listp, rf_ShutdownReconstruction, raidPtr); 174 175 return (0); 176 } 177 178 static RF_RaidReconDesc_t * 179 AllocRaidReconDesc(RF_Raid_t *raidPtr, RF_RowCol_t col, 180 RF_RaidDisk_t *spareDiskPtr, int numDisksDone, 181 RF_RowCol_t scol) 182 { 183 184 RF_RaidReconDesc_t *reconDesc; 185 186 reconDesc = RF_Malloc(sizeof(*reconDesc)); 187 reconDesc->raidPtr = raidPtr; 188 reconDesc->col = col; 189 reconDesc->spareDiskPtr = spareDiskPtr; 190 reconDesc->numDisksDone = numDisksDone; 191 reconDesc->scol = scol; 192 reconDesc->next = NULL; 193 194 return (reconDesc); 195 } 196 197 static void 198 FreeReconDesc(RF_RaidReconDesc_t *reconDesc) 199 { 200 #if RF_RECON_STATS > 0 201 printf("raid%d: %lu recon event waits, %lu recon delays\n", 202 reconDesc->raidPtr->raidid, 203 (long) reconDesc->numReconEventWaits, 204 (long) reconDesc->numReconExecDelays); 205 #endif /* RF_RECON_STATS > 0 */ 206 printf("raid%d: %lu max exec ticks\n", 207 reconDesc->raidPtr->raidid, 208 (long) reconDesc->maxReconExecTicks); 209 RF_Free(reconDesc, sizeof(RF_RaidReconDesc_t)); 210 } 211 212 213 /***************************************************************************** 214 * 215 * primary routine to reconstruct a failed disk. This should be called from 216 * within its own thread. It won't return until reconstruction completes, 217 * fails, or is aborted. 218 *****************************************************************************/ 219 int 220 rf_ReconstructFailedDisk(RF_Raid_t *raidPtr, RF_RowCol_t col) 221 { 222 const RF_LayoutSW_t *lp; 223 int rc; 224 225 lp = raidPtr->Layout.map; 226 if (lp->SubmitReconBuffer) { 227 /* 228 * The current infrastructure only supports reconstructing one 229 * disk at a time for each array. 230 */ 231 rf_lock_mutex2(raidPtr->mutex); 232 while (raidPtr->reconInProgress) { 233 rf_wait_cond2(raidPtr->waitForReconCond, raidPtr->mutex); 234 } 235 raidPtr->reconInProgress++; 236 rf_unlock_mutex2(raidPtr->mutex); 237 rc = rf_ReconstructFailedDiskBasic(raidPtr, col); 238 rf_lock_mutex2(raidPtr->mutex); 239 raidPtr->reconInProgress--; 240 } else { 241 RF_ERRORMSG1("RECON: no way to reconstruct failed disk for arch %c\n", 242 lp->parityConfig); 243 rc = EIO; 244 rf_lock_mutex2(raidPtr->mutex); 245 } 246 rf_signal_cond2(raidPtr->waitForReconCond); 247 rf_unlock_mutex2(raidPtr->mutex); 248 return (rc); 249 } 250 251 int 252 rf_ReconstructFailedDiskBasic(RF_Raid_t *raidPtr, RF_RowCol_t col) 253 { 254 RF_ComponentLabel_t *c_label; 255 RF_RaidDisk_t *spareDiskPtr = NULL; 256 RF_RaidReconDesc_t *reconDesc; 257 RF_RowCol_t scol; 258 int numDisksDone = 0, rc; 259 260 /* first look for a spare drive onto which to reconstruct the data */ 261 /* spare disk descriptors are stored in row 0. This may have to 262 * change eventually */ 263 264 rf_lock_mutex2(raidPtr->mutex); 265 RF_ASSERT(raidPtr->Disks[col].status == rf_ds_failed); 266 #if RF_INCLUDE_PARITY_DECLUSTERING_DS > 0 267 if (raidPtr->Layout.map->flags & RF_DISTRIBUTE_SPARE) { 268 if (raidPtr->status != rf_rs_degraded) { 269 RF_ERRORMSG1("Unable to reconstruct disk at col %d because status not degraded\n", col); 270 rf_unlock_mutex2(raidPtr->mutex); 271 return (EINVAL); 272 } 273 scol = (-1); 274 } else { 275 #endif 276 for (scol = raidPtr->numCol; scol < raidPtr->numCol + raidPtr->numSpare; scol++) { 277 if (raidPtr->Disks[scol].status == rf_ds_spare) { 278 spareDiskPtr = &raidPtr->Disks[scol]; 279 spareDiskPtr->status = rf_ds_rebuilding_spare; 280 break; 281 } 282 } 283 if (!spareDiskPtr) { 284 RF_ERRORMSG1("Unable to reconstruct disk at col %d because no spares are available\n", col); 285 rf_unlock_mutex2(raidPtr->mutex); 286 return (ENOSPC); 287 } 288 printf("RECON: initiating reconstruction on col %d -> spare at col %d\n", col, scol); 289 #if RF_INCLUDE_PARITY_DECLUSTERING_DS > 0 290 } 291 #endif 292 rf_unlock_mutex2(raidPtr->mutex); 293 294 reconDesc = AllocRaidReconDesc((void *) raidPtr, col, spareDiskPtr, numDisksDone, scol); 295 raidPtr->reconDesc = (void *) reconDesc; 296 #if RF_RECON_STATS > 0 297 reconDesc->hsStallCount = 0; 298 reconDesc->numReconExecDelays = 0; 299 reconDesc->numReconEventWaits = 0; 300 #endif /* RF_RECON_STATS > 0 */ 301 reconDesc->reconExecTimerRunning = 0; 302 reconDesc->reconExecTicks = 0; 303 reconDesc->maxReconExecTicks = 0; 304 rc = rf_ContinueReconstructFailedDisk(reconDesc); 305 306 if (!rc) { 307 /* fix up the component label. Note that at this point col and scol have swapped places. */ 308 /* We need to read from the *spared* disk, but use that label for the real component */ 309 310 c_label = raidget_component_label(raidPtr, col); 311 312 raid_init_component_label(raidPtr, c_label); 313 c_label->row = 0; 314 c_label->column = col; 315 c_label->clean = RF_RAID_DIRTY; 316 c_label->status = rf_ds_optimal; 317 rf_component_label_set_partitionsize(c_label, 318 raidPtr->Disks[col].partitionSize); 319 320 /* We've just done a rebuild based on all the other 321 disks, so at this point the parity is known to be 322 clean, even if it wasn't before. */ 323 324 /* XXX doesn't hold for RAID 6!!*/ 325 326 rf_lock_mutex2(raidPtr->mutex); 327 /* The failed disk has already been marked as rf_ds_spared 328 (or rf_ds_dist_spared) in 329 rf_ContinueReconstructFailedDisk() 330 so we just update the spare disk as being a used spare 331 */ 332 333 raidPtr->parity_good = RF_RAID_CLEAN; 334 rf_unlock_mutex2(raidPtr->mutex); 335 336 /* XXXX MORE NEEDED HERE */ 337 raidflush_component_label(raidPtr, col); 338 } else { 339 /* Reconstruct failed. */ 340 341 rf_lock_mutex2(raidPtr->mutex); 342 /* Failed disk goes back to "failed" status */ 343 raidPtr->Disks[col].status = rf_ds_failed; 344 345 /* Spare disk goes back to "spare" status if it didn't fail. */ 346 if (spareDiskPtr->status == rf_ds_rebuilding_spare) 347 spareDiskPtr->status = rf_ds_spare; 348 rf_unlock_mutex2(raidPtr->mutex); 349 350 } 351 rf_update_component_labels(raidPtr, RF_NORMAL_COMPONENT_UPDATE); 352 return (rc); 353 } 354 355 /* 356 357 Allow reconstructing a disk in-place -- i.e. component /dev/sd2e goes AWOL, 358 and you don't get a spare until the next Monday. With this function 359 (and hot-swappable drives) you can now put your new disk containing 360 /dev/sd2e on the bus, scsictl it alive, and then use raidctl(8) to 361 rebuild the data "on the spot". 362 363 */ 364 365 int 366 rf_ReconstructInPlace(RF_Raid_t *raidPtr, RF_RowCol_t col) 367 { 368 RF_RaidDisk_t *spareDiskPtr = NULL; 369 RF_RaidReconDesc_t *reconDesc; 370 const RF_LayoutSW_t *lp; 371 RF_ComponentLabel_t *c_label; 372 RF_RowCol_t fcol, scol; 373 RF_SectorCount_t numBlocks; 374 int numDisksDone = 0, rc; 375 uint64_t numsec; 376 unsigned int secsize, bs; 377 struct pathbuf *pb; 378 struct vnode *vp; 379 int retcode; 380 int ac; 381 382 rf_lock_mutex2(raidPtr->mutex); 383 lp = raidPtr->Layout.map; 384 if (!lp->SubmitReconBuffer) { 385 RF_ERRORMSG1("RECON: no way to reconstruct failed disk for arch %c\n", 386 lp->parityConfig); 387 /* wakeup anyone who might be waiting to do a reconstruct */ 388 rf_signal_cond2(raidPtr->waitForReconCond); 389 rf_unlock_mutex2(raidPtr->mutex); 390 return(EIO); 391 } 392 393 /* 394 * The current infrastructure only supports reconstructing one 395 * disk at a time for each array. 396 */ 397 scol = col; 398 if (col < raidPtr->numCol) { 399 fcol = col; 400 if (raidPtr->Disks[fcol].status != rf_ds_failed) { 401 /* "It's gone..." */ 402 raidPtr->numFailures++; 403 raidPtr->Disks[fcol].status = rf_ds_failed; 404 raidPtr->status = rf_rs_degraded; 405 rf_unlock_mutex2(raidPtr->mutex); 406 rf_update_component_labels(raidPtr, 407 RF_NORMAL_COMPONENT_UPDATE); 408 rf_lock_mutex2(raidPtr->mutex); 409 } 410 } else { 411 fcol = -1; 412 for (int c = 0; c < raidPtr->numCol; c++) { 413 if (raidPtr->Disks[c].status == rf_ds_failed) { 414 fcol = c; 415 break; 416 } 417 } 418 if (fcol == -1 || raidPtr->numFailures != 1 || /* XXX RAID6 */ 419 scol >= raidPtr->numCol + raidPtr->numSpare) { 420 rf_signal_cond2(raidPtr->waitForReconCond); 421 rf_unlock_mutex2(raidPtr->mutex); 422 return (EINVAL); 423 } 424 } 425 426 while (raidPtr->reconInProgress) { 427 rf_wait_cond2(raidPtr->waitForReconCond, raidPtr->mutex); 428 } 429 430 raidPtr->reconInProgress++; 431 432 /* first look for a spare drive onto which to reconstruct the 433 data. spare disk descriptors are stored in row 0. This 434 may have to change eventually */ 435 436 /* Actually, we don't care if it's failed or not... On a RAID 437 set with correct parity, this function should be callable 438 on any component without ill effects. */ 439 /* RF_ASSERT(raidPtr->Disks[fcol].status == rf_ds_failed); */ 440 441 #if RF_INCLUDE_PARITY_DECLUSTERING_DS > 0 442 if (raidPtr->Layout.map->flags & RF_DISTRIBUTE_SPARE) { 443 RF_ERRORMSG1("Unable to reconstruct to disk at col %d: operation not supported for RF_DISTRIBUTE_SPARE\n", col); 444 445 raidPtr->reconInProgress--; 446 rf_signal_cond2(raidPtr->waitForReconCond); 447 rf_unlock_mutex2(raidPtr->mutex); 448 return (EINVAL); 449 } 450 #endif 451 452 /* This device may have been opened successfully the 453 first time. Close it before trying to open it again.. */ 454 455 if (raidPtr->raid_cinfo[scol].ci_vp != NULL) { 456 #if 0 457 printf("Closed the open device: %s\n", 458 raidPtr->Disks[scol].devname); 459 #endif 460 vp = raidPtr->raid_cinfo[scol].ci_vp; 461 ac = raidPtr->Disks[scol].auto_configured; 462 rf_unlock_mutex2(raidPtr->mutex); 463 c_label = raidget_component_label(raidPtr, scol); 464 memset(c_label, 0, sizeof(*c_label)); 465 (void)raidflush_component_label(raidPtr, scol); 466 rf_close_component(raidPtr, vp, ac); 467 rf_lock_mutex2(raidPtr->mutex); 468 raidPtr->raid_cinfo[scol].ci_vp = NULL; 469 } 470 /* note that this disk was *not* auto_configured (any longer)*/ 471 raidPtr->Disks[scol].auto_configured = 0; 472 473 #if 0 474 printf("About to (re-)open the device for rebuilding: %s\n", 475 raidPtr->Disks[scol].devname); 476 #endif 477 rf_unlock_mutex2(raidPtr->mutex); 478 pb = pathbuf_create(raidPtr->Disks[scol].devname); 479 if (pb == NULL) { 480 retcode = ENOMEM; 481 } else { 482 retcode = vn_bdev_openpath(pb, &vp, curlwp); 483 pathbuf_destroy(pb); 484 } 485 486 if (retcode) { 487 printf("raid%d: rebuilding: open device: %s failed: %d!\n",raidPtr->raidid, 488 raidPtr->Disks[scol].devname, retcode); 489 490 /* the component isn't responding properly... 491 must be still dead :-( */ 492 rf_lock_mutex2(raidPtr->mutex); 493 raidPtr->Disks[scol].status = rf_ds_failed; 494 raidPtr->reconInProgress--; 495 rf_signal_cond2(raidPtr->waitForReconCond); 496 rf_unlock_mutex2(raidPtr->mutex); 497 return(retcode); 498 } 499 500 /* Ok, so we can at least do a lookup... 501 How about actually getting a vp for it? */ 502 503 retcode = getdisksize(vp, &numsec, &secsize); 504 if (retcode) { 505 vn_close(vp, FREAD | FWRITE, kauth_cred_get()); 506 rf_lock_mutex2(raidPtr->mutex); 507 raidPtr->Disks[scol].status = rf_ds_failed; 508 raidPtr->reconInProgress--; 509 rf_signal_cond2(raidPtr->waitForReconCond); 510 rf_unlock_mutex2(raidPtr->mutex); 511 return(retcode); 512 } 513 514 bs = 1 << raidPtr->logBytesPerSector; 515 if (secsize != bs) { 516 RF_ERRORMSG3("Block size of %d on disk %s is not the same as on other disks (%d)\n", 517 secsize, raidPtr->Disks[scol].devname, bs); 518 vn_close(vp, FREAD | FWRITE, kauth_cred_get()); 519 rf_lock_mutex2(raidPtr->mutex); 520 raidPtr->Disks[scol].status = rf_ds_failed; 521 raidPtr->reconInProgress--; 522 rf_signal_cond2(raidPtr->waitForReconCond); 523 rf_unlock_mutex2(raidPtr->mutex); 524 return (EINVAL); 525 } 526 527 numBlocks = (numsec - rf_protectedSectors) * rf_sizePercentage / 100; 528 if (numBlocks < raidPtr->sectorsPerDisk) { 529 RF_ERRORMSG3("Disk %s (%" PRIu64 " blocks) is too small to rebuild (need %" PRIu64 " blocks)\n", 530 raidPtr->Disks[scol].devname, numBlocks, 531 raidPtr->sectorsPerDisk); 532 vn_close(vp, FREAD | FWRITE, kauth_cred_get()); 533 rf_lock_mutex2(raidPtr->mutex); 534 raidPtr->Disks[scol].status = rf_ds_failed; 535 raidPtr->reconInProgress--; 536 rf_signal_cond2(raidPtr->waitForReconCond); 537 rf_unlock_mutex2(raidPtr->mutex); 538 return (EINVAL); 539 } 540 if (numBlocks > raidPtr->sectorsPerDisk) { 541 RF_ERRORMSG3("Warning: truncating disk %s to %" PRIu64 " blocks (from %" PRIu64 ")\n", 542 raidPtr->Disks[scol].devname, raidPtr->sectorsPerDisk, 543 numBlocks); 544 numBlocks = raidPtr->sectorsPerDisk; 545 } 546 547 rf_lock_mutex2(raidPtr->mutex); 548 raidPtr->Disks[scol].blockSize = secsize; 549 raidPtr->Disks[scol].numBlocks = numBlocks; 550 raidPtr->Disks[scol].partitionSize = numsec; 551 552 raidPtr->raid_cinfo[scol].ci_vp = vp; 553 raidPtr->raid_cinfo[scol].ci_dev = vp->v_rdev; 554 555 raidPtr->Disks[scol].dev = vp->v_rdev; 556 if (raidPtr->Queues != NULL) { 557 raidPtr->Queues[scol].dev = vp->v_rdev; 558 } 559 rf_unlock_mutex2(raidPtr->mutex); 560 561 spareDiskPtr = &raidPtr->Disks[scol]; 562 spareDiskPtr->status = rf_ds_rebuilding_spare; 563 564 if (fcol == scol) { 565 printf("raid%d: initiating in-place reconstruction on column %d\n", 566 raidPtr->raidid, fcol); 567 } else { 568 printf("raid%d: initiating reconstruction on col %d -> %s (col %d)\n", 569 raidPtr->raidid, fcol, spareDiskPtr->devname, scol); 570 } 571 572 reconDesc = AllocRaidReconDesc((void *) raidPtr, fcol, spareDiskPtr, 573 numDisksDone, scol); 574 raidPtr->reconDesc = (void *) reconDesc; 575 #if RF_RECON_STATS > 0 576 reconDesc->hsStallCount = 0; 577 reconDesc->numReconExecDelays = 0; 578 reconDesc->numReconEventWaits = 0; 579 #endif /* RF_RECON_STATS > 0 */ 580 reconDesc->reconExecTimerRunning = 0; 581 reconDesc->reconExecTicks = 0; 582 reconDesc->maxReconExecTicks = 0; 583 rc = rf_ContinueReconstructFailedDisk(reconDesc); 584 585 if (!rc) { 586 rf_lock_mutex2(raidPtr->mutex); 587 /* Need to set these here, as at this point it'll be claiming 588 that the disk is in rf_ds_spared! But we know better :-) */ 589 590 raidPtr->Disks[fcol].status = rf_ds_optimal; 591 raidPtr->status = rf_rs_optimal; 592 rf_unlock_mutex2(raidPtr->mutex); 593 594 /* fix up the component label */ 595 c_label = raidget_component_label(raidPtr, fcol); 596 597 rf_lock_mutex2(raidPtr->mutex); 598 raid_init_component_label(raidPtr, c_label); 599 600 c_label->row = 0; 601 c_label->column = fcol; 602 c_label->status = rf_ds_optimal; 603 rf_component_label_set_partitionsize(c_label, 604 raidPtr->Disks[fcol].partitionSize); 605 606 /* We've just done a rebuild based on all the other 607 disks, so at this point the parity is known to be 608 clean, even if it wasn't before. */ 609 610 /* XXX doesn't hold for RAID 6!!*/ 611 612 raidPtr->parity_good = RF_RAID_CLEAN; 613 rf_unlock_mutex2(raidPtr->mutex); 614 615 raidflush_component_label(raidPtr, fcol); 616 } else { 617 /* Reconstruct-in-place failed. Disk goes back to 618 "failed" status, regardless of what it was before. */ 619 rf_lock_mutex2(raidPtr->mutex); 620 raidPtr->Disks[fcol].status = rf_ds_failed; 621 raidPtr->Disks[scol].status = rf_ds_failed; 622 rf_unlock_mutex2(raidPtr->mutex); 623 } 624 625 rf_update_component_labels(raidPtr, RF_NORMAL_COMPONENT_UPDATE); 626 627 rf_lock_mutex2(raidPtr->mutex); 628 raidPtr->reconInProgress--; 629 rf_signal_cond2(raidPtr->waitForReconCond); 630 rf_unlock_mutex2(raidPtr->mutex); 631 632 return (rc); 633 } 634 635 636 int 637 rf_ContinueReconstructFailedDisk(RF_RaidReconDesc_t *reconDesc) 638 { 639 RF_Raid_t *raidPtr = reconDesc->raidPtr; 640 RF_RowCol_t col = reconDesc->col; 641 RF_RowCol_t scol = reconDesc->scol; 642 RF_ReconMap_t *mapPtr; 643 RF_ReconCtrl_t *tmp_reconctrl; 644 RF_ReconEvent_t *event; 645 RF_StripeCount_t incPSID,lastPSID,num_writes,pending_writes,prev; 646 #if RF_INCLUDE_RAID5_RS > 0 647 RF_StripeCount_t startPSID,endPSID,aPSID,bPSID,offPSID; 648 #endif 649 RF_ReconUnitCount_t RUsPerPU; 650 struct timeval etime, elpsd; 651 unsigned long xor_s, xor_resid_us; 652 int i, ds; 653 int status, done; 654 int recon_error, write_error; 655 656 raidPtr->accumXorTimeUs = 0; 657 #if RF_ACC_TRACE > 0 658 /* create one trace record per physical disk */ 659 raidPtr->recon_tracerecs = 660 RF_Malloc(raidPtr->numCol * sizeof(*raidPtr->recon_tracerecs)); 661 #endif 662 663 /* quiesce the array prior to starting recon. this is needed 664 * to assure no nasty interactions with pending user writes. 665 * We need to do this before we change the disk or row status. */ 666 667 Dprintf("RECON: begin request suspend\n"); 668 rf_SuspendNewRequestsAndWait(raidPtr); 669 Dprintf("RECON: end request suspend\n"); 670 671 /* allocate our RF_ReconCTRL_t before we protect raidPtr->reconControl[row] */ 672 tmp_reconctrl = rf_MakeReconControl(reconDesc, col, scol); 673 674 rf_lock_mutex2(raidPtr->mutex); 675 676 /* create the reconstruction control pointer and install it in 677 * the right slot */ 678 raidPtr->reconControl = tmp_reconctrl; 679 mapPtr = raidPtr->reconControl->reconMap; 680 raidPtr->reconControl->numRUsTotal = mapPtr->totalRUs; 681 raidPtr->reconControl->numRUsComplete = 0; 682 raidPtr->status = rf_rs_reconstructing; 683 raidPtr->Disks[col].status = rf_ds_reconstructing; 684 raidPtr->Disks[col].spareCol = scol; 685 686 rf_unlock_mutex2(raidPtr->mutex); 687 688 RF_GETTIME(raidPtr->reconControl->starttime); 689 690 Dprintf("RECON: resume requests\n"); 691 rf_ResumeNewRequests(raidPtr); 692 693 694 mapPtr = raidPtr->reconControl->reconMap; 695 696 incPSID = RF_RECONMAP_SIZE; 697 lastPSID = raidPtr->Layout.numStripe / raidPtr->Layout.SUsPerPU - 1; 698 RUsPerPU = raidPtr->Layout.SUsPerPU / raidPtr->Layout.SUsPerRU; 699 recon_error = 0; 700 write_error = 0; 701 pending_writes = incPSID; 702 raidPtr->reconControl->lastPSID = incPSID - 1; 703 704 /* bounds check raidPtr->reconControl->lastPSID and 705 pending_writes so that we don't attempt to wait for more IO 706 than can possibly happen */ 707 708 if (raidPtr->reconControl->lastPSID > lastPSID) 709 raidPtr->reconControl->lastPSID = lastPSID; 710 711 if (pending_writes > lastPSID) 712 pending_writes = lastPSID + 1; 713 714 /* start the actual reconstruction */ 715 716 done = 0; 717 while (!done) { 718 719 if (raidPtr->waitShutdown || 720 raidPtr->abortRecon[col]) { 721 /* 722 * someone is unconfiguring this array 723 * or failed a component 724 *... bail on the reconstruct.. 725 */ 726 recon_error = 1; 727 raidPtr->abortRecon[col] = 0; 728 break; 729 } 730 731 num_writes = 0; 732 733 #if RF_INCLUDE_RAID5_RS > 0 734 /* For RAID5 with Rotated Spares we will be 'short' 735 some number of writes since no writes will get 736 issued for stripes where the spare is on the 737 component being rebuilt. Account for the shortage 738 here so that we don't hang indefinitely below 739 waiting for writes to complete that were never 740 scheduled. 741 742 XXX: Should be fixed for PARITY_DECLUSTERING and 743 others too! 744 745 */ 746 747 if (raidPtr->Layout.numDataCol < 748 raidPtr->numCol - raidPtr->Layout.numParityCol) { 749 /* numDataCol is at least 2 less than numCol, so 750 should be RAID 5 with Rotated Spares */ 751 752 /* XXX need to update for RAID 6 */ 753 754 startPSID = raidPtr->reconControl->lastPSID - pending_writes + 1; 755 endPSID = raidPtr->reconControl->lastPSID; 756 757 offPSID = raidPtr->numCol - col - 1; 758 759 aPSID = startPSID - startPSID % raidPtr->numCol + offPSID; 760 if (aPSID < startPSID) { 761 aPSID += raidPtr->numCol; 762 } 763 764 bPSID = endPSID - ((endPSID - offPSID) % raidPtr->numCol); 765 766 if (aPSID < endPSID) { 767 num_writes = ((bPSID - aPSID) / raidPtr->numCol) + 1; 768 } 769 770 if ((aPSID == endPSID) && (bPSID == endPSID)) { 771 num_writes++; 772 } 773 } 774 #endif 775 776 /* issue a read for each surviving disk */ 777 778 reconDesc->numDisksDone = 0; 779 for (i = 0; i < raidPtr->numCol; i++) { 780 if (i != col) { 781 /* find and issue the next I/O on the 782 * indicated disk */ 783 if (IssueNextReadRequest(raidPtr, i)) { 784 Dprintf1("RECON: done issuing for c%d\n", i); 785 reconDesc->numDisksDone++; 786 } 787 } 788 } 789 790 /* process reconstruction events until all disks report that 791 * they've completed all work */ 792 793 while (reconDesc->numDisksDone < raidPtr->numCol - 1) { 794 795 event = rf_GetNextReconEvent(reconDesc); 796 status = ProcessReconEvent(raidPtr, event); 797 798 /* the normal case is that a read completes, and all is well. */ 799 if (status == RF_RECON_DONE_READS) { 800 reconDesc->numDisksDone++; 801 } else if ((status == RF_RECON_READ_ERROR) || 802 (status == RF_RECON_WRITE_ERROR)) { 803 /* an error was encountered while reconstructing... 804 Pretend we've finished this disk. 805 */ 806 recon_error = 1; 807 raidPtr->reconControl->error = 1; 808 809 /* bump the numDisksDone count for reads, 810 but not for writes */ 811 if (status == RF_RECON_READ_ERROR) 812 reconDesc->numDisksDone++; 813 814 /* write errors are special -- when we are 815 done dealing with the reads that are 816 finished, we don't want to wait for any 817 writes */ 818 if (status == RF_RECON_WRITE_ERROR) { 819 write_error = 1; 820 num_writes++; 821 } 822 823 } else if (status == RF_RECON_READ_STOPPED) { 824 /* count this component as being "done" */ 825 reconDesc->numDisksDone++; 826 } else if (status == RF_RECON_WRITE_DONE) { 827 num_writes++; 828 } 829 830 if (recon_error) { 831 /* make sure any stragglers are woken up so that 832 their theads will complete, and we can get out 833 of here with all IO processed */ 834 835 rf_WakeupHeadSepCBWaiters(raidPtr); 836 } 837 838 raidPtr->reconControl->numRUsTotal = 839 mapPtr->totalRUs; 840 raidPtr->reconControl->numRUsComplete = 841 mapPtr->totalRUs - 842 rf_UnitsLeftToReconstruct(mapPtr); 843 844 #if RF_DEBUG_RECON 845 raidPtr->reconControl->percentComplete = 846 (raidPtr->reconControl->numRUsComplete * 100 / raidPtr->reconControl->numRUsTotal); 847 if (rf_prReconSched) { 848 rf_PrintReconSchedule(raidPtr->reconControl->reconMap, &(raidPtr->reconControl->starttime)); 849 } 850 #endif 851 } 852 853 /* reads done, wakeup any waiters, and then wait for writes */ 854 855 rf_WakeupHeadSepCBWaiters(raidPtr); 856 857 while (!recon_error && (num_writes < pending_writes)) { 858 event = rf_GetNextReconEvent(reconDesc); 859 status = ProcessReconEvent(raidPtr, event); 860 861 if (status == RF_RECON_WRITE_ERROR) { 862 num_writes++; 863 write_error = 1; 864 recon_error = 1; 865 raidPtr->reconControl->error = 1; 866 /* an error was encountered at the very end... bail */ 867 } else if (status == RF_RECON_WRITE_DONE) { 868 num_writes++; 869 } /* else it's something else, and we don't care */ 870 } 871 if (recon_error || 872 (raidPtr->reconControl->lastPSID == lastPSID)) { 873 done = 1; 874 break; 875 } 876 877 prev = raidPtr->reconControl->lastPSID; 878 raidPtr->reconControl->lastPSID += incPSID; 879 880 if (raidPtr->reconControl->lastPSID > lastPSID) { 881 pending_writes = lastPSID - prev; 882 raidPtr->reconControl->lastPSID = lastPSID; 883 } 884 /* back down curPSID to get ready for the next round... */ 885 for (i = 0; i < raidPtr->numCol; i++) { 886 if (i != col) { 887 raidPtr->reconControl->perDiskInfo[i].curPSID--; 888 raidPtr->reconControl->perDiskInfo[i].ru_count = RUsPerPU - 1; 889 } 890 } 891 } 892 893 mapPtr = raidPtr->reconControl->reconMap; 894 if (rf_reconDebug) { 895 printf("RECON: all reads completed\n"); 896 } 897 /* at this point all the reads have completed. We now wait 898 * for any pending writes to complete, and then we're done */ 899 900 while (!recon_error && rf_UnitsLeftToReconstruct(raidPtr->reconControl->reconMap) > 0) { 901 902 event = rf_GetNextReconEvent(reconDesc); 903 status = ProcessReconEvent(raidPtr, event); 904 905 if (status == RF_RECON_WRITE_ERROR) { 906 write_error = 1; 907 recon_error = 1; 908 raidPtr->reconControl->error = 1; 909 /* an error was encountered at the very end... bail */ 910 } else { 911 #if RF_DEBUG_RECON 912 raidPtr->reconControl->percentComplete = 100 - (rf_UnitsLeftToReconstruct(mapPtr) * 100 / mapPtr->totalRUs); 913 if (rf_prReconSched) { 914 rf_PrintReconSchedule(raidPtr->reconControl->reconMap, &(raidPtr->reconControl->starttime)); 915 } 916 #endif 917 } 918 } 919 920 if (recon_error) { 921 /* we've encountered an error in reconstructing. */ 922 printf("raid%d: reconstruction failed.\n", raidPtr->raidid); 923 924 /* we start by blocking IO to the RAID set. */ 925 rf_SuspendNewRequestsAndWait(raidPtr); 926 927 rf_lock_mutex2(raidPtr->mutex); 928 /* mark set as being degraded, rather than 929 rf_rs_reconstructing as we were before the problem. 930 After this is done we can update status of the 931 component disks without worrying about someone 932 trying to read from a failed component. 933 */ 934 raidPtr->status = rf_rs_degraded; 935 rf_unlock_mutex2(raidPtr->mutex); 936 937 /* resume IO */ 938 rf_ResumeNewRequests(raidPtr); 939 940 /* At this point there are two cases: 941 1) If we've experienced a read error, then we've 942 already waited for all the reads we're going to get, 943 and we just need to wait for the writes. 944 945 2) If we've experienced a write error, we've also 946 already waited for all the reads to complete, 947 but there is little point in waiting for the writes -- 948 when they do complete, they will just be ignored. 949 950 So we just wait for writes to complete if we didn't have a 951 write error. 952 */ 953 954 if (!write_error) { 955 /* wait for writes to complete */ 956 while (raidPtr->reconControl->pending_writes > 0) { 957 958 event = rf_GetNextReconEvent(reconDesc); 959 status = ProcessReconEvent(raidPtr, event); 960 961 if (status == RF_RECON_WRITE_ERROR) { 962 raidPtr->reconControl->error = 1; 963 write_error = 1; 964 /* an error was encountered at the very end... bail. 965 This will be very bad news for the user, since 966 at this point there will have been a read error 967 on one component, and a write error on another! 968 */ 969 break; 970 } 971 } 972 } 973 974 if (write_error && col != scol && 975 reconDesc->spareDiskPtr != NULL) { 976 rf_lock_mutex2(raidPtr->mutex); 977 reconDesc->spareDiskPtr->status = rf_ds_failed; 978 rf_unlock_mutex2(raidPtr->mutex); 979 } 980 981 /* cleanup */ 982 983 /* drain the event queue - after waiting for the writes above, 984 there shouldn't be much (if anything!) left in the queue. */ 985 986 rf_DrainReconEventQueue(reconDesc); 987 988 rf_FreeReconControl(raidPtr); 989 990 #if RF_ACC_TRACE > 0 991 RF_Free(raidPtr->recon_tracerecs, raidPtr->numCol * sizeof(RF_AccTraceEntry_t)); 992 #endif 993 FreeReconDesc(reconDesc); 994 995 return (1); 996 } 997 998 /* Success: mark the dead disk as reconstructed. We quiesce 999 * the array here to assure no nasty interactions with pending 1000 * user accesses when we free up the psstatus structure as 1001 * part of FreeReconControl() */ 1002 1003 rf_SuspendNewRequestsAndWait(raidPtr); 1004 1005 rf_lock_mutex2(raidPtr->mutex); 1006 raidPtr->numFailures--; 1007 ds = (raidPtr->Layout.map->flags & RF_DISTRIBUTE_SPARE); 1008 raidPtr->Disks[col].status = (ds) ? rf_ds_dist_spared : rf_ds_spared; 1009 raidPtr->status = (ds) ? rf_rs_reconfigured : rf_rs_optimal; 1010 1011 if (col != scol) { 1012 int end = raidPtr->numCol + raidPtr->numSpare - 1; 1013 1014 /* swap the names, raid_cinfo. queues stay where they are. */ 1015 rf_swap_components(raidPtr, col, scol); 1016 1017 /* mark the new spare as good */ 1018 raidPtr->Disks[col].status = rf_ds_optimal; 1019 1020 for (i = scol; i < end; i++) { 1021 /* now we work our way up the array, swapping as we go. */ 1022 /* swap with the one at the next position, which must be there */ 1023 rf_swap_components(raidPtr, i, i+1); 1024 } 1025 /* 1026 * Only drop the slot if the replaced column had no open vnode 1027 * (i.e. an absent "componentN" placeholder). Otherwise, retain 1028 * the replaced component in Spares as rf_ds_spared so its vnode 1029 * is not leaked and it cannot form a rogue set on rescan. 1030 */ 1031 if (raidPtr->raid_cinfo[end].ci_vp == NULL) { 1032 raidPtr->numSpare--; 1033 } 1034 } 1035 rf_unlock_mutex2(raidPtr->mutex); 1036 RF_GETTIME(etime); 1037 RF_TIMEVAL_DIFF(&(raidPtr->reconControl->starttime), &etime, &elpsd); 1038 1039 rf_ResumeNewRequests(raidPtr); 1040 1041 printf("raid%d: Reconstruction of disk at col %d completed\n", 1042 raidPtr->raidid, col); 1043 xor_s = raidPtr->accumXorTimeUs / 1000000; 1044 xor_resid_us = raidPtr->accumXorTimeUs % 1000000; 1045 printf("raid%d: Recon time was %d.%06d seconds, accumulated XOR time was %ld us (%ld.%06ld)\n", 1046 raidPtr->raidid, 1047 (int) elpsd.tv_sec, (int) elpsd.tv_usec, 1048 raidPtr->accumXorTimeUs, xor_s, xor_resid_us); 1049 printf("raid%d: (start time %d sec %d usec, end time %d sec %d usec)\n", 1050 raidPtr->raidid, 1051 (int) raidPtr->reconControl->starttime.tv_sec, 1052 (int) raidPtr->reconControl->starttime.tv_usec, 1053 (int) etime.tv_sec, (int) etime.tv_usec); 1054 #if RF_RECON_STATS > 0 1055 printf("raid%d: Total head-sep stall count was %d\n", 1056 raidPtr->raidid, (int) reconDesc->hsStallCount); 1057 #endif /* RF_RECON_STATS > 0 */ 1058 rf_FreeReconControl(raidPtr); 1059 #if RF_ACC_TRACE > 0 1060 RF_Free(raidPtr->recon_tracerecs, raidPtr->numCol * sizeof(RF_AccTraceEntry_t)); 1061 #endif 1062 FreeReconDesc(reconDesc); 1063 1064 return (0); 1065 1066 } 1067 /***************************************************************************** 1068 * do the right thing upon each reconstruction event. 1069 *****************************************************************************/ 1070 static int 1071 ProcessReconEvent(RF_Raid_t *raidPtr, RF_ReconEvent_t *event) 1072 { 1073 int retcode = 0, submitblocked; 1074 RF_ReconBuffer_t *rbuf; 1075 RF_SectorCount_t sectorsPerRU; 1076 1077 retcode = RF_RECON_READ_STOPPED; 1078 1079 Dprintf1("RECON: ProcessReconEvent type %d\n", event->type); 1080 1081 switch (event->type) { 1082 1083 /* a read I/O has completed */ 1084 case RF_REVENT_READDONE: 1085 rbuf = raidPtr->reconControl->perDiskInfo[event->col].rbuf; 1086 Dprintf2("RECON: READDONE EVENT: col %d psid %ld\n", 1087 event->col, rbuf->parityStripeID); 1088 Dprintf7("RECON: done read psid %ld buf %lx %02x %02x %02x %02x %02x\n", 1089 rbuf->parityStripeID, rbuf->buffer, rbuf->buffer[0] & 0xff, rbuf->buffer[1] & 0xff, 1090 rbuf->buffer[2] & 0xff, rbuf->buffer[3] & 0xff, rbuf->buffer[4] & 0xff); 1091 rf_FreeDiskQueueData((RF_DiskQueueData_t *) rbuf->arg); 1092 if (!raidPtr->reconControl->error) { 1093 submitblocked = rf_SubmitReconBuffer(rbuf, 0, 0); 1094 Dprintf1("RECON: submitblocked=%d\n", submitblocked); 1095 if (!submitblocked) 1096 retcode = IssueNextReadRequest(raidPtr, event->col); 1097 else 1098 retcode = 0; 1099 } 1100 break; 1101 1102 /* a write I/O has completed */ 1103 case RF_REVENT_WRITEDONE: 1104 #if RF_DEBUG_RECON 1105 if (rf_floatingRbufDebug) { 1106 rf_CheckFloatingRbufCount(raidPtr, 1); 1107 } 1108 #endif 1109 sectorsPerRU = raidPtr->Layout.sectorsPerStripeUnit * raidPtr->Layout.SUsPerRU; 1110 rbuf = (RF_ReconBuffer_t *) event->arg; 1111 rf_FreeDiskQueueData((RF_DiskQueueData_t *) rbuf->arg); 1112 Dprintf3("RECON: WRITEDONE EVENT: psid %d ru %d (%d %% complete)\n", 1113 rbuf->parityStripeID, rbuf->which_ru, raidPtr->reconControl->percentComplete); 1114 rf_ReconMapUpdate(raidPtr, raidPtr->reconControl->reconMap, 1115 rbuf->failedDiskSectorOffset, rbuf->failedDiskSectorOffset + sectorsPerRU - 1); 1116 rf_RemoveFromActiveReconTable(raidPtr, rbuf->parityStripeID, rbuf->which_ru); 1117 1118 rf_lock_mutex2(raidPtr->reconControl->rb_mutex); 1119 raidPtr->reconControl->pending_writes--; 1120 rf_unlock_mutex2(raidPtr->reconControl->rb_mutex); 1121 1122 if (rbuf->type == RF_RBUF_TYPE_FLOATING || 1123 rbuf->type == RF_RBUF_TYPE_FORCED) { 1124 rf_lock_mutex2(raidPtr->reconControl->rb_mutex); 1125 while(raidPtr->reconControl->rb_lock) { 1126 rf_wait_cond2(raidPtr->reconControl->rb_cv, 1127 raidPtr->reconControl->rb_mutex); 1128 } 1129 raidPtr->reconControl->rb_lock = 1; 1130 rf_unlock_mutex2(raidPtr->reconControl->rb_mutex); 1131 1132 raidPtr->numFullReconBuffers--; 1133 if (rbuf->type == RF_RBUF_TYPE_FLOATING) 1134 rf_ReleaseFloatingReconBuffer(raidPtr, rbuf); 1135 else 1136 rf_ReleaseForcedReconBuffer(raidPtr, rbuf); 1137 1138 rf_lock_mutex2(raidPtr->reconControl->rb_mutex); 1139 raidPtr->reconControl->rb_lock = 0; 1140 rf_broadcast_cond2(raidPtr->reconControl->rb_cv); 1141 rf_unlock_mutex2(raidPtr->reconControl->rb_mutex); 1142 } else 1143 RF_ASSERT(0); 1144 retcode = RF_RECON_WRITE_DONE; 1145 break; 1146 1147 case RF_REVENT_BUFCLEAR: /* A buffer-stall condition has been 1148 * cleared */ 1149 Dprintf1("RECON: BUFCLEAR EVENT: col %d\n", event->col); 1150 if (!raidPtr->reconControl->error) { 1151 submitblocked = rf_SubmitReconBuffer(raidPtr->reconControl->perDiskInfo[event->col].rbuf, 1152 0, (int) (long) event->arg); 1153 RF_ASSERT(!submitblocked); /* we wouldn't have gotten the 1154 * BUFCLEAR event if we 1155 * couldn't submit */ 1156 retcode = IssueNextReadRequest(raidPtr, event->col); 1157 } 1158 break; 1159 1160 case RF_REVENT_BLOCKCLEAR: /* A user-write reconstruction 1161 * blockage has been cleared */ 1162 DDprintf1("RECON: BLOCKCLEAR EVENT: col %d\n", event->col); 1163 if (!raidPtr->reconControl->error) { 1164 retcode = TryToRead(raidPtr, event->col); 1165 } 1166 break; 1167 1168 case RF_REVENT_HEADSEPCLEAR: /* A max-head-separation 1169 * reconstruction blockage has been 1170 * cleared */ 1171 Dprintf1("RECON: HEADSEPCLEAR EVENT: col %d\n", event->col); 1172 if (!raidPtr->reconControl->error) { 1173 retcode = TryToRead(raidPtr, event->col); 1174 } 1175 break; 1176 1177 /* a buffer has become ready to write */ 1178 case RF_REVENT_BUFREADY: 1179 Dprintf1("RECON: BUFREADY EVENT: col %d\n", event->col); 1180 if (!raidPtr->reconControl->error) { 1181 retcode = IssueNextWriteRequest(raidPtr); 1182 #if RF_DEBUG_RECON 1183 if (rf_floatingRbufDebug) { 1184 rf_CheckFloatingRbufCount(raidPtr, 1); 1185 } 1186 #endif 1187 } 1188 break; 1189 1190 /* we need to skip the current RU entirely because it got 1191 * recon'd while we were waiting for something else to happen */ 1192 case RF_REVENT_SKIP: 1193 DDprintf1("RECON: SKIP EVENT: col %d\n", event->col); 1194 if (!raidPtr->reconControl->error) { 1195 retcode = IssueNextReadRequest(raidPtr, event->col); 1196 } 1197 break; 1198 1199 /* a forced-reconstruction read access has completed. Just 1200 * submit the buffer */ 1201 case RF_REVENT_FORCEDREADDONE: 1202 rbuf = (RF_ReconBuffer_t *) event->arg; 1203 rf_FreeDiskQueueData((RF_DiskQueueData_t *) rbuf->arg); 1204 DDprintf1("RECON: FORCEDREADDONE EVENT: col %d\n", event->col); 1205 if (!raidPtr->reconControl->error) { 1206 submitblocked = rf_SubmitReconBuffer(rbuf, 1, 0); 1207 RF_ASSERT(!submitblocked); 1208 retcode = 0; 1209 } 1210 break; 1211 1212 /* A read I/O failed to complete */ 1213 case RF_REVENT_READ_FAILED: 1214 retcode = RF_RECON_READ_ERROR; 1215 break; 1216 1217 /* A write I/O failed to complete */ 1218 case RF_REVENT_WRITE_FAILED: 1219 retcode = RF_RECON_WRITE_ERROR; 1220 1221 /* This is an error, but it was a pending write. 1222 Account for it. */ 1223 rf_lock_mutex2(raidPtr->reconControl->rb_mutex); 1224 raidPtr->reconControl->pending_writes--; 1225 rf_unlock_mutex2(raidPtr->reconControl->rb_mutex); 1226 1227 rbuf = (RF_ReconBuffer_t *) event->arg; 1228 1229 /* cleanup the disk queue data */ 1230 rf_FreeDiskQueueData((RF_DiskQueueData_t *) rbuf->arg); 1231 1232 /* At this point we're erroring out, badly, and floatingRbufs 1233 may not even be valid. Rather than putting this back onto 1234 the floatingRbufs list, just arrange for its immediate 1235 destruction. 1236 */ 1237 rf_FreeReconBuffer(rbuf); 1238 break; 1239 1240 /* a forced read I/O failed to complete */ 1241 case RF_REVENT_FORCEDREAD_FAILED: 1242 retcode = RF_RECON_READ_ERROR; 1243 break; 1244 1245 default: 1246 RF_PANIC(); 1247 } 1248 rf_FreeReconEventDesc(raidPtr, event); 1249 return (retcode); 1250 } 1251 /***************************************************************************** 1252 * 1253 * find the next thing that's needed on the indicated disk, and issue 1254 * a read request for it. We assume that the reconstruction buffer 1255 * associated with this process is free to receive the data. If 1256 * reconstruction is blocked on the indicated RU, we issue a 1257 * blockage-release request instead of a physical disk read request. 1258 * If the current disk gets too far ahead of the others, we issue a 1259 * head-separation wait request and return. 1260 * 1261 * ctrl->{ru_count, curPSID, diskOffset} and 1262 * rbuf->failedDiskSectorOffset are maintained to point to the unit 1263 * we're currently accessing. Note that this deviates from the 1264 * standard C idiom of having counters point to the next thing to be 1265 * accessed. This allows us to easily retry when we're blocked by 1266 * head separation or reconstruction-blockage events. 1267 * 1268 *****************************************************************************/ 1269 static int 1270 IssueNextReadRequest(RF_Raid_t *raidPtr, RF_RowCol_t col) 1271 { 1272 RF_PerDiskReconCtrl_t *ctrl = &raidPtr->reconControl->perDiskInfo[col]; 1273 RF_RaidLayout_t *layoutPtr = &raidPtr->Layout; 1274 RF_ReconBuffer_t *rbuf = ctrl->rbuf; 1275 RF_ReconUnitCount_t RUsPerPU = layoutPtr->SUsPerPU / layoutPtr->SUsPerRU; 1276 RF_SectorCount_t sectorsPerRU = layoutPtr->sectorsPerStripeUnit * layoutPtr->SUsPerRU; 1277 int do_new_check = 0, retcode = 0, status; 1278 1279 /* if we are currently the slowest disk, mark that we have to do a new 1280 * check */ 1281 if (ctrl->headSepCounter <= raidPtr->reconControl->minHeadSepCounter) 1282 do_new_check = 1; 1283 1284 while (1) { 1285 1286 ctrl->ru_count++; 1287 if (ctrl->ru_count < RUsPerPU) { 1288 ctrl->diskOffset += sectorsPerRU; 1289 rbuf->failedDiskSectorOffset += sectorsPerRU; 1290 } else { 1291 ctrl->curPSID++; 1292 ctrl->ru_count = 0; 1293 /* code left over from when head-sep was based on 1294 * parity stripe id */ 1295 if (ctrl->curPSID > raidPtr->reconControl->lastPSID) { 1296 CheckForNewMinHeadSep(raidPtr, ++(ctrl->headSepCounter)); 1297 return (RF_RECON_DONE_READS); /* finito! */ 1298 } 1299 /* find the disk offsets of the start of the parity 1300 * stripe on both the current disk and the failed 1301 * disk. skip this entire parity stripe if either disk 1302 * does not appear in the indicated PS */ 1303 status = ComputePSDiskOffsets(raidPtr, ctrl->curPSID, col, &ctrl->diskOffset, &rbuf->failedDiskSectorOffset, 1304 &rbuf->spCol, &rbuf->spOffset); 1305 if (status) { 1306 ctrl->ru_count = RUsPerPU - 1; 1307 continue; 1308 } 1309 } 1310 rbuf->which_ru = ctrl->ru_count; 1311 1312 /* skip this RU if it's already been reconstructed */ 1313 if (rf_CheckRUReconstructed(raidPtr->reconControl->reconMap, rbuf->failedDiskSectorOffset)) { 1314 Dprintf2("Skipping psid %ld ru %d: already reconstructed\n", ctrl->curPSID, ctrl->ru_count); 1315 continue; 1316 } 1317 break; 1318 } 1319 ctrl->headSepCounter++; 1320 if (do_new_check) 1321 CheckForNewMinHeadSep(raidPtr, ctrl->headSepCounter); /* update min if needed */ 1322 1323 1324 /* at this point, we have definitely decided what to do, and we have 1325 * only to see if we can actually do it now */ 1326 rbuf->parityStripeID = ctrl->curPSID; 1327 rbuf->which_ru = ctrl->ru_count; 1328 #if RF_ACC_TRACE > 0 1329 memset(&raidPtr->recon_tracerecs[col], 0, 1330 sizeof(raidPtr->recon_tracerecs[col])); 1331 raidPtr->recon_tracerecs[col].reconacc = 1; 1332 RF_ETIMER_START(raidPtr->recon_tracerecs[col].recon_timer); 1333 #endif 1334 retcode = TryToRead(raidPtr, col); 1335 return (retcode); 1336 } 1337 1338 /* 1339 * tries to issue the next read on the indicated disk. We may be 1340 * blocked by (a) the heads being too far apart, or (b) recon on the 1341 * indicated RU being blocked due to a write by a user thread. In 1342 * this case, we issue a head-sep or blockage wait request, which will 1343 * cause this same routine to be invoked again later when the blockage 1344 * has cleared. 1345 */ 1346 1347 static int 1348 TryToRead(RF_Raid_t *raidPtr, RF_RowCol_t col) 1349 { 1350 RF_PerDiskReconCtrl_t *ctrl = &raidPtr->reconControl->perDiskInfo[col]; 1351 RF_SectorCount_t sectorsPerRU = raidPtr->Layout.sectorsPerStripeUnit * raidPtr->Layout.SUsPerRU; 1352 RF_StripeNum_t psid = ctrl->curPSID; 1353 RF_ReconUnitNum_t which_ru = ctrl->ru_count; 1354 RF_DiskQueueData_t *req; 1355 int status; 1356 RF_ReconParityStripeStatus_t *pssPtr, *newpssPtr; 1357 1358 /* if the current disk is too far ahead of the others, issue a 1359 * head-separation wait and return */ 1360 if (CheckHeadSeparation(raidPtr, ctrl, col, ctrl->headSepCounter, which_ru)) 1361 return (0); 1362 1363 /* allocate a new PSS in case we need it */ 1364 newpssPtr = rf_AllocPSStatus(raidPtr); 1365 1366 RF_LOCK_PSS_MUTEX(raidPtr, psid); 1367 pssPtr = rf_LookupRUStatus(raidPtr, raidPtr->reconControl->pssTable, psid, which_ru, RF_PSS_CREATE, newpssPtr); 1368 1369 if (pssPtr != newpssPtr) { 1370 rf_FreePSStatus(raidPtr, newpssPtr); 1371 } 1372 1373 /* if recon is blocked on the indicated parity stripe, issue a 1374 * block-wait request and return. this also must mark the indicated RU 1375 * in the stripe as under reconstruction if not blocked. */ 1376 status = CheckForcedOrBlockedReconstruction(raidPtr, pssPtr, ctrl, col, psid, which_ru); 1377 if (status == RF_PSS_RECON_BLOCKED) { 1378 Dprintf2("RECON: Stalling psid %ld ru %d: recon blocked\n", psid, which_ru); 1379 goto out; 1380 } else 1381 if (status == RF_PSS_FORCED_ON_WRITE) { 1382 rf_CauseReconEvent(raidPtr, col, NULL, RF_REVENT_SKIP); 1383 goto out; 1384 } 1385 /* make one last check to be sure that the indicated RU didn't get 1386 * reconstructed while we were waiting for something else to happen. 1387 * This is unfortunate in that it causes us to make this check twice 1388 * in the normal case. Might want to make some attempt to re-work 1389 * this so that we only do this check if we've definitely blocked on 1390 * one of the above checks. When this condition is detected, we may 1391 * have just created a bogus status entry, which we need to delete. */ 1392 if (rf_CheckRUReconstructed(raidPtr->reconControl->reconMap, ctrl->rbuf->failedDiskSectorOffset)) { 1393 Dprintf2("RECON: Skipping psid %ld ru %d: prior recon after stall\n", psid, which_ru); 1394 if (pssPtr == newpssPtr) 1395 rf_PSStatusDelete(raidPtr, raidPtr->reconControl->pssTable, pssPtr); 1396 rf_CauseReconEvent(raidPtr, col, NULL, RF_REVENT_SKIP); 1397 goto out; 1398 } 1399 /* found something to read. issue the I/O */ 1400 Dprintf4("RECON: Read for psid %ld on col %d offset %ld buf %lx\n", 1401 psid, col, ctrl->diskOffset, ctrl->rbuf->buffer); 1402 #if RF_ACC_TRACE > 0 1403 RF_ETIMER_STOP(raidPtr->recon_tracerecs[col].recon_timer); 1404 RF_ETIMER_EVAL(raidPtr->recon_tracerecs[col].recon_timer); 1405 raidPtr->recon_tracerecs[col].specific.recon.recon_start_to_fetch_us = 1406 RF_ETIMER_VAL_US(raidPtr->recon_tracerecs[col].recon_timer); 1407 RF_ETIMER_START(raidPtr->recon_tracerecs[col].recon_timer); 1408 #endif 1409 /* should be ok to use a NULL proc pointer here, all the bufs we use 1410 * should be in kernel space */ 1411 req = rf_CreateDiskQueueData(RF_IO_TYPE_READ, ctrl->diskOffset, sectorsPerRU, ctrl->rbuf->buffer, psid, which_ru, 1412 ReconReadDoneProc, (void *) ctrl, 1413 #if RF_ACC_TRACE > 0 1414 &raidPtr->recon_tracerecs[col], 1415 #else 1416 NULL, 1417 #endif 1418 (void *) raidPtr, 0, NULL); 1419 1420 ctrl->rbuf->arg = (void *) req; 1421 rf_DiskIOEnqueue(&raidPtr->Queues[col], req, RF_IO_RECON_PRIORITY); 1422 pssPtr->issued[col] = 1; 1423 1424 out: 1425 RF_UNLOCK_PSS_MUTEX(raidPtr, psid); 1426 return (0); 1427 } 1428 1429 1430 /* 1431 * given a parity stripe ID, we want to find out whether both the 1432 * current disk and the failed disk exist in that parity stripe. If 1433 * not, we want to skip this whole PS. If so, we want to find the 1434 * disk offset of the start of the PS on both the current disk and the 1435 * failed disk. 1436 * 1437 * this works by getting a list of disks comprising the indicated 1438 * parity stripe, and searching the list for the current and failed 1439 * disks. Once we've decided they both exist in the parity stripe, we 1440 * need to decide whether each is data or parity, so that we'll know 1441 * which mapping function to call to get the corresponding disk 1442 * offsets. 1443 * 1444 * this is kind of unpleasant, but doing it this way allows the 1445 * reconstruction code to use parity stripe IDs rather than physical 1446 * disks address to march through the failed disk, which greatly 1447 * simplifies a lot of code, as well as eliminating the need for a 1448 * reverse-mapping function. I also think it will execute faster, 1449 * since the calls to the mapping module are kept to a minimum. 1450 * 1451 * ASSUMES THAT THE STRIPE IDENTIFIER IDENTIFIES THE DISKS COMPRISING 1452 * THE STRIPE IN THE CORRECT ORDER 1453 * 1454 * raidPtr - raid descriptor 1455 * psid - parity stripe identifier 1456 * col - column of disk to find the offsets for 1457 * spCol - out: col of spare unit for failed unit 1458 * spOffset - out: offset into disk containing spare unit 1459 * 1460 */ 1461 1462 1463 static int 1464 ComputePSDiskOffsets(RF_Raid_t *raidPtr, RF_StripeNum_t psid, 1465 RF_RowCol_t col, RF_SectorNum_t *outDiskOffset, 1466 RF_SectorNum_t *outFailedDiskSectorOffset, 1467 RF_RowCol_t *spCol, RF_SectorNum_t *spOffset) 1468 { 1469 RF_RaidLayout_t *layoutPtr = &raidPtr->Layout; 1470 RF_RowCol_t fcol = raidPtr->reconControl->fcol; 1471 RF_RaidAddr_t sosRaidAddress; /* start-of-stripe */ 1472 RF_RowCol_t *diskids; 1473 u_int i, j, k, i_offset, j_offset; 1474 RF_RowCol_t pcol; 1475 int testcol; 1476 RF_SectorNum_t poffset; 1477 char i_is_parity = 0, j_is_parity = 0; 1478 RF_RowCol_t stripeWidth = layoutPtr->numDataCol + layoutPtr->numParityCol; 1479 1480 /* get a listing of the disks comprising that stripe */ 1481 sosRaidAddress = rf_ParityStripeIDToRaidAddress(layoutPtr, psid); 1482 (layoutPtr->map->IdentifyStripe) (raidPtr, sosRaidAddress, &diskids); 1483 RF_ASSERT(diskids); 1484 1485 /* reject this entire parity stripe if it does not contain the 1486 * indicated disk or it does not contain the failed disk */ 1487 1488 for (i = 0; i < stripeWidth; i++) { 1489 if (col == diskids[i]) 1490 break; 1491 } 1492 if (i == stripeWidth) 1493 goto skipit; 1494 for (j = 0; j < stripeWidth; j++) { 1495 if (fcol == diskids[j]) 1496 break; 1497 } 1498 if (j == stripeWidth) { 1499 goto skipit; 1500 } 1501 /* find out which disk the parity is on */ 1502 (layoutPtr->map->MapParity) (raidPtr, sosRaidAddress, &pcol, &poffset, RF_DONT_REMAP); 1503 1504 /* find out if either the current RU or the failed RU is parity */ 1505 /* also, if the parity occurs in this stripe prior to the data and/or 1506 * failed col, we need to decrement i and/or j */ 1507 for (k = 0; k < stripeWidth; k++) 1508 if (diskids[k] == pcol) 1509 break; 1510 RF_ASSERT(k < stripeWidth); 1511 i_offset = i; 1512 j_offset = j; 1513 if (k < i) 1514 i_offset--; 1515 else 1516 if (k == i) { 1517 i_is_parity = 1; 1518 i_offset = 0; 1519 } /* set offsets to zero to disable multiply 1520 * below */ 1521 if (k < j) 1522 j_offset--; 1523 else 1524 if (k == j) { 1525 j_is_parity = 1; 1526 j_offset = 0; 1527 } 1528 /* at this point, [ij]_is_parity tells us whether the [current,failed] 1529 * disk is parity at the start of this RU, and, if data, "[ij]_offset" 1530 * tells us how far into the stripe the [current,failed] disk is. */ 1531 1532 /* call the mapping routine to get the offset into the current disk, 1533 * repeat for failed disk. */ 1534 if (i_is_parity) 1535 layoutPtr->map->MapParity(raidPtr, sosRaidAddress + i_offset * layoutPtr->sectorsPerStripeUnit, &testcol, outDiskOffset, RF_DONT_REMAP); 1536 else 1537 layoutPtr->map->MapSector(raidPtr, sosRaidAddress + i_offset * layoutPtr->sectorsPerStripeUnit, &testcol, outDiskOffset, RF_DONT_REMAP); 1538 1539 RF_ASSERT(col == testcol); 1540 1541 if (j_is_parity) 1542 layoutPtr->map->MapParity(raidPtr, sosRaidAddress + j_offset * layoutPtr->sectorsPerStripeUnit, &testcol, outFailedDiskSectorOffset, RF_DONT_REMAP); 1543 else 1544 layoutPtr->map->MapSector(raidPtr, sosRaidAddress + j_offset * layoutPtr->sectorsPerStripeUnit, &testcol, outFailedDiskSectorOffset, RF_DONT_REMAP); 1545 RF_ASSERT(fcol == testcol); 1546 1547 /* now locate the spare unit for the failed unit */ 1548 #if RF_INCLUDE_PARITY_DECLUSTERING_DS > 0 1549 if (layoutPtr->map->flags & RF_DISTRIBUTE_SPARE) { 1550 if (j_is_parity) 1551 layoutPtr->map->MapParity(raidPtr, sosRaidAddress + j_offset * layoutPtr->sectorsPerStripeUnit, spCol, spOffset, RF_REMAP); 1552 else 1553 layoutPtr->map->MapSector(raidPtr, sosRaidAddress + j_offset * layoutPtr->sectorsPerStripeUnit, spCol, spOffset, RF_REMAP); 1554 } else { 1555 #endif 1556 *spCol = raidPtr->reconControl->spareCol; 1557 *spOffset = *outFailedDiskSectorOffset; 1558 #if RF_INCLUDE_PARITY_DECLUSTERING_DS > 0 1559 } 1560 #endif 1561 return (0); 1562 1563 skipit: 1564 Dprintf2("RECON: Skipping psid %ld: nothing needed from c%d\n", 1565 psid, col); 1566 return (1); 1567 } 1568 /* this is called when a buffer has become ready to write to the replacement disk */ 1569 static int 1570 IssueNextWriteRequest(RF_Raid_t *raidPtr) 1571 { 1572 RF_RaidLayout_t *layoutPtr = &raidPtr->Layout; 1573 RF_SectorCount_t sectorsPerRU = layoutPtr->sectorsPerStripeUnit * layoutPtr->SUsPerRU; 1574 #if RF_ACC_TRACE > 0 1575 RF_RowCol_t fcol = raidPtr->reconControl->fcol; 1576 #endif 1577 RF_ReconBuffer_t *rbuf; 1578 RF_DiskQueueData_t *req; 1579 1580 rbuf = rf_GetFullReconBuffer(raidPtr->reconControl); 1581 RF_ASSERT(rbuf); /* there must be one available, or we wouldn't 1582 * have gotten the event that sent us here */ 1583 RF_ASSERT(rbuf->pssPtr); 1584 1585 rbuf->pssPtr->writeRbuf = rbuf; 1586 rbuf->pssPtr = NULL; 1587 1588 Dprintf6("RECON: New write (c %d offs %d) for psid %ld ru %d (failed disk offset %ld) buf %lx\n", 1589 rbuf->spCol, rbuf->spOffset, rbuf->parityStripeID, 1590 rbuf->which_ru, rbuf->failedDiskSectorOffset, rbuf->buffer); 1591 Dprintf6("RECON: new write psid %ld %02x %02x %02x %02x %02x\n", 1592 rbuf->parityStripeID, rbuf->buffer[0] & 0xff, rbuf->buffer[1] & 0xff, 1593 rbuf->buffer[2] & 0xff, rbuf->buffer[3] & 0xff, rbuf->buffer[4] & 0xff); 1594 1595 /* should be ok to use a NULL b_proc here b/c all addrs should be in 1596 * kernel space */ 1597 req = rf_CreateDiskQueueData(RF_IO_TYPE_WRITE, rbuf->spOffset, 1598 sectorsPerRU, rbuf->buffer, 1599 rbuf->parityStripeID, rbuf->which_ru, 1600 ReconWriteDoneProc, (void *) rbuf, 1601 #if RF_ACC_TRACE > 0 1602 &raidPtr->recon_tracerecs[fcol], 1603 #else 1604 NULL, 1605 #endif 1606 (void *) raidPtr, 0, NULL); 1607 1608 rbuf->arg = (void *) req; 1609 rf_lock_mutex2(raidPtr->reconControl->rb_mutex); 1610 raidPtr->reconControl->pending_writes++; 1611 rf_unlock_mutex2(raidPtr->reconControl->rb_mutex); 1612 rf_DiskIOEnqueue(&raidPtr->Queues[rbuf->spCol], req, RF_IO_RECON_PRIORITY); 1613 1614 return (0); 1615 } 1616 1617 /* 1618 * this gets called upon the completion of a reconstruction read 1619 * operation the arg is a pointer to the per-disk reconstruction 1620 * control structure for the process that just finished a read. 1621 * 1622 * called at interrupt context in the kernel, so don't do anything 1623 * illegal here. 1624 */ 1625 static void 1626 ReconReadDoneProc(void *arg, int status) 1627 { 1628 RF_PerDiskReconCtrl_t *ctrl = (RF_PerDiskReconCtrl_t *) arg; 1629 RF_Raid_t *raidPtr; 1630 1631 /* Detect that reconCtrl is no longer valid, and if that 1632 is the case, bail without calling rf_CauseReconEvent(). 1633 There won't be anyone listening for this event anyway */ 1634 1635 if (ctrl->reconCtrl == NULL) 1636 return; 1637 1638 raidPtr = ctrl->reconCtrl->reconDesc->raidPtr; 1639 1640 if (status) { 1641 printf("raid%d: Recon read failed: %d\n", raidPtr->raidid, status); 1642 rf_CauseReconEvent(raidPtr, ctrl->col, NULL, RF_REVENT_READ_FAILED); 1643 return; 1644 } 1645 #if RF_ACC_TRACE > 0 1646 RF_ETIMER_STOP(raidPtr->recon_tracerecs[ctrl->col].recon_timer); 1647 RF_ETIMER_EVAL(raidPtr->recon_tracerecs[ctrl->col].recon_timer); 1648 raidPtr->recon_tracerecs[ctrl->col].specific.recon.recon_fetch_to_return_us = 1649 RF_ETIMER_VAL_US(raidPtr->recon_tracerecs[ctrl->col].recon_timer); 1650 RF_ETIMER_START(raidPtr->recon_tracerecs[ctrl->col].recon_timer); 1651 #endif 1652 rf_CauseReconEvent(raidPtr, ctrl->col, NULL, RF_REVENT_READDONE); 1653 return; 1654 } 1655 /* this gets called upon the completion of a reconstruction write operation. 1656 * the arg is a pointer to the rbuf that was just written 1657 * 1658 * called at interrupt context in the kernel, so don't do anything illegal here. 1659 */ 1660 static void 1661 ReconWriteDoneProc(void *arg, int status) 1662 { 1663 RF_ReconBuffer_t *rbuf = (RF_ReconBuffer_t *) arg; 1664 1665 /* Detect that reconControl is no longer valid, and if that 1666 is the case, bail without calling rf_CauseReconEvent(). 1667 There won't be anyone listening for this event anyway */ 1668 1669 if (rbuf->raidPtr->reconControl == NULL) 1670 return; 1671 1672 Dprintf2("Reconstruction completed on psid %ld ru %d\n", rbuf->parityStripeID, rbuf->which_ru); 1673 if (status) { 1674 printf("raid%d: Recon write failed (status %d(0x%x))!\n", rbuf->raidPtr->raidid,status,status); 1675 rf_CauseReconEvent(rbuf->raidPtr, rbuf->col, arg, RF_REVENT_WRITE_FAILED); 1676 return; 1677 } 1678 rf_CauseReconEvent(rbuf->raidPtr, rbuf->col, arg, RF_REVENT_WRITEDONE); 1679 } 1680 1681 1682 /* 1683 * computes a new minimum head sep, and wakes up anyone who needs to 1684 * be woken as a result 1685 */ 1686 static void 1687 CheckForNewMinHeadSep(RF_Raid_t *raidPtr, RF_HeadSepLimit_t hsCtr) 1688 { 1689 RF_ReconCtrl_t *reconCtrlPtr = raidPtr->reconControl; 1690 RF_HeadSepLimit_t new_min; 1691 RF_RowCol_t i; 1692 RF_CallbackValueDesc_t *p; 1693 RF_ASSERT(hsCtr >= reconCtrlPtr->minHeadSepCounter); /* from the definition 1694 * of a minimum */ 1695 1696 1697 rf_lock_mutex2(reconCtrlPtr->rb_mutex); 1698 while(reconCtrlPtr->rb_lock) { 1699 rf_wait_cond2(reconCtrlPtr->rb_cv, reconCtrlPtr->rb_mutex); 1700 } 1701 reconCtrlPtr->rb_lock = 1; 1702 rf_unlock_mutex2(reconCtrlPtr->rb_mutex); 1703 1704 new_min = ~(1L << (8 * sizeof(long) - 1)); /* 0x7FFF....FFF */ 1705 for (i = 0; i < raidPtr->numCol; i++) 1706 if (i != reconCtrlPtr->fcol) { 1707 if (reconCtrlPtr->perDiskInfo[i].headSepCounter < new_min) 1708 new_min = reconCtrlPtr->perDiskInfo[i].headSepCounter; 1709 } 1710 /* set the new minimum and wake up anyone who can now run again */ 1711 if (new_min != reconCtrlPtr->minHeadSepCounter) { 1712 reconCtrlPtr->minHeadSepCounter = new_min; 1713 Dprintf1("RECON: new min head pos counter val is %ld\n", new_min); 1714 while (reconCtrlPtr->headSepCBList) { 1715 if (reconCtrlPtr->headSepCBList->v > new_min) 1716 break; 1717 p = reconCtrlPtr->headSepCBList; 1718 reconCtrlPtr->headSepCBList = p->next; 1719 p->next = NULL; 1720 rf_CauseReconEvent(raidPtr, p->col, NULL, RF_REVENT_HEADSEPCLEAR); 1721 rf_FreeCallbackValueDesc(raidPtr, p); 1722 } 1723 1724 } 1725 rf_lock_mutex2(reconCtrlPtr->rb_mutex); 1726 reconCtrlPtr->rb_lock = 0; 1727 rf_broadcast_cond2(reconCtrlPtr->rb_cv); 1728 rf_unlock_mutex2(reconCtrlPtr->rb_mutex); 1729 } 1730 1731 /* 1732 * checks to see that the maximum head separation will not be violated 1733 * if we initiate a reconstruction I/O on the indicated disk. 1734 * Limiting the maximum head separation between two disks eliminates 1735 * the nasty buffer-stall conditions that occur when one disk races 1736 * ahead of the others and consumes all of the floating recon buffers. 1737 * This code is complex and unpleasant but it's necessary to avoid 1738 * some very nasty, albeit fairly rare, reconstruction behavior. 1739 * 1740 * returns non-zero if and only if we have to stop working on the 1741 * indicated disk due to a head-separation delay. 1742 */ 1743 static int 1744 CheckHeadSeparation(RF_Raid_t *raidPtr, RF_PerDiskReconCtrl_t *ctrl, 1745 RF_RowCol_t col, RF_HeadSepLimit_t hsCtr, 1746 RF_ReconUnitNum_t which_ru) 1747 { 1748 RF_ReconCtrl_t *reconCtrlPtr = raidPtr->reconControl; 1749 RF_CallbackValueDesc_t *cb, *p, *pt; 1750 int retval = 0; 1751 1752 /* if we're too far ahead of the slowest disk, stop working on this 1753 * disk until the slower ones catch up. We do this by scheduling a 1754 * wakeup callback for the time when the slowest disk has caught up. 1755 * We define "caught up" with 20% hysteresis, i.e. the head separation 1756 * must have fallen to at most 80% of the max allowable head 1757 * separation before we'll wake up. 1758 * 1759 */ 1760 rf_lock_mutex2(reconCtrlPtr->rb_mutex); 1761 while(reconCtrlPtr->rb_lock) { 1762 rf_wait_cond2(reconCtrlPtr->rb_cv, reconCtrlPtr->rb_mutex); 1763 } 1764 reconCtrlPtr->rb_lock = 1; 1765 rf_unlock_mutex2(reconCtrlPtr->rb_mutex); 1766 if ((raidPtr->headSepLimit >= 0) && 1767 ((ctrl->headSepCounter - reconCtrlPtr->minHeadSepCounter) > raidPtr->headSepLimit)) { 1768 Dprintf5("raid%d: RECON: head sep stall: col %d hsCtr %ld minHSCtr %ld limit %ld\n", 1769 raidPtr->raidid, col, ctrl->headSepCounter, 1770 reconCtrlPtr->minHeadSepCounter, 1771 raidPtr->headSepLimit); 1772 cb = rf_AllocCallbackValueDesc(raidPtr); 1773 /* the minHeadSepCounter value we have to get to before we'll 1774 * wake up. build in 20% hysteresis. */ 1775 cb->v = (ctrl->headSepCounter - raidPtr->headSepLimit + raidPtr->headSepLimit / 5); 1776 cb->col = col; 1777 cb->next = NULL; 1778 1779 /* insert this callback descriptor into the sorted list of 1780 * pending head-sep callbacks */ 1781 p = reconCtrlPtr->headSepCBList; 1782 if (!p) 1783 reconCtrlPtr->headSepCBList = cb; 1784 else 1785 if (cb->v < p->v) { 1786 cb->next = reconCtrlPtr->headSepCBList; 1787 reconCtrlPtr->headSepCBList = cb; 1788 } else { 1789 for (pt = p, p = p->next; p && (p->v < cb->v); pt = p, p = p->next); 1790 cb->next = p; 1791 pt->next = cb; 1792 } 1793 retval = 1; 1794 #if RF_RECON_STATS > 0 1795 ctrl->reconCtrl->reconDesc->hsStallCount++; 1796 #endif /* RF_RECON_STATS > 0 */ 1797 } 1798 rf_lock_mutex2(reconCtrlPtr->rb_mutex); 1799 reconCtrlPtr->rb_lock = 0; 1800 rf_broadcast_cond2(reconCtrlPtr->rb_cv); 1801 rf_unlock_mutex2(reconCtrlPtr->rb_mutex); 1802 1803 return (retval); 1804 } 1805 /* 1806 * checks to see if reconstruction has been either forced or blocked 1807 * by a user operation. if forced, we skip this RU entirely. else if 1808 * blocked, put ourselves on the wait list. else return 0. 1809 * 1810 * ASSUMES THE PSS MUTEX IS LOCKED UPON ENTRY 1811 */ 1812 static int 1813 CheckForcedOrBlockedReconstruction(RF_Raid_t *raidPtr, 1814 RF_ReconParityStripeStatus_t *pssPtr, 1815 RF_PerDiskReconCtrl_t *ctrl, 1816 RF_RowCol_t col, 1817 RF_StripeNum_t psid, 1818 RF_ReconUnitNum_t which_ru) 1819 { 1820 RF_CallbackValueDesc_t *cb; 1821 int retcode = 0; 1822 1823 if ((pssPtr->flags & RF_PSS_FORCED_ON_READ) || (pssPtr->flags & RF_PSS_FORCED_ON_WRITE)) 1824 retcode = RF_PSS_FORCED_ON_WRITE; 1825 else 1826 if (pssPtr->flags & RF_PSS_RECON_BLOCKED) { 1827 Dprintf3("RECON: col %d blocked at psid %ld ru %d\n", col, psid, which_ru); 1828 cb = rf_AllocCallbackValueDesc(raidPtr); /* append ourselves to 1829 * the blockage-wait 1830 * list */ 1831 cb->col = col; 1832 cb->next = pssPtr->blockWaitList; 1833 pssPtr->blockWaitList = cb; 1834 retcode = RF_PSS_RECON_BLOCKED; 1835 } 1836 if (!retcode) 1837 pssPtr->flags |= RF_PSS_UNDER_RECON; /* mark this RU as under 1838 * reconstruction */ 1839 1840 return (retcode); 1841 } 1842 /* 1843 * if reconstruction is currently ongoing for the indicated stripeID, 1844 * reconstruction is forced to completion and we return non-zero to 1845 * indicate that the caller must wait. If not, then reconstruction is 1846 * blocked on the indicated stripe and the routine returns zero. If 1847 * and only if we return non-zero, we'll cause the cbFunc to get 1848 * invoked with the cbArg when the reconstruction has completed. 1849 */ 1850 int 1851 rf_ForceOrBlockRecon(RF_Raid_t *raidPtr, RF_AccessStripeMap_t *asmap, 1852 void (*cbFunc)(void *), void *cbArg) 1853 { 1854 RF_StripeNum_t stripeID = asmap->stripeID; /* the stripe ID we're 1855 * forcing recon on */ 1856 RF_SectorCount_t sectorsPerRU = raidPtr->Layout.sectorsPerStripeUnit * raidPtr->Layout.SUsPerRU; /* num sects in one RU */ 1857 RF_ReconParityStripeStatus_t *pssPtr, *newpssPtr; /* a pointer to the parity 1858 * stripe status structure */ 1859 RF_StripeNum_t psid; /* parity stripe id */ 1860 RF_SectorNum_t offset, fd_offset; /* disk offset, failed-disk 1861 * offset */ 1862 RF_RowCol_t *diskids; 1863 RF_ReconUnitNum_t which_ru; /* RU within parity stripe */ 1864 RF_RowCol_t fcol, diskno, i; 1865 RF_ReconBuffer_t *new_rbuf; /* ptr to newly allocated rbufs */ 1866 RF_DiskQueueData_t *req;/* disk I/O req to be enqueued */ 1867 RF_CallbackFuncDesc_t *cb; 1868 int nPromoted; 1869 1870 psid = rf_MapStripeIDToParityStripeID(&raidPtr->Layout, stripeID, &which_ru); 1871 1872 /* allocate a new PSS in case we need it */ 1873 newpssPtr = rf_AllocPSStatus(raidPtr); 1874 1875 RF_LOCK_PSS_MUTEX(raidPtr, psid); 1876 1877 pssPtr = rf_LookupRUStatus(raidPtr, raidPtr->reconControl->pssTable, psid, which_ru, RF_PSS_CREATE | RF_PSS_RECON_BLOCKED, newpssPtr); 1878 1879 if (pssPtr != newpssPtr) { 1880 rf_FreePSStatus(raidPtr, newpssPtr); 1881 } 1882 1883 /* if recon is not ongoing on this PS, just return */ 1884 if (!(pssPtr->flags & RF_PSS_UNDER_RECON)) { 1885 RF_UNLOCK_PSS_MUTEX(raidPtr, psid); 1886 return (0); 1887 } 1888 /* otherwise, we have to wait for reconstruction to complete on this 1889 * RU. */ 1890 /* In order to avoid waiting for a potentially large number of 1891 * low-priority accesses to complete, we force a normal-priority (i.e. 1892 * not low-priority) reconstruction on this RU. */ 1893 if (!(pssPtr->flags & RF_PSS_FORCED_ON_WRITE) && !(pssPtr->flags & RF_PSS_FORCED_ON_READ)) { 1894 RF_ReconCtrl_t *reconCtrlPtr = raidPtr->reconControl; 1895 RF_RowCol_t stripeWidth = 1896 raidPtr->Layout.numDataCol + raidPtr->Layout.numParityCol; 1897 int unissued = 0, avail = 0; 1898 1899 fcol = reconCtrlPtr->fcol; 1900 1901 /* get a listing of the disks comprising the indicated stripe */ 1902 (raidPtr->Layout.map->IdentifyStripe) (raidPtr, asmap->raidAddress, &diskids); 1903 1904 for (i = 0; i < stripeWidth; i++) { 1905 diskno = diskids[i]; 1906 if (diskno != fcol && !pssPtr->issued[diskno]) 1907 unissued++; 1908 } 1909 1910 rf_lock_mutex2(reconCtrlPtr->rb_mutex); 1911 while (reconCtrlPtr->rb_lock) { 1912 rf_wait_cond2(reconCtrlPtr->rb_cv, 1913 reconCtrlPtr->rb_mutex); 1914 } 1915 reconCtrlPtr->rb_lock = 1; 1916 rf_unlock_mutex2(reconCtrlPtr->rb_mutex); 1917 1918 for (new_rbuf = reconCtrlPtr->forcedRbufs; 1919 new_rbuf != NULL && avail < unissued; 1920 new_rbuf = new_rbuf->next) 1921 avail++; 1922 1923 if (avail >= unissued) { 1924 DDprintf1("Forcing recon on psid %ld\n", psid); 1925 pssPtr->flags |= RF_PSS_FORCED_ON_WRITE; 1926 pssPtr->flags &= ~RF_PSS_RECON_BLOCKED; 1927 } 1928 1929 /* For previously issued reads, elevate them to normal 1930 * priority. If the I/O has already completed, it won't be 1931 * found in the queue, and hence this will be a no-op. For 1932 * unissued reads, pop pre-allocated forced buffers and issue 1933 * new reads if enough forced buffers are available. */ 1934 for (i = 0; i < stripeWidth; i++) 1935 if ((diskno = diskids[i]) != fcol) { 1936 if (pssPtr->issued[diskno]) { 1937 nPromoted = rf_DiskIOPromote(&raidPtr->Queues[diskno], psid, which_ru); 1938 if (rf_reconDebug && nPromoted) 1939 printf("raid%d: promoted read from col %d\n", raidPtr->raidid, diskno); 1940 } else if (avail >= unissued) { 1941 new_rbuf = reconCtrlPtr->forcedRbufs; 1942 reconCtrlPtr->forcedRbufs = new_rbuf->next; 1943 new_rbuf->next = NULL; 1944 new_rbuf->col = diskno; 1945 ComputePSDiskOffsets(raidPtr, psid, diskno, &offset, &fd_offset, 1946 &new_rbuf->spCol, &new_rbuf->spOffset); 1947 new_rbuf->parityStripeID = psid; 1948 new_rbuf->which_ru = which_ru; 1949 new_rbuf->failedDiskSectorOffset = fd_offset; 1950 new_rbuf->priority = RF_IO_NORMAL_PRIORITY; 1951 1952 /* use NULL b_proc b/c all addrs 1953 * should be in kernel space */ 1954 req = rf_CreateDiskQueueData(RF_IO_TYPE_READ, offset + which_ru * sectorsPerRU, sectorsPerRU, new_rbuf->buffer, 1955 psid, which_ru, 1956 ForceReconReadDoneProc, 1957 (void *) new_rbuf, 1958 NULL, (void *) raidPtr, 0, NULL); 1959 1960 new_rbuf->arg = req; 1961 rf_DiskIOEnqueue(&raidPtr->Queues[diskno], req, RF_IO_NORMAL_PRIORITY); 1962 Dprintf2("raid%d: Issued new read req on col %d\n", raidPtr->raidid, diskno); 1963 } 1964 } 1965 1966 rf_lock_mutex2(reconCtrlPtr->rb_mutex); 1967 reconCtrlPtr->rb_lock = 0; 1968 rf_broadcast_cond2(reconCtrlPtr->rb_cv); 1969 rf_unlock_mutex2(reconCtrlPtr->rb_mutex); 1970 1971 /* if the write is sitting in the disk queue, elevate its 1972 * priority */ 1973 if (rf_DiskIOPromote(&raidPtr->Queues[fcol], psid, which_ru)) 1974 if (rf_reconDebug) 1975 printf("raid%d: promoted write to col %d\n", 1976 raidPtr->raidid, fcol); 1977 } 1978 /* install a callback descriptor to be invoked when recon completes on 1979 * this parity stripe. */ 1980 cb = rf_AllocCallbackFuncDesc(raidPtr); 1981 cb->callbackFunc = cbFunc; 1982 cb->callbackArg = cbArg; 1983 cb->next = pssPtr->procWaitList; 1984 pssPtr->procWaitList = cb; 1985 DDprintf2("raid%d: Waiting for forced recon on psid %ld\n", 1986 raidPtr->raidid, psid); 1987 1988 RF_UNLOCK_PSS_MUTEX(raidPtr, psid); 1989 return (1); 1990 } 1991 /* called upon the completion of a forced reconstruction read. 1992 * all we do is schedule the FORCEDREADONE event. 1993 * called at interrupt context in the kernel, so don't do anything illegal here. 1994 */ 1995 static void 1996 ForceReconReadDoneProc(void *arg, int status) 1997 { 1998 RF_ReconBuffer_t *rbuf = arg; 1999 2000 /* Detect that reconControl is no longer valid, and if that 2001 is the case, bail without calling rf_CauseReconEvent(). 2002 There won't be anyone listening for this event anyway */ 2003 2004 if (rbuf->raidPtr->reconControl == NULL) 2005 return; 2006 2007 if (status) { 2008 printf("raid%d: Forced recon read failed!\n", rbuf->raidPtr->raidid); 2009 rf_CauseReconEvent(rbuf->raidPtr, rbuf->col, (void *) rbuf, RF_REVENT_FORCEDREAD_FAILED); 2010 return; 2011 } 2012 rf_CauseReconEvent(rbuf->raidPtr, rbuf->col, (void *) rbuf, RF_REVENT_FORCEDREADDONE); 2013 } 2014 /* releases a block on the reconstruction of the indicated stripe */ 2015 int 2016 rf_UnblockRecon(RF_Raid_t *raidPtr, RF_AccessStripeMap_t *asmap) 2017 { 2018 RF_StripeNum_t stripeID = asmap->stripeID; 2019 RF_ReconParityStripeStatus_t *pssPtr; 2020 RF_ReconUnitNum_t which_ru; 2021 RF_StripeNum_t psid; 2022 RF_CallbackValueDesc_t *cb; 2023 2024 psid = rf_MapStripeIDToParityStripeID(&raidPtr->Layout, stripeID, &which_ru); 2025 RF_LOCK_PSS_MUTEX(raidPtr, psid); 2026 pssPtr = rf_LookupRUStatus(raidPtr, raidPtr->reconControl->pssTable, psid, which_ru, RF_PSS_NONE, NULL); 2027 2028 /* When recon is forced, the pss desc can get deleted before we get 2029 * back to unblock recon. But, this can _only_ happen when recon is 2030 * forced. It would be good to put some kind of sanity check here, but 2031 * how to decide if recon was just forced or not? */ 2032 if (!pssPtr) { 2033 /* printf("Warning: no pss descriptor upon unblock on psid %ld 2034 * RU %d\n",psid,which_ru); */ 2035 #if (RF_DEBUG_RECON > 0) || (RF_DEBUG_PSS > 0) 2036 if (rf_reconDebug || rf_pssDebug) 2037 printf("Warning: no pss descriptor upon unblock on psid %ld RU %d\n", (long) psid, which_ru); 2038 #endif 2039 goto out; 2040 } 2041 pssPtr->blockCount--; 2042 Dprintf3("raid%d: unblocking recon on psid %ld: blockcount is %d\n", 2043 raidPtr->raidid, psid, pssPtr->blockCount); 2044 if (pssPtr->blockCount == 0) { /* if recon blockage has been released */ 2045 2046 /* unblock recon before calling CauseReconEvent in case 2047 * CauseReconEvent causes us to try to issue a new read before 2048 * returning here. */ 2049 pssPtr->flags &= ~RF_PSS_RECON_BLOCKED; 2050 2051 2052 while (pssPtr->blockWaitList) { 2053 /* spin through the block-wait list and 2054 release all the waiters */ 2055 cb = pssPtr->blockWaitList; 2056 pssPtr->blockWaitList = cb->next; 2057 cb->next = NULL; 2058 rf_CauseReconEvent(raidPtr, cb->col, NULL, RF_REVENT_BLOCKCLEAR); 2059 rf_FreeCallbackValueDesc(raidPtr, cb); 2060 } 2061 if (!(pssPtr->flags & RF_PSS_UNDER_RECON)) { 2062 /* if no recon was requested while recon was blocked */ 2063 rf_PSStatusDelete(raidPtr, raidPtr->reconControl->pssTable, pssPtr); 2064 } 2065 } 2066 out: 2067 RF_UNLOCK_PSS_MUTEX(raidPtr, psid); 2068 return (0); 2069 } 2070 2071 void 2072 rf_WakeupHeadSepCBWaiters(RF_Raid_t *raidPtr) 2073 { 2074 RF_CallbackValueDesc_t *p; 2075 2076 rf_lock_mutex2(raidPtr->reconControl->rb_mutex); 2077 while(raidPtr->reconControl->rb_lock) { 2078 rf_wait_cond2(raidPtr->reconControl->rb_cv, 2079 raidPtr->reconControl->rb_mutex); 2080 } 2081 2082 raidPtr->reconControl->rb_lock = 1; 2083 rf_unlock_mutex2(raidPtr->reconControl->rb_mutex); 2084 2085 while (raidPtr->reconControl->headSepCBList) { 2086 p = raidPtr->reconControl->headSepCBList; 2087 raidPtr->reconControl->headSepCBList = p->next; 2088 p->next = NULL; 2089 rf_CauseReconEvent(raidPtr, p->col, NULL, RF_REVENT_HEADSEPCLEAR); 2090 rf_FreeCallbackValueDesc(raidPtr, p); 2091 } 2092 rf_lock_mutex2(raidPtr->reconControl->rb_mutex); 2093 raidPtr->reconControl->rb_lock = 0; 2094 rf_broadcast_cond2(raidPtr->reconControl->rb_cv); 2095 rf_unlock_mutex2(raidPtr->reconControl->rb_mutex); 2096 2097 } 2098 2099