]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blame - repair/scan.c
xfs_repair: better checking of v5 metadata fields
[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
19#include <libxfs.h>
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"
2bd0ea18 32
2bd0ea18 33static xfs_mount_t *mp = NULL;
2bd0ea18 34
48d49157 35/*
364a126c 36 * Variables to validate AG header values against the manual count
48d49157 37 * from the btree traversal.
48d49157 38 */
364a126c
DC
39struct aghdr_cnts {
40 xfs_agnumber_t agno;
41 xfs_extlen_t agffreeblks;
42 xfs_extlen_t agflongest;
43 __uint64_t agfbtreeblks;
44 __uint32_t agicount;
45 __uint32_t agifreecount;
46 __uint64_t fdblocks;
47 __uint64_t icount;
48 __uint64_t ifreecount;
1578050f 49 __uint32_t fibtfreecount;
364a126c 50};
48d49157 51
2bd0ea18
NS
52void
53set_mp(xfs_mount_t *mpp)
54{
f1b058f9 55 libxfs_bcache_purge();
2bd0ea18
NS
56 mp = mpp;
57}
58
8b8a6b02 59static void
2bd0ea18
NS
60scan_sbtree(
61 xfs_agblock_t root,
62 int nlevels,
63 xfs_agnumber_t agno,
64 int suspect,
b3563c19 65 void (*func)(struct xfs_btree_block *block,
2bd0ea18
NS
66 int level,
67 xfs_agblock_t bno,
68 xfs_agnumber_t agno,
69 int suspect,
364a126c 70 int isroot,
e0607266 71 __uint32_t magic,
364a126c
DC
72 void *priv),
73 int isroot,
e0607266
DC
74 __uint32_t magic,
75 void *priv,
76 const struct xfs_buf_ops *ops)
2bd0ea18
NS
77{
78 xfs_buf_t *bp;
79
80 bp = libxfs_readbuf(mp->m_dev, XFS_AGB_TO_DADDR(mp, agno, root),
e0607266 81 XFS_FSB_TO_BB(mp, 1), 0, ops);
2bd0ea18 82 if (!bp) {
507f4e33 83 do_error(_("can't read btree block %d/%d\n"), agno, root);
2bd0ea18
NS
84 return;
85 }
a76a5a71
DC
86 if (bp->b_error == EFSBADCRC || bp->b_error == EFSCORRUPTED) {
87 do_warn(_("btree block %d/%d is suspect, error %d\n"),
88 agno, root, bp->b_error);
89 suspect = 1;
90 }
91
364a126c 92 (*func)(XFS_BUF_TO_BLOCK(bp), nlevels - 1, root, agno, suspect,
e0607266 93 isroot, magic, priv);
2bd0ea18
NS
94 libxfs_putbuf(bp);
95}
96
97/*
98 * returns 1 on bad news (inode needs to be cleared), 0 on good
99 */
100int
101scan_lbtree(
102 xfs_dfsbno_t root,
103 int nlevels,
b3563c19 104 int (*func)(struct xfs_btree_block *block,
2bd0ea18
NS
105 int level,
106 int type,
107 int whichfork,
108 xfs_dfsbno_t bno,
109 xfs_ino_t ino,
110 xfs_drfsbno_t *tot,
111 __uint64_t *nex,
112 blkmap_t **blkmapp,
113 bmap_cursor_t *bm_cursor,
114 int isroot,
115 int check_dups,
e0607266
DC
116 int *dirty,
117 __uint64_t magic),
2bd0ea18
NS
118 int type,
119 int whichfork,
120 xfs_ino_t ino,
121 xfs_drfsbno_t *tot,
122 __uint64_t *nex,
123 blkmap_t **blkmapp,
124 bmap_cursor_t *bm_cursor,
125 int isroot,
e0607266
DC
126 int check_dups,
127 __uint64_t magic,
128 const struct xfs_buf_ops *ops)
2bd0ea18
NS
129{
130 xfs_buf_t *bp;
131 int err;
132 int dirty = 0;
a76a5a71 133 bool badcrc = false;
2bd0ea18
NS
134
135 bp = libxfs_readbuf(mp->m_dev, XFS_FSB_TO_DADDR(mp, root),
e0607266 136 XFS_FSB_TO_BB(mp, 1), 0, ops);
2bd0ea18 137 if (!bp) {
507f4e33 138 do_error(_("can't read btree block %d/%d\n"),
2bd0ea18
NS
139 XFS_FSB_TO_AGNO(mp, root),
140 XFS_FSB_TO_AGBNO(mp, root));
141 return(1);
142 }
a76a5a71
DC
143
144 /*
145 * only check for bad CRC here - caller will determine if there
146 * is a corruption or not and whether it got corrected and so needs
147 * writing back. CRC errors always imply we need to write the block.
148 */
149 if (bp->b_error == EFSBADCRC) {
150 do_warn(_("btree block %d/%d is suspect, error %d\n"),
151 XFS_FSB_TO_AGNO(mp, root),
152 XFS_FSB_TO_AGBNO(mp, root), bp->b_error);
153 badcrc = true;
154 }
155
b3563c19 156 err = (*func)(XFS_BUF_TO_BLOCK(bp), nlevels - 1,
2bd0ea18 157 type, whichfork, root, ino, tot, nex, blkmapp,
e0607266
DC
158 bm_cursor, isroot, check_dups, &dirty,
159 magic);
2bd0ea18 160
27527004 161 ASSERT(dirty == 0 || (dirty && !no_modify));
2bd0ea18 162
a76a5a71 163 if ((dirty || badcrc) && !no_modify)
2bd0ea18
NS
164 libxfs_writebuf(bp, 0);
165 else
166 libxfs_putbuf(bp);
167
168 return(err);
169}
170
171int
e0607266 172scan_bmapbt(
b3563c19 173 struct xfs_btree_block *block,
2bd0ea18
NS
174 int level,
175 int type,
176 int whichfork,
177 xfs_dfsbno_t bno,
178 xfs_ino_t ino,
179 xfs_drfsbno_t *tot,
180 __uint64_t *nex,
181 blkmap_t **blkmapp,
182 bmap_cursor_t *bm_cursor,
183 int isroot,
184 int check_dups,
e0607266
DC
185 int *dirty,
186 __uint64_t magic)
2bd0ea18 187{
2bd0ea18
NS
188 int i;
189 int err;
190 xfs_bmbt_ptr_t *pp;
191 xfs_bmbt_key_t *pkey;
5e656dbb 192 xfs_bmbt_rec_t *rp;
2bd0ea18
NS
193 xfs_dfiloff_t first_key;
194 xfs_dfiloff_t last_key;
beed0dc8 195 char *forkname = get_forkname(whichfork);
5e656dbb 196 int numrecs;
95650c4d
BN
197 xfs_agnumber_t agno;
198 xfs_agblock_t agbno;
199 int state;
2bd0ea18 200
2bd0ea18 201 /*
dfc130f3 202 * unlike the ag freeblock btrees, if anything looks wrong
2bd0ea18
NS
203 * in an inode bmap tree, just bail. it's possible that
204 * we'll miss a case where the to-be-toasted inode and
205 * another inode are claiming the same block but that's
206 * highly unlikely.
207 */
e0607266 208 if (be32_to_cpu(block->bb_magic) != magic) {
5d1b7f0f
CH
209 do_warn(
210_("bad magic # %#x in inode %" PRIu64 " (%s fork) bmbt block %" PRIu64 "\n"),
211 be32_to_cpu(block->bb_magic), ino, forkname, bno);
2bd0ea18
NS
212 return(1);
213 }
5e656dbb 214 if (be16_to_cpu(block->bb_level) != level) {
5d1b7f0f
CH
215 do_warn(
216_("expected level %d got %d in inode %" PRIu64 ", (%s fork) bmbt block %" PRIu64 "\n"),
217 level, be16_to_cpu(block->bb_level),
218 ino, forkname, bno);
2bd0ea18
NS
219 return(1);
220 }
221
e0607266
DC
222 if (magic == XFS_BMAP_CRC_MAGIC) {
223 /* verify owner */
224 if (be64_to_cpu(block->bb_u.l.bb_owner) != ino) {
225 do_warn(
226_("expected owner inode %" PRIu64 ", got %llu, bmbt block %" PRIu64 "\n"),
227 ino, be64_to_cpu(block->bb_u.l.bb_owner), bno);
0519f662
DW
228 return 1;
229 }
230 /* verify block number */
231 if (be64_to_cpu(block->bb_u.l.bb_blkno) !=
232 XFS_FSB_TO_DADDR(mp, bno)) {
233 do_warn(
234_("expected block %" PRIu64 ", got %llu, bmbt block %" PRIu64 "\n"),
235 XFS_FSB_TO_DADDR(mp, bno),
236 be64_to_cpu(block->bb_u.l.bb_blkno), bno);
237 return 1;
238 }
239 /* verify uuid */
240 if (platform_uuid_compare(&block->bb_u.l.bb_uuid,
241 &mp->m_sb.sb_uuid) != 0) {
242 do_warn(
243_("wrong FS UUID, bmbt block %" PRIu64 "\n"),
244 bno);
245 return 1;
e0607266
DC
246 }
247 }
248
2bd0ea18
NS
249 if (check_dups == 0) {
250 /*
251 * check sibling pointers. if bad we have a conflict
252 * between the sibling pointers and the child pointers
253 * in the parent block. blow out the inode if that happens
254 */
255 if (bm_cursor->level[level].fsbno != NULLDFSBNO) {
256 /*
257 * this is not the first block on this level
258 * so the cursor for this level has recorded the
259 * values for this's block left-sibling.
260 */
261 if (bno != bm_cursor->level[level].right_fsbno) {
262 do_warn(
5d1b7f0f
CH
263_("bad fwd (right) sibling pointer (saw %" PRIu64 " parent block says %" PRIu64 ")\n"
264 "\tin inode %" PRIu64 " (%s fork) bmap btree block %" PRIu64 "\n"),
2bd0ea18 265 bm_cursor->level[level].right_fsbno,
507f4e33 266 bno, ino, forkname,
2bd0ea18
NS
267 bm_cursor->level[level].fsbno);
268 return(1);
269 }
b3563c19 270 if (be64_to_cpu(block->bb_u.l.bb_leftsib) !=
2bd0ea18
NS
271 bm_cursor->level[level].fsbno) {
272 do_warn(
5d1b7f0f
CH
273_("bad back (left) sibling pointer (saw %llu parent block says %" PRIu64 ")\n"
274 "\tin inode %" PRIu64 " (%s fork) bmap btree block %" PRIu64 "\n"),
275 (unsigned long long)
276 be64_to_cpu(block->bb_u.l.bb_leftsib),
507f4e33 277 bm_cursor->level[level].fsbno,
2bd0ea18
NS
278 ino, forkname, bno);
279 return(1);
280 }
281 } else {
282 /*
283 * This is the first or only block on this level.
284 * Check that the left sibling pointer is NULL
285 */
b3563c19 286 if (be64_to_cpu(block->bb_u.l.bb_leftsib) != NULLDFSBNO) {
2bd0ea18 287 do_warn(
507f4e33 288_("bad back (left) sibling pointer (saw %llu should be NULL (0))\n"
5d1b7f0f
CH
289 "\tin inode %" PRIu64 " (%s fork) bmap btree block %" PRIu64 "\n"),
290 (unsigned long long)
291 be64_to_cpu(block->bb_u.l.bb_leftsib),
2bd0ea18
NS
292 ino, forkname, bno);
293 return(1);
294 }
295 }
296
297 /*
298 * update cursor block pointers to reflect this block
299 */
300 bm_cursor->level[level].fsbno = bno;
507f4e33 301 bm_cursor->level[level].left_fsbno =
b3563c19 302 be64_to_cpu(block->bb_u.l.bb_leftsib);
507f4e33 303 bm_cursor->level[level].right_fsbno =
b3563c19 304 be64_to_cpu(block->bb_u.l.bb_rightsib);
2bd0ea18 305
95650c4d
BN
306 agno = XFS_FSB_TO_AGNO(mp, bno);
307 agbno = XFS_FSB_TO_AGBNO(mp, bno);
308
586f8abf 309 pthread_mutex_lock(&ag_locks[agno].lock);
95650c4d
BN
310 state = get_bmap(agno, agbno);
311 switch (state) {
2bd0ea18
NS
312 case XR_E_UNKNOWN:
313 case XR_E_FREE1:
314 case XR_E_FREE:
95650c4d 315 set_bmap(agno, agbno, XR_E_INUSE);
2bd0ea18
NS
316 break;
317 case XR_E_FS_MAP:
318 case XR_E_INUSE:
319 /*
320 * we'll try and continue searching here since
321 * the block looks like it's been claimed by file
322 * to store user data, a directory to store directory
323 * data, or the space allocation btrees but since
324 * we made it here, the block probably
325 * contains btree data.
326 */
95650c4d 327 set_bmap(agno, agbno, XR_E_MULT);
2bd0ea18 328 do_warn(
d9db5c4e 329_("inode 0x%" PRIx64 "bmap block 0x%" PRIx64 " claimed, state is %d\n"),
5d1b7f0f 330 ino, bno, state);
2bd0ea18
NS
331 break;
332 case XR_E_MULT:
333 case XR_E_INUSE_FS:
95650c4d 334 set_bmap(agno, agbno, XR_E_MULT);
2bd0ea18 335 do_warn(
d9db5c4e 336_("inode 0x%" PRIx64 " bmap block 0x%" PRIx64 " claimed, state is %d\n"),
5d1b7f0f 337 ino, bno, state);
2bd0ea18
NS
338 /*
339 * if we made it to here, this is probably a bmap block
340 * that is being used by *another* file as a bmap block
341 * so the block will be valid. Both files should be
342 * trashed along with any other file that impinges on
343 * any blocks referenced by either file. So we
344 * continue searching down this btree to mark all
345 * blocks duplicate
346 */
347 break;
348 case XR_E_BAD_STATE:
349 default:
350 do_warn(
2e686aa8 351_("bad state %d, inode %" PRIu64 " bmap block 0x%" PRIx64 "\n"),
5d1b7f0f 352 state, ino, bno);
2bd0ea18
NS
353 break;
354 }
586f8abf 355 pthread_mutex_unlock(&ag_locks[agno].lock);
2bd0ea18
NS
356 } else {
357 /*
358 * attribute fork for realtime files is in the regular
359 * filesystem
360 */
361 if (type != XR_INO_RTDATA || whichfork != XFS_DATA_FORK) {
79872d6e
BN
362 if (search_dup_extent(XFS_FSB_TO_AGNO(mp, bno),
363 XFS_FSB_TO_AGBNO(mp, bno),
364 XFS_FSB_TO_AGBNO(mp, bno) + 1))
2bd0ea18
NS
365 return(1);
366 } else {
367 if (search_rt_dup_extent(mp, bno))
368 return(1);
369 }
370 }
371 (*tot)++;
5e656dbb
BN
372 numrecs = be16_to_cpu(block->bb_numrecs);
373
2bd0ea18 374 if (level == 0) {
5e656dbb
BN
375 if (numrecs > mp->m_bmap_dmxr[0] || (isroot == 0 && numrecs <
376 mp->m_bmap_dmnr[0])) {
507f4e33 377 do_warn(
b52923f3 378_("inode %" PRIu64 " bad # of bmap records (%u, min - %u, max - %u)\n"),
5e656dbb
BN
379 ino, numrecs, mp->m_bmap_dmnr[0],
380 mp->m_bmap_dmxr[0]);
2bd0ea18
NS
381 return(1);
382 }
b3563c19 383 rp = XFS_BMBT_REC_ADDR(mp, block, 1);
5e656dbb 384 *nex += numrecs;
2bd0ea18
NS
385 /*
386 * XXX - if we were going to fix up the btree record,
387 * we'd do it right here. For now, if there's a problem,
388 * we'll bail out and presumably clear the inode.
389 */
390 if (check_dups == 0) {
e1f43b4c
CH
391 err = process_bmbt_reclist(mp, rp, &numrecs, type, ino,
392 tot, blkmapp, &first_key,
393 &last_key, whichfork);
2bd0ea18 394 if (err)
e1f43b4c
CH
395 return 1;
396
2bd0ea18
NS
397 /*
398 * check that key ordering is monotonically increasing.
399 * if the last_key value in the cursor is set to
400 * NULLDFILOFF, then we know this is the first block
401 * on the leaf level and we shouldn't check the
402 * last_key value.
403 */
404 if (first_key <= bm_cursor->level[level].last_key &&
405 bm_cursor->level[level].last_key !=
406 NULLDFILOFF) {
407 do_warn(
5d1b7f0f 408_("out-of-order bmap key (file offset) in inode %" PRIu64 ", %s fork, fsbno %" PRIu64 "\n"),
2bd0ea18
NS
409 ino, forkname, bno);
410 return(1);
411 }
412 /*
413 * update cursor keys to reflect this block.
414 * don't have to check if last_key is > first_key
415 * since that gets checked by process_bmbt_reclist.
416 */
417 bm_cursor->level[level].first_key = first_key;
418 bm_cursor->level[level].last_key = last_key;
419
e1f43b4c
CH
420 return 0;
421 } else {
422 return scan_bmbt_reclist(mp, rp, &numrecs, type, ino,
423 tot, whichfork);
424 }
2bd0ea18 425 }
5e656dbb
BN
426 if (numrecs > mp->m_bmap_dmxr[1] || (isroot == 0 && numrecs <
427 mp->m_bmap_dmnr[1])) {
507f4e33 428 do_warn(
2e686aa8 429_("inode %" PRIu64 " bad # of bmap records (%u, min - %u, max - %u)\n"),
5e656dbb 430 ino, numrecs, mp->m_bmap_dmnr[1], mp->m_bmap_dmxr[1]);
2bd0ea18
NS
431 return(1);
432 }
b3563c19
BN
433 pp = XFS_BMBT_PTR_ADDR(mp, block, 1, mp->m_bmap_dmxr[1]);
434 pkey = XFS_BMBT_KEY_ADDR(mp, block, 1);
2bd0ea18
NS
435
436 last_key = NULLDFILOFF;
437
5e656dbb 438 for (i = 0, err = 0; i < numrecs; i++) {
2bd0ea18
NS
439 /*
440 * XXX - if we were going to fix up the interior btree nodes,
441 * we'd do it right here. For now, if there's a problem,
442 * we'll bail out and presumably clear the inode.
443 */
5e656dbb 444 if (!verify_dfsbno(mp, be64_to_cpu(pp[i]))) {
5d1b7f0f
CH
445 do_warn(
446_("bad bmap btree ptr 0x%llx in ino %" PRIu64 "\n"),
447 (unsigned long long) be64_to_cpu(pp[i]), ino);
2bd0ea18
NS
448 return(1);
449 }
450
e0607266 451 err = scan_lbtree(be64_to_cpu(pp[i]), level, scan_bmapbt,
5e656dbb 452 type, whichfork, ino, tot, nex, blkmapp,
e0607266
DC
453 bm_cursor, 0, check_dups, magic,
454 &xfs_bmbt_buf_ops);
2bd0ea18
NS
455 if (err)
456 return(1);
457
458 /*
459 * fix key (offset) mismatches between the first key
460 * in the child block (as recorded in the cursor) and the
461 * key in the interior node referencing the child block.
462 *
463 * fixes cases where entries have been shifted between
464 * child blocks but the parent hasn't been updated. We
465 * don't have to worry about the key values in the cursor
466 * not being set since we only look at the key values of
467 * our child and those are guaranteed to be set by the
468 * call to scan_lbtree() above.
469 */
5e656dbb 470 if (check_dups == 0 && be64_to_cpu(pkey[i].br_startoff) !=
2bd0ea18
NS
471 bm_cursor->level[level-1].first_key) {
472 if (!no_modify) {
473 do_warn(
5d1b7f0f
CH
474_("correcting bt key (was %llu, now %" PRIu64 ") in inode %" PRIu64 "\n"
475 "\t\t%s fork, btree block %" PRIu64 "\n"),
476 (unsigned long long)
477 be64_to_cpu(pkey[i].br_startoff),
2bd0ea18 478 bm_cursor->level[level-1].first_key,
507f4e33 479 ino,
2bd0ea18
NS
480 forkname, bno);
481 *dirty = 1;
5e656dbb 482 pkey[i].br_startoff = cpu_to_be64(
507f4e33 483 bm_cursor->level[level-1].first_key);
2bd0ea18
NS
484 } else {
485 do_warn(
5d1b7f0f
CH
486_("bad btree key (is %llu, should be %" PRIu64 ") in inode %" PRIu64 "\n"
487 "\t\t%s fork, btree block %" PRIu64 "\n"),
488 (unsigned long long)
489 be64_to_cpu(pkey[i].br_startoff),
2bd0ea18 490 bm_cursor->level[level-1].first_key,
5e656dbb 491 ino, forkname, bno);
2bd0ea18
NS
492 }
493 }
494 }
495
496 /*
e8cb94ee 497 * If we're the last node at our level, check that the last child
4dcea5f4 498 * block's forward sibling pointer is NULL.
2bd0ea18 499 */
dfc130f3 500 if (check_dups == 0 &&
5e656dbb
BN
501 bm_cursor->level[level].right_fsbno == NULLDFSBNO &&
502 bm_cursor->level[level - 1].right_fsbno != NULLDFSBNO) {
2bd0ea18 503 do_warn(
5d1b7f0f
CH
504_("bad fwd (right) sibling pointer (saw %" PRIu64 " should be NULLDFSBNO)\n"
505 "\tin inode %" PRIu64 " (%s fork) bmap btree block %" PRIu64 "\n"),
507f4e33 506 bm_cursor->level[level - 1].right_fsbno,
5e656dbb 507 ino, forkname, bm_cursor->level[level - 1].fsbno);
2bd0ea18
NS
508 return(1);
509 }
510
511 /*
512 * update cursor keys to reflect this block
513 */
514 if (check_dups == 0) {
515 bm_cursor->level[level].first_key =
5e656dbb 516 be64_to_cpu(pkey[0].br_startoff);
2bd0ea18 517 bm_cursor->level[level].last_key =
5e656dbb 518 be64_to_cpu(pkey[numrecs - 1].br_startoff);
2bd0ea18
NS
519 }
520
521 return(0);
522}
523
364a126c 524static void
e0607266 525scan_allocbt(
b3563c19 526 struct xfs_btree_block *block,
2bd0ea18
NS
527 int level,
528 xfs_agblock_t bno,
529 xfs_agnumber_t agno,
530 int suspect,
64a0b0ab 531 int isroot,
364a126c 532 __uint32_t magic,
e0607266 533 void *priv)
2bd0ea18 534{
e0607266 535 struct aghdr_cnts *agcnts = priv;
64a0b0ab 536 const char *name;
2bd0ea18
NS
537 int i;
538 xfs_alloc_ptr_t *pp;
539 xfs_alloc_rec_t *rp;
540 int hdr_errors = 0;
541 int numrecs;
542 int state;
c9638a82
CH
543 xfs_extlen_t lastcount = 0;
544 xfs_agblock_t lastblock = 0;
2bd0ea18 545
e0607266
DC
546 switch (magic) {
547 case XFS_ABTB_CRC_MAGIC:
548 case XFS_ABTB_MAGIC:
549 name = "bno";
550 break;
551 case XFS_ABTC_CRC_MAGIC:
552 case XFS_ABTC_MAGIC:
553 name = "cnt";
554 break;
555 default:
6bddecbc 556 name = "(unknown)";
e0607266
DC
557 assert(0);
558 break;
559 }
64a0b0ab
CH
560
561 if (be32_to_cpu(block->bb_magic) != magic) {
562 do_warn(_("bad magic # %#x in bt%s block %d/%d\n"),
563 be32_to_cpu(block->bb_magic), name, agno, bno);
2bd0ea18
NS
564 hdr_errors++;
565 if (suspect)
566 return;
567 }
48d49157
CH
568
569 /*
570 * All freespace btree blocks except the roots are freed for a
571 * fully used filesystem, thus they are counted towards the
572 * free data block counter.
573 */
574 if (!isroot) {
364a126c
DC
575 agcnts->agfbtreeblks++;
576 agcnts->fdblocks++;
48d49157
CH
577 }
578
5e656dbb 579 if (be16_to_cpu(block->bb_level) != level) {
64a0b0ab
CH
580 do_warn(_("expected level %d got %d in bt%s block %d/%d\n"),
581 level, be16_to_cpu(block->bb_level), name, agno, bno);
2bd0ea18
NS
582 hdr_errors++;
583 if (suspect)
584 return;
585 }
586
587 /*
588 * check for btree blocks multiply claimed
589 */
95650c4d
BN
590 state = get_bmap(agno, bno);
591 if (state != XR_E_UNKNOWN) {
592 set_bmap(agno, bno, XR_E_MULT);
2bd0ea18 593 do_warn(
64a0b0ab
CH
594_("%s freespace btree block claimed (state %d), agno %d, bno %d, suspect %d\n"),
595 name, state, agno, bno, suspect);
2bd0ea18
NS
596 return;
597 }
95650c4d 598 set_bmap(agno, bno, XR_E_FS_MAP);
2bd0ea18 599
5e656dbb
BN
600 numrecs = be16_to_cpu(block->bb_numrecs);
601
2bd0ea18 602 if (level == 0) {
5e656dbb 603 if (numrecs > mp->m_alloc_mxr[0]) {
2bd0ea18
NS
604 numrecs = mp->m_alloc_mxr[0];
605 hdr_errors++;
606 }
5e656dbb 607 if (isroot == 0 && numrecs < mp->m_alloc_mnr[0]) {
2bd0ea18
NS
608 numrecs = mp->m_alloc_mnr[0];
609 hdr_errors++;
610 }
611
c9638a82
CH
612 if (hdr_errors) {
613 do_warn(
614 _("bad btree nrecs (%u, min=%u, max=%u) in bt%s block %u/%u\n"),
615 be16_to_cpu(block->bb_numrecs),
616 mp->m_alloc_mnr[0], mp->m_alloc_mxr[0],
617 name, agno, bno);
2bd0ea18 618 suspect++;
c9638a82 619 }
2bd0ea18 620
b3563c19 621 rp = XFS_ALLOC_REC_ADDR(mp, block, 1);
2bd0ea18 622 for (i = 0; i < numrecs; i++) {
08382cf4 623 xfs_agblock_t b, end;
8961bfde 624 xfs_extlen_t len, blen;
08382cf4
BN
625
626 b = be32_to_cpu(rp[i].ar_startblock);
627 len = be32_to_cpu(rp[i].ar_blockcount);
628 end = b + len;
2bd0ea18 629
c83b756d
CH
630 if (b == 0 || !verify_agbno(mp, agno, b)) {
631 do_warn(
5d1b7f0f 632 _("invalid start block %u in record %u of %s btree block %u/%u\n"),
c83b756d 633 b, i, name, agno, bno);
08382cf4 634 continue;
c83b756d
CH
635 }
636 if (len == 0 || !verify_agbno(mp, agno, end - 1)) {
637 do_warn(
5d1b7f0f 638 _("invalid length %u in record %u of %s btree block %u/%u\n"),
c83b756d 639 len, i, name, agno, bno);
909daa84 640 continue;
c83b756d 641 }
08382cf4 642
e0607266
DC
643 if (magic == XFS_ABTB_MAGIC ||
644 magic == XFS_ABTB_CRC_MAGIC) {
c9638a82
CH
645 if (b <= lastblock) {
646 do_warn(_(
647 "out-of-order bno btree record %d (%u %u) block %u/%u\n"),
648 i, b, len, agno, bno);
649 } else {
650 lastblock = b;
651 }
652 } else {
364a126c
DC
653 agcnts->fdblocks += len;
654 agcnts->agffreeblks += len;
655 if (len > agcnts->agflongest)
656 agcnts->agflongest = len;
c9638a82
CH
657 if (len < lastcount) {
658 do_warn(_(
659 "out-of-order cnt btree record %d (%u %u) block %u/%u\n"),
660 i, b, len, agno, bno);
661 } else {
662 lastcount = len;
663 }
664 }
665
8961bfde
BN
666 for ( ; b < end; b += blen) {
667 state = get_bmap_ext(agno, b, end, &blen);
64a0b0ab
CH
668 switch (state) {
669 case XR_E_UNKNOWN:
95650c4d 670 set_bmap(agno, b, XR_E_FREE1);
64a0b0ab
CH
671 break;
672 case XR_E_FREE1:
673 /*
674 * no warning messages -- we'll catch
675 * FREE1 blocks later
676 */
e0607266
DC
677 if (magic == XFS_ABTC_MAGIC ||
678 magic == XFS_ABTC_CRC_MAGIC) {
8961bfde
BN
679 set_bmap_ext(agno, b, blen,
680 XR_E_FREE);
64a0b0ab
CH
681 break;
682 }
683 default:
507f4e33 684 do_warn(
8961bfde
BN
685 _("block (%d,%d-%d) multiply claimed by %s space tree, state - %d\n"),
686 agno, b, b + blen - 1,
687 name, state);
64a0b0ab 688 break;
2bd0ea18
NS
689 }
690 }
691 }
692 return;
693 }
694
695 /*
696 * interior record
697 */
b3563c19 698 pp = XFS_ALLOC_PTR_ADDR(mp, block, 1, mp->m_alloc_mxr[1]);
2bd0ea18 699
5e656dbb 700 if (numrecs > mp->m_alloc_mxr[1]) {
2bd0ea18
NS
701 numrecs = mp->m_alloc_mxr[1];
702 hdr_errors++;
703 }
5e656dbb 704 if (isroot == 0 && numrecs < mp->m_alloc_mnr[1]) {
2bd0ea18
NS
705 numrecs = mp->m_alloc_mnr[1];
706 hdr_errors++;
707 }
708
709 /*
710 * don't pass bogus tree flag down further if this block
711 * looked ok. bail out if two levels in a row look bad.
712 */
2bd0ea18 713 if (hdr_errors) {
c9638a82
CH
714 do_warn(
715 _("bad btree nrecs (%u, min=%u, max=%u) in bt%s block %u/%u\n"),
716 be16_to_cpu(block->bb_numrecs),
717 mp->m_alloc_mnr[1], mp->m_alloc_mxr[1],
718 name, agno, bno);
2bd0ea18
NS
719 if (suspect)
720 return;
c9638a82
CH
721 suspect++;
722 } else if (suspect) {
723 suspect = 0;
2bd0ea18
NS
724 }
725
726 for (i = 0; i < numrecs; i++) {
08382cf4
BN
727 xfs_agblock_t bno = be32_to_cpu(pp[i]);
728
2bd0ea18
NS
729 /*
730 * XXX - put sibling detection right here.
731 * we know our sibling chain is good. So as we go,
732 * we check the entry before and after each entry.
733 * If either of the entries references a different block,
734 * check the sibling pointer. If there's a sibling
735 * pointer mismatch, try and extract as much data
dfc130f3 736 * as possible.
2bd0ea18 737 */
08382cf4 738 if (bno != 0 && verify_agbno(mp, agno, bno)) {
e0607266
DC
739 switch (magic) {
740 case XFS_ABTB_CRC_MAGIC:
741 case XFS_ABTB_MAGIC:
742 scan_sbtree(bno, level, agno, suspect,
743 scan_allocbt, 0, magic, priv,
744 &xfs_allocbt_buf_ops);
745 break;
746 case XFS_ABTC_CRC_MAGIC:
747 case XFS_ABTC_MAGIC:
748 scan_sbtree(bno, level, agno, suspect,
749 scan_allocbt, 0, magic, priv,
750 &xfs_allocbt_buf_ops);
751 break;
752 }
08382cf4 753 }
2bd0ea18
NS
754 }
755}
756
6ceb5693
BN
757static int
758scan_single_ino_chunk(
759 xfs_agnumber_t agno,
760 xfs_inobt_rec_t *rp,
761 int suspect)
762{
763 xfs_ino_t lino;
764 xfs_agino_t ino;
765 xfs_agblock_t agbno;
766 int j;
767 int nfree;
768 int off;
769 int state;
770 ino_tree_node_t *ino_rec, *first_rec, *last_rec;
771
772 ino = be32_to_cpu(rp->ir_startino);
773 off = XFS_AGINO_TO_OFFSET(mp, ino);
774 agbno = XFS_AGINO_TO_AGBNO(mp, ino);
775 lino = XFS_AGINO_TO_INO(mp, agno, ino);
776
777 /*
778 * on multi-block block chunks, all chunks start
779 * at the beginning of the block. with multi-chunk
780 * blocks, all chunks must start on 64-inode boundaries
781 * since each block can hold N complete chunks. if
782 * fs has aligned inodes, all chunks must start
783 * at a fs_ino_alignment*N'th agbno. skip recs
784 * with badly aligned starting inodes.
785 */
786 if (ino == 0 ||
787 (inodes_per_block <= XFS_INODES_PER_CHUNK && off != 0) ||
788 (inodes_per_block > XFS_INODES_PER_CHUNK &&
789 off % XFS_INODES_PER_CHUNK != 0) ||
ca0a799e
BF
790 (fs_aligned_inodes && fs_ino_alignment &&
791 agbno % fs_ino_alignment != 0)) {
6ceb5693 792 do_warn(
5d1b7f0f 793 _("badly aligned inode rec (starting inode = %" PRIu64 ")\n"),
6ceb5693
BN
794 lino);
795 suspect++;
796 }
797
798 /*
799 * verify numeric validity of inode chunk first
800 * before inserting into a tree. don't have to
801 * worry about the overflow case because the
802 * starting ino number of a chunk can only get
803 * within 255 inodes of max (NULLAGINO). if it
804 * gets closer, the agino number will be illegal
805 * as the agbno will be too large.
806 */
807 if (verify_aginum(mp, agno, ino)) {
808 do_warn(
5d1b7f0f 809_("bad starting inode # (%" PRIu64 " (0x%x 0x%x)) in ino rec, skipping rec\n"),
6ceb5693
BN
810 lino, agno, ino);
811 return ++suspect;
812 }
813
814 if (verify_aginum(mp, agno,
815 ino + XFS_INODES_PER_CHUNK - 1)) {
816 do_warn(
5d1b7f0f 817_("bad ending inode # (%" PRIu64 " (0x%x 0x%zx)) in ino rec, skipping rec\n"),
6ceb5693 818 lino + XFS_INODES_PER_CHUNK - 1,
5d1b7f0f
CH
819 agno,
820 ino + XFS_INODES_PER_CHUNK - 1);
6ceb5693
BN
821 return ++suspect;
822 }
823
824 /*
825 * set state of each block containing inodes
826 */
827 if (off == 0 && !suspect) {
828 for (j = 0;
829 j < XFS_INODES_PER_CHUNK;
830 j += mp->m_sb.sb_inopblock) {
831 agbno = XFS_AGINO_TO_AGBNO(mp, ino + j);
95650c4d
BN
832
833 state = get_bmap(agno, agbno);
6ceb5693 834 if (state == XR_E_UNKNOWN) {
95650c4d 835 set_bmap(agno, agbno, XR_E_INO);
6ceb5693
BN
836 } else if (state == XR_E_INUSE_FS && agno == 0 &&
837 ino + j >= first_prealloc_ino &&
838 ino + j < last_prealloc_ino) {
95650c4d 839 set_bmap(agno, agbno, XR_E_INO);
6ceb5693
BN
840 } else {
841 do_warn(
842_("inode chunk claims used block, inobt block - agno %d, bno %d, inopb %d\n"),
843 agno, agbno, mp->m_sb.sb_inopblock);
844 /*
845 * XXX - maybe should mark
846 * block a duplicate
847 */
848 return ++suspect;
849 }
850 }
851 }
852
853 /*
854 * ensure only one avl entry per chunk
855 */
1ae311d5 856 find_inode_rec_range(mp, agno, ino, ino + XFS_INODES_PER_CHUNK,
6ceb5693
BN
857 &first_rec, &last_rec);
858 if (first_rec != NULL) {
859 /*
860 * this chunk overlaps with one (or more)
861 * already in the tree
862 */
863 do_warn(
5d1b7f0f 864_("inode rec for ino %" PRIu64 " (%d/%d) overlaps existing rec (start %d/%d)\n"),
6ceb5693
BN
865 lino, agno, ino, agno, first_rec->ino_startnum);
866 suspect++;
867
868 /*
869 * if the 2 chunks start at the same place,
870 * then we don't have to put this one
871 * in the uncertain list. go to the next one.
872 */
873 if (first_rec->ino_startnum == ino)
874 return suspect;
875 }
876
877 nfree = 0;
878
879 /*
880 * now mark all the inodes as existing and free or used.
881 * if the tree is suspect, put them into the uncertain
882 * inode tree.
883 */
884 if (!suspect) {
885 if (XFS_INOBT_IS_FREE_DISK(rp, 0)) {
886 nfree++;
1ae311d5 887 ino_rec = set_inode_free_alloc(mp, agno, ino);
6ceb5693 888 } else {
1ae311d5 889 ino_rec = set_inode_used_alloc(mp, agno, ino);
6ceb5693
BN
890 }
891 for (j = 1; j < XFS_INODES_PER_CHUNK; j++) {
892 if (XFS_INOBT_IS_FREE_DISK(rp, j)) {
893 nfree++;
894 set_inode_free(ino_rec, j);
895 } else {
896 set_inode_used(ino_rec, j);
897 }
898 }
899 } else {
900 for (j = 0; j < XFS_INODES_PER_CHUNK; j++) {
901 if (XFS_INOBT_IS_FREE_DISK(rp, j)) {
902 nfree++;
aaca101b 903 add_aginode_uncertain(mp, agno, ino + j, 1);
6ceb5693 904 } else {
aaca101b 905 add_aginode_uncertain(mp, agno, ino + j, 0);
6ceb5693
BN
906 }
907 }
908 }
909
910 if (nfree != be32_to_cpu(rp->ir_freecount)) {
911 do_warn(_("ir_freecount/free mismatch, inode "
5d1b7f0f 912 "chunk %d/%u, freecount %d nfree %d\n"),
6ceb5693
BN
913 agno, ino, be32_to_cpu(rp->ir_freecount), nfree);
914 }
915
916 return suspect;
917}
918
1578050f
BF
919static int
920scan_single_finobt_chunk(
921 xfs_agnumber_t agno,
922 xfs_inobt_rec_t *rp,
923 int suspect)
924{
925 xfs_ino_t lino;
926 xfs_agino_t ino;
927 xfs_agblock_t agbno;
928 int j;
929 int nfree;
930 int off;
931 int state;
932 ino_tree_node_t *first_rec, *last_rec, *ino_rec;
933
934 ino = be32_to_cpu(rp->ir_startino);
935 off = XFS_AGINO_TO_OFFSET(mp, ino);
936 agbno = XFS_AGINO_TO_AGBNO(mp, ino);
937 lino = XFS_AGINO_TO_INO(mp, agno, ino);
938
939 /*
940 * on multi-block block chunks, all chunks start at the beginning of the
941 * block. with multi-chunk blocks, all chunks must start on 64-inode
942 * boundaries since each block can hold N complete chunks. if fs has
943 * aligned inodes, all chunks must start at a fs_ino_alignment*N'th
944 * agbno. skip recs with badly aligned starting inodes.
945 */
946 if (ino == 0 ||
947 (inodes_per_block <= XFS_INODES_PER_CHUNK && off != 0) ||
948 (inodes_per_block > XFS_INODES_PER_CHUNK &&
949 off % XFS_INODES_PER_CHUNK != 0) ||
ca0a799e
BF
950 (fs_aligned_inodes && fs_ino_alignment &&
951 agbno % fs_ino_alignment != 0)) {
1578050f
BF
952 do_warn(
953 _("badly aligned finobt inode rec (starting inode = %" PRIu64 ")\n"),
954 lino);
955 suspect++;
956 }
957
958 /*
959 * verify numeric validity of inode chunk first before inserting into a
960 * tree. don't have to worry about the overflow case because the
961 * starting ino number of a chunk can only get within 255 inodes of max
962 * (NULLAGINO). if it gets closer, the agino number will be illegal as
963 * the agbno will be too large.
964 */
965 if (verify_aginum(mp, agno, ino)) {
966 do_warn(
967_("bad starting inode # (%" PRIu64 " (0x%x 0x%x)) in finobt rec, skipping rec\n"),
968 lino, agno, ino);
969 return ++suspect;
970 }
971
972 if (verify_aginum(mp, agno,
973 ino + XFS_INODES_PER_CHUNK - 1)) {
974 do_warn(
975_("bad ending inode # (%" PRIu64 " (0x%x 0x%zx)) in finobt rec, skipping rec\n"),
976 lino + XFS_INODES_PER_CHUNK - 1,
977 agno,
978 ino + XFS_INODES_PER_CHUNK - 1);
979 return ++suspect;
980 }
981
982 /*
983 * cross check state of each block containing inodes referenced by the
984 * finobt against what we have already scanned from the alloc inobt.
985 */
986 if (off == 0 && !suspect) {
987 for (j = 0;
988 j < XFS_INODES_PER_CHUNK;
989 j += mp->m_sb.sb_inopblock) {
990 agbno = XFS_AGINO_TO_AGBNO(mp, ino + j);
991
992 state = get_bmap(agno, agbno);
993 if (state == XR_E_INO) {
994 continue;
995 } else if ((state == XR_E_UNKNOWN) ||
996 (state == XR_E_INUSE_FS && agno == 0 &&
997 ino + j >= first_prealloc_ino &&
998 ino + j < last_prealloc_ino)) {
999 do_warn(
1000_("inode chunk claims untracked block, finobt block - agno %d, bno %d, inopb %d\n"),
1001 agno, agbno, mp->m_sb.sb_inopblock);
1002
1003 set_bmap(agno, agbno, XR_E_INO);
1004 suspect++;
1005 } else {
1006 do_warn(
1007_("inode chunk claims used block, finobt block - agno %d, bno %d, inopb %d\n"),
1008 agno, agbno, mp->m_sb.sb_inopblock);
1009 return ++suspect;
1010 }
1011 }
1012 }
1013
1014 /*
1015 * ensure we have an incore entry for each chunk
1016 */
1017 find_inode_rec_range(mp, agno, ino, ino + XFS_INODES_PER_CHUNK,
1018 &first_rec, &last_rec);
1019
1020 if (first_rec) {
1021 if (suspect)
1022 return suspect;
1023
1024 /*
1025 * verify consistency between finobt record and incore state
1026 */
1027 if (first_rec->ino_startnum != ino) {
1028 do_warn(
1029_("finobt rec for ino %" PRIu64 " (%d/%u) does not match existing rec (%d/%d)\n"),
1030 lino, agno, ino, agno, first_rec->ino_startnum);
1031 return ++suspect;
1032 }
1033
1034 nfree = 0;
1035 for (j = 0; j < XFS_INODES_PER_CHUNK; j++) {
1036 int isfree = XFS_INOBT_IS_FREE_DISK(rp, j);
1037
1038 if (isfree)
1039 nfree++;
1040
1041 /*
1042 * inode allocation state should be consistent between
1043 * the inobt and finobt
1044 */
1045 if (!suspect &&
1046 isfree != is_inode_free(first_rec, j))
1047 suspect++;
1048 }
1049
1050 goto check_freecount;
1051 }
1052
1053 /*
1054 * the finobt contains a record that the previous alloc inobt scan never
1055 * found. insert the inodes into the appropriate tree.
1056 */
1057 do_warn(_("undiscovered finobt record, ino %" PRIu64 " (%d/%u)\n"),
1058 lino, agno, ino);
1059
1060 if (!suspect) {
1061 /*
1062 * inodes previously inserted into the uncertain tree should be
1063 * superceded by these when the uncertain tree is processed
1064 */
1065 nfree = 0;
1066 if (XFS_INOBT_IS_FREE_DISK(rp, 0)) {
1067 nfree++;
1068 ino_rec = set_inode_free_alloc(mp, agno, ino);
1069 } else {
1070 ino_rec = set_inode_used_alloc(mp, agno, ino);
1071 }
1072 for (j = 1; j < XFS_INODES_PER_CHUNK; j++) {
1073 if (XFS_INOBT_IS_FREE_DISK(rp, j)) {
1074 nfree++;
1075 set_inode_free(ino_rec, j);
1076 } else {
1077 set_inode_used(ino_rec, j);
1078 }
1079 }
1080 } else {
1081 /*
1082 * this should handle the case where the inobt scan may have
1083 * already added uncertain inodes
1084 */
1085 nfree = 0;
1086 for (j = 0; j < XFS_INODES_PER_CHUNK; j++) {
1087 if (XFS_INOBT_IS_FREE_DISK(rp, j)) {
1088 add_aginode_uncertain(mp, agno, ino + j, 1);
1089 nfree++;
1090 } else {
1091 add_aginode_uncertain(mp, agno, ino + j, 0);
1092 }
1093 }
1094 }
1095
1096check_freecount:
1097
1098 /*
1099 * Verify that the record freecount matches the actual number of free
1100 * inodes counted in the record. Don't increment 'suspect' here, since
1101 * we have already verified the allocation state of the individual
1102 * inodes against the in-core state. This will have already incremented
1103 * 'suspect' if something is wrong. If suspect hasn't been set at this
1104 * point, these warnings mean that we have a simple freecount
1105 * inconsistency or a stray finobt record (as opposed to a broader tree
1106 * corruption). Issue a warning and continue the scan. The final btree
1107 * reconstruction will correct this naturally.
1108 */
1109 if (nfree != be32_to_cpu(rp->ir_freecount)) {
1110 do_warn(
1111_("finobt ir_freecount/free mismatch, inode chunk %d/%u, freecount %d nfree %d\n"),
1112 agno, ino, be32_to_cpu(rp->ir_freecount), nfree);
1113 }
1114
1115 if (!nfree) {
1116 do_warn(
1117_("finobt record with no free inodes, inode chunk %d/%u\n"), agno, ino);
1118 }
1119
1120 return suspect;
1121}
6ceb5693 1122
2bd0ea18
NS
1123/*
1124 * this one walks the inode btrees sucking the info there into
1125 * the incore avl tree. We try and rescue corrupted btree records
1126 * to minimize our chances of losing inodes. Inode info from potentially
1127 * corrupt sources could be bogus so rather than put the info straight
1128 * into the tree, instead we put it on a list and try and verify the
1129 * info in the next phase by examining what's on disk. At that point,
1130 * we'll be able to figure out what's what and stick the corrected info
1131 * into the tree. We do bail out at some point and give up on a subtree
1132 * so as to avoid walking randomly all over the ag.
1133 *
1134 * Note that it's also ok if the free/inuse info wrong, we can correct
1135 * that when we examine the on-disk inode. The important thing is to
1136 * get the start and alignment of the inode chunks right. Those chunks
1137 * that we aren't sure about go into the uncertain list.
1138 */
364a126c 1139static void
e0607266 1140scan_inobt(
b3563c19 1141 struct xfs_btree_block *block,
2bd0ea18
NS
1142 int level,
1143 xfs_agblock_t bno,
1144 xfs_agnumber_t agno,
1145 int suspect,
364a126c 1146 int isroot,
e0607266 1147 __uint32_t magic,
364a126c 1148 void *priv)
2bd0ea18 1149{
364a126c 1150 struct aghdr_cnts *agcnts = priv;
2bd0ea18 1151 int i;
2bd0ea18
NS
1152 int numrecs;
1153 int state;
1154 xfs_inobt_ptr_t *pp;
1155 xfs_inobt_rec_t *rp;
2bd0ea18
NS
1156 int hdr_errors;
1157
2bd0ea18
NS
1158 hdr_errors = 0;
1159
e0607266 1160 if (be32_to_cpu(block->bb_magic) != magic) {
507f4e33 1161 do_warn(_("bad magic # %#x in inobt block %d/%d\n"),
5e656dbb 1162 be32_to_cpu(block->bb_magic), agno, bno);
2bd0ea18
NS
1163 hdr_errors++;
1164 bad_ino_btree = 1;
1165 if (suspect)
1166 return;
1167 }
5e656dbb 1168 if (be16_to_cpu(block->bb_level) != level) {
507f4e33 1169 do_warn(_("expected level %d got %d in inobt block %d/%d\n"),
5e656dbb 1170 level, be16_to_cpu(block->bb_level), agno, bno);
2bd0ea18
NS
1171 hdr_errors++;
1172 bad_ino_btree = 1;
1173 if (suspect)
1174 return;
1175 }
1176
1177 /*
1178 * check for btree blocks multiply claimed, any unknown/free state
1179 * is ok in the bitmap block.
1180 */
95650c4d 1181 state = get_bmap(agno, bno);
2bd0ea18
NS
1182 switch (state) {
1183 case XR_E_UNKNOWN:
1184 case XR_E_FREE1:
1185 case XR_E_FREE:
95650c4d 1186 set_bmap(agno, bno, XR_E_FS_MAP);
2bd0ea18
NS
1187 break;
1188 default:
95650c4d 1189 set_bmap(agno, bno, XR_E_MULT);
2bd0ea18 1190 do_warn(
507f4e33
NS
1191_("inode btree block claimed (state %d), agno %d, bno %d, suspect %d\n"),
1192 state, agno, bno, suspect);
2bd0ea18
NS
1193 }
1194
5e656dbb 1195 numrecs = be16_to_cpu(block->bb_numrecs);
2bd0ea18
NS
1196
1197 /*
1198 * leaf record in btree
1199 */
1200 if (level == 0) {
1201 /* check for trashed btree block */
1202
5e656dbb 1203 if (numrecs > mp->m_inobt_mxr[0]) {
2bd0ea18
NS
1204 numrecs = mp->m_inobt_mxr[0];
1205 hdr_errors++;
1206 }
5e656dbb 1207 if (isroot == 0 && numrecs < mp->m_inobt_mnr[0]) {
2bd0ea18
NS
1208 numrecs = mp->m_inobt_mnr[0];
1209 hdr_errors++;
1210 }
1211
1212 if (hdr_errors) {
1213 bad_ino_btree = 1;
507f4e33 1214 do_warn(_("dubious inode btree block header %d/%d\n"),
2bd0ea18
NS
1215 agno, bno);
1216 suspect++;
1217 }
1218
b3563c19 1219 rp = XFS_INOBT_REC_ADDR(mp, block, 1);
2bd0ea18
NS
1220
1221 /*
1222 * step through the records, each record points to
1223 * a chunk of inodes. The start of inode chunks should
1224 * be block-aligned. Each inode btree rec should point
1225 * to the start of a block of inodes or the start of a group
1226 * of INODES_PER_CHUNK (64) inodes. off is the offset into
1227 * the block. skip processing of bogus records.
1228 */
48d49157 1229 for (i = 0; i < numrecs; i++) {
1578050f
BF
1230 if (magic == XFS_IBT_MAGIC ||
1231 magic == XFS_IBT_CRC_MAGIC) {
1232 agcnts->agicount += XFS_INODES_PER_CHUNK;
1233 agcnts->icount += XFS_INODES_PER_CHUNK;
1234 agcnts->agifreecount +=
1235 be32_to_cpu(rp[i].ir_freecount);
1236 agcnts->ifreecount +=
1237 be32_to_cpu(rp[i].ir_freecount);
1238
1239 suspect = scan_single_ino_chunk(agno, &rp[i],
1240 suspect);
1241 } else {
1242 /*
1243 * the finobt tracks records with free inodes,
1244 * so only the free inode count is expected to be
1245 * consistent with the agi
1246 */
1247 agcnts->fibtfreecount +=
1248 be32_to_cpu(rp[i].ir_freecount);
48d49157 1249
1578050f
BF
1250 suspect = scan_single_finobt_chunk(agno, &rp[i],
1251 suspect);
1252 }
48d49157 1253 }
2bd0ea18
NS
1254
1255 if (suspect)
1256 bad_ino_btree = 1;
1257
1258 return;
1259 }
1260
1261 /*
1262 * interior record, continue on
1263 */
5e656dbb 1264 if (numrecs > mp->m_inobt_mxr[1]) {
2bd0ea18
NS
1265 numrecs = mp->m_inobt_mxr[1];
1266 hdr_errors++;
1267 }
5e656dbb 1268 if (isroot == 0 && numrecs < mp->m_inobt_mnr[1]) {
2bd0ea18
NS
1269 numrecs = mp->m_inobt_mnr[1];
1270 hdr_errors++;
1271 }
1272
b3563c19 1273 pp = XFS_INOBT_PTR_ADDR(mp, block, 1, mp->m_inobt_mxr[1]);
2bd0ea18
NS
1274
1275 /*
1276 * don't pass bogus tree flag down further if this block
1277 * looked ok. bail out if two levels in a row look bad.
1278 */
1279
1280 if (suspect && !hdr_errors)
1281 suspect = 0;
1282
1283 if (hdr_errors) {
1284 bad_ino_btree = 1;
1285 if (suspect)
1286 return;
1287 else suspect++;
1288 }
1289
1290 for (i = 0; i < numrecs; i++) {
5e656dbb
BN
1291 if (be32_to_cpu(pp[i]) != 0 && verify_agbno(mp, agno,
1292 be32_to_cpu(pp[i])))
1293 scan_sbtree(be32_to_cpu(pp[i]), level, agno,
e0607266
DC
1294 suspect, scan_inobt, 0, magic, priv,
1295 &xfs_inobt_buf_ops);
2bd0ea18
NS
1296 }
1297}
1298
364a126c 1299static void
2bd0ea18 1300scan_freelist(
364a126c
DC
1301 xfs_agf_t *agf,
1302 struct aghdr_cnts *agcnts)
2bd0ea18 1303{
2bd0ea18 1304 xfs_buf_t *agflbuf;
1d0df0af 1305 xfs_agnumber_t agno;
2bd0ea18
NS
1306 xfs_agblock_t bno;
1307 int count;
1308 int i;
84232448 1309 __be32 *freelist;
2bd0ea18 1310
1d0df0af
BN
1311 agno = be32_to_cpu(agf->agf_seqno);
1312
2bd0ea18 1313 if (XFS_SB_BLOCK(mp) != XFS_AGFL_BLOCK(mp) &&
1d0df0af
BN
1314 XFS_AGF_BLOCK(mp) != XFS_AGFL_BLOCK(mp) &&
1315 XFS_AGI_BLOCK(mp) != XFS_AGFL_BLOCK(mp))
95650c4d 1316 set_bmap(agno, XFS_AGFL_BLOCK(mp), XR_E_FS_MAP);
1d0df0af 1317
5e656dbb 1318 if (be32_to_cpu(agf->agf_flcount) == 0)
2bd0ea18 1319 return;
1d0df0af
BN
1320
1321 agflbuf = libxfs_readbuf(mp->m_dev,
1322 XFS_AG_DADDR(mp, agno, XFS_AGFL_DADDR(mp)),
75c8b434 1323 XFS_FSS_TO_BB(mp, 1), 0, &xfs_agfl_buf_ops);
2bd0ea18 1324 if (!agflbuf) {
1d0df0af 1325 do_abort(_("can't read agfl block for ag %d\n"), agno);
2bd0ea18
NS
1326 return;
1327 }
a76a5a71
DC
1328 if (agflbuf->b_error == EFSBADCRC)
1329 do_warn(_("agfl has bad CRC for ag %d\n"), agno);
1330
84232448 1331 freelist = XFS_BUF_TO_AGFL_BNO(mp, agflbuf);
a529cc7f 1332 i = be32_to_cpu(agf->agf_flfirst);
7e8e3cce
ES
1333
1334 if (no_modify) {
1335 /* agf values not fixed in verify_set_agf, so recheck */
1336 if (be32_to_cpu(agf->agf_flfirst) >= XFS_AGFL_SIZE(mp) ||
1337 be32_to_cpu(agf->agf_fllast) >= XFS_AGFL_SIZE(mp)) {
1338 do_warn(_("agf %d freelist blocks bad, skipping "
1339 "freelist scan\n"), i);
1340 return;
1341 }
b326e067 1342 }
7e8e3cce 1343
2bd0ea18
NS
1344 count = 0;
1345 for (;;) {
84232448 1346 bno = be32_to_cpu(freelist[i]);
1d0df0af 1347 if (verify_agbno(mp, agno, bno))
95650c4d 1348 set_bmap(agno, bno, XR_E_FREE);
2bd0ea18 1349 else
507f4e33 1350 do_warn(_("bad agbno %u in agfl, agno %d\n"),
1d0df0af 1351 bno, agno);
2bd0ea18 1352 count++;
5e656dbb 1353 if (i == be32_to_cpu(agf->agf_fllast))
2bd0ea18 1354 break;
9440d84d 1355 if (++i == XFS_AGFL_SIZE(mp))
2bd0ea18
NS
1356 i = 0;
1357 }
5e656dbb 1358 if (count != be32_to_cpu(agf->agf_flcount)) {
507f4e33 1359 do_warn(_("freeblk count %d != flcount %d in ag %d\n"), count,
1d0df0af 1360 be32_to_cpu(agf->agf_flcount), agno);
2bd0ea18 1361 }
48d49157 1362
364a126c 1363 agcnts->fdblocks += count;
48d49157 1364
2bd0ea18
NS
1365 libxfs_putbuf(agflbuf);
1366}
1367
48d49157
CH
1368static void
1369validate_agf(
1370 struct xfs_agf *agf,
364a126c
DC
1371 xfs_agnumber_t agno,
1372 struct aghdr_cnts *agcnts)
48d49157
CH
1373{
1374 xfs_agblock_t bno;
e0607266 1375 __uint32_t magic;
48d49157
CH
1376
1377 bno = be32_to_cpu(agf->agf_roots[XFS_BTNUM_BNO]);
1378 if (bno != 0 && verify_agbno(mp, agno, bno)) {
e0607266
DC
1379 magic = xfs_sb_version_hascrc(&mp->m_sb) ? XFS_ABTB_CRC_MAGIC
1380 : XFS_ABTB_MAGIC;
48d49157 1381 scan_sbtree(bno, be32_to_cpu(agf->agf_levels[XFS_BTNUM_BNO]),
e0607266
DC
1382 agno, 0, scan_allocbt, 1, magic, agcnts,
1383 &xfs_allocbt_buf_ops);
48d49157
CH
1384 } else {
1385 do_warn(_("bad agbno %u for btbno root, agno %d\n"),
1386 bno, agno);
1387 }
1388
1389 bno = be32_to_cpu(agf->agf_roots[XFS_BTNUM_CNT]);
1390 if (bno != 0 && verify_agbno(mp, agno, bno)) {
e0607266
DC
1391 magic = xfs_sb_version_hascrc(&mp->m_sb) ? XFS_ABTC_CRC_MAGIC
1392 : XFS_ABTC_MAGIC;
48d49157 1393 scan_sbtree(bno, be32_to_cpu(agf->agf_levels[XFS_BTNUM_CNT]),
e0607266
DC
1394 agno, 0, scan_allocbt, 1, magic, agcnts,
1395 &xfs_allocbt_buf_ops);
48d49157
CH
1396 } else {
1397 do_warn(_("bad agbno %u for btbcnt root, agno %d\n"),
1398 bno, agno);
1399 }
1400
364a126c 1401 if (be32_to_cpu(agf->agf_freeblks) != agcnts->agffreeblks) {
48d49157 1402 do_warn(_("agf_freeblks %u, counted %u in ag %u\n"),
364a126c 1403 be32_to_cpu(agf->agf_freeblks), agcnts->agffreeblks, agno);
48d49157
CH
1404 }
1405
364a126c 1406 if (be32_to_cpu(agf->agf_longest) != agcnts->agflongest) {
48d49157 1407 do_warn(_("agf_longest %u, counted %u in ag %u\n"),
364a126c 1408 be32_to_cpu(agf->agf_longest), agcnts->agflongest, agno);
48d49157
CH
1409 }
1410
1411 if (xfs_sb_version_haslazysbcount(&mp->m_sb) &&
364a126c 1412 be32_to_cpu(agf->agf_btreeblks) != agcnts->agfbtreeblks) {
5d1b7f0f 1413 do_warn(_("agf_btreeblks %u, counted %" PRIu64 " in ag %u\n"),
364a126c 1414 be32_to_cpu(agf->agf_btreeblks), agcnts->agfbtreeblks, agno);
48d49157
CH
1415 }
1416}
1417
1418static void
1419validate_agi(
1420 struct xfs_agi *agi,
364a126c
DC
1421 xfs_agnumber_t agno,
1422 struct aghdr_cnts *agcnts)
48d49157
CH
1423{
1424 xfs_agblock_t bno;
1425 int i;
e0607266 1426 __uint32_t magic;
48d49157
CH
1427
1428 bno = be32_to_cpu(agi->agi_root);
1429 if (bno != 0 && verify_agbno(mp, agno, bno)) {
e0607266
DC
1430 magic = xfs_sb_version_hascrc(&mp->m_sb) ? XFS_IBT_CRC_MAGIC
1431 : XFS_IBT_MAGIC;
48d49157 1432 scan_sbtree(bno, be32_to_cpu(agi->agi_level),
e0607266
DC
1433 agno, 0, scan_inobt, 1, magic, agcnts,
1434 &xfs_inobt_buf_ops);
48d49157
CH
1435 } else {
1436 do_warn(_("bad agbno %u for inobt root, agno %d\n"),
1437 be32_to_cpu(agi->agi_root), agno);
1438 }
1439
1578050f
BF
1440 if (xfs_sb_version_hasfinobt(&mp->m_sb)) {
1441 bno = be32_to_cpu(agi->agi_free_root);
1442 if (bno != 0 && verify_agbno(mp, agno, bno)) {
1443 magic = xfs_sb_version_hascrc(&mp->m_sb) ?
1444 XFS_FIBT_CRC_MAGIC : XFS_FIBT_MAGIC;
1445 scan_sbtree(bno, be32_to_cpu(agi->agi_free_level),
1446 agno, 0, scan_inobt, 1, magic, agcnts,
1447 &xfs_inobt_buf_ops);
1448 } else {
1449 do_warn(_("bad agbno %u for finobt root, agno %d\n"),
1450 be32_to_cpu(agi->agi_free_root), agno);
1451 }
1452 }
1453
364a126c 1454 if (be32_to_cpu(agi->agi_count) != agcnts->agicount) {
48d49157 1455 do_warn(_("agi_count %u, counted %u in ag %u\n"),
364a126c 1456 be32_to_cpu(agi->agi_count), agcnts->agicount, agno);
48d49157
CH
1457 }
1458
364a126c 1459 if (be32_to_cpu(agi->agi_freecount) != agcnts->agifreecount) {
48d49157 1460 do_warn(_("agi_freecount %u, counted %u in ag %u\n"),
364a126c 1461 be32_to_cpu(agi->agi_freecount), agcnts->agifreecount, agno);
48d49157
CH
1462 }
1463
1578050f
BF
1464 if (xfs_sb_version_hasfinobt(&mp->m_sb) &&
1465 be32_to_cpu(agi->agi_freecount) != agcnts->fibtfreecount) {
1466 do_warn(_("agi_freecount %u, counted %u in ag %u finobt\n"),
1467 be32_to_cpu(agi->agi_freecount), agcnts->fibtfreecount,
1468 agno);
1469 }
1470
48d49157
CH
1471 for (i = 0; i < XFS_AGI_UNLINKED_BUCKETS; i++) {
1472 xfs_agino_t agino = be32_to_cpu(agi->agi_unlinked[i]);
1473
1474 if (agino != NULLAGINO) {
1475 do_warn(
5d1b7f0f 1476 _("agi unlinked bucket %d is %u in ag %u (inode=%" PRIu64 ")\n"),
48d49157
CH
1477 i, agino, agno,
1478 XFS_AGINO_TO_INO(mp, agno, agino));
1479 }
1480 }
1481}
1482
48d49157
CH
1483/*
1484 * Scan an AG for obvious corruption.
48d49157 1485 */
364a126c 1486static void
2bd0ea18 1487scan_ag(
364a126c
DC
1488 work_queue_t *wq,
1489 xfs_agnumber_t agno,
1490 void *arg)
2bd0ea18 1491{
364a126c 1492 struct aghdr_cnts *agcnts = arg;
8f657d7e
DC
1493 struct xfs_agf *agf;
1494 struct xfs_buf *agfbuf = NULL;
48d49157 1495 int agf_dirty = 0;
8f657d7e
DC
1496 struct xfs_agi *agi;
1497 struct xfs_buf *agibuf = NULL;
48d49157 1498 int agi_dirty = 0;
8f657d7e
DC
1499 struct xfs_sb *sb = NULL;
1500 struct xfs_buf *sbbuf = NULL;
48d49157 1501 int sb_dirty = 0;
2bd0ea18 1502 int status;
8f657d7e 1503 char *objname = NULL;
2bd0ea18 1504
8bc43a39 1505 sb = (struct xfs_sb *)calloc(BBTOB(XFS_FSS_TO_BB(mp, 1)), 1);
507f4e33
NS
1506 if (!sb) {
1507 do_error(_("can't allocate memory for superblock\n"));
507f4e33 1508 return;
dfc130f3 1509 }
8f657d7e
DC
1510
1511 sbbuf = libxfs_readbuf(mp->m_dev, XFS_AG_DADDR(mp, agno, XFS_SB_DADDR),
1512 XFS_FSS_TO_BB(mp, 1), 0, &xfs_sb_buf_ops);
1513 if (!sbbuf) {
1514 objname = _("root superblock");
1515 goto out_free_sb;
1516 }
5e656dbb 1517 libxfs_sb_from_disk(sb, XFS_BUF_TO_SBP(sbbuf));
d085fb48 1518 libxfs_sb_quota_from_disk(sb);
2bd0ea18
NS
1519
1520 agfbuf = libxfs_readbuf(mp->m_dev,
9440d84d 1521 XFS_AG_DADDR(mp, agno, XFS_AGF_DADDR(mp)),
75c8b434 1522 XFS_FSS_TO_BB(mp, 1), 0, &xfs_agf_buf_ops);
2bd0ea18 1523 if (!agfbuf) {
8f657d7e
DC
1524 objname = _("agf block");
1525 goto out_free_sbbuf;
2bd0ea18
NS
1526 }
1527 agf = XFS_BUF_TO_AGF(agfbuf);
1528
1529 agibuf = libxfs_readbuf(mp->m_dev,
9440d84d 1530 XFS_AG_DADDR(mp, agno, XFS_AGI_DADDR(mp)),
75c8b434 1531 XFS_FSS_TO_BB(mp, 1), 0, &xfs_agi_buf_ops);
2bd0ea18 1532 if (!agibuf) {
8f657d7e
DC
1533 objname = _("agi block");
1534 goto out_free_agfbuf;
2bd0ea18
NS
1535 }
1536 agi = XFS_BUF_TO_AGI(agibuf);
1537
1538 /* fix up bad ag headers */
1539
1540 status = verify_set_agheader(mp, sbbuf, sb, agf, agi, agno);
1541
1542 if (status & XR_AG_SB_SEC) {
1543 if (!no_modify)
1544 sb_dirty = 1;
1545 /*
1546 * clear bad sector bit because we don't want
1547 * to skip further processing. we just want to
1548 * ensure that we write out the modified sb buffer.
1549 */
1550 status &= ~XR_AG_SB_SEC;
1551 }
1552 if (status & XR_AG_SB) {
507f4e33
NS
1553 if (!no_modify) {
1554 do_warn(_("reset bad sb for ag %d\n"), agno);
2bd0ea18 1555 sb_dirty = 1;
507f4e33
NS
1556 } else {
1557 do_warn(_("would reset bad sb for ag %d\n"), agno);
1558 }
2bd0ea18
NS
1559 }
1560 if (status & XR_AG_AGF) {
507f4e33
NS
1561 if (!no_modify) {
1562 do_warn(_("reset bad agf for ag %d\n"), agno);
2bd0ea18 1563 agf_dirty = 1;
507f4e33
NS
1564 } else {
1565 do_warn(_("would reset bad agf for ag %d\n"), agno);
1566 }
2bd0ea18
NS
1567 }
1568 if (status & XR_AG_AGI) {
507f4e33
NS
1569 if (!no_modify) {
1570 do_warn(_("reset bad agi for ag %d\n"), agno);
2bd0ea18 1571 agi_dirty = 1;
507f4e33
NS
1572 } else {
1573 do_warn(_("would reset bad agi for ag %d\n"), agno);
1574 }
2bd0ea18
NS
1575 }
1576
1577 if (status && no_modify) {
507f4e33
NS
1578 do_warn(_("bad uncorrected agheader %d, skipping ag...\n"),
1579 agno);
8f657d7e 1580 goto out_free_agibuf;
2bd0ea18
NS
1581 }
1582
364a126c 1583 scan_freelist(agf, agcnts);
2bd0ea18 1584
364a126c
DC
1585 validate_agf(agf, agno, agcnts);
1586 validate_agi(agi, agno, agcnts);
2bd0ea18 1587
27527004 1588 ASSERT(agi_dirty == 0 || (agi_dirty && !no_modify));
8f657d7e
DC
1589 ASSERT(agf_dirty == 0 || (agf_dirty && !no_modify));
1590 ASSERT(sb_dirty == 0 || (sb_dirty && !no_modify));
1591
1592 /*
1593 * Only pay attention to CRC/verifier errors if we can correct them.
1fe7b0b0
DC
1594 * Note that we can get uncorrected EFSCORRUPTED errors here because
1595 * the verifier will flag on out of range values that we can't correct
1596 * until phase 5 when we have all the information necessary to rebuild
1597 * the freespace/inode btrees. We can correct bad CRC errors
1598 * immediately, though.
8f657d7e
DC
1599 */
1600 if (!no_modify) {
8f657d7e
DC
1601 agi_dirty += (agibuf->b_error == EFSBADCRC);
1602 agf_dirty += (agfbuf->b_error == EFSBADCRC);
1603 sb_dirty += (sbbuf->b_error == EFSBADCRC);
1604 }
2bd0ea18
NS
1605
1606 if (agi_dirty && !no_modify)
1607 libxfs_writebuf(agibuf, 0);
1608 else
1609 libxfs_putbuf(agibuf);
1610
2bd0ea18
NS
1611 if (agf_dirty && !no_modify)
1612 libxfs_writebuf(agfbuf, 0);
1613 else
1614 libxfs_putbuf(agfbuf);
1615
2bd0ea18 1616 if (sb_dirty && !no_modify) {
e8cb94ee
BN
1617 if (agno == 0)
1618 memcpy(&mp->m_sb, sb, sizeof(xfs_sb_t));
5e656dbb 1619 libxfs_sb_to_disk(XFS_BUF_TO_SBP(sbbuf), sb, XFS_SB_ALL_BITS);
2bd0ea18 1620 libxfs_writebuf(sbbuf, 0);
dfc130f3 1621 } else
2bd0ea18 1622 libxfs_putbuf(sbbuf);
dfc130f3 1623 free(sb);
06fbdda9 1624 PROG_RPT_INC(prog_rpt_done[agno], 1);
364a126c
DC
1625
1626#ifdef XR_INODE_TRACE
1627 print_inode_list(i);
1628#endif
1629 return;
8f657d7e
DC
1630
1631out_free_agibuf:
1632 libxfs_putbuf(agibuf);
1633out_free_agfbuf:
1634 libxfs_putbuf(agfbuf);
1635out_free_sbbuf:
1636 libxfs_putbuf(sbbuf);
1637out_free_sb:
1638 free(sb);
1639
1640 if (objname)
1641 do_error(_("can't get %s for ag %d\n"), objname, agno);
2bd0ea18 1642}
364a126c
DC
1643
1644#define SCAN_THREADS 32
1645
1646void
1647scan_ags(
1648 struct xfs_mount *mp,
1649 int scan_threads)
1650{
1651 struct aghdr_cnts *agcnts;
1652 __uint64_t fdblocks = 0;
1653 __uint64_t icount = 0;
1654 __uint64_t ifreecount = 0;
1655 xfs_agnumber_t i;
1656 work_queue_t wq;
1657
1658 agcnts = malloc(mp->m_sb.sb_agcount * sizeof(*agcnts));
1659 if (!agcnts) {
1660 do_abort(_("no memory for ag header counts\n"));
1661 return;
1662 }
1663 memset(agcnts, 0, mp->m_sb.sb_agcount * sizeof(*agcnts));
1664
f756f80c 1665 create_work_queue(&wq, mp, scan_threads);
364a126c
DC
1666
1667 for (i = 0; i < mp->m_sb.sb_agcount; i++)
1668 queue_work(&wq, scan_ag, i, &agcnts[i]);
1669
1670 destroy_work_queue(&wq);
1671
1672 /* tally up the counts */
1673 for (i = 0; i < mp->m_sb.sb_agcount; i++) {
1674 fdblocks += agcnts[i].fdblocks;
1675 icount += agcnts[i].icount;
1676 ifreecount += agcnts[i].ifreecount;
1677 }
1678
aba29588
ES
1679 free(agcnts);
1680
364a126c
DC
1681 /*
1682 * Validate that our manual counts match the superblock.
1683 */
1684 if (mp->m_sb.sb_icount != icount) {
5d1b7f0f 1685 do_warn(_("sb_icount %" PRIu64 ", counted %" PRIu64 "\n"),
364a126c
DC
1686 mp->m_sb.sb_icount, icount);
1687 }
1688
1689 if (mp->m_sb.sb_ifree != ifreecount) {
5d1b7f0f 1690 do_warn(_("sb_ifree %" PRIu64 ", counted %" PRIu64 "\n"),
364a126c
DC
1691 mp->m_sb.sb_ifree, ifreecount);
1692 }
1693
1694 if (mp->m_sb.sb_fdblocks != fdblocks) {
5d1b7f0f 1695 do_warn(_("sb_fdblocks %" PRIu64 ", counted %" PRIu64 "\n"),
364a126c
DC
1696 mp->m_sb.sb_fdblocks, fdblocks);
1697 }
1698}
1699