[PATCH 4/4] xfs_scrub: upload clean bills of health

Darrick J. Wong
2023-12-31T22:14:33Z

If scrub terminates with a clean bill of health, tell the kernel that
the result of the scan is that everything's healthy.

Signed-off-by: Darrick J. Wong <djwong@kernel.org>
---
scrub/phase1.c | 38 ++++++++++++++++++++++++++++++++++++++
scrub/repair.c | 15 +++++++++++++++
scrub/repair.h | 1 +
scrub/scrub.c | 9 +++++++++
scrub/scrub.h | 1 +
5 files changed, 64 insertions(+)

diff --git a/scrub/phase1.c b/scrub/phase1.c
index 48ca8313b05..96138e03e71 100644
--- a/scrub/phase1.c
+++ b/scrub/phase1.c
@@ -44,6 +44,40 @@ xfs_shutdown_fs(
str_errno(ctx, ctx->mntpoint);
}

+/*
+ * If we haven't found /any/ problems at all, tell the kernel that we're giving
+ * the filesystem a clean bill of health.
+ */
+static int
+report_to_kernel(
+ struct scrub_ctx *ctx)
+{
+ struct action_list alist;
+ int ret;
+
+ if (!ctx->scrub_setup_succeeded || ctx->corruptions_found ||
+ ctx->runtime_errors || ctx->unfixable_errors ||
+ ctx->warnings_found)
+ return 0;
+
+ action_list_init(&alist);
+ ret = scrub_clean_health(ctx, &alist);
+ if (ret)
+ return ret;
+
+ /*
+ * Complain if we cannot fail the clean bill of health, unless we're
+ * just testing repairs.
+ */
+ if (action_list_length(&alist) > 0 &&
+ !debug_tweak_on("XFS_SCRUB_FORCE_REPAIR")) {
+ str_info(ctx, _("Couldn't upload clean bill of health."), NULL);
+ action_list_discard(&alist);
+ }
+
+ return 0;
+}
+
/* Clean up the XFS-specific state data. */
int
scrub_cleanup(
@@ -51,6 +85,10 @@ scrub_cleanup(
{
int error;

+ error = report_to_kernel(ctx);
+ if (error)
+ return error;
+
action_lists_free(&ctx->action_lists);
if (ctx->fshandle)
free_handle(ctx->fshandle, ctx->fshandle_len);
diff --git a/scrub/repair.c b/scrub/repair.c
index 3cb7224f7cc..9ade805e1b6 100644
--- a/scrub/repair.c
+++ b/scrub/repair.c
@@ -172,6 +172,21 @@ action_lists_alloc(
return 0;
}

+/* Discard repair list contents. */
+void
+action_list_discard(
+ struct action_list *alist)
+{
+ struct action_item *aitem;
+ struct action_item *n;
+
+ list_for_each_entry_safe(aitem, n, &alist->list, list) {
+ alist->nr--;
+ list_del(&aitem->list);
+ free(aitem);
+ }
+}
+
/* Free the repair lists. */
void
action_lists_free(
diff --git a/scrub/repair.h b/scrub/repair.h
index 486617f1ce4..aa3ea13615f 100644
--- a/scrub/repair.h
+++ b/scrub/repair.h
@@ -24,6 +24,7 @@ static inline bool action_list_empty(const struct action_list *alist)

unsigned long long action_list_length(struct action_list *alist);
void action_list_add(struct action_list *dest, struct action_item *item);
+void action_list_discard(struct action_list *alist);
void action_list_splice(struct action_list *dest, struct action_list *src);

void action_list_find_mustfix(struct action_list *actions,
diff --git a/scrub/scrub.c b/scrub/scrub.c
index cf056779526..7cb94af3d15 100644
--- a/scrub/scrub.c
+++ b/scrub/scrub.c
@@ -444,6 +444,15 @@ scrub_nlinks(
return scrub_meta_type(ctx, XFS_SCRUB_TYPE_NLINKS, 0, alist);
}

+/* Update incore health records if we were clean. */
+int
+scrub_clean_health(
+ struct scrub_ctx *ctx,
+ struct action_list *alist)
+{
+ return scrub_meta_type(ctx, XFS_SCRUB_TYPE_HEALTHY, 0, alist);
+}
+
/* How many items do we have to check? */
unsigned int
scrub_estimate_ag_work(
diff --git a/scrub/scrub.h b/scrub/scrub.h
index 5e3f40bf1f4..cb33ddb46f3 100644
--- a/scrub/scrub.h
+++ b/scrub/scrub.h
@@ -29,6 +29,7 @@ int scrub_summary_metadata(struct scrub_ctx *ctx, struct action_list *alist);
int scrub_fs_counters(struct scrub_ctx *ctx, struct action_list *alist);
int scrub_quotacheck(struct scrub_ctx *ctx, struct action_list *alist);
int scrub_nlinks(struct scrub_ctx *ctx, struct action_list *alist);
+int scrub_clean_health(struct scrub_ctx *ctx, struct action_list *alist);

bool can_scrub_fs_metadata(struct scrub_ctx *ctx);
bool can_scrub_inode(struct scrub_ctx *ctx);