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