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