1 // SPDX-License-Identifier: GPL-2.0+
3 * Copyright (C) 2018 Oracle. All Rights Reserved.
4 * Author: Darrick J. Wong <darrick.wong@oracle.com>
11 #include <sys/types.h>
12 #include <sys/statvfs.h>
14 #include "libfrog/paths.h"
15 #include "libfrog/fsgeom.h"
16 #include "libfrog/scrub.h"
17 #include "xfs_scrub.h"
21 #include "xfs_errortag.h"
25 /* Online scrub and repair wrappers. */
27 /* Format a scrub description. */
30 struct scrub_ctx
*ctx
,
35 struct xfs_scrub_metadata
*meta
= where
;
36 const struct xfrog_scrub_descr
*sc
= &xfrog_scrubbers
[meta
->sm_type
];
39 case XFROG_SCRUB_TYPE_AGHEADER
:
40 case XFROG_SCRUB_TYPE_PERAG
:
41 return snprintf(buf
, buflen
, _("AG %u %s"), meta
->sm_agno
,
44 case XFROG_SCRUB_TYPE_INODE
:
45 return scrub_render_ino_descr(ctx
, buf
, buflen
,
46 meta
->sm_ino
, meta
->sm_gen
, "%s",
49 case XFROG_SCRUB_TYPE_FS
:
50 return snprintf(buf
, buflen
, _("%s"), _(sc
->descr
));
52 case XFROG_SCRUB_TYPE_NONE
:
59 /* Predicates for scrub flag state. */
61 static inline bool is_corrupt(struct xfs_scrub_metadata
*sm
)
63 return sm
->sm_flags
& XFS_SCRUB_OFLAG_CORRUPT
;
66 static inline bool is_unoptimized(struct xfs_scrub_metadata
*sm
)
68 return sm
->sm_flags
& XFS_SCRUB_OFLAG_PREEN
;
71 static inline bool xref_failed(struct xfs_scrub_metadata
*sm
)
73 return sm
->sm_flags
& XFS_SCRUB_OFLAG_XFAIL
;
76 static inline bool xref_disagrees(struct xfs_scrub_metadata
*sm
)
78 return sm
->sm_flags
& XFS_SCRUB_OFLAG_XCORRUPT
;
81 static inline bool is_incomplete(struct xfs_scrub_metadata
*sm
)
83 return sm
->sm_flags
& XFS_SCRUB_OFLAG_INCOMPLETE
;
86 static inline bool is_suspicious(struct xfs_scrub_metadata
*sm
)
88 return sm
->sm_flags
& XFS_SCRUB_OFLAG_WARNING
;
91 /* Should we fix it? */
92 static inline bool needs_repair(struct xfs_scrub_metadata
*sm
)
94 return is_corrupt(sm
) || xref_disagrees(sm
);
97 /* Warn about strange circumstances after scrub. */
99 scrub_warn_incomplete_scrub(
100 struct scrub_ctx
*ctx
,
102 struct xfs_scrub_metadata
*meta
)
104 if (is_incomplete(meta
))
105 str_info(ctx
, descr_render(dsc
), _("Check incomplete."));
107 if (is_suspicious(meta
)) {
109 str_info(ctx
, descr_render(dsc
),
110 _("Possibly suspect metadata."));
112 str_warn(ctx
, descr_render(dsc
),
113 _("Possibly suspect metadata."));
116 if (xref_failed(meta
))
117 str_info(ctx
, descr_render(dsc
),
118 _("Cross-referencing failed."));
121 /* Do a read-only check of some metadata. */
122 static enum check_outcome
124 struct scrub_ctx
*ctx
,
125 struct xfs_scrub_metadata
*meta
,
128 DEFINE_DESCR(dsc
, ctx
, format_scrub_descr
);
129 unsigned int tries
= 0;
132 assert(!debug_tweak_on("XFS_SCRUB_NO_KERNEL"));
133 assert(meta
->sm_type
< XFS_SCRUB_TYPE_NR
);
134 descr_set(&dsc
, meta
);
136 dbg_printf("check %s flags %xh\n", descr_render(&dsc
), meta
->sm_flags
);
138 error
= -xfrog_scrub_metadata(&ctx
->mnt
, meta
);
139 if (debug_tweak_on("XFS_SCRUB_FORCE_REPAIR") && !error
)
140 meta
->sm_flags
|= XFS_SCRUB_OFLAG_CORRUPT
;
143 /* No operational errors encountered. */
146 /* Metadata not present, just skip it. */
149 /* FS already crashed, give up. */
150 str_error(ctx
, descr_render(&dsc
),
151 _("Filesystem is shut down, aborting."));
155 /* Abort on I/O errors or insufficient memory. */
156 str_errno(ctx
, descr_render(&dsc
));
163 * The first two should never escape the kernel,
164 * and the other two should be reported via sm_flags.
166 str_liberror(ctx
, error
, _("Kernel bug"));
169 /* Operational error. */
170 str_errno(ctx
, descr_render(&dsc
));
175 * If the kernel says the test was incomplete or that there was
176 * a cross-referencing discrepancy but no obvious corruption,
177 * we'll try the scan again, just in case the fs was busy.
178 * Only retry so many times.
180 if (tries
< 10 && (is_incomplete(meta
) ||
181 (xref_disagrees(meta
) && !is_corrupt(meta
)))) {
186 /* Complain about incomplete or suspicious metadata. */
187 scrub_warn_incomplete_scrub(ctx
, &dsc
, meta
);
190 * If we need repairs or there were discrepancies, schedule a
191 * repair if desired, otherwise complain.
193 if (is_corrupt(meta
) || xref_disagrees(meta
)) {
194 if (ctx
->mode
< SCRUB_MODE_REPAIR
) {
195 str_corrupt(ctx
, descr_render(&dsc
),
196 _("Repairs are required."));
204 * If we could optimize, schedule a repair if desired,
205 * otherwise complain.
207 if (is_unoptimized(meta
)) {
208 if (ctx
->mode
!= SCRUB_MODE_REPAIR
) {
210 /* AG or FS metadata, always warn. */
211 str_info(ctx
, descr_render(&dsc
),
212 _("Optimization is possible."));
213 } else if (!ctx
->preen_triggers
[meta
->sm_type
]) {
214 /* File metadata, only warn once per type. */
215 pthread_mutex_lock(&ctx
->lock
);
216 if (!ctx
->preen_triggers
[meta
->sm_type
])
217 ctx
->preen_triggers
[meta
->sm_type
] = true;
218 pthread_mutex_unlock(&ctx
->lock
);
226 /* Everything is ok. */
230 /* Bulk-notify user about things that could be optimized. */
232 scrub_report_preen_triggers(
233 struct scrub_ctx
*ctx
)
237 for (i
= 0; i
< XFS_SCRUB_TYPE_NR
; i
++) {
238 pthread_mutex_lock(&ctx
->lock
);
239 if (ctx
->preen_triggers
[i
]) {
240 ctx
->preen_triggers
[i
] = false;
241 pthread_mutex_unlock(&ctx
->lock
);
242 str_info(ctx
, ctx
->mntpoint
,
243 _("Optimizations of %s are possible."), _(xfrog_scrubbers
[i
].descr
));
245 pthread_mutex_unlock(&ctx
->lock
);
250 /* Save a scrub context for later repairs. */
253 struct scrub_ctx
*ctx
,
254 struct action_list
*alist
,
255 struct xfs_scrub_metadata
*meta
)
257 struct action_item
*aitem
;
259 /* Schedule this item for later repairs. */
260 aitem
= malloc(sizeof(struct action_item
));
262 str_errno(ctx
, _("adding item to repair list"));
266 memset(aitem
, 0, sizeof(*aitem
));
267 aitem
->type
= meta
->sm_type
;
268 aitem
->flags
= meta
->sm_flags
;
269 switch (xfrog_scrubbers
[meta
->sm_type
].type
) {
270 case XFROG_SCRUB_TYPE_AGHEADER
:
271 case XFROG_SCRUB_TYPE_PERAG
:
272 aitem
->agno
= meta
->sm_agno
;
274 case XFROG_SCRUB_TYPE_INODE
:
275 aitem
->ino
= meta
->sm_ino
;
276 aitem
->gen
= meta
->sm_gen
;
282 action_list_add(alist
, aitem
);
287 * Scrub a single XFS_SCRUB_TYPE_*, saving corruption reports for later.
289 * Returns 0 for success. If errors occur, this function will log them and
290 * return a positive error code.
294 struct scrub_ctx
*ctx
,
297 struct action_list
*alist
)
299 struct xfs_scrub_metadata meta
= {
303 enum check_outcome fix
;
308 /* Check the item. */
309 fix
= xfs_check_metadata(ctx
, &meta
, false);
316 ret
= scrub_save_repair(ctx
, alist
, &meta
);
323 /* CHECK_RETRY should never happen. */
329 * Scrub all metadata types that are assigned to the given XFROG_SCRUB_TYPE_*,
330 * saving corruption reports for later. This should not be used for
331 * XFROG_SCRUB_TYPE_INODE or for checking summary metadata.
335 struct scrub_ctx
*ctx
,
336 enum xfrog_scrub_type scrub_type
,
338 struct action_list
*alist
)
340 const struct xfrog_scrub_descr
*sc
;
343 sc
= xfrog_scrubbers
;
344 for (type
= 0; type
< XFS_SCRUB_TYPE_NR
; type
++, sc
++) {
347 if (sc
->type
!= scrub_type
)
349 if (sc
->flags
& XFROG_SCRUB_DESCR_SUMMARY
)
352 ret
= scrub_meta_type(ctx
, type
, agno
, alist
);
361 * Scrub primary superblock. This will be useful if we ever need to hook
362 * a filesystem-wide pre-scrub activity off of the sb 0 scrubber (which
363 * currently does nothing). If errors occur, this function will log them and
368 struct scrub_ctx
*ctx
,
369 struct action_list
*alist
)
371 return scrub_meta_type(ctx
, XFS_SCRUB_TYPE_SB
, 0, alist
);
374 /* Scrub each AG's header blocks. */
377 struct scrub_ctx
*ctx
,
379 struct action_list
*alist
)
381 return scrub_all_types(ctx
, XFROG_SCRUB_TYPE_AGHEADER
, agno
, alist
);
384 /* Scrub each AG's metadata btrees. */
387 struct scrub_ctx
*ctx
,
389 struct action_list
*alist
)
391 return scrub_all_types(ctx
, XFROG_SCRUB_TYPE_PERAG
, agno
, alist
);
394 /* Scrub whole-FS metadata btrees. */
397 struct scrub_ctx
*ctx
,
398 struct action_list
*alist
)
400 return scrub_all_types(ctx
, XFROG_SCRUB_TYPE_FS
, 0, alist
);
403 /* Scrub FS summary metadata. */
406 struct scrub_ctx
*ctx
,
407 struct action_list
*alist
)
409 return scrub_meta_type(ctx
, XFS_SCRUB_TYPE_FSCOUNTERS
, 0, alist
);
412 /* How many items do we have to check? */
414 scrub_estimate_ag_work(
415 struct scrub_ctx
*ctx
)
417 const struct xfrog_scrub_descr
*sc
;
419 unsigned int estimate
= 0;
421 sc
= xfrog_scrubbers
;
422 for (type
= 0; type
< XFS_SCRUB_TYPE_NR
; type
++, sc
++) {
424 case XFROG_SCRUB_TYPE_AGHEADER
:
425 case XFROG_SCRUB_TYPE_PERAG
:
426 estimate
+= ctx
->mnt
.fsgeom
.agcount
;
428 case XFROG_SCRUB_TYPE_FS
:
439 * Scrub inode metadata. If errors occur, this function will log them and
444 struct scrub_ctx
*ctx
,
448 struct action_list
*alist
)
450 struct xfs_scrub_metadata meta
= {0};
451 enum check_outcome fix
;
453 assert(type
< XFS_SCRUB_TYPE_NR
);
454 assert(xfrog_scrubbers
[type
].type
== XFROG_SCRUB_TYPE_INODE
);
460 /* Scrub the piece of metadata. */
461 fix
= xfs_check_metadata(ctx
, &meta
, true);
462 if (fix
== CHECK_ABORT
)
464 if (fix
== CHECK_DONE
)
467 return scrub_save_repair(ctx
, alist
, &meta
);
472 struct scrub_ctx
*ctx
,
475 struct action_list
*alist
)
477 return __scrub_file(ctx
, ino
, gen
, XFS_SCRUB_TYPE_INODE
, alist
);
482 struct scrub_ctx
*ctx
,
485 struct action_list
*alist
)
487 return __scrub_file(ctx
, ino
, gen
, XFS_SCRUB_TYPE_BMBTD
, alist
);
492 struct scrub_ctx
*ctx
,
495 struct action_list
*alist
)
497 return __scrub_file(ctx
, ino
, gen
, XFS_SCRUB_TYPE_BMBTA
, alist
);
502 struct scrub_ctx
*ctx
,
505 struct action_list
*alist
)
507 return __scrub_file(ctx
, ino
, gen
, XFS_SCRUB_TYPE_BMBTC
, alist
);
512 struct scrub_ctx
*ctx
,
515 struct action_list
*alist
)
517 return __scrub_file(ctx
, ino
, gen
, XFS_SCRUB_TYPE_DIR
, alist
);
522 struct scrub_ctx
*ctx
,
525 struct action_list
*alist
)
527 return __scrub_file(ctx
, ino
, gen
, XFS_SCRUB_TYPE_XATTR
, alist
);
532 struct scrub_ctx
*ctx
,
535 struct action_list
*alist
)
537 return __scrub_file(ctx
, ino
, gen
, XFS_SCRUB_TYPE_SYMLINK
, alist
);
542 struct scrub_ctx
*ctx
,
545 struct action_list
*alist
)
547 return __scrub_file(ctx
, ino
, gen
, XFS_SCRUB_TYPE_PARENT
, alist
);
551 * Test the availability of a kernel scrub command. If errors occur (or the
552 * scrub ioctl is rejected) the errors will be logged and this function will
557 struct scrub_ctx
*ctx
,
561 struct xfs_scrub_metadata meta
= {0};
562 struct xfs_error_injection inject
;
563 static bool injected
;
566 if (debug_tweak_on("XFS_SCRUB_NO_KERNEL"))
568 if (debug_tweak_on("XFS_SCRUB_FORCE_REPAIR") && !injected
) {
569 inject
.fd
= ctx
->mnt
.fd
;
570 inject
.errtag
= XFS_ERRTAG_FORCE_SCRUB_REPAIR
;
571 error
= ioctl(ctx
->mnt
.fd
, XFS_IOC_ERROR_INJECTION
, &inject
);
578 meta
.sm_flags
|= XFS_SCRUB_IFLAG_REPAIR
;
579 error
= -xfrog_scrub_metadata(&ctx
->mnt
, &meta
);
584 str_info(ctx
, ctx
->mntpoint
,
585 _("Filesystem is mounted read-only; cannot proceed."));
587 case ENOTRECOVERABLE
:
588 str_info(ctx
, ctx
->mntpoint
,
589 _("Filesystem is mounted norecovery; cannot proceed."));
593 if (debug
|| verbose
)
594 str_info(ctx
, ctx
->mntpoint
,
595 _("Kernel %s %s facility not detected."),
596 _(xfrog_scrubbers
[type
].descr
),
597 repair
? _("repair") : _("scrub"));
600 /* Scrubber says not present on this fs; that's fine. */
603 str_info(ctx
, ctx
->mntpoint
, "%s", strerror(errno
));
609 can_scrub_fs_metadata(
610 struct scrub_ctx
*ctx
)
612 return __scrub_test(ctx
, XFS_SCRUB_TYPE_PROBE
, false);
617 struct scrub_ctx
*ctx
)
619 return __scrub_test(ctx
, XFS_SCRUB_TYPE_INODE
, false);
624 struct scrub_ctx
*ctx
)
626 return __scrub_test(ctx
, XFS_SCRUB_TYPE_BMBTD
, false);
631 struct scrub_ctx
*ctx
)
633 return __scrub_test(ctx
, XFS_SCRUB_TYPE_DIR
, false);
638 struct scrub_ctx
*ctx
)
640 return __scrub_test(ctx
, XFS_SCRUB_TYPE_XATTR
, false);
645 struct scrub_ctx
*ctx
)
647 return __scrub_test(ctx
, XFS_SCRUB_TYPE_SYMLINK
, false);
652 struct scrub_ctx
*ctx
)
654 return __scrub_test(ctx
, XFS_SCRUB_TYPE_PARENT
, false);
659 struct scrub_ctx
*ctx
)
661 return __scrub_test(ctx
, XFS_SCRUB_TYPE_PROBE
, true);
664 /* General repair routines. */
666 /* Repair some metadata. */
669 struct scrub_ctx
*ctx
,
671 struct action_item
*aitem
,
672 unsigned int repair_flags
)
674 struct xfs_scrub_metadata meta
= { 0 };
675 struct xfs_scrub_metadata oldm
;
676 DEFINE_DESCR(dsc
, ctx
, format_scrub_descr
);
679 assert(aitem
->type
< XFS_SCRUB_TYPE_NR
);
680 assert(!debug_tweak_on("XFS_SCRUB_NO_KERNEL"));
681 meta
.sm_type
= aitem
->type
;
682 meta
.sm_flags
= aitem
->flags
| XFS_SCRUB_IFLAG_REPAIR
;
683 switch (xfrog_scrubbers
[aitem
->type
].type
) {
684 case XFROG_SCRUB_TYPE_AGHEADER
:
685 case XFROG_SCRUB_TYPE_PERAG
:
686 meta
.sm_agno
= aitem
->agno
;
688 case XFROG_SCRUB_TYPE_INODE
:
689 meta
.sm_ino
= aitem
->ino
;
690 meta
.sm_gen
= aitem
->gen
;
696 if (!is_corrupt(&meta
) && (repair_flags
& XRM_REPAIR_ONLY
))
699 memcpy(&oldm
, &meta
, sizeof(oldm
));
700 descr_set(&dsc
, &oldm
);
702 if (needs_repair(&meta
))
703 str_info(ctx
, descr_render(&dsc
), _("Attempting repair."));
704 else if (debug
|| verbose
)
705 str_info(ctx
, descr_render(&dsc
),
706 _("Attempting optimization."));
708 error
= -xfrog_scrub_metadata(&ctx
->mnt
, &meta
);
711 /* No operational errors encountered. */
715 /* Filesystem is busy, try again later. */
716 if (debug
|| verbose
)
717 str_info(ctx
, descr_render(&dsc
),
718 _("Filesystem is busy, deferring repair."));
721 /* Filesystem is already shut down, abort. */
722 str_error(ctx
, descr_render(&dsc
),
723 _("Filesystem is shut down, aborting."));
728 * If we're in no-complain mode, requeue the check for
729 * later. It's possible that an error in another
730 * component caused us to flag an error in this
731 * component. Even if the kernel didn't think it
732 * could fix this, it's at least worth trying the scan
733 * again to see if another repair fixed it.
735 if (!(repair_flags
& XRM_COMPLAIN_IF_UNFIXED
))
738 * If we forced repairs or this is a preen, don't
739 * error out if the kernel doesn't know how to fix.
741 if (is_unoptimized(&oldm
) ||
742 debug_tweak_on("XFS_SCRUB_FORCE_REPAIR"))
746 /* Kernel doesn't know how to repair this? */
747 str_corrupt(ctx
, descr_render(&dsc
),
748 _("Don't know how to fix; offline repair required."));
751 /* Read-only filesystem, can't fix. */
752 if (verbose
|| debug
|| needs_repair(&oldm
))
753 str_error(ctx
, descr_render(&dsc
),
754 _("Read-only filesystem; cannot make changes."));
757 /* Metadata not present, just skip it. */
761 /* Don't care if preen fails due to low resources. */
762 if (is_unoptimized(&oldm
) && !needs_repair(&oldm
))
767 * Operational error. If the caller doesn't want us
768 * to complain about repair failures, tell the caller
769 * to requeue the repair for later and don't say a
770 * thing. Otherwise, print error and bail out.
772 if (!(repair_flags
& XRM_COMPLAIN_IF_UNFIXED
))
774 str_liberror(ctx
, error
, descr_render(&dsc
));
778 if (repair_flags
& XRM_COMPLAIN_IF_UNFIXED
)
779 scrub_warn_incomplete_scrub(ctx
, &dsc
, &meta
);
780 if (needs_repair(&meta
)) {
782 * Still broken; if we've been told not to complain then we
783 * just requeue this and try again later. Otherwise we
784 * log the error loudly and don't try again.
786 if (!(repair_flags
& XRM_COMPLAIN_IF_UNFIXED
))
788 str_corrupt(ctx
, descr_render(&dsc
),
789 _("Repair unsuccessful; offline repair required."));
791 /* Clean operation, no corruption detected. */
792 if (needs_repair(&oldm
))
793 record_repair(ctx
, descr_render(&dsc
),
794 _("Repairs successful."));
796 record_preen(ctx
, descr_render(&dsc
),
797 _("Optimization successful."));