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#include "xfs_btree.h"
18#include "xfs_da_format.h"
19#include "xfs_da_btree.h"
20#include "xfs_quota_defs.h"
21
22/*
23 * Warn about metadata corruption that we detected but haven't fixed, and
24 * make sure we're not sitting on anything that would get in the way of
25 * recovery.
26 */
27void
28xfs_health_unmount(
29 struct xfs_mount *mp)
30{
31 struct xfs_perag *pag;
32 xfs_agnumber_t agno;
33 unsigned int sick = 0;
34 unsigned int checked = 0;
35 bool warn = false;
36
37 if (xfs_is_shutdown(mp))
38 return;
39
40 /* Measure AG corruption levels. */
41 for_each_perag(mp, agno, pag) {
42 xfs_ag_measure_sickness(pag, &sick, &checked);
43 if (sick) {
44 trace_xfs_ag_unfixed_corruption(mp, agno, sick);
45 warn = true;
46 }
47 }
48
49 /* Measure realtime volume corruption levels. */
50 xfs_rt_measure_sickness(mp, &sick, &checked);
51 if (sick) {
52 trace_xfs_rt_unfixed_corruption(mp, flags: sick);
53 warn = true;
54 }
55
56 /*
57 * Measure fs corruption and keep the sample around for the warning.
58 * See the note below for why we exempt FS_COUNTERS.
59 */
60 xfs_fs_measure_sickness(mp, &sick, &checked);
61 if (sick & ~XFS_SICK_FS_COUNTERS) {
62 trace_xfs_fs_unfixed_corruption(mp, flags: sick);
63 warn = true;
64 }
65
66 if (warn) {
67 xfs_warn(mp,
68"Uncorrected metadata errors detected; please run xfs_repair.");
69
70 /*
71 * We discovered uncorrected metadata problems at some point
72 * during this filesystem mount and have advised the
73 * administrator to run repair once the unmount completes.
74 *
75 * However, we must be careful -- when FSCOUNTERS are flagged
76 * unhealthy, the unmount procedure omits writing the clean
77 * unmount record to the log so that the next mount will run
78 * recovery and recompute the summary counters. In other
79 * words, we leave a dirty log to get the counters fixed.
80 *
81 * Unfortunately, xfs_repair cannot recover dirty logs, so if
82 * there were filesystem problems, FSCOUNTERS was flagged, and
83 * the administrator takes our advice to run xfs_repair,
84 * they'll have to zap the log before repairing structures.
85 * We don't really want to encourage this, so we mark the
86 * FSCOUNTERS healthy so that a subsequent repair run won't see
87 * a dirty log.
88 */
89 if (sick & XFS_SICK_FS_COUNTERS)
90 xfs_fs_mark_healthy(mp, XFS_SICK_FS_COUNTERS);
91 }
92}
93
94/* Mark unhealthy per-fs metadata. */
95void
96xfs_fs_mark_sick(
97 struct xfs_mount *mp,
98 unsigned int mask)
99{
100 ASSERT(!(mask & ~XFS_SICK_FS_ALL));
101 trace_xfs_fs_mark_sick(mp, flags: mask);
102
103 spin_lock(lock: &mp->m_sb_lock);
104 mp->m_fs_sick |= mask;
105 spin_unlock(lock: &mp->m_sb_lock);
106}
107
108/* Mark per-fs metadata as having been checked and found unhealthy by fsck. */
109void
110xfs_fs_mark_corrupt(
111 struct xfs_mount *mp,
112 unsigned int mask)
113{
114 ASSERT(!(mask & ~XFS_SICK_FS_ALL));
115 trace_xfs_fs_mark_corrupt(mp, flags: mask);
116
117 spin_lock(lock: &mp->m_sb_lock);
118 mp->m_fs_sick |= mask;
119 mp->m_fs_checked |= mask;
120 spin_unlock(lock: &mp->m_sb_lock);
121}
122
123/* Mark a per-fs metadata healed. */
124void
125xfs_fs_mark_healthy(
126 struct xfs_mount *mp,
127 unsigned int mask)
128{
129 ASSERT(!(mask & ~XFS_SICK_FS_ALL));
130 trace_xfs_fs_mark_healthy(mp, flags: mask);
131
132 spin_lock(lock: &mp->m_sb_lock);
133 mp->m_fs_sick &= ~mask;
134 if (!(mp->m_fs_sick & XFS_SICK_FS_PRIMARY))
135 mp->m_fs_sick &= ~XFS_SICK_FS_SECONDARY;
136 mp->m_fs_checked |= mask;
137 spin_unlock(lock: &mp->m_sb_lock);
138}
139
140/* Sample which per-fs metadata are unhealthy. */
141void
142xfs_fs_measure_sickness(
143 struct xfs_mount *mp,
144 unsigned int *sick,
145 unsigned int *checked)
146{
147 spin_lock(lock: &mp->m_sb_lock);
148 *sick = mp->m_fs_sick;
149 *checked = mp->m_fs_checked;
150 spin_unlock(lock: &mp->m_sb_lock);
151}
152
153/* Mark unhealthy realtime metadata. */
154void
155xfs_rt_mark_sick(
156 struct xfs_mount *mp,
157 unsigned int mask)
158{
159 ASSERT(!(mask & ~XFS_SICK_RT_ALL));
160 trace_xfs_rt_mark_sick(mp, flags: mask);
161
162 spin_lock(lock: &mp->m_sb_lock);
163 mp->m_rt_sick |= mask;
164 spin_unlock(lock: &mp->m_sb_lock);
165}
166
167/* Mark realtime metadata as having been checked and found unhealthy by fsck. */
168void
169xfs_rt_mark_corrupt(
170 struct xfs_mount *mp,
171 unsigned int mask)
172{
173 ASSERT(!(mask & ~XFS_SICK_RT_ALL));
174 trace_xfs_rt_mark_corrupt(mp, flags: mask);
175
176 spin_lock(lock: &mp->m_sb_lock);
177 mp->m_rt_sick |= mask;
178 mp->m_rt_checked |= mask;
179 spin_unlock(lock: &mp->m_sb_lock);
180}
181
182/* Mark a realtime metadata healed. */
183void
184xfs_rt_mark_healthy(
185 struct xfs_mount *mp,
186 unsigned int mask)
187{
188 ASSERT(!(mask & ~XFS_SICK_RT_ALL));
189 trace_xfs_rt_mark_healthy(mp, flags: mask);
190
191 spin_lock(lock: &mp->m_sb_lock);
192 mp->m_rt_sick &= ~mask;
193 if (!(mp->m_rt_sick & XFS_SICK_RT_PRIMARY))
194 mp->m_rt_sick &= ~XFS_SICK_RT_SECONDARY;
195 mp->m_rt_checked |= mask;
196 spin_unlock(lock: &mp->m_sb_lock);
197}
198
199/* Sample which realtime metadata are unhealthy. */
200void
201xfs_rt_measure_sickness(
202 struct xfs_mount *mp,
203 unsigned int *sick,
204 unsigned int *checked)
205{
206 spin_lock(lock: &mp->m_sb_lock);
207 *sick = mp->m_rt_sick;
208 *checked = mp->m_rt_checked;
209 spin_unlock(lock: &mp->m_sb_lock);
210}
211
212/* Mark unhealthy per-ag metadata given a raw AG number. */
213void
214xfs_agno_mark_sick(
215 struct xfs_mount *mp,
216 xfs_agnumber_t agno,
217 unsigned int mask)
218{
219 struct xfs_perag *pag = xfs_perag_get(mp, agno);
220
221 /* per-ag structure not set up yet? */
222 if (!pag)
223 return;
224
225 xfs_ag_mark_sick(pag, mask);
226 xfs_perag_put(pag);
227}
228
229/* Mark unhealthy per-ag metadata. */
230void
231xfs_ag_mark_sick(
232 struct xfs_perag *pag,
233 unsigned int mask)
234{
235 ASSERT(!(mask & ~XFS_SICK_AG_ALL));
236 trace_xfs_ag_mark_sick(pag->pag_mount, pag->pag_agno, mask);
237
238 spin_lock(lock: &pag->pag_state_lock);
239 pag->pag_sick |= mask;
240 spin_unlock(lock: &pag->pag_state_lock);
241}
242
243/* Mark per-ag metadata as having been checked and found unhealthy by fsck. */
244void
245xfs_ag_mark_corrupt(
246 struct xfs_perag *pag,
247 unsigned int mask)
248{
249 ASSERT(!(mask & ~XFS_SICK_AG_ALL));
250 trace_xfs_ag_mark_corrupt(pag->pag_mount, pag->pag_agno, mask);
251
252 spin_lock(lock: &pag->pag_state_lock);
253 pag->pag_sick |= mask;
254 pag->pag_checked |= mask;
255 spin_unlock(lock: &pag->pag_state_lock);
256}
257
258/* Mark per-ag metadata ok. */
259void
260xfs_ag_mark_healthy(
261 struct xfs_perag *pag,
262 unsigned int mask)
263{
264 ASSERT(!(mask & ~XFS_SICK_AG_ALL));
265 trace_xfs_ag_mark_healthy(pag->pag_mount, pag->pag_agno, mask);
266
267 spin_lock(lock: &pag->pag_state_lock);
268 pag->pag_sick &= ~mask;
269 if (!(pag->pag_sick & XFS_SICK_AG_PRIMARY))
270 pag->pag_sick &= ~XFS_SICK_AG_SECONDARY;
271 pag->pag_checked |= mask;
272 spin_unlock(lock: &pag->pag_state_lock);
273}
274
275/* Sample which per-ag metadata are unhealthy. */
276void
277xfs_ag_measure_sickness(
278 struct xfs_perag *pag,
279 unsigned int *sick,
280 unsigned int *checked)
281{
282 spin_lock(lock: &pag->pag_state_lock);
283 *sick = pag->pag_sick;
284 *checked = pag->pag_checked;
285 spin_unlock(lock: &pag->pag_state_lock);
286}
287
288/* Mark the unhealthy parts of an inode. */
289void
290xfs_inode_mark_sick(
291 struct xfs_inode *ip,
292 unsigned int mask)
293{
294 ASSERT(!(mask & ~XFS_SICK_INO_ALL));
295 trace_xfs_inode_mark_sick(ip, flags: mask);
296
297 spin_lock(lock: &ip->i_flags_lock);
298 ip->i_sick |= mask;
299 spin_unlock(lock: &ip->i_flags_lock);
300
301 /*
302 * Keep this inode around so we don't lose the sickness report. Scrub
303 * grabs inodes with DONTCACHE assuming that most inode are ok, which
304 * is not the case here.
305 */
306 spin_lock(lock: &VFS_I(ip)->i_lock);
307 VFS_I(ip)->i_state &= ~I_DONTCACHE;
308 spin_unlock(lock: &VFS_I(ip)->i_lock);
309}
310
311/* Mark inode metadata as having been checked and found unhealthy by fsck. */
312void
313xfs_inode_mark_corrupt(
314 struct xfs_inode *ip,
315 unsigned int mask)
316{
317 ASSERT(!(mask & ~XFS_SICK_INO_ALL));
318 trace_xfs_inode_mark_corrupt(ip, flags: mask);
319
320 spin_lock(lock: &ip->i_flags_lock);
321 ip->i_sick |= mask;
322 ip->i_checked |= mask;
323 spin_unlock(lock: &ip->i_flags_lock);
324
325 /*
326 * Keep this inode around so we don't lose the sickness report. Scrub
327 * grabs inodes with DONTCACHE assuming that most inode are ok, which
328 * is not the case here.
329 */
330 spin_lock(lock: &VFS_I(ip)->i_lock);
331 VFS_I(ip)->i_state &= ~I_DONTCACHE;
332 spin_unlock(lock: &VFS_I(ip)->i_lock);
333}
334
335/* Mark parts of an inode healed. */
336void
337xfs_inode_mark_healthy(
338 struct xfs_inode *ip,
339 unsigned int mask)
340{
341 ASSERT(!(mask & ~XFS_SICK_INO_ALL));
342 trace_xfs_inode_mark_healthy(ip, flags: mask);
343
344 spin_lock(lock: &ip->i_flags_lock);
345 ip->i_sick &= ~mask;
346 if (!(ip->i_sick & XFS_SICK_INO_PRIMARY))
347 ip->i_sick &= ~XFS_SICK_INO_SECONDARY;
348 ip->i_checked |= mask;
349 spin_unlock(lock: &ip->i_flags_lock);
350}
351
352/* Sample which parts of an inode are unhealthy. */
353void
354xfs_inode_measure_sickness(
355 struct xfs_inode *ip,
356 unsigned int *sick,
357 unsigned int *checked)
358{
359 spin_lock(lock: &ip->i_flags_lock);
360 *sick = ip->i_sick;
361 *checked = ip->i_checked;
362 spin_unlock(lock: &ip->i_flags_lock);
363}
364
365/* Mappings between internal sick masks and ioctl sick masks. */
366
367struct ioctl_sick_map {
368 unsigned int sick_mask;
369 unsigned int ioctl_mask;
370};
371
372static const struct ioctl_sick_map fs_map[] = {
373 { XFS_SICK_FS_COUNTERS, XFS_FSOP_GEOM_SICK_COUNTERS},
374 { XFS_SICK_FS_UQUOTA, XFS_FSOP_GEOM_SICK_UQUOTA },
375 { XFS_SICK_FS_GQUOTA, XFS_FSOP_GEOM_SICK_GQUOTA },
376 { XFS_SICK_FS_PQUOTA, XFS_FSOP_GEOM_SICK_PQUOTA },
377 { XFS_SICK_FS_QUOTACHECK, XFS_FSOP_GEOM_SICK_QUOTACHECK },
378 { XFS_SICK_FS_NLINKS, XFS_FSOP_GEOM_SICK_NLINKS },
379 { 0, 0 },
380};
381
382static const struct ioctl_sick_map rt_map[] = {
383 { XFS_SICK_RT_BITMAP, XFS_FSOP_GEOM_SICK_RT_BITMAP },
384 { XFS_SICK_RT_SUMMARY, XFS_FSOP_GEOM_SICK_RT_SUMMARY },
385 { 0, 0 },
386};
387
388static inline void
389xfgeo_health_tick(
390 struct xfs_fsop_geom *geo,
391 unsigned int sick,
392 unsigned int checked,
393 const struct ioctl_sick_map *m)
394{
395 if (checked & m->sick_mask)
396 geo->checked |= m->ioctl_mask;
397 if (sick & m->sick_mask)
398 geo->sick |= m->ioctl_mask;
399}
400
401/* Fill out fs geometry health info. */
402void
403xfs_fsop_geom_health(
404 struct xfs_mount *mp,
405 struct xfs_fsop_geom *geo)
406{
407 const struct ioctl_sick_map *m;
408 unsigned int sick;
409 unsigned int checked;
410
411 geo->sick = 0;
412 geo->checked = 0;
413
414 xfs_fs_measure_sickness(mp, &sick, &checked);
415 for (m = fs_map; m->sick_mask; m++)
416 xfgeo_health_tick(geo, sick, checked, m);
417
418 xfs_rt_measure_sickness(mp, sick: &sick, checked: &checked);
419 for (m = rt_map; m->sick_mask; m++)
420 xfgeo_health_tick(geo, sick, checked, m);
421}
422
423static const struct ioctl_sick_map ag_map[] = {
424 { XFS_SICK_AG_SB, XFS_AG_GEOM_SICK_SB },
425 { XFS_SICK_AG_AGF, XFS_AG_GEOM_SICK_AGF },
426 { XFS_SICK_AG_AGFL, XFS_AG_GEOM_SICK_AGFL },
427 { XFS_SICK_AG_AGI, XFS_AG_GEOM_SICK_AGI },
428 { XFS_SICK_AG_BNOBT, XFS_AG_GEOM_SICK_BNOBT },
429 { XFS_SICK_AG_CNTBT, XFS_AG_GEOM_SICK_CNTBT },
430 { XFS_SICK_AG_INOBT, XFS_AG_GEOM_SICK_INOBT },
431 { XFS_SICK_AG_FINOBT, XFS_AG_GEOM_SICK_FINOBT },
432 { XFS_SICK_AG_RMAPBT, XFS_AG_GEOM_SICK_RMAPBT },
433 { XFS_SICK_AG_REFCNTBT, XFS_AG_GEOM_SICK_REFCNTBT },
434 { XFS_SICK_AG_INODES, XFS_AG_GEOM_SICK_INODES },
435 { 0, 0 },
436};
437
438/* Fill out ag geometry health info. */
439void
440xfs_ag_geom_health(
441 struct xfs_perag *pag,
442 struct xfs_ag_geometry *ageo)
443{
444 const struct ioctl_sick_map *m;
445 unsigned int sick;
446 unsigned int checked;
447
448 ageo->ag_sick = 0;
449 ageo->ag_checked = 0;
450
451 xfs_ag_measure_sickness(pag, sick: &sick, checked: &checked);
452 for (m = ag_map; m->sick_mask; m++) {
453 if (checked & m->sick_mask)
454 ageo->ag_checked |= m->ioctl_mask;
455 if (sick & m->sick_mask)
456 ageo->ag_sick |= m->ioctl_mask;
457 }
458}
459
460static const struct ioctl_sick_map ino_map[] = {
461 { XFS_SICK_INO_CORE, XFS_BS_SICK_INODE },
462 { XFS_SICK_INO_BMBTD, XFS_BS_SICK_BMBTD },
463 { XFS_SICK_INO_BMBTA, XFS_BS_SICK_BMBTA },
464 { XFS_SICK_INO_BMBTC, XFS_BS_SICK_BMBTC },
465 { XFS_SICK_INO_DIR, XFS_BS_SICK_DIR },
466 { XFS_SICK_INO_XATTR, XFS_BS_SICK_XATTR },
467 { XFS_SICK_INO_SYMLINK, XFS_BS_SICK_SYMLINK },
468 { XFS_SICK_INO_PARENT, XFS_BS_SICK_PARENT },
469 { XFS_SICK_INO_BMBTD_ZAPPED, XFS_BS_SICK_BMBTD },
470 { XFS_SICK_INO_BMBTA_ZAPPED, XFS_BS_SICK_BMBTA },
471 { XFS_SICK_INO_DIR_ZAPPED, XFS_BS_SICK_DIR },
472 { XFS_SICK_INO_SYMLINK_ZAPPED, XFS_BS_SICK_SYMLINK },
473 { 0, 0 },
474};
475
476/* Fill out bulkstat health info. */
477void
478xfs_bulkstat_health(
479 struct xfs_inode *ip,
480 struct xfs_bulkstat *bs)
481{
482 const struct ioctl_sick_map *m;
483 unsigned int sick;
484 unsigned int checked;
485
486 bs->bs_sick = 0;
487 bs->bs_checked = 0;
488
489 xfs_inode_measure_sickness(ip, sick: &sick, checked: &checked);
490 for (m = ino_map; m->sick_mask; m++) {
491 if (checked & m->sick_mask)
492 bs->bs_checked |= m->ioctl_mask;
493 if (sick & m->sick_mask)
494 bs->bs_sick |= m->ioctl_mask;
495 }
496}
497
498/* Mark a block mapping sick. */
499void
500xfs_bmap_mark_sick(
501 struct xfs_inode *ip,
502 int whichfork)
503{
504 unsigned int mask;
505
506 switch (whichfork) {
507 case XFS_DATA_FORK:
508 mask = XFS_SICK_INO_BMBTD;
509 break;
510 case XFS_ATTR_FORK:
511 mask = XFS_SICK_INO_BMBTA;
512 break;
513 case XFS_COW_FORK:
514 mask = XFS_SICK_INO_BMBTC;
515 break;
516 default:
517 ASSERT(0);
518 return;
519 }
520
521 xfs_inode_mark_sick(ip, mask);
522}
523
524/* Record observations of btree corruption with the health tracking system. */
525void
526xfs_btree_mark_sick(
527 struct xfs_btree_cur *cur)
528{
529 switch (cur->bc_ops->type) {
530 case XFS_BTREE_TYPE_MEM:
531 /* no health state tracking for ephemeral btrees */
532 return;
533 case XFS_BTREE_TYPE_AG:
534 ASSERT(cur->bc_ops->sick_mask);
535 xfs_ag_mark_sick(cur->bc_ag.pag, cur->bc_ops->sick_mask);
536 return;
537 case XFS_BTREE_TYPE_INODE:
538 if (xfs_btree_is_bmap(cur->bc_ops)) {
539 xfs_bmap_mark_sick(ip: cur->bc_ino.ip,
540 whichfork: cur->bc_ino.whichfork);
541 return;
542 }
543 fallthrough;
544 default:
545 ASSERT(0);
546 return;
547 }
548}
549
550/*
551 * Record observations of dir/attr btree corruption with the health tracking
552 * system.
553 */
554void
555xfs_dirattr_mark_sick(
556 struct xfs_inode *ip,
557 int whichfork)
558{
559 unsigned int mask;
560
561 switch (whichfork) {
562 case XFS_DATA_FORK:
563 mask = XFS_SICK_INO_DIR;
564 break;
565 case XFS_ATTR_FORK:
566 mask = XFS_SICK_INO_XATTR;
567 break;
568 default:
569 ASSERT(0);
570 return;
571 }
572
573 xfs_inode_mark_sick(ip, mask);
574}
575
576/*
577 * Record observations of dir/attr btree corruption with the health tracking
578 * system.
579 */
580void
581xfs_da_mark_sick(
582 struct xfs_da_args *args)
583{
584 xfs_dirattr_mark_sick(ip: args->dp, whichfork: args->whichfork);
585}
586

source code of linux/fs/xfs/xfs_health.c