aboutsummaryrefslogtreecommitdiffstats
path: root/module/zfs/spa_errlog.c
diff options
context:
space:
mode:
authorGeorge Amanakis <[email protected]>2021-12-17 21:35:28 +0100
committerBrian Behlendorf <[email protected]>2023-05-18 11:59:42 -0700
commit482eeef804f0f325faddb102f112c0f1ec86a1b6 (patch)
treef5b052e7fed06ad527285841ec6de2d7503d39ed /module/zfs/spa_errlog.c
parente34e15ed6d1882d29e314321b7642305d99f1b78 (diff)
Teach zpool scrub to scrub only blocks in error log
Added a flag '-e' in zpool scrub to scrub only blocks in error log. A user can pause, resume and cancel the error scrub by passing additional command line arguments -p -s just like a regular scrub. This involves adding a new flag, creating new libzfs interfaces, a new ioctl, and the actual iteration and read-issuing logic. Error scrubbing is executed in multiple txg to make sure pool performance is not affected. Reviewed-by: Brian Behlendorf <[email protected]> Reviewed-by: Tony Hutter <[email protected]> Co-authored-by: TulsiJain [email protected] Signed-off-by: George Amanakis <[email protected]> Closes #8995 Closes #12355
Diffstat (limited to 'module/zfs/spa_errlog.c')
-rw-r--r--module/zfs/spa_errlog.c82
1 files changed, 53 insertions, 29 deletions
diff --git a/module/zfs/spa_errlog.c b/module/zfs/spa_errlog.c
index 5fe352786..2e5c22c11 100644
--- a/module/zfs/spa_errlog.c
+++ b/module/zfs/spa_errlog.c
@@ -110,7 +110,7 @@ errphys_to_name(zbookmark_err_phys_t *zep, char *buf, size_t len)
/*
* Convert a string to a err_phys.
*/
-static void
+void
name_to_errphys(char *buf, zbookmark_err_phys_t *zep)
{
zep->zb_object = zfs_strtonum(buf, &buf);
@@ -139,8 +139,7 @@ name_to_bookmark(char *buf, zbookmark_phys_t *zb)
ASSERT(*buf == '\0');
}
-#ifdef _KERNEL
-static void
+void
zep_to_zb(uint64_t dataset, zbookmark_err_phys_t *zep, zbookmark_phys_t *zb)
{
zb->zb_objset = dataset;
@@ -148,7 +147,6 @@ zep_to_zb(uint64_t dataset, zbookmark_err_phys_t *zep, zbookmark_phys_t *zb)
zb->zb_level = zep->zb_level;
zb->zb_blkid = zep->zb_blkid;
}
-#endif
static void
name_to_object(char *buf, uint64_t *obj)
@@ -238,8 +236,7 @@ spa_log_error(spa_t *spa, const zbookmark_phys_t *zb, const uint64_t *birth)
mutex_exit(&spa->spa_errlist_lock);
}
-#ifdef _KERNEL
-static int
+int
find_birth_txg(dsl_dataset_t *ds, zbookmark_err_phys_t *zep,
uint64_t *birth_txg)
{
@@ -268,6 +265,34 @@ find_birth_txg(dsl_dataset_t *ds, zbookmark_err_phys_t *zep,
}
/*
+ * This function finds the oldest affected filesystem containing an error
+ * block.
+ */
+int
+find_top_affected_fs(spa_t *spa, uint64_t head_ds, zbookmark_err_phys_t *zep,
+ uint64_t *top_affected_fs)
+{
+ uint64_t oldest_dsobj;
+ int error = dsl_dataset_oldest_snapshot(spa, head_ds, zep->zb_birth,
+ &oldest_dsobj);
+ if (error != 0)
+ return (error);
+
+ dsl_dataset_t *ds;
+ error = dsl_dataset_hold_obj_flags(spa->spa_dsl_pool, oldest_dsobj,
+ DS_HOLD_FLAG_DECRYPT, FTAG, &ds);
+ if (error != 0)
+ return (error);
+
+ *top_affected_fs =
+ dsl_dir_phys(ds->ds_dir)->dd_head_dataset_obj;
+ dsl_dataset_rele_flags(ds, DS_HOLD_FLAG_DECRYPT, FTAG);
+ return (0);
+}
+
+
+#ifdef _KERNEL
+/*
* Copy the bookmark to the end of the user-space buffer which starts at
* uaddr and has *count unused entries, and decrement *count by 1.
*/
@@ -288,7 +313,8 @@ copyout_entry(const zbookmark_phys_t *zb, void *uaddr, uint64_t *count)
* Each time the error block is referenced by a snapshot or clone, add a
* zbookmark_phys_t entry to the userspace array at uaddr. The array is
* filled from the back and the in-out parameter *count is modified to be the
- * number of unused entries at the beginning of the array.
+ * number of unused entries at the beginning of the array. The function
+ * scrub_filesystem() is modelled after this one.
*/
static int
check_filesystem(spa_t *spa, uint64_t head_ds, zbookmark_err_phys_t *zep,
@@ -450,28 +476,6 @@ out:
}
static int
-find_top_affected_fs(spa_t *spa, uint64_t head_ds, zbookmark_err_phys_t *zep,
- uint64_t *top_affected_fs)
-{
- uint64_t oldest_dsobj;
- int error = dsl_dataset_oldest_snapshot(spa, head_ds, zep->zb_birth,
- &oldest_dsobj);
- if (error != 0)
- return (error);
-
- dsl_dataset_t *ds;
- error = dsl_dataset_hold_obj_flags(spa->spa_dsl_pool, oldest_dsobj,
- DS_HOLD_FLAG_DECRYPT, FTAG, &ds);
- if (error != 0)
- return (error);
-
- *top_affected_fs =
- dsl_dir_phys(ds->ds_dir)->dd_head_dataset_obj;
- dsl_dataset_rele_flags(ds, DS_HOLD_FLAG_DECRYPT, FTAG);
- return (0);
-}
-
-static int
process_error_block(spa_t *spa, uint64_t head_ds, zbookmark_err_phys_t *zep,
void *uaddr, uint64_t *count)
{
@@ -536,6 +540,21 @@ process_error_block(spa_t *spa, uint64_t head_ds, zbookmark_err_phys_t *zep,
}
#endif
+/* Return the number of errors in the error log */
+uint64_t
+spa_get_last_errlog_size(spa_t *spa)
+{
+ uint64_t total = 0, count;
+ mutex_enter(&spa->spa_errlog_lock);
+
+ if (spa->spa_errlog_last != 0 &&
+ zap_count(spa->spa_meta_objset, spa->spa_errlog_last,
+ &count) == 0)
+ total += count;
+ mutex_exit(&spa->spa_errlog_lock);
+ return (total);
+}
+
/*
* If a healed bookmark matches an entry in the error log we stash it in a tree
* so that we can later remove the related log entries in sync context.
@@ -1447,6 +1466,7 @@ spa_swap_errlog(spa_t *spa, uint64_t new_head_ds, uint64_t old_head_ds,
/* error handling */
EXPORT_SYMBOL(spa_log_error);
EXPORT_SYMBOL(spa_approx_errlog_size);
+EXPORT_SYMBOL(spa_get_last_errlog_size);
EXPORT_SYMBOL(spa_get_errlog);
EXPORT_SYMBOL(spa_errlog_rotate);
EXPORT_SYMBOL(spa_errlog_drain);
@@ -1456,6 +1476,10 @@ EXPORT_SYMBOL(spa_delete_dataset_errlog);
EXPORT_SYMBOL(spa_swap_errlog);
EXPORT_SYMBOL(sync_error_list);
EXPORT_SYMBOL(spa_upgrade_errlog);
+EXPORT_SYMBOL(find_top_affected_fs);
+EXPORT_SYMBOL(find_birth_txg);
+EXPORT_SYMBOL(zep_to_zb);
+EXPORT_SYMBOL(name_to_errphys);
#endif
/* BEGIN CSTYLED */