mirror of
https://git.proxmox.com/git/mirror_zfs.git
synced 2026-05-22 10:37:35 +03:00
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 <behlendorf1@llnl.gov> Reviewed-by: Tony Hutter <hutter2@llnl.gov> Co-authored-by: TulsiJain tulsi.jain@delphix.com Signed-off-by: George Amanakis <gamanakis@gmail.com> Closes #8995 Closes #12355
This commit is contained in:
committed by
Brian Behlendorf
parent
e34e15ed6d
commit
482eeef804
+53
-29
@@ -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)
|
||||
{
|
||||
@@ -267,6 +264,34 @@ find_birth_txg(dsl_dataset_t *ds, zbookmark_err_phys_t *zep,
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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,
|
||||
@@ -449,28 +475,6 @@ out:
|
||||
return (error);
|
||||
}
|
||||
|
||||
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 */
|
||||
|
||||
Reference in New Issue
Block a user