mirror of
https://git.proxmox.com/git/mirror_zfs.git
synced 2026-05-25 03:37:45 +03:00
Fix i/o error handling of livelists and zap iteration
Pool-wide metadata is stored in the MOS (Meta Object Set). This metadata is stored in triplicate, in addition to any pool-level reduncancy (e.g. RAIDZ). However, if all 3+ copies of this metadata are not available, we can still get EIO/ECKSUM when reading from the MOS. If we encounter such an error in syncing context, we have typically already committed to making a change that we now can't do because of the corrupt/missing metadata. We typically "handle" this with a `VERIFY()` or `zfs_panic_recover()`. This prevents the system from continuing on in an undefined state, while minimizing the amount of error-handling code. However, there are some code paths that ignore these i/o errors, or `ASSERT()` that they don't happen. Since assertions are disabled on non-debug builds, they effectively ignore them as well. This can lead to ZFS continuing on in an incorrect state, potentially leading to on-disk inconsistencies. This commit adds handling for these i/o errors on MOS metadata, typically with a `VERIFY()`: * Handle error return from `zap_cursor_retrieve()` in 4 places in `dsl_deadlist.c`. * Handle error return from `zap_contains()` in `dsl_dir_hold_obj()`. Turns out this call isn't necessary because we can always call `zap_lookup()`. * Handle error return from `zap_lookup()` in `dsl_fs_ss_limit_check()`. * Handle error return from `zap_remove()` in `dsl_dir_rename_sync()`. * Handle error return from `zap_lookup()` in `dsl_dir_remove_livelist()`. * Handle error return from `dsl_process_sub_livelist()` in `spa_livelist_delete_cb()`. Additionally: * Augment the internal history log message for `zfs destroy` to note which method is used (e.g. bptree, livelist, or, synchronous) and the mintxg. * Correct a comment in `dbuf_init()`. * Correct indentation in `dsl_dir_remove_livelist()`. Reviewed by: Sara Hartse <sara.hartse@delphix.com> Reviewed-by: George Wilson <george.wilson@delphix.com> Signed-off-by: Matthew Ahrens <mahrens@delphix.com> Closes #10643
This commit is contained in:
@@ -738,6 +738,10 @@ old_synchronous_dataset_destroy(dsl_dataset_t *ds, dmu_tx_t *tx)
|
||||
{
|
||||
struct killarg ka;
|
||||
|
||||
spa_history_log_internal_ds(ds, "destroy", tx,
|
||||
"(synchronous, mintxg=%llu)",
|
||||
(long long)dsl_dataset_phys(ds)->ds_prev_snap_txg);
|
||||
|
||||
/*
|
||||
* Free everything that we point to (that's born after
|
||||
* the previous snapshot, if we are a clone)
|
||||
@@ -902,6 +906,14 @@ dsl_async_clone_destroy(dsl_dataset_t *ds, dmu_tx_t *tx)
|
||||
spa_t *spa = dmu_tx_pool(tx)->dp_spa;
|
||||
VERIFY0(dmu_objset_from_ds(ds, &os));
|
||||
|
||||
uint64_t mintxg = 0;
|
||||
dsl_deadlist_entry_t *dle = dsl_deadlist_first(&dd->dd_livelist);
|
||||
if (dle != NULL)
|
||||
mintxg = dle->dle_mintxg;
|
||||
|
||||
spa_history_log_internal_ds(ds, "destroy", tx,
|
||||
"(livelist, mintxg=%llu)", (long long)mintxg);
|
||||
|
||||
/* Check that the clone is in a correct state to be deleted */
|
||||
dsl_clone_destroy_assert(dd);
|
||||
|
||||
@@ -922,7 +934,7 @@ dsl_async_clone_destroy(dsl_dataset_t *ds, dmu_tx_t *tx)
|
||||
spa->spa_livelists_to_delete = zap_obj;
|
||||
} else if (error != 0) {
|
||||
zfs_panic_recover("zfs: error %d was returned while looking "
|
||||
"up DMU_POOL_DELETED_CLONES in the zap");
|
||||
"up DMU_POOL_DELETED_CLONES in the zap", error);
|
||||
return;
|
||||
}
|
||||
VERIFY0(zap_add_int(mos, zap_obj, to_delete, tx));
|
||||
@@ -952,6 +964,10 @@ dsl_async_dataset_destroy(dsl_dataset_t *ds, dmu_tx_t *tx)
|
||||
dsl_pool_t *dp = dmu_tx_pool(tx);
|
||||
objset_t *mos = dp->dp_meta_objset;
|
||||
|
||||
spa_history_log_internal_ds(ds, "destroy", tx,
|
||||
"(bptree, mintxg=%llu)",
|
||||
(long long)dsl_dataset_phys(ds)->ds_prev_snap_txg);
|
||||
|
||||
zil_destroy_sync(dmu_objset_zil(os), tx);
|
||||
|
||||
if (!spa_feature_is_active(dp->dp_spa,
|
||||
@@ -1003,9 +1019,6 @@ dsl_destroy_head_sync_impl(dsl_dataset_t *ds, dmu_tx_t *tx)
|
||||
rrw_exit(&ds->ds_bp_rwlock, FTAG);
|
||||
ASSERT(RRW_WRITE_HELD(&dp->dp_config_rwlock));
|
||||
|
||||
/* We need to log before removing it from the namespace. */
|
||||
spa_history_log_internal_ds(ds, "destroy", tx, " ");
|
||||
|
||||
dsl_dir_cancel_waiters(ds->ds_dir);
|
||||
|
||||
rmorigin = (dsl_dir_is_clone(ds->ds_dir) &&
|
||||
|
||||
Reference in New Issue
Block a user