]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blame - scrub/phase7.c
xfs_scrub: remove moveon from progress report helpers
[thirdparty/xfsprogs-dev.git] / scrub / phase7.c
CommitLineData
959ef981 1// SPDX-License-Identifier: GPL-2.0+
698c6c7c
DW
2/*
3 * Copyright (C) 2018 Oracle. All Rights Reserved.
698c6c7c 4 * Author: Darrick J. Wong <darrick.wong@oracle.com>
698c6c7c 5 */
a440f877 6#include "xfs.h"
698c6c7c 7#include <stdint.h>
698c6c7c
DW
8#include <stdlib.h>
9#include <sys/statvfs.h>
42b4c8e8 10#include "libfrog/paths.h"
14051909 11#include "libfrog/ptvar.h"
cbaf1c9d 12#include "list.h"
698c6c7c
DW
13#include "xfs_scrub.h"
14#include "common.h"
cbaf1c9d 15#include "scrub.h"
698c6c7c
DW
16#include "fscounters.h"
17#include "spacemap.h"
cbaf1c9d 18#include "repair.h"
698c6c7c
DW
19
20/* Phase 7: Check summary counters. */
21
593f2ab8 22struct summary_counts {
698c6c7c
DW
23 unsigned long long dbytes; /* data dev bytes */
24 unsigned long long rbytes; /* rt dev bytes */
25 unsigned long long next_phys; /* next phys bytes we see? */
26 unsigned long long agbytes; /* freespace bytes */
27};
28
29/* Record block usage. */
7a2eef2b
DW
30static int
31count_block_summary(
593f2ab8 32 struct scrub_ctx *ctx,
593f2ab8
DW
33 struct fsmap *fsmap,
34 void *arg)
698c6c7c 35{
593f2ab8
DW
36 struct summary_counts *counts;
37 unsigned long long len;
cb321a39 38 int ret;
698c6c7c 39
cb321a39
DW
40 counts = ptvar_get((struct ptvar *)arg, &ret);
41 if (ret) {
42 str_liberror(ctx, ret, _("retrieving summary counts"));
7a2eef2b 43 return ret;
cb321a39 44 }
698c6c7c 45 if (fsmap->fmr_device == ctx->fsinfo.fs_logdev)
7a2eef2b 46 return 0;
698c6c7c
DW
47 if ((fsmap->fmr_flags & FMR_OF_SPECIAL_OWNER) &&
48 fsmap->fmr_owner == XFS_FMR_OWN_FREE)
7a2eef2b 49 return 0;
698c6c7c
DW
50
51 len = fsmap->fmr_length;
52
53 /* freesp btrees live in free space, need to adjust counters later. */
54 if ((fsmap->fmr_flags & FMR_OF_SPECIAL_OWNER) &&
55 fsmap->fmr_owner == XFS_FMR_OWN_AG) {
56 counts->agbytes += fsmap->fmr_length;
57 }
58 if (fsmap->fmr_device == ctx->fsinfo.fs_rtdev) {
59 /* Count realtime extents. */
60 counts->rbytes += len;
61 } else {
62 /* Count datadev extents. */
63 if (counts->next_phys >= fsmap->fmr_physical + len)
7a2eef2b 64 return 0;
698c6c7c
DW
65 else if (counts->next_phys > fsmap->fmr_physical)
66 len = counts->next_phys - fsmap->fmr_physical;
67 counts->dbytes += len;
68 counts->next_phys = fsmap->fmr_physical + fsmap->fmr_length;
69 }
70
7a2eef2b 71 return 0;
698c6c7c
DW
72}
73
74/* Add all the summaries in the per-thread counter */
cb321a39 75static int
698c6c7c 76xfs_add_summaries(
593f2ab8
DW
77 struct ptvar *ptv,
78 void *data,
79 void *arg)
698c6c7c 80{
593f2ab8
DW
81 struct summary_counts *total = arg;
82 struct summary_counts *item = data;
698c6c7c
DW
83
84 total->dbytes += item->dbytes;
85 total->rbytes += item->rbytes;
86 total->agbytes += item->agbytes;
cb321a39 87 return 0;
698c6c7c
DW
88}
89
90/*
91 * Count all inodes and blocks in the filesystem as told by GETFSMAP and
92 * BULKSTAT, and compare that to summary counters. Since this is a live
93 * filesystem we'll be content if the summary counts are within 10% of
94 * what we observed.
95 */
96bool
97xfs_scan_summary(
593f2ab8 98 struct scrub_ctx *ctx)
698c6c7c 99{
593f2ab8 100 struct summary_counts totalcount = {0};
cbaf1c9d 101 struct xfs_action_list alist;
593f2ab8
DW
102 struct ptvar *ptvar;
103 unsigned long long used_data;
104 unsigned long long used_rt;
105 unsigned long long used_files;
106 unsigned long long stat_data;
107 unsigned long long stat_rt;
108 uint64_t counted_inodes = 0;
109 unsigned long long absdiff;
110 unsigned long long d_blocks;
111 unsigned long long d_bfree;
112 unsigned long long r_blocks;
113 unsigned long long r_bfree;
114 unsigned long long f_files;
115 unsigned long long f_free;
116 bool moveon;
117 bool complain;
118 int ip;
119 int error;
698c6c7c 120
cbaf1c9d
DW
121 /* Check and fix the fs summary counters. */
122 xfs_action_list_init(&alist);
123 moveon = xfs_scrub_fs_summary(ctx, &alist);
124 if (!moveon)
125 return false;
126 moveon = xfs_action_list_process(ctx, ctx->mnt.fd, &alist,
127 ALP_COMPLAIN_IF_UNFIXED | ALP_NOPROGRESS);
128 if (!moveon)
129 return moveon;
130
698c6c7c 131 /* Flush everything out to disk before we start counting. */
3f9efb2e 132 error = syncfs(ctx->mnt.fd);
698c6c7c
DW
133 if (error) {
134 str_errno(ctx, ctx->mntpoint);
135 return false;
136 }
137
cb321a39
DW
138 error = ptvar_alloc(scrub_nproc(ctx), sizeof(struct summary_counts),
139 &ptvar);
140 if (error) {
141 str_liberror(ctx, error, _("setting up block counter"));
698c6c7c
DW
142 return false;
143 }
144
145 /* Use fsmap to count blocks. */
7a2eef2b
DW
146 error = scrub_scan_all_spacemaps(ctx, count_block_summary, ptvar);
147 if (error) {
148 moveon = false;
698c6c7c 149 goto out_free;
7a2eef2b 150 }
cb321a39
DW
151 error = ptvar_foreach(ptvar, xfs_add_summaries, &totalcount);
152 if (error) {
153 str_liberror(ctx, error, _("counting blocks"));
698c6c7c 154 goto out_free;
cb321a39 155 }
698c6c7c
DW
156 ptvar_free(ptvar);
157
158 /* Scan the whole fs. */
934d8d3a
DW
159 error = scrub_count_all_inodes(ctx, &counted_inodes);
160 if (error) {
161 str_liberror(ctx, error, _("counting inodes"));
162 moveon = false;
698c6c7c 163 goto out;
934d8d3a 164 }
698c6c7c 165
934d8d3a 166 error = scrub_scan_estimate_blocks(ctx, &d_blocks, &d_bfree, &r_blocks,
698c6c7c 167 &r_bfree, &f_files, &f_free);
934d8d3a
DW
168 if (error) {
169 str_liberror(ctx, error, _("estimating verify work"));
170 return false;
171 }
698c6c7c
DW
172
173 /*
174 * If we counted blocks with fsmap, then dblocks includes
175 * blocks for the AGFL and the freespace/rmap btrees. The
176 * filesystem treats them as "free", but since we scanned
177 * them, we'll consider them used.
178 */
a749451c 179 d_bfree -= cvt_b_to_off_fsbt(&ctx->mnt, totalcount.agbytes);
698c6c7c
DW
180
181 /* Report on what we found. */
a749451c
DW
182 used_data = cvt_off_fsb_to_b(&ctx->mnt, d_blocks - d_bfree);
183 used_rt = cvt_off_fsb_to_b(&ctx->mnt, r_blocks - r_bfree);
698c6c7c
DW
184 used_files = f_files - f_free;
185 stat_data = totalcount.dbytes;
186 stat_rt = totalcount.rbytes;
187
188 /*
189 * Complain if the counts are off by more than 10% unless
190 * the inaccuracy is less than 32MB worth of blocks or 100 inodes.
191 */
192 absdiff = 1ULL << 25;
193 complain = verbose;
194 complain |= !within_range(ctx, stat_data, used_data, absdiff, 1, 10,
195 _("data blocks"));
196 complain |= !within_range(ctx, stat_rt, used_rt, absdiff, 1, 10,
197 _("realtime blocks"));
198 complain |= !within_range(ctx, counted_inodes, used_files, 100, 1, 10,
199 _("inodes"));
200
201 if (complain) {
202 double d, r, i;
203 char *du, *ru, *iu;
204
205 if (used_rt || stat_rt) {
206 d = auto_space_units(used_data, &du);
207 r = auto_space_units(used_rt, &ru);
058f45da 208 i = auto_units(used_files, &iu, &ip);
698c6c7c 209 fprintf(stdout,
058f45da
DW
210_("%.1f%s data used; %.1f%s realtime data used; %.*f%s inodes used.\n"),
211 d, du, r, ru, ip, i, iu);
698c6c7c
DW
212 d = auto_space_units(stat_data, &du);
213 r = auto_space_units(stat_rt, &ru);
058f45da 214 i = auto_units(counted_inodes, &iu, &ip);
698c6c7c 215 fprintf(stdout,
058f45da
DW
216_("%.1f%s data found; %.1f%s realtime data found; %.*f%s inodes found.\n"),
217 d, du, r, ru, ip, i, iu);
698c6c7c
DW
218 } else {
219 d = auto_space_units(used_data, &du);
058f45da 220 i = auto_units(used_files, &iu, &ip);
698c6c7c 221 fprintf(stdout,
058f45da
DW
222_("%.1f%s data used; %.*f%s inodes used.\n"),
223 d, du, ip, i, iu);
698c6c7c 224 d = auto_space_units(stat_data, &du);
058f45da 225 i = auto_units(counted_inodes, &iu, &ip);
698c6c7c 226 fprintf(stdout,
058f45da
DW
227_("%.1f%s data found; %.*f%s inodes found.\n"),
228 d, du, ip, i, iu);
698c6c7c
DW
229 }
230 fflush(stdout);
231 }
232
233 /*
234 * Complain if the checked inode counts are off, which
235 * implies an incomplete check.
236 */
237 if (verbose ||
238 !within_range(ctx, counted_inodes, ctx->inodes_checked, 100, 1, 10,
239 _("checked inodes"))) {
240 double i1, i2;
241 char *i1u, *i2u;
058f45da 242 int i1p, i2p;
698c6c7c 243
058f45da
DW
244 i1 = auto_units(counted_inodes, &i1u, &i1p);
245 i2 = auto_units(ctx->inodes_checked, &i2u, &i2p);
698c6c7c 246 fprintf(stdout,
058f45da
DW
247_("%.*f%s inodes counted; %.*f%s inodes checked.\n"),
248 i1p, i1, i1u, i2p, i2, i2u);
698c6c7c
DW
249 fflush(stdout);
250 }
251
252 /*
253 * Complain if the checked block counts are off, which
254 * implies an incomplete check.
255 */
256 if (ctx->bytes_checked &&
257 (verbose ||
258 !within_range(ctx, used_data + used_rt,
259 ctx->bytes_checked, absdiff, 1, 10,
260 _("verified blocks")))) {
261 double b1, b2;
262 char *b1u, *b2u;
263
264 b1 = auto_space_units(used_data + used_rt, &b1u);
265 b2 = auto_space_units(ctx->bytes_checked, &b2u);
266 fprintf(stdout,
267_("%.1f%s data counted; %.1f%s data verified.\n"),
268 b1, b1u, b2, b2u);
269 fflush(stdout);
270 }
271
272 moveon = true;
273
274out:
275 return moveon;
276out_free:
277 ptvar_free(ptvar);
278 return moveon;
279}