diff options
author | Matthew Ahrens <[email protected]> | 2020-08-05 10:22:09 -0700 |
---|---|---|
committer | GitHub <[email protected]> | 2020-08-05 10:22:09 -0700 |
commit | d87676a9fa0b434fe3073933c4125074b8a48325 (patch) | |
tree | dc6298157fc0b13b823768336e1b748f6b79f9a2 /module/zfs/dsl_destroy.c | |
parent | 1b376d176ead7651ffde83d319edcc1bcc65da55 (diff) |
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 <[email protected]>
Reviewed-by: George Wilson <[email protected]>
Signed-off-by: Matthew Ahrens <[email protected]>
Closes #10643
Diffstat (limited to 'module/zfs/dsl_destroy.c')
-rw-r--r-- | module/zfs/dsl_destroy.c | 21 |
1 files changed, 17 insertions, 4 deletions
diff --git a/module/zfs/dsl_destroy.c b/module/zfs/dsl_destroy.c index 190dbdef5..26fdf9634 100644 --- a/module/zfs/dsl_destroy.c +++ b/module/zfs/dsl_destroy.c @@ -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) && |