[PATCH 1/5] xfs_scrub: implement live quotacheck inode scan

Darrick J. Wong
2024-06-03T19:23:06Z

Teach xfs_scrub to check quota resource usage counters when checking a
filesystem.

Signed-off-by: Darrick J. Wong <djwong@kernel.org>
Reviewed-by: Christoph Hellwig <hch@lst.de>
---
libfrog/scrub.c | 5 +++++
scrub/phase4.c | 17 +++++++++++++++++
scrub/repair.c | 3 +++
scrub/scrub.c | 9 +++++++++
scrub/scrub.h | 1 +
5 files changed, 35 insertions(+)

diff --git a/libfrog/scrub.c b/libfrog/scrub.c
index 5a5f522a4..53c47bc2b 100644
--- a/libfrog/scrub.c
+++ b/libfrog/scrub.c
@@ -134,6 +134,11 @@ const struct xfrog_scrub_descr xfrog_scrubbers[XFS_SCRUB_TYPE_NR] = {
.descr = "filesystem summary counters",
.group = XFROG_SCRUB_GROUP_SUMMARY,
},
+ [XFS_SCRUB_TYPE_QUOTACHECK] = {
+ .name = "quotacheck",
+ .descr = "quota counters",
+ .group = XFROG_SCRUB_GROUP_ISCAN,
+ },
};

/* Invoke the scrub ioctl. Returns zero or negative error code. */
diff --git a/scrub/phase4.c b/scrub/phase4.c
index 5dfc3856b..8807f147a 100644
--- a/scrub/phase4.c
+++ b/scrub/phase4.c
@@ -128,6 +128,7 @@ int
phase4_func(
struct scrub_ctx *ctx)
{
+ struct xfs_fsop_geom fsgeom;
int ret;

if (!have_action_items(ctx))
@@ -143,6 +144,22 @@ phase4_func(
if (ret)
return ret;

+ /*
+ * Repair possibly bad quota counts before starting other repairs,
+ * because wildly incorrect quota counts can cause shutdowns.
+ * Quotacheck scans all inodes, so we only want to do it if we know
+ * it's sick.
+ */
+ ret = xfrog_geometry(ctx->mnt.fd, &fsgeom);
+ if (ret)
+ return ret;
+
+ if (fsgeom.sick & XFS_FSOP_GEOM_SICK_QUOTACHECK) {
+ ret = scrub_quotacheck(ctx, &ctx->action_lists[0]);
+ if (ret)
+ return ret;
+ }
+
ret = repair_everything(ctx);
if (ret)
return ret;
diff --git a/scrub/repair.c b/scrub/repair.c
index 65b6dd895..3cb7224f7 100644
--- a/scrub/repair.c
+++ b/scrub/repair.c
@@ -84,6 +84,9 @@ xfs_action_item_priority(
case XFS_SCRUB_TYPE_GQUOTA:
case XFS_SCRUB_TYPE_PQUOTA:
return PRIO(aitem, XFS_SCRUB_TYPE_UQUOTA);
+ case XFS_SCRUB_TYPE_QUOTACHECK:
+ /* This should always go after [UGP]QUOTA no matter what. */
+ return PRIO(aitem, aitem->type);
case XFS_SCRUB_TYPE_FSCOUNTERS:
/* This should always go after AG headers no matter what. */
return PRIO(aitem, INT_MAX);
diff --git a/scrub/scrub.c b/scrub/scrub.c
index 023cc2c2c..a22633a81 100644
--- a/scrub/scrub.c
+++ b/scrub/scrub.c
@@ -440,6 +440,15 @@ scrub_fs_counters(
return scrub_meta_type(ctx, XFS_SCRUB_TYPE_FSCOUNTERS, 0, alist);
}

+/* Scrub /only/ the quota counters. */
+int
+scrub_quotacheck(
+ struct scrub_ctx *ctx,
+ struct action_list *alist)
+{
+ return scrub_meta_type(ctx, XFS_SCRUB_TYPE_QUOTACHECK, 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 0033fe7ed..927f86de9 100644
--- a/scrub/scrub.h
+++ b/scrub/scrub.h
@@ -27,6 +27,7 @@ int scrub_fs_metadata(struct scrub_ctx *ctx, unsigned int scrub_type,
int scrub_iscan_metadata(struct scrub_ctx *ctx, struct action_list *alist);
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);

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