]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blame - db/check.c
misc: clean up MIN/MAX in the utilities
[thirdparty/xfsprogs-dev.git] / db / check.c
CommitLineData
959ef981 1// SPDX-License-Identifier: GPL-2.0
2bd0ea18 2/*
da23017d
NS
3 * Copyright (c) 2000-2002,2005 Silicon Graphics, Inc.
4 * All Rights Reserved.
2bd0ea18
NS
5 */
6
6b803e5a 7#include "libxfs.h"
2bd0ea18 8#include <math.h>
2bd0ea18
NS
9#include <sys/time.h>
10#include "bmap.h"
11#include "check.h"
12#include "command.h"
2bd0ea18 13#include "io.h"
128efca1 14#include "type.h"
46eca962
NS
15#include "fprint.h"
16#include "faddr.h"
17#include "field.h"
add013da 18#include "sb.h"
2bd0ea18 19#include "output.h"
4ca431fc 20#include "init.h"
2bd0ea18 21#include "malloc.h"
a2ceac1f 22#include "dir2.h"
2bd0ea18 23
9b27bdbb
NS
24typedef enum {
25 IS_USER_QUOTA, IS_PROJECT_QUOTA, IS_GROUP_QUOTA,
26} qtype_t;
27
2bd0ea18
NS
28typedef enum {
29 DBM_UNKNOWN, DBM_AGF, DBM_AGFL, DBM_AGI,
30 DBM_ATTR, DBM_BTBMAPA, DBM_BTBMAPD, DBM_BTBNO,
31 DBM_BTCNT, DBM_BTINO, DBM_DATA, DBM_DIR,
32 DBM_FREE1, DBM_FREE2, DBM_FREELIST, DBM_INODE,
33 DBM_LOG, DBM_MISSING, DBM_QUOTA, DBM_RTBITMAP,
34 DBM_RTDATA, DBM_RTFREE, DBM_RTSUM, DBM_SB,
757ad8c7 35 DBM_SYMLINK, DBM_BTFINO, DBM_BTRMAP, DBM_BTREFC,
13ef9674 36 DBM_RLDATA, DBM_COWDATA,
2bd0ea18
NS
37 DBM_NDBM
38} dbm_t;
39
40typedef struct inodata {
41 struct inodata *next;
42 nlink_t link_set;
43 nlink_t link_add;
757ad8c7
DW
44 char isdir:1;
45 char isreflink:1;
2bd0ea18
NS
46 char security;
47 char ilist;
48 xfs_ino_t ino;
49 struct inodata *parent;
50 char *name;
51} inodata_t;
52#define MIN_INODATA_HASH_SIZE 256
53#define MAX_INODATA_HASH_SIZE 65536
54#define INODATA_AVG_HASH_LENGTH 8
55
56typedef struct qinfo {
57 xfs_qcnt_t bc;
58 xfs_qcnt_t ic;
59 xfs_qcnt_t rc;
60} qinfo_t;
61
62#define QDATA_HASH_SIZE 256
63typedef struct qdata {
64 struct qdata *next;
65 xfs_dqid_t id;
66 qinfo_t count;
67 qinfo_t dq;
68} qdata_t;
69
70typedef struct blkent {
71 xfs_fileoff_t startoff;
72 int nblks;
73 xfs_fsblock_t blks[1];
74} blkent_t;
75#define BLKENT_SIZE(n) \
76 (offsetof(blkent_t, blks) + (sizeof(xfs_fsblock_t) * (n)))
77
78typedef struct blkmap {
79 int naents;
80 int nents;
81 blkent_t *ents[1];
82} blkmap_t;
83#define BLKMAP_SIZE(n) \
84 (offsetof(blkmap_t, ents) + (sizeof(blkent_t *) * (n)))
85
86typedef struct freetab {
87 int naents;
88 int nents;
89 xfs_dir2_data_off_t ents[1];
90} freetab_t;
91#define FREETAB_SIZE(n) \
92 (offsetof(freetab_t, ents) + (sizeof(xfs_dir2_data_off_t) * (n)))
93
94typedef struct dirhash {
95 struct dirhash *next;
5e656dbb
BN
96 __u32 hashval;
97 __u32 address;
2bd0ea18
NS
98 int seen;
99} dirhash_t;
100#define DIR_HASH_SIZE 1024
101#define DIR_HASH_FUNC(h,a) (((h) ^ (a)) % DIR_HASH_SIZE)
102
103static xfs_extlen_t agffreeblks;
104static xfs_extlen_t agflongest;
14f8b681
DW
105static uint64_t agf_aggr_freeblks; /* aggregate count over all */
106static uint32_t agfbtreeblks;
cdded3d8 107static int lazycount;
2bd0ea18
NS
108static xfs_agino_t agicount;
109static xfs_agino_t agifreecount;
110static xfs_fsblock_t *blist;
111static int blist_size;
112static char **dbmap; /* really dbm_t:8 */
113static dirhash_t **dirhash;
114static int error;
14f8b681
DW
115static uint64_t fdblocks;
116static uint64_t frextents;
117static uint64_t icount;
118static uint64_t ifree;
2bd0ea18
NS
119static inodata_t ***inodata;
120static int inodata_hash_size;
121static inodata_t ***inomap;
122static int nflag;
123static int pflag;
32a82561 124static int tflag;
9b27bdbb
NS
125static qdata_t **qpdata;
126static int qpdo;
2bd0ea18
NS
127static qdata_t **qudata;
128static int qudo;
9b27bdbb
NS
129static qdata_t **qgdata;
130static int qgdo;
2bd0ea18
NS
131static unsigned sbversion;
132static int sbver_err;
133static int serious_error;
134static int sflag;
135static xfs_suminfo_t *sumcompute;
136static xfs_suminfo_t *sumfile;
137static const char *typename[] = {
138 "unknown",
139 "agf",
140 "agfl",
141 "agi",
142 "attr",
143 "btbmapa",
144 "btbmapd",
145 "btbno",
146 "btcnt",
147 "btino",
148 "data",
149 "dir",
150 "free1",
151 "free2",
152 "freelist",
153 "inode",
154 "log",
155 "missing",
156 "quota",
157 "rtbitmap",
158 "rtdata",
159 "rtfree",
160 "rtsum",
161 "sb",
162 "symlink",
e96864ff 163 "btfino",
e3dcc17b 164 "btrmap",
757ad8c7
DW
165 "btrefcnt",
166 "rldata",
2bd0ea18
NS
167 NULL
168};
169static int verbose;
170
171#define CHECK_BLIST(b) (blist_size && check_blist(b))
172#define CHECK_BLISTA(a,b) \
173 (blist_size && check_blist(XFS_AGB_TO_FSB(mp, a, b)))
174
b3563c19 175typedef void (*scan_lbtree_f_t)(struct xfs_btree_block *block,
2bd0ea18
NS
176 int level,
177 dbm_t type,
178 xfs_fsblock_t bno,
179 inodata_t *id,
5a35bf2c
DC
180 xfs_rfsblock_t *totd,
181 xfs_rfsblock_t *toti,
2bd0ea18
NS
182 xfs_extnum_t *nex,
183 blkmap_t **blkmapp,
184 int isroot,
185 typnm_t btype);
186
b3563c19 187typedef void (*scan_sbtree_f_t)(struct xfs_btree_block *block,
2bd0ea18
NS
188 int level,
189 xfs_agf_t *agf,
190 xfs_agblock_t bno,
191 int isroot);
192
193static void add_blist(xfs_fsblock_t bno);
194static void add_ilist(xfs_ino_t ino);
195static void addlink_inode(inodata_t *id);
196static void addname_inode(inodata_t *id, char *name, int namelen);
197static void addparent_inode(inodata_t *id, xfs_ino_t parent);
198static void blkent_append(blkent_t **entp, xfs_fsblock_t b,
199 xfs_extlen_t c);
200static blkent_t *blkent_new(xfs_fileoff_t o, xfs_fsblock_t b,
201 xfs_extlen_t c);
202static void blkent_prepend(blkent_t **entp, xfs_fsblock_t b,
203 xfs_extlen_t c);
204static blkmap_t *blkmap_alloc(xfs_extnum_t);
205static void blkmap_free(blkmap_t *blkmap);
206static xfs_fsblock_t blkmap_get(blkmap_t *blkmap, xfs_fileoff_t o);
207static int blkmap_getn(blkmap_t *blkmap, xfs_fileoff_t o, int nb,
208 bmap_ext_t **bmpp);
209static void blkmap_grow(blkmap_t **blkmapp, blkent_t **entp,
210 blkent_t *newent);
211static xfs_fileoff_t blkmap_next_off(blkmap_t *blkmap, xfs_fileoff_t o,
212 int *t);
213static void blkmap_set_blk(blkmap_t **blkmapp, xfs_fileoff_t o,
214 xfs_fsblock_t b);
215static void blkmap_set_ext(blkmap_t **blkmapp, xfs_fileoff_t o,
216 xfs_fsblock_t b, xfs_extlen_t c);
217static void blkmap_shrink(blkmap_t *blkmap, blkent_t **entp);
218static int blockfree_f(int argc, char **argv);
219static int blockget_f(int argc, char **argv);
2bd0ea18 220static int blocktrash_f(int argc, char **argv);
2bd0ea18
NS
221static int blockuse_f(int argc, char **argv);
222static int check_blist(xfs_fsblock_t bno);
223static void check_dbmap(xfs_agnumber_t agno, xfs_agblock_t agbno,
757ad8c7
DW
224 xfs_extlen_t len, dbm_t type,
225 int ignore_reflink);
2bd0ea18
NS
226static int check_inomap(xfs_agnumber_t agno, xfs_agblock_t agbno,
227 xfs_extlen_t len, xfs_ino_t c_ino);
228static void check_linkcounts(xfs_agnumber_t agno);
229static int check_range(xfs_agnumber_t agno, xfs_agblock_t agbno,
230 xfs_extlen_t len);
5a35bf2c 231static void check_rdbmap(xfs_rfsblock_t bno, xfs_extlen_t len,
2bd0ea18 232 dbm_t type);
5a35bf2c 233static int check_rinomap(xfs_rfsblock_t bno, xfs_extlen_t len,
2bd0ea18
NS
234 xfs_ino_t c_ino);
235static void check_rootdir(void);
5a35bf2c 236static int check_rrange(xfs_rfsblock_t bno, xfs_extlen_t len);
2bd0ea18
NS
237static void check_set_dbmap(xfs_agnumber_t agno,
238 xfs_agblock_t agbno, xfs_extlen_t len,
239 dbm_t type1, dbm_t type2,
240 xfs_agnumber_t c_agno,
241 xfs_agblock_t c_agbno);
5a35bf2c 242static void check_set_rdbmap(xfs_rfsblock_t bno, xfs_extlen_t len,
2bd0ea18
NS
243 dbm_t type1, dbm_t type2);
244static void check_summary(void);
245static void checknot_dbmap(xfs_agnumber_t agno, xfs_agblock_t agbno,
246 xfs_extlen_t len, int typemask);
5a35bf2c 247static void checknot_rdbmap(xfs_rfsblock_t bno, xfs_extlen_t len,
2bd0ea18
NS
248 int typemask);
249static void dir_hash_add(xfs_dahash_t hash,
250 xfs_dir2_dataptr_t addr);
251static void dir_hash_check(inodata_t *id, int v);
252static void dir_hash_done(void);
253static void dir_hash_init(void);
254static int dir_hash_see(xfs_dahash_t hash,
255 xfs_dir2_dataptr_t addr);
256static inodata_t *find_inode(xfs_ino_t ino, int add);
257static void free_inodata(xfs_agnumber_t agno);
258static int init(int argc, char **argv);
259static char *inode_name(xfs_ino_t ino, inodata_t **ipp);
260static int ncheck_f(int argc, char **argv);
261static char *prepend_path(char *oldpath, char *parent);
262static xfs_ino_t process_block_dir_v2(blkmap_t *blkmap, int *dot,
263 int *dotdot, inodata_t *id);
b9652a81 264static void process_bmbt_reclist(xfs_bmbt_rec_t *rp, int numrecs,
2bd0ea18 265 dbm_t type, inodata_t *id,
5a35bf2c 266 xfs_rfsblock_t *tot,
2bd0ea18
NS
267 blkmap_t **blkmapp);
268static void process_btinode(inodata_t *id, xfs_dinode_t *dip,
5a35bf2c
DC
269 dbm_t type, xfs_rfsblock_t *totd,
270 xfs_rfsblock_t *toti, xfs_extnum_t *nex,
2bd0ea18
NS
271 blkmap_t **blkmapp, int whichfork);
272static xfs_ino_t process_data_dir_v2(int *dot, int *dotdot,
273 inodata_t *id, int v,
274 xfs_dablk_t dabno,
275 freetab_t **freetabp);
eb0cb950
DC
276static xfs_dir2_data_free_t *process_data_dir_v2_freefind(
277 struct xfs_dir2_data_hdr *data,
278 struct xfs_dir2_data_unused *dup);
2bd0ea18
NS
279static void process_dir(xfs_dinode_t *dip, blkmap_t *blkmap,
280 inodata_t *id);
2bd0ea18
NS
281static int process_dir_v2(xfs_dinode_t *dip, blkmap_t *blkmap,
282 int *dot, int *dotdot, inodata_t *id,
283 xfs_ino_t *parent);
284static void process_exinode(inodata_t *id, xfs_dinode_t *dip,
5a35bf2c
DC
285 dbm_t type, xfs_rfsblock_t *totd,
286 xfs_rfsblock_t *toti, xfs_extnum_t *nex,
2bd0ea18
NS
287 blkmap_t **blkmapp, int whichfork);
288static void process_inode(xfs_agf_t *agf, xfs_agino_t agino,
289 xfs_dinode_t *dip, int isfree);
290static void process_lclinode(inodata_t *id, xfs_dinode_t *dip,
5a35bf2c
DC
291 dbm_t type, xfs_rfsblock_t *totd,
292 xfs_rfsblock_t *toti, xfs_extnum_t *nex,
2bd0ea18 293 blkmap_t **blkmapp, int whichfork);
2bd0ea18
NS
294static xfs_ino_t process_leaf_node_dir_v2(blkmap_t *blkmap, int *dot,
295 int *dotdot, inodata_t *id,
296 xfs_fsize_t dirsize);
297static void process_leaf_node_dir_v2_free(inodata_t *id, int v,
298 xfs_dablk_t dbno,
299 freetab_t *freetab);
300static void process_leaf_node_dir_v2_int(inodata_t *id, int v,
301 xfs_dablk_t dbno,
302 freetab_t *freetab);
9b27bdbb 303static void process_quota(qtype_t qtype, inodata_t *id,
2bd0ea18
NS
304 blkmap_t *blkmap);
305static void process_rtbitmap(blkmap_t *blkmap);
306static void process_rtsummary(blkmap_t *blkmap);
307static xfs_ino_t process_sf_dir_v2(xfs_dinode_t *dip, int *dot,
308 int *dotdot, inodata_t *id);
be8e601c 309static void quota_add(xfs_dqid_t *p, xfs_dqid_t *g, xfs_dqid_t *u,
2bd0ea18
NS
310 int dq, xfs_qcnt_t bc, xfs_qcnt_t ic,
311 xfs_qcnt_t rc);
312static void quota_add1(qdata_t **qt, xfs_dqid_t id, int dq,
313 xfs_qcnt_t bc, xfs_qcnt_t ic,
314 xfs_qcnt_t rc);
315static void quota_check(char *s, qdata_t **qt);
316static void quota_init(void);
317static void scan_ag(xfs_agnumber_t agno);
318static void scan_freelist(xfs_agf_t *agf);
319static void scan_lbtree(xfs_fsblock_t root, int nlevels,
320 scan_lbtree_f_t func, dbm_t type,
5a35bf2c
DC
321 inodata_t *id, xfs_rfsblock_t *totd,
322 xfs_rfsblock_t *toti, xfs_extnum_t *nex,
2bd0ea18
NS
323 blkmap_t **blkmapp, int isroot,
324 typnm_t btype);
325static void scan_sbtree(xfs_agf_t *agf, xfs_agblock_t root,
326 int nlevels, int isroot,
327 scan_sbtree_f_t func, typnm_t btype);
b3563c19
BN
328static void scanfunc_bmap(struct xfs_btree_block *block,
329 int level, dbm_t type, xfs_fsblock_t bno,
5a35bf2c
DC
330 inodata_t *id, xfs_rfsblock_t *totd,
331 xfs_rfsblock_t *toti, xfs_extnum_t *nex,
2bd0ea18
NS
332 blkmap_t **blkmapp, int isroot,
333 typnm_t btype);
b3563c19 334static void scanfunc_bno(struct xfs_btree_block *block, int level,
2bd0ea18
NS
335 xfs_agf_t *agf, xfs_agblock_t bno,
336 int isroot);
b3563c19 337static void scanfunc_cnt(struct xfs_btree_block *block, int level,
2bd0ea18
NS
338 xfs_agf_t *agf, xfs_agblock_t bno,
339 int isroot);
b3563c19 340static void scanfunc_ino(struct xfs_btree_block *block, int level,
2bd0ea18
NS
341 xfs_agf_t *agf, xfs_agblock_t bno,
342 int isroot);
e96864ff
DW
343static void scanfunc_fino(struct xfs_btree_block *block, int level,
344 struct xfs_agf *agf, xfs_agblock_t bno,
345 int isroot);
e3dcc17b
DW
346static void scanfunc_rmap(struct xfs_btree_block *block, int level,
347 struct xfs_agf *agf, xfs_agblock_t bno,
348 int isroot);
757ad8c7
DW
349static void scanfunc_refcnt(struct xfs_btree_block *block, int level,
350 struct xfs_agf *agf, xfs_agblock_t bno,
351 int isroot);
2bd0ea18
NS
352static void set_dbmap(xfs_agnumber_t agno, xfs_agblock_t agbno,
353 xfs_extlen_t len, dbm_t type,
354 xfs_agnumber_t c_agno, xfs_agblock_t c_agbno);
355static void set_inomap(xfs_agnumber_t agno, xfs_agblock_t agbno,
356 xfs_extlen_t len, inodata_t *id);
5a35bf2c 357static void set_rdbmap(xfs_rfsblock_t bno, xfs_extlen_t len,
2bd0ea18 358 dbm_t type);
5a35bf2c 359static void set_rinomap(xfs_rfsblock_t bno, xfs_extlen_t len,
2bd0ea18
NS
360 inodata_t *id);
361static void setlink_inode(inodata_t *id, nlink_t nlink, int isdir,
362 int security);
363
dfc130f3 364static const cmdinfo_t blockfree_cmd =
2bd0ea18 365 { "blockfree", NULL, blockfree_f, 0, 0, 0,
9ee7055c 366 NULL, N_("free block usage information"), NULL };
dfc130f3 367static const cmdinfo_t blockget_cmd =
2bd0ea18 368 { "blockget", "check", blockget_f, 0, -1, 0,
9ee7055c
AM
369 N_("[-s|-v] [-n] [-t] [-b bno]... [-i ino] ..."),
370 N_("get block usage and check consistency"), NULL };
dfc130f3 371static const cmdinfo_t blocktrash_cmd =
2bd0ea18 372 { "blocktrash", NULL, blocktrash_f, 0, -1, 0,
9ee7055c
AM
373 N_("[-n count] [-x minlen] [-y maxlen] [-s seed] [-0123] [-t type] ..."),
374 N_("trash randomly selected block(s)"), NULL };
dfc130f3 375static const cmdinfo_t blockuse_cmd =
2bd0ea18 376 { "blockuse", NULL, blockuse_f, 0, 3, 0,
9ee7055c
AM
377 N_("[-n] [-c blockcount]"),
378 N_("print usage for current block(s)"), NULL };
dfc130f3 379static const cmdinfo_t ncheck_cmd =
2bd0ea18 380 { "ncheck", NULL, ncheck_f, 0, -1, 0,
9ee7055c
AM
381 N_("[-s] [-i ino] ..."),
382 N_("print inode-name pairs"), NULL };
2bd0ea18
NS
383
384
385static void
386add_blist(
387 xfs_fsblock_t bno)
388{
389 blist_size++;
390 blist = xrealloc(blist, blist_size * sizeof(bno));
391 blist[blist_size - 1] = bno;
392}
393
394static void
395add_ilist(
396 xfs_ino_t ino)
397{
398 inodata_t *id;
399
400 id = find_inode(ino, 1);
401 if (id == NULL) {
9ee7055c 402 dbprintf(_("-i %lld bad inode number\n"), ino);
2bd0ea18
NS
403 return;
404 }
405 id->ilist = 1;
406}
407
408static void
409addlink_inode(
410 inodata_t *id)
411{
412 id->link_add++;
413 if (verbose || id->ilist)
9ee7055c 414 dbprintf(_("inode %lld add link, now %u\n"), id->ino,
2bd0ea18
NS
415 id->link_add);
416}
417
418static void
419addname_inode(
420 inodata_t *id,
421 char *name,
422 int namelen)
423{
424 if (!nflag || id->name)
425 return;
426 id->name = xmalloc(namelen + 1);
427 memcpy(id->name, name, namelen);
428 id->name[namelen] = '\0';
429}
430
dfc130f3 431static void
2bd0ea18
NS
432addparent_inode(
433 inodata_t *id,
434 xfs_ino_t parent)
435{
436 inodata_t *pid;
437
438 pid = find_inode(parent, 1);
439 id->parent = pid;
440 if (verbose || id->ilist || (pid && pid->ilist))
9ee7055c 441 dbprintf(_("inode %lld parent %lld\n"), id->ino, parent);
2bd0ea18
NS
442}
443
444static void
445blkent_append(
446 blkent_t **entp,
447 xfs_fsblock_t b,
448 xfs_extlen_t c)
449{
450 blkent_t *ent;
451 int i;
452
453 ent = *entp;
454 *entp = ent = xrealloc(ent, BLKENT_SIZE(c + ent->nblks));
455 for (i = 0; i < c; i++)
456 ent->blks[ent->nblks + i] = b + i;
457 ent->nblks += c;
458}
459
460static blkent_t *
461blkent_new(
462 xfs_fileoff_t o,
463 xfs_fsblock_t b,
464 xfs_extlen_t c)
465{
466 blkent_t *ent;
467 int i;
468
469 ent = xmalloc(BLKENT_SIZE(c));
470 ent->nblks = c;
471 ent->startoff = o;
472 for (i = 0; i < c; i++)
473 ent->blks[i] = b + i;
474 return ent;
475}
476
477static void
478blkent_prepend(
479 blkent_t **entp,
480 xfs_fsblock_t b,
481 xfs_extlen_t c)
482{
483 int i;
484 blkent_t *newent;
485 blkent_t *oldent;
486
487 oldent = *entp;
488 newent = xmalloc(BLKENT_SIZE(oldent->nblks + c));
489 newent->nblks = oldent->nblks + c;
490 newent->startoff = oldent->startoff - c;
491 for (i = 0; i < c; i++)
492 newent->blks[i] = b + c;
493 for (; i < oldent->nblks + c; i++)
494 newent->blks[i] = oldent->blks[i - c];
495 xfree(oldent);
496 *entp = newent;
497}
498
499static blkmap_t *
500blkmap_alloc(
501 xfs_extnum_t nex)
502{
503 blkmap_t *blkmap;
504
505 if (nex < 1)
506 nex = 1;
507 blkmap = xmalloc(BLKMAP_SIZE(nex));
508 blkmap->naents = nex;
509 blkmap->nents = 0;
510 return blkmap;
511}
512
513static void
514blkmap_free(
515 blkmap_t *blkmap)
516{
517 blkent_t **entp;
518 xfs_extnum_t i;
519
520 for (i = 0, entp = blkmap->ents; i < blkmap->nents; i++, entp++)
521 xfree(*entp);
522 xfree(blkmap);
523}
524
525static xfs_fsblock_t
526blkmap_get(
527 blkmap_t *blkmap,
528 xfs_fileoff_t o)
529{
530 blkent_t *ent;
531 blkent_t **entp;
532 int i;
533
534 for (i = 0, entp = blkmap->ents; i < blkmap->nents; i++, entp++) {
535 ent = *entp;
536 if (o >= ent->startoff && o < ent->startoff + ent->nblks)
537 return ent->blks[o - ent->startoff];
538 }
539 return NULLFSBLOCK;
540}
541
542static int
543blkmap_getn(
544 blkmap_t *blkmap,
545 xfs_fileoff_t o,
546 int nb,
547 bmap_ext_t **bmpp)
548{
549 bmap_ext_t *bmp;
550 blkent_t *ent;
551 xfs_fileoff_t ento;
552 blkent_t **entp;
553 int i;
554 int nex;
555
556 for (i = nex = 0, bmp = NULL, entp = blkmap->ents;
557 i < blkmap->nents;
558 i++, entp++) {
559 ent = *entp;
560 if (ent->startoff >= o + nb)
561 break;
562 if (ent->startoff + ent->nblks <= o)
563 continue;
564 for (ento = ent->startoff;
565 ento < ent->startoff + ent->nblks && ento < o + nb;
566 ento++) {
567 if (ento < o)
568 continue;
569 if (bmp &&
570 bmp[nex - 1].startoff + bmp[nex - 1].blockcount ==
571 ento &&
572 bmp[nex - 1].startblock + bmp[nex - 1].blockcount ==
573 ent->blks[ento - ent->startoff])
574 bmp[nex - 1].blockcount++;
575 else {
576 bmp = realloc(bmp, ++nex * sizeof(*bmp));
577 bmp[nex - 1].startoff = ento;
578 bmp[nex - 1].startblock =
579 ent->blks[ento - ent->startoff];
580 bmp[nex - 1].blockcount = 1;
581 bmp[nex - 1].flag = 0;
582 }
583 }
584 }
585 *bmpp = bmp;
586 return nex;
587}
588
589static void
590blkmap_grow(
591 blkmap_t **blkmapp,
592 blkent_t **entp,
593 blkent_t *newent)
594{
595 blkmap_t *blkmap;
596 int i;
597 int idx;
598
599 blkmap = *blkmapp;
600 idx = (int)(entp - blkmap->ents);
601 if (blkmap->naents == blkmap->nents) {
602 blkmap = xrealloc(blkmap, BLKMAP_SIZE(blkmap->nents + 1));
603 *blkmapp = blkmap;
604 blkmap->naents++;
605 }
606 for (i = blkmap->nents; i > idx; i--)
607 blkmap->ents[i] = blkmap->ents[i - 1];
608 blkmap->ents[idx] = newent;
609 blkmap->nents++;
610}
611
612static xfs_fileoff_t
613blkmap_last_off(
614 blkmap_t *blkmap)
615{
616 blkent_t *ent;
617
618 if (!blkmap->nents)
619 return NULLFILEOFF;
620 ent = blkmap->ents[blkmap->nents - 1];
621 return ent->startoff + ent->nblks;
622}
623
624static xfs_fileoff_t
625blkmap_next_off(
626 blkmap_t *blkmap,
627 xfs_fileoff_t o,
628 int *t)
629{
630 blkent_t *ent;
631 blkent_t **entp;
632
633 if (!blkmap->nents)
634 return NULLFILEOFF;
635 if (o == NULLFILEOFF) {
636 *t = 0;
637 ent = blkmap->ents[0];
638 return ent->startoff;
639 }
640 entp = &blkmap->ents[*t];
641 ent = *entp;
642 if (o < ent->startoff + ent->nblks - 1)
643 return o + 1;
644 entp++;
645 if (entp >= &blkmap->ents[blkmap->nents])
646 return NULLFILEOFF;
647 (*t)++;
648 ent = *entp;
649 return ent->startoff;
650}
651
652static void
653blkmap_set_blk(
654 blkmap_t **blkmapp,
655 xfs_fileoff_t o,
656 xfs_fsblock_t b)
657{
658 blkmap_t *blkmap;
659 blkent_t *ent;
660 blkent_t **entp;
661 blkent_t *nextent;
662
663 blkmap = *blkmapp;
664 for (entp = blkmap->ents; entp < &blkmap->ents[blkmap->nents]; entp++) {
665 ent = *entp;
666 if (o < ent->startoff - 1) {
667 ent = blkent_new(o, b, 1);
668 blkmap_grow(blkmapp, entp, ent);
669 return;
670 }
671 if (o == ent->startoff - 1) {
672 blkent_prepend(entp, b, 1);
673 return;
674 }
675 if (o >= ent->startoff && o < ent->startoff + ent->nblks) {
676 ent->blks[o - ent->startoff] = b;
677 return;
678 }
679 if (o > ent->startoff + ent->nblks)
680 continue;
681 blkent_append(entp, b, 1);
682 if (entp == &blkmap->ents[blkmap->nents - 1])
683 return;
684 ent = *entp;
685 nextent = entp[1];
686 if (ent->startoff + ent->nblks < nextent->startoff)
687 return;
688 blkent_append(entp, nextent->blks[0], nextent->nblks);
689 blkmap_shrink(blkmap, &entp[1]);
690 return;
691 }
692 ent = blkent_new(o, b, 1);
693 blkmap_grow(blkmapp, entp, ent);
694}
695
696static void
697blkmap_set_ext(
698 blkmap_t **blkmapp,
699 xfs_fileoff_t o,
700 xfs_fsblock_t b,
701 xfs_extlen_t c)
702{
703 blkmap_t *blkmap;
704 blkent_t *ent;
705 blkent_t **entp;
706 xfs_extnum_t i;
707
708 blkmap = *blkmapp;
709 if (!blkmap->nents) {
710 blkmap->ents[0] = blkent_new(o, b, c);
711 blkmap->nents = 1;
712 return;
713 }
714 entp = &blkmap->ents[blkmap->nents - 1];
715 ent = *entp;
716 if (ent->startoff + ent->nblks == o) {
717 blkent_append(entp, b, c);
718 return;
719 }
720 if (ent->startoff + ent->nblks < o) {
721 ent = blkent_new(o, b, c);
722 blkmap_grow(blkmapp, &blkmap->ents[blkmap->nents], ent);
723 return;
724 }
725 for (i = 0; i < c; i++)
726 blkmap_set_blk(blkmapp, o + i, b + i);
727}
728
729static void
730blkmap_shrink(
731 blkmap_t *blkmap,
732 blkent_t **entp)
733{
734 int i;
735 int idx;
736
737 xfree(*entp);
738 idx = (int)(entp - blkmap->ents);
739 for (i = idx + 1; i < blkmap->nents; i++)
740 blkmap->ents[i] = blkmap->ents[i - 1];
741 blkmap->nents--;
742}
743
744/* ARGSUSED */
745static int
746blockfree_f(
747 int argc,
748 char **argv)
749{
750 xfs_agnumber_t c;
751 int rt;
752
753 if (!dbmap) {
9ee7055c 754 dbprintf(_("block usage information not allocated\n"));
2bd0ea18
NS
755 return 0;
756 }
757 rt = mp->m_sb.sb_rextents != 0;
758 for (c = 0; c < mp->m_sb.sb_agcount; c++) {
759 xfree(dbmap[c]);
760 xfree(inomap[c]);
761 free_inodata(c);
762 }
763 if (rt) {
764 xfree(dbmap[c]);
765 xfree(inomap[c]);
766 xfree(sumcompute);
767 xfree(sumfile);
768 sumcompute = sumfile = NULL;
769 }
770 xfree(dbmap);
771 xfree(inomap);
772 xfree(inodata);
773 dbmap = NULL;
774 inomap = NULL;
775 inodata = NULL;
776 return 0;
777}
778
779/*
780 * Check consistency of xfs filesystem contents.
781 */
782static int
783blockget_f(
784 int argc,
785 char **argv)
786{
787 xfs_agnumber_t agno;
788 int oldprefix;
789 int sbyell;
790
791 if (dbmap) {
9ee7055c 792 dbprintf(_("already have block usage information\n"));
2bd0ea18
NS
793 return 0;
794 }
0e3105ad 795
f891d8c4
MS
796 if (!init(argc, argv)) {
797 if (serious_error)
798 exitcode = 3;
799 else
800 exitcode = 1;
2bd0ea18 801 return 0;
f891d8c4 802 }
2bd0ea18
NS
803 oldprefix = dbprefix;
804 dbprefix |= pflag;
805 for (agno = 0, sbyell = 0; agno < mp->m_sb.sb_agcount; agno++) {
806 scan_ag(agno);
807 if (sbver_err > 4 && !sbyell && sbver_err >= agno) {
808 sbyell = 1;
9ee7055c
AM
809 dbprintf(_("WARNING: this may be a newer XFS "
810 "filesystem.\n"));
2bd0ea18
NS
811 }
812 }
813 if (blist_size) {
814 xfree(blist);
815 blist = NULL;
816 blist_size = 0;
817 }
818 if (serious_error) {
819 exitcode = 2;
820 dbprefix = oldprefix;
821 return 0;
822 }
823 check_rootdir();
32a82561
NS
824 /*
825 * Check that there are no blocks either
826 * a) unaccounted for or
827 * b) bno-free but not cnt-free
828 */
829 if (!tflag) { /* are we in test mode, faking out freespace? */
830 for (agno = 0; agno < mp->m_sb.sb_agcount; agno++)
831 checknot_dbmap(agno, 0, mp->m_sb.sb_agblocks,
832 (1 << DBM_UNKNOWN) | (1 << DBM_FREE1));
833 }
834 for (agno = 0; agno < mp->m_sb.sb_agcount; agno++)
2bd0ea18 835 check_linkcounts(agno);
2bd0ea18
NS
836 if (mp->m_sb.sb_rblocks) {
837 checknot_rdbmap(0,
838 (xfs_extlen_t)(mp->m_sb.sb_rextents *
839 mp->m_sb.sb_rextsize),
840 1 << DBM_UNKNOWN);
841 check_summary();
842 }
843 if (mp->m_sb.sb_icount != icount) {
844 if (!sflag)
9ee7055c 845 dbprintf(_("sb_icount %lld, counted %lld\n"),
2bd0ea18
NS
846 mp->m_sb.sb_icount, icount);
847 error++;
848 }
849 if (mp->m_sb.sb_ifree != ifree) {
850 if (!sflag)
9ee7055c 851 dbprintf(_("sb_ifree %lld, counted %lld\n"),
2bd0ea18
NS
852 mp->m_sb.sb_ifree, ifree);
853 error++;
854 }
855 if (mp->m_sb.sb_fdblocks != fdblocks) {
856 if (!sflag)
9ee7055c 857 dbprintf(_("sb_fdblocks %lld, counted %lld\n"),
2bd0ea18
NS
858 mp->m_sb.sb_fdblocks, fdblocks);
859 error++;
860 }
cdded3d8
DC
861 if (lazycount && mp->m_sb.sb_fdblocks != agf_aggr_freeblks) {
862 if (!sflag)
9ee7055c 863 dbprintf(_("sb_fdblocks %lld, aggregate AGF count %lld\n"),
cdded3d8
DC
864 mp->m_sb.sb_fdblocks, agf_aggr_freeblks);
865 error++;
866 }
2bd0ea18
NS
867 if (mp->m_sb.sb_frextents != frextents) {
868 if (!sflag)
9ee7055c 869 dbprintf(_("sb_frextents %lld, counted %lld\n"),
2bd0ea18
NS
870 mp->m_sb.sb_frextents, frextents);
871 error++;
872 }
45935737
BN
873 if (mp->m_sb.sb_bad_features2 != 0 &&
874 mp->m_sb.sb_bad_features2 != mp->m_sb.sb_features2) {
875 if (!sflag)
9ee7055c
AM
876 dbprintf(_("sb_features2 (0x%x) not same as "
877 "sb_bad_features2 (0x%x)\n"),
45935737
BN
878 mp->m_sb.sb_features2,
879 mp->m_sb.sb_bad_features2);
880 error++;
881 }
2bd0ea18 882 if ((sbversion & XFS_SB_VERSION_ATTRBIT) &&
5e656dbb 883 !xfs_sb_version_hasattr(&mp->m_sb)) {
2bd0ea18 884 if (!sflag)
9ee7055c 885 dbprintf(_("sb versionnum missing attr bit %x\n"),
2bd0ea18
NS
886 XFS_SB_VERSION_ATTRBIT);
887 error++;
888 }
2bd0ea18 889 if ((sbversion & XFS_SB_VERSION_QUOTABIT) &&
5e656dbb 890 !xfs_sb_version_hasquota(&mp->m_sb)) {
2bd0ea18 891 if (!sflag)
9ee7055c 892 dbprintf(_("sb versionnum missing quota bit %x\n"),
2bd0ea18
NS
893 XFS_SB_VERSION_QUOTABIT);
894 error++;
895 }
896 if (!(sbversion & XFS_SB_VERSION_ALIGNBIT) &&
5e656dbb 897 xfs_sb_version_hasalign(&mp->m_sb)) {
2bd0ea18 898 if (!sflag)
9ee7055c 899 dbprintf(_("sb versionnum extra align bit %x\n"),
2bd0ea18
NS
900 XFS_SB_VERSION_ALIGNBIT);
901 error++;
902 }
903 if (qudo)
904 quota_check("user", qudata);
9b27bdbb
NS
905 if (qpdo)
906 quota_check("project", qpdata);
b36eef04
NS
907 if (qgdo)
908 quota_check("group", qgdata);
2bd0ea18 909 if (sbver_err > mp->m_sb.sb_agcount / 2)
9ee7055c 910 dbprintf(_("WARNING: this may be a newer XFS filesystem.\n"));
2bd0ea18
NS
911 if (error)
912 exitcode = 3;
913 dbprefix = oldprefix;
914 return 0;
915}
916
2bd0ea18
NS
917typedef struct ltab {
918 int min;
919 int max;
920} ltab_t;
921
922static void
923blocktrash_b(
37faa0da 924 int bit_offset,
2bd0ea18
NS
925 dbm_t type,
926 ltab_t *ltabp,
927 int mode)
928{
929 int bit;
930 int bitno;
931 char *buf;
932 int byte;
933 int len;
934 int mask;
935 int newbit;
bdc2a208 936 const struct xfs_buf_ops *stashed_ops;
2bd0ea18 937 static char *modestr[] = {
9ee7055c 938 N_("zeroed"), N_("set"), N_("flipped"), N_("randomized")
2bd0ea18 939 };
37faa0da
DW
940 xfs_agnumber_t agno;
941 xfs_agblock_t agbno;
2bd0ea18 942
37faa0da
DW
943 agno = XFS_FSB_TO_AGNO(mp, XFS_DADDR_TO_FSB(mp, iocur_top->bb));
944 agbno = XFS_FSB_TO_AGBNO(mp, XFS_DADDR_TO_FSB(mp, iocur_top->bb));
945 if (iocur_top->len == 0) {
946 dbprintf(_("zero-length block %u/%u buffer to trash??\n"),
947 agno, agbno);
948 return;
949 }
2bd0ea18 950 len = (int)((random() % (ltabp->max - ltabp->min + 1)) + ltabp->min);
37faa0da
DW
951 /*
952 * bit_offset >= 0: start fuzzing at this exact bit_offset.
953 * bit_offset < 0: pick an offset at least as high at -(bit_offset + 1).
954 */
955 if (bit_offset < 0) {
956 bit_offset = -(bit_offset + 1);
957 bit_offset += (int)(random() % (int)((iocur_top->len - bit_offset) * NBBY));
958 }
959 if (bit_offset + len >= iocur_top->len * NBBY)
960 len = (iocur_top->len * NBBY) - bit_offset;
2bd0ea18 961 newbit = 0;
bdc2a208
DW
962 stashed_ops = iocur_top->bp->b_ops;
963 iocur_top->bp->b_ops = NULL;
2bd0ea18 964 if ((buf = iocur_top->data) == NULL) {
9ee7055c 965 dbprintf(_("can't read block %u/%u for trashing\n"), agno, agbno);
2bd0ea18
NS
966 return;
967 }
968 for (bitno = 0; bitno < len; bitno++) {
37faa0da 969 bit = (bit_offset + bitno) % (mp->m_sb.sb_blocksize * NBBY);
2bd0ea18
NS
970 byte = bit / NBBY;
971 bit %= NBBY;
972 mask = 1 << bit;
973 switch (mode) {
974 case 0:
975 newbit = 0;
976 break;
977 case 1:
978 newbit = 1;
979 break;
980 case 2:
981 newbit = (buf[byte] & mask) == 0;
982 break;
983 case 3:
984 newbit = (int)random() & 1;
985 break;
986 }
987 if (newbit)
988 buf[byte] |= mask;
989 else
990 buf[byte] &= ~mask;
991 }
992 write_cur();
bdc2a208 993 iocur_top->bp->b_ops = stashed_ops;
9ee7055c 994 printf(_("blocktrash: %u/%u %s block %d bit%s starting %d:%d %s\n"),
2bd0ea18 995 agno, agbno, typename[type], len, len == 1 ? "" : "s",
37faa0da 996 bit_offset / NBBY, bit_offset % NBBY, modestr[mode]);
2bd0ea18
NS
997}
998
999int
1000blocktrash_f(
1001 int argc,
1002 char **argv)
1003{
1004 xfs_agblock_t agbno;
1005 xfs_agnumber_t agno;
5a35bf2c
DC
1006 xfs_rfsblock_t bi;
1007 xfs_rfsblock_t blocks;
2bd0ea18
NS
1008 int c;
1009 int count;
1010 int done;
1011 int goodmask;
1012 int i;
1013 ltab_t *lentab;
1014 int lentablen;
1015 int max;
1016 int min;
1017 int mode;
1018 struct timeval now;
1019 char *p;
5a35bf2c 1020 xfs_rfsblock_t randb;
2bd0ea18
NS
1021 uint seed;
1022 int sopt;
1023 int tmask;
37faa0da
DW
1024 bool this_block = false;
1025 int bit_offset = -1;
2bd0ea18 1026
2bd0ea18
NS
1027 optind = 0;
1028 count = 1;
1029 min = 1;
1030 max = 128 * NBBY;
1031 mode = 2;
1032 gettimeofday(&now, NULL);
1033 seed = (unsigned int)(now.tv_sec ^ now.tv_usec);
1034 sopt = 0;
1035 tmask = 0;
1036 goodmask = (1 << DBM_AGF) |
1037 (1 << DBM_AGFL) |
1038 (1 << DBM_AGI) |
1039 (1 << DBM_ATTR) |
1040 (1 << DBM_BTBMAPA) |
1041 (1 << DBM_BTBMAPD) |
1042 (1 << DBM_BTBNO) |
1043 (1 << DBM_BTCNT) |
1044 (1 << DBM_BTINO) |
1045 (1 << DBM_DIR) |
1046 (1 << DBM_INODE) |
bdc2a208 1047 (1 << DBM_LOG) |
2bd0ea18
NS
1048 (1 << DBM_QUOTA) |
1049 (1 << DBM_RTBITMAP) |
1050 (1 << DBM_RTSUM) |
bdc2a208 1051 (1 << DBM_SYMLINK) |
e96864ff 1052 (1 << DBM_BTFINO) |
e3dcc17b 1053 (1 << DBM_BTRMAP) |
757ad8c7 1054 (1 << DBM_BTREFC) |
2bd0ea18 1055 (1 << DBM_SB);
37faa0da 1056 while ((c = getopt(argc, argv, "0123n:o:s:t:x:y:z")) != EOF) {
2bd0ea18
NS
1057 switch (c) {
1058 case '0':
1059 mode = 0;
1060 break;
1061 case '1':
1062 mode = 1;
1063 break;
1064 case '2':
1065 mode = 2;
1066 break;
1067 case '3':
1068 mode = 3;
1069 break;
1070 case 'n':
1071 count = (int)strtol(optarg, &p, 0);
1072 if (*p != '\0' || count <= 0) {
9ee7055c 1073 dbprintf(_("bad blocktrash count %s\n"), optarg);
2bd0ea18
NS
1074 return 0;
1075 }
1076 break;
37faa0da
DW
1077 case 'o': {
1078 int relative = 0;
1079 if (optarg[0] == '+') {
1080 optarg++;
1081 relative = 1;
1082 }
1083 bit_offset = (int)strtol(optarg, &p, 0);
1084 if (*p != '\0' || bit_offset < 0) {
1085 dbprintf(_("bad blocktrash offset %s\n"), optarg);
1086 return 0;
1087 }
1088 if (relative)
1089 bit_offset = -bit_offset - 1;
1090 break;
1091 }
2bd0ea18
NS
1092 case 's':
1093 seed = (uint)strtoul(optarg, &p, 0);
1094 sopt = 1;
1095 break;
1096 case 't':
1097 for (i = 0; typename[i]; i++) {
1098 if (strcmp(typename[i], optarg) == 0)
1099 break;
1100 }
1101 if (!typename[i] || (((1 << i) & goodmask) == 0)) {
9ee7055c 1102 dbprintf(_("bad blocktrash type %s\n"), optarg);
2bd0ea18
NS
1103 return 0;
1104 }
1105 tmask |= 1 << i;
1106 break;
1107 case 'x':
1108 min = (int)strtol(optarg, &p, 0);
1109 if (*p != '\0' || min <= 0 ||
1110 min > mp->m_sb.sb_blocksize * NBBY) {
9ee7055c 1111 dbprintf(_("bad blocktrash min %s\n"), optarg);
2bd0ea18
NS
1112 return 0;
1113 }
1114 break;
1115 case 'y':
1116 max = (int)strtol(optarg, &p, 0);
1117 if (*p != '\0' || max <= 0 ||
1118 max > mp->m_sb.sb_blocksize * NBBY) {
9ee7055c 1119 dbprintf(_("bad blocktrash max %s\n"), optarg);
2bd0ea18
NS
1120 return 0;
1121 }
1122 break;
37faa0da
DW
1123 case 'z':
1124 this_block = true;
1125 break;
2bd0ea18 1126 default:
9ee7055c 1127 dbprintf(_("bad option for blocktrash command\n"));
2bd0ea18
NS
1128 return 0;
1129 }
1130 }
37faa0da
DW
1131 if (!this_block && !dbmap) {
1132 dbprintf(_("must run blockget first\n"));
1133 return 0;
1134 }
1135 if (this_block && iocur_sp == 0) {
1136 dbprintf(_("nothing on stack\n"));
1137 return 0;
1138 }
2bd0ea18 1139 if (min > max) {
9ee7055c 1140 dbprintf(_("bad min/max for blocktrash command\n"));
2bd0ea18
NS
1141 return 0;
1142 }
1143 if (tmask == 0)
bdc2a208 1144 tmask = goodmask & ~((1 << DBM_LOG) | (1 << DBM_SB));
2bd0ea18
NS
1145 lentab = xmalloc(sizeof(ltab_t));
1146 lentab->min = lentab->max = min;
1147 lentablen = 1;
1148 for (i = min + 1; i <= max; i++) {
1149 if ((i & (i - 1)) == 0) {
1150 lentab = xrealloc(lentab,
1151 sizeof(ltab_t) * (lentablen + 1));
1152 lentab[lentablen].min = lentab[lentablen].max = i;
1153 lentablen++;
1154 } else
1155 lentab[lentablen - 1].max = i;
1156 }
37faa0da
DW
1157 if (!sopt)
1158 dbprintf(_("blocktrash: seed %u\n"), seed);
1159 srandom(seed);
1160 if (this_block) {
1161 blocktrash_b(bit_offset, DBM_UNKNOWN,
1162 &lentab[random() % lentablen], mode);
1163 goto out;
1164 }
2bd0ea18
NS
1165 for (blocks = 0, agno = 0; agno < mp->m_sb.sb_agcount; agno++) {
1166 for (agbno = 0, p = dbmap[agno];
1167 agbno < mp->m_sb.sb_agblocks;
1168 agbno++, p++) {
1169 if ((1 << *p) & tmask)
1170 blocks++;
1171 }
1172 }
1173 if (blocks == 0) {
9ee7055c 1174 dbprintf(_("blocktrash: no matching blocks\n"));
355ac015 1175 goto out;
2bd0ea18 1176 }
2bd0ea18 1177 for (i = 0; i < count; i++) {
14f8b681 1178 randb = (xfs_rfsblock_t)((((int64_t)random() << 32) |
2bd0ea18
NS
1179 random()) % blocks);
1180 for (bi = 0, agno = 0, done = 0;
1181 !done && agno < mp->m_sb.sb_agcount;
1182 agno++) {
1183 for (agbno = 0, p = dbmap[agno];
1184 agbno < mp->m_sb.sb_agblocks;
1185 agbno++, p++) {
1186 if (!((1 << *p) & tmask))
1187 continue;
1188 if (bi++ < randb)
1189 continue;
37faa0da
DW
1190 push_cur();
1191 set_cur(NULL,
1192 XFS_AGB_TO_DADDR(mp, agno, agbno),
1193 blkbb, DB_RING_IGN, NULL);
1194 blocktrash_b(bit_offset, (dbm_t)*p,
2bd0ea18 1195 &lentab[random() % lentablen], mode);
37faa0da 1196 pop_cur();
2bd0ea18
NS
1197 done = 1;
1198 break;
1199 }
1200 }
1201 }
355ac015 1202out:
2bd0ea18
NS
1203 xfree(lentab);
1204 return 0;
1205}
2bd0ea18
NS
1206
1207int
1208blockuse_f(
1209 int argc,
1210 char **argv)
1211{
1212 xfs_agblock_t agbno;
1213 xfs_agnumber_t agno;
1214 int c;
1215 int count;
1216 xfs_agblock_t end;
1217 xfs_fsblock_t fsb;
1218 inodata_t *i;
1219 char *p;
1220 int shownames;
1221
1222 if (!dbmap) {
9ee7055c 1223 dbprintf(_("must run blockget first\n"));
2bd0ea18
NS
1224 return 0;
1225 }
1226 optind = 0;
2bd0ea18
NS
1227 shownames = 0;
1228 fsb = XFS_DADDR_TO_FSB(mp, iocur_top->off >> BBSHIFT);
1229 agno = XFS_FSB_TO_AGNO(mp, fsb);
1230 end = agbno = XFS_FSB_TO_AGBNO(mp, fsb);
1231 while ((c = getopt(argc, argv, "c:n")) != EOF) {
1232 switch (c) {
1233 case 'c':
1234 count = (int)strtol(optarg, &p, 0);
1235 end = agbno + count - 1;
1236 if (*p != '\0' || count <= 0 ||
1237 end >= mp->m_sb.sb_agblocks) {
9ee7055c 1238 dbprintf(_("bad blockuse count %s\n"), optarg);
2bd0ea18
NS
1239 return 0;
1240 }
1241 break;
1242 case 'n':
1243 if (!nflag) {
9ee7055c 1244 dbprintf(_("must run blockget -n first\n"));
2bd0ea18
NS
1245 return 0;
1246 }
1247 shownames = 1;
1248 break;
1249 default:
9ee7055c 1250 dbprintf(_("bad option for blockuse command\n"));
2bd0ea18
NS
1251 return 0;
1252 }
1253 }
1254 while (agbno <= end) {
1255 p = &dbmap[agno][agbno];
1256 i = inomap[agno][agbno];
9ee7055c 1257 dbprintf(_("block %llu (%u/%u) type %s"),
5a35bf2c 1258 (xfs_fsblock_t)XFS_AGB_TO_FSB(mp, agno, agbno),
2bd0ea18
NS
1259 agno, agbno, typename[(dbm_t)*p]);
1260 if (i) {
9ee7055c 1261 dbprintf(_(" inode %lld"), i->ino);
2bd0ea18
NS
1262 if (shownames && (p = inode_name(i->ino, NULL))) {
1263 dbprintf(" %s", p);
1264 xfree(p);
1265 }
1266 }
1267 dbprintf("\n");
1268 agbno++;
1269 }
1270 return 0;
1271}
1272
1273static int
1274check_blist(
1275 xfs_fsblock_t bno)
1276{
1277 int i;
1278
1279 for (i = 0; i < blist_size; i++) {
1280 if (blist[i] == bno)
1281 return 1;
1282 }
1283 return 0;
1284}
1285
1286static void
1287check_dbmap(
1288 xfs_agnumber_t agno,
1289 xfs_agblock_t agbno,
1290 xfs_extlen_t len,
757ad8c7
DW
1291 dbm_t type,
1292 int ignore_reflink)
2bd0ea18
NS
1293{
1294 xfs_extlen_t i;
1295 char *p;
757ad8c7 1296 dbm_t d;
2bd0ea18
NS
1297
1298 for (i = 0, p = &dbmap[agno][agbno]; i < len; i++, p++) {
757ad8c7
DW
1299 d = (dbm_t)*p;
1300 if (ignore_reflink && (d == DBM_UNKNOWN || d == DBM_DATA ||
1301 d == DBM_RLDATA))
1302 continue;
2bd0ea18 1303 if ((dbm_t)*p != type) {
757ad8c7 1304 if (!sflag || CHECK_BLISTA(agno, agbno + i)) {
9ee7055c
AM
1305 dbprintf(_("block %u/%u expected type %s got "
1306 "%s\n"),
2bd0ea18
NS
1307 agno, agbno + i, typename[type],
1308 typename[(dbm_t)*p]);
757ad8c7 1309 }
2bd0ea18
NS
1310 error++;
1311 }
1312 }
1313}
1314
1315void
1316check_init(void)
1317{
1318 add_command(&blockfree_cmd);
1319 add_command(&blockget_cmd);
ef37a4bf
NS
1320 if (expert_mode)
1321 add_command(&blocktrash_cmd);
2bd0ea18
NS
1322 add_command(&blockuse_cmd);
1323 add_command(&ncheck_cmd);
1324}
1325
1326static int
1327check_inomap(
1328 xfs_agnumber_t agno,
1329 xfs_agblock_t agbno,
1330 xfs_extlen_t len,
1331 xfs_ino_t c_ino)
1332{
1333 xfs_extlen_t i;
1334 inodata_t **idp;
1335 int rval;
1336
1337 if (!check_range(agno, agbno, len)) {
9ee7055c 1338 dbprintf(_("blocks %u/%u..%u claimed by inode %lld\n"),
2bd0ea18
NS
1339 agno, agbno, agbno + len - 1, c_ino);
1340 return 0;
1341 }
1342 for (i = 0, rval = 1, idp = &inomap[agno][agbno]; i < len; i++, idp++) {
757ad8c7 1343 if (*idp && !(*idp)->isreflink) {
2bd0ea18
NS
1344 if (!sflag || (*idp)->ilist ||
1345 CHECK_BLISTA(agno, agbno + i))
9ee7055c
AM
1346 dbprintf(_("block %u/%u claimed by inode %lld, "
1347 "previous inum %lld\n"),
2bd0ea18
NS
1348 agno, agbno + i, c_ino, (*idp)->ino);
1349 error++;
1350 rval = 0;
1351 }
1352 }
1353 return rval;
1354}
1355
1356static void
1357check_linkcounts(
1358 xfs_agnumber_t agno)
1359{
1360 inodata_t *ep;
1361 inodata_t **ht;
1362 int idx;
1363 char *path;
1364
1365 ht = inodata[agno];
1366 for (idx = 0; idx < inodata_hash_size; ht++, idx++) {
1367 ep = *ht;
1368 while (ep) {
1369 if (ep->link_set != ep->link_add || ep->link_set == 0) {
1370 path = inode_name(ep->ino, NULL);
1371 if (!path && ep->link_add)
1372 path = xstrdup("?");
1373 if (!sflag || ep->ilist) {
1374 if (ep->link_add)
9ee7055c 1375 dbprintf(_("link count mismatch "
2bd0ea18
NS
1376 "for inode %lld (name "
1377 "%s), nlink %d, "
9ee7055c 1378 "counted %d\n"),
2bd0ea18
NS
1379 ep->ino, path,
1380 ep->link_set,
1381 ep->link_add);
1382 else if (ep->link_set)
9ee7055c
AM
1383 dbprintf(_("disconnected inode "
1384 "%lld, nlink %d\n"),
2bd0ea18
NS
1385 ep->ino, ep->link_set);
1386 else
9ee7055c
AM
1387 dbprintf(_("allocated inode %lld "
1388 "has 0 link count\n"),
2bd0ea18
NS
1389 ep->ino);
1390 }
1391 if (path)
1392 xfree(path);
1393 error++;
1394 } else if (verbose || ep->ilist) {
1395 path = inode_name(ep->ino, NULL);
1396 if (path) {
9ee7055c 1397 dbprintf(_("inode %lld name %s\n"),
2bd0ea18
NS
1398 ep->ino, path);
1399 xfree(path);
1400 }
1401 }
1402 ep = ep->next;
1403 }
1404 }
dfc130f3 1405
2bd0ea18
NS
1406}
1407
1408static int
1409check_range(
9806e8ca
RH
1410 xfs_agnumber_t agno,
1411 xfs_agblock_t agbno,
1412 xfs_extlen_t len)
2bd0ea18 1413{
9806e8ca
RH
1414 xfs_extlen_t i;
1415 xfs_agblock_t low = 0;
1416 xfs_agblock_t high = 0;
1417 int valid_range = 0;
1418 int cur, prev = 0;
2bd0ea18
NS
1419
1420 if (agno >= mp->m_sb.sb_agcount ||
1421 agbno + len - 1 >= mp->m_sb.sb_agblocks) {
1422 for (i = 0; i < len; i++) {
9806e8ca
RH
1423 cur = !sflag || CHECK_BLISTA(agno, agbno + i) ? 1 : 0;
1424 if (cur == 1 && prev == 0) {
1425 low = high = agbno + i;
1426 valid_range = 1;
1427 } else if (cur == 0 && prev == 0) {
1428 /* Do nothing */
1429 } else if (cur == 0 && prev == 1) {
1430 if (low == high) {
9ee7055c 1431 dbprintf(_("block %u/%u out of range\n"),
9806e8ca
RH
1432 agno, low);
1433 } else {
9ee7055c
AM
1434 dbprintf(_("blocks %u/%u..%u "
1435 "out of range\n"),
9806e8ca
RH
1436 agno, low, high);
1437 }
1438 valid_range = 0;
1439 } else if (cur == 1 && prev == 1) {
1440 high = agbno + i;
1441 }
1442 prev = cur;
1443 }
1444 if (valid_range) {
1445 if (low == high) {
9ee7055c 1446 dbprintf(_("block %u/%u out of range\n"),
9806e8ca
RH
1447 agno, low);
1448 } else {
9ee7055c
AM
1449 dbprintf(_("blocks %u/%u..%u "
1450 "out of range\n"),
9806e8ca
RH
1451 agno, low, high);
1452 }
2bd0ea18
NS
1453 }
1454 error++;
1455 return 0;
1456 }
1457 return 1;
1458}
1459
1460static void
1461check_rdbmap(
5a35bf2c 1462 xfs_rfsblock_t bno,
2bd0ea18
NS
1463 xfs_extlen_t len,
1464 dbm_t type)
1465{
1466 xfs_extlen_t i;
1467 char *p;
1468
1469 for (i = 0, p = &dbmap[mp->m_sb.sb_agcount][bno]; i < len; i++, p++) {
1470 if ((dbm_t)*p != type) {
1471 if (!sflag || CHECK_BLIST(bno + i))
9ee7055c
AM
1472 dbprintf(_("rtblock %llu expected type %s got "
1473 "%s\n"),
2bd0ea18
NS
1474 bno + i, typename[type],
1475 typename[(dbm_t)*p]);
1476 error++;
1477 }
1478 }
1479}
1480
1481static int
1482check_rinomap(
5a35bf2c 1483 xfs_rfsblock_t bno,
2bd0ea18
NS
1484 xfs_extlen_t len,
1485 xfs_ino_t c_ino)
1486{
1487 xfs_extlen_t i;
1488 inodata_t **idp;
1489 int rval;
1490
1491 if (!check_rrange(bno, len)) {
9ee7055c 1492 dbprintf(_("rtblocks %llu..%llu claimed by inode %lld\n"),
2bd0ea18
NS
1493 bno, bno + len - 1, c_ino);
1494 return 0;
1495 }
1496 for (i = 0, rval = 1, idp = &inomap[mp->m_sb.sb_agcount][bno];
1497 i < len;
1498 i++, idp++) {
1499 if (*idp) {
1500 if (!sflag || (*idp)->ilist || CHECK_BLIST(bno + i))
9ee7055c
AM
1501 dbprintf(_("rtblock %llu claimed by inode %lld, "
1502 "previous inum %lld\n"),
2bd0ea18
NS
1503 bno + i, c_ino, (*idp)->ino);
1504 error++;
1505 rval = 0;
1506 }
1507 }
1508 return rval;
1509}
1510
1511static void
1512check_rootdir(void)
1513{
1514 inodata_t *id;
1515
1516 id = find_inode(mp->m_sb.sb_rootino, 0);
1517 if (id == NULL) {
1518 if (!sflag)
9ee7055c 1519 dbprintf(_("root inode %lld is missing\n"),
2bd0ea18
NS
1520 mp->m_sb.sb_rootino);
1521 error++;
1522 } else if (!id->isdir) {
1523 if (!sflag || id->ilist)
9ee7055c 1524 dbprintf(_("root inode %lld is not a directory\n"),
2bd0ea18
NS
1525 mp->m_sb.sb_rootino);
1526 error++;
1527 }
1528}
1529
1530static int
1531check_rrange(
5a35bf2c 1532 xfs_rfsblock_t bno,
2bd0ea18
NS
1533 xfs_extlen_t len)
1534{
1535 xfs_extlen_t i;
1536
1537 if (bno + len - 1 >= mp->m_sb.sb_rblocks) {
1538 for (i = 0; i < len; i++) {
1539 if (!sflag || CHECK_BLIST(bno + i))
9ee7055c 1540 dbprintf(_("rtblock %llu out of range\n"),
2bd0ea18
NS
1541 bno + i);
1542 }
1543 error++;
1544 return 0;
1545 }
1546 return 1;
1547}
1548
757ad8c7
DW
1549/*
1550 * We don't check the accuracy of reference counts -- all we do is ensure
1551 * that a data block never crosses with non-data blocks. repair can check
1552 * those kinds of things.
1553 *
1554 * So with that in mind, if we're setting a block to be data or rldata,
1555 * don't complain so long as the block is currently unknown, data, or rldata.
1556 * Don't let blocks downgrade from rldata -> data.
1557 */
1558static bool
1559is_reflink(
1560 dbm_t type2)
1561{
1562 if (!xfs_sb_version_hasreflink(&mp->m_sb))
1563 return false;
1564 if (type2 == DBM_DATA || type2 == DBM_RLDATA)
1565 return true;
1566 return false;
1567}
1568
2bd0ea18
NS
1569static void
1570check_set_dbmap(
1571 xfs_agnumber_t agno,
1572 xfs_agblock_t agbno,
1573 xfs_extlen_t len,
1574 dbm_t type1,
1575 dbm_t type2,
1576 xfs_agnumber_t c_agno,
1577 xfs_agblock_t c_agbno)
1578{
1579 xfs_extlen_t i;
1580 int mayprint;
1581 char *p;
1582
1583 if (!check_range(agno, agbno, len)) {
9ee7055c 1584 dbprintf(_("blocks %u/%u..%u claimed by block %u/%u\n"), agno,
2bd0ea18
NS
1585 agbno, agbno + len - 1, c_agno, c_agbno);
1586 return;
1587 }
757ad8c7 1588 check_dbmap(agno, agbno, len, type1, is_reflink(type2));
2bd0ea18
NS
1589 mayprint = verbose | blist_size;
1590 for (i = 0, p = &dbmap[agno][agbno]; i < len; i++, p++) {
757ad8c7
DW
1591 if (*p == DBM_RLDATA && type2 == DBM_DATA)
1592 ; /* do nothing */
1593 else if (*p == DBM_DATA && type2 == DBM_DATA)
1594 *p = (char)DBM_RLDATA;
1595 else
1596 *p = (char)type2;
2bd0ea18 1597 if (mayprint && (verbose || CHECK_BLISTA(agno, agbno + i)))
9ee7055c 1598 dbprintf(_("setting block %u/%u to %s\n"), agno, agbno + i,
2bd0ea18
NS
1599 typename[type2]);
1600 }
1601}
1602
1603static void
1604check_set_rdbmap(
5a35bf2c 1605 xfs_rfsblock_t bno,
2bd0ea18
NS
1606 xfs_extlen_t len,
1607 dbm_t type1,
1608 dbm_t type2)
1609{
1610 xfs_extlen_t i;
1611 int mayprint;
1612 char *p;
1613
1614 if (!check_rrange(bno, len))
1615 return;
1616 check_rdbmap(bno, len, type1);
1617 mayprint = verbose | blist_size;
1618 for (i = 0, p = &dbmap[mp->m_sb.sb_agcount][bno]; i < len; i++, p++) {
1619 *p = (char)type2;
1620 if (mayprint && (verbose || CHECK_BLIST(bno + i)))
9ee7055c 1621 dbprintf(_("setting rtblock %llu to %s\n"),
2bd0ea18
NS
1622 bno + i, typename[type2]);
1623 }
1624}
1625
1626static void
1627check_summary(void)
1628{
5a35bf2c 1629 xfs_rfsblock_t bno;
2bd0ea18
NS
1630 xfs_suminfo_t *csp;
1631 xfs_suminfo_t *fsp;
1632 int log;
1633
1634 csp = sumcompute;
1635 fsp = sumfile;
1636 for (log = 0; log < mp->m_rsumlevels; log++) {
1637 for (bno = 0;
1638 bno < mp->m_sb.sb_rbmblocks;
1639 bno++, csp++, fsp++) {
1640 if (*csp != *fsp) {
1641 if (!sflag)
9ee7055c 1642 dbprintf(_("rt summary mismatch, size %d "
2bd0ea18 1643 "block %llu, file: %d, "
9ee7055c 1644 "computed: %d\n"),
2bd0ea18
NS
1645 log, bno, *fsp, *csp);
1646 error++;
1647 }
1648 }
1649 }
1650}
1651
1652static void
1653checknot_dbmap(
1654 xfs_agnumber_t agno,
1655 xfs_agblock_t agbno,
1656 xfs_extlen_t len,
1657 int typemask)
1658{
1659 xfs_extlen_t i;
1660 char *p;
1661
1662 if (!check_range(agno, agbno, len))
1663 return;
1664 for (i = 0, p = &dbmap[agno][agbno]; i < len; i++, p++) {
1665 if ((1 << *p) & typemask) {
1666 if (!sflag || CHECK_BLISTA(agno, agbno + i))
9ee7055c 1667 dbprintf(_("block %u/%u type %s not expected\n"),
2bd0ea18
NS
1668 agno, agbno + i, typename[(dbm_t)*p]);
1669 error++;
1670 }
1671 }
1672}
1673
1674static void
1675checknot_rdbmap(
5a35bf2c 1676 xfs_rfsblock_t bno,
2bd0ea18
NS
1677 xfs_extlen_t len,
1678 int typemask)
1679{
1680 xfs_extlen_t i;
1681 char *p;
1682
1683 if (!check_rrange(bno, len))
1684 return;
1685 for (i = 0, p = &dbmap[mp->m_sb.sb_agcount][bno]; i < len; i++, p++) {
1686 if ((1 << *p) & typemask) {
1687 if (!sflag || CHECK_BLIST(bno + i))
9ee7055c 1688 dbprintf(_("rtblock %llu type %s not expected\n"),
2bd0ea18
NS
1689 bno + i, typename[(dbm_t)*p]);
1690 error++;
1691 }
1692 }
1693}
1694
1695static void
1696dir_hash_add(
1697 xfs_dahash_t hash,
1698 xfs_dir2_dataptr_t addr)
1699{
1700 int i;
1701 dirhash_t *p;
1702
1703 i = DIR_HASH_FUNC(hash, addr);
1704 p = malloc(sizeof(*p));
1705 p->next = dirhash[i];
1706 dirhash[i] = p;
5e656dbb
BN
1707 p->hashval = hash;
1708 p->address = addr;
2bd0ea18
NS
1709 p->seen = 0;
1710}
1711
1712static void
1713dir_hash_check(
1714 inodata_t *id,
1715 int v)
1716{
1717 int i;
1718 dirhash_t *p;
1719
1720 for (i = 0; i < DIR_HASH_SIZE; i++) {
1721 for (p = dirhash[i]; p; p = p->next) {
1722 if (p->seen)
1723 continue;
1724 if (!sflag || id->ilist || v)
9ee7055c
AM
1725 dbprintf(_("dir ino %lld missing leaf entry for "
1726 "%x/%x\n"),
5e656dbb 1727 id->ino, p->hashval, p->address);
2bd0ea18
NS
1728 error++;
1729 }
1730 }
1731}
1732
1733static void
1734dir_hash_done(void)
1735{
1736 int i;
1737 dirhash_t *n;
1738 dirhash_t *p;
1739
1740 for (i = 0; i < DIR_HASH_SIZE; i++) {
1741 for (p = dirhash[i]; p; p = n) {
1742 n = p->next;
1743 free(p);
1744 }
1745 dirhash[i] = NULL;
1746 }
1747}
1748
1749static void
1750dir_hash_init(void)
1751{
1752 if (!dirhash)
1753 dirhash = calloc(DIR_HASH_SIZE, sizeof(*dirhash));
1754}
1755
1756static int
1757dir_hash_see(
1758 xfs_dahash_t hash,
1759 xfs_dir2_dataptr_t addr)
1760{
1761 int i;
1762 dirhash_t *p;
1763
1764 i = DIR_HASH_FUNC(hash, addr);
1765 for (p = dirhash[i]; p; p = p->next) {
5e656dbb 1766 if (p->hashval == hash && p->address == addr) {
2bd0ea18
NS
1767 if (p->seen)
1768 return 1;
1769 p->seen = 1;
1770 return 0;
1771 }
1772 }
1773 return -1;
1774}
1775
1776static inodata_t *
1777find_inode(
1778 xfs_ino_t ino,
1779 int add)
1780{
1781 xfs_agino_t agino;
1782 xfs_agnumber_t agno;
1783 inodata_t *ent;
1784 inodata_t **htab;
1785 xfs_agino_t ih;
1786
1787 agno = XFS_INO_TO_AGNO(mp, ino);
1788 agino = XFS_INO_TO_AGINO(mp, ino);
1789 if (agno >= mp->m_sb.sb_agcount ||
1790 XFS_AGINO_TO_INO(mp, agno, agino) != ino)
1791 return NULL;
1792 htab = inodata[agno];
1793 ih = agino % inodata_hash_size;
1794 ent = htab[ih];
1795 while (ent) {
1796 if (ent->ino == ino)
1797 return ent;
1798 ent = ent->next;
1799 }
1800 if (!add)
1801 return NULL;
1802 ent = xcalloc(1, sizeof(*ent));
1803 ent->ino = ino;
1804 ent->next = htab[ih];
1805 htab[ih] = ent;
1806 return ent;
1807}
1808
1809static void
1810free_inodata(
1811 xfs_agnumber_t agno)
1812{
1813 inodata_t *hp;
1814 inodata_t **ht;
1815 int i;
1816 inodata_t *next;
1817
1818 ht = inodata[agno];
1819 for (i = 0; i < inodata_hash_size; i++) {
1820 hp = ht[i];
1821 while (hp) {
1822 next = hp->next;
1823 if (hp->name)
1824 xfree(hp->name);
1825 xfree(hp);
1826 hp = next;
1827 }
1828 }
1829 xfree(ht);
1830}
1831
1832static int
1833init(
1834 int argc,
1835 char **argv)
1836{
1837 xfs_fsblock_t bno;
1838 int c;
1839 xfs_ino_t ino;
1840 int rt;
1841
f891d8c4 1842 serious_error = 0;
2bd0ea18 1843 if (mp->m_sb.sb_magicnum != XFS_SB_MAGIC) {
9ee7055c 1844 dbprintf(_("bad superblock magic number %x, giving up\n"),
2bd0ea18 1845 mp->m_sb.sb_magicnum);
f891d8c4 1846 serious_error = 1;
2bd0ea18
NS
1847 return 0;
1848 }
add013da
NS
1849 if (!sb_logcheck())
1850 return 0;
2bd0ea18
NS
1851 rt = mp->m_sb.sb_rextents != 0;
1852 dbmap = xmalloc((mp->m_sb.sb_agcount + rt) * sizeof(*dbmap));
1853 inomap = xmalloc((mp->m_sb.sb_agcount + rt) * sizeof(*inomap));
1854 inodata = xmalloc(mp->m_sb.sb_agcount * sizeof(*inodata));
1855 inodata_hash_size =
68d16907 1856 (int)max(min(mp->m_sb.sb_icount /
2bd0ea18
NS
1857 (INODATA_AVG_HASH_LENGTH * mp->m_sb.sb_agcount),
1858 MAX_INODATA_HASH_SIZE),
1859 MIN_INODATA_HASH_SIZE);
1860 for (c = 0; c < mp->m_sb.sb_agcount; c++) {
1861 dbmap[c] = xcalloc(mp->m_sb.sb_agblocks, sizeof(**dbmap));
1862 inomap[c] = xcalloc(mp->m_sb.sb_agblocks, sizeof(**inomap));
1863 inodata[c] = xcalloc(inodata_hash_size, sizeof(**inodata));
1864 }
1865 if (rt) {
1866 dbmap[c] = xcalloc(mp->m_sb.sb_rblocks, sizeof(**dbmap));
1867 inomap[c] = xcalloc(mp->m_sb.sb_rblocks, sizeof(**inomap));
1868 sumfile = xcalloc(mp->m_rsumsize, 1);
1869 sumcompute = xcalloc(mp->m_rsumsize, 1);
1870 }
32a82561
NS
1871 nflag = sflag = tflag = verbose = optind = 0;
1872 while ((c = getopt(argc, argv, "b:i:npstv")) != EOF) {
2bd0ea18
NS
1873 switch (c) {
1874 case 'b':
6bef826c 1875 bno = strtoll(optarg, NULL, 10);
2bd0ea18
NS
1876 add_blist(bno);
1877 break;
1878 case 'i':
6bef826c 1879 ino = strtoll(optarg, NULL, 10);
2bd0ea18
NS
1880 add_ilist(ino);
1881 break;
1882 case 'n':
1883 nflag = 1;
1884 break;
1885 case 'p':
1886 pflag = 1;
1887 break;
1888 case 's':
1889 sflag = 1;
1890 break;
32a82561
NS
1891 case 't':
1892 tflag = 1;
1893 break;
2bd0ea18
NS
1894 case 'v':
1895 verbose = 1;
1896 break;
1897 default:
9ee7055c 1898 dbprintf(_("bad option for blockget command\n"));
2bd0ea18
NS
1899 return 0;
1900 }
1901 }
1902 error = sbver_err = serious_error = 0;
1903 fdblocks = frextents = icount = ifree = 0;
1904 sbversion = XFS_SB_VERSION_4;
9da36109
BF
1905 /*
1906 * Note that inoalignmt == 0 is valid when fsb size is large enough for
1907 * at least one full inode record per block. Check this case explicitly.
1908 */
1909 if (mp->m_sb.sb_inoalignmt ||
1910 (xfs_sb_version_hasalign(&mp->m_sb) &&
1911 mp->m_sb.sb_inopblock >= XFS_INODES_PER_CHUNK))
2bd0ea18
NS
1912 sbversion |= XFS_SB_VERSION_ALIGNBIT;
1913 if ((mp->m_sb.sb_uquotino && mp->m_sb.sb_uquotino != NULLFSINO) ||
0340d706
CS
1914 (mp->m_sb.sb_gquotino && mp->m_sb.sb_gquotino != NULLFSINO) ||
1915 (mp->m_sb.sb_pquotino && mp->m_sb.sb_pquotino != NULLFSINO))
2bd0ea18
NS
1916 sbversion |= XFS_SB_VERSION_QUOTABIT;
1917 quota_init();
1918 return 1;
1919}
1920
1921static char *
1922inode_name(
1923 xfs_ino_t ino,
1924 inodata_t **ipp)
1925{
1926 inodata_t *id;
1927 char *npath;
1928 char *path;
1929
1930 id = find_inode(ino, 0);
1931 if (ipp)
1932 *ipp = id;
1933 if (id == NULL)
1934 return NULL;
1935 if (id->name == NULL)
1936 return NULL;
1937 path = xstrdup(id->name);
1938 while (id->parent) {
1939 id = id->parent;
1940 if (id->name == NULL)
1941 break;
1942 npath = prepend_path(path, id->name);
1943 xfree(path);
1944 path = npath;
1945 }
1946 return path;
1947}
1948
1949static int
1950ncheck_f(
1951 int argc,
1952 char **argv)
1953{
1954 xfs_agnumber_t agno;
1955 int c;
1956 inodata_t *hp;
1957 inodata_t **ht;
1958 int i;
1959 inodata_t *id;
1960 xfs_ino_t *ilist;
1961 int ilist_size;
1962 xfs_ino_t *ilp;
1963 xfs_ino_t ino;
1964 char *p;
1965 int security;
1966
1967 if (!inodata || !nflag) {
9ee7055c 1968 dbprintf(_("must run blockget -n first\n"));
2bd0ea18
NS
1969 return 0;
1970 }
1971 security = optind = ilist_size = 0;
1972 ilist = NULL;
1973 while ((c = getopt(argc, argv, "i:s")) != EOF) {
1974 switch (c) {
1975 case 'i':
6bef826c 1976 ino = strtoll(optarg, NULL, 10);
2bd0ea18
NS
1977 ilist = xrealloc(ilist, (ilist_size + 1) *
1978 sizeof(*ilist));
1979 ilist[ilist_size++] = ino;
1980 break;
1981 case 's':
1982 security = 1;
1983 break;
1984 default:
9ee7055c 1985 dbprintf(_("bad option -%c for ncheck command\n"), c);
355ac015 1986 xfree(ilist);
2bd0ea18
NS
1987 return 0;
1988 }
1989 }
1990 if (ilist) {
1991 for (ilp = ilist; ilp < &ilist[ilist_size]; ilp++) {
1992 ino = *ilp;
27527004 1993 if ((p = inode_name(ino, &hp))) {
2bd0ea18
NS
1994 dbprintf("%11llu %s", ino, p);
1995 if (hp->isdir)
1996 dbprintf("/.");
1997 dbprintf("\n");
1998 xfree(p);
1999 }
2000 }
2001 xfree(ilist);
2002 return 0;
2003 }
2004 for (agno = 0; agno < mp->m_sb.sb_agcount; agno++) {
2005 ht = inodata[agno];
2006 for (i = 0; i < inodata_hash_size; i++) {
2007 hp = ht[i];
2008 for (hp = ht[i]; hp; hp = hp->next) {
2009 ino = XFS_AGINO_TO_INO(mp, agno, hp->ino);
2010 p = inode_name(ino, &id);
2011 if (!p || !id)
2012 continue;
2013 if (!security || id->security) {
2014 dbprintf("%11llu %s", ino, p);
2015 if (hp->isdir)
2016 dbprintf("/.");
2017 dbprintf("\n");
2018 }
2019 xfree(p);
2020 }
2021 }
2022 }
2023 return 0;
2024}
2025
2026static char *
2027prepend_path(
2028 char *oldpath,
2029 char *parent)
2030{
2031 int len;
2032 char *path;
2033
2034 len = (int)(strlen(oldpath) + strlen(parent) + 2);
2035 path = xmalloc(len);
2d9475a4 2036 snprintf(path, len, "%s/%s", parent, oldpath);
2bd0ea18
NS
2037 return path;
2038}
2039
2040static xfs_ino_t
2041process_block_dir_v2(
2042 blkmap_t *blkmap,
2043 int *dot,
2044 int *dotdot,
2045 inodata_t *id)
2046{
2047 xfs_fsblock_t b;
2048 bbmap_t bbmap;
2049 bmap_ext_t *bmp;
2050 int nex;
2051 xfs_ino_t parent;
2052 int v;
2053 int x;
2054
ff105f75 2055 nex = blkmap_getn(blkmap, 0, mp->m_dir_geo->fsbcount, &bmp);
2bd0ea18
NS
2056 v = id->ilist || verbose;
2057 if (nex == 0) {
2058 if (!sflag || v)
9ee7055c
AM
2059 dbprintf(_("block 0 for directory inode %lld is "
2060 "missing\n"),
2bd0ea18
NS
2061 id->ino);
2062 error++;
2063 return 0;
2064 }
2065 push_cur();
2066 if (nex > 1)
2067 make_bbmap(&bbmap, nex, bmp);
9a048535 2068 set_cur(&typtab[TYP_DIR2], XFS_FSB_TO_DADDR(mp, bmp->startblock),
ff105f75 2069 mp->m_dir_geo->fsbcount * blkbb, DB_RING_IGN, nex > 1 ? &bbmap : NULL);
2bd0ea18
NS
2070 for (x = 0; !v && x < nex; x++) {
2071 for (b = bmp[x].startblock;
2072 !v && b < bmp[x].startblock + bmp[x].blockcount;
2073 b++)
2074 v = CHECK_BLIST(b);
2075 }
2076 free(bmp);
2077 if (iocur_top->data == NULL) {
2078 if (!sflag || id->ilist || v)
9ee7055c
AM
2079 dbprintf(_("can't read block 0 for directory inode "
2080 "%lld\n"),
2bd0ea18
NS
2081 id->ino);
2082 error++;
d24c0a90 2083 pop_cur();
2bd0ea18
NS
2084 return 0;
2085 }
2086 dir_hash_init();
ff105f75 2087 parent = process_data_dir_v2(dot, dotdot, id, v, mp->m_dir_geo->datablk,
2bd0ea18
NS
2088 NULL);
2089 dir_hash_check(id, v);
2090 dir_hash_done();
2091 pop_cur();
2092 return parent;
2093}
2094
2095static void
2096process_bmbt_reclist(
b9652a81 2097 xfs_bmbt_rec_t *rp,
2bd0ea18
NS
2098 int numrecs,
2099 dbm_t type,
2100 inodata_t *id,
5a35bf2c 2101 xfs_rfsblock_t *tot,
2bd0ea18
NS
2102 blkmap_t **blkmapp)
2103{
2104 xfs_agblock_t agbno;
2105 xfs_agnumber_t agno;
2106 xfs_fsblock_t b;
5a35bf2c
DC
2107 xfs_filblks_t c;
2108 xfs_filblks_t cp;
2bd0ea18
NS
2109 int f;
2110 int i;
2111 xfs_agblock_t iagbno;
2112 xfs_agnumber_t iagno;
5a35bf2c
DC
2113 xfs_fileoff_t o;
2114 xfs_fileoff_t op;
2115 xfs_fsblock_t s;
2bd0ea18
NS
2116 int v;
2117
2118 cp = op = 0;
2119 v = verbose || id->ilist;
2120 iagno = XFS_INO_TO_AGNO(mp, id->ino);
2121 iagbno = XFS_INO_TO_AGBNO(mp, id->ino);
2122 for (i = 0; i < numrecs; i++, rp++) {
b9652a81 2123 convert_extent(rp, &o, &s, &c, &f);
2bd0ea18 2124 if (v)
9ee7055c 2125 dbprintf(_("inode %lld extent [%lld,%lld,%lld,%d]\n"),
2bd0ea18
NS
2126 id->ino, o, s, c, f);
2127 if (!sflag && i > 0 && op + cp > o)
9ee7055c 2128 dbprintf(_("bmap rec out of order, inode %lld entry %d\n"),
2bd0ea18
NS
2129 id->ino, i);
2130 op = o;
2131 cp = c;
2132 if (type == DBM_RTDATA) {
2133 if (!sflag && s >= mp->m_sb.sb_rblocks) {
9ee7055c
AM
2134 dbprintf(_("inode %lld bad rt block number %lld, "
2135 "offset %lld\n"),
2bd0ea18
NS
2136 id->ino, s, o);
2137 continue;
2138 }
2139 } else if (!sflag) {
2140 agno = XFS_FSB_TO_AGNO(mp, s);
2141 agbno = XFS_FSB_TO_AGBNO(mp, s);
2142 if (agno >= mp->m_sb.sb_agcount ||
2143 agbno >= mp->m_sb.sb_agblocks) {
9ee7055c
AM
2144 dbprintf(_("inode %lld bad block number %lld "
2145 "[%d,%d], offset %lld\n"),
2bd0ea18
NS
2146 id->ino, s, agno, agbno, o);
2147 continue;
2148 }
2149 if (agbno + c - 1 >= mp->m_sb.sb_agblocks) {
9ee7055c
AM
2150 dbprintf(_("inode %lld bad block number %lld "
2151 "[%d,%d], offset %lld\n"),
2bd0ea18
NS
2152 id->ino, s + c - 1, agno,
2153 agbno + (xfs_agblock_t)c - 1, o);
2154 continue;
2155 }
2156 }
2157 if (blkmapp && *blkmapp)
2158 blkmap_set_ext(blkmapp, (xfs_fileoff_t)o,
2159 (xfs_fsblock_t)s, (xfs_extlen_t)c);
2160 if (type == DBM_RTDATA) {
2161 set_rdbmap((xfs_fsblock_t)s, (xfs_extlen_t)c,
2162 DBM_RTDATA);
2163 set_rinomap((xfs_fsblock_t)s, (xfs_extlen_t)c, id);
2164 for (b = (xfs_fsblock_t)s;
2165 blist_size && b < s + c;
2166 b++, o++) {
2167 if (CHECK_BLIST(b))
9ee7055c
AM
2168 dbprintf(_("inode %lld block %lld at "
2169 "offset %lld\n"),
5a35bf2c 2170 id->ino, (xfs_fsblock_t)b, o);
2bd0ea18
NS
2171 }
2172 } else {
2173 agno = XFS_FSB_TO_AGNO(mp, (xfs_fsblock_t)s);
2174 agbno = XFS_FSB_TO_AGBNO(mp, (xfs_fsblock_t)s);
2175 set_dbmap(agno, agbno, (xfs_extlen_t)c, type, iagno,
2176 iagbno);
2177 set_inomap(agno, agbno, (xfs_extlen_t)c, id);
2178 for (b = (xfs_fsblock_t)s;
2179 blist_size && b < s + c;
2180 b++, o++, agbno++) {
2181 if (CHECK_BLIST(b))
9ee7055c
AM
2182 dbprintf(_("inode %lld block %lld at "
2183 "offset %lld\n"),
5a35bf2c 2184 id->ino, (xfs_fsblock_t)b, o);
2bd0ea18
NS
2185 }
2186 }
2187 *tot += c;
2188 }
2189}
2190
2191static void
2192process_btinode(
2193 inodata_t *id,
2194 xfs_dinode_t *dip,
2195 dbm_t type,
5a35bf2c
DC
2196 xfs_rfsblock_t *totd,
2197 xfs_rfsblock_t *toti,
2bd0ea18
NS
2198 xfs_extnum_t *nex,
2199 blkmap_t **blkmapp,
2200 int whichfork)
2201{
2202 xfs_bmdr_block_t *dib;
2203 int i;
2204 xfs_bmbt_ptr_t *pp;
2bd0ea18 2205
46eca962 2206 dib = (xfs_bmdr_block_t *)XFS_DFORK_PTR(dip, whichfork);
5e656dbb 2207 if (be16_to_cpu(dib->bb_level) >= XFS_BM_MAXLEVELS(mp, whichfork)) {
2bd0ea18 2208 if (!sflag || id->ilist)
9ee7055c
AM
2209 dbprintf(_("level for ino %lld %s fork bmap root too "
2210 "large (%u)\n"),
2bd0ea18 2211 id->ino,
9ee7055c 2212 whichfork == XFS_DATA_FORK ? _("data") : _("attr"),
5e656dbb 2213 be16_to_cpu(dib->bb_level));
2bd0ea18
NS
2214 error++;
2215 return;
2216 }
b3563c19 2217 if (be16_to_cpu(dib->bb_numrecs) >
e2f60652 2218 libxfs_bmdr_maxrecs(XFS_DFORK_SIZE(dip, mp, whichfork),
b3563c19 2219 be16_to_cpu(dib->bb_level) == 0)) {
2bd0ea18 2220 if (!sflag || id->ilist)
9ee7055c
AM
2221 dbprintf(_("numrecs for ino %lld %s fork bmap root too "
2222 "large (%u)\n"),
dfc130f3 2223 id->ino,
9ee7055c 2224 whichfork == XFS_DATA_FORK ? _("data") : _("attr"),
5e656dbb 2225 be16_to_cpu(dib->bb_numrecs));
2bd0ea18
NS
2226 error++;
2227 return;
2228 }
5e656dbb 2229 if (be16_to_cpu(dib->bb_level) == 0) {
b9652a81 2230 xfs_bmbt_rec_t *rp = XFS_BMDR_REC_ADDR(dib, 1);
f8149110 2231 process_bmbt_reclist(rp, be16_to_cpu(dib->bb_numrecs), type,
5e656dbb
BN
2232 id, totd, blkmapp);
2233 *nex += be16_to_cpu(dib->bb_numrecs);
2bd0ea18
NS
2234 return;
2235 } else {
e2f60652 2236 pp = XFS_BMDR_PTR_ADDR(dib, 1, libxfs_bmdr_maxrecs(
b3563c19 2237 XFS_DFORK_SIZE(dip, mp, whichfork), 0));
5e656dbb 2238 for (i = 0; i < be16_to_cpu(dib->bb_numrecs); i++)
c5d584c0 2239 scan_lbtree(get_unaligned_be64(&pp[i]),
f8149110
JT
2240 be16_to_cpu(dib->bb_level),
2241 scanfunc_bmap, type, id, totd, toti,
2242 nex, blkmapp, 1,
5e656dbb
BN
2243 whichfork == XFS_DATA_FORK ?
2244 TYP_BMAPBTD : TYP_BMAPBTA);
2245 }
2246 if (*nex <= XFS_DFORK_SIZE(dip, mp, whichfork) / sizeof(xfs_bmbt_rec_t)) {
2bd0ea18 2247 if (!sflag || id->ilist)
9ee7055c
AM
2248 dbprintf(_("extent count for ino %lld %s fork too low "
2249 "(%d) for file format\n"),
2bd0ea18 2250 id->ino,
9ee7055c 2251 whichfork == XFS_DATA_FORK ? _("data") : _("attr"),
2bd0ea18
NS
2252 *nex);
2253 error++;
2254 }
2255}
2256
2257static xfs_ino_t
2258process_data_dir_v2(
2259 int *dot,
2260 int *dotdot,
2261 inodata_t *id,
2262 int v,
2263 xfs_dablk_t dabno,
2264 freetab_t **freetabp)
2265{
2266 xfs_dir2_dataptr_t addr;
2267 xfs_dir2_data_free_t *bf;
2268 int bf_err;
eb0cb950 2269 struct xfs_dir2_data_hdr *block;
2bd0ea18
NS
2270 xfs_dir2_block_tail_t *btp = NULL;
2271 inodata_t *cid;
2272 int count;
eb0cb950 2273 struct xfs_dir2_data_hdr *data;
2bd0ea18
NS
2274 xfs_dir2_db_t db;
2275 xfs_dir2_data_entry_t *dep;
2276 xfs_dir2_data_free_t *dfp;
2277 xfs_dir2_data_unused_t *dup;
2278 char *endptr;
2279 int freeseen;
2280 freetab_t *freetab;
2bd0ea18
NS
2281 int i;
2282 int lastfree;
2283 int lastfree_err;
2284 xfs_dir2_leaf_entry_t *lep = NULL;
2285 xfs_ino_t lino;
2286 xfs_ino_t parent = 0;
2287 char *ptr;
2288 int stale = 0;
2289 int tag_err;
5e656dbb
BN
2290 __be16 *tagp;
2291 struct xfs_name xname;
2bd0ea18
NS
2292
2293 data = iocur_top->data;
2294 block = iocur_top->data;
eb0cb950 2295 if (be32_to_cpu(block->magic) != XFS_DIR2_BLOCK_MAGIC &&
e96864ff
DW
2296 be32_to_cpu(data->magic) != XFS_DIR2_DATA_MAGIC &&
2297 be32_to_cpu(block->magic) != XFS_DIR3_BLOCK_MAGIC &&
2298 be32_to_cpu(data->magic) != XFS_DIR3_DATA_MAGIC) {
2bd0ea18 2299 if (!sflag || v)
9ee7055c
AM
2300 dbprintf(_("bad directory data magic # %#x for dir ino "
2301 "%lld block %d\n"),
eb0cb950 2302 be32_to_cpu(data->magic), id->ino, dabno);
2bd0ea18
NS
2303 error++;
2304 return NULLFSINO;
2305 }
ff105f75
DC
2306 db = xfs_dir2_da_to_db(mp->m_dir_geo, dabno);
2307 bf = M_DIROPS(mp)->data_bestfree_p(data);
2308 ptr = (char *)M_DIROPS(mp)->data_unused_p(data);
e96864ff
DW
2309 if (be32_to_cpu(block->magic) == XFS_DIR2_BLOCK_MAGIC ||
2310 be32_to_cpu(block->magic) == XFS_DIR3_BLOCK_MAGIC) {
ff105f75 2311 btp = xfs_dir2_block_tail_p(mp->m_dir_geo, block);
5e656dbb 2312 lep = xfs_dir2_block_leaf_p(btp);
2bd0ea18
NS
2313 endptr = (char *)lep;
2314 if (endptr <= ptr || endptr > (char *)btp) {
ff105f75 2315 endptr = (char *)data + mp->m_dir_geo->blksize;
2bd0ea18
NS
2316 lep = NULL;
2317 if (!sflag || v)
9ee7055c
AM
2318 dbprintf(_("bad block directory tail for dir ino "
2319 "%lld\n"),
2bd0ea18
NS
2320 id->ino);
2321 error++;
2322 }
2323 } else
ff105f75 2324 endptr = (char *)data + mp->m_dir_geo->blksize;
2bd0ea18
NS
2325 bf_err = lastfree_err = tag_err = 0;
2326 count = lastfree = freeseen = 0;
5e656dbb
BN
2327 if (be16_to_cpu(bf[0].length) == 0) {
2328 bf_err += be16_to_cpu(bf[0].offset) != 0;
2bd0ea18
NS
2329 freeseen |= 1 << 0;
2330 }
5e656dbb
BN
2331 if (be16_to_cpu(bf[1].length) == 0) {
2332 bf_err += be16_to_cpu(bf[1].offset) != 0;
2bd0ea18
NS
2333 freeseen |= 1 << 1;
2334 }
5e656dbb
BN
2335 if (be16_to_cpu(bf[2].length) == 0) {
2336 bf_err += be16_to_cpu(bf[2].offset) != 0;
2bd0ea18
NS
2337 freeseen |= 1 << 2;
2338 }
5e656dbb
BN
2339 bf_err += be16_to_cpu(bf[0].length) < be16_to_cpu(bf[1].length);
2340 bf_err += be16_to_cpu(bf[1].length) < be16_to_cpu(bf[2].length);
2bd0ea18
NS
2341 if (freetabp) {
2342 freetab = *freetabp;
2343 if (freetab->naents <= db) {
2344 *freetabp = freetab =
2345 realloc(freetab, FREETAB_SIZE(db + 1));
2346 for (i = freetab->naents; i < db; i++)
2347 freetab->ents[i] = NULLDATAOFF;
2348 freetab->naents = db + 1;
2349 }
2350 if (freetab->nents < db + 1)
2351 freetab->nents = db + 1;
5e656dbb 2352 freetab->ents[db] = be16_to_cpu(bf[0].length);
2bd0ea18
NS
2353 }
2354 while (ptr < endptr) {
2355 dup = (xfs_dir2_data_unused_t *)ptr;
5e656dbb 2356 if (be16_to_cpu(dup->freetag) == XFS_DIR2_DATA_FREE_TAG) {
2bd0ea18 2357 lastfree_err += lastfree != 0;
5e656dbb
BN
2358 tagp = xfs_dir2_data_unused_tag_p(dup);
2359 if ((be16_to_cpu(dup->length) & (XFS_DIR2_DATA_ALIGN - 1)) ||
2360 be16_to_cpu(dup->length) == 0 ||
2361 (char *)tagp >= endptr) {
2bd0ea18 2362 if (!sflag || v)
9ee7055c
AM
2363 dbprintf(_("dir %lld block %d bad free "
2364 "entry at %d\n"),
2bd0ea18
NS
2365 id->ino, dabno,
2366 (int)((char *)dup -
2367 (char *)data));
2368 error++;
2369 break;
2370 }
5e656dbb 2371 tag_err += be16_to_cpu(*tagp) != (char *)dup - (char *)data;
2bd0ea18
NS
2372 dfp = process_data_dir_v2_freefind(data, dup);
2373 if (dfp) {
2374 i = (int)(dfp - bf);
2375 bf_err += (freeseen & (1 << i)) != 0;
2376 freeseen |= 1 << i;
2377 } else
f8149110 2378 bf_err += be16_to_cpu(dup->length) >
5e656dbb
BN
2379 be16_to_cpu(bf[2].length);
2380 ptr += be16_to_cpu(dup->length);
2bd0ea18
NS
2381 lastfree = 1;
2382 continue;
2383 }
2384 dep = (xfs_dir2_data_entry_t *)dup;
2385 if (dep->namelen == 0) {
2386 if (!sflag || v)
9ee7055c
AM
2387 dbprintf(_("dir %lld block %d zero length entry "
2388 "at %d\n"),
2bd0ea18
NS
2389 id->ino, dabno,
2390 (int)((char *)dep - (char *)data));
2391 error++;
2392 }
ff105f75 2393 tagp = M_DIROPS(mp)->data_entry_tag_p(dep);
2bd0ea18
NS
2394 if ((char *)tagp >= endptr) {
2395 if (!sflag || v)
9ee7055c 2396 dbprintf(_("dir %lld block %d bad entry at %d\n"),
2bd0ea18
NS
2397 id->ino, dabno,
2398 (int)((char *)dep - (char *)data));
2399 error++;
2400 break;
2401 }
5e656dbb 2402 tag_err += be16_to_cpu(*tagp) != (char *)dep - (char *)data;
ff105f75 2403 addr = xfs_dir2_db_off_to_dataptr(mp->m_dir_geo, db,
2bd0ea18 2404 (char *)dep - (char *)data);
56b2de80 2405 xname.name = dep->name;
5e656dbb
BN
2406 xname.len = dep->namelen;
2407 dir_hash_add(mp->m_dirnameops->hashname(&xname), addr);
ff105f75 2408 ptr += M_DIROPS(mp)->data_entsize(dep->namelen);
2bd0ea18
NS
2409 count++;
2410 lastfree = 0;
5e656dbb 2411 lino = be64_to_cpu(dep->inumber);
2bd0ea18
NS
2412 cid = find_inode(lino, 1);
2413 if (v)
9ee7055c 2414 dbprintf(_("dir %lld block %d entry %*.*s %lld\n"),
2bd0ea18
NS
2415 id->ino, dabno, dep->namelen, dep->namelen,
2416 dep->name, lino);
2417 if (cid)
2418 addlink_inode(cid);
2419 else {
2420 if (!sflag || v)
9ee7055c
AM
2421 dbprintf(_("dir %lld block %d entry %*.*s bad "
2422 "inode number %lld\n"),
2bd0ea18
NS
2423 id->ino, dabno, dep->namelen,
2424 dep->namelen, dep->name, lino);
2425 error++;
2426 }
2427 if (dep->namelen == 2 && dep->name[0] == '.' &&
2428 dep->name[1] == '.') {
2429 if (parent) {
2430 if (!sflag || v)
9ee7055c
AM
2431 dbprintf(_("multiple .. entries in dir "
2432 "%lld (%lld, %lld)\n"),
2bd0ea18
NS
2433 id->ino, parent, lino);
2434 error++;
2435 } else
2436 parent = cid ? lino : NULLFSINO;
2437 (*dotdot)++;
2438 } else if (dep->namelen != 1 || dep->name[0] != '.') {
2439 if (cid != NULL) {
2440 if (!cid->parent)
2441 cid->parent = id;
2442 addname_inode(cid, (char *)dep->name,
2443 dep->namelen);
2444 }
2445 } else {
2446 if (lino != id->ino) {
2447 if (!sflag || v)
9ee7055c
AM
2448 dbprintf(_("dir %lld entry . inode "
2449 "number mismatch (%lld)\n"),
2bd0ea18
NS
2450 id->ino, lino);
2451 error++;
2452 }
2453 (*dot)++;
2454 }
2455 }
e96864ff
DW
2456 if (be32_to_cpu(data->magic) == XFS_DIR2_BLOCK_MAGIC ||
2457 be32_to_cpu(data->magic) == XFS_DIR3_BLOCK_MAGIC) {
ff105f75 2458 endptr = (char *)data + mp->m_dir_geo->blksize;
5e656dbb 2459 for (i = stale = 0; lep && i < be32_to_cpu(btp->count); i++) {
2bd0ea18
NS
2460 if ((char *)&lep[i] >= endptr) {
2461 if (!sflag || v)
9ee7055c 2462 dbprintf(_("dir %lld block %d bad count "
f8149110 2463 "%u\n"), id->ino, dabno,
5e656dbb 2464 be32_to_cpu(btp->count));
2bd0ea18
NS
2465 error++;
2466 break;
2467 }
5e656dbb 2468 if (be32_to_cpu(lep[i].address) == XFS_DIR2_NULL_DATAPTR)
2bd0ea18 2469 stale++;
f8149110 2470 else if (dir_hash_see(be32_to_cpu(lep[i].hashval),
5e656dbb 2471 be32_to_cpu(lep[i].address))) {
2bd0ea18 2472 if (!sflag || v)
9ee7055c 2473 dbprintf(_("dir %lld block %d extra leaf "
f8149110
JT
2474 "entry %x %x\n"),
2475 id->ino, dabno,
5e656dbb
BN
2476 be32_to_cpu(lep[i].hashval),
2477 be32_to_cpu(lep[i].address));
2bd0ea18
NS
2478 error++;
2479 }
2480 }
2481 }
2482 bf_err += freeseen != 7;
2483 if (bf_err) {
2484 if (!sflag || v)
9ee7055c 2485 dbprintf(_("dir %lld block %d bad bestfree data\n"),
2bd0ea18
NS
2486 id->ino, dabno);
2487 error++;
2488 }
e96864ff
DW
2489 if ((be32_to_cpu(data->magic) == XFS_DIR2_BLOCK_MAGIC ||
2490 be32_to_cpu(data->magic) == XFS_DIR3_BLOCK_MAGIC) &&
eb0cb950 2491 count != be32_to_cpu(btp->count) - be32_to_cpu(btp->stale)) {
2bd0ea18 2492 if (!sflag || v)
9ee7055c 2493 dbprintf(_("dir %lld block %d bad block tail count %d "
f8149110
JT
2494 "(stale %d)\n"),
2495 id->ino, dabno, be32_to_cpu(btp->count),
5e656dbb 2496 be32_to_cpu(btp->stale));
2bd0ea18
NS
2497 error++;
2498 }
e96864ff
DW
2499 if ((be32_to_cpu(data->magic) == XFS_DIR2_BLOCK_MAGIC ||
2500 be32_to_cpu(data->magic) == XFS_DIR2_BLOCK_MAGIC) &&
5e656dbb 2501 stale != be32_to_cpu(btp->stale)) {
2bd0ea18 2502 if (!sflag || v)
9ee7055c 2503 dbprintf(_("dir %lld block %d bad stale tail count %d\n"),
5e656dbb 2504 id->ino, dabno, be32_to_cpu(btp->stale));
2bd0ea18
NS
2505 error++;
2506 }
2507 if (lastfree_err) {
2508 if (!sflag || v)
9ee7055c 2509 dbprintf(_("dir %lld block %d consecutive free entries\n"),
2bd0ea18
NS
2510 id->ino, dabno);
2511 error++;
2512 }
2513 if (tag_err) {
2514 if (!sflag || v)
9ee7055c
AM
2515 dbprintf(_("dir %lld block %d entry/unused tag "
2516 "mismatch\n"),
2bd0ea18
NS
2517 id->ino, dabno);
2518 error++;
2519 }
2520 return parent;
2521}
2522
2523static xfs_dir2_data_free_t *
2524process_data_dir_v2_freefind(
eb0cb950 2525 struct xfs_dir2_data_hdr *data,
2bd0ea18
NS
2526 xfs_dir2_data_unused_t *dup)
2527{
eb0cb950
DC
2528 struct xfs_dir2_data_free *bf;
2529 struct xfs_dir2_data_free *dfp;
2bd0ea18
NS
2530 xfs_dir2_data_aoff_t off;
2531
2532 off = (xfs_dir2_data_aoff_t)((char *)dup - (char *)data);
ff105f75 2533 bf = M_DIROPS(mp)->data_bestfree_p(data);
eb0cb950
DC
2534 if (be16_to_cpu(dup->length) <
2535 be16_to_cpu(bf[XFS_DIR2_DATA_FD_COUNT - 1].length))
2bd0ea18 2536 return NULL;
eb0cb950 2537 for (dfp = bf; dfp < &bf[XFS_DIR2_DATA_FD_COUNT]; dfp++) {
5e656dbb 2538 if (be16_to_cpu(dfp->offset) == 0)
2bd0ea18 2539 return NULL;
5e656dbb 2540 if (be16_to_cpu(dfp->offset) == off)
2bd0ea18
NS
2541 return dfp;
2542 }
2543 return NULL;
2544}
2545
2546static void
2547process_dir(
2548 xfs_dinode_t *dip,
2549 blkmap_t *blkmap,
2550 inodata_t *id)
2551{
2552 xfs_fsblock_t bno;
2553 int dot;
2554 int dotdot;
2555 xfs_ino_t parent;
2556
2557 dot = dotdot = 0;
9a048535
DC
2558 if (process_dir_v2(dip, blkmap, &dot, &dotdot, id, &parent))
2559 return;
2560
2bd0ea18
NS
2561 bno = XFS_INO_TO_FSB(mp, id->ino);
2562 if (dot == 0) {
2563 if (!sflag || id->ilist || CHECK_BLIST(bno))
9ee7055c 2564 dbprintf(_("no . entry for directory %lld\n"), id->ino);
2bd0ea18
NS
2565 error++;
2566 }
2567 if (dotdot == 0) {
2568 if (!sflag || id->ilist || CHECK_BLIST(bno))
9ee7055c 2569 dbprintf(_("no .. entry for directory %lld\n"), id->ino);
2bd0ea18
NS
2570 error++;
2571 } else if (parent == id->ino && id->ino != mp->m_sb.sb_rootino) {
2572 if (!sflag || id->ilist || CHECK_BLIST(bno))
9ee7055c 2573 dbprintf(_(". and .. same for non-root directory %lld\n"),
2bd0ea18
NS
2574 id->ino);
2575 error++;
2576 } else if (id->ino == mp->m_sb.sb_rootino && id->ino != parent) {
2577 if (!sflag || id->ilist || CHECK_BLIST(bno))
9ee7055c 2578 dbprintf(_("root directory %lld has .. %lld\n"), id->ino,
2bd0ea18
NS
2579 parent);
2580 error++;
2581 } else if (parent != NULLFSINO && id->ino != parent)
2582 addparent_inode(id, parent);
2583}
2584
2bd0ea18
NS
2585static int
2586process_dir_v2(
2587 xfs_dinode_t *dip,
2588 blkmap_t *blkmap,
2589 int *dot,
2590 int *dotdot,
2591 inodata_t *id,
2592 xfs_ino_t *parent)
2593{
2594 xfs_fileoff_t last = 0;
56b2de80 2595 xfs_fsize_t size = be64_to_cpu(dip->di_size);
2bd0ea18
NS
2596
2597 if (blkmap)
2598 last = blkmap_last_off(blkmap);
5e656dbb 2599 if (size <= XFS_DFORK_DSIZE(dip, mp) &&
56b2de80 2600 dip->di_format == XFS_DINODE_FMT_LOCAL)
2bd0ea18 2601 *parent = process_sf_dir_v2(dip, dot, dotdot, id);
ff105f75 2602 else if (last == mp->m_dir_geo->fsbcount &&
56b2de80
DC
2603 (dip->di_format == XFS_DINODE_FMT_EXTENTS ||
2604 dip->di_format == XFS_DINODE_FMT_BTREE))
2bd0ea18 2605 *parent = process_block_dir_v2(blkmap, dot, dotdot, id);
ff105f75 2606 else if (last >= mp->m_dir_geo->leafblk + mp->m_dir_geo->fsbcount &&
56b2de80
DC
2607 (dip->di_format == XFS_DINODE_FMT_EXTENTS ||
2608 dip->di_format == XFS_DINODE_FMT_BTREE))
5e656dbb 2609 *parent = process_leaf_node_dir_v2(blkmap, dot, dotdot, id, size);
2bd0ea18 2610 else {
9ee7055c
AM
2611 dbprintf(_("bad size (%lld) or format (%d) for directory inode "
2612 "%lld\n"),
56b2de80 2613 size, dip->di_format, id->ino);
2bd0ea18
NS
2614 error++;
2615 return 1;
2616 }
2617 return 0;
2618}
2619
2620/* ARGSUSED */
2621static void
2622process_exinode(
2623 inodata_t *id,
2624 xfs_dinode_t *dip,
2625 dbm_t type,
5a35bf2c
DC
2626 xfs_rfsblock_t *totd,
2627 xfs_rfsblock_t *toti,
2bd0ea18
NS
2628 xfs_extnum_t *nex,
2629 blkmap_t **blkmapp,
2630 int whichfork)
2631{
b9652a81 2632 xfs_bmbt_rec_t *rp;
2bd0ea18 2633
b9652a81 2634 rp = (xfs_bmbt_rec_t *)XFS_DFORK_PTR(dip, whichfork);
5e656dbb 2635 *nex = XFS_DFORK_NEXTENTS(dip, whichfork);
f8149110 2636 if (*nex < 0 || *nex > XFS_DFORK_SIZE(dip, mp, whichfork) /
b9652a81 2637 sizeof(xfs_bmbt_rec_t)) {
2bd0ea18 2638 if (!sflag || id->ilist)
9ee7055c 2639 dbprintf(_("bad number of extents %d for inode %lld\n"),
2bd0ea18
NS
2640 *nex, id->ino);
2641 error++;
2642 return;
2643 }
2644 process_bmbt_reclist(rp, *nex, type, id, totd, blkmapp);
2645}
2646
2647static void
2648process_inode(
2649 xfs_agf_t *agf,
2650 xfs_agino_t agino,
2651 xfs_dinode_t *dip,
2652 int isfree)
2653{
2654 blkmap_t *blkmap;
2655 xfs_fsblock_t bno = 0;
1bc6cbe3 2656 struct xfs_inode xino;
2bd0ea18
NS
2657 inodata_t *id = NULL;
2658 xfs_ino_t ino;
2659 xfs_extnum_t nextents = 0;
2bd0ea18 2660 int security;
5a35bf2c
DC
2661 xfs_rfsblock_t totblocks;
2662 xfs_rfsblock_t totdblocks = 0;
2663 xfs_rfsblock_t totiblocks = 0;
2bd0ea18
NS
2664 dbm_t type;
2665 xfs_extnum_t anextents = 0;
5a35bf2c
DC
2666 xfs_rfsblock_t atotdblocks = 0;
2667 xfs_rfsblock_t atotiblocks = 0;
2bd0ea18
NS
2668 xfs_qcnt_t bc = 0;
2669 xfs_qcnt_t ic = 0;
2670 xfs_qcnt_t rc = 0;
be8e601c 2671 xfs_dqid_t dqprid;
527d1f42 2672 int v = 0;
e37bf53c 2673 mode_t mode;
2bd0ea18
NS
2674 static char okfmts[] = {
2675 0, /* type 0 unused */
2676 1 << XFS_DINODE_FMT_DEV, /* FIFO */
2677 1 << XFS_DINODE_FMT_DEV, /* CHR */
2678 0, /* type 3 unused */
2679 (1 << XFS_DINODE_FMT_LOCAL) |
2680 (1 << XFS_DINODE_FMT_EXTENTS) |
2681 (1 << XFS_DINODE_FMT_BTREE), /* DIR */
2682 0, /* type 5 unused */
2683 1 << XFS_DINODE_FMT_DEV, /* BLK */
2684 0, /* type 7 unused */
2685 (1 << XFS_DINODE_FMT_EXTENTS) |
2686 (1 << XFS_DINODE_FMT_BTREE), /* REG */
2687 0, /* type 9 unused */
2688 (1 << XFS_DINODE_FMT_LOCAL) |
2689 (1 << XFS_DINODE_FMT_EXTENTS), /* LNK */
2690 0, /* type 11 unused */
2691 1 << XFS_DINODE_FMT_DEV, /* SOCK */
2692 0, /* type 13 unused */
2693 1 << XFS_DINODE_FMT_UUID, /* MNT */
2694 0 /* type 15 unused */
2695 };
2696 static char *fmtnames[] = {
2697 "dev", "local", "extents", "btree", "uuid"
2698 };
2699
1bc6cbe3 2700 libxfs_inode_from_disk(&xino, dip);
2bd0ea18 2701
5e656dbb 2702 ino = XFS_AGINO_TO_INO(mp, be32_to_cpu(agf->agf_seqno), agino);
2bd0ea18
NS
2703 if (!isfree) {
2704 id = find_inode(ino, 1);
2705 bno = XFS_INO_TO_FSB(mp, ino);
2706 blkmap = NULL;
2707 }
527d1f42 2708 v = (!sflag || (id && id->ilist) || CHECK_BLIST(bno));
db17aebe 2709 if (dip->di_magic != cpu_to_be16(XFS_DINODE_MAGIC)) {
527d1f42 2710 if (isfree || v)
9ee7055c 2711 dbprintf(_("bad magic number %#x for inode %lld\n"),
db17aebe 2712 be16_to_cpu(dip->di_magic), ino);
2bd0ea18
NS
2713 error++;
2714 return;
2715 }
e2f60652 2716 if (!libxfs_dinode_good_version(mp, xino.i_d.di_version)) {
527d1f42 2717 if (isfree || v)
9ee7055c 2718 dbprintf(_("bad version number %#x for inode %lld\n"),
1bc6cbe3 2719 xino.i_d.di_version, ino);
2bd0ea18
NS
2720 error++;
2721 return;
2722 }
2723 if (isfree) {
1bc6cbe3 2724 if (xino.i_d.di_nblocks != 0) {
527d1f42 2725 if (v)
9ee7055c
AM
2726 dbprintf(_("bad nblocks %lld for free inode "
2727 "%lld\n"),
1bc6cbe3 2728 xino.i_d.di_nblocks, ino);
2bd0ea18
NS
2729 error++;
2730 }
f089fc42 2731 if (dip->di_nlink != 0) {
527d1f42 2732 if (v)
9ee7055c 2733 dbprintf(_("bad nlink %d for free inode %lld\n"),
f089fc42 2734 be32_to_cpu(dip->di_nlink), ino);
2bd0ea18
NS
2735 error++;
2736 }
e37bf53c 2737 if (dip->di_mode != 0) {
527d1f42 2738 if (v)
9ee7055c 2739 dbprintf(_("bad mode %#o for free inode %lld\n"),
e37bf53c 2740 be16_to_cpu(dip->di_mode), ino);
2bd0ea18
NS
2741 error++;
2742 }
2743 return;
2744 }
527d1f42 2745
49b31417 2746 if (be32_to_cpu(dip->di_next_unlinked) != NULLAGINO) {
527d1f42 2747 if (v)
9ee7055c 2748 dbprintf(_("bad next unlinked %#x for inode %lld\n"),
49b31417
BN
2749 be32_to_cpu(dip->di_next_unlinked), ino);
2750 error++;
2751 }
2bd0ea18
NS
2752 /*
2753 * di_mode is a 16-bit uint so no need to check the < 0 case
2754 */
e37bf53c
DC
2755 mode = be16_to_cpu(dip->di_mode);
2756 if ((((mode & S_IFMT) >> 12) > 15) ||
2757 (!(okfmts[(mode & S_IFMT) >> 12] & (1 << xino.i_d.di_format)))) {
527d1f42 2758 if (v)
9ee7055c 2759 dbprintf(_("bad format %d for inode %lld type %#o\n"),
e37bf53c 2760 xino.i_d.di_format, id->ino, mode & S_IFMT);
2bd0ea18
NS
2761 error++;
2762 return;
2763 }
49f693fa 2764 if ((unsigned int)XFS_DFORK_ASIZE(dip, mp) >=
1bc6cbe3 2765 XFS_LITINO(mp, xino.i_d.di_version)) {
527d1f42 2766 if (v)
9ee7055c 2767 dbprintf(_("bad fork offset %d for inode %lld\n"),
1bc6cbe3 2768 xino.i_d.di_forkoff, id->ino);
2bd0ea18
NS
2769 error++;
2770 return;
2771 }
1bc6cbe3 2772 if ((unsigned int)xino.i_d.di_aformat > XFS_DINODE_FMT_BTREE) {
527d1f42 2773 if (v)
9ee7055c 2774 dbprintf(_("bad attribute format %d for inode %lld\n"),
1bc6cbe3 2775 xino.i_d.di_aformat, id->ino);
2bd0ea18
NS
2776 error++;
2777 return;
2778 }
527d1f42 2779 if (verbose || (id && id->ilist) || CHECK_BLIST(bno))
9ee7055c 2780 dbprintf(_("inode %lld mode %#o fmt %s "
2bd0ea18 2781 "afmt %s "
9ee7055c 2782 "nex %d anex %d nblk %lld sz %lld%s%s%s%s%s%s%s\n"),
e37bf53c 2783 id->ino, mode, fmtnames[(int)xino.i_d.di_format],
1bc6cbe3
DC
2784 fmtnames[(int)xino.i_d.di_aformat],
2785 xino.i_d.di_nextents,
2786 xino.i_d.di_anextents,
2787 xino.i_d.di_nblocks, xino.i_d.di_size,
2788 xino.i_d.di_flags & XFS_DIFLAG_REALTIME ? " rt" : "",
2789 xino.i_d.di_flags & XFS_DIFLAG_PREALLOC ? " pre" : "",
2790 xino.i_d.di_flags & XFS_DIFLAG_IMMUTABLE? " imm" : "",
2791 xino.i_d.di_flags & XFS_DIFLAG_APPEND ? " app" : "",
2792 xino.i_d.di_flags & XFS_DIFLAG_SYNC ? " syn" : "",
2793 xino.i_d.di_flags & XFS_DIFLAG_NOATIME ? " noa" : "",
2794 xino.i_d.di_flags & XFS_DIFLAG_NODUMP ? " nod" : "");
2bd0ea18 2795 security = 0;
e37bf53c 2796 switch (mode & S_IFMT) {
322f2a29 2797 case S_IFDIR:
2bd0ea18 2798 type = DBM_DIR;
1bc6cbe3 2799 if (xino.i_d.di_format == XFS_DINODE_FMT_LOCAL)
2bd0ea18 2800 break;
1bc6cbe3 2801 blkmap = blkmap_alloc(xino.i_d.di_nextents);
2bd0ea18 2802 break;
322f2a29 2803 case S_IFREG:
1bc6cbe3 2804 if (xino.i_d.di_flags & XFS_DIFLAG_REALTIME)
2bd0ea18
NS
2805 type = DBM_RTDATA;
2806 else if (id->ino == mp->m_sb.sb_rbmino) {
2807 type = DBM_RTBITMAP;
1bc6cbe3 2808 blkmap = blkmap_alloc(xino.i_d.di_nextents);
2bd0ea18
NS
2809 addlink_inode(id);
2810 } else if (id->ino == mp->m_sb.sb_rsumino) {
2811 type = DBM_RTSUM;
1bc6cbe3 2812 blkmap = blkmap_alloc(xino.i_d.di_nextents);
2bd0ea18
NS
2813 addlink_inode(id);
2814 }
2815 else if (id->ino == mp->m_sb.sb_uquotino ||
0340d706
CS
2816 id->ino == mp->m_sb.sb_gquotino ||
2817 id->ino == mp->m_sb.sb_pquotino) {
2bd0ea18 2818 type = DBM_QUOTA;
1bc6cbe3 2819 blkmap = blkmap_alloc(xino.i_d.di_nextents);
2bd0ea18
NS
2820 addlink_inode(id);
2821 }
2822 else
2823 type = DBM_DATA;
e37bf53c 2824 if (mode & (S_ISUID | S_ISGID))
2bd0ea18
NS
2825 security = 1;
2826 break;
322f2a29 2827 case S_IFLNK:
2bd0ea18
NS
2828 type = DBM_SYMLINK;
2829 break;
2830 default:
2831 security = 1;
2832 type = DBM_UNKNOWN;
2833 break;
2834 }
f089fc42 2835
757ad8c7 2836 id->isreflink = !!(xino.i_d.di_flags2 & XFS_DIFLAG2_REFLINK);
bcbe04c1 2837 setlink_inode(id, VFS_I(&xino)->i_nlink, type == DBM_DIR, security);
f089fc42 2838
1bc6cbe3 2839 switch (xino.i_d.di_format) {
2bd0ea18
NS
2840 case XFS_DINODE_FMT_LOCAL:
2841 process_lclinode(id, dip, type, &totdblocks, &totiblocks,
2842 &nextents, &blkmap, XFS_DATA_FORK);
2843 break;
2844 case XFS_DINODE_FMT_EXTENTS:
2845 process_exinode(id, dip, type, &totdblocks, &totiblocks,
2846 &nextents, &blkmap, XFS_DATA_FORK);
2847 break;
2848 case XFS_DINODE_FMT_BTREE:
2849 process_btinode(id, dip, type, &totdblocks, &totiblocks,
2850 &nextents, &blkmap, XFS_DATA_FORK);
2851 break;
2852 }
46eca962 2853 if (XFS_DFORK_Q(dip)) {
2bd0ea18 2854 sbversion |= XFS_SB_VERSION_ATTRBIT;
1bc6cbe3 2855 switch (xino.i_d.di_aformat) {
2bd0ea18
NS
2856 case XFS_DINODE_FMT_LOCAL:
2857 process_lclinode(id, dip, DBM_ATTR, &atotdblocks,
2858 &atotiblocks, &anextents, NULL, XFS_ATTR_FORK);
2859 break;
2860 case XFS_DINODE_FMT_EXTENTS:
2861 process_exinode(id, dip, DBM_ATTR, &atotdblocks,
2862 &atotiblocks, &anextents, NULL, XFS_ATTR_FORK);
2863 break;
2864 case XFS_DINODE_FMT_BTREE:
2865 process_btinode(id, dip, DBM_ATTR, &atotdblocks,
2866 &atotiblocks, &anextents, NULL, XFS_ATTR_FORK);
2867 break;
2868 }
2869 }
9b27bdbb 2870 if (qgdo || qpdo || qudo) {
2bd0ea18
NS
2871 switch (type) {
2872 case DBM_DATA:
2873 case DBM_DIR:
2874 case DBM_RTBITMAP:
2875 case DBM_RTSUM:
2876 case DBM_SYMLINK:
2877 case DBM_UNKNOWN:
2878 bc = totdblocks + totiblocks +
2879 atotdblocks + atotiblocks;
2880 ic = 1;
2881 break;
2882 case DBM_RTDATA:
2883 bc = totiblocks + atotdblocks + atotiblocks;
2884 rc = totdblocks;
2885 ic = 1;
2886 break;
2887 default:
6bef826c 2888 break;
2bd0ea18 2889 }
be8e601c 2890 if (ic) {
1bc6cbe3
DC
2891 dqprid = xfs_get_projid(&xino.i_d); /* dquot ID is u32 */
2892 quota_add(&dqprid, &xino.i_d.di_gid, &xino.i_d.di_uid,
9b27bdbb 2893 0, bc, ic, rc);
be8e601c 2894 }
2bd0ea18
NS
2895 }
2896 totblocks = totdblocks + totiblocks + atotdblocks + atotiblocks;
1bc6cbe3 2897 if (totblocks != xino.i_d.di_nblocks) {
527d1f42 2898 if (v)
9ee7055c
AM
2899 dbprintf(_("bad nblocks %lld for inode %lld, counted "
2900 "%lld\n"),
1bc6cbe3 2901 xino.i_d.di_nblocks, id->ino, totblocks);
2bd0ea18
NS
2902 error++;
2903 }
1bc6cbe3 2904 if (nextents != xino.i_d.di_nextents) {
527d1f42 2905 if (v)
9ee7055c 2906 dbprintf(_("bad nextents %d for inode %lld, counted %d\n"),
1bc6cbe3 2907 xino.i_d.di_nextents, id->ino, nextents);
2bd0ea18
NS
2908 error++;
2909 }
1bc6cbe3 2910 if (anextents != xino.i_d.di_anextents) {
527d1f42 2911 if (v)
9ee7055c
AM
2912 dbprintf(_("bad anextents %d for inode %lld, counted "
2913 "%d\n"),
1bc6cbe3 2914 xino.i_d.di_anextents, id->ino, anextents);
2bd0ea18
NS
2915 error++;
2916 }
2917 if (type == DBM_DIR)
2918 process_dir(dip, blkmap, id);
2919 else if (type == DBM_RTBITMAP)
2920 process_rtbitmap(blkmap);
2921 else if (type == DBM_RTSUM)
2922 process_rtsummary(blkmap);
2923 /*
2924 * If the CHKD flag is not set, this can legitimately contain garbage;
2925 * xfs_repair may have cleared that bit.
2926 */
b36eef04
NS
2927 else if (type == DBM_QUOTA) {
2928 if (id->ino == mp->m_sb.sb_uquotino &&
2929 (mp->m_sb.sb_qflags & XFS_UQUOTA_ACCT) &&
2930 (mp->m_sb.sb_qflags & XFS_UQUOTA_CHKD))
9b27bdbb 2931 process_quota(IS_USER_QUOTA, id, blkmap);
b36eef04
NS
2932 else if (id->ino == mp->m_sb.sb_gquotino &&
2933 (mp->m_sb.sb_qflags & XFS_GQUOTA_ACCT) &&
342aef1e 2934 (mp->m_sb.sb_qflags & XFS_GQUOTA_CHKD))
9b27bdbb 2935 process_quota(IS_GROUP_QUOTA, id, blkmap);
0340d706 2936 else if (id->ino == mp->m_sb.sb_pquotino &&
9b27bdbb 2937 (mp->m_sb.sb_qflags & XFS_PQUOTA_ACCT) &&
342aef1e 2938 (mp->m_sb.sb_qflags & XFS_PQUOTA_CHKD))
9b27bdbb 2939 process_quota(IS_PROJECT_QUOTA, id, blkmap);
b36eef04 2940 }
2bd0ea18
NS
2941 if (blkmap)
2942 blkmap_free(blkmap);
2943}
2944
2945/* ARGSUSED */
2946static void
2947process_lclinode(
2948 inodata_t *id,
2949 xfs_dinode_t *dip,
2950 dbm_t type,
5a35bf2c
DC
2951 xfs_rfsblock_t *totd,
2952 xfs_rfsblock_t *toti,
2bd0ea18
NS
2953 xfs_extnum_t *nex,
2954 blkmap_t **blkmapp,
2955 int whichfork)
2956{
2957 xfs_attr_shortform_t *asf;
2958 xfs_fsblock_t bno;
2bd0ea18 2959
2bd0ea18 2960 bno = XFS_INO_TO_FSB(mp, id->ino);
56b2de80 2961 if (whichfork == XFS_DATA_FORK && be64_to_cpu(dip->di_size) >
5e656dbb 2962 XFS_DFORK_DSIZE(dip, mp)) {
2bd0ea18 2963 if (!sflag || id->ilist || CHECK_BLIST(bno))
9ee7055c
AM
2964 dbprintf(_("local inode %lld data is too large (size "
2965 "%lld)\n"),
56b2de80 2966 id->ino, be64_to_cpu(dip->di_size));
2bd0ea18
NS
2967 error++;
2968 }
2969 else if (whichfork == XFS_ATTR_FORK) {
5e656dbb
BN
2970 asf = (xfs_attr_shortform_t *)XFS_DFORK_APTR(dip);
2971 if (be16_to_cpu(asf->hdr.totsize) > XFS_DFORK_ASIZE(dip, mp)) {
2bd0ea18 2972 if (!sflag || id->ilist || CHECK_BLIST(bno))
9ee7055c
AM
2973 dbprintf(_("local inode %lld attr is too large "
2974 "(size %d)\n"),
5e656dbb 2975 id->ino, be16_to_cpu(asf->hdr.totsize));
2bd0ea18
NS
2976 error++;
2977 }
2978 }
2979}
2980
2bd0ea18
NS
2981static xfs_ino_t
2982process_leaf_node_dir_v2(
2983 blkmap_t *blkmap,
2984 int *dot,
2985 int *dotdot,
2986 inodata_t *id,
2987 xfs_fsize_t dirsize)
2988{
2989 xfs_fsblock_t b;
2990 bbmap_t bbmap;
2991 bmap_ext_t *bmp;
2992 xfs_fileoff_t dbno;
2993 freetab_t *freetab;
2994 int i;
2995 xfs_ino_t lino;
2996 int nex;
2997 xfs_ino_t parent;
bb38a39f 2998 int t = 0;
2bd0ea18
NS
2999 int v;
3000 int v2;
3001 int x;
3002
3003 v2 = verbose || id->ilist;
3004 v = parent = 0;
3005 dbno = NULLFILEOFF;
ff105f75
DC
3006 freetab = malloc(FREETAB_SIZE(dirsize / mp->m_dir_geo->blksize));
3007 freetab->naents = (int)(dirsize / mp->m_dir_geo->blksize);
2bd0ea18
NS
3008 freetab->nents = 0;
3009 for (i = 0; i < freetab->naents; i++)
3010 freetab->ents[i] = NULLDATAOFF;
3011 dir_hash_init();
3012 while ((dbno = blkmap_next_off(blkmap, dbno, &t)) != NULLFILEOFF) {
ff105f75 3013 nex = blkmap_getn(blkmap, dbno, mp->m_dir_geo->fsbcount, &bmp);
2bd0ea18
NS
3014 ASSERT(nex > 0);
3015 for (v = v2, x = 0; !v && x < nex; x++) {
3016 for (b = bmp[x].startblock;
3017 !v && b < bmp[x].startblock + bmp[x].blockcount;
3018 b++)
3019 v = CHECK_BLIST(b);
3020 }
3021 if (v)
9ee7055c 3022 dbprintf(_("dir inode %lld block %u=%llu\n"), id->ino,
14f8b681 3023 (uint32_t)dbno,
5a35bf2c 3024 (xfs_fsblock_t)bmp->startblock);
2bd0ea18
NS
3025 push_cur();
3026 if (nex > 1)
3027 make_bbmap(&bbmap, nex, bmp);
9a048535 3028 set_cur(&typtab[TYP_DIR2], XFS_FSB_TO_DADDR(mp, bmp->startblock),
ff105f75 3029 mp->m_dir_geo->fsbcount * blkbb, DB_RING_IGN,
2bd0ea18
NS
3030 nex > 1 ? &bbmap : NULL);
3031 free(bmp);
3032 if (iocur_top->data == NULL) {
3033 if (!sflag || v)
9ee7055c
AM
3034 dbprintf(_("can't read block %u for directory "
3035 "inode %lld\n"),
14f8b681 3036 (uint32_t)dbno, id->ino);
2bd0ea18
NS
3037 error++;
3038 pop_cur();
ff105f75 3039 dbno += mp->m_dir_geo->fsbcount - 1;
2bd0ea18
NS
3040 continue;
3041 }
ff105f75 3042 if (dbno < mp->m_dir_geo->leafblk) {
2bd0ea18
NS
3043 lino = process_data_dir_v2(dot, dotdot, id, v,
3044 (xfs_dablk_t)dbno, &freetab);
3045 if (lino) {
3046 if (parent) {
3047 if (!sflag || v)
9ee7055c
AM
3048 dbprintf(_("multiple .. entries "
3049 "in dir %lld\n"),
2bd0ea18
NS
3050 id->ino);
3051 error++;
3052 } else
3053 parent = lino;
3054 }
ff105f75 3055 } else if (dbno < mp->m_dir_geo->freeblk) {
2bd0ea18
NS
3056 process_leaf_node_dir_v2_int(id, v, (xfs_dablk_t)dbno,
3057 freetab);
3058 } else {
3059 process_leaf_node_dir_v2_free(id, v, (xfs_dablk_t)dbno,
3060 freetab);
3061 }
3062 pop_cur();
ff105f75 3063 dbno += mp->m_dir_geo->fsbcount - 1;
2bd0ea18
NS
3064 }
3065 dir_hash_check(id, v);
3066 dir_hash_done();
3067 for (i = 0; i < freetab->nents; i++) {
3068 if (freetab->ents[i] != NULLDATAOFF) {
3069 if (!sflag || v)
9ee7055c
AM
3070 dbprintf(_("missing free index for data block %d "
3071 "in dir ino %lld\n"),
ff105f75 3072 xfs_dir2_db_to_da(mp->m_dir_geo, i), id->ino);
2bd0ea18
NS
3073 error++;
3074 }
3075 }
3076 free(freetab);
3077 return parent;
3078}
3079
e96864ff
DW
3080static void
3081process_leaf_node_dir_v3_free(
3082 inodata_t *id,
3083 int v,
3084 xfs_dablk_t dabno,
3085 freetab_t *freetab)
3086{
3087 xfs_dir2_data_off_t ent;
3088 struct xfs_dir3_free *free;
3089 int i;
3090 int maxent;
3091 int used;
3092
3093 free = iocur_top->data;
3094 maxent = M_DIROPS(mp)->free_max_bests(mp->m_dir_geo);
f8149110 3095 if (be32_to_cpu(free->hdr.firstdb) != xfs_dir2_da_to_db(mp->m_dir_geo,
e96864ff
DW
3096 dabno - mp->m_dir_geo->freeblk) * maxent) {
3097 if (!sflag || v)
3098 dbprintf(_("bad free block firstdb %d for dir ino %lld "
3099 "block %d\n"),
3100 be32_to_cpu(free->hdr.firstdb), id->ino, dabno);
3101 error++;
3102 return;
3103 }
f8149110
JT
3104 if (be32_to_cpu(free->hdr.nvalid) > maxent ||
3105 be32_to_cpu(free->hdr.nused) > maxent ||
3106 be32_to_cpu(free->hdr.nused) >
e96864ff
DW
3107 be32_to_cpu(free->hdr.nvalid)) {
3108 if (!sflag || v)
3109 dbprintf(_("bad free block nvalid/nused %d/%d for dir "
3110 "ino %lld block %d\n"),
f8149110 3111 be32_to_cpu(free->hdr.nvalid),
e96864ff
DW
3112 be32_to_cpu(free->hdr.nused), id->ino, dabno);
3113 error++;
3114 return;
3115 }
3116 for (used = i = 0; i < be32_to_cpu(free->hdr.nvalid); i++) {
3117 if (freetab->nents <= be32_to_cpu(free->hdr.firstdb) + i)
3118 ent = NULLDATAOFF;
3119 else
3120 ent = freetab->ents[be32_to_cpu(free->hdr.firstdb) + i];
3121 if (ent != be16_to_cpu(free->bests[i])) {
3122 if (!sflag || v)
3123 dbprintf(_("bad free block ent %d is %d should "
3124 "be %d for dir ino %lld block %d\n"),
f8149110 3125 i, be16_to_cpu(free->bests[i]), ent,
e96864ff
DW
3126 id->ino, dabno);
3127 error++;
3128 }
3129 if (be16_to_cpu(free->bests[i]) != NULLDATAOFF)
3130 used++;
3131 if (ent != NULLDATAOFF)
f8149110 3132 freetab->ents[be32_to_cpu(free->hdr.firstdb) + i] =
e96864ff
DW
3133 NULLDATAOFF;
3134 }
3135 if (used != be32_to_cpu(free->hdr.nused)) {
3136 if (!sflag || v)
3137 dbprintf(_("bad free block nused %d should be %d for dir "
3138 "ino %lld block %d\n"),
f8149110 3139 be32_to_cpu(free->hdr.nused), used, id->ino,
e96864ff
DW
3140 dabno);
3141 error++;
3142 }
3143}
3144
2bd0ea18
NS
3145static void
3146process_leaf_node_dir_v2_free(
3147 inodata_t *id,
3148 int v,
3149 xfs_dablk_t dabno,
3150 freetab_t *freetab)
3151{
3152 xfs_dir2_data_off_t ent;
3153 xfs_dir2_free_t *free;
3154 int i;
3155 int maxent;
3156 int used;
3157
3158 free = iocur_top->data;
e96864ff
DW
3159 if (be32_to_cpu(free->hdr.magic) != XFS_DIR2_FREE_MAGIC &&
3160 be32_to_cpu(free->hdr.magic) != XFS_DIR3_FREE_MAGIC) {
2bd0ea18 3161 if (!sflag || v)
9ee7055c
AM
3162 dbprintf(_("bad free block magic # %#x for dir ino %lld "
3163 "block %d\n"),
5e656dbb 3164 be32_to_cpu(free->hdr.magic), id->ino, dabno);
2bd0ea18
NS
3165 error++;
3166 return;
3167 }
e96864ff
DW
3168 if (be32_to_cpu(free->hdr.magic) == XFS_DIR3_FREE_MAGIC) {
3169 process_leaf_node_dir_v3_free(id, v, dabno, freetab);
3170 return;
3171 }
ff105f75 3172 maxent = M_DIROPS(mp)->free_max_bests(mp->m_dir_geo);
f8149110 3173 if (be32_to_cpu(free->hdr.firstdb) != xfs_dir2_da_to_db(mp->m_dir_geo,
ff105f75 3174 dabno - mp->m_dir_geo->freeblk) * maxent) {
2bd0ea18 3175 if (!sflag || v)
9ee7055c
AM
3176 dbprintf(_("bad free block firstdb %d for dir ino %lld "
3177 "block %d\n"),
5e656dbb 3178 be32_to_cpu(free->hdr.firstdb), id->ino, dabno);
2bd0ea18
NS
3179 error++;
3180 return;
3181 }
f8149110 3182 if (be32_to_cpu(free->hdr.nvalid) > maxent ||
f8149110 3183 be32_to_cpu(free->hdr.nused) > maxent ||
f8149110 3184 be32_to_cpu(free->hdr.nused) >
5e656dbb 3185 be32_to_cpu(free->hdr.nvalid)) {
2bd0ea18 3186 if (!sflag || v)
9ee7055c
AM
3187 dbprintf(_("bad free block nvalid/nused %d/%d for dir "
3188 "ino %lld block %d\n"),
f8149110 3189 be32_to_cpu(free->hdr.nvalid),
5e656dbb 3190 be32_to_cpu(free->hdr.nused), id->ino, dabno);
2bd0ea18
NS
3191 error++;
3192 return;
3193 }
5e656dbb
BN
3194 for (used = i = 0; i < be32_to_cpu(free->hdr.nvalid); i++) {
3195 if (freetab->nents <= be32_to_cpu(free->hdr.firstdb) + i)
2bd0ea18
NS
3196 ent = NULLDATAOFF;
3197 else
5e656dbb
BN
3198 ent = freetab->ents[be32_to_cpu(free->hdr.firstdb) + i];
3199 if (ent != be16_to_cpu(free->bests[i])) {
2bd0ea18 3200 if (!sflag || v)
9ee7055c
AM
3201 dbprintf(_("bad free block ent %d is %d should "
3202 "be %d for dir ino %lld block %d\n"),
f8149110 3203 i, be16_to_cpu(free->bests[i]), ent,
5e656dbb 3204 id->ino, dabno);
2bd0ea18
NS
3205 error++;
3206 }
5e656dbb 3207 if (be16_to_cpu(free->bests[i]) != NULLDATAOFF)
2bd0ea18
NS
3208 used++;
3209 if (ent != NULLDATAOFF)
f8149110 3210 freetab->ents[be32_to_cpu(free->hdr.firstdb) + i] =
5e656dbb 3211 NULLDATAOFF;
2bd0ea18 3212 }
5e656dbb 3213 if (used != be32_to_cpu(free->hdr.nused)) {
2bd0ea18 3214 if (!sflag || v)
9ee7055c
AM
3215 dbprintf(_("bad free block nused %d should be %d for dir "
3216 "ino %lld block %d\n"),
f8149110 3217 be32_to_cpu(free->hdr.nused), used, id->ino,
5e656dbb 3218 dabno);
2bd0ea18
NS
3219 error++;
3220 }
3221}
3222
e96864ff
DW
3223/*
3224 * Get address of the bestcount field in the single-leaf block.
3225 */
3226static inline int
3227xfs_dir3_leaf_ents_count(struct xfs_dir2_leaf *lp)
3228{
3229 if (lp->hdr.info.magic == cpu_to_be16(XFS_DIR3_LEAF1_MAGIC) ||
3230 lp->hdr.info.magic == cpu_to_be16(XFS_DIR3_LEAFN_MAGIC)) {
3231 struct xfs_dir3_leaf *lp3 = (struct xfs_dir3_leaf *)lp;
3232
3233 return be16_to_cpu(lp3->hdr.count);
3234 }
3235 return be16_to_cpu(lp->hdr.count);
3236}
3237
2bd0ea18
NS
3238static void
3239process_leaf_node_dir_v2_int(
3240 inodata_t *id,
3241 int v,
3242 xfs_dablk_t dabno,
3243 freetab_t *freetab)
3244{
3245 int i;
5e656dbb 3246 __be16 *lbp;
2bd0ea18 3247 xfs_dir2_leaf_t *leaf;
e96864ff 3248 struct xfs_dir3_leaf *leaf3 = NULL;
2bd0ea18
NS
3249 xfs_dir2_leaf_entry_t *lep;
3250 xfs_dir2_leaf_tail_t *ltp;
3251 xfs_da_intnode_t *node;
3252 int stale;
88b32f06 3253 struct xfs_da3_icnode_hdr nodehdr;
2bd0ea18
NS
3254
3255 leaf = iocur_top->data;
5e656dbb 3256 switch (be16_to_cpu(leaf->hdr.info.magic)) {
e96864ff
DW
3257 case XFS_DIR3_LEAF1_MAGIC:
3258 case XFS_DIR3_LEAFN_MAGIC:
3259 case XFS_DA3_NODE_MAGIC:
3260 leaf3 = iocur_top->data;
3261 break;
3262 }
3263 switch (be16_to_cpu(leaf->hdr.info.magic)) {
2bd0ea18 3264 case XFS_DIR2_LEAF1_MAGIC:
e96864ff 3265 case XFS_DIR3_LEAF1_MAGIC:
f8149110 3266 if (be32_to_cpu(leaf->hdr.info.forw) ||
5e656dbb 3267 be32_to_cpu(leaf->hdr.info.back)) {
2bd0ea18 3268 if (!sflag || v)
9ee7055c
AM
3269 dbprintf(_("bad leaf block forw/back pointers "
3270 "%d/%d for dir ino %lld block %d\n"),
5e656dbb 3271 be32_to_cpu(leaf->hdr.info.forw),
f8149110 3272 be32_to_cpu(leaf->hdr.info.back),
5e656dbb 3273 id->ino, dabno);
2bd0ea18
NS
3274 error++;
3275 }
ff105f75 3276 if (dabno != mp->m_dir_geo->leafblk) {
2bd0ea18 3277 if (!sflag || v)
9ee7055c
AM
3278 dbprintf(_("single leaf block for dir ino %lld "
3279 "block %d should be at block %d\n"),
2bd0ea18 3280 id->ino, dabno,
ff105f75 3281 (xfs_dablk_t)mp->m_dir_geo->leafblk);
2bd0ea18
NS
3282 error++;
3283 }
ff105f75 3284 ltp = xfs_dir2_leaf_tail_p(mp->m_dir_geo, leaf);
5e656dbb
BN
3285 lbp = xfs_dir2_leaf_bests_p(ltp);
3286 for (i = 0; i < be32_to_cpu(ltp->bestcount); i++) {
f8149110 3287 if (freetab->nents <= i || freetab->ents[i] !=
5e656dbb 3288 be16_to_cpu(lbp[i])) {
2bd0ea18 3289 if (!sflag || v)
9ee7055c 3290 dbprintf(_("bestfree %d for dir ino %lld "
2bd0ea18 3291 "block %d doesn't match table "
9ee7055c 3292 "value %d\n"),
2bd0ea18
NS
3293 freetab->nents <= i ?
3294 NULLDATAOFF :
3295 freetab->ents[i],
3296 id->ino,
ff105f75 3297 xfs_dir2_db_to_da(mp->m_dir_geo, i),
5e656dbb 3298 be16_to_cpu(lbp[i]));
2bd0ea18
NS
3299 }
3300 if (freetab->nents > i)
3301 freetab->ents[i] = NULLDATAOFF;
3302 }
3303 break;
3304 case XFS_DIR2_LEAFN_MAGIC:
e96864ff 3305 case XFS_DIR3_LEAFN_MAGIC:
dfc130f3 3306 /* if it's at the root location then we can check the
2bd0ea18
NS
3307 * pointers are null XXX */
3308 break;
3309 case XFS_DA_NODE_MAGIC:
e96864ff 3310 case XFS_DA3_NODE_MAGIC:
2bd0ea18 3311 node = iocur_top->data;
ff105f75 3312 M_DIROPS(mp)->node_hdr_from_disk(&nodehdr, node);
88b32f06 3313 if (nodehdr.level < 1 || nodehdr.level > XFS_DA_NODE_MAXDEPTH) {
2bd0ea18 3314 if (!sflag || v)
9ee7055c
AM
3315 dbprintf(_("bad node block level %d for dir ino "
3316 "%lld block %d\n"),
f8149110 3317 nodehdr.level, id->ino,
5e656dbb 3318 dabno);
2bd0ea18
NS
3319 error++;
3320 }
3321 return;
3322 default:
3323 if (!sflag || v)
9ee7055c
AM
3324 dbprintf(_("bad directory data magic # %#x for dir ino "
3325 "%lld block %d\n"),
f8149110 3326 be16_to_cpu(leaf->hdr.info.magic), id->ino,
5e656dbb 3327 dabno);
2bd0ea18
NS
3328 error++;
3329 return;
3330 }
ff105f75 3331 lep = M_DIROPS(mp)->leaf_ents_p(leaf);
e96864ff 3332 for (i = stale = 0; i < xfs_dir3_leaf_ents_count(leaf); i++) {
5e656dbb 3333 if (be32_to_cpu(lep[i].address) == XFS_DIR2_NULL_DATAPTR)
2bd0ea18 3334 stale++;
f8149110 3335 else if (dir_hash_see(be32_to_cpu(lep[i].hashval),
5e656dbb 3336 be32_to_cpu(lep[i].address))) {
2bd0ea18 3337 if (!sflag || v)
9ee7055c 3338 dbprintf(_("dir %lld block %d extra leaf entry "
f8149110 3339 "%x %x\n"), id->ino, dabno,
5e656dbb
BN
3340 be32_to_cpu(lep[i].hashval),
3341 be32_to_cpu(lep[i].address));
2bd0ea18
NS
3342 error++;
3343 }
3344 }
e96864ff
DW
3345 if (leaf3 && stale != be16_to_cpu(leaf3->hdr.stale)) {
3346 if (!sflag || v)
3347 dbprintf(_("dir3 %lld block %d stale mismatch "
3348 "%d/%d\n"),
3349 id->ino, dabno, stale,
3350 be16_to_cpu(leaf3->hdr.stale));
3351 error++;
3352 } else if (!leaf && stale != be16_to_cpu(leaf->hdr.stale)) {
2bd0ea18 3353 if (!sflag || v)
9ee7055c
AM
3354 dbprintf(_("dir %lld block %d stale mismatch "
3355 "%d/%d\n"),
2bd0ea18 3356 id->ino, dabno, stale,
5e656dbb 3357 be16_to_cpu(leaf->hdr.stale));
2bd0ea18
NS
3358 error++;
3359 }
3360}
3361
2bd0ea18
NS
3362static void
3363process_quota(
9b27bdbb 3364 qtype_t qtype,
2bd0ea18
NS
3365 inodata_t *id,
3366 blkmap_t *blkmap)
3367{
3368 xfs_fsblock_t bno;
3369 int cb;
3370 xfs_dqblk_t *dqb;
3371 xfs_dqid_t dqid;
81043eae 3372 uint8_t exp_flags = 0;
be8e601c
NS
3373 uint i;
3374 uint perblock;
2bd0ea18 3375 xfs_fileoff_t qbno;
d0600b2b 3376 char *s = NULL;
2bd0ea18 3377 int scicb;
bb38a39f 3378 int t = 0;
2bd0ea18 3379
9b27bdbb
NS
3380 switch (qtype) {
3381 case IS_USER_QUOTA:
3382 s = "user";
3383 exp_flags = XFS_DQ_USER;
3384 break;
3385 case IS_PROJECT_QUOTA:
3386 s = "project";
3387 exp_flags = XFS_DQ_PROJ;
3388 break;
3389 case IS_GROUP_QUOTA:
3390 s = "group";
3391 exp_flags = XFS_DQ_GROUP;
3392 break;
3393 default:
3394 ASSERT(0);
3395 }
3396
be8e601c 3397 perblock = (uint)(mp->m_sb.sb_blocksize / sizeof(*dqb));
2bd0ea18
NS
3398 dqid = 0;
3399 qbno = NULLFILEOFF;
d24c0a90 3400 while ((qbno = blkmap_next_off(blkmap, qbno, &t)) != NULLFILEOFF) {
2bd0ea18
NS
3401 bno = blkmap_get(blkmap, qbno);
3402 dqid = (xfs_dqid_t)qbno * perblock;
3403 cb = CHECK_BLIST(bno);
3404 scicb = !sflag || id->ilist || cb;
3405 push_cur();
3406 set_cur(&typtab[TYP_DQBLK], XFS_FSB_TO_DADDR(mp, bno), blkbb,
3407 DB_RING_IGN, NULL);
3408 if ((dqb = iocur_top->data) == NULL) {
2bd0ea18 3409 if (scicb)
9ee7055c
AM
3410 dbprintf(_("can't read block %lld for %s quota "
3411 "inode (fsblock %lld)\n"),
5a35bf2c
DC
3412 (xfs_fileoff_t)qbno, s,
3413 (xfs_fsblock_t)bno);
2bd0ea18 3414 error++;
d24c0a90 3415 pop_cur();
2bd0ea18
NS
3416 continue;
3417 }
3418 for (i = 0; i < perblock; i++, dqid++, dqb++) {
3419 if (verbose || id->ilist || cb)
9ee7055c
AM
3420 dbprintf(_("%s dqblk %lld entry %d id %u bc "
3421 "%lld ic %lld rc %lld\n"),
5a35bf2c 3422 s, (xfs_fileoff_t)qbno, i, dqid,
5e656dbb
BN
3423 be64_to_cpu(dqb->dd_diskdq.d_bcount),
3424 be64_to_cpu(dqb->dd_diskdq.d_icount),
3425 be64_to_cpu(dqb->dd_diskdq.d_rtbcount));
3426 if (be16_to_cpu(dqb->dd_diskdq.d_magic) != XFS_DQUOT_MAGIC) {
2bd0ea18 3427 if (scicb)
9ee7055c
AM
3428 dbprintf(_("bad magic number %#x for %s "
3429 "dqblk %lld entry %d id %u\n"),
5e656dbb 3430 be16_to_cpu(dqb->dd_diskdq.d_magic), s,
5a35bf2c 3431 (xfs_fileoff_t)qbno, i, dqid);
2bd0ea18
NS
3432 error++;
3433 continue;
3434 }
5e656dbb 3435 if (dqb->dd_diskdq.d_version != XFS_DQUOT_VERSION) {
2bd0ea18 3436 if (scicb)
9ee7055c 3437 dbprintf(_("bad version number %#x for "
2bd0ea18 3438 "%s dqblk %lld entry %d id "
9ee7055c 3439 "%u\n"),
5e656dbb 3440 dqb->dd_diskdq.d_version, s,
5a35bf2c 3441 (xfs_fileoff_t)qbno, i, dqid);
2bd0ea18
NS
3442 error++;
3443 continue;
3444 }
5e656dbb 3445 if (dqb->dd_diskdq.d_flags != exp_flags) {
2bd0ea18 3446 if (scicb)
9ee7055c
AM
3447 dbprintf(_("bad flags %#x for %s dqblk "
3448 "%lld entry %d id %u\n"),
5e656dbb 3449 dqb->dd_diskdq.d_flags, s,
5a35bf2c 3450 (xfs_fileoff_t)qbno, i, dqid);
2bd0ea18
NS
3451 error++;
3452 continue;
3453 }
5e656dbb 3454 if (be32_to_cpu(dqb->dd_diskdq.d_id) != dqid) {
2bd0ea18 3455 if (scicb)
9ee7055c
AM
3456 dbprintf(_("bad id %u for %s dqblk %lld "
3457 "entry %d id %u\n"),
5e656dbb 3458 be32_to_cpu(dqb->dd_diskdq.d_id), s,
5a35bf2c 3459 (xfs_fileoff_t)qbno, i, dqid);
2bd0ea18
NS
3460 error++;
3461 continue;
3462 }
be8e601c
NS
3463 quota_add((qtype == IS_PROJECT_QUOTA) ? &dqid : NULL,
3464 (qtype == IS_GROUP_QUOTA) ? &dqid : NULL,
3465 (qtype == IS_USER_QUOTA) ? &dqid : NULL,
9b27bdbb 3466 1,
5e656dbb
BN
3467 be64_to_cpu(dqb->dd_diskdq.d_bcount),
3468 be64_to_cpu(dqb->dd_diskdq.d_icount),
3469 be64_to_cpu(dqb->dd_diskdq.d_rtbcount));
2bd0ea18
NS
3470 }
3471 pop_cur();
3472 }
3473}
3474
3475static void
3476process_rtbitmap(
3477 blkmap_t *blkmap)
3478{
2bd0ea18
NS
3479 int bit;
3480 int bitsperblock;
3481 xfs_fileoff_t bmbno;
3482 xfs_fsblock_t bno;
5a35bf2c 3483 xfs_rtblock_t extno;
2bd0ea18
NS
3484 int len;
3485 int log;
3486 int offs;
3487 int prevbit;
5a35bf2c 3488 xfs_rfsblock_t rtbno;
2bd0ea18
NS
3489 int start_bmbno;
3490 int start_bit;
3491 int t;
3492 xfs_rtword_t *words;
3493
3494 bitsperblock = mp->m_sb.sb_blocksize * NBBY;
3495 bit = extno = prevbit = start_bmbno = start_bit = 0;
3496 bmbno = NULLFILEOFF;
3497 while ((bmbno = blkmap_next_off(blkmap, bmbno, &t)) !=
3498 NULLFILEOFF) {
3499 bno = blkmap_get(blkmap, bmbno);
3500 if (bno == NULLFSBLOCK) {
3501 if (!sflag)
9ee7055c
AM
3502 dbprintf(_("block %lld for rtbitmap inode is "
3503 "missing\n"),
5a35bf2c 3504 (xfs_fileoff_t)bmbno);
2bd0ea18
NS
3505 error++;
3506 continue;
3507 }
3508 push_cur();
3509 set_cur(&typtab[TYP_RTBITMAP], XFS_FSB_TO_DADDR(mp, bno), blkbb,
3510 DB_RING_IGN, NULL);
3511 if ((words = iocur_top->data) == NULL) {
2bd0ea18 3512 if (!sflag)
9ee7055c
AM
3513 dbprintf(_("can't read block %lld for rtbitmap "
3514 "inode\n"),
5a35bf2c 3515 (xfs_fileoff_t)bmbno);
2bd0ea18 3516 error++;
d24c0a90 3517 pop_cur();
2bd0ea18
NS
3518 continue;
3519 }
3520 for (bit = 0;
3521 bit < bitsperblock && extno < mp->m_sb.sb_rextents;
3522 bit++, extno++) {
a580302f 3523 if (xfs_isset(words, bit)) {
2bd0ea18
NS
3524 rtbno = extno * mp->m_sb.sb_rextsize;
3525 set_rdbmap(rtbno, mp->m_sb.sb_rextsize,
3526 DBM_RTFREE);
3527 frextents++;
3528 if (prevbit == 0) {
3529 start_bmbno = (int)bmbno;
3530 start_bit = bit;
3531 prevbit = 1;
3532 }
3533 } else if (prevbit == 1) {
3534 len = ((int)bmbno - start_bmbno) *
3535 bitsperblock + (bit - start_bit);
3536 log = XFS_RTBLOCKLOG(len);
3537 offs = XFS_SUMOFFS(mp, log, start_bmbno);
3538 sumcompute[offs]++;
3539 prevbit = 0;
3540 }
3541 }
3542 pop_cur();
3543 if (extno == mp->m_sb.sb_rextents)
3544 break;
3545 }
3546 if (prevbit == 1) {
3547 len = ((int)bmbno - start_bmbno) * bitsperblock +
3548 (bit - start_bit);
3549 log = XFS_RTBLOCKLOG(len);
3550 offs = XFS_SUMOFFS(mp, log, start_bmbno);
3551 sumcompute[offs]++;
3552 }
3553}
3554
3555static void
3556process_rtsummary(
3557 blkmap_t *blkmap)
3558{
3559 xfs_fsblock_t bno;
3560 char *bytes;
3561 xfs_fileoff_t sumbno;
3562 int t;
3563
3564 sumbno = NULLFILEOFF;
d24c0a90 3565 while ((sumbno = blkmap_next_off(blkmap, sumbno, &t)) != NULLFILEOFF) {
2bd0ea18
NS
3566 bno = blkmap_get(blkmap, sumbno);
3567 if (bno == NULLFSBLOCK) {
3568 if (!sflag)
9ee7055c
AM
3569 dbprintf(_("block %lld for rtsummary inode is "
3570 "missing\n"),
5a35bf2c 3571 (xfs_fileoff_t)sumbno);
2bd0ea18
NS
3572 error++;
3573 continue;
3574 }
3575 push_cur();
3576 set_cur(&typtab[TYP_RTSUMMARY], XFS_FSB_TO_DADDR(mp, bno),
3577 blkbb, DB_RING_IGN, NULL);
3578 if ((bytes = iocur_top->data) == NULL) {
3579 if (!sflag)
9ee7055c
AM
3580 dbprintf(_("can't read block %lld for rtsummary "
3581 "inode\n"),
5a35bf2c 3582 (xfs_fileoff_t)sumbno);
2bd0ea18 3583 error++;
d24c0a90 3584 pop_cur();
2bd0ea18
NS
3585 continue;
3586 }
3587 memcpy((char *)sumfile + sumbno * mp->m_sb.sb_blocksize, bytes,
3588 mp->m_sb.sb_blocksize);
3589 pop_cur();
3590 }
3591}
3592
3593static xfs_ino_t
3594process_sf_dir_v2(
3595 xfs_dinode_t *dip,
3596 int *dot,
3597 int *dotdot,
3598 inodata_t *id)
3599{
3600 inodata_t *cid;
3601 int i;
3602 int i8;
3603 xfs_ino_t lino;
3604 int offset;
eb0cb950 3605 struct xfs_dir2_sf_hdr *sf;
2bd0ea18
NS
3606 xfs_dir2_sf_entry_t *sfe;
3607 int v;
3608
eb0cb950 3609 sf = (struct xfs_dir2_sf_hdr *)XFS_DFORK_DPTR(dip);
2bd0ea18
NS
3610 addlink_inode(id);
3611 v = verbose || id->ilist;
3612 if (v)
9ee7055c 3613 dbprintf(_("dir %lld entry . %lld\n"), id->ino, id->ino);
2bd0ea18 3614 (*dot)++;
eb0cb950 3615 sfe = xfs_dir2_sf_firstentry(sf);
ff105f75 3616 offset = M_DIROPS(mp)->data_first_offset;
eb0cb950 3617 for (i = sf->count - 1, i8 = 0; i >= 0; i--) {
ee6cd73e
CH
3618 if ((intptr_t)sfe + M_DIROPS(mp)->sf_entsize(sf, sfe->namelen) -
3619 (intptr_t)sf > be64_to_cpu(dip->di_size)) {
2bd0ea18 3620 if (!sflag)
9ee7055c 3621 dbprintf(_("dir %llu bad size in entry at %d\n"),
2bd0ea18
NS
3622 id->ino,
3623 (int)((char *)sfe - (char *)sf));
3624 error++;
3625 break;
3626 }
ff105f75 3627 lino = M_DIROPS(mp)->sf_get_ino(sf, sfe);
2bd0ea18
NS
3628 if (lino > XFS_DIR2_MAX_SHORT_INUM)
3629 i8++;
3630 cid = find_inode(lino, 1);
3631 if (cid == NULL) {
3632 if (!sflag)
9ee7055c
AM
3633 dbprintf(_("dir %lld entry %*.*s bad inode "
3634 "number %lld\n"),
2bd0ea18
NS
3635 id->ino, sfe->namelen, sfe->namelen,
3636 sfe->name, lino);
3637 error++;
3638 } else {
3639 addlink_inode(cid);
3640 if (!cid->parent)
3641 cid->parent = id;
3642 addname_inode(cid, (char *)sfe->name, sfe->namelen);
3643 }
3644 if (v)
9ee7055c 3645 dbprintf(_("dir %lld entry %*.*s offset %d %lld\n"),
2bd0ea18 3646 id->ino, sfe->namelen, sfe->namelen, sfe->name,
5e656dbb
BN
3647 xfs_dir2_sf_get_offset(sfe), lino);
3648 if (xfs_dir2_sf_get_offset(sfe) < offset) {
2bd0ea18 3649 if (!sflag)
9ee7055c 3650 dbprintf(_("dir %lld entry %*.*s bad offset %d\n"),
2bd0ea18 3651 id->ino, sfe->namelen, sfe->namelen,
5e656dbb 3652 sfe->name, xfs_dir2_sf_get_offset(sfe));
2bd0ea18
NS
3653 error++;
3654 }
3655 offset =
5e656dbb 3656 xfs_dir2_sf_get_offset(sfe) +
ff105f75
DC
3657 M_DIROPS(mp)->sf_entsize(sf, sfe->namelen);
3658 sfe = M_DIROPS(mp)->sf_nextentry(sf, sfe);
2bd0ea18 3659 }
f8149110 3660 if (i < 0 && (intptr_t)sfe - (intptr_t)sf !=
56b2de80 3661 be64_to_cpu(dip->di_size)) {
2bd0ea18 3662 if (!sflag)
9ee7055c 3663 dbprintf(_("dir %llu size is %lld, should be %u\n"),
56b2de80 3664 id->ino, be64_to_cpu(dip->di_size),
2bd0ea18
NS
3665 (uint)((char *)sfe - (char *)sf));
3666 error++;
3667 }
eb0cb950 3668 if (offset + (sf->count + 2) * sizeof(xfs_dir2_leaf_entry_t) +
ff105f75 3669 sizeof(xfs_dir2_block_tail_t) > mp->m_dir_geo->blksize) {
2bd0ea18 3670 if (!sflag)
9ee7055c 3671 dbprintf(_("dir %llu offsets too high\n"), id->ino);
2bd0ea18
NS
3672 error++;
3673 }
ff105f75 3674 lino = M_DIROPS(mp)->sf_get_parent_ino(sf);
2bd0ea18
NS
3675 if (lino > XFS_DIR2_MAX_SHORT_INUM)
3676 i8++;
3677 cid = find_inode(lino, 1);
3678 if (cid)
3679 addlink_inode(cid);
3680 else {
3681 if (!sflag)
9ee7055c 3682 dbprintf(_("dir %lld entry .. bad inode number %lld\n"),
2bd0ea18
NS
3683 id->ino, lino);
3684 error++;
3685 }
3686 if (v)
9ee7055c 3687 dbprintf(_("dir %lld entry .. %lld\n"), id->ino, lino);
eb0cb950 3688 if (i8 != sf->i8count) {
2bd0ea18 3689 if (!sflag)
9ee7055c
AM
3690 dbprintf(_("dir %lld i8count mismatch is %d should be "
3691 "%d\n"),
eb0cb950 3692 id->ino, sf->i8count, i8);
2bd0ea18
NS
3693 error++;
3694 }
3695 (*dotdot)++;
3696 return cid ? lino : NULLFSINO;
3697}
3698
2bd0ea18
NS
3699
3700static void
3701quota_add(
be8e601c
NS
3702 xfs_dqid_t *prjid,
3703 xfs_dqid_t *grpid,
3704 xfs_dqid_t *usrid,
2bd0ea18
NS
3705 int dq,
3706 xfs_qcnt_t bc,
3707 xfs_qcnt_t ic,
3708 xfs_qcnt_t rc)
3709{
be8e601c
NS
3710 if (qudo && usrid != NULL)
3711 quota_add1(qudata, *usrid, dq, bc, ic, rc);
3712 if (qgdo && grpid != NULL)
3713 quota_add1(qgdata, *grpid, dq, bc, ic, rc);
3714 if (qpdo && prjid != NULL)
3715 quota_add1(qpdata, *prjid, dq, bc, ic, rc);
2bd0ea18
NS
3716}
3717
3718static void
3719quota_add1(
3720 qdata_t **qt,
3721 xfs_dqid_t id,
3722 int dq,
3723 xfs_qcnt_t bc,
3724 xfs_qcnt_t ic,
3725 xfs_qcnt_t rc)
3726{
3727 qdata_t *qe;
3728 int qh;
3729 qinfo_t *qi;
3730
be8e601c 3731 qh = (int)(id % QDATA_HASH_SIZE);
2bd0ea18
NS
3732 qe = qt[qh];
3733 while (qe) {
3734 if (qe->id == id) {
3735 qi = dq ? &qe->dq : &qe->count;
3736 qi->bc += bc;
3737 qi->ic += ic;
3738 qi->rc += rc;
3739 return;
3740 }
3741 qe = qe->next;
3742 }
3743 qe = xmalloc(sizeof(*qe));
3744 qe->id = id;
3745 qi = dq ? &qe->dq : &qe->count;
3746 qi->bc = bc;
3747 qi->ic = ic;
3748 qi->rc = rc;
3749 qi = dq ? &qe->count : &qe->dq;
3750 qi->bc = qi->ic = qi->rc = 0;
3751 qe->next = qt[qh];
3752 qt[qh] = qe;
3753}
3754
3755static void
3756quota_check(
3757 char *s,
3758 qdata_t **qt)
3759{
3760 int i;
3761 qdata_t *next;
3762 qdata_t *qp;
3763
3764 for (i = 0; i < QDATA_HASH_SIZE; i++) {
3765 qp = qt[i];
3766 while (qp) {
3767 next = qp->next;
3768 if (qp->count.bc != qp->dq.bc ||
3769 qp->count.ic != qp->dq.ic ||
3770 qp->count.rc != qp->dq.rc) {
3771 if (!sflag) {
9ee7055c 3772 dbprintf(_("%s quota id %u, have/exp"),
2bd0ea18
NS
3773 s, qp->id);
3774 if (qp->count.bc != qp->dq.bc)
9ee7055c 3775 dbprintf(_(" bc %lld/%lld"),
2bd0ea18
NS
3776 qp->dq.bc,
3777 qp->count.bc);
3778 if (qp->count.ic != qp->dq.ic)
9ee7055c 3779 dbprintf(_(" ic %lld/%lld"),
2bd0ea18
NS
3780 qp->dq.ic,
3781 qp->count.ic);
3782 if (qp->count.rc != qp->dq.rc)
9ee7055c 3783 dbprintf(_(" rc %lld/%lld"),
2bd0ea18
NS
3784 qp->dq.rc,
3785 qp->count.rc);
3786 dbprintf("\n");
3787 }
3788 error++;
3789 }
3790 xfree(qp);
3791 qp = next;
3792 }
3793 }
3794 xfree(qt);
3795}
3796
3797static void
3798quota_init(void)
3799{
3800 qudo = mp->m_sb.sb_uquotino != 0 &&
3801 mp->m_sb.sb_uquotino != NULLFSINO &&
b36eef04 3802 (mp->m_sb.sb_qflags & XFS_UQUOTA_ACCT) &&
2bd0ea18 3803 (mp->m_sb.sb_qflags & XFS_UQUOTA_CHKD);
b36eef04
NS
3804 qgdo = mp->m_sb.sb_gquotino != 0 &&
3805 mp->m_sb.sb_gquotino != NULLFSINO &&
3806 (mp->m_sb.sb_qflags & XFS_GQUOTA_ACCT) &&
342aef1e 3807 (mp->m_sb.sb_qflags & XFS_GQUOTA_CHKD);
0340d706
CS
3808 qpdo = mp->m_sb.sb_pquotino != 0 &&
3809 mp->m_sb.sb_pquotino != NULLFSINO &&
9b27bdbb 3810 (mp->m_sb.sb_qflags & XFS_PQUOTA_ACCT) &&
342aef1e 3811 (mp->m_sb.sb_qflags & XFS_PQUOTA_CHKD);
2bd0ea18
NS
3812 if (qudo)
3813 qudata = xcalloc(QDATA_HASH_SIZE, sizeof(qdata_t *));
b36eef04
NS
3814 if (qgdo)
3815 qgdata = xcalloc(QDATA_HASH_SIZE, sizeof(qdata_t *));
9b27bdbb
NS
3816 if (qpdo)
3817 qpdata = xcalloc(QDATA_HASH_SIZE, sizeof(qdata_t *));
2bd0ea18
NS
3818}
3819
3820static void
3821scan_ag(
3822 xfs_agnumber_t agno)
3823{
3824 xfs_agf_t *agf;
3825 xfs_agi_t *agi;
3826 int i;
3827 xfs_sb_t tsb;
5e656dbb 3828 xfs_sb_t *sb = &tsb;
2bd0ea18
NS
3829
3830 agffreeblks = agflongest = 0;
cdded3d8 3831 agfbtreeblks = -2;
2bd0ea18 3832 agicount = agifreecount = 0;
d24c0a90 3833 push_cur(); /* 1 pushed */
9440d84d
NS
3834 set_cur(&typtab[TYP_SB],
3835 XFS_AG_DADDR(mp, agno, XFS_SB_DADDR),
3836 XFS_FSS_TO_BB(mp, 1), DB_RING_IGN, NULL);
dfc130f3 3837
2bd0ea18 3838 if (!iocur_top->data) {
9ee7055c 3839 dbprintf(_("can't read superblock for ag %u\n"), agno);
2bd0ea18 3840 serious_error++;
d24c0a90 3841 goto pop1_out;
2bd0ea18 3842 }
dfc130f3 3843
5e656dbb 3844 libxfs_sb_from_disk(sb, iocur_top->data);
dfc130f3 3845
2bd0ea18
NS
3846 if (sb->sb_magicnum != XFS_SB_MAGIC) {
3847 if (!sflag)
9ee7055c 3848 dbprintf(_("bad sb magic # %#x in ag %u\n"),
2bd0ea18
NS
3849 sb->sb_magicnum, agno);
3850 error++;
3851 }
5e656dbb 3852 if (!xfs_sb_good_version(sb)) {
2bd0ea18 3853 if (!sflag)
9ee7055c 3854 dbprintf(_("bad sb version # %#x in ag %u\n"),
2bd0ea18
NS
3855 sb->sb_versionnum, agno);
3856 error++;
3857 sbver_err++;
3858 }
5e656dbb 3859 if (!lazycount && xfs_sb_version_haslazysbcount(sb)) {
cdded3d8
DC
3860 lazycount = 1;
3861 }
2bd0ea18
NS
3862 if (agno == 0 && sb->sb_inprogress != 0) {
3863 if (!sflag)
9ee7055c 3864 dbprintf(_("mkfs not completed successfully\n"));
2bd0ea18
NS
3865 error++;
3866 }
3867 set_dbmap(agno, XFS_SB_BLOCK(mp), 1, DBM_SB, agno, XFS_SB_BLOCK(mp));
3868 if (sb->sb_logstart && XFS_FSB_TO_AGNO(mp, sb->sb_logstart) == agno)
3869 set_dbmap(agno, XFS_FSB_TO_AGBNO(mp, sb->sb_logstart),
3870 sb->sb_logblocks, DBM_LOG, agno, XFS_SB_BLOCK(mp));
d24c0a90 3871 push_cur(); /* 2 pushed */
9440d84d
NS
3872 set_cur(&typtab[TYP_AGF],
3873 XFS_AG_DADDR(mp, agno, XFS_AGF_DADDR(mp)),
3874 XFS_FSS_TO_BB(mp, 1), DB_RING_IGN, NULL);
2bd0ea18 3875 if ((agf = iocur_top->data) == NULL) {
9ee7055c 3876 dbprintf(_("can't read agf block for ag %u\n"), agno);
2bd0ea18 3877 serious_error++;
d24c0a90 3878 goto pop2_out;
2bd0ea18 3879 }
5e656dbb 3880 if (be32_to_cpu(agf->agf_magicnum) != XFS_AGF_MAGIC) {
2bd0ea18 3881 if (!sflag)
9ee7055c 3882 dbprintf(_("bad agf magic # %#x in ag %u\n"),
5e656dbb 3883 be32_to_cpu(agf->agf_magicnum), agno);
2bd0ea18
NS
3884 error++;
3885 }
5e656dbb 3886 if (!XFS_AGF_GOOD_VERSION(be32_to_cpu(agf->agf_versionnum))) {
2bd0ea18 3887 if (!sflag)
9ee7055c 3888 dbprintf(_("bad agf version # %#x in ag %u\n"),
5e656dbb 3889 be32_to_cpu(agf->agf_versionnum), agno);
2bd0ea18
NS
3890 error++;
3891 }
3892 if (XFS_SB_BLOCK(mp) != XFS_AGF_BLOCK(mp))
3893 set_dbmap(agno, XFS_AGF_BLOCK(mp), 1, DBM_AGF, agno,
3894 XFS_SB_BLOCK(mp));
5e656dbb
BN
3895 if (sb->sb_agblocks > be32_to_cpu(agf->agf_length))
3896 set_dbmap(agno, be32_to_cpu(agf->agf_length),
3897 sb->sb_agblocks - be32_to_cpu(agf->agf_length),
2bd0ea18 3898 DBM_MISSING, agno, XFS_SB_BLOCK(mp));
d24c0a90 3899 push_cur(); /* 3 pushed */
9440d84d
NS
3900 set_cur(&typtab[TYP_AGI],
3901 XFS_AG_DADDR(mp, agno, XFS_AGI_DADDR(mp)),
3902 XFS_FSS_TO_BB(mp, 1), DB_RING_IGN, NULL);
2bd0ea18 3903 if ((agi = iocur_top->data) == NULL) {
9ee7055c 3904 dbprintf(_("can't read agi block for ag %u\n"), agno);
2bd0ea18 3905 serious_error++;
d24c0a90 3906 goto pop3_out;
2bd0ea18 3907 }
5e656dbb 3908 if (be32_to_cpu(agi->agi_magicnum) != XFS_AGI_MAGIC) {
2bd0ea18 3909 if (!sflag)
9ee7055c 3910 dbprintf(_("bad agi magic # %#x in ag %u\n"),
5e656dbb 3911 be32_to_cpu(agi->agi_magicnum), agno);
2bd0ea18
NS
3912 error++;
3913 }
5e656dbb 3914 if (!XFS_AGI_GOOD_VERSION(be32_to_cpu(agi->agi_versionnum))) {
2bd0ea18 3915 if (!sflag)
9ee7055c 3916 dbprintf(_("bad agi version # %#x in ag %u\n"),
5e656dbb 3917 be32_to_cpu(agi->agi_versionnum), agno);
2bd0ea18
NS
3918 error++;
3919 }
3920 if (XFS_SB_BLOCK(mp) != XFS_AGI_BLOCK(mp) &&
3921 XFS_AGF_BLOCK(mp) != XFS_AGI_BLOCK(mp))
3922 set_dbmap(agno, XFS_AGI_BLOCK(mp), 1, DBM_AGI, agno,
3923 XFS_SB_BLOCK(mp));
3924 scan_freelist(agf);
3925 fdblocks--;
3926 scan_sbtree(agf,
5e656dbb
BN
3927 be32_to_cpu(agf->agf_roots[XFS_BTNUM_BNO]),
3928 be32_to_cpu(agf->agf_levels[XFS_BTNUM_BNO]),
2bd0ea18
NS
3929 1, scanfunc_bno, TYP_BNOBT);
3930 fdblocks--;
3931 scan_sbtree(agf,
5e656dbb
BN
3932 be32_to_cpu(agf->agf_roots[XFS_BTNUM_CNT]),
3933 be32_to_cpu(agf->agf_levels[XFS_BTNUM_CNT]),
2bd0ea18 3934 1, scanfunc_cnt, TYP_CNTBT);
e3dcc17b
DW
3935 if (agf->agf_roots[XFS_BTNUM_RMAP]) {
3936 scan_sbtree(agf,
3937 be32_to_cpu(agf->agf_roots[XFS_BTNUM_RMAP]),
3938 be32_to_cpu(agf->agf_levels[XFS_BTNUM_RMAP]),
3939 1, scanfunc_rmap, TYP_RMAPBT);
3940 }
757ad8c7
DW
3941 if (agf->agf_refcount_root) {
3942 scan_sbtree(agf,
3943 be32_to_cpu(agf->agf_refcount_root),
3944 be32_to_cpu(agf->agf_refcount_level),
3945 1, scanfunc_refcnt, TYP_REFCBT);
3946 }
2bd0ea18 3947 scan_sbtree(agf,
5e656dbb
BN
3948 be32_to_cpu(agi->agi_root),
3949 be32_to_cpu(agi->agi_level),
2bd0ea18 3950 1, scanfunc_ino, TYP_INOBT);
e96864ff
DW
3951 if (agi->agi_free_root) {
3952 scan_sbtree(agf,
3953 be32_to_cpu(agi->agi_free_root),
3954 be32_to_cpu(agi->agi_free_level),
3955 1, scanfunc_fino, TYP_FINOBT);
3956 }
5e656dbb 3957 if (be32_to_cpu(agf->agf_freeblks) != agffreeblks) {
2bd0ea18 3958 if (!sflag)
9ee7055c 3959 dbprintf(_("agf_freeblks %u, counted %u in ag %u\n"),
5e656dbb 3960 be32_to_cpu(agf->agf_freeblks),
2bd0ea18
NS
3961 agffreeblks, agno);
3962 error++;
3963 }
5e656dbb 3964 if (be32_to_cpu(agf->agf_longest) != agflongest) {
2bd0ea18 3965 if (!sflag)
9ee7055c 3966 dbprintf(_("agf_longest %u, counted %u in ag %u\n"),
5e656dbb 3967 be32_to_cpu(agf->agf_longest),
2bd0ea18
NS
3968 agflongest, agno);
3969 error++;
3970 }
cdded3d8 3971 if (lazycount &&
5e656dbb 3972 be32_to_cpu(agf->agf_btreeblks) != agfbtreeblks) {
cdded3d8 3973 if (!sflag)
9ee7055c 3974 dbprintf(_("agf_btreeblks %u, counted %u in ag %u\n"),
5e656dbb 3975 be32_to_cpu(agf->agf_btreeblks),
cdded3d8
DC
3976 agfbtreeblks, agno);
3977 error++;
3978 }
3979 agf_aggr_freeblks += agffreeblks + agfbtreeblks;
5e656dbb 3980 if (be32_to_cpu(agi->agi_count) != agicount) {
2bd0ea18 3981 if (!sflag)
9ee7055c 3982 dbprintf(_("agi_count %u, counted %u in ag %u\n"),
5e656dbb 3983 be32_to_cpu(agi->agi_count),
2bd0ea18
NS
3984 agicount, agno);
3985 error++;
3986 }
5e656dbb 3987 if (be32_to_cpu(agi->agi_freecount) != agifreecount) {
2bd0ea18 3988 if (!sflag)
9ee7055c 3989 dbprintf(_("agi_freecount %u, counted %u in ag %u\n"),
5e656dbb 3990 be32_to_cpu(agi->agi_freecount),
2bd0ea18
NS
3991 agifreecount, agno);
3992 error++;
3993 }
3994 for (i = 0; i < XFS_AGI_UNLINKED_BUCKETS; i++) {
5e656dbb 3995 if (be32_to_cpu(agi->agi_unlinked[i]) != NULLAGINO) {
2bd0ea18 3996 if (!sflag) {
5e656dbb 3997 xfs_agino_t agino=be32_to_cpu(agi->agi_unlinked[i]);
9ee7055c
AM
3998 dbprintf(_("agi unlinked bucket %d is %u in ag "
3999 "%u (inode=%lld)\n"), i, agino, agno,
dfc130f3
RC
4000 XFS_AGINO_TO_INO(mp, agno, agino));
4001 }
2bd0ea18
NS
4002 error++;
4003 }
4004 }
d24c0a90 4005pop3_out:
2bd0ea18 4006 pop_cur();
d24c0a90 4007pop2_out:
2bd0ea18 4008 pop_cur();
d24c0a90 4009pop1_out:
2bd0ea18
NS
4010 pop_cur();
4011}
4012
581c24aa
DW
4013struct agfl_state {
4014 xfs_agnumber_t agno;
4015 unsigned int count;
4016};
4017
4018static int
4019scan_agfl(
4020 struct xfs_mount *mp,
4021 xfs_agblock_t bno,
4022 void *priv)
4023{
4024 struct agfl_state *as = priv;
4025
4026 set_dbmap(as->agno, bno, 1, DBM_FREELIST, as->agno, XFS_AGFL_BLOCK(mp));
4027 as->count++;
4028 return 0;
4029}
4030
2bd0ea18
NS
4031static void
4032scan_freelist(
581c24aa 4033 xfs_agf_t *agf)
2bd0ea18 4034{
581c24aa
DW
4035 xfs_agnumber_t seqno = be32_to_cpu(agf->agf_seqno);
4036 struct agfl_state state;
2bd0ea18
NS
4037
4038 if (XFS_SB_BLOCK(mp) != XFS_AGFL_BLOCK(mp) &&
4039 XFS_AGF_BLOCK(mp) != XFS_AGFL_BLOCK(mp) &&
4040 XFS_AGI_BLOCK(mp) != XFS_AGFL_BLOCK(mp))
4041 set_dbmap(seqno, XFS_AGFL_BLOCK(mp), 1, DBM_AGFL, seqno,
4042 XFS_SB_BLOCK(mp));
5e656dbb 4043 if (be32_to_cpu(agf->agf_flcount) == 0)
2bd0ea18
NS
4044 return;
4045 push_cur();
4046 set_cur(&typtab[TYP_AGFL],
9440d84d
NS
4047 XFS_AG_DADDR(mp, seqno, XFS_AGFL_DADDR(mp)),
4048 XFS_FSS_TO_BB(mp, 1), DB_RING_IGN, NULL);
581c24aa 4049 if (iocur_top->data == NULL) {
9ee7055c 4050 dbprintf(_("can't read agfl block for ag %u\n"), seqno);
2bd0ea18 4051 serious_error++;
d24c0a90 4052 pop_cur();
2bd0ea18
NS
4053 return;
4054 }
a529cc7f
ES
4055
4056 /* verify agf values before proceeding */
b8165508
DC
4057 if (be32_to_cpu(agf->agf_flfirst) >= libxfs_agfl_size(mp) ||
4058 be32_to_cpu(agf->agf_fllast) >= libxfs_agfl_size(mp)) {
a529cc7f 4059 dbprintf(_("agf %d freelist blocks bad, skipping "
581c24aa 4060 "freelist scan\n"), seqno);
a529cc7f
ES
4061 pop_cur();
4062 return;
4063 }
4064
84232448 4065 /* open coded XFS_BUF_TO_AGFL_BNO */
581c24aa
DW
4066 state.count = 0;
4067 state.agno = seqno;
4068 libxfs_agfl_walk(mp, agf, iocur_top->bp, scan_agfl, &state);
4069 if (state.count != be32_to_cpu(agf->agf_flcount)) {
2bd0ea18 4070 if (!sflag)
9ee7055c 4071 dbprintf(_("freeblk count %u != flcount %u in ag %u\n"),
581c24aa
DW
4072 state.count,
4073 be32_to_cpu(agf->agf_flcount),
4074 seqno);
2bd0ea18
NS
4075 error++;
4076 }
581c24aa
DW
4077 fdblocks += state.count;
4078 agf_aggr_freeblks += state.count;
2bd0ea18
NS
4079 pop_cur();
4080}
4081
4082static void
4083scan_lbtree(
4084 xfs_fsblock_t root,
4085 int nlevels,
4086 scan_lbtree_f_t func,
4087 dbm_t type,
4088 inodata_t *id,
5a35bf2c
DC
4089 xfs_rfsblock_t *totd,
4090 xfs_rfsblock_t *toti,
2bd0ea18
NS
4091 xfs_extnum_t *nex,
4092 blkmap_t **blkmapp,
4093 int isroot,
4094 typnm_t btype)
4095{
4096 push_cur();
4097 set_cur(&typtab[btype], XFS_FSB_TO_DADDR(mp, root), blkbb, DB_RING_IGN,
4098 NULL);
4099 if (iocur_top->data == NULL) {
4100 if (!sflag)
9ee7055c 4101 dbprintf(_("can't read btree block %u/%u\n"),
2bd0ea18
NS
4102 XFS_FSB_TO_AGNO(mp, root),
4103 XFS_FSB_TO_AGBNO(mp, root));
4104 error++;
d24c0a90 4105 pop_cur();
2bd0ea18
NS
4106 return;
4107 }
4108 (*func)(iocur_top->data, nlevels - 1, type, root, id, totd, toti, nex,
4109 blkmapp, isroot, btype);
4110 pop_cur();
4111}
4112
4113static void
4114scan_sbtree(
4115 xfs_agf_t *agf,
4116 xfs_agblock_t root,
4117 int nlevels,
4118 int isroot,
4119 scan_sbtree_f_t func,
4120 typnm_t btype)
4121{
5e656dbb 4122 xfs_agnumber_t seqno = be32_to_cpu(agf->agf_seqno);
2bd0ea18
NS
4123
4124 push_cur();
4125 set_cur(&typtab[btype],
4126 XFS_AGB_TO_DADDR(mp, seqno, root), blkbb, DB_RING_IGN, NULL);
4127 if (iocur_top->data == NULL) {
4128 if (!sflag)
9ee7055c 4129 dbprintf(_("can't read btree block %u/%u\n"), seqno, root);
2bd0ea18 4130 error++;
d24c0a90 4131 pop_cur();
2bd0ea18
NS
4132 return;
4133 }
4134 (*func)(iocur_top->data, nlevels - 1, agf, root, isroot);
4135 pop_cur();
4136}
4137
4138static void
4139scanfunc_bmap(
b3563c19 4140 struct xfs_btree_block *block,
2bd0ea18
NS
4141 int level,
4142 dbm_t type,
4143 xfs_fsblock_t bno,
4144 inodata_t *id,
5a35bf2c
DC
4145 xfs_rfsblock_t *totd,
4146 xfs_rfsblock_t *toti,
2bd0ea18
NS
4147 xfs_extnum_t *nex,
4148 blkmap_t **blkmapp,
4149 int isroot,
4150 typnm_t btype)
4151{
4152 xfs_agblock_t agbno;
4153 xfs_agnumber_t agno;
2bd0ea18
NS
4154 int i;
4155 xfs_bmbt_ptr_t *pp;
b9652a81 4156 xfs_bmbt_rec_t *rp;
2bd0ea18
NS
4157
4158 agno = XFS_FSB_TO_AGNO(mp, bno);
4159 agbno = XFS_FSB_TO_AGBNO(mp, bno);
e96864ff
DW
4160 if (be32_to_cpu(block->bb_magic) != XFS_BMAP_MAGIC &&
4161 be32_to_cpu(block->bb_magic) != XFS_BMAP_CRC_MAGIC) {
2bd0ea18 4162 if (!sflag || id->ilist || CHECK_BLIST(bno))
9ee7055c
AM
4163 dbprintf(_("bad magic # %#x in inode %lld bmbt block "
4164 "%u/%u\n"),
5e656dbb 4165 be32_to_cpu(block->bb_magic), id->ino, agno, agbno);
2bd0ea18
NS
4166 error++;
4167 }
5e656dbb 4168 if (be16_to_cpu(block->bb_level) != level) {
2bd0ea18 4169 if (!sflag || id->ilist || CHECK_BLIST(bno))
9ee7055c
AM
4170 dbprintf(_("expected level %d got %d in inode %lld bmbt "
4171 "block %u/%u\n"),
5e656dbb 4172 level, be16_to_cpu(block->bb_level), id->ino, agno, agbno);
2bd0ea18
NS
4173 error++;
4174 }
4175 set_dbmap(agno, agbno, 1, type, agno, agbno);
4176 set_inomap(agno, agbno, 1, id);
4177 (*toti)++;
4178 if (level == 0) {
5e656dbb
BN
4179 if (be16_to_cpu(block->bb_numrecs) > mp->m_bmap_dmxr[0] ||
4180 (isroot == 0 && be16_to_cpu(block->bb_numrecs) < mp->m_bmap_dmnr[0])) {
2bd0ea18 4181 if (!sflag || id->ilist || CHECK_BLIST(bno))
9ee7055c
AM
4182 dbprintf(_("bad btree nrecs (%u, min=%u, max=%u) "
4183 "in inode %lld bmap block %lld\n"),
5e656dbb 4184 be16_to_cpu(block->bb_numrecs), mp->m_bmap_dmnr[0],
2bd0ea18 4185 mp->m_bmap_dmxr[0], id->ino,
5a35bf2c 4186 (xfs_fsblock_t)bno);
2bd0ea18
NS
4187 error++;
4188 return;
4189 }
b9652a81 4190 rp = XFS_BMBT_REC_ADDR(mp, block, 1);
5e656dbb
BN
4191 *nex += be16_to_cpu(block->bb_numrecs);
4192 process_bmbt_reclist(rp, be16_to_cpu(block->bb_numrecs), type, id, totd,
2bd0ea18
NS
4193 blkmapp);
4194 return;
4195 }
5e656dbb
BN
4196 if (be16_to_cpu(block->bb_numrecs) > mp->m_bmap_dmxr[1] ||
4197 (isroot == 0 && be16_to_cpu(block->bb_numrecs) < mp->m_bmap_dmnr[1])) {
2bd0ea18 4198 if (!sflag || id->ilist || CHECK_BLIST(bno))
9ee7055c
AM
4199 dbprintf(_("bad btree nrecs (%u, min=%u, max=%u) in "
4200 "inode %lld bmap block %lld\n"),
5e656dbb 4201 be16_to_cpu(block->bb_numrecs), mp->m_bmap_dmnr[1],
5a35bf2c 4202 mp->m_bmap_dmxr[1], id->ino, (xfs_fsblock_t)bno);
2bd0ea18
NS
4203 error++;
4204 return;
4205 }
b3563c19 4206 pp = XFS_BMBT_PTR_ADDR(mp, block, 1, mp->m_bmap_dmxr[0]);
5e656dbb 4207 for (i = 0; i < be16_to_cpu(block->bb_numrecs); i++)
f8149110 4208 scan_lbtree(be64_to_cpu(pp[i]), level, scanfunc_bmap, type, id,
5e656dbb 4209 totd, toti, nex, blkmapp, 0, btype);
2bd0ea18
NS
4210}
4211
4212static void
4213scanfunc_bno(
b3563c19 4214 struct xfs_btree_block *block,
2bd0ea18
NS
4215 int level,
4216 xfs_agf_t *agf,
4217 xfs_agblock_t bno,
4218 int isroot)
4219{
2bd0ea18
NS
4220 int i;
4221 xfs_alloc_ptr_t *pp;
4222 xfs_alloc_rec_t *rp;
5e656dbb 4223 xfs_agnumber_t seqno = be32_to_cpu(agf->agf_seqno);
9ac8ea13 4224 xfs_agblock_t lastblock;
2bd0ea18 4225
e96864ff
DW
4226 if (be32_to_cpu(block->bb_magic) != XFS_ABTB_MAGIC &&
4227 be32_to_cpu(block->bb_magic) != XFS_ABTB_CRC_MAGIC) {
9ee7055c 4228 dbprintf(_("bad magic # %#x in btbno block %u/%u\n"),
5e656dbb 4229 be32_to_cpu(block->bb_magic), seqno, bno);
2bd0ea18
NS
4230 serious_error++;
4231 return;
4232 }
4233 fdblocks++;
cdded3d8 4234 agfbtreeblks++;
5e656dbb 4235 if (be16_to_cpu(block->bb_level) != level) {
2bd0ea18 4236 if (!sflag)
9ee7055c
AM
4237 dbprintf(_("expected level %d got %d in btbno block "
4238 "%u/%u\n"),
5e656dbb 4239 level, be16_to_cpu(block->bb_level), seqno, bno);
2bd0ea18
NS
4240 error++;
4241 }
4242 set_dbmap(seqno, bno, 1, DBM_BTBNO, seqno, bno);
4243 if (level == 0) {
5e656dbb
BN
4244 if (be16_to_cpu(block->bb_numrecs) > mp->m_alloc_mxr[0] ||
4245 (isroot == 0 && be16_to_cpu(block->bb_numrecs) < mp->m_alloc_mnr[0])) {
9ee7055c
AM
4246 dbprintf(_("bad btree nrecs (%u, min=%u, max=%u) in "
4247 "btbno block %u/%u\n"),
5e656dbb 4248 be16_to_cpu(block->bb_numrecs), mp->m_alloc_mnr[0],
2bd0ea18
NS
4249 mp->m_alloc_mxr[0], seqno, bno);
4250 serious_error++;
4251 return;
4252 }
b3563c19 4253 rp = XFS_ALLOC_REC_ADDR(mp, block, 1);
9ac8ea13 4254 lastblock = 0;
5e656dbb
BN
4255 for (i = 0; i < be16_to_cpu(block->bb_numrecs); i++) {
4256 set_dbmap(seqno, be32_to_cpu(rp[i].ar_startblock),
4257 be32_to_cpu(rp[i].ar_blockcount), DBM_FREE1,
2bd0ea18 4258 seqno, bno);
5e656dbb 4259 if (be32_to_cpu(rp[i].ar_startblock) <= lastblock) {
9ee7055c
AM
4260 dbprintf(_(
4261 "out-of-order bno btree record %d (%u %u) block %u/%u\n"),
5e656dbb
BN
4262 i, be32_to_cpu(rp[i].ar_startblock),
4263 be32_to_cpu(rp[i].ar_blockcount),
4264 be32_to_cpu(agf->agf_seqno), bno);
9ac8ea13
GO
4265 serious_error++;
4266 } else {
5e656dbb 4267 lastblock = be32_to_cpu(rp[i].ar_startblock);
9ac8ea13 4268 }
2bd0ea18
NS
4269 }
4270 return;
4271 }
5e656dbb
BN
4272 if (be16_to_cpu(block->bb_numrecs) > mp->m_alloc_mxr[1] ||
4273 (isroot == 0 && be16_to_cpu(block->bb_numrecs) < mp->m_alloc_mnr[1])) {
9ee7055c
AM
4274 dbprintf(_("bad btree nrecs (%u, min=%u, max=%u) in btbno block "
4275 "%u/%u\n"),
5e656dbb 4276 be16_to_cpu(block->bb_numrecs), mp->m_alloc_mnr[1],
2bd0ea18
NS
4277 mp->m_alloc_mxr[1], seqno, bno);
4278 serious_error++;
4279 return;
4280 }
b3563c19 4281 pp = XFS_ALLOC_PTR_ADDR(mp, block, 1, mp->m_alloc_mxr[1]);
5e656dbb
BN
4282 for (i = 0; i < be16_to_cpu(block->bb_numrecs); i++)
4283 scan_sbtree(agf, be32_to_cpu(pp[i]), level, 0, scanfunc_bno, TYP_BNOBT);
2bd0ea18
NS
4284}
4285
4286static void
4287scanfunc_cnt(
b3563c19 4288 struct xfs_btree_block *block,
2bd0ea18
NS
4289 int level,
4290 xfs_agf_t *agf,
4291 xfs_agblock_t bno,
4292 int isroot)
4293{
5e656dbb 4294 xfs_agnumber_t seqno = be32_to_cpu(agf->agf_seqno);
2bd0ea18
NS
4295 int i;
4296 xfs_alloc_ptr_t *pp;
4297 xfs_alloc_rec_t *rp;
9ac8ea13 4298 xfs_extlen_t lastcount;
2bd0ea18 4299
e96864ff
DW
4300 if (be32_to_cpu(block->bb_magic) != XFS_ABTC_MAGIC &&
4301 be32_to_cpu(block->bb_magic) != XFS_ABTC_CRC_MAGIC) {
9ee7055c 4302 dbprintf(_("bad magic # %#x in btcnt block %u/%u\n"),
5e656dbb 4303 be32_to_cpu(block->bb_magic), seqno, bno);
2bd0ea18
NS
4304 serious_error++;
4305 return;
4306 }
4307 fdblocks++;
cdded3d8 4308 agfbtreeblks++;
5e656dbb 4309 if (be16_to_cpu(block->bb_level) != level) {
2bd0ea18 4310 if (!sflag)
9ee7055c
AM
4311 dbprintf(_("expected level %d got %d in btcnt block "
4312 "%u/%u\n"),
5e656dbb 4313 level, be16_to_cpu(block->bb_level), seqno, bno);
2bd0ea18
NS
4314 error++;
4315 }
4316 set_dbmap(seqno, bno, 1, DBM_BTCNT, seqno, bno);
4317 if (level == 0) {
5e656dbb
BN
4318 if (be16_to_cpu(block->bb_numrecs) > mp->m_alloc_mxr[0] ||
4319 (isroot == 0 && be16_to_cpu(block->bb_numrecs) < mp->m_alloc_mnr[0])) {
9ee7055c
AM
4320 dbprintf(_("bad btree nrecs (%u, min=%u, max=%u) in "
4321 "btbno block %u/%u\n"),
5e656dbb 4322 be16_to_cpu(block->bb_numrecs), mp->m_alloc_mnr[0],
2bd0ea18
NS
4323 mp->m_alloc_mxr[0], seqno, bno);
4324 serious_error++;
4325 return;
4326 }
b3563c19 4327 rp = XFS_ALLOC_REC_ADDR(mp, block, 1);
9ac8ea13 4328 lastcount = 0;
5e656dbb
BN
4329 for (i = 0; i < be16_to_cpu(block->bb_numrecs); i++) {
4330 check_set_dbmap(seqno, be32_to_cpu(rp[i].ar_startblock),
4331 be32_to_cpu(rp[i].ar_blockcount), DBM_FREE1, DBM_FREE2,
2bd0ea18 4332 seqno, bno);
5e656dbb
BN
4333 fdblocks += be32_to_cpu(rp[i].ar_blockcount);
4334 agffreeblks += be32_to_cpu(rp[i].ar_blockcount);
4335 if (be32_to_cpu(rp[i].ar_blockcount) > agflongest)
4336 agflongest = be32_to_cpu(rp[i].ar_blockcount);
4337 if (be32_to_cpu(rp[i].ar_blockcount) < lastcount) {
9ee7055c
AM
4338 dbprintf(_(
4339 "out-of-order cnt btree record %d (%u %u) block %u/%u\n"),
5e656dbb
BN
4340 i, be32_to_cpu(rp[i].ar_startblock),
4341 be32_to_cpu(rp[i].ar_blockcount),
4342 be32_to_cpu(agf->agf_seqno), bno);
9ac8ea13 4343 } else {
5e656dbb 4344 lastcount = be32_to_cpu(rp[i].ar_blockcount);
9ac8ea13 4345 }
2bd0ea18
NS
4346 }
4347 return;
4348 }
5e656dbb
BN
4349 if (be16_to_cpu(block->bb_numrecs) > mp->m_alloc_mxr[1] ||
4350 (isroot == 0 && be16_to_cpu(block->bb_numrecs) < mp->m_alloc_mnr[1])) {
9ee7055c
AM
4351 dbprintf(_("bad btree nrecs (%u, min=%u, max=%u) in btbno block "
4352 "%u/%u\n"),
5e656dbb 4353 be16_to_cpu(block->bb_numrecs), mp->m_alloc_mnr[1],
2bd0ea18
NS
4354 mp->m_alloc_mxr[1], seqno, bno);
4355 serious_error++;
4356 return;
4357 }
b3563c19 4358 pp = XFS_ALLOC_PTR_ADDR(mp, block, 1, mp->m_alloc_mxr[1]);
5e656dbb
BN
4359 for (i = 0; i < be16_to_cpu(block->bb_numrecs); i++)
4360 scan_sbtree(agf, be32_to_cpu(pp[i]), level, 0, scanfunc_cnt, TYP_CNTBT);
2bd0ea18
NS
4361}
4362
4363static void
4364scanfunc_ino(
b3563c19 4365 struct xfs_btree_block *block,
2bd0ea18
NS
4366 int level,
4367 xfs_agf_t *agf,
4368 xfs_agblock_t bno,
4369 int isroot)
4370{
4371 xfs_agino_t agino;
5e656dbb 4372 xfs_agnumber_t seqno = be32_to_cpu(agf->agf_seqno);
2bd0ea18
NS
4373 int i;
4374 int isfree;
4375 int j;
ea8a48fa 4376 int freecount;
2bd0ea18
NS
4377 int nfree;
4378 int off;
4379 xfs_inobt_ptr_t *pp;
4380 xfs_inobt_rec_t *rp;
ea8a48fa
BF
4381 xfs_agblock_t agbno;
4382 xfs_agblock_t end_agbno;
4383 struct xfs_dinode *dip;
4384 int blks_per_buf;
4385 int inodes_per_buf;
4386 int ioff;
4387
4388 if (xfs_sb_version_hassparseinodes(&mp->m_sb))
4389 blks_per_buf = xfs_icluster_size_fsb(mp);
4390 else
4391 blks_per_buf = mp->m_ialloc_blks;
4392 inodes_per_buf = min(blks_per_buf << mp->m_sb.sb_inopblog,
4393 XFS_INODES_PER_CHUNK);
2bd0ea18 4394
e96864ff
DW
4395 if (be32_to_cpu(block->bb_magic) != XFS_IBT_MAGIC &&
4396 be32_to_cpu(block->bb_magic) != XFS_IBT_CRC_MAGIC) {
9ee7055c 4397 dbprintf(_("bad magic # %#x in inobt block %u/%u\n"),
5e656dbb 4398 be32_to_cpu(block->bb_magic), seqno, bno);
2bd0ea18
NS
4399 serious_error++;
4400 return;
4401 }
5e656dbb 4402 if (be16_to_cpu(block->bb_level) != level) {
2bd0ea18 4403 if (!sflag)
9ee7055c
AM
4404 dbprintf(_("expected level %d got %d in inobt block "
4405 "%u/%u\n"),
5e656dbb 4406 level, be16_to_cpu(block->bb_level), seqno, bno);
2bd0ea18
NS
4407 error++;
4408 }
4409 set_dbmap(seqno, bno, 1, DBM_BTINO, seqno, bno);
4410 if (level == 0) {
5e656dbb
BN
4411 if (be16_to_cpu(block->bb_numrecs) > mp->m_inobt_mxr[0] ||
4412 (isroot == 0 && be16_to_cpu(block->bb_numrecs) < mp->m_inobt_mnr[0])) {
9ee7055c
AM
4413 dbprintf(_("bad btree nrecs (%u, min=%u, max=%u) in "
4414 "inobt block %u/%u\n"),
5e656dbb 4415 be16_to_cpu(block->bb_numrecs), mp->m_inobt_mnr[0],
2bd0ea18
NS
4416 mp->m_inobt_mxr[0], seqno, bno);
4417 serious_error++;
4418 return;
4419 }
b3563c19 4420 rp = XFS_INOBT_REC_ADDR(mp, block, 1);
5e656dbb
BN
4421 for (i = 0; i < be16_to_cpu(block->bb_numrecs); i++) {
4422 agino = be32_to_cpu(rp[i].ir_startino);
ea8a48fa
BF
4423 agbno = XFS_AGINO_TO_AGBNO(mp, agino);
4424 off = XFS_AGINO_TO_OFFSET(mp, agino);
4425 end_agbno = agbno + mp->m_ialloc_blks;
09c93e56
BF
4426 if (off == 0) {
4427 if ((sbversion & XFS_SB_VERSION_ALIGNBIT) &&
4428 mp->m_sb.sb_inoalignmt &&
4429 (XFS_INO_TO_AGBNO(mp, agino) %
4430 mp->m_sb.sb_inoalignmt))
2bd0ea18 4431 sbversion &= ~XFS_SB_VERSION_ALIGNBIT;
2bd0ea18 4432 }
ea8a48fa 4433
09c93e56 4434 push_cur();
ea8a48fa
BF
4435
4436 ioff = 0;
4437 nfree = 0;
4438 while (agbno < end_agbno &&
4439 ioff < XFS_INODES_PER_CHUNK) {
4440 if (xfs_inobt_is_sparse_disk(&rp[i], ioff))
4441 goto next_buf;
4442
4443 if (off < XFS_INODES_PER_CHUNK)
4444 set_dbmap(seqno, agbno, blks_per_buf,
4445 DBM_INODE, seqno, bno);
4446
4447 icount += inodes_per_buf;
4448 agicount += inodes_per_buf;
4449
4450 set_cur(&typtab[TYP_INODE],
4451 XFS_AGB_TO_DADDR(mp, seqno, agbno),
4452 XFS_FSB_TO_BB(mp, blks_per_buf),
4453 DB_RING_IGN, NULL);
4454 if (iocur_top->data == NULL) {
4455 if (!sflag)
4456 dbprintf(_("can't read inode block "
4457 "%u/%u\n"), seqno,
4458 agbno);
4459 error++;
4460 goto next_buf;
4461 }
4462
4463 for (j = 0; j < inodes_per_buf; j++) {
4464 isfree = XFS_INOBT_IS_FREE_DISK(&rp[i], ioff + j);
4465 if (isfree)
4466 nfree++;
4467 dip = (xfs_dinode_t *)((char *)iocur_top->data +
4468 ((off + j) << mp->m_sb.sb_inodelog));
4469 process_inode(agf, agino + ioff + j, dip, isfree);
4470 }
4471
4472next_buf:
4473 agbno += blks_per_buf;
4474 ioff += inodes_per_buf;
09c93e56 4475 }
ea8a48fa
BF
4476
4477 if (xfs_sb_version_hassparseinodes(&mp->m_sb))
4478 freecount = rp[i].ir_u.sp.ir_freecount;
4479 else
4480 freecount = be32_to_cpu(rp[i].ir_u.f.ir_freecount);
4481
4482 ifree += freecount;
4483 agifreecount += freecount;
4484
4485 if (nfree != freecount) {
2bd0ea18 4486 if (!sflag)
9ee7055c 4487 dbprintf(_("ir_freecount/free mismatch, "
2bd0ea18 4488 "inode chunk %u/%u, freecount "
9ee7055c 4489 "%d nfree %d\n"),
ea8a48fa 4490 seqno, agino, freecount, nfree);
2bd0ea18
NS
4491 error++;
4492 }
09c93e56 4493 pop_cur();
2bd0ea18
NS
4494 }
4495 return;
4496 }
5e656dbb
BN
4497 if (be16_to_cpu(block->bb_numrecs) > mp->m_inobt_mxr[1] ||
4498 (isroot == 0 && be16_to_cpu(block->bb_numrecs) < mp->m_inobt_mnr[1])) {
9ee7055c
AM
4499 dbprintf(_("bad btree nrecs (%u, min=%u, max=%u) in inobt block "
4500 "%u/%u\n"),
5e656dbb 4501 be16_to_cpu(block->bb_numrecs), mp->m_inobt_mnr[1],
2bd0ea18
NS
4502 mp->m_inobt_mxr[1], seqno, bno);
4503 serious_error++;
4504 return;
4505 }
b3563c19 4506 pp = XFS_INOBT_PTR_ADDR(mp, block, 1, mp->m_inobt_mxr[1]);
5e656dbb
BN
4507 for (i = 0; i < be16_to_cpu(block->bb_numrecs); i++)
4508 scan_sbtree(agf, be32_to_cpu(pp[i]), level, 0, scanfunc_ino, TYP_INOBT);
2bd0ea18
NS
4509}
4510
e96864ff
DW
4511static void
4512scanfunc_fino(
4513 struct xfs_btree_block *block,
4514 int level,
4515 struct xfs_agf *agf,
4516 xfs_agblock_t bno,
4517 int isroot)
4518{
4519 xfs_agino_t agino;
4520 xfs_agnumber_t seqno = be32_to_cpu(agf->agf_seqno);
4521 int i;
4522 int off;
4523 xfs_inobt_ptr_t *pp;
4524 struct xfs_inobt_rec *rp;
ea8a48fa
BF
4525 xfs_agblock_t agbno;
4526 xfs_agblock_t end_agbno;
4527 int blks_per_buf;
4528 int inodes_per_buf;
4529 int ioff;
4530
4531 if (xfs_sb_version_hassparseinodes(&mp->m_sb))
4532 blks_per_buf = xfs_icluster_size_fsb(mp);
4533 else
4534 blks_per_buf = mp->m_ialloc_blks;
4535 inodes_per_buf = min(blks_per_buf << mp->m_sb.sb_inopblog,
4536 XFS_INODES_PER_CHUNK);
e96864ff
DW
4537
4538 if (be32_to_cpu(block->bb_magic) != XFS_FIBT_MAGIC &&
4539 be32_to_cpu(block->bb_magic) != XFS_FIBT_CRC_MAGIC) {
4540 dbprintf(_("bad magic # %#x in finobt block %u/%u\n"),
4541 be32_to_cpu(block->bb_magic), seqno, bno);
4542 serious_error++;
4543 return;
4544 }
4545 if (be16_to_cpu(block->bb_level) != level) {
4546 if (!sflag)
4547 dbprintf(_("expected level %d got %d in finobt block "
4548 "%u/%u\n"),
4549 level, be16_to_cpu(block->bb_level), seqno, bno);
4550 error++;
4551 }
4552 set_dbmap(seqno, bno, 1, DBM_BTFINO, seqno, bno);
4553 if (level == 0) {
4554 if (be16_to_cpu(block->bb_numrecs) > mp->m_inobt_mxr[0] ||
4555 (isroot == 0 && be16_to_cpu(block->bb_numrecs) < mp->m_inobt_mnr[0])) {
4556 dbprintf(_("bad btree nrecs (%u, min=%u, max=%u) in "
4557 "finobt block %u/%u\n"),
4558 be16_to_cpu(block->bb_numrecs), mp->m_inobt_mnr[0],
4559 mp->m_inobt_mxr[0], seqno, bno);
4560 serious_error++;
4561 return;
4562 }
4563 rp = XFS_INOBT_REC_ADDR(mp, block, 1);
4564 for (i = 0; i < be16_to_cpu(block->bb_numrecs); i++) {
4565 agino = be32_to_cpu(rp[i].ir_startino);
ea8a48fa
BF
4566 agbno = XFS_AGINO_TO_AGBNO(mp, agino);
4567 off = XFS_AGINO_TO_OFFSET(mp, agino);
4568 end_agbno = agbno + mp->m_ialloc_blks;
09c93e56
BF
4569 if (off == 0) {
4570 if ((sbversion & XFS_SB_VERSION_ALIGNBIT) &&
4571 mp->m_sb.sb_inoalignmt &&
4572 (XFS_INO_TO_AGBNO(mp, agino) %
4573 mp->m_sb.sb_inoalignmt))
e96864ff 4574 sbversion &= ~XFS_SB_VERSION_ALIGNBIT;
e96864ff 4575 }
ea8a48fa
BF
4576
4577 ioff = 0;
4578 while (agbno < end_agbno &&
4579 ioff < XFS_INODES_PER_CHUNK) {
4580 if (xfs_inobt_is_sparse_disk(&rp[i], ioff))
4581 goto next_buf;
4582
4583 check_set_dbmap(seqno, agbno,
68d16907 4584 (xfs_extlen_t)max(1,
ea8a48fa
BF
4585 inodes_per_buf >>
4586 mp->m_sb.sb_inopblog),
4587 DBM_INODE, DBM_INODE, seqno, bno);
4588
4589next_buf:
4590 agbno += blks_per_buf;
4591 ioff += inodes_per_buf;
4592 }
4593
e96864ff
DW
4594 }
4595 return;
4596 }
4597 if (be16_to_cpu(block->bb_numrecs) > mp->m_inobt_mxr[1] ||
4598 (isroot == 0 && be16_to_cpu(block->bb_numrecs) < mp->m_inobt_mnr[1])) {
4599 dbprintf(_("bad btree nrecs (%u, min=%u, max=%u) in finobt block "
4600 "%u/%u\n"),
4601 be16_to_cpu(block->bb_numrecs), mp->m_inobt_mnr[1],
4602 mp->m_inobt_mxr[1], seqno, bno);
4603 serious_error++;
4604 return;
4605 }
4606 pp = XFS_INOBT_PTR_ADDR(mp, block, 1, mp->m_inobt_mxr[1]);
4607 for (i = 0; i < be16_to_cpu(block->bb_numrecs); i++)
4608 scan_sbtree(agf, be32_to_cpu(pp[i]), level, 0, scanfunc_fino, TYP_FINOBT);
4609}
4610
e3dcc17b
DW
4611static void
4612scanfunc_rmap(
4613 struct xfs_btree_block *block,
4614 int level,
4615 struct xfs_agf *agf,
4616 xfs_agblock_t bno,
4617 int isroot)
4618{
4619 xfs_agnumber_t seqno = be32_to_cpu(agf->agf_seqno);
4620 int i;
4621 xfs_rmap_ptr_t *pp;
4622 struct xfs_rmap_rec *rp;
4623 xfs_agblock_t lastblock;
4624
4625 if (be32_to_cpu(block->bb_magic) != XFS_RMAP_CRC_MAGIC) {
4626 dbprintf(_("bad magic # %#x in rmapbt block %u/%u\n"),
4627 be32_to_cpu(block->bb_magic), seqno, bno);
4628 serious_error++;
4629 return;
4630 }
4631 if (be16_to_cpu(block->bb_level) != level) {
4632 if (!sflag)
4633 dbprintf(_("expected level %d got %d in rmapbt block "
4634 "%u/%u\n"),
4635 level, be16_to_cpu(block->bb_level), seqno, bno);
4636 error++;
4637 }
4638 if (!isroot) {
4639 fdblocks++;
4640 agfbtreeblks++;
4641 }
4642 set_dbmap(seqno, bno, 1, DBM_BTRMAP, seqno, bno);
4643 if (level == 0) {
4644 if (be16_to_cpu(block->bb_numrecs) > mp->m_rmap_mxr[0] ||
4645 (isroot == 0 && be16_to_cpu(block->bb_numrecs) < mp->m_rmap_mnr[0])) {
4646 dbprintf(_("bad btree nrecs (%u, min=%u, max=%u) in "
4647 "rmapbt block %u/%u\n"),
4648 be16_to_cpu(block->bb_numrecs), mp->m_rmap_mnr[0],
4649 mp->m_rmap_mxr[0], seqno, bno);
4650 serious_error++;
4651 return;
4652 }
4653 rp = XFS_RMAP_REC_ADDR(block, 1);
4654 lastblock = 0;
4655 for (i = 0; i < be16_to_cpu(block->bb_numrecs); i++) {
4656 if (be32_to_cpu(rp[i].rm_startblock) < lastblock) {
4657 dbprintf(_(
4658 "out-of-order rmap btree record %d (%u %u) block %u/%u\n"),
4659 i, be32_to_cpu(rp[i].rm_startblock),
4660 be32_to_cpu(rp[i].rm_startblock),
4661 be32_to_cpu(agf->agf_seqno), bno);
4662 } else {
4663 lastblock = be32_to_cpu(rp[i].rm_startblock);
4664 }
4665 }
4666 return;
4667 }
4668 if (be16_to_cpu(block->bb_numrecs) > mp->m_rmap_mxr[1] ||
4669 (isroot == 0 && be16_to_cpu(block->bb_numrecs) < mp->m_rmap_mnr[1])) {
4670 dbprintf(_("bad btree nrecs (%u, min=%u, max=%u) in rmapbt "
4671 "block %u/%u\n"),
4672 be16_to_cpu(block->bb_numrecs), mp->m_rmap_mnr[1],
4673 mp->m_rmap_mxr[1], seqno, bno);
4674 serious_error++;
4675 return;
4676 }
4677 pp = XFS_RMAP_PTR_ADDR(block, 1, mp->m_rmap_mxr[1]);
4678 for (i = 0; i < be16_to_cpu(block->bb_numrecs); i++)
4679 scan_sbtree(agf, be32_to_cpu(pp[i]), level, 0, scanfunc_rmap,
4680 TYP_RMAPBT);
4681}
4682
757ad8c7
DW
4683static void
4684scanfunc_refcnt(
4685 struct xfs_btree_block *block,
4686 int level,
4687 struct xfs_agf *agf,
4688 xfs_agblock_t bno,
4689 int isroot)
4690{
4691 xfs_agnumber_t seqno = be32_to_cpu(agf->agf_seqno);
4692 int i;
4693 xfs_refcount_ptr_t *pp;
4694 struct xfs_refcount_rec *rp;
4695 xfs_agblock_t lastblock;
4696
4697 if (be32_to_cpu(block->bb_magic) != XFS_REFC_CRC_MAGIC) {
4698 dbprintf(_("bad magic # %#x in refcntbt block %u/%u\n"),
4699 be32_to_cpu(block->bb_magic), seqno, bno);
4700 serious_error++;
4701 return;
4702 }
4703 if (be16_to_cpu(block->bb_level) != level) {
4704 if (!sflag)
4705 dbprintf(_("expected level %d got %d in refcntbt block "
4706 "%u/%u\n"),
4707 level, be16_to_cpu(block->bb_level), seqno, bno);
4708 error++;
4709 }
4710 set_dbmap(seqno, bno, 1, DBM_BTREFC, seqno, bno);
4711 if (level == 0) {
4712 if (be16_to_cpu(block->bb_numrecs) > mp->m_refc_mxr[0] ||
4713 (isroot == 0 && be16_to_cpu(block->bb_numrecs) < mp->m_refc_mnr[0])) {
4714 dbprintf(_("bad btree nrecs (%u, min=%u, max=%u) in "
4715 "refcntbt block %u/%u\n"),
4716 be16_to_cpu(block->bb_numrecs), mp->m_refc_mnr[0],
4717 mp->m_refc_mxr[0], seqno, bno);
4718 serious_error++;
4719 return;
4720 }
4721 rp = XFS_REFCOUNT_REC_ADDR(block, 1);
4722 lastblock = 0;
4723 for (i = 0; i < be16_to_cpu(block->bb_numrecs); i++) {
13ef9674 4724 if (be32_to_cpu(rp[i].rc_refcount) == 1) {
b638281f
DW
4725 xfs_agblock_t agbno;
4726 char *msg;
4727
4728 agbno = be32_to_cpu(rp[i].rc_startblock);
4729 if (agbno >= XFS_REFC_COW_START) {
4730 agbno -= XFS_REFC_COW_START;
4731 msg = _(
4732 "leftover CoW extent (%u/%u) len %u\n");
4733 } else {
4734 msg = _(
4735 "leftover CoW extent at unexpected address (%u/%u) len %u\n");
4736 }
4737 dbprintf(msg,
13ef9674 4738 seqno,
b638281f 4739 agbno,
13ef9674
DW
4740 be32_to_cpu(rp[i].rc_blockcount));
4741 set_dbmap(seqno,
b638281f 4742 agbno,
13ef9674
DW
4743 be32_to_cpu(rp[i].rc_blockcount),
4744 DBM_COWDATA, seqno, bno);
4745 } else {
4746 set_dbmap(seqno,
4747 be32_to_cpu(rp[i].rc_startblock),
4748 be32_to_cpu(rp[i].rc_blockcount),
4749 DBM_RLDATA, seqno, bno);
4750 }
757ad8c7
DW
4751 if (be32_to_cpu(rp[i].rc_startblock) < lastblock) {
4752 dbprintf(_(
4753 "out-of-order refcnt btree record %d (%u %u) block %u/%u\n"),
4754 i, be32_to_cpu(rp[i].rc_startblock),
4755 be32_to_cpu(rp[i].rc_startblock),
4756 be32_to_cpu(agf->agf_seqno), bno);
4757 } else {
4758 lastblock = be32_to_cpu(rp[i].rc_startblock) +
4759 be32_to_cpu(rp[i].rc_blockcount);
4760 }
4761 }
4762 return;
4763 }
4764 if (be16_to_cpu(block->bb_numrecs) > mp->m_refc_mxr[1] ||
4765 (isroot == 0 && be16_to_cpu(block->bb_numrecs) < mp->m_refc_mnr[1])) {
4766 dbprintf(_("bad btree nrecs (%u, min=%u, max=%u) in refcntbt "
4767 "block %u/%u\n"),
4768 be16_to_cpu(block->bb_numrecs), mp->m_refc_mnr[1],
4769 mp->m_refc_mxr[1], seqno, bno);
4770 serious_error++;
4771 return;
4772 }
4773 pp = XFS_REFCOUNT_PTR_ADDR(block, 1, mp->m_refc_mxr[1]);
4774 for (i = 0; i < be16_to_cpu(block->bb_numrecs); i++)
4775 scan_sbtree(agf, be32_to_cpu(pp[i]), level, 0, scanfunc_refcnt,
4776 TYP_REFCBT);
4777}
4778
2bd0ea18
NS
4779static void
4780set_dbmap(
4781 xfs_agnumber_t agno,
4782 xfs_agblock_t agbno,
4783 xfs_extlen_t len,
4784 dbm_t type,
4785 xfs_agnumber_t c_agno,
4786 xfs_agblock_t c_agbno)
4787{
4788 check_set_dbmap(agno, agbno, len, DBM_UNKNOWN, type, c_agno, c_agbno);
4789}
4790
4791static void
4792set_inomap(
4793 xfs_agnumber_t agno,
4794 xfs_agblock_t agbno,
4795 xfs_extlen_t len,
4796 inodata_t *id)
4797{
4798 xfs_extlen_t i;
4799 inodata_t **idp;
4800 int mayprint;
4801
4802 if (!check_inomap(agno, agbno, len, id->ino))
4803 return;
4804 mayprint = verbose | id->ilist | blist_size;
4805 for (i = 0, idp = &inomap[agno][agbno]; i < len; i++, idp++) {
4806 *idp = id;
4807 if (mayprint &&
4808 (verbose || id->ilist || CHECK_BLISTA(agno, agbno + i)))
9ee7055c 4809 dbprintf(_("setting inode to %lld for block %u/%u\n"),
2bd0ea18
NS
4810 id->ino, agno, agbno + i);
4811 }
4812}
4813
4814static void
4815set_rdbmap(
5a35bf2c 4816 xfs_rfsblock_t bno,
2bd0ea18
NS
4817 xfs_extlen_t len,
4818 dbm_t type)
4819{
4820 check_set_rdbmap(bno, len, DBM_UNKNOWN, type);
4821}
4822
4823static void
4824set_rinomap(
5a35bf2c 4825 xfs_rfsblock_t bno,
2bd0ea18
NS
4826 xfs_extlen_t len,
4827 inodata_t *id)
4828{
4829 xfs_extlen_t i;
4830 inodata_t **idp;
4831 int mayprint;
4832
4833 if (!check_rinomap(bno, len, id->ino))
4834 return;
4835 mayprint = verbose | id->ilist | blist_size;
4836 for (i = 0, idp = &inomap[mp->m_sb.sb_agcount][bno];
4837 i < len;
4838 i++, idp++) {
4839 *idp = id;
4840 if (mayprint && (verbose || id->ilist || CHECK_BLIST(bno + i)))
9ee7055c 4841 dbprintf(_("setting inode to %lld for rtblock %llu\n"),
2bd0ea18
NS
4842 id->ino, bno + i);
4843 }
4844}
4845
4846static void
4847setlink_inode(
4848 inodata_t *id,
4849 nlink_t nlink,
4850 int isdir,
4851 int security)
4852{
4853 id->link_set = nlink;
4854 id->isdir = isdir;
4855 id->security = security;
4856 if (verbose || id->ilist)
9ee7055c 4857 dbprintf(_("inode %lld nlink %u %s dir\n"), id->ino, nlink,
2bd0ea18
NS
4858 isdir ? "is" : "not");
4859}