]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blame - repair/scan.c
xfs_repair: fix naming problems in repair/rmap.c
[thirdparty/xfsprogs-dev.git] / repair / scan.c
CommitLineData
2bd0ea18 1/*
da23017d
NS
2 * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc.
3 * All Rights Reserved.
dfc130f3 4 *
da23017d
NS
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
2bd0ea18 7 * published by the Free Software Foundation.
dfc130f3 8 *
da23017d
NS
9 * This program is distributed in the hope that it would be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
dfc130f3 13 *
da23017d
NS
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write the Free Software Foundation,
16 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
2bd0ea18
NS
17 */
18
6b803e5a 19#include "libxfs.h"
2bd0ea18
NS
20#include "avl.h"
21#include "globals.h"
22#include "agheader.h"
23#include "incore.h"
24#include "protos.h"
25#include "err_protos.h"
26#include "dinode.h"
27#include "scan.h"
28#include "versions.h"
29#include "bmap.h"
06fbdda9 30#include "progress.h"
364a126c 31#include "threads.h"
11b9e510 32#include "slab.h"
00efc33a 33#include "rmap.h"
2bd0ea18 34
2bd0ea18 35static xfs_mount_t *mp = NULL;
2bd0ea18 36
48d49157 37/*
364a126c 38 * Variables to validate AG header values against the manual count
48d49157 39 * from the btree traversal.
48d49157 40 */
364a126c
DC
41struct aghdr_cnts {
42 xfs_agnumber_t agno;
43 xfs_extlen_t agffreeblks;
44 xfs_extlen_t agflongest;
45 __uint64_t agfbtreeblks;
46 __uint32_t agicount;
47 __uint32_t agifreecount;
48 __uint64_t fdblocks;
0f94fa4b 49 __uint64_t usedblocks;
364a126c 50 __uint64_t ifreecount;
1578050f 51 __uint32_t fibtfreecount;
364a126c 52};
48d49157 53
2bd0ea18
NS
54void
55set_mp(xfs_mount_t *mpp)
56{
f1b058f9 57 libxfs_bcache_purge();
2bd0ea18
NS
58 mp = mpp;
59}
60
8b8a6b02 61static void
2bd0ea18
NS
62scan_sbtree(
63 xfs_agblock_t root,
64 int nlevels,
65 xfs_agnumber_t agno,
66 int suspect,
b3563c19 67 void (*func)(struct xfs_btree_block *block,
2bd0ea18
NS
68 int level,
69 xfs_agblock_t bno,
70 xfs_agnumber_t agno,
71 int suspect,
364a126c 72 int isroot,
e0607266 73 __uint32_t magic,
364a126c
DC
74 void *priv),
75 int isroot,
e0607266
DC
76 __uint32_t magic,
77 void *priv,
78 const struct xfs_buf_ops *ops)
2bd0ea18
NS
79{
80 xfs_buf_t *bp;
81
82 bp = libxfs_readbuf(mp->m_dev, XFS_AGB_TO_DADDR(mp, agno, root),
e0607266 83 XFS_FSB_TO_BB(mp, 1), 0, ops);
2bd0ea18 84 if (!bp) {
507f4e33 85 do_error(_("can't read btree block %d/%d\n"), agno, root);
2bd0ea18
NS
86 return;
87 }
66fc04e0 88 if (bp->b_error == -EFSBADCRC || bp->b_error == -EFSCORRUPTED) {
a76a5a71
DC
89 do_warn(_("btree block %d/%d is suspect, error %d\n"),
90 agno, root, bp->b_error);
91 suspect = 1;
92 }
93
364a126c 94 (*func)(XFS_BUF_TO_BLOCK(bp), nlevels - 1, root, agno, suspect,
e0607266 95 isroot, magic, priv);
2bd0ea18
NS
96 libxfs_putbuf(bp);
97}
98
99/*
100 * returns 1 on bad news (inode needs to be cleared), 0 on good
101 */
102int
103scan_lbtree(
5a35bf2c 104 xfs_fsblock_t root,
2bd0ea18 105 int nlevels,
b3563c19 106 int (*func)(struct xfs_btree_block *block,
2bd0ea18
NS
107 int level,
108 int type,
109 int whichfork,
5a35bf2c 110 xfs_fsblock_t bno,
2bd0ea18 111 xfs_ino_t ino,
5a35bf2c 112 xfs_rfsblock_t *tot,
2bd0ea18
NS
113 __uint64_t *nex,
114 blkmap_t **blkmapp,
115 bmap_cursor_t *bm_cursor,
116 int isroot,
117 int check_dups,
e0607266
DC
118 int *dirty,
119 __uint64_t magic),
2bd0ea18
NS
120 int type,
121 int whichfork,
122 xfs_ino_t ino,
5a35bf2c 123 xfs_rfsblock_t *tot,
2bd0ea18
NS
124 __uint64_t *nex,
125 blkmap_t **blkmapp,
126 bmap_cursor_t *bm_cursor,
127 int isroot,
e0607266
DC
128 int check_dups,
129 __uint64_t magic,
130 const struct xfs_buf_ops *ops)
2bd0ea18
NS
131{
132 xfs_buf_t *bp;
133 int err;
134 int dirty = 0;
a76a5a71 135 bool badcrc = false;
2bd0ea18
NS
136
137 bp = libxfs_readbuf(mp->m_dev, XFS_FSB_TO_DADDR(mp, root),
e0607266 138 XFS_FSB_TO_BB(mp, 1), 0, ops);
2bd0ea18 139 if (!bp) {
507f4e33 140 do_error(_("can't read btree block %d/%d\n"),
2bd0ea18
NS
141 XFS_FSB_TO_AGNO(mp, root),
142 XFS_FSB_TO_AGBNO(mp, root));
143 return(1);
144 }
a76a5a71
DC
145
146 /*
147 * only check for bad CRC here - caller will determine if there
148 * is a corruption or not and whether it got corrected and so needs
149 * writing back. CRC errors always imply we need to write the block.
150 */
66fc04e0 151 if (bp->b_error == -EFSBADCRC) {
a76a5a71
DC
152 do_warn(_("btree block %d/%d is suspect, error %d\n"),
153 XFS_FSB_TO_AGNO(mp, root),
154 XFS_FSB_TO_AGBNO(mp, root), bp->b_error);
155 badcrc = true;
156 }
157
b3563c19 158 err = (*func)(XFS_BUF_TO_BLOCK(bp), nlevels - 1,
2bd0ea18 159 type, whichfork, root, ino, tot, nex, blkmapp,
e0607266
DC
160 bm_cursor, isroot, check_dups, &dirty,
161 magic);
2bd0ea18 162
27527004 163 ASSERT(dirty == 0 || (dirty && !no_modify));
2bd0ea18 164
a76a5a71 165 if ((dirty || badcrc) && !no_modify)
2bd0ea18
NS
166 libxfs_writebuf(bp, 0);
167 else
168 libxfs_putbuf(bp);
169
170 return(err);
171}
172
173int
e0607266 174scan_bmapbt(
b3563c19 175 struct xfs_btree_block *block,
2bd0ea18
NS
176 int level,
177 int type,
178 int whichfork,
5a35bf2c 179 xfs_fsblock_t bno,
2bd0ea18 180 xfs_ino_t ino,
5a35bf2c 181 xfs_rfsblock_t *tot,
2bd0ea18
NS
182 __uint64_t *nex,
183 blkmap_t **blkmapp,
184 bmap_cursor_t *bm_cursor,
185 int isroot,
186 int check_dups,
e0607266
DC
187 int *dirty,
188 __uint64_t magic)
2bd0ea18 189{
2bd0ea18
NS
190 int i;
191 int err;
192 xfs_bmbt_ptr_t *pp;
193 xfs_bmbt_key_t *pkey;
5e656dbb 194 xfs_bmbt_rec_t *rp;
5a35bf2c
DC
195 xfs_fileoff_t first_key;
196 xfs_fileoff_t last_key;
beed0dc8 197 char *forkname = get_forkname(whichfork);
5e656dbb 198 int numrecs;
95650c4d
BN
199 xfs_agnumber_t agno;
200 xfs_agblock_t agbno;
201 int state;
00efc33a 202 int error;
2bd0ea18 203
2bd0ea18 204 /*
dfc130f3 205 * unlike the ag freeblock btrees, if anything looks wrong
2bd0ea18
NS
206 * in an inode bmap tree, just bail. it's possible that
207 * we'll miss a case where the to-be-toasted inode and
208 * another inode are claiming the same block but that's
209 * highly unlikely.
210 */
e0607266 211 if (be32_to_cpu(block->bb_magic) != magic) {
5d1b7f0f
CH
212 do_warn(
213_("bad magic # %#x in inode %" PRIu64 " (%s fork) bmbt block %" PRIu64 "\n"),
214 be32_to_cpu(block->bb_magic), ino, forkname, bno);
2bd0ea18
NS
215 return(1);
216 }
5e656dbb 217 if (be16_to_cpu(block->bb_level) != level) {
5d1b7f0f
CH
218 do_warn(
219_("expected level %d got %d in inode %" PRIu64 ", (%s fork) bmbt block %" PRIu64 "\n"),
220 level, be16_to_cpu(block->bb_level),
221 ino, forkname, bno);
2bd0ea18
NS
222 return(1);
223 }
224
e0607266
DC
225 if (magic == XFS_BMAP_CRC_MAGIC) {
226 /* verify owner */
227 if (be64_to_cpu(block->bb_u.l.bb_owner) != ino) {
228 do_warn(
229_("expected owner inode %" PRIu64 ", got %llu, bmbt block %" PRIu64 "\n"),
230 ino, be64_to_cpu(block->bb_u.l.bb_owner), bno);
0519f662
DW
231 return 1;
232 }
233 /* verify block number */
234 if (be64_to_cpu(block->bb_u.l.bb_blkno) !=
235 XFS_FSB_TO_DADDR(mp, bno)) {
236 do_warn(
237_("expected block %" PRIu64 ", got %llu, bmbt block %" PRIu64 "\n"),
238 XFS_FSB_TO_DADDR(mp, bno),
239 be64_to_cpu(block->bb_u.l.bb_blkno), bno);
240 return 1;
241 }
242 /* verify uuid */
243 if (platform_uuid_compare(&block->bb_u.l.bb_uuid,
f31982ae 244 &mp->m_sb.sb_meta_uuid) != 0) {
0519f662
DW
245 do_warn(
246_("wrong FS UUID, bmbt block %" PRIu64 "\n"),
247 bno);
248 return 1;
e0607266
DC
249 }
250 }
251
2bd0ea18
NS
252 if (check_dups == 0) {
253 /*
254 * check sibling pointers. if bad we have a conflict
255 * between the sibling pointers and the child pointers
256 * in the parent block. blow out the inode if that happens
257 */
5a35bf2c 258 if (bm_cursor->level[level].fsbno != NULLFSBLOCK) {
2bd0ea18
NS
259 /*
260 * this is not the first block on this level
261 * so the cursor for this level has recorded the
262 * values for this's block left-sibling.
263 */
264 if (bno != bm_cursor->level[level].right_fsbno) {
265 do_warn(
5d1b7f0f
CH
266_("bad fwd (right) sibling pointer (saw %" PRIu64 " parent block says %" PRIu64 ")\n"
267 "\tin inode %" PRIu64 " (%s fork) bmap btree block %" PRIu64 "\n"),
2bd0ea18 268 bm_cursor->level[level].right_fsbno,
507f4e33 269 bno, ino, forkname,
2bd0ea18
NS
270 bm_cursor->level[level].fsbno);
271 return(1);
272 }
b3563c19 273 if (be64_to_cpu(block->bb_u.l.bb_leftsib) !=
2bd0ea18
NS
274 bm_cursor->level[level].fsbno) {
275 do_warn(
5d1b7f0f
CH
276_("bad back (left) sibling pointer (saw %llu parent block says %" PRIu64 ")\n"
277 "\tin inode %" PRIu64 " (%s fork) bmap btree block %" PRIu64 "\n"),
278 (unsigned long long)
279 be64_to_cpu(block->bb_u.l.bb_leftsib),
507f4e33 280 bm_cursor->level[level].fsbno,
2bd0ea18
NS
281 ino, forkname, bno);
282 return(1);
283 }
284 } else {
285 /*
286 * This is the first or only block on this level.
287 * Check that the left sibling pointer is NULL
288 */
5a35bf2c 289 if (be64_to_cpu(block->bb_u.l.bb_leftsib) != NULLFSBLOCK) {
2bd0ea18 290 do_warn(
507f4e33 291_("bad back (left) sibling pointer (saw %llu should be NULL (0))\n"
5d1b7f0f
CH
292 "\tin inode %" PRIu64 " (%s fork) bmap btree block %" PRIu64 "\n"),
293 (unsigned long long)
294 be64_to_cpu(block->bb_u.l.bb_leftsib),
2bd0ea18
NS
295 ino, forkname, bno);
296 return(1);
297 }
298 }
299
300 /*
301 * update cursor block pointers to reflect this block
302 */
303 bm_cursor->level[level].fsbno = bno;
507f4e33 304 bm_cursor->level[level].left_fsbno =
b3563c19 305 be64_to_cpu(block->bb_u.l.bb_leftsib);
507f4e33 306 bm_cursor->level[level].right_fsbno =
b3563c19 307 be64_to_cpu(block->bb_u.l.bb_rightsib);
2bd0ea18 308
95650c4d
BN
309 agno = XFS_FSB_TO_AGNO(mp, bno);
310 agbno = XFS_FSB_TO_AGBNO(mp, bno);
311
586f8abf 312 pthread_mutex_lock(&ag_locks[agno].lock);
95650c4d
BN
313 state = get_bmap(agno, agbno);
314 switch (state) {
0f94fa4b
DW
315 case XR_E_INUSE1:
316 /*
317 * block was claimed as in use data by the rmap
318 * btree, but has not been found in the data extent
319 * map for the inode. That means this bmbt block hasn't
320 * yet been claimed as in use, which means -it's ours-
321 */
2bd0ea18
NS
322 case XR_E_UNKNOWN:
323 case XR_E_FREE1:
324 case XR_E_FREE:
95650c4d 325 set_bmap(agno, agbno, XR_E_INUSE);
2bd0ea18
NS
326 break;
327 case XR_E_FS_MAP:
328 case XR_E_INUSE:
329 /*
330 * we'll try and continue searching here since
331 * the block looks like it's been claimed by file
332 * to store user data, a directory to store directory
333 * data, or the space allocation btrees but since
334 * we made it here, the block probably
335 * contains btree data.
336 */
95650c4d 337 set_bmap(agno, agbno, XR_E_MULT);
2bd0ea18 338 do_warn(
d9db5c4e 339_("inode 0x%" PRIx64 "bmap block 0x%" PRIx64 " claimed, state is %d\n"),
5d1b7f0f 340 ino, bno, state);
2bd0ea18
NS
341 break;
342 case XR_E_MULT:
343 case XR_E_INUSE_FS:
95650c4d 344 set_bmap(agno, agbno, XR_E_MULT);
2bd0ea18 345 do_warn(
d9db5c4e 346_("inode 0x%" PRIx64 " bmap block 0x%" PRIx64 " claimed, state is %d\n"),
5d1b7f0f 347 ino, bno, state);
2bd0ea18
NS
348 /*
349 * if we made it to here, this is probably a bmap block
350 * that is being used by *another* file as a bmap block
351 * so the block will be valid. Both files should be
352 * trashed along with any other file that impinges on
353 * any blocks referenced by either file. So we
354 * continue searching down this btree to mark all
355 * blocks duplicate
356 */
357 break;
358 case XR_E_BAD_STATE:
359 default:
360 do_warn(
2e686aa8 361_("bad state %d, inode %" PRIu64 " bmap block 0x%" PRIx64 "\n"),
5d1b7f0f 362 state, ino, bno);
2bd0ea18
NS
363 break;
364 }
586f8abf 365 pthread_mutex_unlock(&ag_locks[agno].lock);
2bd0ea18
NS
366 } else {
367 /*
368 * attribute fork for realtime files is in the regular
369 * filesystem
370 */
371 if (type != XR_INO_RTDATA || whichfork != XFS_DATA_FORK) {
79872d6e
BN
372 if (search_dup_extent(XFS_FSB_TO_AGNO(mp, bno),
373 XFS_FSB_TO_AGBNO(mp, bno),
374 XFS_FSB_TO_AGBNO(mp, bno) + 1))
2bd0ea18
NS
375 return(1);
376 } else {
377 if (search_rt_dup_extent(mp, bno))
378 return(1);
379 }
380 }
381 (*tot)++;
5e656dbb
BN
382 numrecs = be16_to_cpu(block->bb_numrecs);
383
00efc33a
DW
384 /* Record BMBT blocks in the reverse-mapping data. */
385 if (check_dups && collect_rmaps) {
2d273771 386 error = rmap_add_bmbt_rec(mp, ino, whichfork, bno);
00efc33a
DW
387 if (error)
388 do_error(
389_("couldn't add inode %"PRIu64" bmbt block %"PRIu64" reverse-mapping data."),
390 ino, bno);
391 }
392
2bd0ea18 393 if (level == 0) {
5e656dbb
BN
394 if (numrecs > mp->m_bmap_dmxr[0] || (isroot == 0 && numrecs <
395 mp->m_bmap_dmnr[0])) {
507f4e33 396 do_warn(
b52923f3 397_("inode %" PRIu64 " bad # of bmap records (%u, min - %u, max - %u)\n"),
5e656dbb
BN
398 ino, numrecs, mp->m_bmap_dmnr[0],
399 mp->m_bmap_dmxr[0]);
2bd0ea18
NS
400 return(1);
401 }
b3563c19 402 rp = XFS_BMBT_REC_ADDR(mp, block, 1);
5e656dbb 403 *nex += numrecs;
2bd0ea18
NS
404 /*
405 * XXX - if we were going to fix up the btree record,
406 * we'd do it right here. For now, if there's a problem,
407 * we'll bail out and presumably clear the inode.
408 */
409 if (check_dups == 0) {
e1f43b4c
CH
410 err = process_bmbt_reclist(mp, rp, &numrecs, type, ino,
411 tot, blkmapp, &first_key,
412 &last_key, whichfork);
2bd0ea18 413 if (err)
e1f43b4c
CH
414 return 1;
415
2bd0ea18
NS
416 /*
417 * check that key ordering is monotonically increasing.
418 * if the last_key value in the cursor is set to
5a35bf2c 419 * NULLFILEOFF, then we know this is the first block
2bd0ea18
NS
420 * on the leaf level and we shouldn't check the
421 * last_key value.
422 */
423 if (first_key <= bm_cursor->level[level].last_key &&
424 bm_cursor->level[level].last_key !=
5a35bf2c 425 NULLFILEOFF) {
2bd0ea18 426 do_warn(
5d1b7f0f 427_("out-of-order bmap key (file offset) in inode %" PRIu64 ", %s fork, fsbno %" PRIu64 "\n"),
2bd0ea18
NS
428 ino, forkname, bno);
429 return(1);
430 }
431 /*
432 * update cursor keys to reflect this block.
433 * don't have to check if last_key is > first_key
434 * since that gets checked by process_bmbt_reclist.
435 */
436 bm_cursor->level[level].first_key = first_key;
437 bm_cursor->level[level].last_key = last_key;
438
e1f43b4c
CH
439 return 0;
440 } else {
441 return scan_bmbt_reclist(mp, rp, &numrecs, type, ino,
442 tot, whichfork);
443 }
2bd0ea18 444 }
5e656dbb
BN
445 if (numrecs > mp->m_bmap_dmxr[1] || (isroot == 0 && numrecs <
446 mp->m_bmap_dmnr[1])) {
507f4e33 447 do_warn(
2e686aa8 448_("inode %" PRIu64 " bad # of bmap records (%u, min - %u, max - %u)\n"),
5e656dbb 449 ino, numrecs, mp->m_bmap_dmnr[1], mp->m_bmap_dmxr[1]);
2bd0ea18
NS
450 return(1);
451 }
b3563c19
BN
452 pp = XFS_BMBT_PTR_ADDR(mp, block, 1, mp->m_bmap_dmxr[1]);
453 pkey = XFS_BMBT_KEY_ADDR(mp, block, 1);
2bd0ea18 454
5a35bf2c 455 last_key = NULLFILEOFF;
2bd0ea18 456
5e656dbb 457 for (i = 0, err = 0; i < numrecs; i++) {
2bd0ea18
NS
458 /*
459 * XXX - if we were going to fix up the interior btree nodes,
460 * we'd do it right here. For now, if there's a problem,
461 * we'll bail out and presumably clear the inode.
462 */
5e656dbb 463 if (!verify_dfsbno(mp, be64_to_cpu(pp[i]))) {
5d1b7f0f
CH
464 do_warn(
465_("bad bmap btree ptr 0x%llx in ino %" PRIu64 "\n"),
466 (unsigned long long) be64_to_cpu(pp[i]), ino);
2bd0ea18
NS
467 return(1);
468 }
469
e0607266 470 err = scan_lbtree(be64_to_cpu(pp[i]), level, scan_bmapbt,
5e656dbb 471 type, whichfork, ino, tot, nex, blkmapp,
e0607266
DC
472 bm_cursor, 0, check_dups, magic,
473 &xfs_bmbt_buf_ops);
2bd0ea18
NS
474 if (err)
475 return(1);
476
477 /*
478 * fix key (offset) mismatches between the first key
479 * in the child block (as recorded in the cursor) and the
480 * key in the interior node referencing the child block.
481 *
482 * fixes cases where entries have been shifted between
483 * child blocks but the parent hasn't been updated. We
484 * don't have to worry about the key values in the cursor
485 * not being set since we only look at the key values of
486 * our child and those are guaranteed to be set by the
487 * call to scan_lbtree() above.
488 */
5e656dbb 489 if (check_dups == 0 && be64_to_cpu(pkey[i].br_startoff) !=
2bd0ea18
NS
490 bm_cursor->level[level-1].first_key) {
491 if (!no_modify) {
492 do_warn(
5d1b7f0f
CH
493_("correcting bt key (was %llu, now %" PRIu64 ") in inode %" PRIu64 "\n"
494 "\t\t%s fork, btree block %" PRIu64 "\n"),
495 (unsigned long long)
496 be64_to_cpu(pkey[i].br_startoff),
2bd0ea18 497 bm_cursor->level[level-1].first_key,
507f4e33 498 ino,
2bd0ea18
NS
499 forkname, bno);
500 *dirty = 1;
5e656dbb 501 pkey[i].br_startoff = cpu_to_be64(
507f4e33 502 bm_cursor->level[level-1].first_key);
2bd0ea18
NS
503 } else {
504 do_warn(
5d1b7f0f
CH
505_("bad btree key (is %llu, should be %" PRIu64 ") in inode %" PRIu64 "\n"
506 "\t\t%s fork, btree block %" PRIu64 "\n"),
507 (unsigned long long)
508 be64_to_cpu(pkey[i].br_startoff),
2bd0ea18 509 bm_cursor->level[level-1].first_key,
5e656dbb 510 ino, forkname, bno);
2bd0ea18
NS
511 }
512 }
513 }
514
515 /*
e8cb94ee 516 * If we're the last node at our level, check that the last child
4dcea5f4 517 * block's forward sibling pointer is NULL.
2bd0ea18 518 */
dfc130f3 519 if (check_dups == 0 &&
5a35bf2c
DC
520 bm_cursor->level[level].right_fsbno == NULLFSBLOCK &&
521 bm_cursor->level[level - 1].right_fsbno != NULLFSBLOCK) {
2bd0ea18 522 do_warn(
5a35bf2c 523_("bad fwd (right) sibling pointer (saw %" PRIu64 " should be NULLFSBLOCK)\n"
5d1b7f0f 524 "\tin inode %" PRIu64 " (%s fork) bmap btree block %" PRIu64 "\n"),
507f4e33 525 bm_cursor->level[level - 1].right_fsbno,
5e656dbb 526 ino, forkname, bm_cursor->level[level - 1].fsbno);
2bd0ea18
NS
527 return(1);
528 }
529
530 /*
531 * update cursor keys to reflect this block
532 */
533 if (check_dups == 0) {
534 bm_cursor->level[level].first_key =
5e656dbb 535 be64_to_cpu(pkey[0].br_startoff);
2bd0ea18 536 bm_cursor->level[level].last_key =
5e656dbb 537 be64_to_cpu(pkey[numrecs - 1].br_startoff);
2bd0ea18
NS
538 }
539
540 return(0);
541}
542
364a126c 543static void
e0607266 544scan_allocbt(
b3563c19 545 struct xfs_btree_block *block,
2bd0ea18
NS
546 int level,
547 xfs_agblock_t bno,
548 xfs_agnumber_t agno,
549 int suspect,
64a0b0ab 550 int isroot,
364a126c 551 __uint32_t magic,
e0607266 552 void *priv)
2bd0ea18 553{
e0607266 554 struct aghdr_cnts *agcnts = priv;
64a0b0ab 555 const char *name;
2bd0ea18
NS
556 int i;
557 xfs_alloc_ptr_t *pp;
558 xfs_alloc_rec_t *rp;
559 int hdr_errors = 0;
560 int numrecs;
561 int state;
c9638a82
CH
562 xfs_extlen_t lastcount = 0;
563 xfs_agblock_t lastblock = 0;
2bd0ea18 564
e0607266
DC
565 switch (magic) {
566 case XFS_ABTB_CRC_MAGIC:
567 case XFS_ABTB_MAGIC:
568 name = "bno";
569 break;
570 case XFS_ABTC_CRC_MAGIC:
571 case XFS_ABTC_MAGIC:
572 name = "cnt";
573 break;
574 default:
6bddecbc 575 name = "(unknown)";
e0607266
DC
576 assert(0);
577 break;
578 }
64a0b0ab
CH
579
580 if (be32_to_cpu(block->bb_magic) != magic) {
581 do_warn(_("bad magic # %#x in bt%s block %d/%d\n"),
582 be32_to_cpu(block->bb_magic), name, agno, bno);
2bd0ea18
NS
583 hdr_errors++;
584 if (suspect)
585 return;
586 }
48d49157
CH
587
588 /*
589 * All freespace btree blocks except the roots are freed for a
590 * fully used filesystem, thus they are counted towards the
591 * free data block counter.
592 */
593 if (!isroot) {
364a126c
DC
594 agcnts->agfbtreeblks++;
595 agcnts->fdblocks++;
48d49157
CH
596 }
597
5e656dbb 598 if (be16_to_cpu(block->bb_level) != level) {
64a0b0ab
CH
599 do_warn(_("expected level %d got %d in bt%s block %d/%d\n"),
600 level, be16_to_cpu(block->bb_level), name, agno, bno);
2bd0ea18
NS
601 hdr_errors++;
602 if (suspect)
603 return;
604 }
605
606 /*
607 * check for btree blocks multiply claimed
608 */
95650c4d
BN
609 state = get_bmap(agno, bno);
610 if (state != XR_E_UNKNOWN) {
611 set_bmap(agno, bno, XR_E_MULT);
2bd0ea18 612 do_warn(
64a0b0ab
CH
613_("%s freespace btree block claimed (state %d), agno %d, bno %d, suspect %d\n"),
614 name, state, agno, bno, suspect);
2bd0ea18
NS
615 return;
616 }
95650c4d 617 set_bmap(agno, bno, XR_E_FS_MAP);
2bd0ea18 618
5e656dbb
BN
619 numrecs = be16_to_cpu(block->bb_numrecs);
620
2bd0ea18 621 if (level == 0) {
5e656dbb 622 if (numrecs > mp->m_alloc_mxr[0]) {
2bd0ea18
NS
623 numrecs = mp->m_alloc_mxr[0];
624 hdr_errors++;
625 }
5e656dbb 626 if (isroot == 0 && numrecs < mp->m_alloc_mnr[0]) {
2bd0ea18
NS
627 numrecs = mp->m_alloc_mnr[0];
628 hdr_errors++;
629 }
630
c9638a82
CH
631 if (hdr_errors) {
632 do_warn(
633 _("bad btree nrecs (%u, min=%u, max=%u) in bt%s block %u/%u\n"),
634 be16_to_cpu(block->bb_numrecs),
635 mp->m_alloc_mnr[0], mp->m_alloc_mxr[0],
636 name, agno, bno);
2bd0ea18 637 suspect++;
c9638a82 638 }
2bd0ea18 639
b3563c19 640 rp = XFS_ALLOC_REC_ADDR(mp, block, 1);
2bd0ea18 641 for (i = 0; i < numrecs; i++) {
08382cf4 642 xfs_agblock_t b, end;
8961bfde 643 xfs_extlen_t len, blen;
08382cf4
BN
644
645 b = be32_to_cpu(rp[i].ar_startblock);
646 len = be32_to_cpu(rp[i].ar_blockcount);
647 end = b + len;
2bd0ea18 648
c83b756d
CH
649 if (b == 0 || !verify_agbno(mp, agno, b)) {
650 do_warn(
5d1b7f0f 651 _("invalid start block %u in record %u of %s btree block %u/%u\n"),
c83b756d 652 b, i, name, agno, bno);
08382cf4 653 continue;
c83b756d
CH
654 }
655 if (len == 0 || !verify_agbno(mp, agno, end - 1)) {
656 do_warn(
5d1b7f0f 657 _("invalid length %u in record %u of %s btree block %u/%u\n"),
c83b756d 658 len, i, name, agno, bno);
909daa84 659 continue;
c83b756d 660 }
08382cf4 661
e0607266
DC
662 if (magic == XFS_ABTB_MAGIC ||
663 magic == XFS_ABTB_CRC_MAGIC) {
c9638a82
CH
664 if (b <= lastblock) {
665 do_warn(_(
666 "out-of-order bno btree record %d (%u %u) block %u/%u\n"),
667 i, b, len, agno, bno);
668 } else {
669 lastblock = b;
670 }
671 } else {
364a126c
DC
672 agcnts->fdblocks += len;
673 agcnts->agffreeblks += len;
674 if (len > agcnts->agflongest)
675 agcnts->agflongest = len;
c9638a82
CH
676 if (len < lastcount) {
677 do_warn(_(
678 "out-of-order cnt btree record %d (%u %u) block %u/%u\n"),
679 i, b, len, agno, bno);
680 } else {
681 lastcount = len;
682 }
683 }
684
8961bfde
BN
685 for ( ; b < end; b += blen) {
686 state = get_bmap_ext(agno, b, end, &blen);
64a0b0ab
CH
687 switch (state) {
688 case XR_E_UNKNOWN:
95650c4d 689 set_bmap(agno, b, XR_E_FREE1);
64a0b0ab
CH
690 break;
691 case XR_E_FREE1:
692 /*
693 * no warning messages -- we'll catch
694 * FREE1 blocks later
695 */
e0607266
DC
696 if (magic == XFS_ABTC_MAGIC ||
697 magic == XFS_ABTC_CRC_MAGIC) {
8961bfde
BN
698 set_bmap_ext(agno, b, blen,
699 XR_E_FREE);
64a0b0ab
CH
700 break;
701 }
702 default:
507f4e33 703 do_warn(
8961bfde
BN
704 _("block (%d,%d-%d) multiply claimed by %s space tree, state - %d\n"),
705 agno, b, b + blen - 1,
706 name, state);
64a0b0ab 707 break;
2bd0ea18
NS
708 }
709 }
710 }
711 return;
712 }
713
714 /*
715 * interior record
716 */
b3563c19 717 pp = XFS_ALLOC_PTR_ADDR(mp, block, 1, mp->m_alloc_mxr[1]);
2bd0ea18 718
5e656dbb 719 if (numrecs > mp->m_alloc_mxr[1]) {
2bd0ea18
NS
720 numrecs = mp->m_alloc_mxr[1];
721 hdr_errors++;
722 }
5e656dbb 723 if (isroot == 0 && numrecs < mp->m_alloc_mnr[1]) {
2bd0ea18
NS
724 numrecs = mp->m_alloc_mnr[1];
725 hdr_errors++;
726 }
727
728 /*
729 * don't pass bogus tree flag down further if this block
730 * looked ok. bail out if two levels in a row look bad.
731 */
2bd0ea18 732 if (hdr_errors) {
c9638a82
CH
733 do_warn(
734 _("bad btree nrecs (%u, min=%u, max=%u) in bt%s block %u/%u\n"),
735 be16_to_cpu(block->bb_numrecs),
736 mp->m_alloc_mnr[1], mp->m_alloc_mxr[1],
737 name, agno, bno);
2bd0ea18
NS
738 if (suspect)
739 return;
c9638a82
CH
740 suspect++;
741 } else if (suspect) {
742 suspect = 0;
2bd0ea18
NS
743 }
744
745 for (i = 0; i < numrecs; i++) {
08382cf4
BN
746 xfs_agblock_t bno = be32_to_cpu(pp[i]);
747
2bd0ea18
NS
748 /*
749 * XXX - put sibling detection right here.
750 * we know our sibling chain is good. So as we go,
751 * we check the entry before and after each entry.
752 * If either of the entries references a different block,
753 * check the sibling pointer. If there's a sibling
754 * pointer mismatch, try and extract as much data
dfc130f3 755 * as possible.
2bd0ea18 756 */
08382cf4 757 if (bno != 0 && verify_agbno(mp, agno, bno)) {
e0607266
DC
758 switch (magic) {
759 case XFS_ABTB_CRC_MAGIC:
760 case XFS_ABTB_MAGIC:
761 scan_sbtree(bno, level, agno, suspect,
762 scan_allocbt, 0, magic, priv,
763 &xfs_allocbt_buf_ops);
764 break;
765 case XFS_ABTC_CRC_MAGIC:
766 case XFS_ABTC_MAGIC:
767 scan_sbtree(bno, level, agno, suspect,
768 scan_allocbt, 0, magic, priv,
769 &xfs_allocbt_buf_ops);
770 break;
771 }
08382cf4 772 }
2bd0ea18
NS
773 }
774}
775
c749bd55
BF
776static bool
777ino_issparse(
778 struct xfs_inobt_rec *rp,
779 int offset)
780{
781 if (!xfs_sb_version_hassparseinodes(&mp->m_sb))
782 return false;
783
784 return xfs_inobt_is_sparse_disk(rp, offset);
785}
786
0f94fa4b
DW
787/* See if the rmapbt owners agree with our observations. */
788static void
789process_rmap_rec(
790 struct xfs_mount *mp,
791 xfs_agnumber_t agno,
792 xfs_agblock_t b,
793 xfs_agblock_t end,
794 xfs_extlen_t blen,
795 int64_t owner,
796 int state,
797 const char *name)
798{
799 switch (state) {
800 case XR_E_UNKNOWN:
801 switch (owner) {
802 case XFS_RMAP_OWN_FS:
803 case XFS_RMAP_OWN_LOG:
804 set_bmap_ext(agno, b, blen, XR_E_INUSE_FS1);
805 break;
806 case XFS_RMAP_OWN_AG:
807 case XFS_RMAP_OWN_INOBT:
808 set_bmap_ext(agno, b, blen, XR_E_FS_MAP1);
809 break;
810 case XFS_RMAP_OWN_INODES:
811 set_bmap_ext(agno, b, blen, XR_E_INO1);
812 break;
813 case XFS_RMAP_OWN_NULL:
814 /* still unknown */
815 break;
816 default:
817 /* file data */
818 set_bmap_ext(agno, b, blen, XR_E_INUSE1);
819 break;
820 }
821 break;
822 case XR_E_INUSE_FS:
823 if (owner == XFS_RMAP_OWN_FS ||
824 owner == XFS_RMAP_OWN_LOG)
825 break;
826 do_warn(
827_("Static meta block (%d,%d-%d) mismatch in %s tree, state - %d,%" PRIx64 "\n"),
828 agno, b, b + blen - 1,
829 name, state, owner);
830 break;
831 case XR_E_FS_MAP:
832 if (owner == XFS_RMAP_OWN_AG ||
833 owner == XFS_RMAP_OWN_INOBT)
834 break;
835 do_warn(
836_("AG meta block (%d,%d-%d) mismatch in %s tree, state - %d,%" PRIx64 "\n"),
837 agno, b, b + blen - 1,
838 name, state, owner);
839 break;
840 case XR_E_INO:
841 if (owner == XFS_RMAP_OWN_INODES)
842 break;
843 do_warn(
844_("inode block (%d,%d-%d) mismatch in %s tree, state - %d,%" PRIx64 "\n"),
845 agno, b, b + blen - 1,
846 name, state, owner);
847 break;
848 case XR_E_INUSE:
849 if (owner >= 0 &&
850 owner < mp->m_sb.sb_dblocks)
851 break;
852 do_warn(
853_("in use block (%d,%d-%d) mismatch in %s tree, state - %d,%" PRIx64 "\n"),
854 agno, b, b + blen - 1,
855 name, state, owner);
856 break;
857 case XR_E_FREE1:
858 case XR_E_FREE:
859 /*
860 * May be on the AGFL. If not, they'll
861 * be caught later.
862 */
863 break;
864 default:
865 do_warn(
866_("unknown block (%d,%d-%d) mismatch on %s tree, state - %d,%" PRIx64 "\n"),
867 agno, b, b + blen - 1,
868 name, state, owner);
869 break;
870 }
871}
872
11b9e510
DW
873struct rmap_priv {
874 struct aghdr_cnts *agcnts;
875 struct xfs_rmap_irec high_key;
65841734 876 struct xfs_rmap_irec last_rec;
11b9e510
DW
877 xfs_agblock_t nr_blocks;
878};
879
0f94fa4b
DW
880static void
881scan_rmapbt(
882 struct xfs_btree_block *block,
883 int level,
884 xfs_agblock_t bno,
885 xfs_agnumber_t agno,
886 int suspect,
887 int isroot,
888 __uint32_t magic,
889 void *priv)
890{
0f94fa4b
DW
891 const char *name = "rmap";
892 int i;
893 xfs_rmap_ptr_t *pp;
894 struct xfs_rmap_rec *rp;
11b9e510 895 struct rmap_priv *rmap_priv = priv;
0f94fa4b
DW
896 int hdr_errors = 0;
897 int numrecs;
898 int state;
899 xfs_agblock_t lastblock = 0;
11b9e510 900 struct xfs_rmap_key *kp;
138ce9ff 901 struct xfs_rmap_irec key = {0};
0f94fa4b
DW
902
903 if (magic != XFS_RMAP_CRC_MAGIC) {
904 name = "(unknown)";
11b9e510
DW
905 hdr_errors++;
906 suspect++;
907 goto out;
0f94fa4b
DW
908 }
909
910 if (be32_to_cpu(block->bb_magic) != magic) {
911 do_warn(_("bad magic # %#x in bt%s block %d/%d\n"),
912 be32_to_cpu(block->bb_magic), name, agno, bno);
913 hdr_errors++;
914 if (suspect)
11b9e510 915 goto out;
0f94fa4b
DW
916 }
917
918 /*
919 * All RMAP btree blocks except the roots are freed for a
920 * fully empty filesystem, thus they are counted towards the
921 * free data block counter.
922 */
923 if (!isroot) {
11b9e510
DW
924 rmap_priv->agcnts->agfbtreeblks++;
925 rmap_priv->agcnts->fdblocks++;
0f94fa4b 926 }
11b9e510 927 rmap_priv->nr_blocks++;
0f94fa4b
DW
928
929 if (be16_to_cpu(block->bb_level) != level) {
930 do_warn(_("expected level %d got %d in bt%s block %d/%d\n"),
931 level, be16_to_cpu(block->bb_level), name, agno, bno);
932 hdr_errors++;
933 if (suspect)
11b9e510 934 goto out;
0f94fa4b
DW
935 }
936
937 /* check for btree blocks multiply claimed */
938 state = get_bmap(agno, bno);
939 if (!(state == XR_E_UNKNOWN || state == XR_E_FS_MAP1)) {
940 set_bmap(agno, bno, XR_E_MULT);
941 do_warn(
942_("%s rmap btree block claimed (state %d), agno %d, bno %d, suspect %d\n"),
943 name, state, agno, bno, suspect);
11b9e510 944 goto out;
0f94fa4b
DW
945 }
946 set_bmap(agno, bno, XR_E_FS_MAP);
947
948 numrecs = be16_to_cpu(block->bb_numrecs);
949 if (level == 0) {
950 if (numrecs > mp->m_rmap_mxr[0]) {
951 numrecs = mp->m_rmap_mxr[0];
952 hdr_errors++;
953 }
954 if (isroot == 0 && numrecs < mp->m_rmap_mnr[0]) {
955 numrecs = mp->m_rmap_mnr[0];
956 hdr_errors++;
957 }
958
959 if (hdr_errors) {
960 do_warn(
961 _("bad btree nrecs (%u, min=%u, max=%u) in bt%s block %u/%u\n"),
962 be16_to_cpu(block->bb_numrecs),
963 mp->m_rmap_mnr[0], mp->m_rmap_mxr[0],
964 name, agno, bno);
965 suspect++;
966 }
967
968 rp = XFS_RMAP_REC_ADDR(block, 1);
969 for (i = 0; i < numrecs; i++) {
970 xfs_agblock_t b, end;
971 xfs_extlen_t len, blen;
972 int64_t owner, offset;
973
974 b = be32_to_cpu(rp[i].rm_startblock);
975 len = be32_to_cpu(rp[i].rm_blockcount);
976 owner = be64_to_cpu(rp[i].rm_owner);
977 offset = be64_to_cpu(rp[i].rm_offset);
11b9e510
DW
978
979 key.rm_flags = 0;
980 key.rm_startblock = b;
981 key.rm_blockcount = len;
982 key.rm_owner = owner;
983 if (libxfs_rmap_irec_offset_unpack(offset, &key)) {
984 /* Look for impossible flags. */
985 do_warn(
986 _("invalid flags in record %u of %s btree block %u/%u\n"),
987 i, name, agno, bno);
988 continue;
989 }
990
991 end = key.rm_startblock + key.rm_blockcount;
0f94fa4b
DW
992
993 /* Make sure agbno & len make sense. */
994 if (!verify_agbno(mp, agno, b)) {
995 do_warn(
996 _("invalid start block %u in record %u of %s btree block %u/%u\n"),
997 b, i, name, agno, bno);
998 continue;
999 }
1000 if (len == 0 || !verify_agbno(mp, agno, end - 1)) {
1001 do_warn(
1002 _("invalid length %u in record %u of %s btree block %u/%u\n"),
1003 len, i, name, agno, bno);
1004 continue;
1005 }
1006
1007 /* Look for impossible owners. */
1008 if (!(owner > 0 || (owner > XFS_RMAP_OWN_MIN &&
1009 owner <= XFS_RMAP_OWN_FS)))
1010 do_warn(
1011 _("invalid owner in rmap btree record %d (%"PRId64" %u) block %u/%u\n"),
1012 i, owner, len, agno, bno);
1013
a418fe7d
DW
1014 /* Look for impossible record field combinations. */
1015 if (XFS_RMAP_NON_INODE_OWNER(key.rm_owner)) {
1016 if (key.rm_flags)
1017 do_warn(
1018 _("record %d of block (%u/%u) in %s btree cannot have non-inode owner with flags\n"),
1019 i, agno, bno, name);
1020 if (key.rm_offset)
1021 do_warn(
1022 _("record %d of block (%u/%u) in %s btree cannot have non-inode owner with offset\n"),
1023 i, agno, bno, name);
1024 }
1025
0f94fa4b
DW
1026 /* Check for out of order records. */
1027 if (i == 0) {
1028advance:
1029 lastblock = b;
0f94fa4b
DW
1030 } else {
1031 bool bad;
1032
1033 bad = b <= lastblock;
1034 if (bad)
1035 do_warn(
1036 _("out-of-order rmap btree record %d (%u %"PRId64" %"PRIx64" %u) block %u/%u\n"),
1037 i, b, owner, offset, len, agno, bno);
1038 else
1039 goto advance;
1040 }
1041
65841734 1042 /* Is this mergeable with the previous record? */
2d273771 1043 if (rmaps_are_mergeable(&rmap_priv->last_rec, &key)) {
65841734
DW
1044 do_warn(
1045 _("record %d in block (%u/%u) of %s tree should be merged with previous record\n"),
1046 i, agno, bno, name);
1047 rmap_priv->last_rec.rm_blockcount +=
1048 key.rm_blockcount;
1049 } else
1050 rmap_priv->last_rec = key;
1051
11b9e510
DW
1052 /* Check that we don't go past the high key. */
1053 key.rm_startblock += key.rm_blockcount - 1;
1054 if (!XFS_RMAP_NON_INODE_OWNER(key.rm_owner) &&
1055 !(key.rm_flags & XFS_RMAP_BMBT_BLOCK))
1056 key.rm_offset += key.rm_blockcount - 1;
1057 key.rm_blockcount = 0;
1058 if (rmap_diffkeys(&key, &rmap_priv->high_key) > 0) {
1059 do_warn(
1060 _("record %d greater than high key of block (%u/%u) in %s tree\n"),
1061 i, agno, bno, name);
1062 }
1063
0f94fa4b
DW
1064 /* Check for block owner collisions. */
1065 for ( ; b < end; b += blen) {
1066 state = get_bmap_ext(agno, b, end, &blen);
1067 process_rmap_rec(mp, agno, b, end, blen, owner,
1068 state, name);
1069 }
1070 }
11b9e510 1071 goto out;
0f94fa4b
DW
1072 }
1073
1074 /*
1075 * interior record
1076 */
1077 pp = XFS_RMAP_PTR_ADDR(block, 1, mp->m_rmap_mxr[1]);
1078
1079 if (numrecs > mp->m_rmap_mxr[1]) {
1080 numrecs = mp->m_rmap_mxr[1];
1081 hdr_errors++;
1082 }
1083 if (isroot == 0 && numrecs < mp->m_rmap_mnr[1]) {
1084 numrecs = mp->m_rmap_mnr[1];
1085 hdr_errors++;
1086 }
1087
1088 /*
1089 * don't pass bogus tree flag down further if this block
1090 * looked ok. bail out if two levels in a row look bad.
1091 */
1092 if (hdr_errors) {
1093 do_warn(
1094 _("bad btree nrecs (%u, min=%u, max=%u) in bt%s block %u/%u\n"),
1095 be16_to_cpu(block->bb_numrecs),
1096 mp->m_rmap_mnr[1], mp->m_rmap_mxr[1],
1097 name, agno, bno);
1098 if (suspect)
11b9e510 1099 goto out;
0f94fa4b
DW
1100 suspect++;
1101 } else if (suspect) {
1102 suspect = 0;
1103 }
1104
11b9e510
DW
1105 /* check the node's high keys */
1106 for (i = 0; !isroot && i < numrecs; i++) {
1107 kp = XFS_RMAP_HIGH_KEY_ADDR(block, i + 1);
1108
1109 key.rm_flags = 0;
1110 key.rm_startblock = be32_to_cpu(kp->rm_startblock);
1111 key.rm_owner = be64_to_cpu(kp->rm_owner);
1112 if (libxfs_rmap_irec_offset_unpack(be64_to_cpu(kp->rm_offset),
1113 &key)) {
1114 /* Look for impossible flags. */
1115 do_warn(
1116 _("invalid flags in key %u of %s btree block %u/%u\n"),
1117 i, name, agno, bno);
1118 continue;
1119 }
1120 if (rmap_diffkeys(&key, &rmap_priv->high_key) > 0)
1121 do_warn(
1122 _("key %d greater than high key of block (%u/%u) in %s tree\n"),
1123 i, agno, bno, name);
1124 }
1125
0f94fa4b
DW
1126 for (i = 0; i < numrecs; i++) {
1127 xfs_agblock_t bno = be32_to_cpu(pp[i]);
1128
1129 /*
1130 * XXX - put sibling detection right here.
1131 * we know our sibling chain is good. So as we go,
1132 * we check the entry before and after each entry.
1133 * If either of the entries references a different block,
1134 * check the sibling pointer. If there's a sibling
1135 * pointer mismatch, try and extract as much data
1136 * as possible.
1137 */
11b9e510
DW
1138 kp = XFS_RMAP_HIGH_KEY_ADDR(block, i + 1);
1139 rmap_priv->high_key.rm_flags = 0;
1140 rmap_priv->high_key.rm_startblock =
1141 be32_to_cpu(kp->rm_startblock);
1142 rmap_priv->high_key.rm_owner =
1143 be64_to_cpu(kp->rm_owner);
1144 if (libxfs_rmap_irec_offset_unpack(be64_to_cpu(kp->rm_offset),
1145 &rmap_priv->high_key)) {
1146 /* Look for impossible flags. */
1147 do_warn(
1148 _("invalid flags in high key %u of %s btree block %u/%u\n"),
1149 i, name, agno, bno);
1150 continue;
1151 }
1152
0f94fa4b
DW
1153 if (bno != 0 && verify_agbno(mp, agno, bno)) {
1154 scan_sbtree(bno, level, agno, suspect, scan_rmapbt, 0,
1155 magic, priv, &xfs_rmapbt_buf_ops);
1156 }
1157 }
11b9e510
DW
1158
1159out:
1160 if (suspect)
1161 rmap_avoid_check();
0f94fa4b
DW
1162}
1163
22458187
BF
1164/*
1165 * The following helpers are to help process and validate individual on-disk
1166 * inode btree records. We have two possible inode btrees with slightly
1167 * different semantics. Many of the validations and actions are equivalent, such
1168 * as record alignment constraints, etc. Other validations differ, such as the
1169 * fact that the inode chunk block allocation state is set by the content of the
1170 * core inobt and verified by the content of the finobt.
1171 *
1172 * The following structures are used to facilitate common validation routines
1173 * where the only difference between validation of the inobt or finobt might be
1174 * the error messages that results in the event of failure.
1175 */
1176
1177enum inobt_type {
1178 INOBT,
1179 FINOBT
1180};
1181const char *inobt_names[] = {
1182 "inobt",
1183 "finobt"
1184};
1185
6ceb5693 1186static int
22458187 1187verify_single_ino_chunk_align(
6ceb5693 1188 xfs_agnumber_t agno,
22458187
BF
1189 enum inobt_type type,
1190 struct xfs_inobt_rec *rp,
1191 int suspect,
1192 bool *skip)
6ceb5693 1193{
22458187 1194 const char *inobt_name = inobt_names[type];
6ceb5693
BN
1195 xfs_ino_t lino;
1196 xfs_agino_t ino;
1197 xfs_agblock_t agbno;
6ceb5693 1198 int off;
6ceb5693 1199
22458187 1200 *skip = false;
6ceb5693
BN
1201 ino = be32_to_cpu(rp->ir_startino);
1202 off = XFS_AGINO_TO_OFFSET(mp, ino);
1203 agbno = XFS_AGINO_TO_AGBNO(mp, ino);
1204 lino = XFS_AGINO_TO_INO(mp, agno, ino);
1205
1206 /*
22458187
BF
1207 * on multi-block block chunks, all chunks start at the beginning of the
1208 * block. with multi-chunk blocks, all chunks must start on 64-inode
1209 * boundaries since each block can hold N complete chunks. if fs has
1210 * aligned inodes, all chunks must start at a fs_ino_alignment*N'th
1211 * agbno. skip recs with badly aligned starting inodes.
6ceb5693
BN
1212 */
1213 if (ino == 0 ||
1214 (inodes_per_block <= XFS_INODES_PER_CHUNK && off != 0) ||
1215 (inodes_per_block > XFS_INODES_PER_CHUNK &&
1216 off % XFS_INODES_PER_CHUNK != 0) ||
ca0a799e 1217 (fs_aligned_inodes && fs_ino_alignment &&
22458187 1218 agbno % fs_ino_alignment != 0)) {
6ceb5693 1219 do_warn(
22458187
BF
1220 _("badly aligned %s rec (starting inode = %" PRIu64 ")\n"),
1221 inobt_name, lino);
6ceb5693
BN
1222 suspect++;
1223 }
1224
1225 /*
22458187
BF
1226 * verify numeric validity of inode chunk first before inserting into a
1227 * tree. don't have to worry about the overflow case because the
1228 * starting ino number of a chunk can only get within 255 inodes of max
1229 * (NULLAGINO). if it gets closer, the agino number will be illegal as
1230 * the agbno will be too large.
6ceb5693 1231 */
22458187 1232 if (verify_aginum(mp, agno, ino)) {
6ceb5693 1233 do_warn(
22458187
BF
1234_("bad starting inode # (%" PRIu64 " (0x%x 0x%x)) in %s rec, skipping rec\n"),
1235 lino, agno, ino, inobt_name);
1236 *skip = true;
6ceb5693
BN
1237 return ++suspect;
1238 }
1239
1240 if (verify_aginum(mp, agno,
22458187 1241 ino + XFS_INODES_PER_CHUNK - 1)) {
6ceb5693 1242 do_warn(
22458187 1243_("bad ending inode # (%" PRIu64 " (0x%x 0x%zx)) in %s rec, skipping rec\n"),
6ceb5693 1244 lino + XFS_INODES_PER_CHUNK - 1,
5d1b7f0f 1245 agno,
22458187
BF
1246 ino + XFS_INODES_PER_CHUNK - 1,
1247 inobt_name);
1248 *skip = true;
6ceb5693
BN
1249 return ++suspect;
1250 }
1251
22458187
BF
1252 return suspect;
1253}
1254
411c5e55
BF
1255/*
1256 * Process the state of individual inodes in an on-disk inobt record and import
1257 * into the appropriate in-core tree based on whether the on-disk tree is
1258 * suspect. Return the total and free inode counts based on the record free and
1259 * hole masks.
1260 */
1261static int
1262import_single_ino_chunk(
1263 xfs_agnumber_t agno,
1264 enum inobt_type type,
1265 struct xfs_inobt_rec *rp,
1266 int suspect,
1267 int *p_nfree,
1268 int *p_ninodes)
1269{
1270 struct ino_tree_node *ino_rec = NULL;
1271 const char *inobt_name = inobt_names[type];
1272 xfs_agino_t ino;
1273 int j;
1274 int nfree;
1275 int ninodes;
1276
1277 ino = be32_to_cpu(rp->ir_startino);
1278
1279 if (!suspect) {
1280 if (XFS_INOBT_IS_FREE_DISK(rp, 0))
1281 ino_rec = set_inode_free_alloc(mp, agno, ino);
1282 else
1283 ino_rec = set_inode_used_alloc(mp, agno, ino);
1284 for (j = 1; j < XFS_INODES_PER_CHUNK; j++) {
1285 if (XFS_INOBT_IS_FREE_DISK(rp, j))
1286 set_inode_free(ino_rec, j);
1287 else
1288 set_inode_used(ino_rec, j);
1289 }
1290 } else {
1291 for (j = 0; j < XFS_INODES_PER_CHUNK; j++) {
1292 if (XFS_INOBT_IS_FREE_DISK(rp, j))
1293 add_aginode_uncertain(mp, agno, ino + j, 1);
1294 else
1295 add_aginode_uncertain(mp, agno, ino + j, 0);
1296 }
1297 }
1298
1299 /*
1300 * Mark sparse inodes as such in the in-core tree. Verify that sparse
1301 * inodes are free and that freecount is consistent with the free mask.
1302 */
1303 nfree = ninodes = 0;
1304 for (j = 0; j < XFS_INODES_PER_CHUNK; j++) {
1305 if (ino_issparse(rp, j)) {
1306 if (!suspect && !XFS_INOBT_IS_FREE_DISK(rp, j)) {
1307 do_warn(
1308_("ir_holemask/ir_free mismatch, %s chunk %d/%u, holemask 0x%x free 0x%llx\n"),
1309 inobt_name, agno, ino,
1310 be16_to_cpu(rp->ir_u.sp.ir_holemask),
1311 be64_to_cpu(rp->ir_free));
1312 suspect++;
1313 }
1314 if (!suspect && ino_rec)
1315 set_inode_sparse(ino_rec, j);
1316 } else {
1317 /* count fields track non-sparse inos */
1318 if (XFS_INOBT_IS_FREE_DISK(rp, j))
1319 nfree++;
1320 ninodes++;
1321 }
1322 }
1323
1324 *p_nfree = nfree;
1325 *p_ninodes = ninodes;
1326
1327 return suspect;
1328}
1329
22458187
BF
1330static int
1331scan_single_ino_chunk(
1332 xfs_agnumber_t agno,
1333 xfs_inobt_rec_t *rp,
1334 int suspect)
1335{
1336 xfs_ino_t lino;
1337 xfs_agino_t ino;
1338 xfs_agblock_t agbno;
1339 int j;
1340 int nfree;
1341 int ninodes;
1342 int off;
1343 int state;
22458187
BF
1344 ino_tree_node_t *first_rec, *last_rec;
1345 int freecount;
1346 bool skip = false;
1347
1348 ino = be32_to_cpu(rp->ir_startino);
1349 off = XFS_AGINO_TO_OFFSET(mp, ino);
1350 agbno = XFS_AGINO_TO_AGBNO(mp, ino);
1351 lino = XFS_AGINO_TO_INO(mp, agno, ino);
1352 freecount = inorec_get_freecount(mp, rp);
1353
1354 /*
1355 * Verify record alignment, start/end inode numbers, etc.
1356 */
1357 suspect = verify_single_ino_chunk_align(agno, INOBT, rp, suspect,
1358 &skip);
1359 if (skip)
1360 return suspect;
1361
6ceb5693
BN
1362 /*
1363 * set state of each block containing inodes
1364 */
1365 if (off == 0 && !suspect) {
1366 for (j = 0;
1367 j < XFS_INODES_PER_CHUNK;
1368 j += mp->m_sb.sb_inopblock) {
95650c4d 1369
c749bd55
BF
1370 /* inodes in sparse chunks don't use blocks */
1371 if (ino_issparse(rp, j))
1372 continue;
1373
1374 agbno = XFS_AGINO_TO_AGBNO(mp, ino + j);
95650c4d 1375 state = get_bmap(agno, agbno);
0f94fa4b
DW
1376 switch (state) {
1377 case XR_E_INO:
1378 break;
1379 case XR_E_UNKNOWN:
1380 case XR_E_INO1: /* seen by rmap */
95650c4d 1381 set_bmap(agno, agbno, XR_E_INO);
0f94fa4b
DW
1382 break;
1383 case XR_E_INUSE_FS:
1384 case XR_E_INUSE_FS1:
1385 if (agno == 0 &&
1386 ino + j >= first_prealloc_ino &&
1387 ino + j < last_prealloc_ino) {
1388 set_bmap(agno, agbno, XR_E_INO);
1389 break;
1390 }
1391 /* fall through */
1392 default:
1393 /* XXX - maybe should mark block a duplicate */
6ceb5693
BN
1394 do_warn(
1395_("inode chunk claims used block, inobt block - agno %d, bno %d, inopb %d\n"),
1396 agno, agbno, mp->m_sb.sb_inopblock);
6ceb5693
BN
1397 return ++suspect;
1398 }
1399 }
1400 }
1401
1402 /*
1403 * ensure only one avl entry per chunk
1404 */
1ae311d5 1405 find_inode_rec_range(mp, agno, ino, ino + XFS_INODES_PER_CHUNK,
6ceb5693
BN
1406 &first_rec, &last_rec);
1407 if (first_rec != NULL) {
1408 /*
1409 * this chunk overlaps with one (or more)
1410 * already in the tree
1411 */
1412 do_warn(
5d1b7f0f 1413_("inode rec for ino %" PRIu64 " (%d/%d) overlaps existing rec (start %d/%d)\n"),
6ceb5693
BN
1414 lino, agno, ino, agno, first_rec->ino_startnum);
1415 suspect++;
1416
1417 /*
1418 * if the 2 chunks start at the same place,
1419 * then we don't have to put this one
1420 * in the uncertain list. go to the next one.
1421 */
1422 if (first_rec->ino_startnum == ino)
1423 return suspect;
1424 }
1425
6ceb5693 1426 /*
411c5e55
BF
1427 * Import the state of individual inodes into the appropriate in-core
1428 * trees, mark them free or used, and get the resulting total and free
1429 * inode counts.
c749bd55 1430 */
4a7d3215 1431 nfree = ninodes = 0;
411c5e55
BF
1432 suspect = import_single_ino_chunk(agno, INOBT, rp, suspect, &nfree,
1433 &ninodes);
c749bd55 1434
aa6ce1f1
BF
1435 if (nfree != freecount) {
1436 do_warn(
1437_("ir_freecount/free mismatch, inode chunk %d/%u, freecount %d nfree %d\n"),
1438 agno, ino, freecount, nfree);
6ceb5693
BN
1439 }
1440
4a7d3215
BF
1441 /* verify sparse record formats have a valid inode count */
1442 if (xfs_sb_version_hassparseinodes(&mp->m_sb) &&
1443 ninodes != rp->ir_u.sp.ir_count) {
1444 do_warn(
1445_("invalid inode count, inode chunk %d/%u, count %d ninodes %d\n"),
1446 agno, ino, rp->ir_u.sp.ir_count, ninodes);
1447 }
1448
6ceb5693
BN
1449 return suspect;
1450}
1451
1578050f
BF
1452static int
1453scan_single_finobt_chunk(
1454 xfs_agnumber_t agno,
1455 xfs_inobt_rec_t *rp,
1456 int suspect)
1457{
1458 xfs_ino_t lino;
1459 xfs_agino_t ino;
1460 xfs_agblock_t agbno;
1461 int j;
1462 int nfree;
4a7d3215 1463 int ninodes;
1578050f
BF
1464 int off;
1465 int state;
3f05ceae 1466 ino_tree_node_t *first_rec, *last_rec;
aa6ce1f1 1467 int freecount;
22458187 1468 bool skip = false;
1578050f
BF
1469
1470 ino = be32_to_cpu(rp->ir_startino);
1471 off = XFS_AGINO_TO_OFFSET(mp, ino);
1472 agbno = XFS_AGINO_TO_AGBNO(mp, ino);
1473 lino = XFS_AGINO_TO_INO(mp, agno, ino);
ac9a3f73 1474 freecount = inorec_get_freecount(mp, rp);
1578050f
BF
1475
1476 /*
22458187 1477 * Verify record alignment, start/end inode numbers, etc.
1578050f 1478 */
22458187
BF
1479 suspect = verify_single_ino_chunk_align(agno, FINOBT, rp, suspect,
1480 &skip);
1481 if (skip)
1482 return suspect;
1578050f
BF
1483
1484 /*
1485 * cross check state of each block containing inodes referenced by the
1486 * finobt against what we have already scanned from the alloc inobt.
1487 */
1488 if (off == 0 && !suspect) {
1489 for (j = 0;
1490 j < XFS_INODES_PER_CHUNK;
1491 j += mp->m_sb.sb_inopblock) {
1492 agbno = XFS_AGINO_TO_AGBNO(mp, ino + j);
1578050f 1493 state = get_bmap(agno, agbno);
3f05ceae
BF
1494
1495 /* sparse inodes should not refer to inode blocks */
1496 if (ino_issparse(rp, j)) {
1497 if (state == XR_E_INO) {
1498 do_warn(
1499_("sparse inode chunk claims inode block, finobt block - agno %d, bno %d, inopb %d\n"),
1500 agno, agbno, mp->m_sb.sb_inopblock);
1501 suspect++;
1502 }
1503 continue;
1504 }
1505
0f94fa4b
DW
1506 switch (state) {
1507 case XR_E_INO:
1508 break;
1509 case XR_E_INO1: /* seen by rmap */
1510 set_bmap(agno, agbno, XR_E_INO);
1511 break;
1512 case XR_E_UNKNOWN:
1578050f
BF
1513 do_warn(
1514_("inode chunk claims untracked block, finobt block - agno %d, bno %d, inopb %d\n"),
1515 agno, agbno, mp->m_sb.sb_inopblock);
1516
1517 set_bmap(agno, agbno, XR_E_INO);
1518 suspect++;
0f94fa4b
DW
1519 break;
1520 case XR_E_INUSE_FS:
1521 case XR_E_INUSE_FS1:
1522 if (agno == 0 &&
1523 ino + j >= first_prealloc_ino &&
1524 ino + j < last_prealloc_ino) {
1525 do_warn(
1526_("inode chunk claims untracked block, finobt block - agno %d, bno %d, inopb %d\n"),
1527 agno, agbno, mp->m_sb.sb_inopblock);
1528
1529 set_bmap(agno, agbno, XR_E_INO);
1530 suspect++;
1531 break;
1532 }
1533 /* fall through */
1534 default:
1578050f
BF
1535 do_warn(
1536_("inode chunk claims used block, finobt block - agno %d, bno %d, inopb %d\n"),
1537 agno, agbno, mp->m_sb.sb_inopblock);
1538 return ++suspect;
1539 }
1540 }
1541 }
1542
1543 /*
1544 * ensure we have an incore entry for each chunk
1545 */
1546 find_inode_rec_range(mp, agno, ino, ino + XFS_INODES_PER_CHUNK,
1547 &first_rec, &last_rec);
1548
1549 if (first_rec) {
1550 if (suspect)
1551 return suspect;
1552
1553 /*
1554 * verify consistency between finobt record and incore state
1555 */
1556 if (first_rec->ino_startnum != ino) {
1557 do_warn(
1558_("finobt rec for ino %" PRIu64 " (%d/%u) does not match existing rec (%d/%d)\n"),
1559 lino, agno, ino, agno, first_rec->ino_startnum);
1560 return ++suspect;
1561 }
1562
4a7d3215 1563 nfree = ninodes = 0;
1578050f
BF
1564 for (j = 0; j < XFS_INODES_PER_CHUNK; j++) {
1565 int isfree = XFS_INOBT_IS_FREE_DISK(rp, j);
3f05ceae 1566 int issparse = ino_issparse(rp, j);
1578050f 1567
4a7d3215
BF
1568 if (!issparse)
1569 ninodes++;
3f05ceae 1570 if (isfree && !issparse)
1578050f
BF
1571 nfree++;
1572
1573 /*
1574 * inode allocation state should be consistent between
1575 * the inobt and finobt
1576 */
1577 if (!suspect &&
1578 isfree != is_inode_free(first_rec, j))
1579 suspect++;
3f05ceae
BF
1580
1581 if (!suspect &&
1582 issparse != is_inode_sparse(first_rec, j))
1583 suspect++;
1578050f
BF
1584 }
1585
1586 goto check_freecount;
1587 }
1588
1589 /*
411c5e55
BF
1590 * The finobt contains a record that the previous inobt scan never
1591 * found. Warn about it and import the inodes into the appropriate
1592 * trees.
1593 *
1594 * Note that this should do the right thing if the previous inobt scan
1595 * had added these inodes to the uncertain tree. If the finobt is not
1596 * suspect, these inodes should supercede the uncertain ones. Otherwise,
1597 * the uncertain tree helpers handle the case where uncertain inodes
1598 * already exist.
1578050f
BF
1599 */
1600 do_warn(_("undiscovered finobt record, ino %" PRIu64 " (%d/%u)\n"),
1601 lino, agno, ino);
1602
4a7d3215 1603 nfree = ninodes = 0;
411c5e55
BF
1604 suspect = import_single_ino_chunk(agno, FINOBT, rp, suspect, &nfree,
1605 &ninodes);
3f05ceae 1606
1578050f
BF
1607check_freecount:
1608
1609 /*
1610 * Verify that the record freecount matches the actual number of free
1611 * inodes counted in the record. Don't increment 'suspect' here, since
1612 * we have already verified the allocation state of the individual
1613 * inodes against the in-core state. This will have already incremented
1614 * 'suspect' if something is wrong. If suspect hasn't been set at this
1615 * point, these warnings mean that we have a simple freecount
1616 * inconsistency or a stray finobt record (as opposed to a broader tree
1617 * corruption). Issue a warning and continue the scan. The final btree
1618 * reconstruction will correct this naturally.
1619 */
aa6ce1f1 1620 if (nfree != freecount) {
1578050f
BF
1621 do_warn(
1622_("finobt ir_freecount/free mismatch, inode chunk %d/%u, freecount %d nfree %d\n"),
aa6ce1f1 1623 agno, ino, freecount, nfree);
1578050f
BF
1624 }
1625
1626 if (!nfree) {
1627 do_warn(
1628_("finobt record with no free inodes, inode chunk %d/%u\n"), agno, ino);
1629 }
1630
4a7d3215
BF
1631 /* verify sparse record formats have a valid inode count */
1632 if (xfs_sb_version_hassparseinodes(&mp->m_sb) &&
1633 ninodes != rp->ir_u.sp.ir_count) {
1634 do_warn(
1635_("invalid inode count, inode chunk %d/%u, count %d ninodes %d\n"),
1636 agno, ino, rp->ir_u.sp.ir_count, ninodes);
1637 }
1638
1578050f
BF
1639 return suspect;
1640}
6ceb5693 1641
2bd0ea18
NS
1642/*
1643 * this one walks the inode btrees sucking the info there into
1644 * the incore avl tree. We try and rescue corrupted btree records
1645 * to minimize our chances of losing inodes. Inode info from potentially
1646 * corrupt sources could be bogus so rather than put the info straight
1647 * into the tree, instead we put it on a list and try and verify the
1648 * info in the next phase by examining what's on disk. At that point,
1649 * we'll be able to figure out what's what and stick the corrected info
1650 * into the tree. We do bail out at some point and give up on a subtree
1651 * so as to avoid walking randomly all over the ag.
1652 *
1653 * Note that it's also ok if the free/inuse info wrong, we can correct
1654 * that when we examine the on-disk inode. The important thing is to
1655 * get the start and alignment of the inode chunks right. Those chunks
1656 * that we aren't sure about go into the uncertain list.
1657 */
364a126c 1658static void
e0607266 1659scan_inobt(
b3563c19 1660 struct xfs_btree_block *block,
2bd0ea18
NS
1661 int level,
1662 xfs_agblock_t bno,
1663 xfs_agnumber_t agno,
1664 int suspect,
364a126c 1665 int isroot,
e0607266 1666 __uint32_t magic,
364a126c 1667 void *priv)
2bd0ea18 1668{
364a126c 1669 struct aghdr_cnts *agcnts = priv;
2bd0ea18 1670 int i;
2bd0ea18
NS
1671 int numrecs;
1672 int state;
1673 xfs_inobt_ptr_t *pp;
1674 xfs_inobt_rec_t *rp;
2bd0ea18 1675 int hdr_errors;
aa6ce1f1 1676 int freecount;
2bd0ea18 1677
2bd0ea18
NS
1678 hdr_errors = 0;
1679
e0607266 1680 if (be32_to_cpu(block->bb_magic) != magic) {
507f4e33 1681 do_warn(_("bad magic # %#x in inobt block %d/%d\n"),
5e656dbb 1682 be32_to_cpu(block->bb_magic), agno, bno);
2bd0ea18
NS
1683 hdr_errors++;
1684 bad_ino_btree = 1;
1685 if (suspect)
1686 return;
1687 }
5e656dbb 1688 if (be16_to_cpu(block->bb_level) != level) {
507f4e33 1689 do_warn(_("expected level %d got %d in inobt block %d/%d\n"),
5e656dbb 1690 level, be16_to_cpu(block->bb_level), agno, bno);
2bd0ea18
NS
1691 hdr_errors++;
1692 bad_ino_btree = 1;
1693 if (suspect)
1694 return;
1695 }
1696
1697 /*
1698 * check for btree blocks multiply claimed, any unknown/free state
1699 * is ok in the bitmap block.
1700 */
95650c4d 1701 state = get_bmap(agno, bno);
2bd0ea18 1702 switch (state) {
0f94fa4b 1703 case XR_E_FS_MAP1: /* already been seen by an rmap scan */
2bd0ea18
NS
1704 case XR_E_UNKNOWN:
1705 case XR_E_FREE1:
1706 case XR_E_FREE:
95650c4d 1707 set_bmap(agno, bno, XR_E_FS_MAP);
2bd0ea18
NS
1708 break;
1709 default:
95650c4d 1710 set_bmap(agno, bno, XR_E_MULT);
2bd0ea18 1711 do_warn(
507f4e33
NS
1712_("inode btree block claimed (state %d), agno %d, bno %d, suspect %d\n"),
1713 state, agno, bno, suspect);
2bd0ea18
NS
1714 }
1715
5e656dbb 1716 numrecs = be16_to_cpu(block->bb_numrecs);
2bd0ea18
NS
1717
1718 /*
1719 * leaf record in btree
1720 */
1721 if (level == 0) {
1722 /* check for trashed btree block */
1723
5e656dbb 1724 if (numrecs > mp->m_inobt_mxr[0]) {
2bd0ea18
NS
1725 numrecs = mp->m_inobt_mxr[0];
1726 hdr_errors++;
1727 }
5e656dbb 1728 if (isroot == 0 && numrecs < mp->m_inobt_mnr[0]) {
2bd0ea18
NS
1729 numrecs = mp->m_inobt_mnr[0];
1730 hdr_errors++;
1731 }
1732
1733 if (hdr_errors) {
1734 bad_ino_btree = 1;
507f4e33 1735 do_warn(_("dubious inode btree block header %d/%d\n"),
2bd0ea18
NS
1736 agno, bno);
1737 suspect++;
1738 }
1739
b3563c19 1740 rp = XFS_INOBT_REC_ADDR(mp, block, 1);
2bd0ea18
NS
1741
1742 /*
1743 * step through the records, each record points to
1744 * a chunk of inodes. The start of inode chunks should
1745 * be block-aligned. Each inode btree rec should point
1746 * to the start of a block of inodes or the start of a group
1747 * of INODES_PER_CHUNK (64) inodes. off is the offset into
1748 * the block. skip processing of bogus records.
1749 */
48d49157 1750 for (i = 0; i < numrecs; i++) {
ac9a3f73 1751 freecount = inorec_get_freecount(mp, &rp[i]);
aa6ce1f1 1752
1578050f
BF
1753 if (magic == XFS_IBT_MAGIC ||
1754 magic == XFS_IBT_CRC_MAGIC) {
85ed3bc3
BF
1755 int icount = XFS_INODES_PER_CHUNK;
1756
1757 /*
1758 * ir_count holds the inode count for all
1759 * records on fs' with sparse inode support
1760 */
1761 if (xfs_sb_version_hassparseinodes(&mp->m_sb))
1762 icount = rp[i].ir_u.sp.ir_count;
1763
1764 agcnts->agicount += icount;
aa6ce1f1
BF
1765 agcnts->agifreecount += freecount;
1766 agcnts->ifreecount += freecount;
1578050f
BF
1767
1768 suspect = scan_single_ino_chunk(agno, &rp[i],
1769 suspect);
1770 } else {
1771 /*
1772 * the finobt tracks records with free inodes,
1773 * so only the free inode count is expected to be
1774 * consistent with the agi
1775 */
aa6ce1f1 1776 agcnts->fibtfreecount += freecount;
48d49157 1777
1578050f
BF
1778 suspect = scan_single_finobt_chunk(agno, &rp[i],
1779 suspect);
1780 }
48d49157 1781 }
2bd0ea18
NS
1782
1783 if (suspect)
1784 bad_ino_btree = 1;
1785
1786 return;
1787 }
1788
1789 /*
1790 * interior record, continue on
1791 */
5e656dbb 1792 if (numrecs > mp->m_inobt_mxr[1]) {
2bd0ea18
NS
1793 numrecs = mp->m_inobt_mxr[1];
1794 hdr_errors++;
1795 }
5e656dbb 1796 if (isroot == 0 && numrecs < mp->m_inobt_mnr[1]) {
2bd0ea18
NS
1797 numrecs = mp->m_inobt_mnr[1];
1798 hdr_errors++;
1799 }
1800
b3563c19 1801 pp = XFS_INOBT_PTR_ADDR(mp, block, 1, mp->m_inobt_mxr[1]);
2bd0ea18
NS
1802
1803 /*
1804 * don't pass bogus tree flag down further if this block
1805 * looked ok. bail out if two levels in a row look bad.
1806 */
1807
1808 if (suspect && !hdr_errors)
1809 suspect = 0;
1810
1811 if (hdr_errors) {
1812 bad_ino_btree = 1;
1813 if (suspect)
1814 return;
1815 else suspect++;
1816 }
1817
1818 for (i = 0; i < numrecs; i++) {
5e656dbb
BN
1819 if (be32_to_cpu(pp[i]) != 0 && verify_agbno(mp, agno,
1820 be32_to_cpu(pp[i])))
1821 scan_sbtree(be32_to_cpu(pp[i]), level, agno,
e0607266
DC
1822 suspect, scan_inobt, 0, magic, priv,
1823 &xfs_inobt_buf_ops);
2bd0ea18
NS
1824 }
1825}
1826
364a126c 1827static void
2bd0ea18 1828scan_freelist(
364a126c
DC
1829 xfs_agf_t *agf,
1830 struct aghdr_cnts *agcnts)
2bd0ea18 1831{
2bd0ea18 1832 xfs_buf_t *agflbuf;
1d0df0af 1833 xfs_agnumber_t agno;
2bd0ea18
NS
1834 xfs_agblock_t bno;
1835 int count;
1836 int i;
84232448 1837 __be32 *freelist;
2bd0ea18 1838
1d0df0af
BN
1839 agno = be32_to_cpu(agf->agf_seqno);
1840
2bd0ea18 1841 if (XFS_SB_BLOCK(mp) != XFS_AGFL_BLOCK(mp) &&
1d0df0af
BN
1842 XFS_AGF_BLOCK(mp) != XFS_AGFL_BLOCK(mp) &&
1843 XFS_AGI_BLOCK(mp) != XFS_AGFL_BLOCK(mp))
0f94fa4b 1844 set_bmap(agno, XFS_AGFL_BLOCK(mp), XR_E_INUSE_FS);
1d0df0af 1845
5e656dbb 1846 if (be32_to_cpu(agf->agf_flcount) == 0)
2bd0ea18 1847 return;
1d0df0af
BN
1848
1849 agflbuf = libxfs_readbuf(mp->m_dev,
1850 XFS_AG_DADDR(mp, agno, XFS_AGFL_DADDR(mp)),
75c8b434 1851 XFS_FSS_TO_BB(mp, 1), 0, &xfs_agfl_buf_ops);
2bd0ea18 1852 if (!agflbuf) {
1d0df0af 1853 do_abort(_("can't read agfl block for ag %d\n"), agno);
2bd0ea18
NS
1854 return;
1855 }
66fc04e0 1856 if (agflbuf->b_error == -EFSBADCRC)
a76a5a71
DC
1857 do_warn(_("agfl has bad CRC for ag %d\n"), agno);
1858
84232448 1859 freelist = XFS_BUF_TO_AGFL_BNO(mp, agflbuf);
a529cc7f 1860 i = be32_to_cpu(agf->agf_flfirst);
7e8e3cce
ES
1861
1862 if (no_modify) {
1863 /* agf values not fixed in verify_set_agf, so recheck */
1864 if (be32_to_cpu(agf->agf_flfirst) >= XFS_AGFL_SIZE(mp) ||
1865 be32_to_cpu(agf->agf_fllast) >= XFS_AGFL_SIZE(mp)) {
1866 do_warn(_("agf %d freelist blocks bad, skipping "
1867 "freelist scan\n"), i);
1868 return;
1869 }
b326e067 1870 }
7e8e3cce 1871
2bd0ea18
NS
1872 count = 0;
1873 for (;;) {
84232448 1874 bno = be32_to_cpu(freelist[i]);
1d0df0af 1875 if (verify_agbno(mp, agno, bno))
95650c4d 1876 set_bmap(agno, bno, XR_E_FREE);
2bd0ea18 1877 else
507f4e33 1878 do_warn(_("bad agbno %u in agfl, agno %d\n"),
1d0df0af 1879 bno, agno);
2bd0ea18 1880 count++;
5e656dbb 1881 if (i == be32_to_cpu(agf->agf_fllast))
2bd0ea18 1882 break;
9440d84d 1883 if (++i == XFS_AGFL_SIZE(mp))
2bd0ea18
NS
1884 i = 0;
1885 }
5e656dbb 1886 if (count != be32_to_cpu(agf->agf_flcount)) {
507f4e33 1887 do_warn(_("freeblk count %d != flcount %d in ag %d\n"), count,
1d0df0af 1888 be32_to_cpu(agf->agf_flcount), agno);
2bd0ea18 1889 }
48d49157 1890
364a126c 1891 agcnts->fdblocks += count;
48d49157 1892
2bd0ea18
NS
1893 libxfs_putbuf(agflbuf);
1894}
1895
48d49157
CH
1896static void
1897validate_agf(
1898 struct xfs_agf *agf,
364a126c
DC
1899 xfs_agnumber_t agno,
1900 struct aghdr_cnts *agcnts)
48d49157
CH
1901{
1902 xfs_agblock_t bno;
e0607266 1903 __uint32_t magic;
48d49157
CH
1904
1905 bno = be32_to_cpu(agf->agf_roots[XFS_BTNUM_BNO]);
1906 if (bno != 0 && verify_agbno(mp, agno, bno)) {
e0607266
DC
1907 magic = xfs_sb_version_hascrc(&mp->m_sb) ? XFS_ABTB_CRC_MAGIC
1908 : XFS_ABTB_MAGIC;
48d49157 1909 scan_sbtree(bno, be32_to_cpu(agf->agf_levels[XFS_BTNUM_BNO]),
e0607266
DC
1910 agno, 0, scan_allocbt, 1, magic, agcnts,
1911 &xfs_allocbt_buf_ops);
48d49157
CH
1912 } else {
1913 do_warn(_("bad agbno %u for btbno root, agno %d\n"),
1914 bno, agno);
1915 }
1916
1917 bno = be32_to_cpu(agf->agf_roots[XFS_BTNUM_CNT]);
1918 if (bno != 0 && verify_agbno(mp, agno, bno)) {
e0607266
DC
1919 magic = xfs_sb_version_hascrc(&mp->m_sb) ? XFS_ABTC_CRC_MAGIC
1920 : XFS_ABTC_MAGIC;
48d49157 1921 scan_sbtree(bno, be32_to_cpu(agf->agf_levels[XFS_BTNUM_CNT]),
e0607266
DC
1922 agno, 0, scan_allocbt, 1, magic, agcnts,
1923 &xfs_allocbt_buf_ops);
48d49157
CH
1924 } else {
1925 do_warn(_("bad agbno %u for btbcnt root, agno %d\n"),
1926 bno, agno);
1927 }
1928
0f94fa4b 1929 if (xfs_sb_version_hasrmapbt(&mp->m_sb)) {
11b9e510
DW
1930 struct rmap_priv priv;
1931
1932 memset(&priv.high_key, 0xFF, sizeof(priv.high_key));
1933 priv.high_key.rm_blockcount = 0;
1934 priv.agcnts = agcnts;
65841734 1935 priv.last_rec.rm_owner = XFS_RMAP_OWN_UNKNOWN;
11b9e510 1936 priv.nr_blocks = 0;
0f94fa4b
DW
1937 bno = be32_to_cpu(agf->agf_roots[XFS_BTNUM_RMAP]);
1938 if (bno != 0 && verify_agbno(mp, agno, bno)) {
1939 scan_sbtree(bno,
1940 be32_to_cpu(agf->agf_levels[XFS_BTNUM_RMAP]),
1941 agno, 0, scan_rmapbt, 1, XFS_RMAP_CRC_MAGIC,
11b9e510
DW
1942 &priv, &xfs_rmapbt_buf_ops);
1943 if (be32_to_cpu(agf->agf_rmap_blocks) != priv.nr_blocks)
1944 do_warn(_("bad rmapbt block count %u, saw %u\n"),
1945 priv.nr_blocks,
1946 be32_to_cpu(agf->agf_rmap_blocks));
0f94fa4b
DW
1947 } else {
1948 do_warn(_("bad agbno %u for rmapbt root, agno %d\n"),
1949 bno, agno);
11b9e510 1950 rmap_avoid_check();
0f94fa4b
DW
1951 }
1952 }
1953
364a126c 1954 if (be32_to_cpu(agf->agf_freeblks) != agcnts->agffreeblks) {
48d49157 1955 do_warn(_("agf_freeblks %u, counted %u in ag %u\n"),
364a126c 1956 be32_to_cpu(agf->agf_freeblks), agcnts->agffreeblks, agno);
48d49157
CH
1957 }
1958
364a126c 1959 if (be32_to_cpu(agf->agf_longest) != agcnts->agflongest) {
48d49157 1960 do_warn(_("agf_longest %u, counted %u in ag %u\n"),
364a126c 1961 be32_to_cpu(agf->agf_longest), agcnts->agflongest, agno);
48d49157
CH
1962 }
1963
1964 if (xfs_sb_version_haslazysbcount(&mp->m_sb) &&
364a126c 1965 be32_to_cpu(agf->agf_btreeblks) != agcnts->agfbtreeblks) {
5d1b7f0f 1966 do_warn(_("agf_btreeblks %u, counted %" PRIu64 " in ag %u\n"),
364a126c 1967 be32_to_cpu(agf->agf_btreeblks), agcnts->agfbtreeblks, agno);
48d49157 1968 }
0f94fa4b 1969
48d49157
CH
1970}
1971
1972static void
1973validate_agi(
1974 struct xfs_agi *agi,
364a126c
DC
1975 xfs_agnumber_t agno,
1976 struct aghdr_cnts *agcnts)
48d49157
CH
1977{
1978 xfs_agblock_t bno;
1979 int i;
e0607266 1980 __uint32_t magic;
48d49157
CH
1981
1982 bno = be32_to_cpu(agi->agi_root);
1983 if (bno != 0 && verify_agbno(mp, agno, bno)) {
e0607266
DC
1984 magic = xfs_sb_version_hascrc(&mp->m_sb) ? XFS_IBT_CRC_MAGIC
1985 : XFS_IBT_MAGIC;
48d49157 1986 scan_sbtree(bno, be32_to_cpu(agi->agi_level),
e0607266
DC
1987 agno, 0, scan_inobt, 1, magic, agcnts,
1988 &xfs_inobt_buf_ops);
48d49157
CH
1989 } else {
1990 do_warn(_("bad agbno %u for inobt root, agno %d\n"),
1991 be32_to_cpu(agi->agi_root), agno);
1992 }
1993
1578050f
BF
1994 if (xfs_sb_version_hasfinobt(&mp->m_sb)) {
1995 bno = be32_to_cpu(agi->agi_free_root);
1996 if (bno != 0 && verify_agbno(mp, agno, bno)) {
1997 magic = xfs_sb_version_hascrc(&mp->m_sb) ?
1998 XFS_FIBT_CRC_MAGIC : XFS_FIBT_MAGIC;
1999 scan_sbtree(bno, be32_to_cpu(agi->agi_free_level),
2000 agno, 0, scan_inobt, 1, magic, agcnts,
2001 &xfs_inobt_buf_ops);
2002 } else {
2003 do_warn(_("bad agbno %u for finobt root, agno %d\n"),
2004 be32_to_cpu(agi->agi_free_root), agno);
2005 }
2006 }
2007
364a126c 2008 if (be32_to_cpu(agi->agi_count) != agcnts->agicount) {
48d49157 2009 do_warn(_("agi_count %u, counted %u in ag %u\n"),
364a126c 2010 be32_to_cpu(agi->agi_count), agcnts->agicount, agno);
48d49157
CH
2011 }
2012
364a126c 2013 if (be32_to_cpu(agi->agi_freecount) != agcnts->agifreecount) {
48d49157 2014 do_warn(_("agi_freecount %u, counted %u in ag %u\n"),
364a126c 2015 be32_to_cpu(agi->agi_freecount), agcnts->agifreecount, agno);
48d49157
CH
2016 }
2017
1578050f
BF
2018 if (xfs_sb_version_hasfinobt(&mp->m_sb) &&
2019 be32_to_cpu(agi->agi_freecount) != agcnts->fibtfreecount) {
2020 do_warn(_("agi_freecount %u, counted %u in ag %u finobt\n"),
2021 be32_to_cpu(agi->agi_freecount), agcnts->fibtfreecount,
2022 agno);
2023 }
2024
48d49157
CH
2025 for (i = 0; i < XFS_AGI_UNLINKED_BUCKETS; i++) {
2026 xfs_agino_t agino = be32_to_cpu(agi->agi_unlinked[i]);
2027
2028 if (agino != NULLAGINO) {
2029 do_warn(
5d1b7f0f 2030 _("agi unlinked bucket %d is %u in ag %u (inode=%" PRIu64 ")\n"),
48d49157
CH
2031 i, agino, agno,
2032 XFS_AGINO_TO_INO(mp, agno, agino));
2033 }
2034 }
2035}
2036
48d49157
CH
2037/*
2038 * Scan an AG for obvious corruption.
48d49157 2039 */
364a126c 2040static void
2bd0ea18 2041scan_ag(
364a126c
DC
2042 work_queue_t *wq,
2043 xfs_agnumber_t agno,
2044 void *arg)
2bd0ea18 2045{
364a126c 2046 struct aghdr_cnts *agcnts = arg;
8f657d7e
DC
2047 struct xfs_agf *agf;
2048 struct xfs_buf *agfbuf = NULL;
48d49157 2049 int agf_dirty = 0;
8f657d7e
DC
2050 struct xfs_agi *agi;
2051 struct xfs_buf *agibuf = NULL;
48d49157 2052 int agi_dirty = 0;
8f657d7e
DC
2053 struct xfs_sb *sb = NULL;
2054 struct xfs_buf *sbbuf = NULL;
48d49157 2055 int sb_dirty = 0;
2bd0ea18 2056 int status;
8f657d7e 2057 char *objname = NULL;
2bd0ea18 2058
8bc43a39 2059 sb = (struct xfs_sb *)calloc(BBTOB(XFS_FSS_TO_BB(mp, 1)), 1);
507f4e33
NS
2060 if (!sb) {
2061 do_error(_("can't allocate memory for superblock\n"));
507f4e33 2062 return;
dfc130f3 2063 }
8f657d7e
DC
2064
2065 sbbuf = libxfs_readbuf(mp->m_dev, XFS_AG_DADDR(mp, agno, XFS_SB_DADDR),
2066 XFS_FSS_TO_BB(mp, 1), 0, &xfs_sb_buf_ops);
2067 if (!sbbuf) {
2068 objname = _("root superblock");
2069 goto out_free_sb;
2070 }
5e656dbb 2071 libxfs_sb_from_disk(sb, XFS_BUF_TO_SBP(sbbuf));
2bd0ea18
NS
2072
2073 agfbuf = libxfs_readbuf(mp->m_dev,
9440d84d 2074 XFS_AG_DADDR(mp, agno, XFS_AGF_DADDR(mp)),
75c8b434 2075 XFS_FSS_TO_BB(mp, 1), 0, &xfs_agf_buf_ops);
2bd0ea18 2076 if (!agfbuf) {
8f657d7e
DC
2077 objname = _("agf block");
2078 goto out_free_sbbuf;
2bd0ea18
NS
2079 }
2080 agf = XFS_BUF_TO_AGF(agfbuf);
2081
2082 agibuf = libxfs_readbuf(mp->m_dev,
9440d84d 2083 XFS_AG_DADDR(mp, agno, XFS_AGI_DADDR(mp)),
75c8b434 2084 XFS_FSS_TO_BB(mp, 1), 0, &xfs_agi_buf_ops);
2bd0ea18 2085 if (!agibuf) {
8f657d7e
DC
2086 objname = _("agi block");
2087 goto out_free_agfbuf;
2bd0ea18
NS
2088 }
2089 agi = XFS_BUF_TO_AGI(agibuf);
2090
2091 /* fix up bad ag headers */
2092
2093 status = verify_set_agheader(mp, sbbuf, sb, agf, agi, agno);
2094
2095 if (status & XR_AG_SB_SEC) {
2096 if (!no_modify)
2097 sb_dirty = 1;
2098 /*
2099 * clear bad sector bit because we don't want
2100 * to skip further processing. we just want to
2101 * ensure that we write out the modified sb buffer.
2102 */
2103 status &= ~XR_AG_SB_SEC;
2104 }
2105 if (status & XR_AG_SB) {
507f4e33
NS
2106 if (!no_modify) {
2107 do_warn(_("reset bad sb for ag %d\n"), agno);
2bd0ea18 2108 sb_dirty = 1;
507f4e33
NS
2109 } else {
2110 do_warn(_("would reset bad sb for ag %d\n"), agno);
2111 }
2bd0ea18
NS
2112 }
2113 if (status & XR_AG_AGF) {
507f4e33
NS
2114 if (!no_modify) {
2115 do_warn(_("reset bad agf for ag %d\n"), agno);
2bd0ea18 2116 agf_dirty = 1;
507f4e33
NS
2117 } else {
2118 do_warn(_("would reset bad agf for ag %d\n"), agno);
2119 }
2bd0ea18
NS
2120 }
2121 if (status & XR_AG_AGI) {
507f4e33
NS
2122 if (!no_modify) {
2123 do_warn(_("reset bad agi for ag %d\n"), agno);
2bd0ea18 2124 agi_dirty = 1;
507f4e33
NS
2125 } else {
2126 do_warn(_("would reset bad agi for ag %d\n"), agno);
2127 }
2bd0ea18
NS
2128 }
2129
2130 if (status && no_modify) {
507f4e33
NS
2131 do_warn(_("bad uncorrected agheader %d, skipping ag...\n"),
2132 agno);
8f657d7e 2133 goto out_free_agibuf;
2bd0ea18
NS
2134 }
2135
364a126c 2136 scan_freelist(agf, agcnts);
2bd0ea18 2137
364a126c
DC
2138 validate_agf(agf, agno, agcnts);
2139 validate_agi(agi, agno, agcnts);
2bd0ea18 2140
27527004 2141 ASSERT(agi_dirty == 0 || (agi_dirty && !no_modify));
8f657d7e
DC
2142 ASSERT(agf_dirty == 0 || (agf_dirty && !no_modify));
2143 ASSERT(sb_dirty == 0 || (sb_dirty && !no_modify));
2144
2145 /*
2146 * Only pay attention to CRC/verifier errors if we can correct them.
1fe7b0b0
DC
2147 * Note that we can get uncorrected EFSCORRUPTED errors here because
2148 * the verifier will flag on out of range values that we can't correct
2149 * until phase 5 when we have all the information necessary to rebuild
2150 * the freespace/inode btrees. We can correct bad CRC errors
2151 * immediately, though.
8f657d7e
DC
2152 */
2153 if (!no_modify) {
66fc04e0
DW
2154 agi_dirty += (agibuf->b_error == -EFSBADCRC);
2155 agf_dirty += (agfbuf->b_error == -EFSBADCRC);
2156 sb_dirty += (sbbuf->b_error == -EFSBADCRC);
8f657d7e 2157 }
2bd0ea18
NS
2158
2159 if (agi_dirty && !no_modify)
2160 libxfs_writebuf(agibuf, 0);
2161 else
2162 libxfs_putbuf(agibuf);
2163
2bd0ea18
NS
2164 if (agf_dirty && !no_modify)
2165 libxfs_writebuf(agfbuf, 0);
2166 else
2167 libxfs_putbuf(agfbuf);
2168
2bd0ea18 2169 if (sb_dirty && !no_modify) {
e8cb94ee
BN
2170 if (agno == 0)
2171 memcpy(&mp->m_sb, sb, sizeof(xfs_sb_t));
19ebedcf 2172 libxfs_sb_to_disk(XFS_BUF_TO_SBP(sbbuf), sb);
2bd0ea18 2173 libxfs_writebuf(sbbuf, 0);
dfc130f3 2174 } else
2bd0ea18 2175 libxfs_putbuf(sbbuf);
dfc130f3 2176 free(sb);
06fbdda9 2177 PROG_RPT_INC(prog_rpt_done[agno], 1);
364a126c
DC
2178
2179#ifdef XR_INODE_TRACE
2180 print_inode_list(i);
2181#endif
2182 return;
8f657d7e
DC
2183
2184out_free_agibuf:
2185 libxfs_putbuf(agibuf);
2186out_free_agfbuf:
2187 libxfs_putbuf(agfbuf);
2188out_free_sbbuf:
2189 libxfs_putbuf(sbbuf);
2190out_free_sb:
2191 free(sb);
2192
2193 if (objname)
2194 do_error(_("can't get %s for ag %d\n"), objname, agno);
2bd0ea18 2195}
364a126c
DC
2196
2197#define SCAN_THREADS 32
2198
2199void
2200scan_ags(
2201 struct xfs_mount *mp,
2202 int scan_threads)
2203{
2204 struct aghdr_cnts *agcnts;
2205 __uint64_t fdblocks = 0;
2206 __uint64_t icount = 0;
2207 __uint64_t ifreecount = 0;
0f94fa4b 2208 __uint64_t usedblocks = 0;
364a126c
DC
2209 xfs_agnumber_t i;
2210 work_queue_t wq;
2211
2212 agcnts = malloc(mp->m_sb.sb_agcount * sizeof(*agcnts));
2213 if (!agcnts) {
2214 do_abort(_("no memory for ag header counts\n"));
2215 return;
2216 }
2217 memset(agcnts, 0, mp->m_sb.sb_agcount * sizeof(*agcnts));
2218
f756f80c 2219 create_work_queue(&wq, mp, scan_threads);
364a126c
DC
2220
2221 for (i = 0; i < mp->m_sb.sb_agcount; i++)
2222 queue_work(&wq, scan_ag, i, &agcnts[i]);
2223
2224 destroy_work_queue(&wq);
2225
2226 /* tally up the counts */
2227 for (i = 0; i < mp->m_sb.sb_agcount; i++) {
2228 fdblocks += agcnts[i].fdblocks;
37246b95 2229 icount += agcnts[i].agicount;
364a126c 2230 ifreecount += agcnts[i].ifreecount;
0f94fa4b 2231 usedblocks += agcnts[i].usedblocks;
364a126c
DC
2232 }
2233
aba29588
ES
2234 free(agcnts);
2235
364a126c
DC
2236 /*
2237 * Validate that our manual counts match the superblock.
2238 */
2239 if (mp->m_sb.sb_icount != icount) {
5d1b7f0f 2240 do_warn(_("sb_icount %" PRIu64 ", counted %" PRIu64 "\n"),
364a126c
DC
2241 mp->m_sb.sb_icount, icount);
2242 }
2243
2244 if (mp->m_sb.sb_ifree != ifreecount) {
5d1b7f0f 2245 do_warn(_("sb_ifree %" PRIu64 ", counted %" PRIu64 "\n"),
364a126c
DC
2246 mp->m_sb.sb_ifree, ifreecount);
2247 }
2248
2249 if (mp->m_sb.sb_fdblocks != fdblocks) {
5d1b7f0f 2250 do_warn(_("sb_fdblocks %" PRIu64 ", counted %" PRIu64 "\n"),
364a126c
DC
2251 mp->m_sb.sb_fdblocks, fdblocks);
2252 }
0f94fa4b
DW
2253
2254 if (usedblocks &&
2255 usedblocks != mp->m_sb.sb_dblocks - fdblocks) {
2256 do_warn(_("used blocks %" PRIu64 ", counted %" PRIu64 "\n"),
2257 mp->m_sb.sb_dblocks - fdblocks, usedblocks);
2258 }
364a126c 2259}