]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blob - scrub/phase6.c
xfs_scrub: remove moveon from vfs directory tree iteration
[thirdparty/xfsprogs-dev.git] / scrub / phase6.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 <dirent.h>
9 #include <sys/statvfs.h>
10 #include "handle.h"
11 #include "libfrog/paths.h"
12 #include "libfrog/workqueue.h"
13 #include "xfs_scrub.h"
14 #include "common.h"
15 #include "libfrog/bitmap.h"
16 #include "disk.h"
17 #include "filemap.h"
18 #include "fscounters.h"
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
36 /* Verify disk blocks with GETFSMAP */
37
38 struct media_verify_state {
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
46 /* Find the fd for a given device identifier. */
47 static struct read_verify_pool *
48 xfs_dev_to_pool(
49 struct scrub_ctx *ctx,
50 struct media_verify_state *vs,
51 dev_t dev)
52 {
53 if (dev == ctx->fsinfo.fs_datadev)
54 return vs->rvp_data;
55 else if (dev == ctx->fsinfo.fs_logdev)
56 return vs->rvp_log;
57 else if (dev == ctx->fsinfo.fs_rtdev)
58 return vs->rvp_realtime;
59 abort();
60 }
61
62 /* Find the device major/minor for a given file descriptor. */
63 static dev_t
64 xfs_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
77 /* Find the incore bad blocks bitmap for a given disk. */
78 static struct bitmap *
79 bitmap_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
93 struct disk_ioerr_report {
94 struct scrub_ctx *ctx;
95 struct disk *disk;
96 };
97
98 struct owner_decode {
99 uint64_t owner;
100 const char *descr;
101 };
102
103 static 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. */
118 static const char *
119 xfs_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
135 struct badfile_report {
136 struct scrub_ctx *ctx;
137 const char *descr;
138 struct media_verify_state *vs;
139 struct file_bmap *bmap;
140 };
141
142 /* Report on bad extents found during a media scan. */
143 static int
144 report_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
165 str_unfixable_error(br->ctx, br->descr,
166 _("media error at data offset %llu length %llu."),
167 br->bmap->bm_offset + bad_offset, bad_length);
168 return 0;
169 }
170
171 /* Report if this extent overlaps a bad region. */
172 static int
173 report_data_loss(
174 struct scrub_ctx *ctx,
175 int fd,
176 int whichfork,
177 struct fsxattr *fsx,
178 struct file_bmap *bmap,
179 void *arg)
180 {
181 struct badfile_report *br = arg;
182 struct media_verify_state *vs = br->vs;
183 struct bitmap *bmp;
184
185 br->bmap = bmap;
186
187 /* Only report errors for real extents. */
188 if (bmap->bm_flags & (BMV_OF_PREALLOC | BMV_OF_DELALLOC))
189 return 0;
190
191 if (fsx->fsx_xflags & FS_XFLAG_REALTIME)
192 bmp = vs->r_bad;
193 else
194 bmp = vs->d_bad;
195
196 return bitmap_iterate_range(bmp, bmap->bm_physical, bmap->bm_length,
197 report_badfile, br);
198 }
199
200 /* Report if the extended attribute data overlaps a bad region. */
201 static int
202 report_attr_loss(
203 struct scrub_ctx *ctx,
204 int fd,
205 int whichfork,
206 struct fsxattr *fsx,
207 struct file_bmap *bmap,
208 void *arg)
209 {
210 struct badfile_report *br = arg;
211 struct media_verify_state *vs = br->vs;
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)) {
216 str_info(ctx, br->descr,
217 _("found unexpected unwritten/delalloc attr fork extent."));
218 return 0;
219 }
220
221 if (fsx->fsx_xflags & FS_XFLAG_REALTIME) {
222 str_info(ctx, br->descr,
223 _("found unexpected realtime attr fork extent."));
224 return 0;
225 }
226
227 if (bitmap_test(bmp, bmap->bm_physical, bmap->bm_length))
228 str_corrupt(ctx, br->descr,
229 _("media error in extended attribute data."));
230
231 return 0;
232 }
233
234 /* Iterate the extent mappings of a file to report errors. */
235 static bool
236 xfs_report_verify_fd(
237 struct scrub_ctx *ctx,
238 const char *descr,
239 int fd,
240 void *arg)
241 {
242 struct badfile_report br = {
243 .ctx = ctx,
244 .vs = arg,
245 .descr = descr,
246 };
247 struct file_bmap key = {0};
248 int ret;
249
250 /* data fork */
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);
255 return false;
256 }
257
258 /* attr fork */
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;
266 }
267
268 /* Report read verify errors in unlinked (but still open) files. */
269 static int
270 xfs_report_verify_inode(
271 struct scrub_ctx *ctx,
272 struct xfs_handle *handle,
273 struct xfs_bulkstat *bstat,
274 void *arg)
275 {
276 char descr[DESCR_BUFSZ];
277 bool moveon;
278 int fd;
279 int error;
280
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
287 scrub_render_ino_descr(ctx, descr, DESCR_BUFSZ,
288 bstat->bs_ino, bstat->bs_gen, _("(unlinked)"));
289
290 /* Try to open the inode. */
291 fd = scrub_open_handle(handle);
292 if (fd < 0) {
293 error = errno;
294 if (error == ESTALE)
295 return error;
296
297 str_info(ctx, descr,
298 _("Disappeared during read error reporting."));
299 return error;
300 }
301
302 /* Go find the badness. */
303 moveon = xfs_report_verify_fd(ctx, descr, fd, arg);
304 error = close(fd);
305 if (error)
306 str_errno(ctx, descr);
307
308 return moveon ? 0 : XFS_ITERATE_INODES_ABORT;
309 }
310
311 /* Scan a directory for matches in the read verify error list. */
312 static int
313 xfs_report_verify_dir(
314 struct scrub_ctx *ctx,
315 const char *path,
316 int dir_fd,
317 void *arg)
318 {
319 bool moveon;
320
321 moveon = xfs_report_verify_fd(ctx, path, dir_fd, arg);
322 return moveon ? 0 : -1;
323 }
324
325 /*
326 * Scan the inode associated with a directory entry for matches with
327 * the read verify error list.
328 */
329 static int
330 xfs_report_verify_dirent(
331 struct scrub_ctx *ctx,
332 const char *path,
333 int dir_fd,
334 struct dirent *dirent,
335 struct stat *sb,
336 void *arg)
337 {
338 bool moveon;
339 int fd;
340 int error;
341
342 /* Ignore things we can't open. */
343 if (!S_ISREG(sb->st_mode) && !S_ISDIR(sb->st_mode))
344 return 0;
345
346 /* Ignore . and .. */
347 if (!strcmp(".", dirent->d_name) || !strcmp("..", dirent->d_name))
348 return 0;
349
350 /*
351 * If we were given a dirent, open the associated file under
352 * dir_fd for badblocks scanning. If dirent is NULL, then it's
353 * the directory itself we want to scan.
354 */
355 fd = openat(dir_fd, dirent->d_name,
356 O_RDONLY | O_NOATIME | O_NOFOLLOW | O_NOCTTY);
357 if (fd < 0) {
358 if (errno == ENOENT)
359 return 0;
360 str_errno(ctx, path);
361 return errno;
362 }
363
364 /* Go find the badness. */
365 moveon = xfs_report_verify_fd(ctx, path, fd, arg);
366 if (moveon)
367 goto out;
368
369 out:
370 error = close(fd);
371 if (error)
372 str_errno(ctx, path);
373 return moveon ? 0 : -1;
374 }
375
376 /* Use a fsmap to report metadata lost to a media error. */
377 static bool
378 report_ioerr_fsmap(
379 struct scrub_ctx *ctx,
380 const char *descr,
381 struct fsmap *map,
382 void *arg)
383 {
384 const char *type;
385 char buf[DESCR_BUFSZ];
386 uint64_t err_physical = *(uint64_t *)arg;
387 uint64_t err_off;
388
389 /* Don't care about unwritten extents. */
390 if (map->fmr_flags & FMR_OF_PREALLOC)
391 return true;
392
393 if (err_physical > map->fmr_physical)
394 err_off = err_physical - map->fmr_physical;
395 else
396 err_off = 0;
397
398 /* Report special owners */
399 if (map->fmr_flags & FMR_OF_SPECIAL_OWNER) {
400 snprintf(buf, DESCR_BUFSZ, _("disk offset %"PRIu64),
401 (uint64_t)map->fmr_physical + err_off);
402 type = xfs_decode_special_owner(map->fmr_owner);
403 str_corrupt(ctx, buf, _("media error in %s."), type);
404 }
405
406 /* Report extent maps */
407 if (map->fmr_flags & FMR_OF_EXTENT_MAP) {
408 bool attr = (map->fmr_flags & FMR_OF_ATTR_FORK);
409
410 scrub_render_ino_descr(ctx, buf, DESCR_BUFSZ,
411 map->fmr_owner, 0, " %s",
412 attr ? _("extended attribute") :
413 _("file data"));
414 str_corrupt(ctx, buf, _("media error in extent map"));
415 }
416
417 /*
418 * XXX: If we had a getparent() call we could report IO errors
419 * efficiently. Until then, we'll have to scan the dir tree
420 * to find the bad file's pathname.
421 */
422
423 return true;
424 }
425
426 /*
427 * For a range of bad blocks, visit each space mapping that overlaps the bad
428 * range so that we can report lost metadata.
429 */
430 static int
431 report_ioerr(
432 uint64_t start,
433 uint64_t length,
434 void *arg)
435 {
436 struct fsmap keys[2];
437 char descr[DESCR_BUFSZ];
438 struct disk_ioerr_report *dioerr = arg;
439 dev_t dev;
440
441 dev = xfs_disk_to_dev(dioerr->ctx, dioerr->disk);
442
443 snprintf(descr, DESCR_BUFSZ,
444 _("dev %d:%d ioerr @ %"PRIu64":%"PRIu64" "),
445 major(dev), minor(dev), start, length);
446
447 /* Go figure out which blocks are bad from the fsmap. */
448 memset(keys, 0, sizeof(struct fsmap) * 2);
449 keys->fmr_device = dev;
450 keys->fmr_physical = start;
451 (keys + 1)->fmr_device = dev;
452 (keys + 1)->fmr_physical = start + length - 1;
453 (keys + 1)->fmr_owner = ULLONG_MAX;
454 (keys + 1)->fmr_offset = ULLONG_MAX;
455 (keys + 1)->fmr_flags = UINT_MAX;
456 xfs_iterate_fsmap(dioerr->ctx, descr, keys, report_ioerr_fsmap,
457 &start);
458 return 0;
459 }
460
461 /* Report all the media errors found on a disk. */
462 static int
463 report_disk_ioerrs(
464 struct scrub_ctx *ctx,
465 struct disk *disk,
466 struct media_verify_state *vs)
467 {
468 struct disk_ioerr_report dioerr = {
469 .ctx = ctx,
470 .disk = disk,
471 };
472 struct bitmap *tree;
473
474 if (!disk)
475 return 0;
476 tree = bitmap_for_disk(ctx, disk, vs);
477 if (!tree)
478 return 0;
479 return bitmap_iterate(tree, report_ioerr, &dioerr);
480 }
481
482 /* Given bad extent lists for the data & rtdev, find bad files. */
483 static bool
484 report_all_media_errors(
485 struct scrub_ctx *ctx,
486 struct media_verify_state *vs)
487 {
488 int ret;
489
490 ret = report_disk_ioerrs(ctx, ctx->datadev, vs);
491 if (ret) {
492 str_liberror(ctx, ret, _("walking datadev io errors"));
493 return false;
494 }
495
496 ret = report_disk_ioerrs(ctx, ctx->rtdev, vs);
497 if (ret) {
498 str_liberror(ctx, ret, _("walking rtdev io errors"));
499 return false;
500 }
501
502 /* Scan the directory tree to get file paths. */
503 ret = scan_fs_tree(ctx, xfs_report_verify_dir,
504 xfs_report_verify_dirent, vs);
505 if (ret)
506 return false;
507
508 /* Scan for unlinked files. */
509 ret = scrub_scan_all_inodes(ctx, xfs_report_verify_inode, vs);
510 return ret == 0;
511 }
512
513 /* Schedule a read-verify of a (data block) extent. */
514 static bool
515 xfs_check_rmap(
516 struct scrub_ctx *ctx,
517 const char *descr,
518 struct fsmap *map,
519 void *arg)
520 {
521 struct media_verify_state *vs = arg;
522 struct read_verify_pool *rvp;
523 int ret;
524
525 rvp = xfs_dev_to_pool(ctx, vs, map->fmr_device);
526
527 dbg_printf("rmap dev %d:%d phys %"PRIu64" owner %"PRId64
528 " offset %"PRIu64" len %"PRIu64" flags 0x%x\n",
529 major(map->fmr_device), minor(map->fmr_device),
530 (uint64_t)map->fmr_physical, (int64_t)map->fmr_owner,
531 (uint64_t)map->fmr_offset, (uint64_t)map->fmr_length,
532 map->fmr_flags);
533
534 /* "Unknown" extents should be verified; they could be data. */
535 if ((map->fmr_flags & FMR_OF_SPECIAL_OWNER) &&
536 map->fmr_owner == XFS_FMR_OWN_UNKNOWN)
537 map->fmr_flags &= ~FMR_OF_SPECIAL_OWNER;
538
539 /*
540 * We only care about read-verifying data extents that have been
541 * written to disk. This means we can skip "special" owners
542 * (metadata), xattr blocks, unwritten extents, and extent maps.
543 * These should all get checked elsewhere in the scrubber.
544 */
545 if (map->fmr_flags & (FMR_OF_PREALLOC | FMR_OF_ATTR_FORK |
546 FMR_OF_EXTENT_MAP | FMR_OF_SPECIAL_OWNER))
547 return true;
548
549 /* XXX: Filter out directory data blocks. */
550
551 /* Schedule the read verify command for (eventual) running. */
552 ret = read_verify_schedule_io(rvp, map->fmr_physical, map->fmr_length,
553 vs);
554 if (ret) {
555 str_liberror(ctx, ret, descr);
556 return false;
557 }
558
559 return true;
560 }
561
562 /* Wait for read/verify actions to finish, then return # bytes checked. */
563 static int
564 clean_pool(
565 struct read_verify_pool *rvp,
566 unsigned long long *bytes_checked)
567 {
568 uint64_t pool_checked;
569 int ret;
570
571 if (!rvp)
572 return 0;
573
574 ret = read_verify_force_io(rvp);
575 if (ret)
576 return ret;
577
578 ret = read_verify_pool_flush(rvp);
579 if (ret)
580 goto out_destroy;
581
582 ret = read_verify_bytes(rvp, &pool_checked);
583 if (ret)
584 goto out_destroy;
585
586 *bytes_checked += pool_checked;
587 out_destroy:
588 read_verify_pool_destroy(rvp);
589 return ret;
590 }
591
592 /* Remember a media error for later. */
593 static void
594 remember_ioerr(
595 struct scrub_ctx *ctx,
596 struct disk *disk,
597 uint64_t start,
598 uint64_t length,
599 int error,
600 void *arg)
601 {
602 struct media_verify_state *vs = arg;
603 struct bitmap *tree;
604 int ret;
605
606 tree = bitmap_for_disk(ctx, disk, vs);
607 if (!tree) {
608 str_liberror(ctx, ENOENT, _("finding bad block bitmap"));
609 return;
610 }
611
612 ret = bitmap_set(tree, start, length);
613 if (ret)
614 str_liberror(ctx, ret, _("setting bad block bitmap"));
615 }
616
617 /*
618 * Read verify all the file data blocks in a filesystem. Since XFS doesn't
619 * do data checksums, we trust that the underlying storage will pass back
620 * an IO error if it can't retrieve whatever we previously stored there.
621 * If we hit an IO error, we'll record the bad blocks in a bitmap and then
622 * scan the extent maps of the entire fs tree to figure (and the unlinked
623 * inodes) out which files are now broken.
624 */
625 bool
626 xfs_scan_blocks(
627 struct scrub_ctx *ctx)
628 {
629 struct media_verify_state vs = { NULL };
630 bool moveon = false;
631 int ret;
632
633 ret = bitmap_alloc(&vs.d_bad);
634 if (ret) {
635 str_liberror(ctx, ret, _("creating datadev badblock bitmap"));
636 goto out;
637 }
638
639 ret = bitmap_alloc(&vs.r_bad);
640 if (ret) {
641 str_liberror(ctx, ret, _("creating realtime badblock bitmap"));
642 goto out_dbad;
643 }
644
645 ret = read_verify_pool_alloc(ctx, ctx->datadev,
646 ctx->mnt.fsgeom.blocksize, remember_ioerr,
647 scrub_nproc(ctx), &vs.rvp_data);
648 if (ret) {
649 str_liberror(ctx, ret, _("creating datadev media verifier"));
650 goto out_rbad;
651 }
652 if (ctx->logdev) {
653 ret = read_verify_pool_alloc(ctx, ctx->logdev,
654 ctx->mnt.fsgeom.blocksize, remember_ioerr,
655 scrub_nproc(ctx), &vs.rvp_log);
656 if (ret) {
657 str_liberror(ctx, ret,
658 _("creating logdev media verifier"));
659 goto out_datapool;
660 }
661 }
662 if (ctx->rtdev) {
663 ret = read_verify_pool_alloc(ctx, ctx->rtdev,
664 ctx->mnt.fsgeom.blocksize, remember_ioerr,
665 scrub_nproc(ctx), &vs.rvp_realtime);
666 if (ret) {
667 str_liberror(ctx, ret,
668 _("creating rtdev media verifier"));
669 goto out_logpool;
670 }
671 }
672 moveon = xfs_scan_all_spacemaps(ctx, xfs_check_rmap, &vs);
673 if (!moveon)
674 goto out_rtpool;
675
676 ret = clean_pool(vs.rvp_data, &ctx->bytes_checked);
677 if (ret) {
678 str_liberror(ctx, ret, _("flushing datadev verify pool"));
679 moveon = false;
680 }
681
682 ret = clean_pool(vs.rvp_log, &ctx->bytes_checked);
683 if (ret) {
684 str_liberror(ctx, ret, _("flushing logdev verify pool"));
685 moveon = false;
686 }
687
688 ret = clean_pool(vs.rvp_realtime, &ctx->bytes_checked);
689 if (ret) {
690 str_liberror(ctx, ret, _("flushing rtdev verify pool"));
691 moveon = false;
692 }
693
694 /* Scan the whole dir tree to see what matches the bad extents. */
695 if (moveon && (!bitmap_empty(vs.d_bad) || !bitmap_empty(vs.r_bad)))
696 moveon = report_all_media_errors(ctx, &vs);
697
698 bitmap_free(&vs.r_bad);
699 bitmap_free(&vs.d_bad);
700 return moveon;
701
702 out_rtpool:
703 if (vs.rvp_realtime) {
704 read_verify_pool_abort(vs.rvp_realtime);
705 read_verify_pool_destroy(vs.rvp_realtime);
706 }
707 out_logpool:
708 if (vs.rvp_log) {
709 read_verify_pool_abort(vs.rvp_log);
710 read_verify_pool_destroy(vs.rvp_log);
711 }
712 out_datapool:
713 read_verify_pool_abort(vs.rvp_data);
714 read_verify_pool_destroy(vs.rvp_data);
715 out_rbad:
716 bitmap_free(&vs.r_bad);
717 out_dbad:
718 bitmap_free(&vs.d_bad);
719 out:
720 return moveon;
721 }
722
723 /* Estimate how much work we're going to do. */
724 bool
725 xfs_estimate_verify_work(
726 struct scrub_ctx *ctx,
727 uint64_t *items,
728 unsigned int *nr_threads,
729 int *rshift)
730 {
731 unsigned long long d_blocks;
732 unsigned long long d_bfree;
733 unsigned long long r_blocks;
734 unsigned long long r_bfree;
735 unsigned long long f_files;
736 unsigned long long f_free;
737 int ret;
738
739 ret = scrub_scan_estimate_blocks(ctx, &d_blocks, &d_bfree,
740 &r_blocks, &r_bfree, &f_files, &f_free);
741 if (ret) {
742 str_liberror(ctx, ret, _("estimating verify work"));
743 return false;
744 }
745
746 *items = cvt_off_fsb_to_b(&ctx->mnt,
747 (d_blocks - d_bfree) + (r_blocks - r_bfree));
748 *nr_threads = disk_heads(ctx->datadev);
749 *rshift = 20;
750 return true;
751 }