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 xfs_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;
133 assert(!debug_tweak_on("XFS_SCRUB_NO_KERNEL"));
134 assert(meta
->sm_type
< XFS_SCRUB_TYPE_NR
);
135 descr_set(&dsc
, meta
);
137 dbg_printf("check %s flags %xh\n", descr_render(&dsc
), meta
->sm_flags
);
139 error
= xfrog_scrub_metadata(&ctx
->mnt
, meta
);
140 if (debug_tweak_on("XFS_SCRUB_FORCE_REPAIR") && !error
)
141 meta
->sm_flags
|= XFS_SCRUB_OFLAG_CORRUPT
;
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
, code
, _("Kernel bug"));
169 /* Operational error. */
170 str_errno(ctx
, descr_render(&dsc
));
176 * If the kernel says the test was incomplete or that there was
177 * a cross-referencing discrepancy but no obvious corruption,
178 * we'll try the scan again, just in case the fs was busy.
179 * Only retry so many times.
181 if (tries
< 10 && (is_incomplete(meta
) ||
182 (xref_disagrees(meta
) && !is_corrupt(meta
)))) {
187 /* Complain about incomplete or suspicious metadata. */
188 xfs_scrub_warn_incomplete_scrub(ctx
, &dsc
, meta
);
191 * If we need repairs or there were discrepancies, schedule a
192 * repair if desired, otherwise complain.
194 if (is_corrupt(meta
) || xref_disagrees(meta
)) {
195 if (ctx
->mode
< SCRUB_MODE_REPAIR
) {
196 str_corrupt(ctx
, descr_render(&dsc
),
197 _("Repairs are required."));
205 * If we could optimize, schedule a repair if desired,
206 * otherwise complain.
208 if (is_unoptimized(meta
)) {
209 if (ctx
->mode
!= SCRUB_MODE_REPAIR
) {
211 /* AG or FS metadata, always warn. */
212 str_info(ctx
, descr_render(&dsc
),
213 _("Optimization is possible."));
214 } else if (!ctx
->preen_triggers
[meta
->sm_type
]) {
215 /* File metadata, only warn once per type. */
216 pthread_mutex_lock(&ctx
->lock
);
217 if (!ctx
->preen_triggers
[meta
->sm_type
])
218 ctx
->preen_triggers
[meta
->sm_type
] = true;
219 pthread_mutex_unlock(&ctx
->lock
);
227 /* Everything is ok. */
231 /* Bulk-notify user about things that could be optimized. */
233 xfs_scrub_report_preen_triggers(
234 struct scrub_ctx
*ctx
)
238 for (i
= 0; i
< XFS_SCRUB_TYPE_NR
; i
++) {
239 pthread_mutex_lock(&ctx
->lock
);
240 if (ctx
->preen_triggers
[i
]) {
241 ctx
->preen_triggers
[i
] = false;
242 pthread_mutex_unlock(&ctx
->lock
);
243 str_info(ctx
, ctx
->mntpoint
,
244 _("Optimizations of %s are possible."), _(xfrog_scrubbers
[i
].descr
));
246 pthread_mutex_unlock(&ctx
->lock
);
251 /* Save a scrub context for later repairs. */
253 xfs_scrub_save_repair(
254 struct scrub_ctx
*ctx
,
255 struct xfs_action_list
*alist
,
256 struct xfs_scrub_metadata
*meta
)
258 struct action_item
*aitem
;
260 /* Schedule this item for later repairs. */
261 aitem
= malloc(sizeof(struct action_item
));
263 str_errno(ctx
, _("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 xfs_action_list_add(alist
, aitem
);
286 /* Scrub a single XFS_SCRUB_TYPE_*, saving corruption reports for later. */
289 struct scrub_ctx
*ctx
,
292 struct xfs_action_list
*alist
)
294 struct xfs_scrub_metadata meta
= {
298 enum check_outcome fix
;
302 /* Check the item. */
303 fix
= xfs_check_metadata(ctx
, &meta
, false);
310 if (!xfs_scrub_save_repair(ctx
, alist
, &meta
))
316 /* CHECK_RETRY should never happen. */
322 * Scrub all metadata types that are assigned to the given XFROG_SCRUB_TYPE_*,
323 * saving corruption reports for later. This should not be used for
324 * XFROG_SCRUB_TYPE_INODE or for checking summary metadata.
328 struct scrub_ctx
*ctx
,
329 enum xfrog_scrub_type scrub_type
,
331 struct xfs_action_list
*alist
)
333 const struct xfrog_scrub_descr
*sc
;
336 sc
= xfrog_scrubbers
;
337 for (type
= 0; type
< XFS_SCRUB_TYPE_NR
; type
++, sc
++) {
340 if (sc
->type
!= scrub_type
)
342 if (sc
->flags
& XFROG_SCRUB_DESCR_SUMMARY
)
345 ret
= xfs_scrub_meta_type(ctx
, type
, agno
, alist
);
354 * Scrub primary superblock. This will be useful if we ever need to hook
355 * a filesystem-wide pre-scrub activity off of the sb 0 scrubber (which
356 * currently does nothing).
359 xfs_scrub_primary_super(
360 struct scrub_ctx
*ctx
,
361 struct xfs_action_list
*alist
)
365 ret
= xfs_scrub_meta_type(ctx
, XFS_SCRUB_TYPE_SB
, 0, alist
);
369 /* Scrub each AG's header blocks. */
371 xfs_scrub_ag_headers(
372 struct scrub_ctx
*ctx
,
374 struct xfs_action_list
*alist
)
376 return xfs_scrub_all_types(ctx
, XFROG_SCRUB_TYPE_AGHEADER
, agno
, alist
);
379 /* Scrub each AG's metadata btrees. */
381 xfs_scrub_ag_metadata(
382 struct scrub_ctx
*ctx
,
384 struct xfs_action_list
*alist
)
386 return xfs_scrub_all_types(ctx
, XFROG_SCRUB_TYPE_PERAG
, agno
, alist
);
389 /* Scrub whole-FS metadata btrees. */
391 xfs_scrub_fs_metadata(
392 struct scrub_ctx
*ctx
,
393 struct xfs_action_list
*alist
)
395 return xfs_scrub_all_types(ctx
, XFROG_SCRUB_TYPE_FS
, 0, alist
);
398 /* Scrub FS summary metadata. */
400 xfs_scrub_fs_summary(
401 struct scrub_ctx
*ctx
,
402 struct xfs_action_list
*alist
)
406 ret
= xfs_scrub_meta_type(ctx
, XFS_SCRUB_TYPE_FSCOUNTERS
, 0, alist
);
410 /* How many items do we have to check? */
412 xfs_scrub_estimate_ag_work(
413 struct scrub_ctx
*ctx
)
415 const struct xfrog_scrub_descr
*sc
;
417 unsigned int estimate
= 0;
419 sc
= xfrog_scrubbers
;
420 for (type
= 0; type
< XFS_SCRUB_TYPE_NR
; type
++, sc
++) {
422 case XFROG_SCRUB_TYPE_AGHEADER
:
423 case XFROG_SCRUB_TYPE_PERAG
:
424 estimate
+= ctx
->mnt
.fsgeom
.agcount
;
426 case XFROG_SCRUB_TYPE_FS
:
436 /* Scrub inode metadata. */
439 struct scrub_ctx
*ctx
,
443 struct xfs_action_list
*alist
)
445 struct xfs_scrub_metadata meta
= {0};
446 enum check_outcome fix
;
448 assert(type
< XFS_SCRUB_TYPE_NR
);
449 assert(xfrog_scrubbers
[type
].type
== XFROG_SCRUB_TYPE_INODE
);
455 /* Scrub the piece of metadata. */
456 fix
= xfs_check_metadata(ctx
, &meta
, true);
457 if (fix
== CHECK_ABORT
)
459 if (fix
== CHECK_DONE
)
462 return xfs_scrub_save_repair(ctx
, alist
, &meta
);
466 xfs_scrub_inode_fields(
467 struct scrub_ctx
*ctx
,
470 struct xfs_action_list
*alist
)
472 return __xfs_scrub_file(ctx
, ino
, gen
, XFS_SCRUB_TYPE_INODE
, alist
);
477 struct scrub_ctx
*ctx
,
480 struct xfs_action_list
*alist
)
482 return __xfs_scrub_file(ctx
, ino
, gen
, XFS_SCRUB_TYPE_BMBTD
, alist
);
487 struct scrub_ctx
*ctx
,
490 struct xfs_action_list
*alist
)
492 return __xfs_scrub_file(ctx
, ino
, gen
, XFS_SCRUB_TYPE_BMBTA
, alist
);
497 struct scrub_ctx
*ctx
,
500 struct xfs_action_list
*alist
)
502 return __xfs_scrub_file(ctx
, ino
, gen
, XFS_SCRUB_TYPE_BMBTC
, alist
);
507 struct scrub_ctx
*ctx
,
510 struct xfs_action_list
*alist
)
512 return __xfs_scrub_file(ctx
, ino
, gen
, XFS_SCRUB_TYPE_DIR
, alist
);
517 struct scrub_ctx
*ctx
,
520 struct xfs_action_list
*alist
)
522 return __xfs_scrub_file(ctx
, ino
, gen
, XFS_SCRUB_TYPE_XATTR
, alist
);
527 struct scrub_ctx
*ctx
,
530 struct xfs_action_list
*alist
)
532 return __xfs_scrub_file(ctx
, ino
, gen
, XFS_SCRUB_TYPE_SYMLINK
, alist
);
537 struct scrub_ctx
*ctx
,
540 struct xfs_action_list
*alist
)
542 return __xfs_scrub_file(ctx
, ino
, gen
, XFS_SCRUB_TYPE_PARENT
, alist
);
545 /* Test the availability of a kernel scrub command. */
548 struct scrub_ctx
*ctx
,
552 struct xfs_scrub_metadata meta
= {0};
553 struct xfs_error_injection inject
;
554 static bool injected
;
557 if (debug_tweak_on("XFS_SCRUB_NO_KERNEL"))
559 if (debug_tweak_on("XFS_SCRUB_FORCE_REPAIR") && !injected
) {
560 inject
.fd
= ctx
->mnt
.fd
;
561 inject
.errtag
= XFS_ERRTAG_FORCE_SCRUB_REPAIR
;
562 error
= ioctl(ctx
->mnt
.fd
, XFS_IOC_ERROR_INJECTION
, &inject
);
569 meta
.sm_flags
|= XFS_SCRUB_IFLAG_REPAIR
;
570 error
= xfrog_scrub_metadata(&ctx
->mnt
, &meta
);
575 str_info(ctx
, ctx
->mntpoint
,
576 _("Filesystem is mounted read-only; cannot proceed."));
578 case ENOTRECOVERABLE
:
579 str_info(ctx
, ctx
->mntpoint
,
580 _("Filesystem is mounted norecovery; cannot proceed."));
584 if (debug
|| verbose
)
585 str_info(ctx
, ctx
->mntpoint
,
586 _("Kernel %s %s facility not detected."),
587 _(xfrog_scrubbers
[type
].descr
),
588 repair
? _("repair") : _("scrub"));
591 /* Scrubber says not present on this fs; that's fine. */
594 str_info(ctx
, ctx
->mntpoint
, "%s", strerror(errno
));
600 xfs_can_scrub_fs_metadata(
601 struct scrub_ctx
*ctx
)
603 return __xfs_scrub_test(ctx
, XFS_SCRUB_TYPE_PROBE
, false);
608 struct scrub_ctx
*ctx
)
610 return __xfs_scrub_test(ctx
, XFS_SCRUB_TYPE_INODE
, false);
615 struct scrub_ctx
*ctx
)
617 return __xfs_scrub_test(ctx
, XFS_SCRUB_TYPE_BMBTD
, false);
622 struct scrub_ctx
*ctx
)
624 return __xfs_scrub_test(ctx
, XFS_SCRUB_TYPE_DIR
, false);
629 struct scrub_ctx
*ctx
)
631 return __xfs_scrub_test(ctx
, XFS_SCRUB_TYPE_XATTR
, false);
635 xfs_can_scrub_symlink(
636 struct scrub_ctx
*ctx
)
638 return __xfs_scrub_test(ctx
, XFS_SCRUB_TYPE_SYMLINK
, false);
642 xfs_can_scrub_parent(
643 struct scrub_ctx
*ctx
)
645 return __xfs_scrub_test(ctx
, XFS_SCRUB_TYPE_PARENT
, false);
650 struct scrub_ctx
*ctx
)
652 return __xfs_scrub_test(ctx
, XFS_SCRUB_TYPE_PROBE
, true);
655 /* General repair routines. */
657 /* Repair some metadata. */
660 struct scrub_ctx
*ctx
,
662 struct action_item
*aitem
,
663 unsigned int repair_flags
)
665 struct xfs_scrub_metadata meta
= { 0 };
666 struct xfs_scrub_metadata oldm
;
667 DEFINE_DESCR(dsc
, ctx
, format_scrub_descr
);
670 assert(aitem
->type
< XFS_SCRUB_TYPE_NR
);
671 assert(!debug_tweak_on("XFS_SCRUB_NO_KERNEL"));
672 meta
.sm_type
= aitem
->type
;
673 meta
.sm_flags
= aitem
->flags
| XFS_SCRUB_IFLAG_REPAIR
;
674 switch (xfrog_scrubbers
[aitem
->type
].type
) {
675 case XFROG_SCRUB_TYPE_AGHEADER
:
676 case XFROG_SCRUB_TYPE_PERAG
:
677 meta
.sm_agno
= aitem
->agno
;
679 case XFROG_SCRUB_TYPE_INODE
:
680 meta
.sm_ino
= aitem
->ino
;
681 meta
.sm_gen
= aitem
->gen
;
687 if (!is_corrupt(&meta
) && (repair_flags
& XRM_REPAIR_ONLY
))
690 memcpy(&oldm
, &meta
, sizeof(oldm
));
691 descr_set(&dsc
, &oldm
);
693 if (needs_repair(&meta
))
694 str_info(ctx
, descr_render(&dsc
), _("Attempting repair."));
695 else if (debug
|| verbose
)
696 str_info(ctx
, descr_render(&dsc
),
697 _("Attempting optimization."));
699 error
= xfrog_scrub_metadata(&ctx
->mnt
, &meta
);
704 /* Filesystem is busy, try again later. */
705 if (debug
|| verbose
)
706 str_info(ctx
, descr_render(&dsc
),
707 _("Filesystem is busy, deferring repair."));
710 /* Filesystem is already shut down, abort. */
711 str_error(ctx
, descr_render(&dsc
),
712 _("Filesystem is shut down, aborting."));
717 * If we're in no-complain mode, requeue the check for
718 * later. It's possible that an error in another
719 * component caused us to flag an error in this
720 * component. Even if the kernel didn't think it
721 * could fix this, it's at least worth trying the scan
722 * again to see if another repair fixed it.
724 if (!(repair_flags
& XRM_COMPLAIN_IF_UNFIXED
))
727 * If we forced repairs or this is a preen, don't
728 * error out if the kernel doesn't know how to fix.
730 if (is_unoptimized(&oldm
) ||
731 debug_tweak_on("XFS_SCRUB_FORCE_REPAIR"))
735 /* Kernel doesn't know how to repair this? */
736 str_corrupt(ctx
, descr_render(&dsc
),
737 _("Don't know how to fix; offline repair required."));
740 /* Read-only filesystem, can't fix. */
741 if (verbose
|| debug
|| needs_repair(&oldm
))
742 str_error(ctx
, descr_render(&dsc
),
743 _("Read-only filesystem; cannot make changes."));
746 /* Metadata not present, just skip it. */
750 /* Don't care if preen fails due to low resources. */
751 if (is_unoptimized(&oldm
) && !needs_repair(&oldm
))
756 * Operational error. If the caller doesn't want us
757 * to complain about repair failures, tell the caller
758 * to requeue the repair for later and don't say a
759 * thing. Otherwise, print error and bail out.
761 if (!(repair_flags
& XRM_COMPLAIN_IF_UNFIXED
))
763 str_errno(ctx
, descr_render(&dsc
));
767 if (repair_flags
& XRM_COMPLAIN_IF_UNFIXED
)
768 xfs_scrub_warn_incomplete_scrub(ctx
, &dsc
, &meta
);
769 if (needs_repair(&meta
)) {
771 * Still broken; if we've been told not to complain then we
772 * just requeue this and try again later. Otherwise we
773 * log the error loudly and don't try again.
775 if (!(repair_flags
& XRM_COMPLAIN_IF_UNFIXED
))
777 str_corrupt(ctx
, descr_render(&dsc
),
778 _("Repair unsuccessful; offline repair required."));
780 /* Clean operation, no corruption detected. */
781 if (needs_repair(&oldm
))
782 record_repair(ctx
, descr_render(&dsc
),
783 _("Repairs successful."));
785 record_preen(ctx
, descr_render(&dsc
),
786 _("Optimization successful."));