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