]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blame_incremental - scrub/scrub.c
xfs_scrub: only call read_verify_force_io once per pool
[thirdparty/xfsprogs-dev.git] / scrub / scrub.c
... / ...
CommitLineData
1// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Copyright (C) 2018 Oracle. All Rights Reserved.
4 * Author: Darrick J. Wong <darrick.wong@oracle.com>
5 */
6#include "xfs.h"
7#include <stdint.h>
8#include <stdlib.h>
9#include <unistd.h>
10#include <string.h>
11#include <sys/types.h>
12#include <sys/statvfs.h>
13#include "list.h"
14#include "libfrog/paths.h"
15#include "libfrog/fsgeom.h"
16#include "libfrog/scrub.h"
17#include "xfs_scrub.h"
18#include "common.h"
19#include "progress.h"
20#include "scrub.h"
21#include "xfs_errortag.h"
22#include "repair.h"
23
24/* Online scrub and repair wrappers. */
25
26/* Format a scrub description. */
27static void
28format_scrub_descr(
29 char *buf,
30 size_t buflen,
31 struct xfs_scrub_metadata *meta,
32 const struct xfrog_scrub_descr *sc)
33{
34 switch (sc->type) {
35 case XFROG_SCRUB_TYPE_AGHEADER:
36 case XFROG_SCRUB_TYPE_PERAG:
37 snprintf(buf, buflen, _("AG %u %s"), meta->sm_agno,
38 _(sc->descr));
39 break;
40 case XFROG_SCRUB_TYPE_INODE:
41 snprintf(buf, buflen, _("Inode %"PRIu64" %s"),
42 (uint64_t)meta->sm_ino, _(sc->descr));
43 break;
44 case XFROG_SCRUB_TYPE_FS:
45 snprintf(buf, buflen, _("%s"), _(sc->descr));
46 break;
47 case XFROG_SCRUB_TYPE_NONE:
48 assert(0);
49 break;
50 }
51}
52
53/* Predicates for scrub flag state. */
54
55static inline bool is_corrupt(struct xfs_scrub_metadata *sm)
56{
57 return sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT;
58}
59
60static inline bool is_unoptimized(struct xfs_scrub_metadata *sm)
61{
62 return sm->sm_flags & XFS_SCRUB_OFLAG_PREEN;
63}
64
65static inline bool xref_failed(struct xfs_scrub_metadata *sm)
66{
67 return sm->sm_flags & XFS_SCRUB_OFLAG_XFAIL;
68}
69
70static inline bool xref_disagrees(struct xfs_scrub_metadata *sm)
71{
72 return sm->sm_flags & XFS_SCRUB_OFLAG_XCORRUPT;
73}
74
75static inline bool is_incomplete(struct xfs_scrub_metadata *sm)
76{
77 return sm->sm_flags & XFS_SCRUB_OFLAG_INCOMPLETE;
78}
79
80static inline bool is_suspicious(struct xfs_scrub_metadata *sm)
81{
82 return sm->sm_flags & XFS_SCRUB_OFLAG_WARNING;
83}
84
85/* Should we fix it? */
86static inline bool needs_repair(struct xfs_scrub_metadata *sm)
87{
88 return is_corrupt(sm) || xref_disagrees(sm);
89}
90
91/* Warn about strange circumstances after scrub. */
92static inline void
93xfs_scrub_warn_incomplete_scrub(
94 struct scrub_ctx *ctx,
95 const char *descr,
96 struct xfs_scrub_metadata *meta)
97{
98 if (is_incomplete(meta))
99 str_info(ctx, descr, _("Check incomplete."));
100
101 if (is_suspicious(meta)) {
102 if (debug)
103 str_info(ctx, descr, _("Possibly suspect metadata."));
104 else
105 str_warn(ctx, descr, _("Possibly suspect metadata."));
106 }
107
108 if (xref_failed(meta))
109 str_info(ctx, descr, _("Cross-referencing failed."));
110}
111
112/* Do a read-only check of some metadata. */
113static enum check_outcome
114xfs_check_metadata(
115 struct scrub_ctx *ctx,
116 struct xfs_scrub_metadata *meta,
117 bool is_inode)
118{
119 char buf[DESCR_BUFSZ];
120 unsigned int tries = 0;
121 int code;
122 int error;
123
124 assert(!debug_tweak_on("XFS_SCRUB_NO_KERNEL"));
125 assert(meta->sm_type < XFS_SCRUB_TYPE_NR);
126 format_scrub_descr(buf, DESCR_BUFSZ, meta,
127 &xfrog_scrubbers[meta->sm_type]);
128
129 dbg_printf("check %s flags %xh\n", buf, meta->sm_flags);
130retry:
131 error = xfrog_scrub_metadata(&ctx->mnt, meta);
132 if (debug_tweak_on("XFS_SCRUB_FORCE_REPAIR") && !error)
133 meta->sm_flags |= XFS_SCRUB_OFLAG_CORRUPT;
134 if (error) {
135 code = errno;
136 switch (code) {
137 case ENOENT:
138 /* Metadata not present, just skip it. */
139 return CHECK_DONE;
140 case ESHUTDOWN:
141 /* FS already crashed, give up. */
142 str_info(ctx, buf,
143_("Filesystem is shut down, aborting."));
144 return CHECK_ABORT;
145 case EIO:
146 case ENOMEM:
147 /* Abort on I/O errors or insufficient memory. */
148 str_errno(ctx, buf);
149 return CHECK_ABORT;
150 case EDEADLOCK:
151 case EBUSY:
152 case EFSBADCRC:
153 case EFSCORRUPTED:
154 /*
155 * The first two should never escape the kernel,
156 * and the other two should be reported via sm_flags.
157 */
158 str_info(ctx, buf,
159_("Kernel bug! errno=%d"), code);
160 /* fall through */
161 default:
162 /* Operational error. */
163 str_errno(ctx, buf);
164 return CHECK_DONE;
165 }
166 }
167
168 /*
169 * If the kernel says the test was incomplete or that there was
170 * a cross-referencing discrepancy but no obvious corruption,
171 * we'll try the scan again, just in case the fs was busy.
172 * Only retry so many times.
173 */
174 if (tries < 10 && (is_incomplete(meta) ||
175 (xref_disagrees(meta) && !is_corrupt(meta)))) {
176 tries++;
177 goto retry;
178 }
179
180 /* Complain about incomplete or suspicious metadata. */
181 xfs_scrub_warn_incomplete_scrub(ctx, buf, meta);
182
183 /*
184 * If we need repairs or there were discrepancies, schedule a
185 * repair if desired, otherwise complain.
186 */
187 if (is_corrupt(meta) || xref_disagrees(meta)) {
188 if (ctx->mode < SCRUB_MODE_REPAIR) {
189 str_error(ctx, buf,
190_("Repairs are required."));
191 return CHECK_DONE;
192 }
193
194 return CHECK_REPAIR;
195 }
196
197 /*
198 * If we could optimize, schedule a repair if desired,
199 * otherwise complain.
200 */
201 if (is_unoptimized(meta)) {
202 if (ctx->mode != SCRUB_MODE_REPAIR) {
203 if (!is_inode) {
204 /* AG or FS metadata, always warn. */
205 str_info(ctx, buf,
206_("Optimization is possible."));
207 } else if (!ctx->preen_triggers[meta->sm_type]) {
208 /* File metadata, only warn once per type. */
209 pthread_mutex_lock(&ctx->lock);
210 if (!ctx->preen_triggers[meta->sm_type])
211 ctx->preen_triggers[meta->sm_type] = true;
212 pthread_mutex_unlock(&ctx->lock);
213 }
214 return CHECK_DONE;
215 }
216
217 return CHECK_REPAIR;
218 }
219
220 /* Everything is ok. */
221 return CHECK_DONE;
222}
223
224/* Bulk-notify user about things that could be optimized. */
225void
226xfs_scrub_report_preen_triggers(
227 struct scrub_ctx *ctx)
228{
229 int i;
230
231 for (i = 0; i < XFS_SCRUB_TYPE_NR; i++) {
232 pthread_mutex_lock(&ctx->lock);
233 if (ctx->preen_triggers[i]) {
234 ctx->preen_triggers[i] = false;
235 pthread_mutex_unlock(&ctx->lock);
236 str_info(ctx, ctx->mntpoint,
237_("Optimizations of %s are possible."), _(xfrog_scrubbers[i].descr));
238 } else {
239 pthread_mutex_unlock(&ctx->lock);
240 }
241 }
242}
243
244/* Save a scrub context for later repairs. */
245static bool
246xfs_scrub_save_repair(
247 struct scrub_ctx *ctx,
248 struct xfs_action_list *alist,
249 struct xfs_scrub_metadata *meta)
250{
251 struct action_item *aitem;
252
253 /* Schedule this item for later repairs. */
254 aitem = malloc(sizeof(struct action_item));
255 if (!aitem) {
256 str_errno(ctx, _("repair list"));
257 return false;
258 }
259 memset(aitem, 0, sizeof(*aitem));
260 aitem->type = meta->sm_type;
261 aitem->flags = meta->sm_flags;
262 switch (xfrog_scrubbers[meta->sm_type].type) {
263 case XFROG_SCRUB_TYPE_AGHEADER:
264 case XFROG_SCRUB_TYPE_PERAG:
265 aitem->agno = meta->sm_agno;
266 break;
267 case XFROG_SCRUB_TYPE_INODE:
268 aitem->ino = meta->sm_ino;
269 aitem->gen = meta->sm_gen;
270 break;
271 default:
272 break;
273 }
274
275 xfs_action_list_add(alist, aitem);
276 return true;
277}
278
279/* Scrub a single XFS_SCRUB_TYPE_*, saving corruption reports for later. */
280static int
281xfs_scrub_meta_type(
282 struct scrub_ctx *ctx,
283 unsigned int type,
284 xfs_agnumber_t agno,
285 struct xfs_action_list *alist)
286{
287 struct xfs_scrub_metadata meta = {
288 .sm_type = type,
289 .sm_agno = agno,
290 };
291 enum check_outcome fix;
292
293 background_sleep();
294
295 /* Check the item. */
296 fix = xfs_check_metadata(ctx, &meta, false);
297 progress_add(1);
298
299 switch (fix) {
300 case CHECK_ABORT:
301 return ECANCELED;
302 case CHECK_REPAIR:
303 if (!xfs_scrub_save_repair(ctx, alist, &meta))
304 return ENOMEM;
305 /* fall through */
306 case CHECK_DONE:
307 return 0;
308 default:
309 /* CHECK_RETRY should never happen. */
310 abort();
311 }
312}
313
314/*
315 * Scrub all metadata types that are assigned to the given XFROG_SCRUB_TYPE_*,
316 * saving corruption reports for later. This should not be used for
317 * XFROG_SCRUB_TYPE_INODE or for checking summary metadata.
318 */
319static bool
320xfs_scrub_all_types(
321 struct scrub_ctx *ctx,
322 enum xfrog_scrub_type scrub_type,
323 xfs_agnumber_t agno,
324 struct xfs_action_list *alist)
325{
326 const struct xfrog_scrub_descr *sc;
327 unsigned int type;
328
329 sc = xfrog_scrubbers;
330 for (type = 0; type < XFS_SCRUB_TYPE_NR; type++, sc++) {
331 int ret;
332
333 if (sc->type != scrub_type)
334 continue;
335 if (sc->flags & XFROG_SCRUB_DESCR_SUMMARY)
336 continue;
337
338 ret = xfs_scrub_meta_type(ctx, type, agno, alist);
339 if (ret)
340 return false;
341 }
342
343 return true;
344}
345
346/*
347 * Scrub primary superblock. This will be useful if we ever need to hook
348 * a filesystem-wide pre-scrub activity off of the sb 0 scrubber (which
349 * currently does nothing).
350 */
351bool
352xfs_scrub_primary_super(
353 struct scrub_ctx *ctx,
354 struct xfs_action_list *alist)
355{
356 int ret;
357
358 ret = xfs_scrub_meta_type(ctx, XFS_SCRUB_TYPE_SB, 0, alist);
359 return ret == 0;
360}
361
362/* Scrub each AG's header blocks. */
363bool
364xfs_scrub_ag_headers(
365 struct scrub_ctx *ctx,
366 xfs_agnumber_t agno,
367 struct xfs_action_list *alist)
368{
369 return xfs_scrub_all_types(ctx, XFROG_SCRUB_TYPE_AGHEADER, agno, alist);
370}
371
372/* Scrub each AG's metadata btrees. */
373bool
374xfs_scrub_ag_metadata(
375 struct scrub_ctx *ctx,
376 xfs_agnumber_t agno,
377 struct xfs_action_list *alist)
378{
379 return xfs_scrub_all_types(ctx, XFROG_SCRUB_TYPE_PERAG, agno, alist);
380}
381
382/* Scrub whole-FS metadata btrees. */
383bool
384xfs_scrub_fs_metadata(
385 struct scrub_ctx *ctx,
386 struct xfs_action_list *alist)
387{
388 return xfs_scrub_all_types(ctx, XFROG_SCRUB_TYPE_FS, 0, alist);
389}
390
391/* Scrub FS summary metadata. */
392bool
393xfs_scrub_fs_summary(
394 struct scrub_ctx *ctx,
395 struct xfs_action_list *alist)
396{
397 int ret;
398
399 ret = xfs_scrub_meta_type(ctx, XFS_SCRUB_TYPE_FSCOUNTERS, 0, alist);
400 return ret == 0;
401}
402
403/* How many items do we have to check? */
404unsigned int
405xfs_scrub_estimate_ag_work(
406 struct scrub_ctx *ctx)
407{
408 const struct xfrog_scrub_descr *sc;
409 int type;
410 unsigned int estimate = 0;
411
412 sc = xfrog_scrubbers;
413 for (type = 0; type < XFS_SCRUB_TYPE_NR; type++, sc++) {
414 switch (sc->type) {
415 case XFROG_SCRUB_TYPE_AGHEADER:
416 case XFROG_SCRUB_TYPE_PERAG:
417 estimate += ctx->mnt.fsgeom.agcount;
418 break;
419 case XFROG_SCRUB_TYPE_FS:
420 estimate++;
421 break;
422 default:
423 break;
424 }
425 }
426 return estimate;
427}
428
429/* Scrub inode metadata. */
430static bool
431__xfs_scrub_file(
432 struct scrub_ctx *ctx,
433 uint64_t ino,
434 uint32_t gen,
435 unsigned int type,
436 struct xfs_action_list *alist)
437{
438 struct xfs_scrub_metadata meta = {0};
439 enum check_outcome fix;
440
441 assert(type < XFS_SCRUB_TYPE_NR);
442 assert(xfrog_scrubbers[type].type == XFROG_SCRUB_TYPE_INODE);
443
444 meta.sm_type = type;
445 meta.sm_ino = ino;
446 meta.sm_gen = gen;
447
448 /* Scrub the piece of metadata. */
449 fix = xfs_check_metadata(ctx, &meta, true);
450 if (fix == CHECK_ABORT)
451 return false;
452 if (fix == CHECK_DONE)
453 return true;
454
455 return xfs_scrub_save_repair(ctx, alist, &meta);
456}
457
458bool
459xfs_scrub_inode_fields(
460 struct scrub_ctx *ctx,
461 uint64_t ino,
462 uint32_t gen,
463 struct xfs_action_list *alist)
464{
465 return __xfs_scrub_file(ctx, ino, gen, XFS_SCRUB_TYPE_INODE, alist);
466}
467
468bool
469xfs_scrub_data_fork(
470 struct scrub_ctx *ctx,
471 uint64_t ino,
472 uint32_t gen,
473 struct xfs_action_list *alist)
474{
475 return __xfs_scrub_file(ctx, ino, gen, XFS_SCRUB_TYPE_BMBTD, alist);
476}
477
478bool
479xfs_scrub_attr_fork(
480 struct scrub_ctx *ctx,
481 uint64_t ino,
482 uint32_t gen,
483 struct xfs_action_list *alist)
484{
485 return __xfs_scrub_file(ctx, ino, gen, XFS_SCRUB_TYPE_BMBTA, alist);
486}
487
488bool
489xfs_scrub_cow_fork(
490 struct scrub_ctx *ctx,
491 uint64_t ino,
492 uint32_t gen,
493 struct xfs_action_list *alist)
494{
495 return __xfs_scrub_file(ctx, ino, gen, XFS_SCRUB_TYPE_BMBTC, alist);
496}
497
498bool
499xfs_scrub_dir(
500 struct scrub_ctx *ctx,
501 uint64_t ino,
502 uint32_t gen,
503 struct xfs_action_list *alist)
504{
505 return __xfs_scrub_file(ctx, ino, gen, XFS_SCRUB_TYPE_DIR, alist);
506}
507
508bool
509xfs_scrub_attr(
510 struct scrub_ctx *ctx,
511 uint64_t ino,
512 uint32_t gen,
513 struct xfs_action_list *alist)
514{
515 return __xfs_scrub_file(ctx, ino, gen, XFS_SCRUB_TYPE_XATTR, alist);
516}
517
518bool
519xfs_scrub_symlink(
520 struct scrub_ctx *ctx,
521 uint64_t ino,
522 uint32_t gen,
523 struct xfs_action_list *alist)
524{
525 return __xfs_scrub_file(ctx, ino, gen, XFS_SCRUB_TYPE_SYMLINK, alist);
526}
527
528bool
529xfs_scrub_parent(
530 struct scrub_ctx *ctx,
531 uint64_t ino,
532 uint32_t gen,
533 struct xfs_action_list *alist)
534{
535 return __xfs_scrub_file(ctx, ino, gen, XFS_SCRUB_TYPE_PARENT, alist);
536}
537
538/* Test the availability of a kernel scrub command. */
539static bool
540__xfs_scrub_test(
541 struct scrub_ctx *ctx,
542 unsigned int type,
543 bool repair)
544{
545 struct xfs_scrub_metadata meta = {0};
546 struct xfs_error_injection inject;
547 static bool injected;
548 int error;
549
550 if (debug_tweak_on("XFS_SCRUB_NO_KERNEL"))
551 return false;
552 if (debug_tweak_on("XFS_SCRUB_FORCE_REPAIR") && !injected) {
553 inject.fd = ctx->mnt.fd;
554 inject.errtag = XFS_ERRTAG_FORCE_SCRUB_REPAIR;
555 error = ioctl(ctx->mnt.fd, XFS_IOC_ERROR_INJECTION, &inject);
556 if (error == 0)
557 injected = true;
558 }
559
560 meta.sm_type = type;
561 if (repair)
562 meta.sm_flags |= XFS_SCRUB_IFLAG_REPAIR;
563 error = xfrog_scrub_metadata(&ctx->mnt, &meta);
564 if (!error)
565 return true;
566 switch (errno) {
567 case EROFS:
568 str_info(ctx, ctx->mntpoint,
569_("Filesystem is mounted read-only; cannot proceed."));
570 return false;
571 case ENOTRECOVERABLE:
572 str_info(ctx, ctx->mntpoint,
573_("Filesystem is mounted norecovery; cannot proceed."));
574 return false;
575 case EOPNOTSUPP:
576 case ENOTTY:
577 if (debug || verbose)
578 str_info(ctx, ctx->mntpoint,
579_("Kernel %s %s facility not detected."),
580 _(xfrog_scrubbers[type].descr),
581 repair ? _("repair") : _("scrub"));
582 return false;
583 case ENOENT:
584 /* Scrubber says not present on this fs; that's fine. */
585 return true;
586 default:
587 str_info(ctx, ctx->mntpoint, "%s", strerror(errno));
588 return true;
589 }
590}
591
592bool
593xfs_can_scrub_fs_metadata(
594 struct scrub_ctx *ctx)
595{
596 return __xfs_scrub_test(ctx, XFS_SCRUB_TYPE_PROBE, false);
597}
598
599bool
600xfs_can_scrub_inode(
601 struct scrub_ctx *ctx)
602{
603 return __xfs_scrub_test(ctx, XFS_SCRUB_TYPE_INODE, false);
604}
605
606bool
607xfs_can_scrub_bmap(
608 struct scrub_ctx *ctx)
609{
610 return __xfs_scrub_test(ctx, XFS_SCRUB_TYPE_BMBTD, false);
611}
612
613bool
614xfs_can_scrub_dir(
615 struct scrub_ctx *ctx)
616{
617 return __xfs_scrub_test(ctx, XFS_SCRUB_TYPE_DIR, false);
618}
619
620bool
621xfs_can_scrub_attr(
622 struct scrub_ctx *ctx)
623{
624 return __xfs_scrub_test(ctx, XFS_SCRUB_TYPE_XATTR, false);
625}
626
627bool
628xfs_can_scrub_symlink(
629 struct scrub_ctx *ctx)
630{
631 return __xfs_scrub_test(ctx, XFS_SCRUB_TYPE_SYMLINK, false);
632}
633
634bool
635xfs_can_scrub_parent(
636 struct scrub_ctx *ctx)
637{
638 return __xfs_scrub_test(ctx, XFS_SCRUB_TYPE_PARENT, false);
639}
640
641bool
642xfs_can_repair(
643 struct scrub_ctx *ctx)
644{
645 return __xfs_scrub_test(ctx, XFS_SCRUB_TYPE_PROBE, true);
646}
647
648/* General repair routines. */
649
650/* Repair some metadata. */
651enum check_outcome
652xfs_repair_metadata(
653 struct scrub_ctx *ctx,
654 int fd,
655 struct action_item *aitem,
656 unsigned int repair_flags)
657{
658 char buf[DESCR_BUFSZ];
659 struct xfs_scrub_metadata meta = { 0 };
660 struct xfs_scrub_metadata oldm;
661 int error;
662
663 assert(aitem->type < XFS_SCRUB_TYPE_NR);
664 assert(!debug_tweak_on("XFS_SCRUB_NO_KERNEL"));
665 meta.sm_type = aitem->type;
666 meta.sm_flags = aitem->flags | XFS_SCRUB_IFLAG_REPAIR;
667 switch (xfrog_scrubbers[aitem->type].type) {
668 case XFROG_SCRUB_TYPE_AGHEADER:
669 case XFROG_SCRUB_TYPE_PERAG:
670 meta.sm_agno = aitem->agno;
671 break;
672 case XFROG_SCRUB_TYPE_INODE:
673 meta.sm_ino = aitem->ino;
674 meta.sm_gen = aitem->gen;
675 break;
676 default:
677 break;
678 }
679
680 if (!is_corrupt(&meta) && (repair_flags & XRM_REPAIR_ONLY))
681 return CHECK_RETRY;
682
683 memcpy(&oldm, &meta, sizeof(oldm));
684 format_scrub_descr(buf, DESCR_BUFSZ, &meta,
685 &xfrog_scrubbers[meta.sm_type]);
686
687 if (needs_repair(&meta))
688 str_info(ctx, buf, _("Attempting repair."));
689 else if (debug || verbose)
690 str_info(ctx, buf, _("Attempting optimization."));
691
692 error = xfrog_scrub_metadata(&ctx->mnt, &meta);
693 if (error) {
694 switch (errno) {
695 case EDEADLOCK:
696 case EBUSY:
697 /* Filesystem is busy, try again later. */
698 if (debug || verbose)
699 str_info(ctx, buf,
700_("Filesystem is busy, deferring repair."));
701 return CHECK_RETRY;
702 case ESHUTDOWN:
703 /* Filesystem is already shut down, abort. */
704 str_info(ctx, buf,
705_("Filesystem is shut down, aborting."));
706 return CHECK_ABORT;
707 case ENOTTY:
708 case EOPNOTSUPP:
709 /*
710 * If we're in no-complain mode, requeue the check for
711 * later. It's possible that an error in another
712 * component caused us to flag an error in this
713 * component. Even if the kernel didn't think it
714 * could fix this, it's at least worth trying the scan
715 * again to see if another repair fixed it.
716 */
717 if (!(repair_flags & XRM_COMPLAIN_IF_UNFIXED))
718 return CHECK_RETRY;
719 /*
720 * If we forced repairs or this is a preen, don't
721 * error out if the kernel doesn't know how to fix.
722 */
723 if (is_unoptimized(&oldm) ||
724 debug_tweak_on("XFS_SCRUB_FORCE_REPAIR"))
725 return CHECK_DONE;
726 /* fall through */
727 case EINVAL:
728 /* Kernel doesn't know how to repair this? */
729 str_error(ctx, buf,
730_("Don't know how to fix; offline repair required."));
731 return CHECK_DONE;
732 case EROFS:
733 /* Read-only filesystem, can't fix. */
734 if (verbose || debug || needs_repair(&oldm))
735 str_info(ctx, buf,
736_("Read-only filesystem; cannot make changes."));
737 return CHECK_DONE;
738 case ENOENT:
739 /* Metadata not present, just skip it. */
740 return CHECK_DONE;
741 case ENOMEM:
742 case ENOSPC:
743 /* Don't care if preen fails due to low resources. */
744 if (is_unoptimized(&oldm) && !needs_repair(&oldm))
745 return CHECK_DONE;
746 /* fall through */
747 default:
748 /*
749 * Operational error. If the caller doesn't want us
750 * to complain about repair failures, tell the caller
751 * to requeue the repair for later and don't say a
752 * thing. Otherwise, print error and bail out.
753 */
754 if (!(repair_flags & XRM_COMPLAIN_IF_UNFIXED))
755 return CHECK_RETRY;
756 str_errno(ctx, buf);
757 return CHECK_DONE;
758 }
759 }
760 if (repair_flags & XRM_COMPLAIN_IF_UNFIXED)
761 xfs_scrub_warn_incomplete_scrub(ctx, buf, &meta);
762 if (needs_repair(&meta)) {
763 /*
764 * Still broken; if we've been told not to complain then we
765 * just requeue this and try again later. Otherwise we
766 * log the error loudly and don't try again.
767 */
768 if (!(repair_flags & XRM_COMPLAIN_IF_UNFIXED))
769 return CHECK_RETRY;
770 str_error(ctx, buf,
771_("Repair unsuccessful; offline repair required."));
772 } else {
773 /* Clean operation, no corruption detected. */
774 if (needs_repair(&oldm))
775 record_repair(ctx, buf, _("Repairs successful."));
776 else
777 record_preen(ctx, buf, _("Optimization successful."));
778 }
779 return CHECK_DONE;
780}