]>
Commit | Line | Data |
---|---|---|
959ef981 | 1 | // SPDX-License-Identifier: GPL-2.0+ |
e758ad01 DW |
2 | /* |
3 | * Copyright (C) 2018 Oracle. All Rights Reserved. | |
e758ad01 | 4 | * Author: Darrick J. Wong <darrick.wong@oracle.com> |
e758ad01 | 5 | */ |
a440f877 | 6 | #include "xfs.h" |
e758ad01 | 7 | #include <stdint.h> |
e758ad01 | 8 | #include <sys/types.h> |
e758ad01 | 9 | #include <sys/statvfs.h> |
19852474 | 10 | #include "list.h" |
e758ad01 DW |
11 | #include "path.h" |
12 | #include "workqueue.h" | |
13 | #include "xfs_scrub.h" | |
14 | #include "common.h" | |
15 | #include "scrub.h" | |
ee310b0c | 16 | #include "repair.h" |
e758ad01 DW |
17 | |
18 | /* Phase 2: Check internal metadata. */ | |
19 | ||
20 | /* Scrub each AG's metadata btrees. */ | |
21 | static void | |
22 | xfs_scan_ag_metadata( | |
23 | struct workqueue *wq, | |
24 | xfs_agnumber_t agno, | |
25 | void *arg) | |
26 | { | |
27 | struct scrub_ctx *ctx = (struct scrub_ctx *)wq->wq_ctx; | |
28 | bool *pmoveon = arg; | |
ee310b0c DW |
29 | struct xfs_action_list alist; |
30 | struct xfs_action_list immediate_alist; | |
31 | unsigned long long broken_primaries; | |
32 | unsigned long long broken_secondaries; | |
e758ad01 DW |
33 | bool moveon; |
34 | char descr[DESCR_BUFSZ]; | |
35 | ||
ee310b0c DW |
36 | xfs_action_list_init(&alist); |
37 | xfs_action_list_init(&immediate_alist); | |
e758ad01 DW |
38 | snprintf(descr, DESCR_BUFSZ, _("AG %u"), agno); |
39 | ||
40 | /* | |
41 | * First we scrub and fix the AG headers, because we need | |
42 | * them to work well enough to check the AG btrees. | |
43 | */ | |
ee310b0c DW |
44 | moveon = xfs_scrub_ag_headers(ctx, agno, &alist); |
45 | if (!moveon) | |
46 | goto err; | |
47 | ||
48 | /* Repair header damage. */ | |
49 | moveon = xfs_action_list_process_or_defer(ctx, agno, &alist); | |
e758ad01 DW |
50 | if (!moveon) |
51 | goto err; | |
52 | ||
53 | /* Now scrub the AG btrees. */ | |
ee310b0c DW |
54 | moveon = xfs_scrub_ag_metadata(ctx, agno, &alist); |
55 | if (!moveon) | |
56 | goto err; | |
57 | ||
58 | /* | |
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. | |
64 | */ | |
65 | broken_secondaries = 0; | |
66 | broken_primaries = 0; | |
67 | xfs_action_list_find_mustfix(&alist, &immediate_alist, | |
68 | &broken_primaries, &broken_secondaries); | |
69 | if (broken_secondaries && !debug_tweak_on("XFS_SCRUB_FORCE_REPAIR")) { | |
70 | if (broken_primaries) | |
71 | str_info(ctx, descr, | |
72 | _("Corrupt primary and secondary block mapping metadata.")); | |
73 | else | |
74 | str_info(ctx, descr, | |
75 | _("Corrupt secondary block mapping metadata.")); | |
76 | str_info(ctx, descr, | |
77 | _("Filesystem might not be repairable.")); | |
78 | } | |
79 | ||
80 | /* Repair (inode) btree damage. */ | |
81 | moveon = xfs_action_list_process_or_defer(ctx, agno, &immediate_alist); | |
e758ad01 DW |
82 | if (!moveon) |
83 | goto err; | |
84 | ||
ee310b0c DW |
85 | /* Everything else gets fixed during phase 4. */ |
86 | xfs_action_list_defer(ctx, agno, &alist); | |
87 | ||
e758ad01 DW |
88 | return; |
89 | err: | |
90 | *pmoveon = false; | |
91 | } | |
92 | ||
93 | /* Scrub whole-FS metadata btrees. */ | |
94 | static void | |
95 | xfs_scan_fs_metadata( | |
96 | struct workqueue *wq, | |
97 | xfs_agnumber_t agno, | |
98 | void *arg) | |
99 | { | |
100 | struct scrub_ctx *ctx = (struct scrub_ctx *)wq->wq_ctx; | |
101 | bool *pmoveon = arg; | |
ee310b0c | 102 | struct xfs_action_list alist; |
e758ad01 DW |
103 | bool moveon; |
104 | ||
ee310b0c DW |
105 | xfs_action_list_init(&alist); |
106 | moveon = xfs_scrub_fs_metadata(ctx, &alist); | |
e758ad01 DW |
107 | if (!moveon) |
108 | *pmoveon = false; | |
ee310b0c DW |
109 | |
110 | xfs_action_list_defer(ctx, agno, &alist); | |
e758ad01 DW |
111 | } |
112 | ||
113 | /* Scan all filesystem metadata. */ | |
114 | bool | |
115 | xfs_scan_metadata( | |
116 | struct scrub_ctx *ctx) | |
117 | { | |
ee310b0c | 118 | struct xfs_action_list alist; |
e758ad01 DW |
119 | struct workqueue wq; |
120 | xfs_agnumber_t agno; | |
121 | bool moveon = true; | |
122 | int ret; | |
123 | ||
124 | ret = workqueue_create(&wq, (struct xfs_mount *)ctx, | |
125 | scrub_nproc_workqueue(ctx)); | |
126 | if (ret) { | |
82377bde | 127 | str_info(ctx, ctx->mntpoint, _("Could not create workqueue.")); |
e758ad01 DW |
128 | return false; |
129 | } | |
130 | ||
131 | /* | |
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 | |
134 | * anything else. | |
135 | */ | |
ee310b0c DW |
136 | xfs_action_list_init(&alist); |
137 | moveon = xfs_scrub_primary_super(ctx, &alist); | |
138 | if (!moveon) | |
139 | goto out; | |
140 | moveon = xfs_action_list_process_or_defer(ctx, 0, &alist); | |
e758ad01 | 141 | if (!moveon) |
224df902 | 142 | goto out; |
e758ad01 DW |
143 | |
144 | for (agno = 0; moveon && agno < ctx->geo.agcount; agno++) { | |
145 | ret = workqueue_add(&wq, xfs_scan_ag_metadata, agno, &moveon); | |
146 | if (ret) { | |
147 | moveon = false; | |
82377bde | 148 | str_info(ctx, ctx->mntpoint, |
e758ad01 DW |
149 | _("Could not queue AG %u scrub work."), agno); |
150 | goto out; | |
151 | } | |
152 | } | |
153 | ||
154 | if (!moveon) | |
155 | goto out; | |
156 | ||
157 | ret = workqueue_add(&wq, xfs_scan_fs_metadata, 0, &moveon); | |
158 | if (ret) { | |
159 | moveon = false; | |
82377bde | 160 | str_info(ctx, ctx->mntpoint, |
e758ad01 DW |
161 | _("Could not queue filesystem scrub work.")); |
162 | goto out; | |
163 | } | |
164 | ||
165 | out: | |
166 | workqueue_destroy(&wq); | |
167 | return moveon; | |
168 | } | |
ed60d210 DW |
169 | |
170 | /* Estimate how much work we're going to do. */ | |
171 | bool | |
172 | xfs_estimate_metadata_work( | |
173 | struct scrub_ctx *ctx, | |
174 | uint64_t *items, | |
175 | unsigned int *nr_threads, | |
176 | int *rshift) | |
177 | { | |
178 | *items = xfs_scrub_estimate_ag_work(ctx); | |
179 | *nr_threads = scrub_nproc(ctx); | |
180 | *rshift = 0; | |
181 | return true; | |
182 | } |