]>
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; | |
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]; | |
d22f2471 | 35 | int ret; |
e758ad01 | 36 | |
ee310b0c DW |
37 | xfs_action_list_init(&alist); |
38 | xfs_action_list_init(&immediate_alist); | |
e758ad01 DW |
39 | snprintf(descr, DESCR_BUFSZ, _("AG %u"), agno); |
40 | ||
41 | /* | |
42 | * First we scrub and fix the AG headers, because we need | |
43 | * them to work well enough to check the AG btrees. | |
44 | */ | |
d22f2471 DW |
45 | ret = xfs_scrub_ag_headers(ctx, agno, &alist); |
46 | if (ret) | |
ee310b0c DW |
47 | goto err; |
48 | ||
49 | /* Repair header damage. */ | |
50 | moveon = xfs_action_list_process_or_defer(ctx, agno, &alist); | |
e758ad01 DW |
51 | if (!moveon) |
52 | goto err; | |
53 | ||
54 | /* Now scrub the AG btrees. */ | |
d22f2471 DW |
55 | ret = xfs_scrub_ag_metadata(ctx, agno, &alist); |
56 | if (ret) | |
ee310b0c DW |
57 | goto err; |
58 | ||
59 | /* | |
60 | * Figure out if we need to perform early fixing. The only | |
61 | * reason we need to do this is if the inobt is broken, which | |
62 | * prevents phase 3 (inode scan) from running. We can rebuild | |
63 | * the inobt from rmapbt data, but if the rmapbt is broken even | |
64 | * at this early phase then we are sunk. | |
65 | */ | |
66 | broken_secondaries = 0; | |
67 | broken_primaries = 0; | |
68 | xfs_action_list_find_mustfix(&alist, &immediate_alist, | |
69 | &broken_primaries, &broken_secondaries); | |
70 | if (broken_secondaries && !debug_tweak_on("XFS_SCRUB_FORCE_REPAIR")) { | |
71 | if (broken_primaries) | |
72 | str_info(ctx, descr, | |
73 | _("Corrupt primary and secondary block mapping metadata.")); | |
74 | else | |
75 | str_info(ctx, descr, | |
76 | _("Corrupt secondary block mapping metadata.")); | |
77 | str_info(ctx, descr, | |
78 | _("Filesystem might not be repairable.")); | |
79 | } | |
80 | ||
81 | /* Repair (inode) btree damage. */ | |
82 | moveon = xfs_action_list_process_or_defer(ctx, agno, &immediate_alist); | |
e758ad01 DW |
83 | if (!moveon) |
84 | goto err; | |
85 | ||
ee310b0c DW |
86 | /* Everything else gets fixed during phase 4. */ |
87 | xfs_action_list_defer(ctx, agno, &alist); | |
88 | ||
e758ad01 DW |
89 | return; |
90 | err: | |
91 | *pmoveon = false; | |
92 | } | |
93 | ||
94 | /* Scrub whole-FS metadata btrees. */ | |
95 | static void | |
96 | xfs_scan_fs_metadata( | |
97 | struct workqueue *wq, | |
98 | xfs_agnumber_t agno, | |
99 | void *arg) | |
100 | { | |
101 | struct scrub_ctx *ctx = (struct scrub_ctx *)wq->wq_ctx; | |
102 | bool *pmoveon = arg; | |
ee310b0c | 103 | struct xfs_action_list alist; |
d22f2471 | 104 | int ret; |
e758ad01 | 105 | |
ee310b0c | 106 | xfs_action_list_init(&alist); |
d22f2471 DW |
107 | ret = xfs_scrub_fs_metadata(ctx, &alist); |
108 | if (ret) | |
e758ad01 | 109 | *pmoveon = false; |
ee310b0c DW |
110 | |
111 | xfs_action_list_defer(ctx, agno, &alist); | |
e758ad01 DW |
112 | } |
113 | ||
114 | /* Scan all filesystem metadata. */ | |
115 | bool | |
116 | xfs_scan_metadata( | |
117 | struct scrub_ctx *ctx) | |
118 | { | |
ee310b0c | 119 | struct xfs_action_list alist; |
e758ad01 DW |
120 | struct workqueue wq; |
121 | xfs_agnumber_t agno; | |
122 | bool moveon = true; | |
123 | int ret; | |
124 | ||
125 | ret = workqueue_create(&wq, (struct xfs_mount *)ctx, | |
126 | scrub_nproc_workqueue(ctx)); | |
127 | if (ret) { | |
9d57cbfc | 128 | str_liberror(ctx, ret, _("creating scrub workqueue")); |
e758ad01 DW |
129 | return false; |
130 | } | |
131 | ||
132 | /* | |
133 | * In case we ever use the primary super scrubber to perform fs | |
134 | * upgrades (followed by a full scrub), do that before we launch | |
135 | * anything else. | |
136 | */ | |
ee310b0c | 137 | xfs_action_list_init(&alist); |
d22f2471 DW |
138 | ret = xfs_scrub_primary_super(ctx, &alist); |
139 | if (ret) { | |
140 | moveon = false; | |
ee310b0c | 141 | goto out; |
d22f2471 | 142 | } |
ee310b0c | 143 | moveon = xfs_action_list_process_or_defer(ctx, 0, &alist); |
e758ad01 | 144 | if (!moveon) |
224df902 | 145 | goto out; |
e758ad01 | 146 | |
3f9efb2e | 147 | for (agno = 0; moveon && agno < ctx->mnt.fsgeom.agcount; agno++) { |
e758ad01 DW |
148 | ret = workqueue_add(&wq, xfs_scan_ag_metadata, agno, &moveon); |
149 | if (ret) { | |
150 | moveon = false; | |
9d57cbfc | 151 | str_liberror(ctx, ret, _("queueing per-AG scrub work")); |
e758ad01 DW |
152 | goto out; |
153 | } | |
154 | } | |
155 | ||
156 | if (!moveon) | |
157 | goto out; | |
158 | ||
159 | ret = workqueue_add(&wq, xfs_scan_fs_metadata, 0, &moveon); | |
160 | if (ret) { | |
161 | moveon = false; | |
9d57cbfc | 162 | str_liberror(ctx, ret, _("queueing per-FS scrub work")); |
e758ad01 DW |
163 | goto out; |
164 | } | |
165 | ||
166 | out: | |
71296cf8 DW |
167 | ret = workqueue_terminate(&wq); |
168 | if (ret) { | |
169 | moveon = false; | |
170 | str_liberror(ctx, ret, _("finishing scrub work")); | |
171 | } | |
e758ad01 DW |
172 | workqueue_destroy(&wq); |
173 | return moveon; | |
174 | } | |
ed60d210 DW |
175 | |
176 | /* Estimate how much work we're going to do. */ | |
177 | bool | |
178 | xfs_estimate_metadata_work( | |
179 | struct scrub_ctx *ctx, | |
180 | uint64_t *items, | |
181 | unsigned int *nr_threads, | |
182 | int *rshift) | |
183 | { | |
d22f2471 | 184 | *items = scrub_estimate_ag_work(ctx); |
ed60d210 DW |
185 | *nr_threads = scrub_nproc(ctx); |
186 | *rshift = 0; | |
187 | return true; | |
188 | } |