]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blame - db/check.c
xfs_{db,repair}: use accessor functions for bitmap words
[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;
2e62ddc4 3597 xfs_rtxnum_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;
0457cd25
DW
3609 words = malloc(mp->m_blockwsize << XFS_WORDLOG);
3610 if (!words) {
3611 dbprintf(_("could not allocate rtwords buffer\n"));
3612 error++;
3613 return;
3614 }
2bd0ea18
NS
3615 bit = extno = prevbit = start_bmbno = start_bit = 0;
3616 bmbno = NULLFILEOFF;
61b7c5fd
DW
3617 while ((bmbno = blkmap_next_off(blkmap, bmbno, &t)) != NULLFILEOFF) {
3618 struct xfs_rtalloc_args args = {
3619 .mp = mp,
3620 };
0457cd25
DW
3621 xfs_rtword_t *incore = words;
3622 unsigned int i;
61b7c5fd 3623
2bd0ea18
NS
3624 bno = blkmap_get(blkmap, bmbno);
3625 if (bno == NULLFSBLOCK) {
3626 if (!sflag)
9ee7055c
AM
3627 dbprintf(_("block %lld for rtbitmap inode is "
3628 "missing\n"),
5a35bf2c 3629 (xfs_fileoff_t)bmbno);
2bd0ea18
NS
3630 error++;
3631 continue;
3632 }
3633 push_cur();
3634 set_cur(&typtab[TYP_RTBITMAP], XFS_FSB_TO_DADDR(mp, bno), blkbb,
3635 DB_RING_IGN, NULL);
61b7c5fd 3636 if (!iocur_top->bp) {
2bd0ea18 3637 if (!sflag)
9ee7055c
AM
3638 dbprintf(_("can't read block %lld for rtbitmap "
3639 "inode\n"),
5a35bf2c 3640 (xfs_fileoff_t)bmbno);
2bd0ea18 3641 error++;
d24c0a90 3642 pop_cur();
2bd0ea18
NS
3643 continue;
3644 }
61b7c5fd
DW
3645
3646 args.rbmbp = iocur_top->bp;
0457cd25
DW
3647 for (i = 0; i < mp->m_blockwsize; i++, incore++)
3648 *incore = libxfs_rtbitmap_getword(&args, i);
3649
2bd0ea18
NS
3650 for (bit = 0;
3651 bit < bitsperblock && extno < mp->m_sb.sb_rextents;
3652 bit++, extno++) {
a580302f 3653 if (xfs_isset(words, bit)) {
2bd0ea18
NS
3654 rtbno = extno * mp->m_sb.sb_rextsize;
3655 set_rdbmap(rtbno, mp->m_sb.sb_rextsize,
3656 DBM_RTFREE);
3657 frextents++;
3658 if (prevbit == 0) {
3659 start_bmbno = (int)bmbno;
3660 start_bit = bit;
3661 prevbit = 1;
3662 }
3663 } else if (prevbit == 1) {
3664 len = ((int)bmbno - start_bmbno) *
3665 bitsperblock + (bit - start_bit);
3666 log = XFS_RTBLOCKLOG(len);
ccffd2f9 3667 offs = xfs_rtsumoffs(mp, log, start_bmbno);
2bd0ea18
NS
3668 sumcompute[offs]++;
3669 prevbit = 0;
3670 }
3671 }
3672 pop_cur();
3673 if (extno == mp->m_sb.sb_rextents)
3674 break;
3675 }
3676 if (prevbit == 1) {
3677 len = ((int)bmbno - start_bmbno) * bitsperblock +
3678 (bit - start_bit);
3679 log = XFS_RTBLOCKLOG(len);
ccffd2f9 3680 offs = xfs_rtsumoffs(mp, log, start_bmbno);
2bd0ea18
NS
3681 sumcompute[offs]++;
3682 }
0457cd25 3683 free(words);
2bd0ea18
NS
3684}
3685
3686static void
3687process_rtsummary(
3688 blkmap_t *blkmap)
3689{
3690 xfs_fsblock_t bno;
3691 char *bytes;
3692 xfs_fileoff_t sumbno;
3693 int t;
3694
3695 sumbno = NULLFILEOFF;
d24c0a90 3696 while ((sumbno = blkmap_next_off(blkmap, sumbno, &t)) != NULLFILEOFF) {
2bd0ea18
NS
3697 bno = blkmap_get(blkmap, sumbno);
3698 if (bno == NULLFSBLOCK) {
3699 if (!sflag)
9ee7055c
AM
3700 dbprintf(_("block %lld for rtsummary inode is "
3701 "missing\n"),
5a35bf2c 3702 (xfs_fileoff_t)sumbno);
2bd0ea18
NS
3703 error++;
3704 continue;
3705 }
3706 push_cur();
3707 set_cur(&typtab[TYP_RTSUMMARY], XFS_FSB_TO_DADDR(mp, bno),
3708 blkbb, DB_RING_IGN, NULL);
3709 if ((bytes = iocur_top->data) == NULL) {
3710 if (!sflag)
9ee7055c
AM
3711 dbprintf(_("can't read block %lld for rtsummary "
3712 "inode\n"),
5a35bf2c 3713 (xfs_fileoff_t)sumbno);
2bd0ea18 3714 error++;
d24c0a90 3715 pop_cur();
2bd0ea18
NS
3716 continue;
3717 }
3718 memcpy((char *)sumfile + sumbno * mp->m_sb.sb_blocksize, bytes,
3719 mp->m_sb.sb_blocksize);
3720 pop_cur();
3721 }
3722}
3723
3724static xfs_ino_t
3725process_sf_dir_v2(
7328ea6e 3726 struct xfs_dinode *dip,
2bd0ea18
NS
3727 int *dot,
3728 int *dotdot,
3729 inodata_t *id)
3730{
3731 inodata_t *cid;
3732 int i;
3733 int i8;
3734 xfs_ino_t lino;
3735 int offset;
eb0cb950 3736 struct xfs_dir2_sf_hdr *sf;
2bd0ea18
NS
3737 xfs_dir2_sf_entry_t *sfe;
3738 int v;
3739
eb0cb950 3740 sf = (struct xfs_dir2_sf_hdr *)XFS_DFORK_DPTR(dip);
2bd0ea18
NS
3741 addlink_inode(id);
3742 v = verbose || id->ilist;
3743 if (v)
9ee7055c 3744 dbprintf(_("dir %lld entry . %lld\n"), id->ino, id->ino);
2bd0ea18 3745 (*dot)++;
eb0cb950 3746 sfe = xfs_dir2_sf_firstentry(sf);
58a1d356 3747 offset = mp->m_dir_geo->data_first_offset;
eb0cb950 3748 for (i = sf->count - 1, i8 = 0; i >= 0; i--) {
660836c9
CH
3749 if ((intptr_t)sfe +
3750 libxfs_dir2_sf_entsize(mp, sf, sfe->namelen) -
ee6cd73e 3751 (intptr_t)sf > be64_to_cpu(dip->di_size)) {
2bd0ea18 3752 if (!sflag)
9ee7055c 3753 dbprintf(_("dir %llu bad size in entry at %d\n"),
2bd0ea18
NS
3754 id->ino,
3755 (int)((char *)sfe - (char *)sf));
3756 error++;
3757 break;
3758 }
e96bd2d3 3759 lino = libxfs_dir2_sf_get_ino(mp, sf, sfe);
2bd0ea18
NS
3760 if (lino > XFS_DIR2_MAX_SHORT_INUM)
3761 i8++;
3762 cid = find_inode(lino, 1);
3763 if (cid == NULL) {
3764 if (!sflag)
9ee7055c
AM
3765 dbprintf(_("dir %lld entry %*.*s bad inode "
3766 "number %lld\n"),
2bd0ea18
NS
3767 id->ino, sfe->namelen, sfe->namelen,
3768 sfe->name, lino);
3769 error++;
3770 } else {
3771 addlink_inode(cid);
3772 if (!cid->parent)
3773 cid->parent = id;
3774 addname_inode(cid, (char *)sfe->name, sfe->namelen);
3775 }
3776 if (v)
9ee7055c 3777 dbprintf(_("dir %lld entry %*.*s offset %d %lld\n"),
2bd0ea18 3778 id->ino, sfe->namelen, sfe->namelen, sfe->name,
5e656dbb
BN
3779 xfs_dir2_sf_get_offset(sfe), lino);
3780 if (xfs_dir2_sf_get_offset(sfe) < offset) {
2bd0ea18 3781 if (!sflag)
9ee7055c 3782 dbprintf(_("dir %lld entry %*.*s bad offset %d\n"),
2bd0ea18 3783 id->ino, sfe->namelen, sfe->namelen,
5e656dbb 3784 sfe->name, xfs_dir2_sf_get_offset(sfe));
2bd0ea18
NS
3785 error++;
3786 }
3787 offset =
5e656dbb 3788 xfs_dir2_sf_get_offset(sfe) +
660836c9
CH
3789 libxfs_dir2_sf_entsize(mp, sf, sfe->namelen);
3790 sfe = libxfs_dir2_sf_nextentry(mp, sf, sfe);
2bd0ea18 3791 }
f8149110 3792 if (i < 0 && (intptr_t)sfe - (intptr_t)sf !=
56b2de80 3793 be64_to_cpu(dip->di_size)) {
2bd0ea18 3794 if (!sflag)
9ee7055c 3795 dbprintf(_("dir %llu size is %lld, should be %u\n"),
56b2de80 3796 id->ino, be64_to_cpu(dip->di_size),
2bd0ea18
NS
3797 (uint)((char *)sfe - (char *)sf));
3798 error++;
3799 }
eb0cb950 3800 if (offset + (sf->count + 2) * sizeof(xfs_dir2_leaf_entry_t) +
ff105f75 3801 sizeof(xfs_dir2_block_tail_t) > mp->m_dir_geo->blksize) {
2bd0ea18 3802 if (!sflag)
9ee7055c 3803 dbprintf(_("dir %llu offsets too high\n"), id->ino);
2bd0ea18
NS
3804 error++;
3805 }
8a7190bd 3806 lino = libxfs_dir2_sf_get_parent_ino(sf);
2bd0ea18
NS
3807 if (lino > XFS_DIR2_MAX_SHORT_INUM)
3808 i8++;
3809 cid = find_inode(lino, 1);
3810 if (cid)
3811 addlink_inode(cid);
3812 else {
3813 if (!sflag)
9ee7055c 3814 dbprintf(_("dir %lld entry .. bad inode number %lld\n"),
2bd0ea18
NS
3815 id->ino, lino);
3816 error++;
3817 }
3818 if (v)
9ee7055c 3819 dbprintf(_("dir %lld entry .. %lld\n"), id->ino, lino);
eb0cb950 3820 if (i8 != sf->i8count) {
2bd0ea18 3821 if (!sflag)
9ee7055c
AM
3822 dbprintf(_("dir %lld i8count mismatch is %d should be "
3823 "%d\n"),
eb0cb950 3824 id->ino, sf->i8count, i8);
2bd0ea18
NS
3825 error++;
3826 }
3827 (*dotdot)++;
3828 return cid ? lino : NULLFSINO;
3829}
3830
2bd0ea18
NS
3831
3832static void
3833quota_add(
be8e601c
NS
3834 xfs_dqid_t *prjid,
3835 xfs_dqid_t *grpid,
3836 xfs_dqid_t *usrid,
2bd0ea18
NS
3837 int dq,
3838 xfs_qcnt_t bc,
3839 xfs_qcnt_t ic,
3840 xfs_qcnt_t rc)
3841{
be8e601c
NS
3842 if (qudo && usrid != NULL)
3843 quota_add1(qudata, *usrid, dq, bc, ic, rc);
3844 if (qgdo && grpid != NULL)
3845 quota_add1(qgdata, *grpid, dq, bc, ic, rc);
3846 if (qpdo && prjid != NULL)
3847 quota_add1(qpdata, *prjid, dq, bc, ic, rc);
2bd0ea18
NS
3848}
3849
3850static void
3851quota_add1(
3852 qdata_t **qt,
3853 xfs_dqid_t id,
3854 int dq,
3855 xfs_qcnt_t bc,
3856 xfs_qcnt_t ic,
3857 xfs_qcnt_t rc)
3858{
3859 qdata_t *qe;
3860 int qh;
3861 qinfo_t *qi;
3862
be8e601c 3863 qh = (int)(id % QDATA_HASH_SIZE);
2bd0ea18
NS
3864 qe = qt[qh];
3865 while (qe) {
3866 if (qe->id == id) {
3867 qi = dq ? &qe->dq : &qe->count;
3868 qi->bc += bc;
3869 qi->ic += ic;
3870 qi->rc += rc;
3871 return;
3872 }
3873 qe = qe->next;
3874 }
3875 qe = xmalloc(sizeof(*qe));
3876 qe->id = id;
3877 qi = dq ? &qe->dq : &qe->count;
3878 qi->bc = bc;
3879 qi->ic = ic;
3880 qi->rc = rc;
3881 qi = dq ? &qe->count : &qe->dq;
3882 qi->bc = qi->ic = qi->rc = 0;
3883 qe->next = qt[qh];
3884 qt[qh] = qe;
3885}
3886
3887static void
3888quota_check(
3889 char *s,
3890 qdata_t **qt)
3891{
3892 int i;
3893 qdata_t *next;
3894 qdata_t *qp;
3895
3896 for (i = 0; i < QDATA_HASH_SIZE; i++) {
3897 qp = qt[i];
3898 while (qp) {
3899 next = qp->next;
3900 if (qp->count.bc != qp->dq.bc ||
3901 qp->count.ic != qp->dq.ic ||
3902 qp->count.rc != qp->dq.rc) {
3903 if (!sflag) {
9ee7055c 3904 dbprintf(_("%s quota id %u, have/exp"),
2bd0ea18
NS
3905 s, qp->id);
3906 if (qp->count.bc != qp->dq.bc)
9ee7055c 3907 dbprintf(_(" bc %lld/%lld"),
2bd0ea18
NS
3908 qp->dq.bc,
3909 qp->count.bc);
3910 if (qp->count.ic != qp->dq.ic)
9ee7055c 3911 dbprintf(_(" ic %lld/%lld"),
2bd0ea18
NS
3912 qp->dq.ic,
3913 qp->count.ic);
3914 if (qp->count.rc != qp->dq.rc)
9ee7055c 3915 dbprintf(_(" rc %lld/%lld"),
2bd0ea18
NS
3916 qp->dq.rc,
3917 qp->count.rc);
3918 dbprintf("\n");
3919 }
3920 error++;
3921 }
3922 xfree(qp);
3923 qp = next;
3924 }
3925 }
3926 xfree(qt);
3927}
3928
3929static void
3930quota_init(void)
3931{
3932 qudo = mp->m_sb.sb_uquotino != 0 &&
3933 mp->m_sb.sb_uquotino != NULLFSINO &&
b36eef04 3934 (mp->m_sb.sb_qflags & XFS_UQUOTA_ACCT) &&
2bd0ea18 3935 (mp->m_sb.sb_qflags & XFS_UQUOTA_CHKD);
b36eef04
NS
3936 qgdo = mp->m_sb.sb_gquotino != 0 &&
3937 mp->m_sb.sb_gquotino != NULLFSINO &&
3938 (mp->m_sb.sb_qflags & XFS_GQUOTA_ACCT) &&
342aef1e 3939 (mp->m_sb.sb_qflags & XFS_GQUOTA_CHKD);
0340d706
CS
3940 qpdo = mp->m_sb.sb_pquotino != 0 &&
3941 mp->m_sb.sb_pquotino != NULLFSINO &&
9b27bdbb 3942 (mp->m_sb.sb_qflags & XFS_PQUOTA_ACCT) &&
342aef1e 3943 (mp->m_sb.sb_qflags & XFS_PQUOTA_CHKD);
2bd0ea18
NS
3944 if (qudo)
3945 qudata = xcalloc(QDATA_HASH_SIZE, sizeof(qdata_t *));
b36eef04
NS
3946 if (qgdo)
3947 qgdata = xcalloc(QDATA_HASH_SIZE, sizeof(qdata_t *));
9b27bdbb
NS
3948 if (qpdo)
3949 qpdata = xcalloc(QDATA_HASH_SIZE, sizeof(qdata_t *));
2bd0ea18
NS
3950}
3951
3952static void
3953scan_ag(
3954 xfs_agnumber_t agno)
3955{
3956 xfs_agf_t *agf;
3957 xfs_agi_t *agi;
3958 int i;
3959 xfs_sb_t tsb;
5e656dbb 3960 xfs_sb_t *sb = &tsb;
2bd0ea18
NS
3961
3962 agffreeblks = agflongest = 0;
cdded3d8 3963 agfbtreeblks = -2;
2bd0ea18 3964 agicount = agifreecount = 0;
d24c0a90 3965 push_cur(); /* 1 pushed */
9440d84d
NS
3966 set_cur(&typtab[TYP_SB],
3967 XFS_AG_DADDR(mp, agno, XFS_SB_DADDR),
3968 XFS_FSS_TO_BB(mp, 1), DB_RING_IGN, NULL);
dfc130f3 3969
2bd0ea18 3970 if (!iocur_top->data) {
9ee7055c 3971 dbprintf(_("can't read superblock for ag %u\n"), agno);
2bd0ea18 3972 serious_error++;
d24c0a90 3973 goto pop1_out;
2bd0ea18 3974 }
dfc130f3 3975
5e656dbb 3976 libxfs_sb_from_disk(sb, iocur_top->data);
dfc130f3 3977
2bd0ea18
NS
3978 if (sb->sb_magicnum != XFS_SB_MAGIC) {
3979 if (!sflag)
9ee7055c 3980 dbprintf(_("bad sb magic # %#x in ag %u\n"),
2bd0ea18
NS
3981 sb->sb_magicnum, agno);
3982 error++;
3983 }
5e656dbb 3984 if (!xfs_sb_good_version(sb)) {
2bd0ea18 3985 if (!sflag)
9ee7055c 3986 dbprintf(_("bad sb version # %#x in ag %u\n"),
2bd0ea18
NS
3987 sb->sb_versionnum, agno);
3988 error++;
3989 sbver_err++;
3990 }
5e656dbb 3991 if (!lazycount && xfs_sb_version_haslazysbcount(sb)) {
cdded3d8
DC
3992 lazycount = 1;
3993 }
2bd0ea18
NS
3994 if (agno == 0 && sb->sb_inprogress != 0) {
3995 if (!sflag)
9ee7055c 3996 dbprintf(_("mkfs not completed successfully\n"));
2bd0ea18
NS
3997 error++;
3998 }
67b8ca98
DW
3999 if (xfs_sb_version_needsrepair(sb)) {
4000 if (!sflag)
4001 dbprintf(_("filesystem needs xfs_repair\n"));
4002 error++;
4003 }
2bd0ea18
NS
4004 set_dbmap(agno, XFS_SB_BLOCK(mp), 1, DBM_SB, agno, XFS_SB_BLOCK(mp));
4005 if (sb->sb_logstart && XFS_FSB_TO_AGNO(mp, sb->sb_logstart) == agno)
4006 set_dbmap(agno, XFS_FSB_TO_AGBNO(mp, sb->sb_logstart),
4007 sb->sb_logblocks, DBM_LOG, agno, XFS_SB_BLOCK(mp));
d24c0a90 4008 push_cur(); /* 2 pushed */
9440d84d
NS
4009 set_cur(&typtab[TYP_AGF],
4010 XFS_AG_DADDR(mp, agno, XFS_AGF_DADDR(mp)),
4011 XFS_FSS_TO_BB(mp, 1), DB_RING_IGN, NULL);
2bd0ea18 4012 if ((agf = iocur_top->data) == NULL) {
9ee7055c 4013 dbprintf(_("can't read agf block for ag %u\n"), agno);
2bd0ea18 4014 serious_error++;
d24c0a90 4015 goto pop2_out;
2bd0ea18 4016 }
5e656dbb 4017 if (be32_to_cpu(agf->agf_magicnum) != XFS_AGF_MAGIC) {
2bd0ea18 4018 if (!sflag)
9ee7055c 4019 dbprintf(_("bad agf magic # %#x in ag %u\n"),
5e656dbb 4020 be32_to_cpu(agf->agf_magicnum), agno);
2bd0ea18
NS
4021 error++;
4022 }
5e656dbb 4023 if (!XFS_AGF_GOOD_VERSION(be32_to_cpu(agf->agf_versionnum))) {
2bd0ea18 4024 if (!sflag)
9ee7055c 4025 dbprintf(_("bad agf version # %#x in ag %u\n"),
5e656dbb 4026 be32_to_cpu(agf->agf_versionnum), agno);
2bd0ea18
NS
4027 error++;
4028 }
4029 if (XFS_SB_BLOCK(mp) != XFS_AGF_BLOCK(mp))
4030 set_dbmap(agno, XFS_AGF_BLOCK(mp), 1, DBM_AGF, agno,
4031 XFS_SB_BLOCK(mp));
5e656dbb
BN
4032 if (sb->sb_agblocks > be32_to_cpu(agf->agf_length))
4033 set_dbmap(agno, be32_to_cpu(agf->agf_length),
4034 sb->sb_agblocks - be32_to_cpu(agf->agf_length),
2bd0ea18 4035 DBM_MISSING, agno, XFS_SB_BLOCK(mp));
d24c0a90 4036 push_cur(); /* 3 pushed */
9440d84d
NS
4037 set_cur(&typtab[TYP_AGI],
4038 XFS_AG_DADDR(mp, agno, XFS_AGI_DADDR(mp)),
4039 XFS_FSS_TO_BB(mp, 1), DB_RING_IGN, NULL);
2bd0ea18 4040 if ((agi = iocur_top->data) == NULL) {
9ee7055c 4041 dbprintf(_("can't read agi block for ag %u\n"), agno);
2bd0ea18 4042 serious_error++;
d24c0a90 4043 goto pop3_out;
2bd0ea18 4044 }
5e656dbb 4045 if (be32_to_cpu(agi->agi_magicnum) != XFS_AGI_MAGIC) {
2bd0ea18 4046 if (!sflag)
9ee7055c 4047 dbprintf(_("bad agi magic # %#x in ag %u\n"),
5e656dbb 4048 be32_to_cpu(agi->agi_magicnum), agno);
2bd0ea18
NS
4049 error++;
4050 }
5e656dbb 4051 if (!XFS_AGI_GOOD_VERSION(be32_to_cpu(agi->agi_versionnum))) {
2bd0ea18 4052 if (!sflag)
9ee7055c 4053 dbprintf(_("bad agi version # %#x in ag %u\n"),
5e656dbb 4054 be32_to_cpu(agi->agi_versionnum), agno);
2bd0ea18
NS
4055 error++;
4056 }
4057 if (XFS_SB_BLOCK(mp) != XFS_AGI_BLOCK(mp) &&
4058 XFS_AGF_BLOCK(mp) != XFS_AGI_BLOCK(mp))
4059 set_dbmap(agno, XFS_AGI_BLOCK(mp), 1, DBM_AGI, agno,
4060 XFS_SB_BLOCK(mp));
4061 scan_freelist(agf);
4062 fdblocks--;
4063 scan_sbtree(agf,
5e656dbb
BN
4064 be32_to_cpu(agf->agf_roots[XFS_BTNUM_BNO]),
4065 be32_to_cpu(agf->agf_levels[XFS_BTNUM_BNO]),
2bd0ea18
NS
4066 1, scanfunc_bno, TYP_BNOBT);
4067 fdblocks--;
4068 scan_sbtree(agf,
5e656dbb
BN
4069 be32_to_cpu(agf->agf_roots[XFS_BTNUM_CNT]),
4070 be32_to_cpu(agf->agf_levels[XFS_BTNUM_CNT]),
2bd0ea18 4071 1, scanfunc_cnt, TYP_CNTBT);
e3dcc17b
DW
4072 if (agf->agf_roots[XFS_BTNUM_RMAP]) {
4073 scan_sbtree(agf,
4074 be32_to_cpu(agf->agf_roots[XFS_BTNUM_RMAP]),
4075 be32_to_cpu(agf->agf_levels[XFS_BTNUM_RMAP]),
4076 1, scanfunc_rmap, TYP_RMAPBT);
4077 }
757ad8c7
DW
4078 if (agf->agf_refcount_root) {
4079 scan_sbtree(agf,
4080 be32_to_cpu(agf->agf_refcount_root),
4081 be32_to_cpu(agf->agf_refcount_level),
4082 1, scanfunc_refcnt, TYP_REFCBT);
4083 }
2bd0ea18 4084 scan_sbtree(agf,
5e656dbb
BN
4085 be32_to_cpu(agi->agi_root),
4086 be32_to_cpu(agi->agi_level),
2bd0ea18 4087 1, scanfunc_ino, TYP_INOBT);
e96864ff
DW
4088 if (agi->agi_free_root) {
4089 scan_sbtree(agf,
4090 be32_to_cpu(agi->agi_free_root),
4091 be32_to_cpu(agi->agi_free_level),
4092 1, scanfunc_fino, TYP_FINOBT);
4093 }
5e656dbb 4094 if (be32_to_cpu(agf->agf_freeblks) != agffreeblks) {
2bd0ea18 4095 if (!sflag)
9ee7055c 4096 dbprintf(_("agf_freeblks %u, counted %u in ag %u\n"),
5e656dbb 4097 be32_to_cpu(agf->agf_freeblks),
2bd0ea18
NS
4098 agffreeblks, agno);
4099 error++;
4100 }
5e656dbb 4101 if (be32_to_cpu(agf->agf_longest) != agflongest) {
2bd0ea18 4102 if (!sflag)
9ee7055c 4103 dbprintf(_("agf_longest %u, counted %u in ag %u\n"),
5e656dbb 4104 be32_to_cpu(agf->agf_longest),
2bd0ea18
NS
4105 agflongest, agno);
4106 error++;
4107 }
cdded3d8 4108 if (lazycount &&
5e656dbb 4109 be32_to_cpu(agf->agf_btreeblks) != agfbtreeblks) {
cdded3d8 4110 if (!sflag)
9ee7055c 4111 dbprintf(_("agf_btreeblks %u, counted %u in ag %u\n"),
5e656dbb 4112 be32_to_cpu(agf->agf_btreeblks),
cdded3d8
DC
4113 agfbtreeblks, agno);
4114 error++;
4115 }
4116 agf_aggr_freeblks += agffreeblks + agfbtreeblks;
5e656dbb 4117 if (be32_to_cpu(agi->agi_count) != agicount) {
2bd0ea18 4118 if (!sflag)
9ee7055c 4119 dbprintf(_("agi_count %u, counted %u in ag %u\n"),
5e656dbb 4120 be32_to_cpu(agi->agi_count),
2bd0ea18
NS
4121 agicount, agno);
4122 error++;
4123 }
5e656dbb 4124 if (be32_to_cpu(agi->agi_freecount) != agifreecount) {
2bd0ea18 4125 if (!sflag)
9ee7055c 4126 dbprintf(_("agi_freecount %u, counted %u in ag %u\n"),
5e656dbb 4127 be32_to_cpu(agi->agi_freecount),
2bd0ea18
NS
4128 agifreecount, agno);
4129 error++;
4130 }
4131 for (i = 0; i < XFS_AGI_UNLINKED_BUCKETS; i++) {
5e656dbb 4132 if (be32_to_cpu(agi->agi_unlinked[i]) != NULLAGINO) {
2bd0ea18 4133 if (!sflag) {
5e656dbb 4134 xfs_agino_t agino=be32_to_cpu(agi->agi_unlinked[i]);
9ee7055c
AM
4135 dbprintf(_("agi unlinked bucket %d is %u in ag "
4136 "%u (inode=%lld)\n"), i, agino, agno,
dfc130f3
RC
4137 XFS_AGINO_TO_INO(mp, agno, agino));
4138 }
2bd0ea18
NS
4139 error++;
4140 }
4141 }
d24c0a90 4142pop3_out:
2bd0ea18 4143 pop_cur();
d24c0a90 4144pop2_out:
2bd0ea18 4145 pop_cur();
d24c0a90 4146pop1_out:
2bd0ea18
NS
4147 pop_cur();
4148}
4149
581c24aa
DW
4150struct agfl_state {
4151 xfs_agnumber_t agno;
4152 unsigned int count;
4153};
4154
4155static int
4156scan_agfl(
4157 struct xfs_mount *mp,
4158 xfs_agblock_t bno,
4159 void *priv)
4160{
4161 struct agfl_state *as = priv;
4162
4163 set_dbmap(as->agno, bno, 1, DBM_FREELIST, as->agno, XFS_AGFL_BLOCK(mp));
4164 as->count++;
4165 return 0;
4166}
4167
2bd0ea18
NS
4168static void
4169scan_freelist(
581c24aa 4170 xfs_agf_t *agf)
2bd0ea18 4171{
581c24aa
DW
4172 xfs_agnumber_t seqno = be32_to_cpu(agf->agf_seqno);
4173 struct agfl_state state;
2bd0ea18
NS
4174
4175 if (XFS_SB_BLOCK(mp) != XFS_AGFL_BLOCK(mp) &&
4176 XFS_AGF_BLOCK(mp) != XFS_AGFL_BLOCK(mp) &&
4177 XFS_AGI_BLOCK(mp) != XFS_AGFL_BLOCK(mp))
4178 set_dbmap(seqno, XFS_AGFL_BLOCK(mp), 1, DBM_AGFL, seqno,
4179 XFS_SB_BLOCK(mp));
5e656dbb 4180 if (be32_to_cpu(agf->agf_flcount) == 0)
2bd0ea18
NS
4181 return;
4182 push_cur();
4183 set_cur(&typtab[TYP_AGFL],
9440d84d
NS
4184 XFS_AG_DADDR(mp, seqno, XFS_AGFL_DADDR(mp)),
4185 XFS_FSS_TO_BB(mp, 1), DB_RING_IGN, NULL);
581c24aa 4186 if (iocur_top->data == NULL) {
9ee7055c 4187 dbprintf(_("can't read agfl block for ag %u\n"), seqno);
2bd0ea18 4188 serious_error++;
d24c0a90 4189 pop_cur();
2bd0ea18
NS
4190 return;
4191 }
a529cc7f
ES
4192
4193 /* verify agf values before proceeding */
b8165508
DC
4194 if (be32_to_cpu(agf->agf_flfirst) >= libxfs_agfl_size(mp) ||
4195 be32_to_cpu(agf->agf_fllast) >= libxfs_agfl_size(mp)) {
a529cc7f 4196 dbprintf(_("agf %d freelist blocks bad, skipping "
581c24aa 4197 "freelist scan\n"), seqno);
a529cc7f
ES
4198 pop_cur();
4199 return;
4200 }
4201
30f8e916 4202 /* open coded xfs_buf_to_agfl_bno */
581c24aa
DW
4203 state.count = 0;
4204 state.agno = seqno;
4205 libxfs_agfl_walk(mp, agf, iocur_top->bp, scan_agfl, &state);
4206 if (state.count != be32_to_cpu(agf->agf_flcount)) {
2bd0ea18 4207 if (!sflag)
9ee7055c 4208 dbprintf(_("freeblk count %u != flcount %u in ag %u\n"),
581c24aa
DW
4209 state.count,
4210 be32_to_cpu(agf->agf_flcount),
4211 seqno);
2bd0ea18
NS
4212 error++;
4213 }
581c24aa
DW
4214 fdblocks += state.count;
4215 agf_aggr_freeblks += state.count;
2bd0ea18
NS
4216 pop_cur();
4217}
4218
4219static void
4220scan_lbtree(
4221 xfs_fsblock_t root,
4222 int nlevels,
4223 scan_lbtree_f_t func,
4224 dbm_t type,
4225 inodata_t *id,
5a35bf2c
DC
4226 xfs_rfsblock_t *totd,
4227 xfs_rfsblock_t *toti,
2bd0ea18
NS
4228 xfs_extnum_t *nex,
4229 blkmap_t **blkmapp,
4230 int isroot,
4231 typnm_t btype)
4232{
4233 push_cur();
4234 set_cur(&typtab[btype], XFS_FSB_TO_DADDR(mp, root), blkbb, DB_RING_IGN,
4235 NULL);
4236 if (iocur_top->data == NULL) {
4237 if (!sflag)
9ee7055c 4238 dbprintf(_("can't read btree block %u/%u\n"),
2bd0ea18
NS
4239 XFS_FSB_TO_AGNO(mp, root),
4240 XFS_FSB_TO_AGBNO(mp, root));
4241 error++;
d24c0a90 4242 pop_cur();
2bd0ea18
NS
4243 return;
4244 }
4245 (*func)(iocur_top->data, nlevels - 1, type, root, id, totd, toti, nex,
4246 blkmapp, isroot, btype);
4247 pop_cur();
4248}
4249
4250static void
4251scan_sbtree(
4252 xfs_agf_t *agf,
4253 xfs_agblock_t root,
4254 int nlevels,
4255 int isroot,
4256 scan_sbtree_f_t func,
4257 typnm_t btype)
4258{
5e656dbb 4259 xfs_agnumber_t seqno = be32_to_cpu(agf->agf_seqno);
2bd0ea18
NS
4260
4261 push_cur();
4262 set_cur(&typtab[btype],
4263 XFS_AGB_TO_DADDR(mp, seqno, root), blkbb, DB_RING_IGN, NULL);
4264 if (iocur_top->data == NULL) {
4265 if (!sflag)
9ee7055c 4266 dbprintf(_("can't read btree block %u/%u\n"), seqno, root);
2bd0ea18 4267 error++;
d24c0a90 4268 pop_cur();
2bd0ea18
NS
4269 return;
4270 }
4271 (*func)(iocur_top->data, nlevels - 1, agf, root, isroot);
4272 pop_cur();
4273}
4274
4275static void
4276scanfunc_bmap(
b3563c19 4277 struct xfs_btree_block *block,
2bd0ea18
NS
4278 int level,
4279 dbm_t type,
4280 xfs_fsblock_t bno,
4281 inodata_t *id,
5a35bf2c
DC
4282 xfs_rfsblock_t *totd,
4283 xfs_rfsblock_t *toti,
2bd0ea18
NS
4284 xfs_extnum_t *nex,
4285 blkmap_t **blkmapp,
4286 int isroot,
4287 typnm_t btype)
4288{
4289 xfs_agblock_t agbno;
4290 xfs_agnumber_t agno;
2bd0ea18
NS
4291 int i;
4292 xfs_bmbt_ptr_t *pp;
b9652a81 4293 xfs_bmbt_rec_t *rp;
2bd0ea18
NS
4294
4295 agno = XFS_FSB_TO_AGNO(mp, bno);
4296 agbno = XFS_FSB_TO_AGBNO(mp, bno);
e96864ff
DW
4297 if (be32_to_cpu(block->bb_magic) != XFS_BMAP_MAGIC &&
4298 be32_to_cpu(block->bb_magic) != XFS_BMAP_CRC_MAGIC) {
2bd0ea18 4299 if (!sflag || id->ilist || CHECK_BLIST(bno))
9ee7055c
AM
4300 dbprintf(_("bad magic # %#x in inode %lld bmbt block "
4301 "%u/%u\n"),
5e656dbb 4302 be32_to_cpu(block->bb_magic), id->ino, agno, agbno);
2bd0ea18
NS
4303 error++;
4304 }
5e656dbb 4305 if (be16_to_cpu(block->bb_level) != level) {
2bd0ea18 4306 if (!sflag || id->ilist || CHECK_BLIST(bno))
9ee7055c
AM
4307 dbprintf(_("expected level %d got %d in inode %lld bmbt "
4308 "block %u/%u\n"),
5e656dbb 4309 level, be16_to_cpu(block->bb_level), id->ino, agno, agbno);
2bd0ea18
NS
4310 error++;
4311 }
4312 set_dbmap(agno, agbno, 1, type, agno, agbno);
4313 set_inomap(agno, agbno, 1, id);
4314 (*toti)++;
4315 if (level == 0) {
5e656dbb
BN
4316 if (be16_to_cpu(block->bb_numrecs) > mp->m_bmap_dmxr[0] ||
4317 (isroot == 0 && be16_to_cpu(block->bb_numrecs) < mp->m_bmap_dmnr[0])) {
2bd0ea18 4318 if (!sflag || id->ilist || CHECK_BLIST(bno))
9ee7055c
AM
4319 dbprintf(_("bad btree nrecs (%u, min=%u, max=%u) "
4320 "in inode %lld bmap block %lld\n"),
5e656dbb 4321 be16_to_cpu(block->bb_numrecs), mp->m_bmap_dmnr[0],
2bd0ea18 4322 mp->m_bmap_dmxr[0], id->ino,
5a35bf2c 4323 (xfs_fsblock_t)bno);
2bd0ea18
NS
4324 error++;
4325 return;
4326 }
b9652a81 4327 rp = XFS_BMBT_REC_ADDR(mp, block, 1);
5e656dbb
BN
4328 *nex += be16_to_cpu(block->bb_numrecs);
4329 process_bmbt_reclist(rp, be16_to_cpu(block->bb_numrecs), type, id, totd,
2bd0ea18
NS
4330 blkmapp);
4331 return;
4332 }
5e656dbb
BN
4333 if (be16_to_cpu(block->bb_numrecs) > mp->m_bmap_dmxr[1] ||
4334 (isroot == 0 && be16_to_cpu(block->bb_numrecs) < mp->m_bmap_dmnr[1])) {
2bd0ea18 4335 if (!sflag || id->ilist || CHECK_BLIST(bno))
9ee7055c
AM
4336 dbprintf(_("bad btree nrecs (%u, min=%u, max=%u) in "
4337 "inode %lld bmap block %lld\n"),
5e656dbb 4338 be16_to_cpu(block->bb_numrecs), mp->m_bmap_dmnr[1],
5a35bf2c 4339 mp->m_bmap_dmxr[1], id->ino, (xfs_fsblock_t)bno);
2bd0ea18
NS
4340 error++;
4341 return;
4342 }
b3563c19 4343 pp = XFS_BMBT_PTR_ADDR(mp, block, 1, mp->m_bmap_dmxr[0]);
5e656dbb 4344 for (i = 0; i < be16_to_cpu(block->bb_numrecs); i++)
f8149110 4345 scan_lbtree(be64_to_cpu(pp[i]), level, scanfunc_bmap, type, id,
5e656dbb 4346 totd, toti, nex, blkmapp, 0, btype);
2bd0ea18
NS
4347}
4348
4349static void
4350scanfunc_bno(
b3563c19 4351 struct xfs_btree_block *block,
2bd0ea18
NS
4352 int level,
4353 xfs_agf_t *agf,
4354 xfs_agblock_t bno,
4355 int isroot)
4356{
2bd0ea18
NS
4357 int i;
4358 xfs_alloc_ptr_t *pp;
4359 xfs_alloc_rec_t *rp;
5e656dbb 4360 xfs_agnumber_t seqno = be32_to_cpu(agf->agf_seqno);
9ac8ea13 4361 xfs_agblock_t lastblock;
2bd0ea18 4362
e96864ff
DW
4363 if (be32_to_cpu(block->bb_magic) != XFS_ABTB_MAGIC &&
4364 be32_to_cpu(block->bb_magic) != XFS_ABTB_CRC_MAGIC) {
9ee7055c 4365 dbprintf(_("bad magic # %#x in btbno block %u/%u\n"),
5e656dbb 4366 be32_to_cpu(block->bb_magic), seqno, bno);
2bd0ea18
NS
4367 serious_error++;
4368 return;
4369 }
4370 fdblocks++;
cdded3d8 4371 agfbtreeblks++;
5e656dbb 4372 if (be16_to_cpu(block->bb_level) != level) {
2bd0ea18 4373 if (!sflag)
9ee7055c
AM
4374 dbprintf(_("expected level %d got %d in btbno block "
4375 "%u/%u\n"),
5e656dbb 4376 level, be16_to_cpu(block->bb_level), seqno, bno);
2bd0ea18
NS
4377 error++;
4378 }
4379 set_dbmap(seqno, bno, 1, DBM_BTBNO, seqno, bno);
4380 if (level == 0) {
5e656dbb
BN
4381 if (be16_to_cpu(block->bb_numrecs) > mp->m_alloc_mxr[0] ||
4382 (isroot == 0 && be16_to_cpu(block->bb_numrecs) < mp->m_alloc_mnr[0])) {
9ee7055c
AM
4383 dbprintf(_("bad btree nrecs (%u, min=%u, max=%u) in "
4384 "btbno block %u/%u\n"),
5e656dbb 4385 be16_to_cpu(block->bb_numrecs), mp->m_alloc_mnr[0],
2bd0ea18
NS
4386 mp->m_alloc_mxr[0], seqno, bno);
4387 serious_error++;
4388 return;
4389 }
b3563c19 4390 rp = XFS_ALLOC_REC_ADDR(mp, block, 1);
9ac8ea13 4391 lastblock = 0;
5e656dbb
BN
4392 for (i = 0; i < be16_to_cpu(block->bb_numrecs); i++) {
4393 set_dbmap(seqno, be32_to_cpu(rp[i].ar_startblock),
4394 be32_to_cpu(rp[i].ar_blockcount), DBM_FREE1,
2bd0ea18 4395 seqno, bno);
5e656dbb 4396 if (be32_to_cpu(rp[i].ar_startblock) <= lastblock) {
9ee7055c
AM
4397 dbprintf(_(
4398 "out-of-order bno btree record %d (%u %u) block %u/%u\n"),
5e656dbb
BN
4399 i, be32_to_cpu(rp[i].ar_startblock),
4400 be32_to_cpu(rp[i].ar_blockcount),
4401 be32_to_cpu(agf->agf_seqno), bno);
9ac8ea13
GO
4402 serious_error++;
4403 } else {
5e656dbb 4404 lastblock = be32_to_cpu(rp[i].ar_startblock);
9ac8ea13 4405 }
2bd0ea18
NS
4406 }
4407 return;
4408 }
5e656dbb
BN
4409 if (be16_to_cpu(block->bb_numrecs) > mp->m_alloc_mxr[1] ||
4410 (isroot == 0 && be16_to_cpu(block->bb_numrecs) < mp->m_alloc_mnr[1])) {
9ee7055c
AM
4411 dbprintf(_("bad btree nrecs (%u, min=%u, max=%u) in btbno block "
4412 "%u/%u\n"),
5e656dbb 4413 be16_to_cpu(block->bb_numrecs), mp->m_alloc_mnr[1],
2bd0ea18
NS
4414 mp->m_alloc_mxr[1], seqno, bno);
4415 serious_error++;
4416 return;
4417 }
b3563c19 4418 pp = XFS_ALLOC_PTR_ADDR(mp, block, 1, mp->m_alloc_mxr[1]);
5e656dbb
BN
4419 for (i = 0; i < be16_to_cpu(block->bb_numrecs); i++)
4420 scan_sbtree(agf, be32_to_cpu(pp[i]), level, 0, scanfunc_bno, TYP_BNOBT);
2bd0ea18
NS
4421}
4422
4423static void
4424scanfunc_cnt(
b3563c19 4425 struct xfs_btree_block *block,
2bd0ea18
NS
4426 int level,
4427 xfs_agf_t *agf,
4428 xfs_agblock_t bno,
4429 int isroot)
4430{
5e656dbb 4431 xfs_agnumber_t seqno = be32_to_cpu(agf->agf_seqno);
2bd0ea18
NS
4432 int i;
4433 xfs_alloc_ptr_t *pp;
4434 xfs_alloc_rec_t *rp;
9ac8ea13 4435 xfs_extlen_t lastcount;
2bd0ea18 4436
e96864ff
DW
4437 if (be32_to_cpu(block->bb_magic) != XFS_ABTC_MAGIC &&
4438 be32_to_cpu(block->bb_magic) != XFS_ABTC_CRC_MAGIC) {
9ee7055c 4439 dbprintf(_("bad magic # %#x in btcnt block %u/%u\n"),
5e656dbb 4440 be32_to_cpu(block->bb_magic), seqno, bno);
2bd0ea18
NS
4441 serious_error++;
4442 return;
4443 }
4444 fdblocks++;
cdded3d8 4445 agfbtreeblks++;
5e656dbb 4446 if (be16_to_cpu(block->bb_level) != level) {
2bd0ea18 4447 if (!sflag)
9ee7055c
AM
4448 dbprintf(_("expected level %d got %d in btcnt block "
4449 "%u/%u\n"),
5e656dbb 4450 level, be16_to_cpu(block->bb_level), seqno, bno);
2bd0ea18
NS
4451 error++;
4452 }
4453 set_dbmap(seqno, bno, 1, DBM_BTCNT, seqno, bno);
4454 if (level == 0) {
5e656dbb
BN
4455 if (be16_to_cpu(block->bb_numrecs) > mp->m_alloc_mxr[0] ||
4456 (isroot == 0 && be16_to_cpu(block->bb_numrecs) < mp->m_alloc_mnr[0])) {
9ee7055c
AM
4457 dbprintf(_("bad btree nrecs (%u, min=%u, max=%u) in "
4458 "btbno block %u/%u\n"),
5e656dbb 4459 be16_to_cpu(block->bb_numrecs), mp->m_alloc_mnr[0],
2bd0ea18
NS
4460 mp->m_alloc_mxr[0], seqno, bno);
4461 serious_error++;
4462 return;
4463 }
b3563c19 4464 rp = XFS_ALLOC_REC_ADDR(mp, block, 1);
9ac8ea13 4465 lastcount = 0;
5e656dbb
BN
4466 for (i = 0; i < be16_to_cpu(block->bb_numrecs); i++) {
4467 check_set_dbmap(seqno, be32_to_cpu(rp[i].ar_startblock),
4468 be32_to_cpu(rp[i].ar_blockcount), DBM_FREE1, DBM_FREE2,
2bd0ea18 4469 seqno, bno);
5e656dbb
BN
4470 fdblocks += be32_to_cpu(rp[i].ar_blockcount);
4471 agffreeblks += be32_to_cpu(rp[i].ar_blockcount);
4472 if (be32_to_cpu(rp[i].ar_blockcount) > agflongest)
4473 agflongest = be32_to_cpu(rp[i].ar_blockcount);
4474 if (be32_to_cpu(rp[i].ar_blockcount) < lastcount) {
9ee7055c
AM
4475 dbprintf(_(
4476 "out-of-order cnt btree record %d (%u %u) block %u/%u\n"),
5e656dbb
BN
4477 i, be32_to_cpu(rp[i].ar_startblock),
4478 be32_to_cpu(rp[i].ar_blockcount),
4479 be32_to_cpu(agf->agf_seqno), bno);
9ac8ea13 4480 } else {
5e656dbb 4481 lastcount = be32_to_cpu(rp[i].ar_blockcount);
9ac8ea13 4482 }
2bd0ea18
NS
4483 }
4484 return;
4485 }
5e656dbb
BN
4486 if (be16_to_cpu(block->bb_numrecs) > mp->m_alloc_mxr[1] ||
4487 (isroot == 0 && be16_to_cpu(block->bb_numrecs) < mp->m_alloc_mnr[1])) {
9ee7055c
AM
4488 dbprintf(_("bad btree nrecs (%u, min=%u, max=%u) in btbno block "
4489 "%u/%u\n"),
5e656dbb 4490 be16_to_cpu(block->bb_numrecs), mp->m_alloc_mnr[1],
2bd0ea18
NS
4491 mp->m_alloc_mxr[1], seqno, bno);
4492 serious_error++;
4493 return;
4494 }
b3563c19 4495 pp = XFS_ALLOC_PTR_ADDR(mp, block, 1, mp->m_alloc_mxr[1]);
5e656dbb
BN
4496 for (i = 0; i < be16_to_cpu(block->bb_numrecs); i++)
4497 scan_sbtree(agf, be32_to_cpu(pp[i]), level, 0, scanfunc_cnt, TYP_CNTBT);
2bd0ea18
NS
4498}
4499
4500static void
4501scanfunc_ino(
b3563c19 4502 struct xfs_btree_block *block,
2bd0ea18
NS
4503 int level,
4504 xfs_agf_t *agf,
4505 xfs_agblock_t bno,
4506 int isroot)
4507{
4508 xfs_agino_t agino;
5e656dbb 4509 xfs_agnumber_t seqno = be32_to_cpu(agf->agf_seqno);
2bd0ea18
NS
4510 int i;
4511 int isfree;
4512 int j;
ea8a48fa 4513 int freecount;
2bd0ea18
NS
4514 int nfree;
4515 int off;
4516 xfs_inobt_ptr_t *pp;
4517 xfs_inobt_rec_t *rp;
ea8a48fa
BF
4518 xfs_agblock_t agbno;
4519 xfs_agblock_t end_agbno;
4520 struct xfs_dinode *dip;
4521 int blks_per_buf;
4522 int inodes_per_buf;
4523 int ioff;
e7fd2b6f 4524 struct xfs_ino_geometry *igeo = M_IGEO(mp);
ea8a48fa 4525
2660e653 4526 if (xfs_has_sparseinodes(mp))
e7fd2b6f 4527 blks_per_buf = igeo->blocks_per_cluster;
ea8a48fa 4528 else
e7fd2b6f 4529 blks_per_buf = igeo->ialloc_blks;
7516da71 4530 inodes_per_buf = min(XFS_FSB_TO_INO(mp, blks_per_buf),
ea8a48fa 4531 XFS_INODES_PER_CHUNK);
2bd0ea18 4532
e96864ff
DW
4533 if (be32_to_cpu(block->bb_magic) != XFS_IBT_MAGIC &&
4534 be32_to_cpu(block->bb_magic) != XFS_IBT_CRC_MAGIC) {
9ee7055c 4535 dbprintf(_("bad magic # %#x in inobt block %u/%u\n"),
5e656dbb 4536 be32_to_cpu(block->bb_magic), seqno, bno);
2bd0ea18
NS
4537 serious_error++;
4538 return;
4539 }
5e656dbb 4540 if (be16_to_cpu(block->bb_level) != level) {
2bd0ea18 4541 if (!sflag)
9ee7055c
AM
4542 dbprintf(_("expected level %d got %d in inobt block "
4543 "%u/%u\n"),
5e656dbb 4544 level, be16_to_cpu(block->bb_level), seqno, bno);
2bd0ea18
NS
4545 error++;
4546 }
4547 set_dbmap(seqno, bno, 1, DBM_BTINO, seqno, bno);
4548 if (level == 0) {
e7fd2b6f
DW
4549 if (be16_to_cpu(block->bb_numrecs) > igeo->inobt_mxr[0] ||
4550 (isroot == 0 && be16_to_cpu(block->bb_numrecs) < igeo->inobt_mnr[0])) {
9ee7055c
AM
4551 dbprintf(_("bad btree nrecs (%u, min=%u, max=%u) in "
4552 "inobt block %u/%u\n"),
e7fd2b6f
DW
4553 be16_to_cpu(block->bb_numrecs), igeo->inobt_mnr[0],
4554 igeo->inobt_mxr[0], seqno, bno);
2bd0ea18
NS
4555 serious_error++;
4556 return;
4557 }
b3563c19 4558 rp = XFS_INOBT_REC_ADDR(mp, block, 1);
5e656dbb
BN
4559 for (i = 0; i < be16_to_cpu(block->bb_numrecs); i++) {
4560 agino = be32_to_cpu(rp[i].ir_startino);
ea8a48fa
BF
4561 agbno = XFS_AGINO_TO_AGBNO(mp, agino);
4562 off = XFS_AGINO_TO_OFFSET(mp, agino);
e7fd2b6f 4563 end_agbno = agbno + igeo->ialloc_blks;
09c93e56
BF
4564 if (off == 0) {
4565 if ((sbversion & XFS_SB_VERSION_ALIGNBIT) &&
4566 mp->m_sb.sb_inoalignmt &&
4567 (XFS_INO_TO_AGBNO(mp, agino) %
4568 mp->m_sb.sb_inoalignmt))
2bd0ea18 4569 sbversion &= ~XFS_SB_VERSION_ALIGNBIT;
2bd0ea18 4570 }
ea8a48fa 4571
09c93e56 4572 push_cur();
ea8a48fa
BF
4573
4574 ioff = 0;
4575 nfree = 0;
4576 while (agbno < end_agbno &&
4577 ioff < XFS_INODES_PER_CHUNK) {
4578 if (xfs_inobt_is_sparse_disk(&rp[i], ioff))
4579 goto next_buf;
4580
4581 if (off < XFS_INODES_PER_CHUNK)
4582 set_dbmap(seqno, agbno, blks_per_buf,
4583 DBM_INODE, seqno, bno);
4584
4585 icount += inodes_per_buf;
4586 agicount += inodes_per_buf;
4587
4588 set_cur(&typtab[TYP_INODE],
4589 XFS_AGB_TO_DADDR(mp, seqno, agbno),
4590 XFS_FSB_TO_BB(mp, blks_per_buf),
4591 DB_RING_IGN, NULL);
4592 if (iocur_top->data == NULL) {
4593 if (!sflag)
4594 dbprintf(_("can't read inode block "
4595 "%u/%u\n"), seqno,
4596 agbno);
4597 error++;
4598 goto next_buf;
4599 }
4600
4601 for (j = 0; j < inodes_per_buf; j++) {
4602 isfree = XFS_INOBT_IS_FREE_DISK(&rp[i], ioff + j);
4603 if (isfree)
4604 nfree++;
7328ea6e 4605 dip = (struct xfs_dinode *)((char *)iocur_top->data +
ea8a48fa
BF
4606 ((off + j) << mp->m_sb.sb_inodelog));
4607 process_inode(agf, agino + ioff + j, dip, isfree);
4608 }
4609
4610next_buf:
4611 agbno += blks_per_buf;
4612 ioff += inodes_per_buf;
09c93e56 4613 }
ea8a48fa 4614
2660e653 4615 if (xfs_has_sparseinodes(mp))
ea8a48fa
BF
4616 freecount = rp[i].ir_u.sp.ir_freecount;
4617 else
4618 freecount = be32_to_cpu(rp[i].ir_u.f.ir_freecount);
4619
4620 ifree += freecount;
4621 agifreecount += freecount;
4622
4623 if (nfree != freecount) {
2bd0ea18 4624 if (!sflag)
9ee7055c 4625 dbprintf(_("ir_freecount/free mismatch, "
2bd0ea18 4626 "inode chunk %u/%u, freecount "
9ee7055c 4627 "%d nfree %d\n"),
ea8a48fa 4628 seqno, agino, freecount, nfree);
2bd0ea18
NS
4629 error++;
4630 }
09c93e56 4631 pop_cur();
2bd0ea18
NS
4632 }
4633 return;
4634 }
e7fd2b6f
DW
4635 if (be16_to_cpu(block->bb_numrecs) > igeo->inobt_mxr[1] ||
4636 (isroot == 0 && be16_to_cpu(block->bb_numrecs) < igeo->inobt_mnr[1])) {
9ee7055c
AM
4637 dbprintf(_("bad btree nrecs (%u, min=%u, max=%u) in inobt block "
4638 "%u/%u\n"),
e7fd2b6f
DW
4639 be16_to_cpu(block->bb_numrecs), igeo->inobt_mnr[1],
4640 igeo->inobt_mxr[1], seqno, bno);
2bd0ea18
NS
4641 serious_error++;
4642 return;
4643 }
e7fd2b6f 4644 pp = XFS_INOBT_PTR_ADDR(mp, block, 1, igeo->inobt_mxr[1]);
5e656dbb
BN
4645 for (i = 0; i < be16_to_cpu(block->bb_numrecs); i++)
4646 scan_sbtree(agf, be32_to_cpu(pp[i]), level, 0, scanfunc_ino, TYP_INOBT);
2bd0ea18
NS
4647}
4648
e96864ff
DW
4649static void
4650scanfunc_fino(
4651 struct xfs_btree_block *block,
4652 int level,
4653 struct xfs_agf *agf,
4654 xfs_agblock_t bno,
4655 int isroot)
4656{
4657 xfs_agino_t agino;
4658 xfs_agnumber_t seqno = be32_to_cpu(agf->agf_seqno);
4659 int i;
4660 int off;
4661 xfs_inobt_ptr_t *pp;
4662 struct xfs_inobt_rec *rp;
ea8a48fa
BF
4663 xfs_agblock_t agbno;
4664 xfs_agblock_t end_agbno;
4665 int blks_per_buf;
4666 int inodes_per_buf;
4667 int ioff;
e7fd2b6f 4668 struct xfs_ino_geometry *igeo = M_IGEO(mp);
ea8a48fa 4669
2660e653 4670 if (xfs_has_sparseinodes(mp))
e7fd2b6f 4671 blks_per_buf = igeo->blocks_per_cluster;
ea8a48fa 4672 else
e7fd2b6f 4673 blks_per_buf = igeo->ialloc_blks;
7516da71 4674 inodes_per_buf = min(XFS_FSB_TO_INO(mp, blks_per_buf),
ea8a48fa 4675 XFS_INODES_PER_CHUNK);
e96864ff
DW
4676
4677 if (be32_to_cpu(block->bb_magic) != XFS_FIBT_MAGIC &&
4678 be32_to_cpu(block->bb_magic) != XFS_FIBT_CRC_MAGIC) {
4679 dbprintf(_("bad magic # %#x in finobt block %u/%u\n"),
4680 be32_to_cpu(block->bb_magic), seqno, bno);
4681 serious_error++;
4682 return;
4683 }
4684 if (be16_to_cpu(block->bb_level) != level) {
4685 if (!sflag)
4686 dbprintf(_("expected level %d got %d in finobt block "
4687 "%u/%u\n"),
4688 level, be16_to_cpu(block->bb_level), seqno, bno);
4689 error++;
4690 }
4691 set_dbmap(seqno, bno, 1, DBM_BTFINO, seqno, bno);
4692 if (level == 0) {
e7fd2b6f
DW
4693 if (be16_to_cpu(block->bb_numrecs) > igeo->inobt_mxr[0] ||
4694 (isroot == 0 && be16_to_cpu(block->bb_numrecs) < igeo->inobt_mnr[0])) {
e96864ff
DW
4695 dbprintf(_("bad btree nrecs (%u, min=%u, max=%u) in "
4696 "finobt block %u/%u\n"),
e7fd2b6f
DW
4697 be16_to_cpu(block->bb_numrecs), igeo->inobt_mnr[0],
4698 igeo->inobt_mxr[0], seqno, bno);
e96864ff
DW
4699 serious_error++;
4700 return;
4701 }
4702 rp = XFS_INOBT_REC_ADDR(mp, block, 1);
4703 for (i = 0; i < be16_to_cpu(block->bb_numrecs); i++) {
4704 agino = be32_to_cpu(rp[i].ir_startino);
ea8a48fa
BF
4705 agbno = XFS_AGINO_TO_AGBNO(mp, agino);
4706 off = XFS_AGINO_TO_OFFSET(mp, agino);
e7fd2b6f 4707 end_agbno = agbno + igeo->ialloc_blks;
09c93e56
BF
4708 if (off == 0) {
4709 if ((sbversion & XFS_SB_VERSION_ALIGNBIT) &&
4710 mp->m_sb.sb_inoalignmt &&
4711 (XFS_INO_TO_AGBNO(mp, agino) %
4712 mp->m_sb.sb_inoalignmt))
e96864ff 4713 sbversion &= ~XFS_SB_VERSION_ALIGNBIT;
e96864ff 4714 }
ea8a48fa
BF
4715
4716 ioff = 0;
4717 while (agbno < end_agbno &&
4718 ioff < XFS_INODES_PER_CHUNK) {
4719 if (xfs_inobt_is_sparse_disk(&rp[i], ioff))
4720 goto next_buf;
4721
4722 check_set_dbmap(seqno, agbno,
68d16907 4723 (xfs_extlen_t)max(1,
ea8a48fa
BF
4724 inodes_per_buf >>
4725 mp->m_sb.sb_inopblog),
4726 DBM_INODE, DBM_INODE, seqno, bno);
4727
4728next_buf:
4729 agbno += blks_per_buf;
4730 ioff += inodes_per_buf;
4731 }
4732
e96864ff
DW
4733 }
4734 return;
4735 }
e7fd2b6f
DW
4736 if (be16_to_cpu(block->bb_numrecs) > igeo->inobt_mxr[1] ||
4737 (isroot == 0 && be16_to_cpu(block->bb_numrecs) < igeo->inobt_mnr[1])) {
e96864ff
DW
4738 dbprintf(_("bad btree nrecs (%u, min=%u, max=%u) in finobt block "
4739 "%u/%u\n"),
e7fd2b6f
DW
4740 be16_to_cpu(block->bb_numrecs), igeo->inobt_mnr[1],
4741 igeo->inobt_mxr[1], seqno, bno);
e96864ff
DW
4742 serious_error++;
4743 return;
4744 }
e7fd2b6f 4745 pp = XFS_INOBT_PTR_ADDR(mp, block, 1, igeo->inobt_mxr[1]);
e96864ff
DW
4746 for (i = 0; i < be16_to_cpu(block->bb_numrecs); i++)
4747 scan_sbtree(agf, be32_to_cpu(pp[i]), level, 0, scanfunc_fino, TYP_FINOBT);
4748}
4749
e3dcc17b
DW
4750static void
4751scanfunc_rmap(
4752 struct xfs_btree_block *block,
4753 int level,
4754 struct xfs_agf *agf,
4755 xfs_agblock_t bno,
4756 int isroot)
4757{
4758 xfs_agnumber_t seqno = be32_to_cpu(agf->agf_seqno);
4759 int i;
4760 xfs_rmap_ptr_t *pp;
4761 struct xfs_rmap_rec *rp;
4762 xfs_agblock_t lastblock;
4763
4764 if (be32_to_cpu(block->bb_magic) != XFS_RMAP_CRC_MAGIC) {
4765 dbprintf(_("bad magic # %#x in rmapbt block %u/%u\n"),
4766 be32_to_cpu(block->bb_magic), seqno, bno);
4767 serious_error++;
4768 return;
4769 }
4770 if (be16_to_cpu(block->bb_level) != level) {
4771 if (!sflag)
4772 dbprintf(_("expected level %d got %d in rmapbt block "
4773 "%u/%u\n"),
4774 level, be16_to_cpu(block->bb_level), seqno, bno);
4775 error++;
4776 }
4777 if (!isroot) {
4778 fdblocks++;
4779 agfbtreeblks++;
4780 }
4781 set_dbmap(seqno, bno, 1, DBM_BTRMAP, seqno, bno);
4782 if (level == 0) {
4783 if (be16_to_cpu(block->bb_numrecs) > mp->m_rmap_mxr[0] ||
4784 (isroot == 0 && be16_to_cpu(block->bb_numrecs) < mp->m_rmap_mnr[0])) {
4785 dbprintf(_("bad btree nrecs (%u, min=%u, max=%u) in "
4786 "rmapbt block %u/%u\n"),
4787 be16_to_cpu(block->bb_numrecs), mp->m_rmap_mnr[0],
4788 mp->m_rmap_mxr[0], seqno, bno);
4789 serious_error++;
4790 return;
4791 }
4792 rp = XFS_RMAP_REC_ADDR(block, 1);
4793 lastblock = 0;
4794 for (i = 0; i < be16_to_cpu(block->bb_numrecs); i++) {
4795 if (be32_to_cpu(rp[i].rm_startblock) < lastblock) {
4796 dbprintf(_(
4797 "out-of-order rmap btree record %d (%u %u) block %u/%u\n"),
4798 i, be32_to_cpu(rp[i].rm_startblock),
4799 be32_to_cpu(rp[i].rm_startblock),
4800 be32_to_cpu(agf->agf_seqno), bno);
4801 } else {
4802 lastblock = be32_to_cpu(rp[i].rm_startblock);
4803 }
4804 }
4805 return;
4806 }
4807 if (be16_to_cpu(block->bb_numrecs) > mp->m_rmap_mxr[1] ||
4808 (isroot == 0 && be16_to_cpu(block->bb_numrecs) < mp->m_rmap_mnr[1])) {
4809 dbprintf(_("bad btree nrecs (%u, min=%u, max=%u) in rmapbt "
4810 "block %u/%u\n"),
4811 be16_to_cpu(block->bb_numrecs), mp->m_rmap_mnr[1],
4812 mp->m_rmap_mxr[1], seqno, bno);
4813 serious_error++;
4814 return;
4815 }
4816 pp = XFS_RMAP_PTR_ADDR(block, 1, mp->m_rmap_mxr[1]);
4817 for (i = 0; i < be16_to_cpu(block->bb_numrecs); i++)
4818 scan_sbtree(agf, be32_to_cpu(pp[i]), level, 0, scanfunc_rmap,
4819 TYP_RMAPBT);
4820}
4821
757ad8c7
DW
4822static void
4823scanfunc_refcnt(
4824 struct xfs_btree_block *block,
4825 int level,
4826 struct xfs_agf *agf,
4827 xfs_agblock_t bno,
4828 int isroot)
4829{
4830 xfs_agnumber_t seqno = be32_to_cpu(agf->agf_seqno);
4831 int i;
4832 xfs_refcount_ptr_t *pp;
4833 struct xfs_refcount_rec *rp;
4834 xfs_agblock_t lastblock;
4835
4836 if (be32_to_cpu(block->bb_magic) != XFS_REFC_CRC_MAGIC) {
4837 dbprintf(_("bad magic # %#x in refcntbt block %u/%u\n"),
4838 be32_to_cpu(block->bb_magic), seqno, bno);
4839 serious_error++;
4840 return;
4841 }
4842 if (be16_to_cpu(block->bb_level) != level) {
4843 if (!sflag)
4844 dbprintf(_("expected level %d got %d in refcntbt block "
4845 "%u/%u\n"),
4846 level, be16_to_cpu(block->bb_level), seqno, bno);
4847 error++;
4848 }
4849 set_dbmap(seqno, bno, 1, DBM_BTREFC, seqno, bno);
4850 if (level == 0) {
4851 if (be16_to_cpu(block->bb_numrecs) > mp->m_refc_mxr[0] ||
4852 (isroot == 0 && be16_to_cpu(block->bb_numrecs) < mp->m_refc_mnr[0])) {
4853 dbprintf(_("bad btree nrecs (%u, min=%u, max=%u) in "
4854 "refcntbt block %u/%u\n"),
4855 be16_to_cpu(block->bb_numrecs), mp->m_refc_mnr[0],
4856 mp->m_refc_mxr[0], seqno, bno);
4857 serious_error++;
4858 return;
4859 }
4860 rp = XFS_REFCOUNT_REC_ADDR(block, 1);
4861 lastblock = 0;
4862 for (i = 0; i < be16_to_cpu(block->bb_numrecs); i++) {
13ef9674 4863 if (be32_to_cpu(rp[i].rc_refcount) == 1) {
b638281f
DW
4864 xfs_agblock_t agbno;
4865 char *msg;
4866
4867 agbno = be32_to_cpu(rp[i].rc_startblock);
2b9d6f15
DW
4868 if (agbno & XFS_REFC_COWFLAG) {
4869 agbno &= ~XFS_REFC_COWFLAG;
b638281f
DW
4870 msg = _(
4871 "leftover CoW extent (%u/%u) len %u\n");
4872 } else {
4873 msg = _(
4874 "leftover CoW extent at unexpected address (%u/%u) len %u\n");
4875 }
4876 dbprintf(msg,
13ef9674 4877 seqno,
b638281f 4878 agbno,
13ef9674
DW
4879 be32_to_cpu(rp[i].rc_blockcount));
4880 set_dbmap(seqno,
b638281f 4881 agbno,
13ef9674
DW
4882 be32_to_cpu(rp[i].rc_blockcount),
4883 DBM_COWDATA, seqno, bno);
4884 } else {
4885 set_dbmap(seqno,
4886 be32_to_cpu(rp[i].rc_startblock),
4887 be32_to_cpu(rp[i].rc_blockcount),
4888 DBM_RLDATA, seqno, bno);
4889 }
757ad8c7
DW
4890 if (be32_to_cpu(rp[i].rc_startblock) < lastblock) {
4891 dbprintf(_(
4892 "out-of-order refcnt btree record %d (%u %u) block %u/%u\n"),
4893 i, be32_to_cpu(rp[i].rc_startblock),
4894 be32_to_cpu(rp[i].rc_startblock),
4895 be32_to_cpu(agf->agf_seqno), bno);
4896 } else {
4897 lastblock = be32_to_cpu(rp[i].rc_startblock) +
4898 be32_to_cpu(rp[i].rc_blockcount);
4899 }
4900 }
4901 return;
4902 }
4903 if (be16_to_cpu(block->bb_numrecs) > mp->m_refc_mxr[1] ||
4904 (isroot == 0 && be16_to_cpu(block->bb_numrecs) < mp->m_refc_mnr[1])) {
4905 dbprintf(_("bad btree nrecs (%u, min=%u, max=%u) in refcntbt "
4906 "block %u/%u\n"),
4907 be16_to_cpu(block->bb_numrecs), mp->m_refc_mnr[1],
4908 mp->m_refc_mxr[1], seqno, bno);
4909 serious_error++;
4910 return;
4911 }
4912 pp = XFS_REFCOUNT_PTR_ADDR(block, 1, mp->m_refc_mxr[1]);
4913 for (i = 0; i < be16_to_cpu(block->bb_numrecs); i++)
4914 scan_sbtree(agf, be32_to_cpu(pp[i]), level, 0, scanfunc_refcnt,
4915 TYP_REFCBT);
4916}
4917
2bd0ea18
NS
4918static void
4919set_dbmap(
4920 xfs_agnumber_t agno,
4921 xfs_agblock_t agbno,
4922 xfs_extlen_t len,
4923 dbm_t type,
4924 xfs_agnumber_t c_agno,
4925 xfs_agblock_t c_agbno)
4926{
4927 check_set_dbmap(agno, agbno, len, DBM_UNKNOWN, type, c_agno, c_agbno);
4928}
4929
4930static void
4931set_inomap(
4932 xfs_agnumber_t agno,
4933 xfs_agblock_t agbno,
4934 xfs_extlen_t len,
4935 inodata_t *id)
4936{
4937 xfs_extlen_t i;
4938 inodata_t **idp;
4939 int mayprint;
4940
4941 if (!check_inomap(agno, agbno, len, id->ino))
4942 return;
4943 mayprint = verbose | id->ilist | blist_size;
4944 for (i = 0, idp = &inomap[agno][agbno]; i < len; i++, idp++) {
4945 *idp = id;
4946 if (mayprint &&
4947 (verbose || id->ilist || CHECK_BLISTA(agno, agbno + i)))
9ee7055c 4948 dbprintf(_("setting inode to %lld for block %u/%u\n"),
2bd0ea18
NS
4949 id->ino, agno, agbno + i);
4950 }
4951}
4952
4953static void
4954set_rdbmap(
5a35bf2c 4955 xfs_rfsblock_t bno,
2bd0ea18
NS
4956 xfs_extlen_t len,
4957 dbm_t type)
4958{
4959 check_set_rdbmap(bno, len, DBM_UNKNOWN, type);
4960}
4961
4962static void
4963set_rinomap(
5a35bf2c 4964 xfs_rfsblock_t bno,
2bd0ea18
NS
4965 xfs_extlen_t len,
4966 inodata_t *id)
4967{
4968 xfs_extlen_t i;
4969 inodata_t **idp;
4970 int mayprint;
4971
4972 if (!check_rinomap(bno, len, id->ino))
4973 return;
4974 mayprint = verbose | id->ilist | blist_size;
4975 for (i = 0, idp = &inomap[mp->m_sb.sb_agcount][bno];
4976 i < len;
4977 i++, idp++) {
4978 *idp = id;
4979 if (mayprint && (verbose || id->ilist || CHECK_BLIST(bno + i)))
9ee7055c 4980 dbprintf(_("setting inode to %lld for rtblock %llu\n"),
2bd0ea18
NS
4981 id->ino, bno + i);
4982 }
4983}
4984
4985static void
4986setlink_inode(
4987 inodata_t *id,
4988 nlink_t nlink,
4989 int isdir,
4990 int security)
4991{
4992 id->link_set = nlink;
4993 id->isdir = isdir;
4994 id->security = security;
4995 if (verbose || id->ilist)
9ee7055c 4996 dbprintf(_("inode %lld nlink %u %s dir\n"), id->ino, nlink,
2bd0ea18
NS
4997 isdir ? "is" : "not");
4998}