@@ -745,6 +745,87 @@ run_kernel_fs_scan_scrubbers(
return ret;
}
+/* Queue one metapath scrubber. */
+static int
+queue_metapath_scan(
+ struct workqueue *wq,
+ bool *abortedp,
+ uint64_t type)
+{
+ struct fs_scan_item *item;
+ struct scrub_ctx *ctx = wq->wq_ctx;
+ int ret;
+
+ item = malloc(sizeof(struct fs_scan_item));
+ if (!item) {
+ ret = ENOMEM;
+ str_liberror(ctx, ret, _("setting up metapath scan"));
+ return ret;
+ }
+ scrub_item_init_metapath(&item->sri, type);
+ scrub_item_schedule(&item->sri, XFS_SCRUB_TYPE_METAPATH);
+ item->abortedp = abortedp;
+
+ ret = -workqueue_add(wq, fs_scan_worker, 0, item);
+ if (ret)
+ str_liberror(ctx, ret, _("queuing metapath scan work"));
+
+ return ret;
+}
+
+/*
+ * Scrub metadata directory file paths to ensure that fs metadata are still
+ * connected where the fs needs to find them.
+ */
+static int
+run_kernel_metadir_path_scrubbers(
+ struct scrub_ctx *ctx)
+{
+ struct workqueue wq;
+ const struct xfrog_scrub_descr *sc;
+ uint64_t type;
+ unsigned int nr_threads = scrub_nproc_workqueue(ctx);
+ bool aborted = false;
+ int ret, ret2;
+
+ ret = -workqueue_create(&wq, (struct xfs_mount *)ctx, nr_threads);
+ if (ret) {
+ str_liberror(ctx, ret, _("setting up metapath scan workqueue"));
+ return ret;
+ }
+
+ /*
+ * Scan all the metadata files in parallel if metadata directories
+ * are enabled, because the phase 3 scrubbers might have taken out
+ * parts of the metadir tree.
+ */
+ for (type = 0; type < XFS_SCRUB_METAPATH_NR; type++) {
+ sc = &xfrog_metapaths[type];
+ if (sc->group != XFROG_SCRUB_GROUP_FS)
+ continue;
+
+ ret = queue_metapath_scan(&wq, &aborted, type);
+ if (ret) {
+ str_liberror(ctx, ret,
+ _("queueing metapath scrub work"));
+ goto wait;
+ }
+ }
+
+wait:
+ ret2 = -workqueue_terminate(&wq);
+ if (ret2) {
+ str_liberror(ctx, ret2, _("joining metapath scan workqueue"));
+ if (!ret)
+ ret = ret2;
+ }
+ if (aborted && !ret)
+ ret = ECANCELED;
+
+ workqueue_destroy(&wq);
+ return ret;
+}
+
/* Check directory connectivity. */
int
phase5_func(
@@ -753,6 +834,16 @@ phase5_func(
struct ncheck_state ncs = { .ctx = ctx };
int ret;
+ /*
+ * Make sure metadata files are still connected to the metadata
+ * directory tree now that phase 3 pruned all corrupt directory tree
+ * links.
+ */
+ if (ctx->mnt.fsgeom.flags & XFS_FSOP_GEOM_FLAGS_METADIR) {
+ ret = run_kernel_metadir_path_scrubbers(ctx);
+ if (ret)
+ return ret;
+ }
/*
* Check and fix anything that requires a full filesystem scan. We do
@@ -805,8 +896,12 @@ phase5_estimate(
unsigned int *nr_threads,
int *rshift)
{
+ unsigned int scans = 2;
+
*items = scrub_estimate_iscan_work(ctx);
- *nr_threads = scrub_nproc(ctx) * 2;
+ if (ctx->mnt.fsgeom.flags & XFS_FSOP_GEOM_FLAGS_METADIR)
+ scans++;
+ *nr_threads = scrub_nproc(ctx) * scans;
*rshift = 0;
return 0;
}
@@ -108,6 +108,13 @@ scrub_item_init_file(struct scrub_item *sri, const struct xfs_bulkstat *bstat)
sri->sri_gen = bstat->bs_gen;
}
+static inline void
+scrub_item_init_metapath(struct scrub_item *sri, uint64_t metapath)
+{
+ memset(sri, 0, sizeof(*sri));
+ sri->sri_ino = metapath;
+}
+
void scrub_item_dump(struct scrub_item *sri, unsigned int group_mask,
const char *tag);