From: Darrick J. Wong <djwong@xxxxxxxxxx> For metadata files on a metadir filesystem, re-run the scrubbers during phase 5 to ensure that the metadata files are still connected. Signed-off-by: "Darrick J. Wong" <djwong@xxxxxxxxxx> Reviewed-by: Christoph Hellwig <hch@xxxxxx> --- scrub/phase5.c | 97 +++++++++++++++++++++++++++++++++++++++++++++++++++++++- scrub/scrub.h | 7 ++++ 2 files changed, 103 insertions(+), 1 deletion(-) diff --git a/scrub/phase5.c b/scrub/phase5.c index 69b1cae5c5e2c0..4d0a76a529b55d 100644 --- a/scrub/phase5.c +++ b/scrub/phase5.c @@ -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; } diff --git a/scrub/scrub.h b/scrub/scrub.h index c3eed1b261d511..3bb3ea1d07bf40 100644 --- a/scrub/scrub.h +++ b/scrub/scrub.h @@ -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);