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>
15 #include "xfs_scrub.h"
19 #include "xfs_errortag.h"
22 /* Online scrub and repair wrappers. */
24 /* Type info and names for the scrub types. */
26 ST_NONE
, /* disabled */
27 ST_AGHEADER
, /* per-AG header */
28 ST_PERAG
, /* per-AG metadata */
29 ST_FS
, /* per-FS metadata */
30 ST_INODE
, /* per-inode metadata */
37 /* These must correspond to XFS_SCRUB_TYPE_ */
38 static const struct scrub_descr scrubbers
[XFS_SCRUB_TYPE_NR
] = {
39 [XFS_SCRUB_TYPE_PROBE
] =
40 {"metadata", ST_NONE
},
42 {"superblock", ST_AGHEADER
},
43 [XFS_SCRUB_TYPE_AGF
] =
44 {"free space header", ST_AGHEADER
},
45 [XFS_SCRUB_TYPE_AGFL
] =
46 {"free list", ST_AGHEADER
},
47 [XFS_SCRUB_TYPE_AGI
] =
48 {"inode header", ST_AGHEADER
},
49 [XFS_SCRUB_TYPE_BNOBT
] =
50 {"freesp by block btree", ST_PERAG
},
51 [XFS_SCRUB_TYPE_CNTBT
] =
52 {"freesp by length btree", ST_PERAG
},
53 [XFS_SCRUB_TYPE_INOBT
] =
54 {"inode btree", ST_PERAG
},
55 [XFS_SCRUB_TYPE_FINOBT
] =
56 {"free inode btree", ST_PERAG
},
57 [XFS_SCRUB_TYPE_RMAPBT
] =
58 {"reverse mapping btree", ST_PERAG
},
59 [XFS_SCRUB_TYPE_REFCNTBT
] =
60 {"reference count btree", ST_PERAG
},
61 [XFS_SCRUB_TYPE_INODE
] =
62 {"inode record", ST_INODE
},
63 [XFS_SCRUB_TYPE_BMBTD
] =
64 {"data block map", ST_INODE
},
65 [XFS_SCRUB_TYPE_BMBTA
] =
66 {"attr block map", ST_INODE
},
67 [XFS_SCRUB_TYPE_BMBTC
] =
68 {"CoW block map", ST_INODE
},
69 [XFS_SCRUB_TYPE_DIR
] =
70 {"directory entries", ST_INODE
},
71 [XFS_SCRUB_TYPE_XATTR
] =
72 {"extended attributes", ST_INODE
},
73 [XFS_SCRUB_TYPE_SYMLINK
] =
74 {"symbolic link", ST_INODE
},
75 [XFS_SCRUB_TYPE_PARENT
] =
76 {"parent pointer", ST_INODE
},
77 [XFS_SCRUB_TYPE_RTBITMAP
] =
78 {"realtime bitmap", ST_FS
},
79 [XFS_SCRUB_TYPE_RTSUM
] =
80 {"realtime summary", ST_FS
},
81 [XFS_SCRUB_TYPE_UQUOTA
] =
82 {"user quotas", ST_FS
},
83 [XFS_SCRUB_TYPE_GQUOTA
] =
84 {"group quotas", ST_FS
},
85 [XFS_SCRUB_TYPE_PQUOTA
] =
86 {"project quotas", ST_FS
},
89 /* Format a scrub description. */
94 struct xfs_scrub_metadata
*meta
,
95 const struct scrub_descr
*sc
)
100 snprintf(buf
, buflen
, _("AG %u %s"), meta
->sm_agno
,
104 snprintf(buf
, buflen
, _("Inode %"PRIu64
" %s"),
105 (uint64_t)meta
->sm_ino
, _(sc
->name
));
108 snprintf(buf
, buflen
, _("%s"), _(sc
->name
));
116 /* Predicates for scrub flag state. */
118 static inline bool is_corrupt(struct xfs_scrub_metadata
*sm
)
120 return sm
->sm_flags
& XFS_SCRUB_OFLAG_CORRUPT
;
123 static inline bool is_unoptimized(struct xfs_scrub_metadata
*sm
)
125 return sm
->sm_flags
& XFS_SCRUB_OFLAG_PREEN
;
128 static inline bool xref_failed(struct xfs_scrub_metadata
*sm
)
130 return sm
->sm_flags
& XFS_SCRUB_OFLAG_XFAIL
;
133 static inline bool xref_disagrees(struct xfs_scrub_metadata
*sm
)
135 return sm
->sm_flags
& XFS_SCRUB_OFLAG_XCORRUPT
;
138 static inline bool is_incomplete(struct xfs_scrub_metadata
*sm
)
140 return sm
->sm_flags
& XFS_SCRUB_OFLAG_INCOMPLETE
;
143 static inline bool is_suspicious(struct xfs_scrub_metadata
*sm
)
145 return sm
->sm_flags
& XFS_SCRUB_OFLAG_WARNING
;
148 /* Should we fix it? */
149 static inline bool needs_repair(struct xfs_scrub_metadata
*sm
)
151 return is_corrupt(sm
) || xref_disagrees(sm
);
154 /* Warn about strange circumstances after scrub. */
156 xfs_scrub_warn_incomplete_scrub(
157 struct scrub_ctx
*ctx
,
159 struct xfs_scrub_metadata
*meta
)
161 if (is_incomplete(meta
))
162 str_info(ctx
, descr
, _("Check incomplete."));
164 if (is_suspicious(meta
)) {
166 str_info(ctx
, descr
, _("Possibly suspect metadata."));
168 str_warn(ctx
, descr
, _("Possibly suspect metadata."));
171 if (xref_failed(meta
))
172 str_info(ctx
, descr
, _("Cross-referencing failed."));
175 /* Do a read-only check of some metadata. */
176 static enum check_outcome
178 struct scrub_ctx
*ctx
,
180 struct xfs_scrub_metadata
*meta
,
183 char buf
[DESCR_BUFSZ
];
184 unsigned int tries
= 0;
188 assert(!debug_tweak_on("XFS_SCRUB_NO_KERNEL"));
189 assert(meta
->sm_type
< XFS_SCRUB_TYPE_NR
);
190 format_scrub_descr(buf
, DESCR_BUFSZ
, meta
, &scrubbers
[meta
->sm_type
]);
192 dbg_printf("check %s flags %xh\n", buf
, meta
->sm_flags
);
194 error
= ioctl(fd
, XFS_IOC_SCRUB_METADATA
, meta
);
195 if (debug_tweak_on("XFS_SCRUB_FORCE_REPAIR") && !error
)
196 meta
->sm_flags
|= XFS_SCRUB_OFLAG_CORRUPT
;
201 /* Metadata not present, just skip it. */
204 /* FS already crashed, give up. */
206 _("Filesystem is shut down, aborting."));
210 /* Abort on I/O errors or insufficient memory. */
218 * The first two should never escape the kernel,
219 * and the other two should be reported via sm_flags.
222 _("Kernel bug! errno=%d"), code
);
225 /* Operational error. */
232 * If the kernel says the test was incomplete or that there was
233 * a cross-referencing discrepancy but no obvious corruption,
234 * we'll try the scan again, just in case the fs was busy.
235 * Only retry so many times.
237 if (tries
< 10 && (is_incomplete(meta
) ||
238 (xref_disagrees(meta
) && !is_corrupt(meta
)))) {
243 /* Complain about incomplete or suspicious metadata. */
244 xfs_scrub_warn_incomplete_scrub(ctx
, buf
, meta
);
247 * If we need repairs or there were discrepancies, schedule a
248 * repair if desired, otherwise complain.
250 if (is_corrupt(meta
) || xref_disagrees(meta
)) {
251 if (ctx
->mode
< SCRUB_MODE_REPAIR
) {
253 _("Repairs are required."));
261 * If we could optimize, schedule a repair if desired,
262 * otherwise complain.
264 if (is_unoptimized(meta
)) {
265 if (ctx
->mode
!= SCRUB_MODE_REPAIR
) {
267 /* AG or FS metadata, always warn. */
269 _("Optimization is possible."));
270 } else if (!ctx
->preen_triggers
[meta
->sm_type
]) {
271 /* File metadata, only warn once per type. */
272 pthread_mutex_lock(&ctx
->lock
);
273 if (!ctx
->preen_triggers
[meta
->sm_type
])
274 ctx
->preen_triggers
[meta
->sm_type
] = true;
275 pthread_mutex_unlock(&ctx
->lock
);
283 /* Everything is ok. */
287 /* Bulk-notify user about things that could be optimized. */
289 xfs_scrub_report_preen_triggers(
290 struct scrub_ctx
*ctx
)
294 for (i
= 0; i
< XFS_SCRUB_TYPE_NR
; i
++) {
295 pthread_mutex_lock(&ctx
->lock
);
296 if (ctx
->preen_triggers
[i
]) {
297 ctx
->preen_triggers
[i
] = false;
298 pthread_mutex_unlock(&ctx
->lock
);
299 str_info(ctx
, ctx
->mntpoint
,
300 _("Optimizations of %s are possible."), scrubbers
[i
].name
);
302 pthread_mutex_unlock(&ctx
->lock
);
307 /* Save a scrub context for later repairs. */
309 xfs_scrub_save_repair(
310 struct scrub_ctx
*ctx
,
311 struct xfs_action_list
*alist
,
312 struct xfs_scrub_metadata
*meta
)
314 struct action_item
*aitem
;
316 /* Schedule this item for later repairs. */
317 aitem
= malloc(sizeof(struct action_item
));
319 str_errno(ctx
, _("repair list"));
322 memset(aitem
, 0, sizeof(*aitem
));
323 aitem
->type
= meta
->sm_type
;
324 aitem
->flags
= meta
->sm_flags
;
325 switch (scrubbers
[meta
->sm_type
].type
) {
328 aitem
->agno
= meta
->sm_agno
;
331 aitem
->ino
= meta
->sm_ino
;
332 aitem
->gen
= meta
->sm_gen
;
338 xfs_action_list_add(alist
, aitem
);
342 /* Scrub metadata, saving corruption reports for later. */
345 struct scrub_ctx
*ctx
,
346 enum scrub_type scrub_type
,
348 struct xfs_action_list
*alist
)
350 struct xfs_scrub_metadata meta
= {0};
351 const struct scrub_descr
*sc
;
352 enum check_outcome fix
;
356 for (type
= 0; type
< XFS_SCRUB_TYPE_NR
; type
++, sc
++) {
357 if (sc
->type
!= scrub_type
)
365 /* Check the item. */
366 fix
= xfs_check_metadata(ctx
, ctx
->mnt
.fd
, &meta
, false);
372 if (!xfs_scrub_save_repair(ctx
, alist
, &meta
))
387 * Scrub primary superblock. This will be useful if we ever need to hook
388 * a filesystem-wide pre-scrub activity off of the sb 0 scrubber (which
389 * currently does nothing).
392 xfs_scrub_primary_super(
393 struct scrub_ctx
*ctx
,
394 struct xfs_action_list
*alist
)
396 struct xfs_scrub_metadata meta
= {
397 .sm_type
= XFS_SCRUB_TYPE_SB
,
399 enum check_outcome fix
;
401 /* Check the item. */
402 fix
= xfs_check_metadata(ctx
, ctx
->mnt
.fd
, &meta
, false);
407 if (!xfs_scrub_save_repair(ctx
, alist
, &meta
))
420 /* Scrub each AG's header blocks. */
422 xfs_scrub_ag_headers(
423 struct scrub_ctx
*ctx
,
425 struct xfs_action_list
*alist
)
427 return xfs_scrub_metadata(ctx
, ST_AGHEADER
, agno
, alist
);
430 /* Scrub each AG's metadata btrees. */
432 xfs_scrub_ag_metadata(
433 struct scrub_ctx
*ctx
,
435 struct xfs_action_list
*alist
)
437 return xfs_scrub_metadata(ctx
, ST_PERAG
, agno
, alist
);
440 /* Scrub whole-FS metadata btrees. */
442 xfs_scrub_fs_metadata(
443 struct scrub_ctx
*ctx
,
444 struct xfs_action_list
*alist
)
446 return xfs_scrub_metadata(ctx
, ST_FS
, 0, alist
);
449 /* How many items do we have to check? */
451 xfs_scrub_estimate_ag_work(
452 struct scrub_ctx
*ctx
)
454 const struct scrub_descr
*sc
;
456 unsigned int estimate
= 0;
459 for (type
= 0; type
< XFS_SCRUB_TYPE_NR
; type
++, sc
++) {
463 estimate
+= ctx
->mnt
.fsgeom
.agcount
;
475 /* Scrub inode metadata. */
478 struct scrub_ctx
*ctx
,
483 struct xfs_action_list
*alist
)
485 struct xfs_scrub_metadata meta
= {0};
486 enum check_outcome fix
;
488 assert(type
< XFS_SCRUB_TYPE_NR
);
489 assert(scrubbers
[type
].type
== ST_INODE
);
495 /* Scrub the piece of metadata. */
496 fix
= xfs_check_metadata(ctx
, fd
, &meta
, true);
497 if (fix
== CHECK_ABORT
)
499 if (fix
== CHECK_DONE
)
502 return xfs_scrub_save_repair(ctx
, alist
, &meta
);
506 xfs_scrub_inode_fields(
507 struct scrub_ctx
*ctx
,
511 struct xfs_action_list
*alist
)
513 return __xfs_scrub_file(ctx
, ino
, gen
, fd
, XFS_SCRUB_TYPE_INODE
, alist
);
518 struct scrub_ctx
*ctx
,
522 struct xfs_action_list
*alist
)
524 return __xfs_scrub_file(ctx
, ino
, gen
, fd
, XFS_SCRUB_TYPE_BMBTD
, alist
);
529 struct scrub_ctx
*ctx
,
533 struct xfs_action_list
*alist
)
535 return __xfs_scrub_file(ctx
, ino
, gen
, fd
, XFS_SCRUB_TYPE_BMBTA
, alist
);
540 struct scrub_ctx
*ctx
,
544 struct xfs_action_list
*alist
)
546 return __xfs_scrub_file(ctx
, ino
, gen
, fd
, XFS_SCRUB_TYPE_BMBTC
, alist
);
551 struct scrub_ctx
*ctx
,
555 struct xfs_action_list
*alist
)
557 return __xfs_scrub_file(ctx
, ino
, gen
, fd
, XFS_SCRUB_TYPE_DIR
, alist
);
562 struct scrub_ctx
*ctx
,
566 struct xfs_action_list
*alist
)
568 return __xfs_scrub_file(ctx
, ino
, gen
, fd
, XFS_SCRUB_TYPE_XATTR
, alist
);
573 struct scrub_ctx
*ctx
,
577 struct xfs_action_list
*alist
)
579 return __xfs_scrub_file(ctx
, ino
, gen
, fd
, XFS_SCRUB_TYPE_SYMLINK
, alist
);
584 struct scrub_ctx
*ctx
,
588 struct xfs_action_list
*alist
)
590 return __xfs_scrub_file(ctx
, ino
, gen
, fd
, XFS_SCRUB_TYPE_PARENT
, alist
);
593 /* Test the availability of a kernel scrub command. */
596 struct scrub_ctx
*ctx
,
600 struct xfs_scrub_metadata meta
= {0};
601 struct xfs_error_injection inject
;
602 static bool injected
;
605 if (debug_tweak_on("XFS_SCRUB_NO_KERNEL"))
607 if (debug_tweak_on("XFS_SCRUB_FORCE_REPAIR") && !injected
) {
608 inject
.fd
= ctx
->mnt
.fd
;
609 inject
.errtag
= XFS_ERRTAG_FORCE_SCRUB_REPAIR
;
610 error
= ioctl(ctx
->mnt
.fd
, XFS_IOC_ERROR_INJECTION
, &inject
);
617 meta
.sm_flags
|= XFS_SCRUB_IFLAG_REPAIR
;
618 error
= ioctl(ctx
->mnt
.fd
, XFS_IOC_SCRUB_METADATA
, &meta
);
623 str_info(ctx
, ctx
->mntpoint
,
624 _("Filesystem is mounted read-only; cannot proceed."));
626 case ENOTRECOVERABLE
:
627 str_info(ctx
, ctx
->mntpoint
,
628 _("Filesystem is mounted norecovery; cannot proceed."));
632 if (debug
|| verbose
)
633 str_info(ctx
, ctx
->mntpoint
,
634 _("Kernel %s %s facility not detected."),
635 _(scrubbers
[type
].name
),
636 repair
? _("repair") : _("scrub"));
639 /* Scrubber says not present on this fs; that's fine. */
642 str_info(ctx
, ctx
->mntpoint
, "%s", strerror(errno
));
648 xfs_can_scrub_fs_metadata(
649 struct scrub_ctx
*ctx
)
651 return __xfs_scrub_test(ctx
, XFS_SCRUB_TYPE_PROBE
, false);
656 struct scrub_ctx
*ctx
)
658 return __xfs_scrub_test(ctx
, XFS_SCRUB_TYPE_INODE
, false);
663 struct scrub_ctx
*ctx
)
665 return __xfs_scrub_test(ctx
, XFS_SCRUB_TYPE_BMBTD
, false);
670 struct scrub_ctx
*ctx
)
672 return __xfs_scrub_test(ctx
, XFS_SCRUB_TYPE_DIR
, false);
677 struct scrub_ctx
*ctx
)
679 return __xfs_scrub_test(ctx
, XFS_SCRUB_TYPE_XATTR
, false);
683 xfs_can_scrub_symlink(
684 struct scrub_ctx
*ctx
)
686 return __xfs_scrub_test(ctx
, XFS_SCRUB_TYPE_SYMLINK
, false);
690 xfs_can_scrub_parent(
691 struct scrub_ctx
*ctx
)
693 return __xfs_scrub_test(ctx
, XFS_SCRUB_TYPE_PARENT
, false);
698 struct scrub_ctx
*ctx
)
700 return __xfs_scrub_test(ctx
, XFS_SCRUB_TYPE_PROBE
, true);
703 /* General repair routines. */
705 /* Repair some metadata. */
708 struct scrub_ctx
*ctx
,
710 struct action_item
*aitem
,
711 unsigned int repair_flags
)
713 char buf
[DESCR_BUFSZ
];
714 struct xfs_scrub_metadata meta
= { 0 };
715 struct xfs_scrub_metadata oldm
;
718 assert(aitem
->type
< XFS_SCRUB_TYPE_NR
);
719 assert(!debug_tweak_on("XFS_SCRUB_NO_KERNEL"));
720 meta
.sm_type
= aitem
->type
;
721 meta
.sm_flags
= aitem
->flags
| XFS_SCRUB_IFLAG_REPAIR
;
722 switch (scrubbers
[aitem
->type
].type
) {
725 meta
.sm_agno
= aitem
->agno
;
728 meta
.sm_ino
= aitem
->ino
;
729 meta
.sm_gen
= aitem
->gen
;
735 if (!is_corrupt(&meta
) && (repair_flags
& XRM_REPAIR_ONLY
))
738 memcpy(&oldm
, &meta
, sizeof(oldm
));
739 format_scrub_descr(buf
, DESCR_BUFSZ
, &meta
, &scrubbers
[meta
.sm_type
]);
741 if (needs_repair(&meta
))
742 str_info(ctx
, buf
, _("Attempting repair."));
743 else if (debug
|| verbose
)
744 str_info(ctx
, buf
, _("Attempting optimization."));
746 error
= ioctl(fd
, XFS_IOC_SCRUB_METADATA
, &meta
);
751 /* Filesystem is busy, try again later. */
752 if (debug
|| verbose
)
754 _("Filesystem is busy, deferring repair."));
757 /* Filesystem is already shut down, abort. */
759 _("Filesystem is shut down, aborting."));
764 * If we're in no-complain mode, requeue the check for
765 * later. It's possible that an error in another
766 * component caused us to flag an error in this
767 * component. Even if the kernel didn't think it
768 * could fix this, it's at least worth trying the scan
769 * again to see if another repair fixed it.
771 if (!(repair_flags
& XRM_COMPLAIN_IF_UNFIXED
))
774 * If we forced repairs or this is a preen, don't
775 * error out if the kernel doesn't know how to fix.
777 if (is_unoptimized(&oldm
) ||
778 debug_tweak_on("XFS_SCRUB_FORCE_REPAIR"))
782 /* Kernel doesn't know how to repair this? */
784 _("Don't know how to fix; offline repair required."));
787 /* Read-only filesystem, can't fix. */
788 if (verbose
|| debug
|| needs_repair(&oldm
))
790 _("Read-only filesystem; cannot make changes."));
793 /* Metadata not present, just skip it. */
797 /* Don't care if preen fails due to low resources. */
798 if (is_unoptimized(&oldm
) && !needs_repair(&oldm
))
803 * Operational error. If the caller doesn't want us
804 * to complain about repair failures, tell the caller
805 * to requeue the repair for later and don't say a
806 * thing. Otherwise, print error and bail out.
808 if (!(repair_flags
& XRM_COMPLAIN_IF_UNFIXED
))
814 if (repair_flags
& XRM_COMPLAIN_IF_UNFIXED
)
815 xfs_scrub_warn_incomplete_scrub(ctx
, buf
, &meta
);
816 if (needs_repair(&meta
)) {
818 * Still broken; if we've been told not to complain then we
819 * just requeue this and try again later. Otherwise we
820 * log the error loudly and don't try again.
822 if (!(repair_flags
& XRM_COMPLAIN_IF_UNFIXED
))
825 _("Repair unsuccessful; offline repair required."));
827 /* Clean operation, no corruption detected. */
828 if (needs_repair(&oldm
))
829 record_repair(ctx
, buf
, _("Repairs successful."));
831 record_preen(ctx
, buf
, _("Optimization successful."));