Line data Source code
1 : // SPDX-License-Identifier: GPL-2.0+
2 : /*
3 : * Copyright (C) 2019 Oracle. All Rights Reserved.
4 : * Author: Darrick J. Wong <darrick.wong@oracle.com>
5 : */
6 : #include "xfs.h"
7 : #include "xfs_fs.h"
8 : #include "xfs_shared.h"
9 : #include "xfs_format.h"
10 : #include "xfs_log_format.h"
11 : #include "xfs_trans_resv.h"
12 : #include "xfs_mount.h"
13 : #include "xfs_inode.h"
14 : #include "xfs_trace.h"
15 : #include "xfs_health.h"
16 : #include "xfs_ag.h"
17 :
18 : /*
19 : * Warn about metadata corruption that we detected but haven't fixed, and
20 : * make sure we're not sitting on anything that would get in the way of
21 : * recovery.
22 : */
23 : void
24 22482 : xfs_health_unmount(
25 : struct xfs_mount *mp)
26 : {
27 22482 : struct xfs_perag *pag;
28 22482 : xfs_agnumber_t agno;
29 22482 : unsigned int sick = 0;
30 22482 : unsigned int checked = 0;
31 22482 : bool warn = false;
32 :
33 44964 : if (xfs_is_shutdown(mp))
34 10727 : return;
35 :
36 : /* Measure AG corruption levels. */
37 95761 : for_each_perag(mp, agno, pag) {
38 84006 : xfs_ag_measure_sickness(pag, &sick, &checked);
39 84006 : if (sick) {
40 2 : trace_xfs_ag_unfixed_corruption(mp, agno, sick);
41 2 : warn = true;
42 : }
43 : }
44 :
45 : /* Measure realtime volume corruption levels. */
46 11755 : xfs_rt_measure_sickness(mp, &sick, &checked);
47 11755 : if (sick) {
48 0 : trace_xfs_rt_unfixed_corruption(mp, sick);
49 0 : warn = true;
50 : }
51 :
52 : /*
53 : * Measure fs corruption and keep the sample around for the warning.
54 : * See the note below for why we exempt FS_COUNTERS.
55 : */
56 11755 : xfs_fs_measure_sickness(mp, &sick, &checked);
57 11755 : if (sick & ~XFS_SICK_FS_COUNTERS) {
58 0 : trace_xfs_fs_unfixed_corruption(mp, sick);
59 0 : warn = true;
60 : }
61 :
62 11755 : if (warn) {
63 2 : xfs_warn(mp,
64 : "Uncorrected metadata errors detected; please run xfs_repair.");
65 :
66 : /*
67 : * We discovered uncorrected metadata problems at some point
68 : * during this filesystem mount and have advised the
69 : * administrator to run repair once the unmount completes.
70 : *
71 : * However, we must be careful -- when FSCOUNTERS are flagged
72 : * unhealthy, the unmount procedure omits writing the clean
73 : * unmount record to the log so that the next mount will run
74 : * recovery and recompute the summary counters. In other
75 : * words, we leave a dirty log to get the counters fixed.
76 : *
77 : * Unfortunately, xfs_repair cannot recover dirty logs, so if
78 : * there were filesystem problems, FSCOUNTERS was flagged, and
79 : * the administrator takes our advice to run xfs_repair,
80 : * they'll have to zap the log before repairing structures.
81 : * We don't really want to encourage this, so we mark the
82 : * FSCOUNTERS healthy so that a subsequent repair run won't see
83 : * a dirty log.
84 : */
85 2 : if (sick & XFS_SICK_FS_COUNTERS)
86 0 : xfs_fs_mark_healthy(mp, XFS_SICK_FS_COUNTERS);
87 : }
88 : }
89 :
90 : /* Mark unhealthy per-fs metadata. */
91 : void
92 554035 : xfs_fs_mark_sick(
93 : struct xfs_mount *mp,
94 : unsigned int mask)
95 : {
96 554035 : ASSERT(!(mask & ~XFS_SICK_FS_PRIMARY));
97 554035 : trace_xfs_fs_mark_sick(mp, mask);
98 :
99 554045 : spin_lock(&mp->m_sb_lock);
100 554051 : mp->m_fs_sick |= mask;
101 554051 : mp->m_fs_checked |= mask;
102 554051 : spin_unlock(&mp->m_sb_lock);
103 554050 : }
104 :
105 : /* Mark a per-fs metadata healed. */
106 : void
107 721952 : xfs_fs_mark_healthy(
108 : struct xfs_mount *mp,
109 : unsigned int mask)
110 : {
111 721952 : ASSERT(!(mask & ~XFS_SICK_FS_PRIMARY));
112 721952 : trace_xfs_fs_mark_healthy(mp, mask);
113 :
114 721952 : spin_lock(&mp->m_sb_lock);
115 721952 : mp->m_fs_sick &= ~mask;
116 721952 : mp->m_fs_checked |= mask;
117 721952 : spin_unlock(&mp->m_sb_lock);
118 721952 : }
119 :
120 : /* Sample which per-fs metadata are unhealthy. */
121 : void
122 26383 : xfs_fs_measure_sickness(
123 : struct xfs_mount *mp,
124 : unsigned int *sick,
125 : unsigned int *checked)
126 : {
127 38138 : spin_lock(&mp->m_sb_lock);
128 1942791 : *sick = mp->m_fs_sick;
129 1942791 : *checked = mp->m_fs_checked;
130 1942791 : spin_unlock(&mp->m_sb_lock);
131 26383 : }
132 :
133 : /* Mark unhealthy realtime metadata. */
134 : void
135 0 : xfs_rt_mark_sick(
136 : struct xfs_mount *mp,
137 : unsigned int mask)
138 : {
139 0 : ASSERT(!(mask & ~XFS_SICK_RT_PRIMARY));
140 0 : trace_xfs_rt_mark_sick(mp, mask);
141 :
142 0 : spin_lock(&mp->m_sb_lock);
143 0 : mp->m_rt_sick |= mask;
144 0 : mp->m_rt_checked |= mask;
145 0 : spin_unlock(&mp->m_sb_lock);
146 0 : }
147 :
148 : /* Mark a realtime metadata healed. */
149 : void
150 79603 : xfs_rt_mark_healthy(
151 : struct xfs_mount *mp,
152 : unsigned int mask)
153 : {
154 79603 : ASSERT(!(mask & ~XFS_SICK_RT_PRIMARY));
155 79603 : trace_xfs_rt_mark_healthy(mp, mask);
156 :
157 79603 : spin_lock(&mp->m_sb_lock);
158 79603 : mp->m_rt_sick &= ~mask;
159 79603 : mp->m_rt_checked |= mask;
160 79603 : spin_unlock(&mp->m_sb_lock);
161 79603 : }
162 :
163 : /* Sample which realtime metadata are unhealthy. */
164 : void
165 0 : xfs_rt_measure_sickness(
166 : struct xfs_mount *mp,
167 : unsigned int *sick,
168 : unsigned int *checked)
169 : {
170 11755 : spin_lock(&mp->m_sb_lock);
171 1916408 : *sick = mp->m_rt_sick;
172 1916408 : *checked = mp->m_rt_checked;
173 1916408 : spin_unlock(&mp->m_sb_lock);
174 0 : }
175 :
176 : /* Mark unhealthy per-ag metadata. */
177 : void
178 2 : xfs_ag_mark_sick(
179 : struct xfs_perag *pag,
180 : unsigned int mask)
181 : {
182 2 : ASSERT(!(mask & ~XFS_SICK_AG_PRIMARY));
183 2 : trace_xfs_ag_mark_sick(pag->pag_mount, pag->pag_agno, mask);
184 :
185 2 : spin_lock(&pag->pag_state_lock);
186 2 : pag->pag_sick |= mask;
187 2 : pag->pag_checked |= mask;
188 2 : spin_unlock(&pag->pag_state_lock);
189 2 : }
190 :
191 : /* Mark per-ag metadata ok. */
192 : void
193 9080408 : xfs_ag_mark_healthy(
194 : struct xfs_perag *pag,
195 : unsigned int mask)
196 : {
197 9080408 : ASSERT(!(mask & ~XFS_SICK_AG_PRIMARY));
198 9080408 : trace_xfs_ag_mark_healthy(pag->pag_mount, pag->pag_agno, mask);
199 :
200 9080468 : spin_lock(&pag->pag_state_lock);
201 9080951 : pag->pag_sick &= ~mask;
202 9080951 : pag->pag_checked |= mask;
203 9080951 : spin_unlock(&pag->pag_state_lock);
204 9080777 : }
205 :
206 : /* Sample which per-ag metadata are unhealthy. */
207 : void
208 2766998653 : xfs_ag_measure_sickness(
209 : struct xfs_perag *pag,
210 : unsigned int *sick,
211 : unsigned int *checked)
212 : {
213 2767082659 : spin_lock(&pag->pag_state_lock);
214 2767389340 : *sick = pag->pag_sick;
215 2767389340 : *checked = pag->pag_checked;
216 2767389340 : spin_unlock(&pag->pag_state_lock);
217 2767154837 : }
218 :
219 : /* Mark the unhealthy parts of an inode. */
220 : void
221 6 : xfs_inode_mark_sick(
222 : struct xfs_inode *ip,
223 : unsigned int mask)
224 : {
225 6 : ASSERT(!(mask & ~XFS_SICK_INO_PRIMARY));
226 6 : trace_xfs_inode_mark_sick(ip, mask);
227 :
228 6 : spin_lock(&ip->i_flags_lock);
229 6 : ip->i_sick |= mask;
230 6 : ip->i_checked |= mask;
231 6 : spin_unlock(&ip->i_flags_lock);
232 :
233 : /*
234 : * Keep this inode around so we don't lose the sickness report. Scrub
235 : * grabs inodes with DONTCACHE assuming that most inode are ok, which
236 : * is not the case here.
237 : */
238 6 : spin_lock(&VFS_I(ip)->i_lock);
239 6 : VFS_I(ip)->i_state &= ~I_DONTCACHE;
240 6 : spin_unlock(&VFS_I(ip)->i_lock);
241 6 : }
242 :
243 : /* Mark parts of an inode healed. */
244 : void
245 1186567834 : xfs_inode_mark_healthy(
246 : struct xfs_inode *ip,
247 : unsigned int mask)
248 : {
249 1186567834 : ASSERT(!(mask & ~XFS_SICK_INO_PRIMARY));
250 1186567834 : trace_xfs_inode_mark_healthy(ip, mask);
251 :
252 1186650077 : spin_lock(&ip->i_flags_lock);
253 1186954670 : ip->i_sick &= ~mask;
254 1186954670 : ip->i_checked |= mask;
255 1186954670 : spin_unlock(&ip->i_flags_lock);
256 1186783817 : }
257 :
258 : /* Sample which parts of an inode are unhealthy. */
259 : void
260 0 : xfs_inode_measure_sickness(
261 : struct xfs_inode *ip,
262 : unsigned int *sick,
263 : unsigned int *checked)
264 : {
265 0 : spin_lock(&ip->i_flags_lock);
266 47055242616 : *sick = ip->i_sick;
267 47055242616 : *checked = ip->i_checked;
268 47055242616 : spin_unlock(&ip->i_flags_lock);
269 0 : }
270 :
271 : /* Mappings between internal sick masks and ioctl sick masks. */
272 :
273 : struct ioctl_sick_map {
274 : unsigned int sick_mask;
275 : unsigned int ioctl_mask;
276 : };
277 :
278 : static const struct ioctl_sick_map fs_map[] = {
279 : { XFS_SICK_FS_COUNTERS, XFS_FSOP_GEOM_SICK_COUNTERS},
280 : { XFS_SICK_FS_UQUOTA, XFS_FSOP_GEOM_SICK_UQUOTA },
281 : { XFS_SICK_FS_GQUOTA, XFS_FSOP_GEOM_SICK_GQUOTA },
282 : { XFS_SICK_FS_PQUOTA, XFS_FSOP_GEOM_SICK_PQUOTA },
283 : { 0, 0 },
284 : };
285 :
286 : static const struct ioctl_sick_map rt_map[] = {
287 : { XFS_SICK_RT_BITMAP, XFS_FSOP_GEOM_SICK_RT_BITMAP },
288 : { XFS_SICK_RT_SUMMARY, XFS_FSOP_GEOM_SICK_RT_SUMMARY },
289 : { 0, 0 },
290 : };
291 :
292 : static inline void
293 11426613 : xfgeo_health_tick(
294 : struct xfs_fsop_geom *geo,
295 : unsigned int sick,
296 : unsigned int checked,
297 : const struct ioctl_sick_map *m)
298 : {
299 11426613 : if (checked & m->sick_mask)
300 673774 : geo->checked |= m->ioctl_mask;
301 11426613 : if (sick & m->sick_mask)
302 48227 : geo->sick |= m->ioctl_mask;
303 11426613 : }
304 :
305 : /* Fill out fs geometry health info. */
306 : void
307 1904450 : xfs_fsop_geom_health(
308 : struct xfs_mount *mp,
309 : struct xfs_fsop_geom *geo)
310 : {
311 1904450 : const struct ioctl_sick_map *m;
312 1904450 : unsigned int sick;
313 1904450 : unsigned int checked;
314 :
315 1904450 : geo->sick = 0;
316 1904450 : geo->checked = 0;
317 :
318 1904450 : xfs_fs_measure_sickness(mp, &sick, &checked);
319 11426967 : for (m = fs_map; m->sick_mask; m++)
320 7617808 : xfgeo_health_tick(geo, sick, checked, m);
321 :
322 1904506 : xfs_rt_measure_sickness(mp, &sick, &checked);
323 7618146 : for (m = rt_map; m->sick_mask; m++)
324 3808924 : xfgeo_health_tick(geo, sick, checked, m);
325 1904569 : }
326 :
327 : static const struct ioctl_sick_map ag_map[] = {
328 : { XFS_SICK_AG_SB, XFS_AG_GEOM_SICK_SB },
329 : { XFS_SICK_AG_AGF, XFS_AG_GEOM_SICK_AGF },
330 : { XFS_SICK_AG_AGFL, XFS_AG_GEOM_SICK_AGFL },
331 : { XFS_SICK_AG_AGI, XFS_AG_GEOM_SICK_AGI },
332 : { XFS_SICK_AG_BNOBT, XFS_AG_GEOM_SICK_BNOBT },
333 : { XFS_SICK_AG_CNTBT, XFS_AG_GEOM_SICK_CNTBT },
334 : { XFS_SICK_AG_INOBT, XFS_AG_GEOM_SICK_INOBT },
335 : { XFS_SICK_AG_FINOBT, XFS_AG_GEOM_SICK_FINOBT },
336 : { XFS_SICK_AG_RMAPBT, XFS_AG_GEOM_SICK_RMAPBT },
337 : { XFS_SICK_AG_REFCNTBT, XFS_AG_GEOM_SICK_REFCNTBT },
338 : { 0, 0 },
339 : };
340 :
341 : /* Fill out ag geometry health info. */
342 : void
343 14819 : xfs_ag_geom_health(
344 : struct xfs_perag *pag,
345 : struct xfs_ag_geometry *ageo)
346 : {
347 14819 : const struct ioctl_sick_map *m;
348 14819 : unsigned int sick;
349 14819 : unsigned int checked;
350 :
351 14819 : ageo->ag_sick = 0;
352 14819 : ageo->ag_checked = 0;
353 :
354 14819 : xfs_ag_measure_sickness(pag, &sick, &checked);
355 177828 : for (m = ag_map; m->sick_mask; m++) {
356 148190 : if (checked & m->sick_mask)
357 147630 : ageo->ag_checked |= m->ioctl_mask;
358 148190 : if (sick & m->sick_mask)
359 2 : ageo->ag_sick |= m->ioctl_mask;
360 : }
361 14819 : }
362 :
363 : static const struct ioctl_sick_map ino_map[] = {
364 : { XFS_SICK_INO_CORE, XFS_BS_SICK_INODE },
365 : { XFS_SICK_INO_BMBTD, XFS_BS_SICK_BMBTD },
366 : { XFS_SICK_INO_BMBTA, XFS_BS_SICK_BMBTA },
367 : { XFS_SICK_INO_BMBTC, XFS_BS_SICK_BMBTC },
368 : { XFS_SICK_INO_DIR, XFS_BS_SICK_DIR },
369 : { XFS_SICK_INO_XATTR, XFS_BS_SICK_XATTR },
370 : { XFS_SICK_INO_SYMLINK, XFS_BS_SICK_SYMLINK },
371 : { XFS_SICK_INO_PARENT, XFS_BS_SICK_PARENT },
372 : { 0, 0 },
373 : };
374 :
375 : /* Fill out bulkstat health info. */
376 : void
377 46868508587 : xfs_bulkstat_health(
378 : struct xfs_inode *ip,
379 : struct xfs_bulkstat *bs)
380 : {
381 46868508587 : const struct ioctl_sick_map *m;
382 46868508587 : unsigned int sick;
383 46868508587 : unsigned int checked;
384 :
385 46868508587 : bs->bs_sick = 0;
386 46868508587 : bs->bs_checked = 0;
387 :
388 46868508587 : xfs_inode_measure_sickness(ip, &sick, &checked);
389 >46667*10^7 : for (m = ino_map; m->sick_mask; m++) {
390 >37256*10^7 : if (checked & m->sick_mask)
391 27758806277 : bs->bs_checked |= m->ioctl_mask;
392 >37256*10^7 : if (sick & m->sick_mask)
393 0 : bs->bs_sick |= m->ioctl_mask;
394 : }
395 47058051066 : }
|