@@ -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. */
@@ -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;
@@ -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);
@@ -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(
@@ -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);