]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blame - scrub/phase6.c
xfs_scrub: remove moveon from the fscounters functions
[thirdparty/xfsprogs-dev.git] / scrub / phase6.c
CommitLineData
959ef981 1// SPDX-License-Identifier: GPL-2.0+
b364a9c0
DW
2/*
3 * Copyright (C) 2018 Oracle. All Rights Reserved.
b364a9c0 4 * Author: Darrick J. Wong <darrick.wong@oracle.com>
b364a9c0 5 */
a440f877 6#include "xfs.h"
b364a9c0 7#include <stdint.h>
b364a9c0
DW
8#include <dirent.h>
9#include <sys/statvfs.h>
b364a9c0 10#include "handle.h"
42b4c8e8 11#include "libfrog/paths.h"
56598728 12#include "libfrog/workqueue.h"
b364a9c0
DW
13#include "xfs_scrub.h"
14#include "common.h"
a58400ed 15#include "libfrog/bitmap.h"
b364a9c0
DW
16#include "disk.h"
17#include "filemap.h"
ed60d210 18#include "fscounters.h"
b364a9c0
DW
19#include "inodes.h"
20#include "read_verify.h"
21#include "spacemap.h"
22#include "vfs.h"
23
24/*
25 * Phase 6: Verify data file integrity.
26 *
27 * Identify potential data block extents with GETFSMAP, then feed those
28 * extents to the read-verify pool to get the verify commands batched,
29 * issued, and (if there are problems) reported back to us. If there
30 * are errors, we'll record the bad regions and (if available) use rmap
31 * to tell us if metadata are now corrupt. Otherwise, we'll scan the
32 * whole directory tree looking for files that overlap the bad regions
33 * and report the paths of the now corrupt files.
34 */
35
f1bb1696
DW
36/* Verify disk blocks with GETFSMAP */
37
557f98d7 38struct media_verify_state {
f1bb1696
DW
39 struct read_verify_pool *rvp_data;
40 struct read_verify_pool *rvp_log;
41 struct read_verify_pool *rvp_realtime;
42 struct bitmap *d_bad; /* bytes */
43 struct bitmap *r_bad; /* bytes */
44};
45
b364a9c0 46/* Find the fd for a given device identifier. */
f1bb1696
DW
47static struct read_verify_pool *
48xfs_dev_to_pool(
49 struct scrub_ctx *ctx,
557f98d7 50 struct media_verify_state *vs,
f1bb1696 51 dev_t dev)
b364a9c0
DW
52{
53 if (dev == ctx->fsinfo.fs_datadev)
557f98d7 54 return vs->rvp_data;
b364a9c0 55 else if (dev == ctx->fsinfo.fs_logdev)
557f98d7 56 return vs->rvp_log;
b364a9c0 57 else if (dev == ctx->fsinfo.fs_rtdev)
557f98d7 58 return vs->rvp_realtime;
b364a9c0
DW
59 abort();
60}
61
62/* Find the device major/minor for a given file descriptor. */
63static dev_t
64xfs_disk_to_dev(
65 struct scrub_ctx *ctx,
66 struct disk *disk)
67{
68 if (disk == ctx->datadev)
69 return ctx->fsinfo.fs_datadev;
70 else if (disk == ctx->logdev)
71 return ctx->fsinfo.fs_logdev;
72 else if (disk == ctx->rtdev)
73 return ctx->fsinfo.fs_rtdev;
74 abort();
75}
76
c9b349bd
DW
77/* Find the incore bad blocks bitmap for a given disk. */
78static struct bitmap *
79bitmap_for_disk(
80 struct scrub_ctx *ctx,
81 struct disk *disk,
82 struct media_verify_state *vs)
83{
84 dev_t dev = xfs_disk_to_dev(ctx, disk);
85
86 if (dev == ctx->fsinfo.fs_datadev)
87 return vs->d_bad;
88 else if (dev == ctx->fsinfo.fs_rtdev)
89 return vs->r_bad;
90 return NULL;
91}
92
93struct disk_ioerr_report {
94 struct scrub_ctx *ctx;
95 struct disk *disk;
96};
97
b364a9c0
DW
98struct owner_decode {
99 uint64_t owner;
100 const char *descr;
101};
102
103static const struct owner_decode special_owners[] = {
104 {XFS_FMR_OWN_FREE, "free space"},
105 {XFS_FMR_OWN_UNKNOWN, "unknown owner"},
106 {XFS_FMR_OWN_FS, "static FS metadata"},
107 {XFS_FMR_OWN_LOG, "journalling log"},
108 {XFS_FMR_OWN_AG, "per-AG metadata"},
109 {XFS_FMR_OWN_INOBT, "inode btree blocks"},
110 {XFS_FMR_OWN_INODES, "inodes"},
111 {XFS_FMR_OWN_REFC, "refcount btree"},
112 {XFS_FMR_OWN_COW, "CoW staging"},
113 {XFS_FMR_OWN_DEFECTIVE, "bad blocks"},
114 {0, NULL},
115};
116
117/* Decode a special owner. */
118static const char *
119xfs_decode_special_owner(
120 uint64_t owner)
121{
122 const struct owner_decode *od = special_owners;
123
124 while (od->descr) {
125 if (od->owner == owner)
126 return od->descr;
127 od++;
128 }
129
130 return NULL;
131}
132
133/* Routines to translate bad physical extents into file paths and offsets. */
134
ed953d26 135struct badfile_report {
73ce9669
DW
136 struct scrub_ctx *ctx;
137 const char *descr;
138 struct media_verify_state *vs;
139 struct file_bmap *bmap;
ed953d26
DW
140};
141
142/* Report on bad extents found during a media scan. */
143static int
144report_badfile(
145 uint64_t start,
146 uint64_t length,
147 void *arg)
148{
149 struct badfile_report *br = arg;
150 unsigned long long bad_offset;
151 unsigned long long bad_length;
152
153 /* Clamp the bad region to the file mapping. */
154 if (start < br->bmap->bm_physical) {
155 length -= br->bmap->bm_physical - start;
156 start = br->bmap->bm_physical;
157 }
158 length = min(length, br->bmap->bm_length);
159
160 /* Figure out how far into the bmap is the bad mapping and report it. */
161 bad_offset = start - br->bmap->bm_physical;
162 bad_length = min(start + length,
163 br->bmap->bm_physical + br->bmap->bm_length) - start;
164
49e05cb0 165 str_unfixable_error(br->ctx, br->descr,
ed953d26
DW
166_("media error at data offset %llu length %llu."),
167 br->bmap->bm_offset + bad_offset, bad_length);
168 return 0;
169}
170
b364a9c0 171/* Report if this extent overlaps a bad region. */
73ce9669 172static int
663e02a0 173report_data_loss(
b364a9c0 174 struct scrub_ctx *ctx,
b364a9c0
DW
175 int fd,
176 int whichfork,
177 struct fsxattr *fsx,
73ce9669 178 struct file_bmap *bmap,
b364a9c0
DW
179 void *arg)
180{
73ce9669
DW
181 struct badfile_report *br = arg;
182 struct media_verify_state *vs = br->vs;
b364a9c0 183 struct bitmap *bmp;
73ce9669
DW
184
185 br->bmap = bmap;
b364a9c0
DW
186
187 /* Only report errors for real extents. */
188 if (bmap->bm_flags & (BMV_OF_PREALLOC | BMV_OF_DELALLOC))
73ce9669 189 return 0;
b364a9c0
DW
190
191 if (fsx->fsx_xflags & FS_XFLAG_REALTIME)
ed5f9cc7 192 bmp = vs->r_bad;
b364a9c0 193 else
ed5f9cc7 194 bmp = vs->d_bad;
b364a9c0 195
73ce9669
DW
196 return bitmap_iterate_range(bmp, bmap->bm_physical, bmap->bm_length,
197 report_badfile, br);
b364a9c0
DW
198}
199
663e02a0 200/* Report if the extended attribute data overlaps a bad region. */
73ce9669 201static int
663e02a0
DW
202report_attr_loss(
203 struct scrub_ctx *ctx,
663e02a0
DW
204 int fd,
205 int whichfork,
206 struct fsxattr *fsx,
73ce9669 207 struct file_bmap *bmap,
663e02a0
DW
208 void *arg)
209{
73ce9669
DW
210 struct badfile_report *br = arg;
211 struct media_verify_state *vs = br->vs;
663e02a0
DW
212 struct bitmap *bmp = vs->d_bad;
213
214 /* Complain about attr fork extents that don't look right. */
215 if (bmap->bm_flags & (BMV_OF_PREALLOC | BMV_OF_DELALLOC)) {
73ce9669 216 str_info(ctx, br->descr,
663e02a0 217_("found unexpected unwritten/delalloc attr fork extent."));
73ce9669 218 return 0;
663e02a0
DW
219 }
220
221 if (fsx->fsx_xflags & FS_XFLAG_REALTIME) {
73ce9669 222 str_info(ctx, br->descr,
663e02a0 223_("found unexpected realtime attr fork extent."));
73ce9669 224 return 0;
663e02a0
DW
225 }
226
227 if (bitmap_test(bmp, bmap->bm_physical, bmap->bm_length))
73ce9669 228 str_corrupt(ctx, br->descr,
663e02a0
DW
229_("media error in extended attribute data."));
230
73ce9669 231 return 0;
663e02a0
DW
232}
233
b364a9c0
DW
234/* Iterate the extent mappings of a file to report errors. */
235static bool
236xfs_report_verify_fd(
237 struct scrub_ctx *ctx,
238 const char *descr,
239 int fd,
240 void *arg)
241{
73ce9669
DW
242 struct badfile_report br = {
243 .ctx = ctx,
244 .vs = arg,
245 .descr = descr,
246 };
247 struct file_bmap key = {0};
248 int ret;
b364a9c0
DW
249
250 /* data fork */
73ce9669
DW
251 ret = scrub_iterate_filemaps(ctx, fd, XFS_DATA_FORK, &key,
252 report_data_loss, &br);
253 if (ret) {
254 str_liberror(ctx, ret, descr);
b364a9c0 255 return false;
73ce9669 256 }
b364a9c0
DW
257
258 /* attr fork */
73ce9669
DW
259 ret = scrub_iterate_filemaps(ctx, fd, XFS_ATTR_FORK, &key,
260 report_attr_loss, &br);
261 if (ret) {
262 str_liberror(ctx, ret, descr);
263 return false;
264 }
265 return true;
b364a9c0
DW
266}
267
268/* Report read verify errors in unlinked (but still open) files. */
269static int
270xfs_report_verify_inode(
271 struct scrub_ctx *ctx,
272 struct xfs_handle *handle,
4cca629d 273 struct xfs_bulkstat *bstat,
b364a9c0
DW
274 void *arg)
275{
276 char descr[DESCR_BUFSZ];
b364a9c0
DW
277 bool moveon;
278 int fd;
279 int error;
280
b364a9c0
DW
281 /* Ignore linked files and things we can't open. */
282 if (bstat->bs_nlink != 0)
283 return 0;
284 if (!S_ISREG(bstat->bs_mode) && !S_ISDIR(bstat->bs_mode))
285 return 0;
286
15589f0a
DW
287 scrub_render_ino_descr(ctx, descr, DESCR_BUFSZ,
288 bstat->bs_ino, bstat->bs_gen, _("(unlinked)"));
289
b364a9c0
DW
290 /* Try to open the inode. */
291 fd = xfs_open_handle(handle);
292 if (fd < 0) {
293 error = errno;
294 if (error == ESTALE)
295 return error;
296
bb5dbd06
DW
297 str_info(ctx, descr,
298_("Disappeared during read error reporting."));
b364a9c0
DW
299 return error;
300 }
301
302 /* Go find the badness. */
303 moveon = xfs_report_verify_fd(ctx, descr, fd, arg);
6c05cc5d
DW
304 error = close(fd);
305 if (error)
306 str_errno(ctx, descr);
b364a9c0
DW
307
308 return moveon ? 0 : XFS_ITERATE_INODES_ABORT;
309}
310
311/* Scan a directory for matches in the read verify error list. */
312static bool
313xfs_report_verify_dir(
314 struct scrub_ctx *ctx,
315 const char *path,
316 int dir_fd,
317 void *arg)
318{
319 return xfs_report_verify_fd(ctx, path, dir_fd, arg);
320}
321
322/*
323 * Scan the inode associated with a directory entry for matches with
324 * the read verify error list.
325 */
326static bool
327xfs_report_verify_dirent(
328 struct scrub_ctx *ctx,
329 const char *path,
330 int dir_fd,
331 struct dirent *dirent,
332 struct stat *sb,
333 void *arg)
334{
335 bool moveon;
336 int fd;
6c05cc5d 337 int error;
b364a9c0
DW
338
339 /* Ignore things we can't open. */
340 if (!S_ISREG(sb->st_mode) && !S_ISDIR(sb->st_mode))
341 return true;
342
343 /* Ignore . and .. */
344 if (!strcmp(".", dirent->d_name) || !strcmp("..", dirent->d_name))
345 return true;
346
347 /*
348 * If we were given a dirent, open the associated file under
349 * dir_fd for badblocks scanning. If dirent is NULL, then it's
350 * the directory itself we want to scan.
351 */
352 fd = openat(dir_fd, dirent->d_name,
353 O_RDONLY | O_NOATIME | O_NOFOLLOW | O_NOCTTY);
354 if (fd < 0)
355 return true;
356
357 /* Go find the badness. */
358 moveon = xfs_report_verify_fd(ctx, path, fd, arg);
359 if (moveon)
360 goto out;
361
362out:
6c05cc5d
DW
363 error = close(fd);
364 if (error)
365 str_errno(ctx, path);
b364a9c0
DW
366 return moveon;
367}
368
c9b349bd 369/* Use a fsmap to report metadata lost to a media error. */
b364a9c0 370static bool
c9b349bd 371report_ioerr_fsmap(
b364a9c0
DW
372 struct scrub_ctx *ctx,
373 const char *descr,
374 struct fsmap *map,
375 void *arg)
376{
377 const char *type;
f1f5fd3a 378 char buf[DESCR_BUFSZ];
b364a9c0
DW
379 uint64_t err_physical = *(uint64_t *)arg;
380 uint64_t err_off;
381
909c6a54
DW
382 /* Don't care about unwritten extents. */
383 if (map->fmr_flags & FMR_OF_PREALLOC)
384 return true;
385
b364a9c0
DW
386 if (err_physical > map->fmr_physical)
387 err_off = err_physical - map->fmr_physical;
388 else
389 err_off = 0;
390
f1f5fd3a 391 /* Report special owners */
b364a9c0 392 if (map->fmr_flags & FMR_OF_SPECIAL_OWNER) {
f1f5fd3a
DW
393 snprintf(buf, DESCR_BUFSZ, _("disk offset %"PRIu64),
394 (uint64_t)map->fmr_physical + err_off);
b364a9c0 395 type = xfs_decode_special_owner(map->fmr_owner);
abc2e70d 396 str_corrupt(ctx, buf, _("media error in %s."), type);
b364a9c0
DW
397 }
398
02d0069e
DW
399 /* Report extent maps */
400 if (map->fmr_flags & FMR_OF_EXTENT_MAP) {
401 bool attr = (map->fmr_flags & FMR_OF_ATTR_FORK);
402
403 scrub_render_ino_descr(ctx, buf, DESCR_BUFSZ,
404 map->fmr_owner, 0, " %s",
405 attr ? _("extended attribute") :
406 _("file data"));
abc2e70d 407 str_corrupt(ctx, buf, _("media error in extent map"));
02d0069e
DW
408 }
409
b364a9c0
DW
410 /*
411 * XXX: If we had a getparent() call we could report IO errors
412 * efficiently. Until then, we'll have to scan the dir tree
413 * to find the bad file's pathname.
414 */
415
416 return true;
417}
418
419/*
c9b349bd
DW
420 * For a range of bad blocks, visit each space mapping that overlaps the bad
421 * range so that we can report lost metadata.
b364a9c0 422 */
c9b349bd
DW
423static int
424report_ioerr(
b364a9c0
DW
425 uint64_t start,
426 uint64_t length,
b364a9c0
DW
427 void *arg)
428{
429 struct fsmap keys[2];
430 char descr[DESCR_BUFSZ];
c9b349bd 431 struct disk_ioerr_report *dioerr = arg;
b364a9c0 432 dev_t dev;
b364a9c0 433
c9b349bd 434 dev = xfs_disk_to_dev(dioerr->ctx, dioerr->disk);
b364a9c0 435
c9b349bd
DW
436 snprintf(descr, DESCR_BUFSZ,
437_("dev %d:%d ioerr @ %"PRIu64":%"PRIu64" "),
b364a9c0
DW
438 major(dev), minor(dev), start, length);
439
440 /* Go figure out which blocks are bad from the fsmap. */
441 memset(keys, 0, sizeof(struct fsmap) * 2);
442 keys->fmr_device = dev;
443 keys->fmr_physical = start;
444 (keys + 1)->fmr_device = dev;
445 (keys + 1)->fmr_physical = start + length - 1;
446 (keys + 1)->fmr_owner = ULLONG_MAX;
447 (keys + 1)->fmr_offset = ULLONG_MAX;
448 (keys + 1)->fmr_flags = UINT_MAX;
c9b349bd 449 xfs_iterate_fsmap(dioerr->ctx, descr, keys, report_ioerr_fsmap,
b364a9c0 450 &start);
c9b349bd
DW
451 return 0;
452}
453
454/* Report all the media errors found on a disk. */
455static int
456report_disk_ioerrs(
457 struct scrub_ctx *ctx,
458 struct disk *disk,
459 struct media_verify_state *vs)
460{
461 struct disk_ioerr_report dioerr = {
462 .ctx = ctx,
463 .disk = disk,
464 };
465 struct bitmap *tree;
466
467 if (!disk)
468 return 0;
469 tree = bitmap_for_disk(ctx, disk, vs);
470 if (!tree)
471 return 0;
472 return bitmap_iterate(tree, report_ioerr, &dioerr);
473}
474
475/* Given bad extent lists for the data & rtdev, find bad files. */
476static bool
477report_all_media_errors(
478 struct scrub_ctx *ctx,
479 struct media_verify_state *vs)
480{
481 bool moveon;
482 int ret;
483
484 ret = report_disk_ioerrs(ctx, ctx->datadev, vs);
485 if (ret) {
486 str_liberror(ctx, ret, _("walking datadev io errors"));
487 return false;
488 }
489
490 ret = report_disk_ioerrs(ctx, ctx->rtdev, vs);
491 if (ret) {
492 str_liberror(ctx, ret, _("walking rtdev io errors"));
493 return false;
494 }
495
496 /* Scan the directory tree to get file paths. */
497 moveon = scan_fs_tree(ctx, xfs_report_verify_dir,
498 xfs_report_verify_dirent, vs);
499 if (!moveon)
500 return false;
501
502 /* Scan for unlinked files. */
503 return xfs_scan_all_inodes(ctx, xfs_report_verify_inode, vs);
b364a9c0
DW
504}
505
506/* Schedule a read-verify of a (data block) extent. */
507static bool
508xfs_check_rmap(
509 struct scrub_ctx *ctx,
510 const char *descr,
511 struct fsmap *map,
512 void *arg)
513{
557f98d7 514 struct media_verify_state *vs = arg;
f1bb1696 515 struct read_verify_pool *rvp;
8cab77d3 516 int ret;
f1bb1696 517
557f98d7 518 rvp = xfs_dev_to_pool(ctx, vs, map->fmr_device);
b364a9c0
DW
519
520 dbg_printf("rmap dev %d:%d phys %"PRIu64" owner %"PRId64
521 " offset %"PRIu64" len %"PRIu64" flags 0x%x\n",
522 major(map->fmr_device), minor(map->fmr_device),
523 (uint64_t)map->fmr_physical, (int64_t)map->fmr_owner,
524 (uint64_t)map->fmr_offset, (uint64_t)map->fmr_length,
525 map->fmr_flags);
526
527 /* "Unknown" extents should be verified; they could be data. */
528 if ((map->fmr_flags & FMR_OF_SPECIAL_OWNER) &&
529 map->fmr_owner == XFS_FMR_OWN_UNKNOWN)
530 map->fmr_flags &= ~FMR_OF_SPECIAL_OWNER;
531
532 /*
533 * We only care about read-verifying data extents that have been
534 * written to disk. This means we can skip "special" owners
535 * (metadata), xattr blocks, unwritten extents, and extent maps.
536 * These should all get checked elsewhere in the scrubber.
537 */
538 if (map->fmr_flags & (FMR_OF_PREALLOC | FMR_OF_ATTR_FORK |
539 FMR_OF_EXTENT_MAP | FMR_OF_SPECIAL_OWNER))
22d658ec 540 return true;
b364a9c0
DW
541
542 /* XXX: Filter out directory data blocks. */
543
544 /* Schedule the read verify command for (eventual) running. */
8cab77d3
DW
545 ret = read_verify_schedule_io(rvp, map->fmr_physical, map->fmr_length,
546 vs);
547 if (ret) {
548 str_liberror(ctx, ret, descr);
549 return false;
550 }
b364a9c0 551
b364a9c0
DW
552 return true;
553}
554
f1bb1696 555/* Wait for read/verify actions to finish, then return # bytes checked. */
8cab77d3 556static int
f1bb1696 557clean_pool(
8cab77d3
DW
558 struct read_verify_pool *rvp,
559 unsigned long long *bytes_checked)
f1bb1696 560{
8cab77d3
DW
561 uint64_t pool_checked;
562 int ret;
f1bb1696
DW
563
564 if (!rvp)
565 return 0;
566
22d658ec
DW
567 ret = read_verify_force_io(rvp);
568 if (ret)
569 return ret;
570
8cab77d3
DW
571 ret = read_verify_pool_flush(rvp);
572 if (ret)
573 goto out_destroy;
574
575 ret = read_verify_bytes(rvp, &pool_checked);
576 if (ret)
577 goto out_destroy;
578
579 *bytes_checked += pool_checked;
580out_destroy:
f1bb1696
DW
581 read_verify_pool_destroy(rvp);
582 return ret;
583}
584
c9b349bd
DW
585/* Remember a media error for later. */
586static void
587remember_ioerr(
588 struct scrub_ctx *ctx,
589 struct disk *disk,
590 uint64_t start,
591 uint64_t length,
592 int error,
593 void *arg)
594{
595 struct media_verify_state *vs = arg;
596 struct bitmap *tree;
597 int ret;
598
599 tree = bitmap_for_disk(ctx, disk, vs);
600 if (!tree) {
601 str_liberror(ctx, ENOENT, _("finding bad block bitmap"));
602 return;
603 }
604
605 ret = bitmap_set(tree, start, length);
606 if (ret)
607 str_liberror(ctx, ret, _("setting bad block bitmap"));
608}
609
b364a9c0
DW
610/*
611 * Read verify all the file data blocks in a filesystem. Since XFS doesn't
612 * do data checksums, we trust that the underlying storage will pass back
613 * an IO error if it can't retrieve whatever we previously stored there.
614 * If we hit an IO error, we'll record the bad blocks in a bitmap and then
615 * scan the extent maps of the entire fs tree to figure (and the unlinked
616 * inodes) out which files are now broken.
617 */
618bool
619xfs_scan_blocks(
620 struct scrub_ctx *ctx)
621{
557f98d7 622 struct media_verify_state vs = { NULL };
93ab49dd 623 bool moveon = false;
233fabee 624 int ret;
b364a9c0 625
233fabee
DW
626 ret = bitmap_alloc(&vs.d_bad);
627 if (ret) {
628 str_liberror(ctx, ret, _("creating datadev badblock bitmap"));
41c08606 629 goto out;
b364a9c0
DW
630 }
631
233fabee
DW
632 ret = bitmap_alloc(&vs.r_bad);
633 if (ret) {
634 str_liberror(ctx, ret, _("creating realtime badblock bitmap"));
b364a9c0
DW
635 goto out_dbad;
636 }
637
8cab77d3 638 ret = read_verify_pool_alloc(ctx, ctx->datadev,
c9b349bd 639 ctx->mnt.fsgeom.blocksize, remember_ioerr,
8cab77d3
DW
640 scrub_nproc(ctx), &vs.rvp_data);
641 if (ret) {
642 str_liberror(ctx, ret, _("creating datadev media verifier"));
b364a9c0
DW
643 goto out_rbad;
644 }
f1bb1696 645 if (ctx->logdev) {
8cab77d3 646 ret = read_verify_pool_alloc(ctx, ctx->logdev,
c9b349bd 647 ctx->mnt.fsgeom.blocksize, remember_ioerr,
8cab77d3
DW
648 scrub_nproc(ctx), &vs.rvp_log);
649 if (ret) {
650 str_liberror(ctx, ret,
651 _("creating logdev media verifier"));
f1bb1696
DW
652 goto out_datapool;
653 }
654 }
655 if (ctx->rtdev) {
8cab77d3 656 ret = read_verify_pool_alloc(ctx, ctx->rtdev,
c9b349bd 657 ctx->mnt.fsgeom.blocksize, remember_ioerr,
8cab77d3
DW
658 scrub_nproc(ctx), &vs.rvp_realtime);
659 if (ret) {
660 str_liberror(ctx, ret,
661 _("creating rtdev media verifier"));
f1bb1696
DW
662 goto out_logpool;
663 }
664 }
557f98d7 665 moveon = xfs_scan_all_spacemaps(ctx, xfs_check_rmap, &vs);
b364a9c0 666 if (!moveon)
f1bb1696 667 goto out_rtpool;
8cab77d3
DW
668
669 ret = clean_pool(vs.rvp_data, &ctx->bytes_checked);
670 if (ret) {
671 str_liberror(ctx, ret, _("flushing datadev verify pool"));
672 moveon = false;
673 }
674
675 ret = clean_pool(vs.rvp_log, &ctx->bytes_checked);
676 if (ret) {
677 str_liberror(ctx, ret, _("flushing logdev verify pool"));
678 moveon = false;
679 }
680
681 ret = clean_pool(vs.rvp_realtime, &ctx->bytes_checked);
682 if (ret) {
683 str_liberror(ctx, ret, _("flushing rtdev verify pool"));
684 moveon = false;
685 }
b364a9c0
DW
686
687 /* Scan the whole dir tree to see what matches the bad extents. */
8cab77d3 688 if (moveon && (!bitmap_empty(vs.d_bad) || !bitmap_empty(vs.r_bad)))
c9b349bd 689 moveon = report_all_media_errors(ctx, &vs);
b364a9c0 690
557f98d7
DW
691 bitmap_free(&vs.r_bad);
692 bitmap_free(&vs.d_bad);
b364a9c0
DW
693 return moveon;
694
f1bb1696 695out_rtpool:
7668d01d 696 if (vs.rvp_realtime) {
4cd869e5 697 read_verify_pool_abort(vs.rvp_realtime);
557f98d7 698 read_verify_pool_destroy(vs.rvp_realtime);
7668d01d 699 }
f1bb1696 700out_logpool:
7668d01d 701 if (vs.rvp_log) {
4cd869e5 702 read_verify_pool_abort(vs.rvp_log);
557f98d7 703 read_verify_pool_destroy(vs.rvp_log);
7668d01d 704 }
f1bb1696 705out_datapool:
4cd869e5 706 read_verify_pool_abort(vs.rvp_data);
557f98d7 707 read_verify_pool_destroy(vs.rvp_data);
b364a9c0 708out_rbad:
557f98d7 709 bitmap_free(&vs.r_bad);
b364a9c0 710out_dbad:
557f98d7 711 bitmap_free(&vs.d_bad);
41c08606 712out:
b364a9c0
DW
713 return moveon;
714}
ed60d210
DW
715
716/* Estimate how much work we're going to do. */
717bool
718xfs_estimate_verify_work(
719 struct scrub_ctx *ctx,
720 uint64_t *items,
721 unsigned int *nr_threads,
722 int *rshift)
723{
724 unsigned long long d_blocks;
725 unsigned long long d_bfree;
726 unsigned long long r_blocks;
727 unsigned long long r_bfree;
728 unsigned long long f_files;
729 unsigned long long f_free;
934d8d3a 730 int ret;
ed60d210 731
934d8d3a 732 ret = scrub_scan_estimate_blocks(ctx, &d_blocks, &d_bfree,
ed60d210 733 &r_blocks, &r_bfree, &f_files, &f_free);
934d8d3a
DW
734 if (ret) {
735 str_liberror(ctx, ret, _("estimating verify work"));
736 return false;
737 }
ed60d210 738
a749451c
DW
739 *items = cvt_off_fsb_to_b(&ctx->mnt,
740 (d_blocks - d_bfree) + (r_blocks - r_bfree));
ed60d210
DW
741 *nr_threads = disk_heads(ctx->datadev);
742 *rshift = 20;
934d8d3a 743 return true;
ed60d210 744}