From: Darrick J. Wong <djwong@xxxxxxxxxx> Teach xfs_scrub to check quota resource usage counters when checking a filesystem. Signed-off-by: Darrick J. Wong <djwong@xxxxxxxxxx> Reviewed-by: Christoph Hellwig <hch@xxxxxx> --- 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);