@@ -184,6 +184,7 @@ parse_args(
case XFROG_SCRUB_GROUP_FS:
case XFROG_SCRUB_GROUP_NONE:
case XFROG_SCRUB_GROUP_SUMMARY:
+ case XFROG_SCRUB_GROUP_ISCAN:
if (!parse_none(argc, optind)) {
exitcode = 1;
return command_usage(cmdinfo);
@@ -13,6 +13,7 @@ enum xfrog_scrub_group {
XFROG_SCRUB_GROUP_PERAG, /* per-AG metadata */
XFROG_SCRUB_GROUP_FS, /* per-FS metadata */
XFROG_SCRUB_GROUP_INODE, /* per-inode metadata */
+ XFROG_SCRUB_GROUP_ISCAN, /* metadata requiring full inode scan */
XFROG_SCRUB_GROUP_SUMMARY, /* summary metadata */
};
@@ -16,6 +16,8 @@
#include "list.h"
#include "libfrog/paths.h"
#include "libfrog/workqueue.h"
+#include "libfrog/fsgeom.h"
+#include "libfrog/scrub.h"
#include "xfs_scrub.h"
#include "common.h"
#include "inodes.h"
@@ -23,8 +25,9 @@
#include "scrub.h"
#include "descr.h"
#include "unicrash.h"
+#include "repair.h"
-/* Phase 5: Check directory connectivity. */
+/* Phase 5: Full inode scans and check directory connectivity. */
/*
* Warn about problematic bytes in a directory/attribute name. That means
@@ -386,9 +389,24 @@ int
phase5_func(
struct scrub_ctx *ctx)
{
+ struct action_list alist;
bool aborted = false;
int ret;
+ /*
+ * Check and fix anything that requires a full inode scan. We do this
+ * after we've checked all inodes and repaired anything that could get
+ * in the way of a scan.
+ */
+ action_list_init(&alist);
+ ret = scrub_iscan_metadata(ctx, &alist);
+ if (ret)
+ return ret;
+ ret = action_list_process(ctx, ctx->mnt.fd, &alist,
+ ALP_COMPLAIN_IF_UNFIXED | ALP_NOPROGRESS);
+ if (ret)
+ return ret;
+
if (ctx->corruptions_found || ctx->unfixable_errors) {
str_info(ctx, ctx->mntpoint,
_("Filesystem has errors, skipping connectivity checks."));
@@ -417,7 +435,7 @@ phase5_estimate(
unsigned int *nr_threads,
int *rshift)
{
- *items = ctx->mnt_sv.f_files - ctx->mnt_sv.f_ffree;
+ *items = scrub_estimate_iscan_work(ctx);
*nr_threads = scrub_nproc(ctx);
*rshift = 0;
return 0;
@@ -47,6 +47,7 @@ format_scrub_descr(
break;
case XFROG_SCRUB_GROUP_FS:
case XFROG_SCRUB_GROUP_SUMMARY:
+ case XFROG_SCRUB_GROUP_ISCAN:
return snprintf(buf, buflen, _("%s"), _(sc->descr));
break;
case XFROG_SCRUB_GROUP_NONE:
@@ -421,6 +422,15 @@ scrub_summary_metadata(
return scrub_group(ctx, XFROG_SCRUB_GROUP_SUMMARY, 0, alist);
}
+/* Scrub all metadata requiring a full inode scan. */
+int
+scrub_iscan_metadata(
+ struct scrub_ctx *ctx,
+ struct action_list *alist)
+{
+ return scrub_group(ctx, XFROG_SCRUB_GROUP_ISCAN, 0, alist);
+}
+
/* Scrub /only/ the superblock summary counters. */
int
scrub_fs_counters(
@@ -456,6 +466,29 @@ scrub_estimate_ag_work(
return estimate;
}
+/*
+ * How many kernel calls will we make to scrub everything requiring a full
+ * inode scan?
+ */
+unsigned int
+scrub_estimate_iscan_work(
+ struct scrub_ctx *ctx)
+{
+ const struct xfrog_scrub_descr *sc;
+ int type;
+ unsigned int estimate;
+
+ estimate = ctx->mnt_sv.f_files - ctx->mnt_sv.f_ffree;
+
+ sc = xfrog_scrubbers;
+ for (type = 0; type < XFS_SCRUB_TYPE_NR; type++, sc++) {
+ if (sc->group == XFROG_SCRUB_GROUP_ISCAN)
+ estimate++;
+ }
+
+ return estimate;
+}
+
/*
* Scrub file metadata of some sort. If errors occur, this function will log
* them and return nonzero.
@@ -24,6 +24,7 @@ int scrub_ag_metadata(struct scrub_ctx *ctx, xfs_agnumber_t agno,
struct action_list *alist);
int scrub_fs_metadata(struct scrub_ctx *ctx, unsigned int scrub_type,
struct action_list *alist);
+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);
@@ -99,6 +99,7 @@ int phase7_func(struct scrub_ctx *ctx);
/* Progress estimator functions */
unsigned int scrub_estimate_ag_work(struct scrub_ctx *ctx);
+unsigned int scrub_estimate_iscan_work(struct scrub_ctx *ctx);
int phase2_estimate(struct scrub_ctx *ctx, uint64_t *items,
unsigned int *nr_threads, int *rshift);
int phase3_estimate(struct scrub_ctx *ctx, uint64_t *items,