From: Darrick J. Wong <djwong@xxxxxxxxxx> Start using the scrub_item to track which metadata objects need checking by adding a new flag to the scrub_item state set. Signed-off-by: Darrick J. Wong <djwong@xxxxxxxxxx> Reviewed-by: Christoph Hellwig <hch@xxxxxx> --- scrub/phase1.c | 3 + scrub/phase2.c | 12 +++-- scrub/phase3.c | 41 +++++----------- scrub/phase4.c | 16 +++--- scrub/phase5.c | 5 +- scrub/phase7.c | 5 ++ scrub/scrub.c | 147 +++++++++++++++++++------------------------------------- scrub/scrub.h | 28 ++++++++--- 8 files changed, 108 insertions(+), 149 deletions(-) diff --git a/scrub/phase1.c b/scrub/phase1.c index 1e56f9fb1..60a8db572 100644 --- a/scrub/phase1.c +++ b/scrub/phase1.c @@ -61,7 +61,8 @@ report_to_kernel( return 0; scrub_item_init_fs(&sri); - ret = scrub_meta_type(ctx, XFS_SCRUB_TYPE_HEALTHY, &sri); + scrub_item_schedule(&sri, XFS_SCRUB_TYPE_HEALTHY); + ret = scrub_item_check(ctx, &sri); if (ret) return ret; diff --git a/scrub/phase2.c b/scrub/phase2.c index 4d90291ed..79b33dd04 100644 --- a/scrub/phase2.c +++ b/scrub/phase2.c @@ -75,7 +75,8 @@ scan_ag_metadata( * First we scrub and fix the AG headers, because we need * them to work well enough to check the AG btrees. */ - ret = scrub_ag_headers(ctx, &sri); + scrub_item_schedule_group(&sri, XFROG_SCRUB_GROUP_AGHEADER); + ret = scrub_item_check(ctx, &sri); if (ret) goto err; @@ -85,7 +86,8 @@ scan_ag_metadata( goto err; /* Now scrub the AG btrees. */ - ret = scrub_ag_metadata(ctx, &sri); + scrub_item_schedule_group(&sri, XFROG_SCRUB_GROUP_PERAG); + ret = scrub_item_check(ctx, &sri); if (ret) goto err; @@ -131,7 +133,8 @@ scan_fs_metadata( goto out; scrub_item_init_fs(&sri); - ret = scrub_meta_type(ctx, type, &sri); + scrub_item_schedule(&sri, type); + ret = scrub_item_check(ctx, &sri); if (ret) { sctl->aborted = true; goto out; @@ -189,7 +192,8 @@ phase2_func( * If errors occur, this function will log them and return nonzero. */ scrub_item_init_ag(&sri, 0); - ret = scrub_meta_type(ctx, XFS_SCRUB_TYPE_SB, &sri); + scrub_item_schedule(&sri, XFS_SCRUB_TYPE_SB); + ret = scrub_item_check(ctx, &sri); if (ret) goto out_wq; ret = repair_item_completely(ctx, &sri); diff --git a/scrub/phase3.c b/scrub/phase3.c index fa2eef4de..09347c977 100644 --- a/scrub/phase3.c +++ b/scrub/phase3.c @@ -144,7 +144,8 @@ scrub_inode( fd = scrub_open_handle(handle); /* Scrub the inode. */ - error = scrub_file(ctx, fd, bstat, XFS_SCRUB_TYPE_INODE, &sri); + scrub_item_schedule(&sri, XFS_SCRUB_TYPE_INODE); + error = scrub_item_check_file(ctx, &sri, fd); if (error) goto out; @@ -153,13 +154,10 @@ scrub_inode( goto out; /* Scrub all block mappings. */ - error = scrub_file(ctx, fd, bstat, XFS_SCRUB_TYPE_BMBTD, &sri); - if (error) - goto out; - error = scrub_file(ctx, fd, bstat, XFS_SCRUB_TYPE_BMBTA, &sri); - if (error) - goto out; - error = scrub_file(ctx, fd, bstat, XFS_SCRUB_TYPE_BMBTC, &sri); + scrub_item_schedule(&sri, XFS_SCRUB_TYPE_BMBTD); + scrub_item_schedule(&sri, XFS_SCRUB_TYPE_BMBTA); + scrub_item_schedule(&sri, XFS_SCRUB_TYPE_BMBTC); + error = scrub_item_check_file(ctx, &sri, fd); if (error) goto out; @@ -177,27 +175,14 @@ scrub_inode( * content scrubbers. Better to have them return -ENOENT than miss * some coverage. */ - if (S_ISLNK(bstat->bs_mode) || !bstat->bs_mode) { - /* Check symlink contents. */ - error = scrub_file(ctx, fd, bstat, XFS_SCRUB_TYPE_SYMLINK, - &sri); - if (error) - goto out; - } - if (S_ISDIR(bstat->bs_mode) || !bstat->bs_mode) { - /* Check the directory entries. */ - error = scrub_file(ctx, fd, bstat, XFS_SCRUB_TYPE_DIR, &sri); - if (error) - goto out; - } + if (S_ISLNK(bstat->bs_mode) || !bstat->bs_mode) + scrub_item_schedule(&sri, XFS_SCRUB_TYPE_SYMLINK); + if (S_ISDIR(bstat->bs_mode) || !bstat->bs_mode) + scrub_item_schedule(&sri, XFS_SCRUB_TYPE_DIR); - /* Check all the extended attributes. */ - error = scrub_file(ctx, fd, bstat, XFS_SCRUB_TYPE_XATTR, &sri); - if (error) - goto out; - - /* Check parent pointers. */ - error = scrub_file(ctx, fd, bstat, XFS_SCRUB_TYPE_PARENT, &sri); + scrub_item_schedule(&sri, XFS_SCRUB_TYPE_XATTR); + scrub_item_schedule(&sri, XFS_SCRUB_TYPE_PARENT); + error = scrub_item_check_file(ctx, &sri, fd); if (error) goto out; diff --git a/scrub/phase4.c b/scrub/phase4.c index 230c559f0..3c51b38a5 100644 --- a/scrub/phase4.c +++ b/scrub/phase4.c @@ -143,9 +143,7 @@ phase4_func( * metadata. If repairs fails, we'll come back during phase 7. */ scrub_item_init_fs(&sri); - ret = scrub_meta_type(ctx, XFS_SCRUB_TYPE_FSCOUNTERS, &sri); - if (ret) - return ret; + scrub_item_schedule(&sri, XFS_SCRUB_TYPE_FSCOUNTERS); /* * Repair possibly bad quota counts before starting other repairs, @@ -157,13 +155,13 @@ phase4_func( if (ret) return ret; - if (fsgeom.sick & XFS_FSOP_GEOM_SICK_QUOTACHECK) { - ret = scrub_meta_type(ctx, XFS_SCRUB_TYPE_QUOTACHECK, &sri); - if (ret) - return ret; - } + if (fsgeom.sick & XFS_FSOP_GEOM_SICK_QUOTACHECK) + scrub_item_schedule(&sri, XFS_SCRUB_TYPE_QUOTACHECK); - /* Repair counters before starting on the rest. */ + /* Check and repair counters before starting on the rest. */ + ret = scrub_item_check(ctx, &sri); + if (ret) + return ret; ret = repair_item_corruption(ctx, &sri); if (ret) return ret; diff --git a/scrub/phase5.c b/scrub/phase5.c index 6c9a518db..0df8c46e9 100644 --- a/scrub/phase5.c +++ b/scrub/phase5.c @@ -387,7 +387,6 @@ check_fs_label( struct fs_scan_item { struct scrub_item sri; bool *abortedp; - unsigned int scrub_type; }; /* Run one full-fs scan scrubber in this thread. */ @@ -412,7 +411,7 @@ fs_scan_worker( nanosleep(&tv, NULL); } - ret = scrub_meta_type(ctx, item->scrub_type, &item->sri); + ret = scrub_item_check(ctx, &item->sri); if (ret) { str_liberror(ctx, ret, _("checking fs scan metadata")); *item->abortedp = true; @@ -450,7 +449,7 @@ queue_fs_scan( return ret; } scrub_item_init_fs(&item->sri); - item->scrub_type = scrub_type; + scrub_item_schedule(&item->sri, scrub_type); item->abortedp = abortedp; ret = -workqueue_add(wq, fs_scan_worker, nr, item); diff --git a/scrub/phase7.c b/scrub/phase7.c index 02da6b42b..cd4501f72 100644 --- a/scrub/phase7.c +++ b/scrub/phase7.c @@ -10,6 +10,8 @@ #include <linux/fsmap.h> #include "libfrog/paths.h" #include "libfrog/ptvar.h" +#include "libfrog/fsgeom.h" +#include "libfrog/scrub.h" #include "list.h" #include "xfs_scrub.h" #include "common.h" @@ -118,7 +120,8 @@ phase7_func( /* Check and fix the summary metadata. */ scrub_item_init_fs(&sri); - error = scrub_summary_metadata(ctx, &sri); + scrub_item_schedule_group(&sri, XFROG_SCRUB_GROUP_SUMMARY); + error = scrub_item_check(ctx, &sri); if (error) return error; error = repair_item_completely(ctx, &sri); diff --git a/scrub/scrub.c b/scrub/scrub.c index 5fc549f97..5aa36a964 100644 --- a/scrub/scrub.c +++ b/scrub/scrub.c @@ -86,9 +86,11 @@ xfs_check_metadata( bool is_inode) { DEFINE_DESCR(dsc, ctx, format_scrub_descr); + enum xfrog_scrub_group group; unsigned int tries = 0; int error; + group = xfrog_scrubbers[meta->sm_type].group; assert(!debug_tweak_on("XFS_SCRUB_NO_KERNEL")); assert(meta->sm_type < XFS_SCRUB_TYPE_NR); descr_set(&dsc, meta); @@ -165,7 +167,7 @@ _("Repairs are required.")); */ if (is_unoptimized(meta)) { if (ctx->mode != SCRUB_MODE_REPAIR) { - if (!is_inode) { + if (group != XFROG_SCRUB_GROUP_INODE) { /* AG or FS metadata, always warn. */ str_info(ctx, descr_render(&dsc), _("Optimization is possible.")); @@ -223,9 +225,10 @@ _("Optimizations of %s are possible."), _(xfrog_scrubbers[i].descr)); * Returns 0 for success. If errors occur, this function will log them and * return a positive error code. */ -int +static int scrub_meta_type( struct scrub_ctx *ctx, + struct xfs_fd *xfdp, unsigned int type, struct scrub_item *sri) { @@ -243,16 +246,20 @@ scrub_meta_type( break; case XFROG_SCRUB_GROUP_FS: case XFROG_SCRUB_GROUP_SUMMARY: + case XFROG_SCRUB_GROUP_ISCAN: case XFROG_SCRUB_GROUP_NONE: break; - default: - assert(0); + case XFROG_SCRUB_GROUP_INODE: + meta.sm_ino = sri->sri_ino; + meta.sm_gen = sri->sri_gen; break; } /* Check the item. */ - fix = xfs_check_metadata(ctx, &ctx->mnt, &meta, false); - progress_add(1); + fix = xfs_check_metadata(ctx, xfdp, &meta, false); + + if (xfrog_scrubbers[type].group != XFROG_SCRUB_GROUP_INODE) + progress_add(1); switch (fix) { case CHECK_ABORT: @@ -269,60 +276,54 @@ scrub_meta_type( } } -/* - * Scrub all metadata types that are assigned to the given XFROG_SCRUB_GROUP_*, - * saving corruption reports for later. This should not be used for - * XFROG_SCRUB_GROUP_INODE or for checking summary metadata. - */ -static bool -scrub_group( - struct scrub_ctx *ctx, - enum xfrog_scrub_group group, - struct scrub_item *sri) +/* Schedule scrub for all metadata of a given group. */ +void +scrub_item_schedule_group( + struct scrub_item *sri, + enum xfrog_scrub_group group) { - const struct xfrog_scrub_descr *sc; - unsigned int type; - - sc = xfrog_scrubbers; - for (type = 0; type < XFS_SCRUB_TYPE_NR; type++, sc++) { - int ret; + unsigned int scrub_type; - if (sc->group != group) + foreach_scrub_type(scrub_type) { + if (xfrog_scrubbers[scrub_type].group != group) continue; - - ret = scrub_meta_type(ctx, type, sri); - if (ret) - return ret; + scrub_item_schedule(sri, scrub_type); } - - return 0; } -/* Scrub each AG's header blocks. */ +/* Run all the incomplete scans on this scrub principal. */ int -scrub_ag_headers( +scrub_item_check_file( struct scrub_ctx *ctx, - struct scrub_item *sri) + struct scrub_item *sri, + int override_fd) { - return scrub_group(ctx, XFROG_SCRUB_GROUP_AGHEADER, sri); -} + struct xfs_fd xfd; + struct xfs_fd *xfdp = &ctx->mnt; + unsigned int scrub_type; + int error; -/* Scrub each AG's metadata btrees. */ -int -scrub_ag_metadata( - struct scrub_ctx *ctx, - struct scrub_item *sri) -{ - return scrub_group(ctx, XFROG_SCRUB_GROUP_PERAG, sri); -} + /* + * If the caller passed us a file descriptor for a scrub, use it + * instead of scrub-by-handle because this enables the kernel to skip + * costly inode btree lookups. + */ + if (override_fd >= 0) { + memcpy(&xfd, xfdp, sizeof(xfd)); + xfd.fd = override_fd; + xfdp = &xfd; + } -/* Scrub all FS summary metadata. */ -int -scrub_summary_metadata( - struct scrub_ctx *ctx, - struct scrub_item *sri) -{ - return scrub_group(ctx, XFROG_SCRUB_GROUP_SUMMARY, sri); + foreach_scrub_type(scrub_type) { + if (!(sri->sri_state[scrub_type] & SCRUB_ITEM_NEEDSCHECK)) + continue; + + error = scrub_meta_type(ctx, xfdp, scrub_type, sri); + if (error) + break; + } + + return error; } /* How many items do we have to check? */ @@ -374,54 +375,6 @@ scrub_estimate_iscan_work( return estimate; } -/* - * Scrub file metadata of some sort. If errors occur, this function will log - * them and return nonzero. - */ -int -scrub_file( - struct scrub_ctx *ctx, - int fd, - const struct xfs_bulkstat *bstat, - unsigned int type, - struct scrub_item *sri) -{ - struct xfs_scrub_metadata meta = {0}; - struct xfs_fd xfd; - struct xfs_fd *xfdp = &ctx->mnt; - enum check_outcome fix; - - assert(type < XFS_SCRUB_TYPE_NR); - assert(xfrog_scrubbers[type].group == XFROG_SCRUB_GROUP_INODE); - - meta.sm_type = type; - meta.sm_ino = bstat->bs_ino; - meta.sm_gen = bstat->bs_gen; - - /* - * If the caller passed us a file descriptor for a scrub, use it - * instead of scrub-by-handle because this enables the kernel to skip - * costly inode btree lookups. - */ - if (fd >= 0) { - memcpy(&xfd, xfdp, sizeof(xfd)); - xfd.fd = fd; - xfdp = &xfd; - } - - /* Scrub the piece of metadata. */ - fix = xfs_check_metadata(ctx, xfdp, &meta, true); - if (fix == CHECK_ABORT) - return ECANCELED; - if (fix == CHECK_DONE) { - scrub_item_clean_state(sri, type); - return 0; - } - - scrub_item_save_state(sri, type, meta.sm_flags); - return 0; -} - /* Dump a scrub item for debugging purposes. */ void scrub_item_dump( diff --git a/scrub/scrub.h b/scrub/scrub.h index 3ae0bfd29..1ac0d8aed 100644 --- a/scrub/scrub.h +++ b/scrub/scrub.h @@ -6,6 +6,8 @@ #ifndef XFS_SCRUB_SCRUB_H_ #define XFS_SCRUB_SCRUB_H_ +enum xfrog_scrub_group; + /* Online scrub and repair. */ enum check_outcome { CHECK_DONE, /* no further processing needed */ @@ -33,6 +35,9 @@ enum check_outcome { #define SCRUB_ITEM_XFAIL (XFS_SCRUB_OFLAG_XFAIL) /* (1 << 3) */ #define SCRUB_ITEM_XCORRUPT (XFS_SCRUB_OFLAG_XCORRUPT) /* (1 << 4) */ +/* This scrub type needs to be checked. */ +#define SCRUB_ITEM_NEEDSCHECK (1 << 5) + /* All of the state flags that we need to prioritize repair work. */ #define SCRUB_ITEM_REPAIR_ANY (SCRUB_ITEM_CORRUPT | \ SCRUB_ITEM_PREEN | \ @@ -96,13 +101,24 @@ scrub_item_init_file(struct scrub_item *sri, const struct xfs_bulkstat *bstat) void scrub_item_dump(struct scrub_item *sri, unsigned int group_mask, const char *tag); +static inline void +scrub_item_schedule(struct scrub_item *sri, unsigned int scrub_type) +{ + sri->sri_state[scrub_type] = SCRUB_ITEM_NEEDSCHECK; +} + +void scrub_item_schedule_group(struct scrub_item *sri, + enum xfrog_scrub_group group); +int scrub_item_check_file(struct scrub_ctx *ctx, struct scrub_item *sri, + int override_fd); + +static inline int +scrub_item_check(struct scrub_ctx *ctx, struct scrub_item *sri) +{ + return scrub_item_check_file(ctx, sri, -1); +} + void scrub_report_preen_triggers(struct scrub_ctx *ctx); -int scrub_ag_headers(struct scrub_ctx *ctx, struct scrub_item *sri); -int scrub_ag_metadata(struct scrub_ctx *ctx, struct scrub_item *sri); -int scrub_iscan_metadata(struct scrub_ctx *ctx, struct scrub_item *sri); -int scrub_summary_metadata(struct scrub_ctx *ctx, struct scrub_item *sri); -int scrub_meta_type(struct scrub_ctx *ctx, unsigned int type, - struct scrub_item *sri); bool can_scrub_fs_metadata(struct scrub_ctx *ctx); bool can_scrub_inode(struct scrub_ctx *ctx);