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