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