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