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