From: Darrick J. Wong <djwong@xxxxxxxxxx> Define a "self_healing" filesystem property so that sysadmins can indicate their preferences for background online fsck. Add an extended option to xfs_scrub so that it selects the operation mode from the self healing fs property. Signed-off-by: Darrick J. Wong <djwong@xxxxxxxxxx> --- man/man8/xfs_scrub.8 | 44 +++++++++++++++++++++++++++ scrub/phase1.c | 81 ++++++++++++++++++++++++++++++++++++++++++++++++++ scrub/xfs_scrub.c | 14 +++++++++ scrub/xfs_scrub.h | 7 ++++ 4 files changed, 146 insertions(+) diff --git a/man/man8/xfs_scrub.8 b/man/man8/xfs_scrub.8 index 1fd122f2a242..1e017078019c 100644 --- a/man/man8/xfs_scrub.8 +++ b/man/man8/xfs_scrub.8 @@ -107,6 +107,14 @@ The supported are: .RS 1.0i .TP +.B fsprops_advise +Decide the operating mode from the value of the +.I self_healing +filesystem property. +See the +.B filesytem properties +section for more details. +.TP .BI fstrim_pct= percentage To constrain the amount of time spent on fstrim activities during phase 8, this program tries to balance estimated runtime against completeness of the @@ -192,6 +200,42 @@ Scheduling a quotacheck for the next mount. .PP If corrupt metadata is successfully repaired, this program will log that a repair has succeeded instead of a corruption report. +.SH FILESYSTEM PROPERTIES +System administrators can convey their preferences for scrubbing of a +particular filesystem by setting the filesystem property +.B self_healing +via the +.B setfsprops +subcommand of the +.B xfs_spaceman +on the filesystem. +These preferences will be honored if the +.B -o fsprops_advise +option is specified. + +Recognized values for the +.B self_healing +property are: +.RS +.TP +.I none +Do not scan the filesystem at all. +.TP +.I check +Scan and report corruption and opportunities for optimization, but do not +change anything. +.TP +.I optimize +Scan the filesystem and optimize where possible. +Report corruptions, but do not fix them. +.TP +.I repair +Scan the filesystem, fix corruptions, and optimize where possible. +.RE + +If the property is not set, the default is +.IR check . + .SH EXIT CODE The exit code returned by .B xfs_scrub diff --git a/scrub/phase1.c b/scrub/phase1.c index 091b59e57e7b..5fa215a5bb79 100644 --- a/scrub/phase1.c +++ b/scrub/phase1.c @@ -28,6 +28,8 @@ #include "repair.h" #include "libfrog/fsgeom.h" #include "xfs_errortag.h" +#include "libfrog/fsprops.h" +#include "libfrog/fsproperties.h" /* Phase 1: Find filesystem geometry (and clean up after) */ @@ -130,6 +132,77 @@ enable_force_repair( return error; } +#define MAX_SELFHEAL_LEN 128 +/* + * Decide the operating mode from filesystem properties. No fs property or + * system errors means we only check. + */ +static void +mode_from_fsprops( + struct scrub_ctx *ctx) +{ + struct fsprops_handle fph = { }; + char valuebuf[MAX_SELFHEAL_LEN + 1] = { 0 }; + size_t valuelen = MAX_SELFHEAL_LEN; + enum fsprop_self_healing shval; + int ret; + + ret = fsprops_open_handle(&ctx->mnt, &ctx->fsinfo, &fph); + if (ret) { + ctx->mode = SCRUB_MODE_DRY_RUN; + goto summarize; + } + + ret = fsprops_get(&fph, FSPROP_SELF_HEALING_NAME, valuebuf, &valuelen); + if (ret) { + ctx->mode = SCRUB_MODE_DRY_RUN; + goto summarize; + } + + shval = fsprop_read_self_healing(valuebuf); + switch (shval) { + case FSPROP_SELFHEAL_NONE: + ctx->mode = SCRUB_MODE_NONE; + break; + case FSPROP_SELFHEAL_OPTIMIZE: + ctx->mode = SCRUB_MODE_PREEN; + break; + case FSPROP_SELFHEAL_REPAIR: + ctx->mode = SCRUB_MODE_REPAIR; + break; + case FSPROP_SELFHEAL_UNSET: + str_info(ctx, ctx->mntpoint, + _("Unknown self_healing directive \"%s\"."), + valuebuf); + fallthrough; + case FSPROP_SELFHEAL_CHECK: + ctx->mode = SCRUB_MODE_DRY_RUN; + break; + } + + fsprops_free_handle(&fph); + +summarize: + switch (ctx->mode) { + case SCRUB_MODE_NONE: + str_info(ctx, ctx->mntpoint, + _("Disabling scrub per self_healing directive.")); + break; + case SCRUB_MODE_DRY_RUN: + str_info(ctx, ctx->mntpoint, + _("Checking per self_healing directive.")); + break; + case SCRUB_MODE_PREEN: + str_info(ctx, ctx->mntpoint, + _("Optimizing per self_healing directive.")); + break; + case SCRUB_MODE_REPAIR: + str_info(ctx, ctx->mntpoint, + _("Checking and repairing per self_healing directive.")); + break; + } +} + /* * Bind to the mountpoint, read the XFS geometry, bind to the block devices. * Anything we've already built will be cleaned up by scrub_cleanup. @@ -206,6 +279,14 @@ _("Not an XFS filesystem.")); return error; } + /* + * If we've been instructed to decide the operating mode from the + * fs properties set on the mount point, do that now before we start + * downgrading based on actual fs/kernel capabilities. + */ + if (ctx->mode == SCRUB_MODE_NONE) + mode_from_fsprops(ctx); + /* Do we have kernel-assisted metadata scrubbing? */ if (!can_scrub_fs_metadata(ctx) || !can_scrub_inode(ctx) || !can_scrub_bmap(ctx) || !can_scrub_dir(ctx) || diff --git a/scrub/xfs_scrub.c b/scrub/xfs_scrub.c index f5b58de12812..a9d7e5ffe6d7 100644 --- a/scrub/xfs_scrub.c +++ b/scrub/xfs_scrub.c @@ -526,6 +526,10 @@ _("Scrub aborted after phase %d."), if (ret) break; + /* Did background scrub get canceled on us? */ + if (ctx->mode == SCRUB_MODE_NONE) + break; + /* Too many errors? */ if (scrub_excessive_errors(ctx)) { ret = ECANCELED; @@ -630,12 +634,14 @@ report_outcome( enum o_opt_nums { IWARN = 0, FSTRIM_PCT, + FSPROPS_ADVISE, O_MAX_OPTS, }; static char *o_opts[] = { [IWARN] = "iwarn", [FSTRIM_PCT] = "fstrim_pct", + [FSPROPS_ADVISE] = "fsprops_advise", [O_MAX_OPTS] = NULL, }; @@ -688,6 +694,14 @@ parse_o_opts( ctx->fstrim_block_pct = dval / 100.0; break; + case FSPROPS_ADVISE: + if (val) { + fprintf(stderr, + _("-o fsprops_advise does not take an argument\n")); + usage(); + } + ctx->mode = SCRUB_MODE_NONE; + break; default: usage(); break; diff --git a/scrub/xfs_scrub.h b/scrub/xfs_scrub.h index 4d9a028921b5..582ec8e579e9 100644 --- a/scrub/xfs_scrub.h +++ b/scrub/xfs_scrub.h @@ -26,6 +26,13 @@ extern bool use_force_rebuild; extern bool info_is_warning; enum scrub_mode { + /* + * Prior to phase 1, this means that xfs_scrub should read the + * "self_healing" fs property from the mount and set the value + * appropriate. If it's still set after phase 1, this means we should + * exit without doing anything. + */ + SCRUB_MODE_NONE, SCRUB_MODE_DRY_RUN, SCRUB_MODE_PREEN, SCRUB_MODE_REPAIR,