1 // SPDX-License-Identifier: GPL-2.0+
3 * Copyright (C) 2018 Oracle. All Rights Reserved.
4 * Author: Darrick J. Wong <darrick.wong@oracle.com>
9 #include <sys/statvfs.h>
11 #include "libfrog/paths.h"
12 #include "libfrog/workqueue.h"
13 #include "xfs_scrub.h"
18 /* Phase 2: Check internal metadata. */
20 /* Scrub each AG's metadata btrees. */
27 struct scrub_ctx
*ctx
= (struct scrub_ctx
*)wq
->wq_ctx
;
29 struct action_list alist
;
30 struct action_list immediate_alist
;
31 unsigned long long broken_primaries
;
32 unsigned long long broken_secondaries
;
33 char descr
[DESCR_BUFSZ
];
36 action_list_init(&alist
);
37 action_list_init(&immediate_alist
);
38 snprintf(descr
, DESCR_BUFSZ
, _("AG %u"), agno
);
41 * First we scrub and fix the AG headers, because we need
42 * them to work well enough to check the AG btrees.
44 ret
= xfs_scrub_ag_headers(ctx
, agno
, &alist
);
48 /* Repair header damage. */
49 ret
= action_list_process_or_defer(ctx
, agno
, &alist
);
53 /* Now scrub the AG btrees. */
54 ret
= xfs_scrub_ag_metadata(ctx
, agno
, &alist
);
59 * Figure out if we need to perform early fixing. The only
60 * reason we need to do this is if the inobt is broken, which
61 * prevents phase 3 (inode scan) from running. We can rebuild
62 * the inobt from rmapbt data, but if the rmapbt is broken even
63 * at this early phase then we are sunk.
65 broken_secondaries
= 0;
67 action_list_find_mustfix(&alist
, &immediate_alist
,
68 &broken_primaries
, &broken_secondaries
);
69 if (broken_secondaries
&& !debug_tweak_on("XFS_SCRUB_FORCE_REPAIR")) {
72 _("Corrupt primary and secondary block mapping metadata."));
75 _("Corrupt secondary block mapping metadata."));
77 _("Filesystem might not be repairable."));
80 /* Repair (inode) btree damage. */
81 ret
= action_list_process_or_defer(ctx
, agno
, &immediate_alist
);
85 /* Everything else gets fixed during phase 4. */
86 action_list_defer(ctx
, agno
, &alist
);
93 /* Scrub whole-FS metadata btrees. */
100 struct scrub_ctx
*ctx
= (struct scrub_ctx
*)wq
->wq_ctx
;
102 struct action_list alist
;
105 action_list_init(&alist
);
106 ret
= xfs_scrub_fs_metadata(ctx
, &alist
);
110 action_list_defer(ctx
, agno
, &alist
);
113 /* Scan all filesystem metadata. */
116 struct scrub_ctx
*ctx
)
118 struct action_list alist
;
124 ret
= workqueue_create(&wq
, (struct xfs_mount
*)ctx
,
125 scrub_nproc_workqueue(ctx
));
127 str_liberror(ctx
, ret
, _("creating scrub workqueue"));
132 * In case we ever use the primary super scrubber to perform fs
133 * upgrades (followed by a full scrub), do that before we launch
136 action_list_init(&alist
);
137 ret
= xfs_scrub_primary_super(ctx
, &alist
);
142 ret
= action_list_process_or_defer(ctx
, 0, &alist
);
148 for (agno
= 0; moveon
&& agno
< ctx
->mnt
.fsgeom
.agcount
; agno
++) {
149 ret
= workqueue_add(&wq
, xfs_scan_ag_metadata
, agno
, &moveon
);
152 str_liberror(ctx
, ret
, _("queueing per-AG scrub work"));
160 ret
= workqueue_add(&wq
, xfs_scan_fs_metadata
, 0, &moveon
);
163 str_liberror(ctx
, ret
, _("queueing per-FS scrub work"));
168 ret
= workqueue_terminate(&wq
);
171 str_liberror(ctx
, ret
, _("finishing scrub work"));
173 workqueue_destroy(&wq
);
177 /* Estimate how much work we're going to do. */
179 xfs_estimate_metadata_work(
180 struct scrub_ctx
*ctx
,
182 unsigned int *nr_threads
,
185 *items
= scrub_estimate_ag_work(ctx
);
186 *nr_threads
= scrub_nproc(ctx
);