]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blob - scrub/scrub.c
62edc361499c842908ee97a2991f36315aac1a37
[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 "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 struct xfs_scrub_metadata *meta,
180 bool is_inode)
181 {
182 char buf[DESCR_BUFSZ];
183 unsigned int tries = 0;
184 int code;
185 int error;
186
187 assert(!debug_tweak_on("XFS_SCRUB_NO_KERNEL"));
188 assert(meta->sm_type < XFS_SCRUB_TYPE_NR);
189 format_scrub_descr(buf, DESCR_BUFSZ, meta, &scrubbers[meta->sm_type]);
190
191 dbg_printf("check %s flags %xh\n", buf, meta->sm_flags);
192 retry:
193 error = ioctl(ctx->mnt.fd, XFS_IOC_SCRUB_METADATA, meta);
194 if (debug_tweak_on("XFS_SCRUB_FORCE_REPAIR") && !error)
195 meta->sm_flags |= XFS_SCRUB_OFLAG_CORRUPT;
196 if (error) {
197 code = errno;
198 switch (code) {
199 case ENOENT:
200 /* Metadata not present, just skip it. */
201 return CHECK_DONE;
202 case ESHUTDOWN:
203 /* FS already crashed, give up. */
204 str_info(ctx, buf,
205 _("Filesystem is shut down, aborting."));
206 return CHECK_ABORT;
207 case EIO:
208 case ENOMEM:
209 /* Abort on I/O errors or insufficient memory. */
210 str_errno(ctx, buf);
211 return CHECK_ABORT;
212 case EDEADLOCK:
213 case EBUSY:
214 case EFSBADCRC:
215 case EFSCORRUPTED:
216 /*
217 * The first two should never escape the kernel,
218 * and the other two should be reported via sm_flags.
219 */
220 str_info(ctx, buf,
221 _("Kernel bug! errno=%d"), code);
222 /* fall through */
223 default:
224 /* Operational error. */
225 str_errno(ctx, buf);
226 return CHECK_DONE;
227 }
228 }
229
230 /*
231 * If the kernel says the test was incomplete or that there was
232 * a cross-referencing discrepancy but no obvious corruption,
233 * we'll try the scan again, just in case the fs was busy.
234 * Only retry so many times.
235 */
236 if (tries < 10 && (is_incomplete(meta) ||
237 (xref_disagrees(meta) && !is_corrupt(meta)))) {
238 tries++;
239 goto retry;
240 }
241
242 /* Complain about incomplete or suspicious metadata. */
243 xfs_scrub_warn_incomplete_scrub(ctx, buf, meta);
244
245 /*
246 * If we need repairs or there were discrepancies, schedule a
247 * repair if desired, otherwise complain.
248 */
249 if (is_corrupt(meta) || xref_disagrees(meta)) {
250 if (ctx->mode < SCRUB_MODE_REPAIR) {
251 str_error(ctx, buf,
252 _("Repairs are required."));
253 return CHECK_DONE;
254 }
255
256 return CHECK_REPAIR;
257 }
258
259 /*
260 * If we could optimize, schedule a repair if desired,
261 * otherwise complain.
262 */
263 if (is_unoptimized(meta)) {
264 if (ctx->mode != SCRUB_MODE_REPAIR) {
265 if (!is_inode) {
266 /* AG or FS metadata, always warn. */
267 str_info(ctx, buf,
268 _("Optimization is possible."));
269 } else if (!ctx->preen_triggers[meta->sm_type]) {
270 /* File metadata, only warn once per type. */
271 pthread_mutex_lock(&ctx->lock);
272 if (!ctx->preen_triggers[meta->sm_type])
273 ctx->preen_triggers[meta->sm_type] = true;
274 pthread_mutex_unlock(&ctx->lock);
275 }
276 return CHECK_DONE;
277 }
278
279 return CHECK_REPAIR;
280 }
281
282 /* Everything is ok. */
283 return CHECK_DONE;
284 }
285
286 /* Bulk-notify user about things that could be optimized. */
287 void
288 xfs_scrub_report_preen_triggers(
289 struct scrub_ctx *ctx)
290 {
291 int i;
292
293 for (i = 0; i < XFS_SCRUB_TYPE_NR; i++) {
294 pthread_mutex_lock(&ctx->lock);
295 if (ctx->preen_triggers[i]) {
296 ctx->preen_triggers[i] = false;
297 pthread_mutex_unlock(&ctx->lock);
298 str_info(ctx, ctx->mntpoint,
299 _("Optimizations of %s are possible."), scrubbers[i].name);
300 } else {
301 pthread_mutex_unlock(&ctx->lock);
302 }
303 }
304 }
305
306 /* Save a scrub context for later repairs. */
307 static bool
308 xfs_scrub_save_repair(
309 struct scrub_ctx *ctx,
310 struct xfs_action_list *alist,
311 struct xfs_scrub_metadata *meta)
312 {
313 struct action_item *aitem;
314
315 /* Schedule this item for later repairs. */
316 aitem = malloc(sizeof(struct action_item));
317 if (!aitem) {
318 str_errno(ctx, _("repair list"));
319 return false;
320 }
321 memset(aitem, 0, sizeof(*aitem));
322 aitem->type = meta->sm_type;
323 aitem->flags = meta->sm_flags;
324 switch (scrubbers[meta->sm_type].type) {
325 case ST_AGHEADER:
326 case ST_PERAG:
327 aitem->agno = meta->sm_agno;
328 break;
329 case ST_INODE:
330 aitem->ino = meta->sm_ino;
331 aitem->gen = meta->sm_gen;
332 break;
333 default:
334 break;
335 }
336
337 xfs_action_list_add(alist, aitem);
338 return true;
339 }
340
341 /* Scrub metadata, saving corruption reports for later. */
342 static bool
343 xfs_scrub_metadata(
344 struct scrub_ctx *ctx,
345 enum scrub_type scrub_type,
346 xfs_agnumber_t agno,
347 struct xfs_action_list *alist)
348 {
349 struct xfs_scrub_metadata meta = {0};
350 const struct scrub_descr *sc;
351 enum check_outcome fix;
352 int type;
353
354 sc = scrubbers;
355 for (type = 0; type < XFS_SCRUB_TYPE_NR; type++, sc++) {
356 if (sc->type != scrub_type)
357 continue;
358
359 meta.sm_type = type;
360 meta.sm_flags = 0;
361 meta.sm_agno = agno;
362 background_sleep();
363
364 /* Check the item. */
365 fix = xfs_check_metadata(ctx, &meta, false);
366 progress_add(1);
367 switch (fix) {
368 case CHECK_ABORT:
369 return false;
370 case CHECK_REPAIR:
371 if (!xfs_scrub_save_repair(ctx, alist, &meta))
372 return false;
373 /* fall through */
374 case CHECK_DONE:
375 continue;
376 case CHECK_RETRY:
377 abort();
378 break;
379 }
380 }
381
382 return true;
383 }
384
385 /*
386 * Scrub primary superblock. This will be useful if we ever need to hook
387 * a filesystem-wide pre-scrub activity off of the sb 0 scrubber (which
388 * currently does nothing).
389 */
390 bool
391 xfs_scrub_primary_super(
392 struct scrub_ctx *ctx,
393 struct xfs_action_list *alist)
394 {
395 struct xfs_scrub_metadata meta = {
396 .sm_type = XFS_SCRUB_TYPE_SB,
397 };
398 enum check_outcome fix;
399
400 /* Check the item. */
401 fix = xfs_check_metadata(ctx, &meta, false);
402 switch (fix) {
403 case CHECK_ABORT:
404 return false;
405 case CHECK_REPAIR:
406 if (!xfs_scrub_save_repair(ctx, alist, &meta))
407 return false;
408 /* fall through */
409 case CHECK_DONE:
410 return true;
411 case CHECK_RETRY:
412 abort();
413 break;
414 }
415
416 return true;
417 }
418
419 /* Scrub each AG's header blocks. */
420 bool
421 xfs_scrub_ag_headers(
422 struct scrub_ctx *ctx,
423 xfs_agnumber_t agno,
424 struct xfs_action_list *alist)
425 {
426 return xfs_scrub_metadata(ctx, ST_AGHEADER, agno, alist);
427 }
428
429 /* Scrub each AG's metadata btrees. */
430 bool
431 xfs_scrub_ag_metadata(
432 struct scrub_ctx *ctx,
433 xfs_agnumber_t agno,
434 struct xfs_action_list *alist)
435 {
436 return xfs_scrub_metadata(ctx, ST_PERAG, agno, alist);
437 }
438
439 /* Scrub whole-FS metadata btrees. */
440 bool
441 xfs_scrub_fs_metadata(
442 struct scrub_ctx *ctx,
443 struct xfs_action_list *alist)
444 {
445 return xfs_scrub_metadata(ctx, ST_FS, 0, alist);
446 }
447
448 /* How many items do we have to check? */
449 unsigned int
450 xfs_scrub_estimate_ag_work(
451 struct scrub_ctx *ctx)
452 {
453 const struct scrub_descr *sc;
454 int type;
455 unsigned int estimate = 0;
456
457 sc = scrubbers;
458 for (type = 0; type < XFS_SCRUB_TYPE_NR; type++, sc++) {
459 switch (sc->type) {
460 case ST_AGHEADER:
461 case ST_PERAG:
462 estimate += ctx->mnt.fsgeom.agcount;
463 break;
464 case ST_FS:
465 estimate++;
466 break;
467 default:
468 break;
469 }
470 }
471 return estimate;
472 }
473
474 /* Scrub inode metadata. */
475 static bool
476 __xfs_scrub_file(
477 struct scrub_ctx *ctx,
478 uint64_t ino,
479 uint32_t gen,
480 unsigned int type,
481 struct xfs_action_list *alist)
482 {
483 struct xfs_scrub_metadata meta = {0};
484 enum check_outcome fix;
485
486 assert(type < XFS_SCRUB_TYPE_NR);
487 assert(scrubbers[type].type == ST_INODE);
488
489 meta.sm_type = type;
490 meta.sm_ino = ino;
491 meta.sm_gen = gen;
492
493 /* Scrub the piece of metadata. */
494 fix = xfs_check_metadata(ctx, &meta, true);
495 if (fix == CHECK_ABORT)
496 return false;
497 if (fix == CHECK_DONE)
498 return true;
499
500 return xfs_scrub_save_repair(ctx, alist, &meta);
501 }
502
503 bool
504 xfs_scrub_inode_fields(
505 struct scrub_ctx *ctx,
506 uint64_t ino,
507 uint32_t gen,
508 struct xfs_action_list *alist)
509 {
510 return __xfs_scrub_file(ctx, ino, gen, XFS_SCRUB_TYPE_INODE, alist);
511 }
512
513 bool
514 xfs_scrub_data_fork(
515 struct scrub_ctx *ctx,
516 uint64_t ino,
517 uint32_t gen,
518 struct xfs_action_list *alist)
519 {
520 return __xfs_scrub_file(ctx, ino, gen, XFS_SCRUB_TYPE_BMBTD, alist);
521 }
522
523 bool
524 xfs_scrub_attr_fork(
525 struct scrub_ctx *ctx,
526 uint64_t ino,
527 uint32_t gen,
528 struct xfs_action_list *alist)
529 {
530 return __xfs_scrub_file(ctx, ino, gen, XFS_SCRUB_TYPE_BMBTA, alist);
531 }
532
533 bool
534 xfs_scrub_cow_fork(
535 struct scrub_ctx *ctx,
536 uint64_t ino,
537 uint32_t gen,
538 struct xfs_action_list *alist)
539 {
540 return __xfs_scrub_file(ctx, ino, gen, XFS_SCRUB_TYPE_BMBTC, alist);
541 }
542
543 bool
544 xfs_scrub_dir(
545 struct scrub_ctx *ctx,
546 uint64_t ino,
547 uint32_t gen,
548 struct xfs_action_list *alist)
549 {
550 return __xfs_scrub_file(ctx, ino, gen, XFS_SCRUB_TYPE_DIR, alist);
551 }
552
553 bool
554 xfs_scrub_attr(
555 struct scrub_ctx *ctx,
556 uint64_t ino,
557 uint32_t gen,
558 struct xfs_action_list *alist)
559 {
560 return __xfs_scrub_file(ctx, ino, gen, XFS_SCRUB_TYPE_XATTR, alist);
561 }
562
563 bool
564 xfs_scrub_symlink(
565 struct scrub_ctx *ctx,
566 uint64_t ino,
567 uint32_t gen,
568 struct xfs_action_list *alist)
569 {
570 return __xfs_scrub_file(ctx, ino, gen, XFS_SCRUB_TYPE_SYMLINK, alist);
571 }
572
573 bool
574 xfs_scrub_parent(
575 struct scrub_ctx *ctx,
576 uint64_t ino,
577 uint32_t gen,
578 struct xfs_action_list *alist)
579 {
580 return __xfs_scrub_file(ctx, ino, gen, XFS_SCRUB_TYPE_PARENT, alist);
581 }
582
583 /* Test the availability of a kernel scrub command. */
584 static bool
585 __xfs_scrub_test(
586 struct scrub_ctx *ctx,
587 unsigned int type,
588 bool repair)
589 {
590 struct xfs_scrub_metadata meta = {0};
591 struct xfs_error_injection inject;
592 static bool injected;
593 int error;
594
595 if (debug_tweak_on("XFS_SCRUB_NO_KERNEL"))
596 return false;
597 if (debug_tweak_on("XFS_SCRUB_FORCE_REPAIR") && !injected) {
598 inject.fd = ctx->mnt.fd;
599 inject.errtag = XFS_ERRTAG_FORCE_SCRUB_REPAIR;
600 error = ioctl(ctx->mnt.fd, XFS_IOC_ERROR_INJECTION, &inject);
601 if (error == 0)
602 injected = true;
603 }
604
605 meta.sm_type = type;
606 if (repair)
607 meta.sm_flags |= XFS_SCRUB_IFLAG_REPAIR;
608 error = ioctl(ctx->mnt.fd, XFS_IOC_SCRUB_METADATA, &meta);
609 if (!error)
610 return true;
611 switch (errno) {
612 case EROFS:
613 str_info(ctx, ctx->mntpoint,
614 _("Filesystem is mounted read-only; cannot proceed."));
615 return false;
616 case ENOTRECOVERABLE:
617 str_info(ctx, ctx->mntpoint,
618 _("Filesystem is mounted norecovery; cannot proceed."));
619 return false;
620 case EOPNOTSUPP:
621 case ENOTTY:
622 if (debug || verbose)
623 str_info(ctx, ctx->mntpoint,
624 _("Kernel %s %s facility not detected."),
625 _(scrubbers[type].name),
626 repair ? _("repair") : _("scrub"));
627 return false;
628 case ENOENT:
629 /* Scrubber says not present on this fs; that's fine. */
630 return true;
631 default:
632 str_info(ctx, ctx->mntpoint, "%s", strerror(errno));
633 return true;
634 }
635 }
636
637 bool
638 xfs_can_scrub_fs_metadata(
639 struct scrub_ctx *ctx)
640 {
641 return __xfs_scrub_test(ctx, XFS_SCRUB_TYPE_PROBE, false);
642 }
643
644 bool
645 xfs_can_scrub_inode(
646 struct scrub_ctx *ctx)
647 {
648 return __xfs_scrub_test(ctx, XFS_SCRUB_TYPE_INODE, false);
649 }
650
651 bool
652 xfs_can_scrub_bmap(
653 struct scrub_ctx *ctx)
654 {
655 return __xfs_scrub_test(ctx, XFS_SCRUB_TYPE_BMBTD, false);
656 }
657
658 bool
659 xfs_can_scrub_dir(
660 struct scrub_ctx *ctx)
661 {
662 return __xfs_scrub_test(ctx, XFS_SCRUB_TYPE_DIR, false);
663 }
664
665 bool
666 xfs_can_scrub_attr(
667 struct scrub_ctx *ctx)
668 {
669 return __xfs_scrub_test(ctx, XFS_SCRUB_TYPE_XATTR, false);
670 }
671
672 bool
673 xfs_can_scrub_symlink(
674 struct scrub_ctx *ctx)
675 {
676 return __xfs_scrub_test(ctx, XFS_SCRUB_TYPE_SYMLINK, false);
677 }
678
679 bool
680 xfs_can_scrub_parent(
681 struct scrub_ctx *ctx)
682 {
683 return __xfs_scrub_test(ctx, XFS_SCRUB_TYPE_PARENT, false);
684 }
685
686 bool
687 xfs_can_repair(
688 struct scrub_ctx *ctx)
689 {
690 return __xfs_scrub_test(ctx, XFS_SCRUB_TYPE_PROBE, true);
691 }
692
693 /* General repair routines. */
694
695 /* Repair some metadata. */
696 enum check_outcome
697 xfs_repair_metadata(
698 struct scrub_ctx *ctx,
699 int fd,
700 struct action_item *aitem,
701 unsigned int repair_flags)
702 {
703 char buf[DESCR_BUFSZ];
704 struct xfs_scrub_metadata meta = { 0 };
705 struct xfs_scrub_metadata oldm;
706 int error;
707
708 assert(aitem->type < XFS_SCRUB_TYPE_NR);
709 assert(!debug_tweak_on("XFS_SCRUB_NO_KERNEL"));
710 meta.sm_type = aitem->type;
711 meta.sm_flags = aitem->flags | XFS_SCRUB_IFLAG_REPAIR;
712 switch (scrubbers[aitem->type].type) {
713 case ST_AGHEADER:
714 case ST_PERAG:
715 meta.sm_agno = aitem->agno;
716 break;
717 case ST_INODE:
718 meta.sm_ino = aitem->ino;
719 meta.sm_gen = aitem->gen;
720 break;
721 default:
722 break;
723 }
724
725 if (!is_corrupt(&meta) && (repair_flags & XRM_REPAIR_ONLY))
726 return CHECK_RETRY;
727
728 memcpy(&oldm, &meta, sizeof(oldm));
729 format_scrub_descr(buf, DESCR_BUFSZ, &meta, &scrubbers[meta.sm_type]);
730
731 if (needs_repair(&meta))
732 str_info(ctx, buf, _("Attempting repair."));
733 else if (debug || verbose)
734 str_info(ctx, buf, _("Attempting optimization."));
735
736 error = ioctl(fd, XFS_IOC_SCRUB_METADATA, &meta);
737 if (error) {
738 switch (errno) {
739 case EDEADLOCK:
740 case EBUSY:
741 /* Filesystem is busy, try again later. */
742 if (debug || verbose)
743 str_info(ctx, buf,
744 _("Filesystem is busy, deferring repair."));
745 return CHECK_RETRY;
746 case ESHUTDOWN:
747 /* Filesystem is already shut down, abort. */
748 str_info(ctx, buf,
749 _("Filesystem is shut down, aborting."));
750 return CHECK_ABORT;
751 case ENOTTY:
752 case EOPNOTSUPP:
753 /*
754 * If we're in no-complain mode, requeue the check for
755 * later. It's possible that an error in another
756 * component caused us to flag an error in this
757 * component. Even if the kernel didn't think it
758 * could fix this, it's at least worth trying the scan
759 * again to see if another repair fixed it.
760 */
761 if (!(repair_flags & XRM_COMPLAIN_IF_UNFIXED))
762 return CHECK_RETRY;
763 /*
764 * If we forced repairs or this is a preen, don't
765 * error out if the kernel doesn't know how to fix.
766 */
767 if (is_unoptimized(&oldm) ||
768 debug_tweak_on("XFS_SCRUB_FORCE_REPAIR"))
769 return CHECK_DONE;
770 /* fall through */
771 case EINVAL:
772 /* Kernel doesn't know how to repair this? */
773 str_error(ctx, buf,
774 _("Don't know how to fix; offline repair required."));
775 return CHECK_DONE;
776 case EROFS:
777 /* Read-only filesystem, can't fix. */
778 if (verbose || debug || needs_repair(&oldm))
779 str_info(ctx, buf,
780 _("Read-only filesystem; cannot make changes."));
781 return CHECK_DONE;
782 case ENOENT:
783 /* Metadata not present, just skip it. */
784 return CHECK_DONE;
785 case ENOMEM:
786 case ENOSPC:
787 /* Don't care if preen fails due to low resources. */
788 if (is_unoptimized(&oldm) && !needs_repair(&oldm))
789 return CHECK_DONE;
790 /* fall through */
791 default:
792 /*
793 * Operational error. If the caller doesn't want us
794 * to complain about repair failures, tell the caller
795 * to requeue the repair for later and don't say a
796 * thing. Otherwise, print error and bail out.
797 */
798 if (!(repair_flags & XRM_COMPLAIN_IF_UNFIXED))
799 return CHECK_RETRY;
800 str_errno(ctx, buf);
801 return CHECK_DONE;
802 }
803 }
804 if (repair_flags & XRM_COMPLAIN_IF_UNFIXED)
805 xfs_scrub_warn_incomplete_scrub(ctx, buf, &meta);
806 if (needs_repair(&meta)) {
807 /*
808 * Still broken; if we've been told not to complain then we
809 * just requeue this and try again later. Otherwise we
810 * log the error loudly and don't try again.
811 */
812 if (!(repair_flags & XRM_COMPLAIN_IF_UNFIXED))
813 return CHECK_RETRY;
814 str_error(ctx, buf,
815 _("Repair unsuccessful; offline repair required."));
816 } else {
817 /* Clean operation, no corruption detected. */
818 if (needs_repair(&oldm))
819 record_repair(ctx, buf, _("Repairs successful."));
820 else
821 record_preen(ctx, buf, _("Optimization successful."));
822 }
823 return CHECK_DONE;
824 }