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 59234 : xfs_health_unmount(
25 : struct xfs_mount *mp)
26 : {
27 59234 : struct xfs_perag *pag;
28 59234 : xfs_agnumber_t agno;
29 59234 : unsigned int sick = 0;
30 59234 : unsigned int checked = 0;
31 59234 : bool warn = false;
32 :
33 118468 : if (xfs_is_shutdown(mp))
34 13082 : return;
35 :
36 : /* Measure AG corruption levels. */
37 435628 : for_each_perag(mp, agno, pag) {
38 389476 : xfs_ag_measure_sickness(pag, &sick, &checked);
39 389476 : if (sick) {
40 11 : trace_xfs_ag_unfixed_corruption(mp, agno, sick);
41 11 : warn = true;
42 : }
43 : }
44 :
45 : /* Measure realtime volume corruption levels. */
46 46152 : xfs_rt_measure_sickness(mp, &sick, &checked);
47 46152 : 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 46152 : xfs_fs_measure_sickness(mp, &sick, &checked);
57 46152 : if (sick & ~XFS_SICK_FS_COUNTERS) {
58 0 : trace_xfs_fs_unfixed_corruption(mp, sick);
59 0 : warn = true;
60 : }
61 :
62 46152 : if (warn) {
63 11 : 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 11 : 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 611631 : xfs_fs_mark_sick(
93 : struct xfs_mount *mp,
94 : unsigned int mask)
95 : {
96 611631 : ASSERT(!(mask & ~XFS_SICK_FS_PRIMARY));
97 611631 : trace_xfs_fs_mark_sick(mp, mask);
98 :
99 611445 : spin_lock(&mp->m_sb_lock);
100 612129 : mp->m_fs_sick |= mask;
101 612129 : mp->m_fs_checked |= mask;
102 612129 : spin_unlock(&mp->m_sb_lock);
103 612125 : }
104 :
105 : /* Mark a per-fs metadata healed. */
106 : void
107 705103 : xfs_fs_mark_healthy(
108 : struct xfs_mount *mp,
109 : unsigned int mask)
110 : {
111 705103 : ASSERT(!(mask & ~XFS_SICK_FS_PRIMARY));
112 705103 : trace_xfs_fs_mark_healthy(mp, mask);
113 :
114 705103 : spin_lock(&mp->m_sb_lock);
115 705103 : mp->m_fs_sick &= ~mask;
116 705103 : mp->m_fs_checked |= mask;
117 705103 : spin_unlock(&mp->m_sb_lock);
118 705103 : }
119 :
120 : /* Sample which per-fs metadata are unhealthy. */
121 : void
122 94228 : xfs_fs_measure_sickness(
123 : struct xfs_mount *mp,
124 : unsigned int *sick,
125 : unsigned int *checked)
126 : {
127 140380 : spin_lock(&mp->m_sb_lock);
128 5708605 : *sick = mp->m_fs_sick;
129 5708605 : *checked = mp->m_fs_checked;
130 5708605 : spin_unlock(&mp->m_sb_lock);
131 94228 : }
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 89673 : xfs_rt_mark_healthy(
151 : struct xfs_mount *mp,
152 : unsigned int mask)
153 : {
154 89673 : ASSERT(!(mask & ~XFS_SICK_RT_PRIMARY));
155 89673 : trace_xfs_rt_mark_healthy(mp, mask);
156 :
157 89673 : spin_lock(&mp->m_sb_lock);
158 89673 : mp->m_rt_sick &= ~mask;
159 89673 : mp->m_rt_checked |= mask;
160 89673 : spin_unlock(&mp->m_sb_lock);
161 89673 : }
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 46152 : spin_lock(&mp->m_sb_lock);
171 5614377 : *sick = mp->m_rt_sick;
172 5614377 : *checked = mp->m_rt_checked;
173 5614377 : spin_unlock(&mp->m_sb_lock);
174 0 : }
175 :
176 : /* Mark unhealthy per-ag metadata. */
177 : void
178 11 : xfs_ag_mark_sick(
179 : struct xfs_perag *pag,
180 : unsigned int mask)
181 : {
182 11 : ASSERT(!(mask & ~XFS_SICK_AG_PRIMARY));
183 11 : trace_xfs_ag_mark_sick(pag->pag_mount, pag->pag_agno, mask);
184 :
185 11 : spin_lock(&pag->pag_state_lock);
186 11 : pag->pag_sick |= mask;
187 11 : pag->pag_checked |= mask;
188 11 : spin_unlock(&pag->pag_state_lock);
189 11 : }
190 :
191 : /* Mark per-ag metadata ok. */
192 : void
193 10195838 : xfs_ag_mark_healthy(
194 : struct xfs_perag *pag,
195 : unsigned int mask)
196 : {
197 10195838 : ASSERT(!(mask & ~XFS_SICK_AG_PRIMARY));
198 10195838 : trace_xfs_ag_mark_healthy(pag->pag_mount, pag->pag_agno, mask);
199 :
200 10186548 : spin_lock(&pag->pag_state_lock);
201 10199174 : pag->pag_sick &= ~mask;
202 10199174 : pag->pag_checked |= mask;
203 10199174 : spin_unlock(&pag->pag_state_lock);
204 10198516 : }
205 :
206 : /* Sample which per-ag metadata are unhealthy. */
207 : void
208 3536968954 : xfs_ag_measure_sickness(
209 : struct xfs_perag *pag,
210 : unsigned int *sick,
211 : unsigned int *checked)
212 : {
213 3537358430 : spin_lock(&pag->pag_state_lock);
214 3539596885 : *sick = pag->pag_sick;
215 3539596885 : *checked = pag->pag_checked;
216 3539596885 : spin_unlock(&pag->pag_state_lock);
217 3539416570 : }
218 :
219 : /* Mark the unhealthy parts of an inode. */
220 : void
221 33 : xfs_inode_mark_sick(
222 : struct xfs_inode *ip,
223 : unsigned int mask)
224 : {
225 33 : ASSERT(!(mask & ~XFS_SICK_INO_PRIMARY));
226 33 : trace_xfs_inode_mark_sick(ip, mask);
227 :
228 33 : spin_lock(&ip->i_flags_lock);
229 33 : ip->i_sick |= mask;
230 33 : ip->i_checked |= mask;
231 33 : 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 33 : spin_lock(&VFS_I(ip)->i_lock);
239 33 : VFS_I(ip)->i_state &= ~I_DONTCACHE;
240 33 : spin_unlock(&VFS_I(ip)->i_lock);
241 33 : }
242 :
243 : /* Mark parts of an inode healed. */
244 : void
245 1379670915 : xfs_inode_mark_healthy(
246 : struct xfs_inode *ip,
247 : unsigned int mask)
248 : {
249 1379670915 : ASSERT(!(mask & ~XFS_SICK_INO_PRIMARY));
250 1379670915 : trace_xfs_inode_mark_healthy(ip, mask);
251 :
252 1379310355 : spin_lock(&ip->i_flags_lock);
253 1382093021 : ip->i_sick &= ~mask;
254 1382093021 : ip->i_checked |= mask;
255 1382093021 : spin_unlock(&ip->i_flags_lock);
256 1382741949 : }
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 53197045502 : *sick = ip->i_sick;
267 53197045502 : *checked = ip->i_checked;
268 53197045502 : 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 33336017 : 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 33336017 : if (checked & m->sick_mask)
300 710851 : geo->checked |= m->ioctl_mask;
301 33336017 : if (sick & m->sick_mask)
302 52702 : geo->sick |= m->ioctl_mask;
303 33336017 : }
304 :
305 : /* Fill out fs geometry health info. */
306 : void
307 5556293 : xfs_fsop_geom_health(
308 : struct xfs_mount *mp,
309 : struct xfs_fsop_geom *geo)
310 : {
311 5556293 : const struct ioctl_sick_map *m;
312 5556293 : unsigned int sick;
313 5556293 : unsigned int checked;
314 :
315 5556293 : geo->sick = 0;
316 5556293 : geo->checked = 0;
317 :
318 5556293 : xfs_fs_measure_sickness(mp, &sick, &checked);
319 33340906 : for (m = fs_map; m->sick_mask; m++)
320 22218483 : xfgeo_health_tick(geo, sick, checked, m);
321 :
322 5554198 : xfs_rt_measure_sickness(mp, &sick, &checked);
323 22263503 : for (m = rt_map; m->sick_mask; m++)
324 11131048 : xfgeo_health_tick(geo, sick, checked, m);
325 5564230 : }
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 67727 : xfs_ag_geom_health(
344 : struct xfs_perag *pag,
345 : struct xfs_ag_geometry *ageo)
346 : {
347 67727 : const struct ioctl_sick_map *m;
348 67727 : unsigned int sick;
349 67727 : unsigned int checked;
350 :
351 67727 : ageo->ag_sick = 0;
352 67727 : ageo->ag_checked = 0;
353 :
354 67727 : xfs_ag_measure_sickness(pag, &sick, &checked);
355 812724 : for (m = ag_map; m->sick_mask; m++) {
356 677270 : if (checked & m->sick_mask)
357 650282 : ageo->ag_checked |= m->ioctl_mask;
358 677270 : if (sick & m->sick_mask)
359 11 : ageo->ag_sick |= m->ioctl_mask;
360 : }
361 67727 : }
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 52167494627 : xfs_bulkstat_health(
378 : struct xfs_inode *ip,
379 : struct xfs_bulkstat *bs)
380 : {
381 52167494627 : const struct ioctl_sick_map *m;
382 52167494627 : unsigned int sick;
383 52167494627 : unsigned int checked;
384 :
385 52167494627 : bs->bs_sick = 0;
386 52167494627 : bs->bs_checked = 0;
387 :
388 52167494627 : xfs_inode_measure_sickness(ip, &sick, &checked);
389 >52082*10^7 : for (m = ino_map; m->sick_mask; m++) {
390 >41474*10^7 : if (checked & m->sick_mask)
391 29421947381 : bs->bs_checked |= m->ioctl_mask;
392 >41474*10^7 : if (sick & m->sick_mask)
393 0 : bs->bs_sick |= m->ioctl_mask;
394 : }
395 52878031787 : }
|