/* ARGSUSED */ static void dsl_pool_scrub_cancel_sync(void *arg1, void *arg2, cred_t *cr, dmu_tx_t *tx) { dsl_pool_t *dp = arg1; boolean_t *completep = arg2; if (dp->dp_scrub_func == SCRUB_FUNC_NONE) return; mutex_enter(&dp->dp_scrub_cancel_lock); if (dp->dp_scrub_restart) { dp->dp_scrub_restart = B_FALSE; *completep = B_FALSE; } /* XXX this is scrub-clean specific */ mutex_enter(&dp->dp_spa->spa_scrub_lock); while (dp->dp_spa->spa_scrub_inflight > 0) { cv_wait(&dp->dp_spa->spa_scrub_io_cv, &dp->dp_spa->spa_scrub_lock); } mutex_exit(&dp->dp_spa->spa_scrub_lock); dp->dp_spa->spa_scrub_active = B_FALSE; dp->dp_scrub_func = SCRUB_FUNC_NONE; VERIFY(0 == dmu_object_free(dp->dp_meta_objset, dp->dp_scrub_queue_obj, tx)); dp->dp_scrub_queue_obj = 0; bzero(&dp->dp_scrub_bookmark, sizeof (zbookmark_t)); bzero(&dp->dp_scrub_ddt_bookmark, sizeof (ddt_bookmark_t)); VERIFY(0 == zap_remove(dp->dp_meta_objset, DMU_POOL_DIRECTORY_OBJECT, DMU_POOL_SCRUB_QUEUE, tx)); VERIFY(0 == zap_remove(dp->dp_meta_objset, DMU_POOL_DIRECTORY_OBJECT, DMU_POOL_SCRUB_MIN_TXG, tx)); VERIFY(0 == zap_remove(dp->dp_meta_objset, DMU_POOL_DIRECTORY_OBJECT, DMU_POOL_SCRUB_MAX_TXG, tx)); VERIFY(0 == zap_remove(dp->dp_meta_objset, DMU_POOL_DIRECTORY_OBJECT, DMU_POOL_SCRUB_BOOKMARK, tx)); VERIFY(0 == zap_remove(dp->dp_meta_objset, DMU_POOL_DIRECTORY_OBJECT, DMU_POOL_SCRUB_FUNC, tx)); VERIFY(0 == zap_remove(dp->dp_meta_objset, DMU_POOL_DIRECTORY_OBJECT, DMU_POOL_SCRUB_ERRORS, tx)); (void) zap_remove(dp->dp_meta_objset, DMU_POOL_DIRECTORY_OBJECT, DMU_POOL_SCRUB_DDT_BOOKMARK, tx); (void) zap_remove(dp->dp_meta_objset, DMU_POOL_DIRECTORY_OBJECT, DMU_POOL_SCRUB_DDT_CLASS_MAX, tx); spa_history_internal_log(LOG_POOL_SCRUB_DONE, dp->dp_spa, tx, cr, "complete=%u", *completep); /* below is scrub-clean specific */ vdev_scrub_stat_update(dp->dp_spa->spa_root_vdev, POOL_SCRUB_NONE, *completep); /* * If the scrub/resilver completed, update all DTLs to reflect this. * Whether it succeeded or not, vacate all temporary scrub DTLs. */ vdev_dtl_reassess(dp->dp_spa->spa_root_vdev, tx->tx_txg, *completep ? dp->dp_scrub_max_txg : 0, B_TRUE); dp->dp_spa->spa_scrub_started = B_FALSE; if (*completep) spa_event_notify(dp->dp_spa, NULL, dp->dp_scrub_min_txg ? ESC_ZFS_RESILVER_FINISH : ESC_ZFS_SCRUB_FINISH); spa_errlog_rotate(dp->dp_spa); /* * We may have finished replacing a device. * Let the async thread assess this and handle the detach. */ spa_async_request(dp->dp_spa, SPA_ASYNC_RESILVER_DONE); dp->dp_scrub_min_txg = dp->dp_scrub_max_txg = 0; mutex_exit(&dp->dp_scrub_cancel_lock); }
/* ARGSUSED */ static void dsl_pool_scrub_setup_sync(void *arg1, void *arg2, cred_t *cr, dmu_tx_t *tx) { dsl_pool_t *dp = arg1; enum scrub_func *funcp = arg2; dmu_object_type_t ot = 0; boolean_t complete = B_FALSE; dsl_pool_scrub_cancel_sync(dp, &complete, cr, tx); ASSERT(dp->dp_scrub_func == SCRUB_FUNC_NONE); ASSERT(*funcp > SCRUB_FUNC_NONE); ASSERT(*funcp < SCRUB_FUNC_NUMFUNCS); dp->dp_scrub_min_txg = 0; dp->dp_scrub_max_txg = tx->tx_txg; dp->dp_scrub_ddt_class_max = zfs_scrub_ddt_class_max; if (*funcp == SCRUB_FUNC_CLEAN) { vdev_t *rvd = dp->dp_spa->spa_root_vdev; /* rewrite all disk labels */ vdev_config_dirty(rvd); if (vdev_resilver_needed(rvd, &dp->dp_scrub_min_txg, &dp->dp_scrub_max_txg)) { spa_event_notify(dp->dp_spa, NULL, ESC_ZFS_RESILVER_START); dp->dp_scrub_max_txg = MIN(dp->dp_scrub_max_txg, tx->tx_txg); } else { spa_event_notify(dp->dp_spa, NULL, ESC_ZFS_SCRUB_START); } /* zero out the scrub stats in all vdev_stat_t's */ vdev_scrub_stat_update(rvd, dp->dp_scrub_min_txg ? POOL_SCRUB_RESILVER : POOL_SCRUB_EVERYTHING, B_FALSE); /* * If this is an incremental scrub, limit the DDT scrub phase * to just the auto-ditto class (for correctness); the rest * of the scrub should go faster using top-down pruning. */ if (dp->dp_scrub_min_txg > TXG_INITIAL) dp->dp_scrub_ddt_class_max = DDT_CLASS_DITTO; dp->dp_spa->spa_scrub_started = B_TRUE; } /* back to the generic stuff */ if (dp->dp_blkstats == NULL) { dp->dp_blkstats = kmem_alloc(sizeof (zfs_all_blkstats_t), KM_SLEEP); } bzero(dp->dp_blkstats, sizeof (zfs_all_blkstats_t)); if (spa_version(dp->dp_spa) < SPA_VERSION_DSL_SCRUB) ot = DMU_OT_ZAP_OTHER; dp->dp_scrub_func = *funcp; dp->dp_scrub_queue_obj = zap_create(dp->dp_meta_objset, ot ? ot : DMU_OT_SCRUB_QUEUE, DMU_OT_NONE, 0, tx); bzero(&dp->dp_scrub_bookmark, sizeof (zbookmark_t)); bzero(&dp->dp_scrub_ddt_bookmark, sizeof (ddt_bookmark_t)); dp->dp_scrub_restart = B_FALSE; dp->dp_spa->spa_scrub_errors = 0; VERIFY(0 == zap_add(dp->dp_meta_objset, DMU_POOL_DIRECTORY_OBJECT, DMU_POOL_SCRUB_FUNC, sizeof (uint32_t), 1, &dp->dp_scrub_func, tx)); VERIFY(0 == zap_add(dp->dp_meta_objset, DMU_POOL_DIRECTORY_OBJECT, DMU_POOL_SCRUB_QUEUE, sizeof (uint64_t), 1, &dp->dp_scrub_queue_obj, tx)); VERIFY(0 == zap_add(dp->dp_meta_objset, DMU_POOL_DIRECTORY_OBJECT, DMU_POOL_SCRUB_MIN_TXG, sizeof (uint64_t), 1, &dp->dp_scrub_min_txg, tx)); VERIFY(0 == zap_add(dp->dp_meta_objset, DMU_POOL_DIRECTORY_OBJECT, DMU_POOL_SCRUB_MAX_TXG, sizeof (uint64_t), 1, &dp->dp_scrub_max_txg, tx)); VERIFY(0 == zap_add(dp->dp_meta_objset, DMU_POOL_DIRECTORY_OBJECT, DMU_POOL_SCRUB_BOOKMARK, sizeof (uint64_t), sizeof (dp->dp_scrub_bookmark) / sizeof (uint64_t), &dp->dp_scrub_bookmark, tx)); VERIFY(0 == zap_update(dp->dp_meta_objset, DMU_POOL_DIRECTORY_OBJECT, DMU_POOL_SCRUB_DDT_BOOKMARK, sizeof (uint64_t), sizeof (dp->dp_scrub_ddt_bookmark) / sizeof (uint64_t), &dp->dp_scrub_ddt_bookmark, tx)); VERIFY(0 == zap_update(dp->dp_meta_objset, DMU_POOL_DIRECTORY_OBJECT, DMU_POOL_SCRUB_DDT_CLASS_MAX, sizeof (uint64_t), 1, &dp->dp_scrub_ddt_class_max, tx)); VERIFY(0 == zap_add(dp->dp_meta_objset, DMU_POOL_DIRECTORY_OBJECT, DMU_POOL_SCRUB_ERRORS, sizeof (uint64_t), 1, &dp->dp_spa->spa_scrub_errors, tx)); spa_history_internal_log(LOG_POOL_SCRUB, dp->dp_spa, tx, cr, "func=%u mintxg=%llu maxtxg=%llu", *funcp, dp->dp_scrub_min_txg, dp->dp_scrub_max_txg); }
/* ARGSUSED */ static void dsl_pool_scrub_setup_sync(void *arg1, void *arg2, cred_t *cr, dmu_tx_t *tx) { dsl_pool_t *dp = arg1; enum scrub_func *funcp = arg2; dmu_object_type_t ot = 0; boolean_t complete = B_FALSE; dsl_pool_scrub_cancel_sync(dp, &complete, cr, tx); ASSERT(dp->dp_scrub_func == SCRUB_FUNC_NONE); ASSERT(*funcp > SCRUB_FUNC_NONE); ASSERT(*funcp < SCRUB_FUNC_NUMFUNCS); dp->dp_scrub_min_txg = 0; dp->dp_scrub_max_txg = tx->tx_txg; if (*funcp == SCRUB_FUNC_CLEAN) { vdev_t *rvd = dp->dp_spa->spa_root_vdev; /* rewrite all disk labels */ vdev_config_dirty(rvd); if (vdev_resilver_needed(rvd, &dp->dp_scrub_min_txg, &dp->dp_scrub_max_txg)) { spa_event_notify(dp->dp_spa, NULL, ESC_ZFS_RESILVER_START); dp->dp_scrub_max_txg = MIN(dp->dp_scrub_max_txg, tx->tx_txg); } /* zero out the scrub stats in all vdev_stat_t's */ vdev_scrub_stat_update(rvd, dp->dp_scrub_min_txg ? POOL_SCRUB_RESILVER : POOL_SCRUB_EVERYTHING, B_FALSE); dp->dp_spa->spa_scrub_started = B_TRUE; } /* back to the generic stuff */ if (spa_version(dp->dp_spa) < SPA_VERSION_DSL_SCRUB) ot = DMU_OT_ZAP_OTHER; dp->dp_scrub_func = *funcp; dp->dp_scrub_queue_obj = zap_create(dp->dp_meta_objset, ot ? ot : DMU_OT_SCRUB_QUEUE, DMU_OT_NONE, 0, tx); bzero(&dp->dp_scrub_bookmark, sizeof (zbookmark_t)); dp->dp_scrub_restart = B_FALSE; dp->dp_spa->spa_scrub_errors = 0; VERIFY(0 == zap_add(dp->dp_meta_objset, DMU_POOL_DIRECTORY_OBJECT, DMU_POOL_SCRUB_FUNC, sizeof (uint32_t), 1, &dp->dp_scrub_func, tx)); VERIFY(0 == zap_add(dp->dp_meta_objset, DMU_POOL_DIRECTORY_OBJECT, DMU_POOL_SCRUB_QUEUE, sizeof (uint64_t), 1, &dp->dp_scrub_queue_obj, tx)); VERIFY(0 == zap_add(dp->dp_meta_objset, DMU_POOL_DIRECTORY_OBJECT, DMU_POOL_SCRUB_MIN_TXG, sizeof (uint64_t), 1, &dp->dp_scrub_min_txg, tx)); VERIFY(0 == zap_add(dp->dp_meta_objset, DMU_POOL_DIRECTORY_OBJECT, DMU_POOL_SCRUB_MAX_TXG, sizeof (uint64_t), 1, &dp->dp_scrub_max_txg, tx)); VERIFY(0 == zap_add(dp->dp_meta_objset, DMU_POOL_DIRECTORY_OBJECT, DMU_POOL_SCRUB_BOOKMARK, sizeof (uint64_t), 4, &dp->dp_scrub_bookmark, tx)); VERIFY(0 == zap_add(dp->dp_meta_objset, DMU_POOL_DIRECTORY_OBJECT, DMU_POOL_SCRUB_ERRORS, sizeof (uint64_t), 1, &dp->dp_spa->spa_scrub_errors, tx)); spa_history_internal_log(LOG_POOL_SCRUB, dp->dp_spa, tx, cr, "func=%u mintxg=%llu maxtxg=%llu", *funcp, dp->dp_scrub_min_txg, dp->dp_scrub_max_txg); }