From 0409d3327371cef8a8c5886cb7530ded6f5f1091 Mon Sep 17 00:00:00 2001 From: George Amanakis Date: Tue, 26 Apr 2022 02:25:42 +0200 Subject: Improve zpool status output, list all affected datasets Currently, determining which datasets are affected by corruption is a manual process. The primary difficulty in reporting the list of affected snapshots is that since the error was initially found, the snapshot where the error originally occurred in, may have been deleted. To solve this issue, we add the ID of the head dataset of the original snapshot which the error was detected in, to the stored error report. Then any time a filesystem is deleted, the errors associated with it are deleted as well. Any time a clone promote occurs, we modify reports associated with the original head to refer to the new head. The stored error reports are identified by this head ID, the birth time of the block which the error occurred in, as well as some information about the error itself are also stored. Once this information is stored, we can find the set of datasets affected by an error by walking back the list of snapshots in the given head until we find one with the appropriate birth txg, and then traverse through the snapshots of the clone family, terminating a branch if the block was replaced in a given snapshot. Then we report this information back to libzfs, and to the zpool status command, where it is displayed as follows: pool: test state: ONLINE status: One or more devices has experienced an error resulting in data corruption. Applications may be affected. action: Restore the file in question if possible. Otherwise restore the entire pool from backup. see: https://openzfs.github.io/openzfs-docs/msg/ZFS-8000-8A scan: scrub repaired 0B in 00:00:00 with 800 errors on Fri Dec 3 08:27:57 2021 config: NAME STATE READ WRITE CKSUM test ONLINE 0 0 0 sdb ONLINE 0 0 1.58K errors: Permanent errors have been detected in the following files: test@1:/test.0.0 /test/test.0.0 /test/1clone/test.0.0 A new feature flag is introduced to mark the presence of this change, as well as promotion and backwards compatibility logic. This is an updated version of #9175. Rebase required fixing the tests, updating the ABI of libzfs, updating the man pages, fixing bugs, fixing the error returns, and updating the old on-disk error logs to the new format when activating the feature. Reviewed-by: Matthew Ahrens Reviewed-by: Brian Behlendorf Reviewed-by: Mark Maybee Reviewed-by: Tony Hutter Co-authored-by: TulsiJain Signed-off-by: George Amanakis Closes #9175 Closes #12812 --- include/sys/dsl_dataset.h | 3 +++ include/sys/spa.h | 8 +++++++- include/sys/zio.h | 14 ++++++++++++++ include/zfeature_common.h | 1 + 4 files changed, 25 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/include/sys/dsl_dataset.h b/include/sys/dsl_dataset.h index 02147171a..a8ca7444a 100644 --- a/include/sys/dsl_dataset.h +++ b/include/sys/dsl_dataset.h @@ -487,6 +487,9 @@ boolean_t dsl_dataset_get_uint64_array_feature(dsl_dataset_t *ds, void dsl_dataset_activate_redaction(dsl_dataset_t *ds, uint64_t *redact_snaps, uint64_t num_redact_snaps, dmu_tx_t *tx); +int dsl_dataset_oldest_snapshot(spa_t *spa, uint64_t head_ds, uint64_t min_txg, + uint64_t *oldest_dsobj); + #ifdef ZFS_DEBUG #define dprintf_ds(ds, fmt, ...) do { \ if (zfs_flags & ZFS_DEBUG_DPRINTF) { \ diff --git a/include/sys/spa.h b/include/sys/spa.h index 2ce84c21c..232855449 100644 --- a/include/sys/spa.h +++ b/include/sys/spa.h @@ -1144,11 +1144,17 @@ extern void zfs_post_remove(spa_t *spa, vdev_t *vd); extern void zfs_post_state_change(spa_t *spa, vdev_t *vd, uint64_t laststate); extern void zfs_post_autoreplace(spa_t *spa, vdev_t *vd); extern uint64_t spa_get_errlog_size(spa_t *spa); -extern int spa_get_errlog(spa_t *spa, void *uaddr, size_t *count); +extern int spa_get_errlog(spa_t *spa, void *uaddr, uint64_t *count); extern void spa_errlog_rotate(spa_t *spa); extern void spa_errlog_drain(spa_t *spa); extern void spa_errlog_sync(spa_t *spa, uint64_t txg); extern void spa_get_errlists(spa_t *spa, avl_tree_t *last, avl_tree_t *scrub); +extern void spa_delete_dataset_errlog(spa_t *spa, uint64_t ds, dmu_tx_t *tx); +extern void spa_swap_errlog(spa_t *spa, uint64_t new_head_ds, + uint64_t old_head_ds, dmu_tx_t *tx); +extern void sync_error_list(spa_t *spa, avl_tree_t *t, uint64_t *obj, + dmu_tx_t *tx); +extern void spa_upgrade_errlog(spa_t *spa, dmu_tx_t *tx); /* vdev cache */ extern void vdev_cache_stat_init(void); diff --git a/include/sys/zio.h b/include/sys/zio.h index 2cf10f309..7b78f0878 100644 --- a/include/sys/zio.h +++ b/include/sys/zio.h @@ -283,6 +283,13 @@ extern const char *const zio_type_name[ZIO_TYPES]; * Note: this structure is passed between userland and the kernel, and is * stored on disk (by virtue of being incorporated into other on-disk * structures, e.g. dsl_scan_phys_t). + * + * If the head_errlog feature is enabled a different on-disk format for error + * logs is used. This introduces the use of an error bookmark, a four-tuple + * that uniquely identifies any error block + * in the pool. The birth transaction group is used to track whether the block + * has been overwritten by newer data or added to a snapshot since its marking + * as an error. */ struct zbookmark_phys { uint64_t zb_objset; @@ -291,6 +298,13 @@ struct zbookmark_phys { uint64_t zb_blkid; }; +typedef struct zbookmark_err_phys { + uint64_t zb_object; + int64_t zb_level; + uint64_t zb_blkid; + uint64_t zb_birth; +} zbookmark_err_phys_t; + #define SET_BOOKMARK(zb, objset, object, level, blkid) \ { \ (zb)->zb_objset = objset; \ diff --git a/include/zfeature_common.h b/include/zfeature_common.h index 580f5ff3e..d4d636f9c 100644 --- a/include/zfeature_common.h +++ b/include/zfeature_common.h @@ -76,6 +76,7 @@ typedef enum spa_feature { SPA_FEATURE_ZSTD_COMPRESS, SPA_FEATURE_DRAID, SPA_FEATURE_ZILSAXATTR, + SPA_FEATURE_HEAD_ERRLOG, SPA_FEATURES } spa_feature_t; -- cgit v1.2.3