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