]>
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" |
42b4c8e8 | 11 | #include "libfrog/paths.h" |
56598728 | 12 | #include "libfrog/workqueue.h" |
e758ad01 DW |
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; | |
83d2c80b DW |
29 | struct action_list alist; |
30 | struct action_list immediate_alist; | |
ee310b0c DW |
31 | unsigned long long broken_primaries; |
32 | unsigned long long broken_secondaries; | |
e758ad01 | 33 | char descr[DESCR_BUFSZ]; |
d22f2471 | 34 | int ret; |
e758ad01 | 35 | |
83d2c80b DW |
36 | action_list_init(&alist); |
37 | 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 | */ | |
d22f2471 DW |
44 | ret = xfs_scrub_ag_headers(ctx, agno, &alist); |
45 | if (ret) | |
ee310b0c DW |
46 | goto err; |
47 | ||
48 | /* Repair header damage. */ | |
83d2c80b DW |
49 | ret = action_list_process_or_defer(ctx, agno, &alist); |
50 | if (ret) | |
e758ad01 DW |
51 | goto err; |
52 | ||
53 | /* Now scrub the AG btrees. */ | |
d22f2471 DW |
54 | ret = xfs_scrub_ag_metadata(ctx, agno, &alist); |
55 | if (ret) | |
ee310b0c DW |
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; | |
83d2c80b | 67 | action_list_find_mustfix(&alist, &immediate_alist, |
ee310b0c DW |
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. */ | |
83d2c80b DW |
81 | ret = action_list_process_or_defer(ctx, agno, &immediate_alist); |
82 | if (ret) | |
e758ad01 DW |
83 | goto err; |
84 | ||
ee310b0c | 85 | /* Everything else gets fixed during phase 4. */ |
83d2c80b | 86 | action_list_defer(ctx, agno, &alist); |
ee310b0c | 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; | |
83d2c80b | 102 | struct action_list alist; |
d22f2471 | 103 | int ret; |
e758ad01 | 104 | |
83d2c80b | 105 | action_list_init(&alist); |
d22f2471 DW |
106 | ret = xfs_scrub_fs_metadata(ctx, &alist); |
107 | if (ret) | |
e758ad01 | 108 | *pmoveon = false; |
ee310b0c | 109 | |
83d2c80b | 110 | 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 | { | |
83d2c80b | 118 | struct 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) { | |
9d57cbfc | 127 | str_liberror(ctx, ret, _("creating scrub 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 | */ | |
83d2c80b | 136 | action_list_init(&alist); |
d22f2471 DW |
137 | ret = xfs_scrub_primary_super(ctx, &alist); |
138 | if (ret) { | |
139 | moveon = false; | |
ee310b0c | 140 | goto out; |
d22f2471 | 141 | } |
83d2c80b DW |
142 | ret = action_list_process_or_defer(ctx, 0, &alist); |
143 | if (ret) { | |
144 | moveon = false; | |
224df902 | 145 | goto out; |
83d2c80b | 146 | } |
e758ad01 | 147 | |
3f9efb2e | 148 | for (agno = 0; moveon && agno < ctx->mnt.fsgeom.agcount; agno++) { |
e758ad01 DW |
149 | ret = workqueue_add(&wq, xfs_scan_ag_metadata, agno, &moveon); |
150 | if (ret) { | |
151 | moveon = false; | |
9d57cbfc | 152 | str_liberror(ctx, ret, _("queueing per-AG scrub work")); |
e758ad01 DW |
153 | goto out; |
154 | } | |
155 | } | |
156 | ||
157 | if (!moveon) | |
158 | goto out; | |
159 | ||
160 | ret = workqueue_add(&wq, xfs_scan_fs_metadata, 0, &moveon); | |
161 | if (ret) { | |
162 | moveon = false; | |
9d57cbfc | 163 | str_liberror(ctx, ret, _("queueing per-FS scrub work")); |
e758ad01 DW |
164 | goto out; |
165 | } | |
166 | ||
167 | out: | |
71296cf8 DW |
168 | ret = workqueue_terminate(&wq); |
169 | if (ret) { | |
170 | moveon = false; | |
171 | str_liberror(ctx, ret, _("finishing scrub work")); | |
172 | } | |
e758ad01 DW |
173 | workqueue_destroy(&wq); |
174 | return moveon; | |
175 | } | |
ed60d210 DW |
176 | |
177 | /* Estimate how much work we're going to do. */ | |
178 | bool | |
179 | xfs_estimate_metadata_work( | |
180 | struct scrub_ctx *ctx, | |
181 | uint64_t *items, | |
182 | unsigned int *nr_threads, | |
183 | int *rshift) | |
184 | { | |
d22f2471 | 185 | *items = scrub_estimate_ag_work(ctx); |
ed60d210 DW |
186 | *nr_threads = scrub_nproc(ctx); |
187 | *rshift = 0; | |
188 | return true; | |
189 | } |