@@ -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
@@ -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) ||
@@ -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;
@@ -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,