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
];
39 action_list_init(&alist
);
40 action_list_init(&immediate_alist
);
41 snprintf(descr
, DESCR_BUFSZ
, _("AG %u"), agno
);
44 * First we scrub and fix the AG headers, because we need
45 * them to work well enough to check the AG btrees.
47 ret
= xfs_scrub_ag_headers(ctx
, agno
, &alist
);
51 /* Repair header damage. */
52 ret
= action_list_process_or_defer(ctx
, agno
, &alist
);
56 /* Now scrub the AG btrees. */
57 ret
= xfs_scrub_ag_metadata(ctx
, agno
, &alist
);
62 * Figure out if we need to perform early fixing. The only
63 * reason we need to do this is if the inobt is broken, which
64 * prevents phase 3 (inode scan) from running. We can rebuild
65 * the inobt from rmapbt data, but if the rmapbt is broken even
66 * at this early phase then we are sunk.
68 broken_secondaries
= 0;
70 action_list_find_mustfix(&alist
, &immediate_alist
,
71 &broken_primaries
, &broken_secondaries
);
72 if (broken_secondaries
&& !debug_tweak_on("XFS_SCRUB_FORCE_REPAIR")) {
75 _("Corrupt primary and secondary block mapping metadata."));
78 _("Corrupt secondary block mapping metadata."));
80 _("Filesystem might not be repairable."));
83 /* Repair (inode) btree damage. */
84 ret
= action_list_process_or_defer(ctx
, agno
, &immediate_alist
);
88 /* Everything else gets fixed during phase 4. */
89 action_list_defer(ctx
, agno
, &alist
);
95 /* Scrub whole-FS metadata btrees. */
102 struct scrub_ctx
*ctx
= (struct scrub_ctx
*)wq
->wq_ctx
;
104 struct action_list alist
;
110 action_list_init(&alist
);
111 ret
= xfs_scrub_fs_metadata(ctx
, &alist
);
117 action_list_defer(ctx
, agno
, &alist
);
120 /* Scan all filesystem metadata. */
123 struct scrub_ctx
*ctx
)
125 struct action_list alist
;
128 bool aborted
= false;
131 ret
= workqueue_create(&wq
, (struct xfs_mount
*)ctx
,
132 scrub_nproc_workqueue(ctx
));
134 str_liberror(ctx
, ret
, _("creating scrub workqueue"));
139 * In case we ever use the primary super scrubber to perform fs
140 * upgrades (followed by a full scrub), do that before we launch
143 action_list_init(&alist
);
144 ret
= xfs_scrub_primary_super(ctx
, &alist
);
147 ret
= action_list_process_or_defer(ctx
, 0, &alist
);
151 for (agno
= 0; !aborted
&& agno
< ctx
->mnt
.fsgeom
.agcount
; agno
++) {
152 ret
= workqueue_add(&wq
, scan_ag_metadata
, agno
, &aborted
);
154 str_liberror(ctx
, ret
, _("queueing per-AG scrub work"));
162 ret
= workqueue_add(&wq
, scan_fs_metadata
, 0, &aborted
);
164 str_liberror(ctx
, ret
, _("queueing per-FS scrub work"));
169 ret2
= workqueue_terminate(&wq
);
171 str_liberror(ctx
, ret2
, _("finishing scrub work"));
175 workqueue_destroy(&wq
);
182 /* Estimate how much work we're going to do. */
185 struct scrub_ctx
*ctx
,
187 unsigned int *nr_threads
,
190 *items
= scrub_estimate_ag_work(ctx
);
191 *nr_threads
= scrub_nproc(ctx
);