* Issues a rebuild I/O and takes care of rate limiting the number of queued * rebuild I/Os. The provided start and size must be properly aligned for the * top-level vdev type being rebuilt. */
| 533 | * top-level vdev type being rebuilt. |
| 534 | */ |
| 535 | static int |
| 536 | vdev_rebuild_range(vdev_rebuild_t *vr, uint64_t start, uint64_t size) |
| 537 | { |
| 538 | uint64_t ms_id __maybe_unused = vr->vr_scan_msp->ms_id; |
| 539 | vdev_t *vd = vr->vr_top_vdev; |
| 540 | spa_t *spa = vd->vdev_spa; |
| 541 | blkptr_t blk; |
| 542 | |
| 543 | ASSERT3U(ms_id, ==, start >> vd->vdev_ms_shift); |
| 544 | ASSERT3U(ms_id, ==, (start + size - 1) >> vd->vdev_ms_shift); |
| 545 | |
| 546 | vr->vr_pass_bytes_scanned += size; |
| 547 | vr->vr_rebuild_phys.vrp_bytes_scanned += size; |
| 548 | |
| 549 | /* |
| 550 | * Rebuild the data in this range by constructing a special block |
| 551 | * pointer. It has no relation to any existing blocks in the pool. |
| 552 | * However, by disabling checksum verification and issuing a scrub IO |
| 553 | * we can reconstruct and repair any children with missing data. |
| 554 | */ |
| 555 | vdev_rebuild_blkptr_init(&blk, vd, start, size); |
| 556 | uint64_t psize = BP_GET_PSIZE(&blk); |
| 557 | |
| 558 | if (!vdev_dtl_need_resilver(vd, &blk.blk_dva[0], psize, TXG_UNKNOWN)) |
| 559 | return (0); |
| 560 | |
| 561 | mutex_enter(&vr->vr_io_lock); |
| 562 | |
| 563 | /* Limit in flight rebuild I/Os */ |
| 564 | while (vr->vr_bytes_inflight >= vr->vr_bytes_inflight_max) |
| 565 | cv_wait(&vr->vr_io_cv, &vr->vr_io_lock); |
| 566 | |
| 567 | vr->vr_bytes_inflight += psize; |
| 568 | mutex_exit(&vr->vr_io_lock); |
| 569 | |
| 570 | dmu_tx_t *tx = dmu_tx_create_dd(spa_get_dsl(spa)->dp_mos_dir); |
| 571 | VERIFY0(dmu_tx_assign(tx, TXG_WAIT)); |
| 572 | uint64_t txg = dmu_tx_get_txg(tx); |
| 573 | |
| 574 | spa_config_enter(spa, SCL_STATE_ALL, vd, RW_READER); |
| 575 | mutex_enter(&vd->vdev_rebuild_lock); |
| 576 | |
| 577 | /* This is the first I/O for this txg. */ |
| 578 | if (vr->vr_scan_offset[txg & TXG_MASK] == 0) { |
| 579 | vr->vr_scan_offset[txg & TXG_MASK] = start; |
| 580 | dsl_sync_task_nowait(spa_get_dsl(spa), |
| 581 | vdev_rebuild_update_sync, |
| 582 | (void *)(uintptr_t)vd->vdev_id, tx); |
| 583 | } |
| 584 | |
| 585 | /* When exiting write out our progress. */ |
| 586 | if (vdev_rebuild_should_stop(vd)) { |
| 587 | mutex_enter(&vr->vr_io_lock); |
| 588 | vr->vr_bytes_inflight -= psize; |
| 589 | mutex_exit(&vr->vr_io_lock); |
| 590 | spa_config_exit(vd->vdev_spa, SCL_STATE_ALL, vd); |
| 591 | mutex_exit(&vd->vdev_rebuild_lock); |
| 592 | dmu_tx_commit(tx); |
no test coverage detected