diff options
Diffstat (limited to 'module/zfs/vdev.c')
-rw-r--r-- | module/zfs/vdev.c | 43 |
1 files changed, 33 insertions, 10 deletions
diff --git a/module/zfs/vdev.c b/module/zfs/vdev.c index 9305bd894..860572336 100644 --- a/module/zfs/vdev.c +++ b/module/zfs/vdev.c @@ -3149,9 +3149,9 @@ vdev_dtl_should_excise(vdev_t *vd, boolean_t rebuild_done) * Reassess DTLs after a config change or scrub completion. If txg == 0 no * write operations will be issued to the pool. */ -void -vdev_dtl_reassess(vdev_t *vd, uint64_t txg, uint64_t scrub_txg, - boolean_t scrub_done, boolean_t rebuild_done) +static void +vdev_dtl_reassess_impl(vdev_t *vd, uint64_t txg, uint64_t scrub_txg, + boolean_t scrub_done, boolean_t rebuild_done, boolean_t faulting) { spa_t *spa = vd->vdev_spa; avl_tree_t reftree; @@ -3160,8 +3160,8 @@ vdev_dtl_reassess(vdev_t *vd, uint64_t txg, uint64_t scrub_txg, ASSERT(spa_config_held(spa, SCL_ALL, RW_READER) != 0); for (int c = 0; c < vd->vdev_children; c++) - vdev_dtl_reassess(vd->vdev_child[c], txg, - scrub_txg, scrub_done, rebuild_done); + vdev_dtl_reassess_impl(vd->vdev_child[c], txg, + scrub_txg, scrub_done, rebuild_done, faulting); if (vd == spa->spa_root_vdev || !vdev_is_concrete(vd) || vd->vdev_aux) return; @@ -3255,11 +3255,21 @@ vdev_dtl_reassess(vdev_t *vd, uint64_t txg, uint64_t scrub_txg, if (scrub_done) range_tree_vacate(vd->vdev_dtl[DTL_SCRUB], NULL, NULL); range_tree_vacate(vd->vdev_dtl[DTL_OUTAGE], NULL, NULL); - if (!vdev_readable(vd)) + + /* + * For the faulting case, treat members of a replacing vdev + * as if they are not available. It's more likely than not that + * a vdev in a replacing vdev could encounter read errors so + * treat it as not being able to contribute. + */ + if (!vdev_readable(vd) || + (faulting && vd->vdev_parent != NULL && + vd->vdev_parent->vdev_ops == &vdev_replacing_ops)) { range_tree_add(vd->vdev_dtl[DTL_OUTAGE], 0, -1ULL); - else + } else { range_tree_walk(vd->vdev_dtl[DTL_MISSING], range_tree_add, vd->vdev_dtl[DTL_OUTAGE]); + } /* * If the vdev was resilvering or rebuilding and no longer @@ -3321,6 +3331,14 @@ vdev_dtl_reassess(vdev_t *vd, uint64_t txg, uint64_t scrub_txg, } } +void +vdev_dtl_reassess(vdev_t *vd, uint64_t txg, uint64_t scrub_txg, + boolean_t scrub_done, boolean_t rebuild_done) +{ + return (vdev_dtl_reassess_impl(vd, txg, scrub_txg, scrub_done, + rebuild_done, B_FALSE)); +} + /* * Iterate over all the vdevs except spare, and post kobj events */ @@ -3548,7 +3566,11 @@ vdev_dtl_sync(vdev_t *vd, uint64_t txg) } /* - * Determine whether the specified vdev can be offlined/detached/removed + * Determine whether the specified vdev can be + * - offlined + * - detached + * - removed + * - faulted * without losing data. */ boolean_t @@ -3558,6 +3580,7 @@ vdev_dtl_required(vdev_t *vd) vdev_t *tvd = vd->vdev_top; uint8_t cant_read = vd->vdev_cant_read; boolean_t required; + boolean_t faulting = vd->vdev_state == VDEV_STATE_FAULTED; ASSERT(spa_config_held(spa, SCL_STATE_ALL, RW_WRITER) == SCL_STATE_ALL); @@ -3570,10 +3593,10 @@ vdev_dtl_required(vdev_t *vd) * If not, we can safely offline/detach/remove the device. */ vd->vdev_cant_read = B_TRUE; - vdev_dtl_reassess(tvd, 0, 0, B_FALSE, B_FALSE); + vdev_dtl_reassess_impl(tvd, 0, 0, B_FALSE, B_FALSE, faulting); required = !vdev_dtl_empty(tvd, DTL_OUTAGE); vd->vdev_cant_read = cant_read; - vdev_dtl_reassess(tvd, 0, 0, B_FALSE, B_FALSE); + vdev_dtl_reassess_impl(tvd, 0, 0, B_FALSE, B_FALSE, faulting); if (!required && zio_injection_enabled) { required = !!zio_handle_device_injection(vd, NULL, |