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