]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blame - db/check.c
xfs_{db,repair}: use helpers for rtsummary block/wordcount computations
[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) {
113af235
DW
1947 unsigned long long words;
1948
2bd0ea18
NS
1949 dbmap[c] = xcalloc(mp->m_sb.sb_rblocks, sizeof(**dbmap));
1950 inomap[c] = xcalloc(mp->m_sb.sb_rblocks, sizeof(**inomap));
113af235
DW
1951 words = libxfs_rtsummary_wordcount(mp, mp->m_rsumlevels,
1952 mp->m_sb.sb_rbmblocks);
1953 sumfile = xcalloc(words, sizeof(xfs_suminfo_t));
1954 sumcompute = xcalloc(words, sizeof(xfs_suminfo_t));
2bd0ea18 1955 }
32a82561
NS
1956 nflag = sflag = tflag = verbose = optind = 0;
1957 while ((c = getopt(argc, argv, "b:i:npstv")) != EOF) {
2bd0ea18
NS
1958 switch (c) {
1959 case 'b':
6bef826c 1960 bno = strtoll(optarg, NULL, 10);
2bd0ea18
NS
1961 add_blist(bno);
1962 break;
1963 case 'i':
6bef826c 1964 ino = strtoll(optarg, NULL, 10);
2bd0ea18
NS
1965 add_ilist(ino);
1966 break;
1967 case 'n':
1968 nflag = 1;
1969 break;
1970 case 'p':
1971 pflag = 1;
1972 break;
1973 case 's':
1974 sflag = 1;
1975 break;
32a82561
NS
1976 case 't':
1977 tflag = 1;
1978 break;
2bd0ea18
NS
1979 case 'v':
1980 verbose = 1;
1981 break;
1982 default:
9ee7055c 1983 dbprintf(_("bad option for blockget command\n"));
2bd0ea18
NS
1984 return 0;
1985 }
1986 }
1987 error = sbver_err = serious_error = 0;
1988 fdblocks = frextents = icount = ifree = 0;
1989 sbversion = XFS_SB_VERSION_4;
9da36109
BF
1990 /*
1991 * Note that inoalignmt == 0 is valid when fsb size is large enough for
1992 * at least one full inode record per block. Check this case explicitly.
1993 */
1994 if (mp->m_sb.sb_inoalignmt ||
2660e653 1995 (xfs_has_align(mp) &&
9da36109 1996 mp->m_sb.sb_inopblock >= XFS_INODES_PER_CHUNK))
2bd0ea18
NS
1997 sbversion |= XFS_SB_VERSION_ALIGNBIT;
1998 if ((mp->m_sb.sb_uquotino && mp->m_sb.sb_uquotino != NULLFSINO) ||
0340d706
CS
1999 (mp->m_sb.sb_gquotino && mp->m_sb.sb_gquotino != NULLFSINO) ||
2000 (mp->m_sb.sb_pquotino && mp->m_sb.sb_pquotino != NULLFSINO))
2bd0ea18
NS
2001 sbversion |= XFS_SB_VERSION_QUOTABIT;
2002 quota_init();
2003 return 1;
2004}
2005
2006static char *
2007inode_name(
2008 xfs_ino_t ino,
2009 inodata_t **ipp)
2010{
2011 inodata_t *id;
2012 char *npath;
2013 char *path;
2014
2015 id = find_inode(ino, 0);
2016 if (ipp)
2017 *ipp = id;
2018 if (id == NULL)
2019 return NULL;
2020 if (id->name == NULL)
2021 return NULL;
2022 path = xstrdup(id->name);
2023 while (id->parent) {
2024 id = id->parent;
2025 if (id->name == NULL)
2026 break;
2027 npath = prepend_path(path, id->name);
2028 xfree(path);
2029 path = npath;
2030 }
2031 return path;
2032}
2033
2034static int
2035ncheck_f(
2036 int argc,
2037 char **argv)
2038{
2039 xfs_agnumber_t agno;
2040 int c;
2041 inodata_t *hp;
2042 inodata_t **ht;
2043 int i;
2044 inodata_t *id;
2045 xfs_ino_t *ilist;
2046 int ilist_size;
2047 xfs_ino_t *ilp;
2048 xfs_ino_t ino;
2049 char *p;
2050 int security;
2051
2052 if (!inodata || !nflag) {
9ee7055c 2053 dbprintf(_("must run blockget -n first\n"));
2bd0ea18
NS
2054 return 0;
2055 }
2056 security = optind = ilist_size = 0;
2057 ilist = NULL;
2058 while ((c = getopt(argc, argv, "i:s")) != EOF) {
2059 switch (c) {
2060 case 'i':
6bef826c 2061 ino = strtoll(optarg, NULL, 10);
2bd0ea18
NS
2062 ilist = xrealloc(ilist, (ilist_size + 1) *
2063 sizeof(*ilist));
2064 ilist[ilist_size++] = ino;
2065 break;
2066 case 's':
2067 security = 1;
2068 break;
2069 default:
9ee7055c 2070 dbprintf(_("bad option -%c for ncheck command\n"), c);
355ac015 2071 xfree(ilist);
2bd0ea18
NS
2072 return 0;
2073 }
2074 }
2075 if (ilist) {
2076 for (ilp = ilist; ilp < &ilist[ilist_size]; ilp++) {
2077 ino = *ilp;
27527004 2078 if ((p = inode_name(ino, &hp))) {
2bd0ea18
NS
2079 dbprintf("%11llu %s", ino, p);
2080 if (hp->isdir)
2081 dbprintf("/.");
2082 dbprintf("\n");
2083 xfree(p);
2084 }
2085 }
2086 xfree(ilist);
2087 return 0;
2088 }
2089 for (agno = 0; agno < mp->m_sb.sb_agcount; agno++) {
2090 ht = inodata[agno];
2091 for (i = 0; i < inodata_hash_size; i++) {
2092 hp = ht[i];
2093 for (hp = ht[i]; hp; hp = hp->next) {
2094 ino = XFS_AGINO_TO_INO(mp, agno, hp->ino);
2095 p = inode_name(ino, &id);
2096 if (!p || !id)
2097 continue;
2098 if (!security || id->security) {
2099 dbprintf("%11llu %s", ino, p);
2100 if (hp->isdir)
2101 dbprintf("/.");
2102 dbprintf("\n");
2103 }
2104 xfree(p);
2105 }
2106 }
2107 }
2108 return 0;
2109}
2110
2111static char *
2112prepend_path(
2113 char *oldpath,
2114 char *parent)
2115{
2116 int len;
2117 char *path;
2118
2119 len = (int)(strlen(oldpath) + strlen(parent) + 2);
2120 path = xmalloc(len);
2d9475a4 2121 snprintf(path, len, "%s/%s", parent, oldpath);
2bd0ea18
NS
2122 return path;
2123}
2124
2125static xfs_ino_t
2126process_block_dir_v2(
2127 blkmap_t *blkmap,
2128 int *dot,
2129 int *dotdot,
2130 inodata_t *id)
2131{
2132 xfs_fsblock_t b;
2133 bbmap_t bbmap;
2134 bmap_ext_t *bmp;
2135 int nex;
2136 xfs_ino_t parent;
2137 int v;
4add9d50 2138 int i;
2bd0ea18 2139
ff105f75 2140 nex = blkmap_getn(blkmap, 0, mp->m_dir_geo->fsbcount, &bmp);
2bd0ea18
NS
2141 v = id->ilist || verbose;
2142 if (nex == 0) {
2143 if (!sflag || v)
9ee7055c
AM
2144 dbprintf(_("block 0 for directory inode %lld is "
2145 "missing\n"),
2bd0ea18
NS
2146 id->ino);
2147 error++;
2148 return 0;
2149 }
2150 push_cur();
2151 if (nex > 1)
2152 make_bbmap(&bbmap, nex, bmp);
9a048535 2153 set_cur(&typtab[TYP_DIR2], XFS_FSB_TO_DADDR(mp, bmp->startblock),
ff105f75 2154 mp->m_dir_geo->fsbcount * blkbb, DB_RING_IGN, nex > 1 ? &bbmap : NULL);
4add9d50
ES
2155 for (i = 0; !v && i < nex; i++) {
2156 for (b = bmp[i].startblock;
2157 !v && b < bmp[i].startblock + bmp[i].blockcount;
2bd0ea18
NS
2158 b++)
2159 v = CHECK_BLIST(b);
2160 }
2161 free(bmp);
2162 if (iocur_top->data == NULL) {
2163 if (!sflag || id->ilist || v)
9ee7055c
AM
2164 dbprintf(_("can't read block 0 for directory inode "
2165 "%lld\n"),
2bd0ea18
NS
2166 id->ino);
2167 error++;
d24c0a90 2168 pop_cur();
2bd0ea18
NS
2169 return 0;
2170 }
2171 dir_hash_init();
ff105f75 2172 parent = process_data_dir_v2(dot, dotdot, id, v, mp->m_dir_geo->datablk,
2bd0ea18
NS
2173 NULL);
2174 dir_hash_check(id, v);
2175 dir_hash_done();
2176 pop_cur();
2177 return parent;
2178}
2179
2180static void
2181process_bmbt_reclist(
b9652a81 2182 xfs_bmbt_rec_t *rp,
3a2414fa 2183 xfs_extnum_t numrecs,
2bd0ea18
NS
2184 dbm_t type,
2185 inodata_t *id,
5a35bf2c 2186 xfs_rfsblock_t *tot,
2bd0ea18
NS
2187 blkmap_t **blkmapp)
2188{
2189 xfs_agblock_t agbno;
2190 xfs_agnumber_t agno;
2191 xfs_fsblock_t b;
5a35bf2c
DC
2192 xfs_filblks_t c;
2193 xfs_filblks_t cp;
2bd0ea18 2194 int f;
3a2414fa 2195 xfs_extnum_t i;
2bd0ea18
NS
2196 xfs_agblock_t iagbno;
2197 xfs_agnumber_t iagno;
5a35bf2c
DC
2198 xfs_fileoff_t o;
2199 xfs_fileoff_t op;
2200 xfs_fsblock_t s;
2bd0ea18
NS
2201 int v;
2202
2203 cp = op = 0;
2204 v = verbose || id->ilist;
2205 iagno = XFS_INO_TO_AGNO(mp, id->ino);
2206 iagbno = XFS_INO_TO_AGBNO(mp, id->ino);
2207 for (i = 0; i < numrecs; i++, rp++) {
b9652a81 2208 convert_extent(rp, &o, &s, &c, &f);
2bd0ea18 2209 if (v)
9ee7055c 2210 dbprintf(_("inode %lld extent [%lld,%lld,%lld,%d]\n"),
2bd0ea18
NS
2211 id->ino, o, s, c, f);
2212 if (!sflag && i > 0 && op + cp > o)
9ee7055c 2213 dbprintf(_("bmap rec out of order, inode %lld entry %d\n"),
2bd0ea18
NS
2214 id->ino, i);
2215 op = o;
2216 cp = c;
2217 if (type == DBM_RTDATA) {
2218 if (!sflag && s >= mp->m_sb.sb_rblocks) {
9ee7055c
AM
2219 dbprintf(_("inode %lld bad rt block number %lld, "
2220 "offset %lld\n"),
2bd0ea18
NS
2221 id->ino, s, o);
2222 continue;
2223 }
2224 } else if (!sflag) {
2225 agno = XFS_FSB_TO_AGNO(mp, s);
2226 agbno = XFS_FSB_TO_AGBNO(mp, s);
2227 if (agno >= mp->m_sb.sb_agcount ||
2228 agbno >= mp->m_sb.sb_agblocks) {
9ee7055c
AM
2229 dbprintf(_("inode %lld bad block number %lld "
2230 "[%d,%d], offset %lld\n"),
2bd0ea18
NS
2231 id->ino, s, agno, agbno, o);
2232 continue;
2233 }
2234 if (agbno + c - 1 >= mp->m_sb.sb_agblocks) {
9ee7055c
AM
2235 dbprintf(_("inode %lld bad block number %lld "
2236 "[%d,%d], offset %lld\n"),
2bd0ea18
NS
2237 id->ino, s + c - 1, agno,
2238 agbno + (xfs_agblock_t)c - 1, o);
2239 continue;
2240 }
2241 }
2242 if (blkmapp && *blkmapp)
2243 blkmap_set_ext(blkmapp, (xfs_fileoff_t)o,
2244 (xfs_fsblock_t)s, (xfs_extlen_t)c);
2245 if (type == DBM_RTDATA) {
2246 set_rdbmap((xfs_fsblock_t)s, (xfs_extlen_t)c,
2247 DBM_RTDATA);
2248 set_rinomap((xfs_fsblock_t)s, (xfs_extlen_t)c, id);
2249 for (b = (xfs_fsblock_t)s;
2250 blist_size && b < s + c;
2251 b++, o++) {
2252 if (CHECK_BLIST(b))
9ee7055c
AM
2253 dbprintf(_("inode %lld block %lld at "
2254 "offset %lld\n"),
5a35bf2c 2255 id->ino, (xfs_fsblock_t)b, o);
2bd0ea18
NS
2256 }
2257 } else {
2258 agno = XFS_FSB_TO_AGNO(mp, (xfs_fsblock_t)s);
2259 agbno = XFS_FSB_TO_AGBNO(mp, (xfs_fsblock_t)s);
2260 set_dbmap(agno, agbno, (xfs_extlen_t)c, type, iagno,
2261 iagbno);
2262 set_inomap(agno, agbno, (xfs_extlen_t)c, id);
2263 for (b = (xfs_fsblock_t)s;
2264 blist_size && b < s + c;
2265 b++, o++, agbno++) {
2266 if (CHECK_BLIST(b))
9ee7055c
AM
2267 dbprintf(_("inode %lld block %lld at "
2268 "offset %lld\n"),
5a35bf2c 2269 id->ino, (xfs_fsblock_t)b, o);
2bd0ea18
NS
2270 }
2271 }
2272 *tot += c;
2273 }
2274}
2275
2276static void
2277process_btinode(
2278 inodata_t *id,
7328ea6e 2279 struct xfs_dinode *dip,
2bd0ea18 2280 dbm_t type,
5a35bf2c
DC
2281 xfs_rfsblock_t *totd,
2282 xfs_rfsblock_t *toti,
2bd0ea18
NS
2283 xfs_extnum_t *nex,
2284 blkmap_t **blkmapp,
2285 int whichfork)
2286{
2287 xfs_bmdr_block_t *dib;
2288 int i;
2289 xfs_bmbt_ptr_t *pp;
2bd0ea18 2290
46eca962 2291 dib = (xfs_bmdr_block_t *)XFS_DFORK_PTR(dip, whichfork);
5e656dbb 2292 if (be16_to_cpu(dib->bb_level) >= XFS_BM_MAXLEVELS(mp, whichfork)) {
2bd0ea18 2293 if (!sflag || id->ilist)
9ee7055c
AM
2294 dbprintf(_("level for ino %lld %s fork bmap root too "
2295 "large (%u)\n"),
2bd0ea18 2296 id->ino,
9ee7055c 2297 whichfork == XFS_DATA_FORK ? _("data") : _("attr"),
5e656dbb 2298 be16_to_cpu(dib->bb_level));
2bd0ea18
NS
2299 error++;
2300 return;
2301 }
b3563c19 2302 if (be16_to_cpu(dib->bb_numrecs) >
e2f60652 2303 libxfs_bmdr_maxrecs(XFS_DFORK_SIZE(dip, mp, whichfork),
b3563c19 2304 be16_to_cpu(dib->bb_level) == 0)) {
2bd0ea18 2305 if (!sflag || id->ilist)
9ee7055c
AM
2306 dbprintf(_("numrecs for ino %lld %s fork bmap root too "
2307 "large (%u)\n"),
dfc130f3 2308 id->ino,
9ee7055c 2309 whichfork == XFS_DATA_FORK ? _("data") : _("attr"),
5e656dbb 2310 be16_to_cpu(dib->bb_numrecs));
2bd0ea18
NS
2311 error++;
2312 return;
2313 }
5e656dbb 2314 if (be16_to_cpu(dib->bb_level) == 0) {
b9652a81 2315 xfs_bmbt_rec_t *rp = XFS_BMDR_REC_ADDR(dib, 1);
f8149110 2316 process_bmbt_reclist(rp, be16_to_cpu(dib->bb_numrecs), type,
5e656dbb
BN
2317 id, totd, blkmapp);
2318 *nex += be16_to_cpu(dib->bb_numrecs);
2bd0ea18
NS
2319 return;
2320 } else {
e2f60652 2321 pp = XFS_BMDR_PTR_ADDR(dib, 1, libxfs_bmdr_maxrecs(
b3563c19 2322 XFS_DFORK_SIZE(dip, mp, whichfork), 0));
5e656dbb 2323 for (i = 0; i < be16_to_cpu(dib->bb_numrecs); i++)
c5d584c0 2324 scan_lbtree(get_unaligned_be64(&pp[i]),
f8149110
JT
2325 be16_to_cpu(dib->bb_level),
2326 scanfunc_bmap, type, id, totd, toti,
2327 nex, blkmapp, 1,
5e656dbb
BN
2328 whichfork == XFS_DATA_FORK ?
2329 TYP_BMAPBTD : TYP_BMAPBTA);
2330 }
2331 if (*nex <= XFS_DFORK_SIZE(dip, mp, whichfork) / sizeof(xfs_bmbt_rec_t)) {
2bd0ea18 2332 if (!sflag || id->ilist)
9ee7055c
AM
2333 dbprintf(_("extent count for ino %lld %s fork too low "
2334 "(%d) for file format\n"),
2bd0ea18 2335 id->ino,
9ee7055c 2336 whichfork == XFS_DATA_FORK ? _("data") : _("attr"),
2bd0ea18
NS
2337 *nex);
2338 error++;
2339 }
2340}
2341
2342static xfs_ino_t
2343process_data_dir_v2(
2344 int *dot,
2345 int *dotdot,
2346 inodata_t *id,
2347 int v,
2348 xfs_dablk_t dabno,
2349 freetab_t **freetabp)
2350{
2351 xfs_dir2_dataptr_t addr;
2352 xfs_dir2_data_free_t *bf;
2353 int bf_err;
eb0cb950 2354 struct xfs_dir2_data_hdr *block;
2bd0ea18
NS
2355 xfs_dir2_block_tail_t *btp = NULL;
2356 inodata_t *cid;
2357 int count;
eb0cb950 2358 struct xfs_dir2_data_hdr *data;
2bd0ea18
NS
2359 xfs_dir2_db_t db;
2360 xfs_dir2_data_entry_t *dep;
2361 xfs_dir2_data_free_t *dfp;
2362 xfs_dir2_data_unused_t *dup;
2363 char *endptr;
2364 int freeseen;
2365 freetab_t *freetab;
2bd0ea18
NS
2366 int i;
2367 int lastfree;
2368 int lastfree_err;
2369 xfs_dir2_leaf_entry_t *lep = NULL;
2370 xfs_ino_t lino;
2371 xfs_ino_t parent = 0;
2372 char *ptr;
2373 int stale = 0;
2374 int tag_err;
5e656dbb
BN
2375 __be16 *tagp;
2376 struct xfs_name xname;
2bd0ea18
NS
2377
2378 data = iocur_top->data;
2379 block = iocur_top->data;
eb0cb950 2380 if (be32_to_cpu(block->magic) != XFS_DIR2_BLOCK_MAGIC &&
e96864ff
DW
2381 be32_to_cpu(data->magic) != XFS_DIR2_DATA_MAGIC &&
2382 be32_to_cpu(block->magic) != XFS_DIR3_BLOCK_MAGIC &&
2383 be32_to_cpu(data->magic) != XFS_DIR3_DATA_MAGIC) {
2bd0ea18 2384 if (!sflag || v)
9ee7055c
AM
2385 dbprintf(_("bad directory data magic # %#x for dir ino "
2386 "%lld block %d\n"),
eb0cb950 2387 be32_to_cpu(data->magic), id->ino, dabno);
2bd0ea18
NS
2388 error++;
2389 return NULLFSINO;
2390 }
ff105f75 2391 db = xfs_dir2_da_to_db(mp->m_dir_geo, dabno);
04f6f354 2392 bf = libxfs_dir2_data_bestfree_p(mp, data);
58a1d356 2393 ptr = (char *)data + mp->m_dir_geo->data_entry_offset;
e96864ff
DW
2394 if (be32_to_cpu(block->magic) == XFS_DIR2_BLOCK_MAGIC ||
2395 be32_to_cpu(block->magic) == XFS_DIR3_BLOCK_MAGIC) {
ff105f75 2396 btp = xfs_dir2_block_tail_p(mp->m_dir_geo, block);
5e656dbb 2397 lep = xfs_dir2_block_leaf_p(btp);
2bd0ea18
NS
2398 endptr = (char *)lep;
2399 if (endptr <= ptr || endptr > (char *)btp) {
ff105f75 2400 endptr = (char *)data + mp->m_dir_geo->blksize;
2bd0ea18
NS
2401 lep = NULL;
2402 if (!sflag || v)
9ee7055c
AM
2403 dbprintf(_("bad block directory tail for dir ino "
2404 "%lld\n"),
2bd0ea18
NS
2405 id->ino);
2406 error++;
2407 }
2408 } else
ff105f75 2409 endptr = (char *)data + mp->m_dir_geo->blksize;
2bd0ea18
NS
2410 bf_err = lastfree_err = tag_err = 0;
2411 count = lastfree = freeseen = 0;
5e656dbb
BN
2412 if (be16_to_cpu(bf[0].length) == 0) {
2413 bf_err += be16_to_cpu(bf[0].offset) != 0;
2bd0ea18
NS
2414 freeseen |= 1 << 0;
2415 }
5e656dbb
BN
2416 if (be16_to_cpu(bf[1].length) == 0) {
2417 bf_err += be16_to_cpu(bf[1].offset) != 0;
2bd0ea18
NS
2418 freeseen |= 1 << 1;
2419 }
5e656dbb
BN
2420 if (be16_to_cpu(bf[2].length) == 0) {
2421 bf_err += be16_to_cpu(bf[2].offset) != 0;
2bd0ea18
NS
2422 freeseen |= 1 << 2;
2423 }
5e656dbb
BN
2424 bf_err += be16_to_cpu(bf[0].length) < be16_to_cpu(bf[1].length);
2425 bf_err += be16_to_cpu(bf[1].length) < be16_to_cpu(bf[2].length);
2bd0ea18
NS
2426 if (freetabp) {
2427 freetab = *freetabp;
2428 if (freetab->naents <= db) {
2429 *freetabp = freetab =
2430 realloc(freetab, FREETAB_SIZE(db + 1));
2431 for (i = freetab->naents; i < db; i++)
2432 freetab->ents[i] = NULLDATAOFF;
2433 freetab->naents = db + 1;
2434 }
2435 if (freetab->nents < db + 1)
2436 freetab->nents = db + 1;
5e656dbb 2437 freetab->ents[db] = be16_to_cpu(bf[0].length);
2bd0ea18
NS
2438 }
2439 while (ptr < endptr) {
2440 dup = (xfs_dir2_data_unused_t *)ptr;
5e656dbb 2441 if (be16_to_cpu(dup->freetag) == XFS_DIR2_DATA_FREE_TAG) {
2bd0ea18 2442 lastfree_err += lastfree != 0;
5e656dbb
BN
2443 tagp = xfs_dir2_data_unused_tag_p(dup);
2444 if ((be16_to_cpu(dup->length) & (XFS_DIR2_DATA_ALIGN - 1)) ||
2445 be16_to_cpu(dup->length) == 0 ||
2446 (char *)tagp >= endptr) {
2bd0ea18 2447 if (!sflag || v)
9ee7055c
AM
2448 dbprintf(_("dir %lld block %d bad free "
2449 "entry at %d\n"),
2bd0ea18
NS
2450 id->ino, dabno,
2451 (int)((char *)dup -
2452 (char *)data));
2453 error++;
2454 break;
2455 }
5e656dbb 2456 tag_err += be16_to_cpu(*tagp) != (char *)dup - (char *)data;
2bd0ea18
NS
2457 dfp = process_data_dir_v2_freefind(data, dup);
2458 if (dfp) {
2459 i = (int)(dfp - bf);
2460 bf_err += (freeseen & (1 << i)) != 0;
2461 freeseen |= 1 << i;
2462 } else
f8149110 2463 bf_err += be16_to_cpu(dup->length) >
5e656dbb
BN
2464 be16_to_cpu(bf[2].length);
2465 ptr += be16_to_cpu(dup->length);
2bd0ea18
NS
2466 lastfree = 1;
2467 continue;
2468 }
2469 dep = (xfs_dir2_data_entry_t *)dup;
2470 if (dep->namelen == 0) {
2471 if (!sflag || v)
9ee7055c
AM
2472 dbprintf(_("dir %lld block %d zero length entry "
2473 "at %d\n"),
2bd0ea18
NS
2474 id->ino, dabno,
2475 (int)((char *)dep - (char *)data));
2476 error++;
2477 }
823711f2 2478 tagp = libxfs_dir2_data_entry_tag_p(mp, dep);
2bd0ea18
NS
2479 if ((char *)tagp >= endptr) {
2480 if (!sflag || v)
9ee7055c 2481 dbprintf(_("dir %lld block %d bad entry at %d\n"),
2bd0ea18
NS
2482 id->ino, dabno,
2483 (int)((char *)dep - (char *)data));
2484 error++;
2485 break;
2486 }
5e656dbb 2487 tag_err += be16_to_cpu(*tagp) != (char *)dep - (char *)data;
ff105f75 2488 addr = xfs_dir2_db_off_to_dataptr(mp->m_dir_geo, db,
2bd0ea18 2489 (char *)dep - (char *)data);
56b2de80 2490 xname.name = dep->name;
5e656dbb 2491 xname.len = dep->namelen;
e169cc9b 2492 dir_hash_add(libxfs_dir2_hashname(mp, &xname), addr);
271a654f 2493 ptr += libxfs_dir2_data_entsize(mp, dep->namelen);
2bd0ea18
NS
2494 count++;
2495 lastfree = 0;
5e656dbb 2496 lino = be64_to_cpu(dep->inumber);
2bd0ea18
NS
2497 cid = find_inode(lino, 1);
2498 if (v)
9ee7055c 2499 dbprintf(_("dir %lld block %d entry %*.*s %lld\n"),
2bd0ea18
NS
2500 id->ino, dabno, dep->namelen, dep->namelen,
2501 dep->name, lino);
2502 if (cid)
2503 addlink_inode(cid);
2504 else {
2505 if (!sflag || v)
9ee7055c
AM
2506 dbprintf(_("dir %lld block %d entry %*.*s bad "
2507 "inode number %lld\n"),
2bd0ea18
NS
2508 id->ino, dabno, dep->namelen,
2509 dep->namelen, dep->name, lino);
2510 error++;
2511 }
2512 if (dep->namelen == 2 && dep->name[0] == '.' &&
2513 dep->name[1] == '.') {
2514 if (parent) {
2515 if (!sflag || v)
9ee7055c
AM
2516 dbprintf(_("multiple .. entries in dir "
2517 "%lld (%lld, %lld)\n"),
2bd0ea18
NS
2518 id->ino, parent, lino);
2519 error++;
2520 } else
2521 parent = cid ? lino : NULLFSINO;
2522 (*dotdot)++;
2523 } else if (dep->namelen != 1 || dep->name[0] != '.') {
2524 if (cid != NULL) {
2525 if (!cid->parent)
2526 cid->parent = id;
2527 addname_inode(cid, (char *)dep->name,
2528 dep->namelen);
2529 }
2530 } else {
2531 if (lino != id->ino) {
2532 if (!sflag || v)
9ee7055c
AM
2533 dbprintf(_("dir %lld entry . inode "
2534 "number mismatch (%lld)\n"),
2bd0ea18
NS
2535 id->ino, lino);
2536 error++;
2537 }
2538 (*dot)++;
2539 }
2540 }
e96864ff
DW
2541 if (be32_to_cpu(data->magic) == XFS_DIR2_BLOCK_MAGIC ||
2542 be32_to_cpu(data->magic) == XFS_DIR3_BLOCK_MAGIC) {
ff105f75 2543 endptr = (char *)data + mp->m_dir_geo->blksize;
5e656dbb 2544 for (i = stale = 0; lep && i < be32_to_cpu(btp->count); i++) {
2bd0ea18
NS
2545 if ((char *)&lep[i] >= endptr) {
2546 if (!sflag || v)
9ee7055c 2547 dbprintf(_("dir %lld block %d bad count "
f8149110 2548 "%u\n"), id->ino, dabno,
5e656dbb 2549 be32_to_cpu(btp->count));
2bd0ea18
NS
2550 error++;
2551 break;
2552 }
5e656dbb 2553 if (be32_to_cpu(lep[i].address) == XFS_DIR2_NULL_DATAPTR)
2bd0ea18 2554 stale++;
f8149110 2555 else if (dir_hash_see(be32_to_cpu(lep[i].hashval),
5e656dbb 2556 be32_to_cpu(lep[i].address))) {
2bd0ea18 2557 if (!sflag || v)
9ee7055c 2558 dbprintf(_("dir %lld block %d extra leaf "
f8149110
JT
2559 "entry %x %x\n"),
2560 id->ino, dabno,
5e656dbb
BN
2561 be32_to_cpu(lep[i].hashval),
2562 be32_to_cpu(lep[i].address));
2bd0ea18
NS
2563 error++;
2564 }
2565 }
2566 }
2567 bf_err += freeseen != 7;
2568 if (bf_err) {
2569 if (!sflag || v)
9ee7055c 2570 dbprintf(_("dir %lld block %d bad bestfree data\n"),
2bd0ea18
NS
2571 id->ino, dabno);
2572 error++;
2573 }
e96864ff
DW
2574 if ((be32_to_cpu(data->magic) == XFS_DIR2_BLOCK_MAGIC ||
2575 be32_to_cpu(data->magic) == XFS_DIR3_BLOCK_MAGIC) &&
eb0cb950 2576 count != be32_to_cpu(btp->count) - be32_to_cpu(btp->stale)) {
2bd0ea18 2577 if (!sflag || v)
9ee7055c 2578 dbprintf(_("dir %lld block %d bad block tail count %d "
f8149110
JT
2579 "(stale %d)\n"),
2580 id->ino, dabno, be32_to_cpu(btp->count),
5e656dbb 2581 be32_to_cpu(btp->stale));
2bd0ea18
NS
2582 error++;
2583 }
e96864ff 2584 if ((be32_to_cpu(data->magic) == XFS_DIR2_BLOCK_MAGIC ||
7374f58b 2585 be32_to_cpu(data->magic) == XFS_DIR3_BLOCK_MAGIC) &&
5e656dbb 2586 stale != be32_to_cpu(btp->stale)) {
2bd0ea18 2587 if (!sflag || v)
9ee7055c 2588 dbprintf(_("dir %lld block %d bad stale tail count %d\n"),
5e656dbb 2589 id->ino, dabno, be32_to_cpu(btp->stale));
2bd0ea18
NS
2590 error++;
2591 }
2592 if (lastfree_err) {
2593 if (!sflag || v)
9ee7055c 2594 dbprintf(_("dir %lld block %d consecutive free entries\n"),
2bd0ea18
NS
2595 id->ino, dabno);
2596 error++;
2597 }
2598 if (tag_err) {
2599 if (!sflag || v)
9ee7055c
AM
2600 dbprintf(_("dir %lld block %d entry/unused tag "
2601 "mismatch\n"),
2bd0ea18
NS
2602 id->ino, dabno);
2603 error++;
2604 }
2605 return parent;
2606}
2607
2608static xfs_dir2_data_free_t *
2609process_data_dir_v2_freefind(
eb0cb950 2610 struct xfs_dir2_data_hdr *data,
2bd0ea18
NS
2611 xfs_dir2_data_unused_t *dup)
2612{
eb0cb950
DC
2613 struct xfs_dir2_data_free *bf;
2614 struct xfs_dir2_data_free *dfp;
2bd0ea18
NS
2615 xfs_dir2_data_aoff_t off;
2616
2617 off = (xfs_dir2_data_aoff_t)((char *)dup - (char *)data);
04f6f354 2618 bf = libxfs_dir2_data_bestfree_p(mp, data);
eb0cb950
DC
2619 if (be16_to_cpu(dup->length) <
2620 be16_to_cpu(bf[XFS_DIR2_DATA_FD_COUNT - 1].length))
2bd0ea18 2621 return NULL;
eb0cb950 2622 for (dfp = bf; dfp < &bf[XFS_DIR2_DATA_FD_COUNT]; dfp++) {
5e656dbb 2623 if (be16_to_cpu(dfp->offset) == 0)
2bd0ea18 2624 return NULL;
5e656dbb 2625 if (be16_to_cpu(dfp->offset) == off)
2bd0ea18
NS
2626 return dfp;
2627 }
2628 return NULL;
2629}
2630
2631static void
2632process_dir(
7328ea6e
CH
2633 struct xfs_dinode *dip,
2634 blkmap_t *blkmap,
2635 inodata_t *id)
2bd0ea18 2636{
7328ea6e
CH
2637 xfs_fsblock_t bno;
2638 int dot;
2639 int dotdot;
2640 xfs_ino_t parent;
2bd0ea18
NS
2641
2642 dot = dotdot = 0;
9a048535
DC
2643 if (process_dir_v2(dip, blkmap, &dot, &dotdot, id, &parent))
2644 return;
2645
2bd0ea18
NS
2646 bno = XFS_INO_TO_FSB(mp, id->ino);
2647 if (dot == 0) {
2648 if (!sflag || id->ilist || CHECK_BLIST(bno))
9ee7055c 2649 dbprintf(_("no . entry for directory %lld\n"), id->ino);
2bd0ea18
NS
2650 error++;
2651 }
2652 if (dotdot == 0) {
2653 if (!sflag || id->ilist || CHECK_BLIST(bno))
9ee7055c 2654 dbprintf(_("no .. entry for directory %lld\n"), id->ino);
2bd0ea18
NS
2655 error++;
2656 } else if (parent == id->ino && id->ino != mp->m_sb.sb_rootino) {
2657 if (!sflag || id->ilist || CHECK_BLIST(bno))
9ee7055c 2658 dbprintf(_(". and .. same for non-root directory %lld\n"),
2bd0ea18
NS
2659 id->ino);
2660 error++;
2661 } else if (id->ino == mp->m_sb.sb_rootino && id->ino != parent) {
2662 if (!sflag || id->ilist || CHECK_BLIST(bno))
9ee7055c 2663 dbprintf(_("root directory %lld has .. %lld\n"), id->ino,
2bd0ea18
NS
2664 parent);
2665 error++;
2666 } else if (parent != NULLFSINO && id->ino != parent)
2667 addparent_inode(id, parent);
2668}
2669
2bd0ea18
NS
2670static int
2671process_dir_v2(
7328ea6e
CH
2672 struct xfs_dinode *dip,
2673 blkmap_t *blkmap,
2674 int *dot,
2675 int *dotdot,
2676 inodata_t *id,
2677 xfs_ino_t *parent)
2bd0ea18 2678{
7328ea6e
CH
2679 xfs_fileoff_t last = 0;
2680 xfs_fsize_t size = be64_to_cpu(dip->di_size);
2bd0ea18
NS
2681
2682 if (blkmap)
2683 last = blkmap_last_off(blkmap);
5e656dbb 2684 if (size <= XFS_DFORK_DSIZE(dip, mp) &&
56b2de80 2685 dip->di_format == XFS_DINODE_FMT_LOCAL)
2bd0ea18 2686 *parent = process_sf_dir_v2(dip, dot, dotdot, id);
ff105f75 2687 else if (last == mp->m_dir_geo->fsbcount &&
56b2de80
DC
2688 (dip->di_format == XFS_DINODE_FMT_EXTENTS ||
2689 dip->di_format == XFS_DINODE_FMT_BTREE))
2bd0ea18 2690 *parent = process_block_dir_v2(blkmap, dot, dotdot, id);
ff105f75 2691 else if (last >= mp->m_dir_geo->leafblk + mp->m_dir_geo->fsbcount &&
56b2de80
DC
2692 (dip->di_format == XFS_DINODE_FMT_EXTENTS ||
2693 dip->di_format == XFS_DINODE_FMT_BTREE))
5e656dbb 2694 *parent = process_leaf_node_dir_v2(blkmap, dot, dotdot, id, size);
2bd0ea18 2695 else {
9ee7055c
AM
2696 dbprintf(_("bad size (%lld) or format (%d) for directory inode "
2697 "%lld\n"),
56b2de80 2698 size, dip->di_format, id->ino);
2bd0ea18
NS
2699 error++;
2700 return 1;
2701 }
2702 return 0;
2703}
2704
2705/* ARGSUSED */
2706static void
2707process_exinode(
2708 inodata_t *id,
7328ea6e 2709 struct xfs_dinode *dip,
2bd0ea18 2710 dbm_t type,
5a35bf2c
DC
2711 xfs_rfsblock_t *totd,
2712 xfs_rfsblock_t *toti,
2bd0ea18
NS
2713 xfs_extnum_t *nex,
2714 blkmap_t **blkmapp,
2715 int whichfork)
2716{
b9652a81 2717 xfs_bmbt_rec_t *rp;
95e3fc7f 2718 xfs_extnum_t max_nex;
2bd0ea18 2719
b9652a81 2720 rp = (xfs_bmbt_rec_t *)XFS_DFORK_PTR(dip, whichfork);
5f70c91b 2721 *nex = xfs_dfork_nextents(dip, whichfork);
95e3fc7f
DW
2722 max_nex = xfs_iext_max_nextents(
2723 xfs_dinode_has_large_extent_counts(dip),
2724 whichfork);
2725 if (*nex > max_nex || *nex > XFS_DFORK_SIZE(dip, mp, whichfork) /
b9652a81 2726 sizeof(xfs_bmbt_rec_t)) {
2bd0ea18 2727 if (!sflag || id->ilist)
95e3fc7f
DW
2728 dbprintf(_("bad number of extents %llu for inode %lld\n"),
2729 (unsigned long long)*nex, id->ino);
2bd0ea18
NS
2730 error++;
2731 return;
2732 }
2733 process_bmbt_reclist(rp, *nex, type, id, totd, blkmapp);
2734}
2735
2736static void
2737process_inode(
2738 xfs_agf_t *agf,
2739 xfs_agino_t agino,
7328ea6e 2740 struct xfs_dinode *dip,
2bd0ea18
NS
2741 int isfree)
2742{
2743 blkmap_t *blkmap;
2744 xfs_fsblock_t bno = 0;
2bd0ea18
NS
2745 inodata_t *id = NULL;
2746 xfs_ino_t ino;
2747 xfs_extnum_t nextents = 0;
5f70c91b 2748 xfs_extnum_t dnextents;
2bd0ea18 2749 int security;
5a35bf2c
DC
2750 xfs_rfsblock_t totblocks;
2751 xfs_rfsblock_t totdblocks = 0;
2752 xfs_rfsblock_t totiblocks = 0;
2bd0ea18
NS
2753 dbm_t type;
2754 xfs_extnum_t anextents = 0;
5f70c91b 2755 xfs_extnum_t danextents;
5a35bf2c
DC
2756 xfs_rfsblock_t atotdblocks = 0;
2757 xfs_rfsblock_t atotiblocks = 0;
2bd0ea18
NS
2758 xfs_qcnt_t bc = 0;
2759 xfs_qcnt_t ic = 0;
2760 xfs_qcnt_t rc = 0;
527d1f42 2761 int v = 0;
e37bf53c 2762 mode_t mode;
6526f30e
DW
2763 uint16_t diflags;
2764 uint64_t diflags2 = 0;
2765 xfs_nlink_t nlink;
2766 xfs_dqid_t uid;
2767 xfs_dqid_t gid;
2768 xfs_dqid_t prid;
2bd0ea18
NS
2769 static char okfmts[] = {
2770 0, /* type 0 unused */
2771 1 << XFS_DINODE_FMT_DEV, /* FIFO */
2772 1 << XFS_DINODE_FMT_DEV, /* CHR */
2773 0, /* type 3 unused */
2774 (1 << XFS_DINODE_FMT_LOCAL) |
2775 (1 << XFS_DINODE_FMT_EXTENTS) |
2776 (1 << XFS_DINODE_FMT_BTREE), /* DIR */
2777 0, /* type 5 unused */
2778 1 << XFS_DINODE_FMT_DEV, /* BLK */
2779 0, /* type 7 unused */
2780 (1 << XFS_DINODE_FMT_EXTENTS) |
2781 (1 << XFS_DINODE_FMT_BTREE), /* REG */
2782 0, /* type 9 unused */
2783 (1 << XFS_DINODE_FMT_LOCAL) |
2784 (1 << XFS_DINODE_FMT_EXTENTS), /* LNK */
2785 0, /* type 11 unused */
2786 1 << XFS_DINODE_FMT_DEV, /* SOCK */
2787 0, /* type 13 unused */
2788 1 << XFS_DINODE_FMT_UUID, /* MNT */
2789 0 /* type 15 unused */
2790 };
2791 static char *fmtnames[] = {
2792 "dev", "local", "extents", "btree", "uuid"
2793 };
2794
5e656dbb 2795 ino = XFS_AGINO_TO_INO(mp, be32_to_cpu(agf->agf_seqno), agino);
2bd0ea18
NS
2796 if (!isfree) {
2797 id = find_inode(ino, 1);
2798 bno = XFS_INO_TO_FSB(mp, ino);
2799 blkmap = NULL;
2800 }
527d1f42 2801 v = (!sflag || (id && id->ilist) || CHECK_BLIST(bno));
db17aebe 2802 if (dip->di_magic != cpu_to_be16(XFS_DINODE_MAGIC)) {
527d1f42 2803 if (isfree || v)
9ee7055c 2804 dbprintf(_("bad magic number %#x for inode %lld\n"),
db17aebe 2805 be16_to_cpu(dip->di_magic), ino);
2bd0ea18
NS
2806 error++;
2807 return;
2808 }
03d8044d 2809 if (!libxfs_dinode_good_version(mp, dip->di_version)) {
527d1f42 2810 if (isfree || v)
9ee7055c 2811 dbprintf(_("bad version number %#x for inode %lld\n"),
fd82a87e 2812 dip->di_version, ino);
2bd0ea18
NS
2813 error++;
2814 return;
2815 }
6526f30e
DW
2816 if (dip->di_version == 1) {
2817 nlink = be16_to_cpu(dip->di_onlink);
2818 prid = 0;
2819 } else {
2820 nlink = be32_to_cpu(dip->di_nlink);
2821 prid = (xfs_dqid_t)be16_to_cpu(dip->di_projid_hi) << 16 |
2822 be16_to_cpu(dip->di_projid_lo);
2823 }
2824 uid = be32_to_cpu(dip->di_uid);
2825 gid = be32_to_cpu(dip->di_gid);
2826 diflags = be16_to_cpu(dip->di_flags);
2660e653 2827 if (xfs_has_v3inodes(mp))
6526f30e 2828 diflags2 = be64_to_cpu(dip->di_flags2);
2bd0ea18 2829 if (isfree) {
6526f30e 2830 if (be64_to_cpu(dip->di_nblocks) != 0) {
527d1f42 2831 if (v)
9ee7055c
AM
2832 dbprintf(_("bad nblocks %lld for free inode "
2833 "%lld\n"),
6526f30e 2834 be64_to_cpu(dip->di_nblocks), ino);
2bd0ea18
NS
2835 error++;
2836 }
4751e054 2837 if (nlink != 0) {
527d1f42 2838 if (v)
9ee7055c 2839 dbprintf(_("bad nlink %d for free inode %lld\n"),
4751e054 2840 nlink, ino);
2bd0ea18
NS
2841 error++;
2842 }
e37bf53c 2843 if (dip->di_mode != 0) {
527d1f42 2844 if (v)
9ee7055c 2845 dbprintf(_("bad mode %#o for free inode %lld\n"),
e37bf53c 2846 be16_to_cpu(dip->di_mode), ino);
2bd0ea18
NS
2847 error++;
2848 }
2849 return;
2850 }
527d1f42 2851
49b31417 2852 if (be32_to_cpu(dip->di_next_unlinked) != NULLAGINO) {
527d1f42 2853 if (v)
9ee7055c 2854 dbprintf(_("bad next unlinked %#x for inode %lld\n"),
49b31417
BN
2855 be32_to_cpu(dip->di_next_unlinked), ino);
2856 error++;
2857 }
2bd0ea18
NS
2858 /*
2859 * di_mode is a 16-bit uint so no need to check the < 0 case
2860 */
e37bf53c
DC
2861 mode = be16_to_cpu(dip->di_mode);
2862 if ((((mode & S_IFMT) >> 12) > 15) ||
6526f30e 2863 (!(okfmts[(mode & S_IFMT) >> 12] & (1 << dip->di_format)))) {
527d1f42 2864 if (v)
9ee7055c 2865 dbprintf(_("bad format %d for inode %lld type %#o\n"),
6526f30e 2866 dip->di_format, id->ino, mode & S_IFMT);
2bd0ea18
NS
2867 error++;
2868 return;
2869 }
4de63245 2870 if ((unsigned int)XFS_DFORK_ASIZE(dip, mp) >= XFS_LITINO(mp)) {
527d1f42 2871 if (v)
9ee7055c 2872 dbprintf(_("bad fork offset %d for inode %lld\n"),
6526f30e 2873 dip->di_forkoff, id->ino);
2bd0ea18
NS
2874 error++;
2875 return;
2876 }
6526f30e 2877 if ((unsigned int)dip->di_aformat > XFS_DINODE_FMT_BTREE) {
527d1f42 2878 if (v)
9ee7055c 2879 dbprintf(_("bad attribute format %d for inode %lld\n"),
6526f30e 2880 dip->di_aformat, id->ino);
2bd0ea18
NS
2881 error++;
2882 return;
2883 }
5f70c91b
CB
2884
2885 dnextents = xfs_dfork_data_extents(dip);
2886 danextents = xfs_dfork_attr_extents(dip);
2887
527d1f42 2888 if (verbose || (id && id->ilist) || CHECK_BLIST(bno))
9ee7055c 2889 dbprintf(_("inode %lld mode %#o fmt %s "
2bd0ea18 2890 "afmt %s "
9ee7055c 2891 "nex %d anex %d nblk %lld sz %lld%s%s%s%s%s%s%s\n"),
6526f30e
DW
2892 id->ino, mode, fmtnames[(int)dip->di_format],
2893 fmtnames[(int)dip->di_aformat],
5f70c91b 2894 dnextents, danextents,
6526f30e
DW
2895 be64_to_cpu(dip->di_nblocks), be64_to_cpu(dip->di_size),
2896 diflags & XFS_DIFLAG_REALTIME ? " rt" : "",
2897 diflags & XFS_DIFLAG_PREALLOC ? " pre" : "",
2898 diflags & XFS_DIFLAG_IMMUTABLE? " imm" : "",
2899 diflags & XFS_DIFLAG_APPEND ? " app" : "",
2900 diflags & XFS_DIFLAG_SYNC ? " syn" : "",
2901 diflags & XFS_DIFLAG_NOATIME ? " noa" : "",
2902 diflags & XFS_DIFLAG_NODUMP ? " nod" : "");
2bd0ea18 2903 security = 0;
e37bf53c 2904 switch (mode & S_IFMT) {
322f2a29 2905 case S_IFDIR:
2bd0ea18 2906 type = DBM_DIR;
6526f30e 2907 if (dip->di_format == XFS_DINODE_FMT_LOCAL)
2bd0ea18 2908 break;
5f70c91b 2909 blkmap = blkmap_alloc(dnextents);
2bd0ea18 2910 break;
322f2a29 2911 case S_IFREG:
6526f30e 2912 if (diflags & XFS_DIFLAG_REALTIME)
2bd0ea18
NS
2913 type = DBM_RTDATA;
2914 else if (id->ino == mp->m_sb.sb_rbmino) {
2915 type = DBM_RTBITMAP;
5f70c91b 2916 blkmap = blkmap_alloc(dnextents);
2bd0ea18
NS
2917 addlink_inode(id);
2918 } else if (id->ino == mp->m_sb.sb_rsumino) {
2919 type = DBM_RTSUM;
5f70c91b 2920 blkmap = blkmap_alloc(dnextents);
2bd0ea18
NS
2921 addlink_inode(id);
2922 }
2923 else if (id->ino == mp->m_sb.sb_uquotino ||
0340d706
CS
2924 id->ino == mp->m_sb.sb_gquotino ||
2925 id->ino == mp->m_sb.sb_pquotino) {
2bd0ea18 2926 type = DBM_QUOTA;
5f70c91b 2927 blkmap = blkmap_alloc(dnextents);
2bd0ea18
NS
2928 addlink_inode(id);
2929 }
2930 else
2931 type = DBM_DATA;
e37bf53c 2932 if (mode & (S_ISUID | S_ISGID))
2bd0ea18
NS
2933 security = 1;
2934 break;
322f2a29 2935 case S_IFLNK:
2bd0ea18
NS
2936 type = DBM_SYMLINK;
2937 break;
2938 default:
2939 security = 1;
2940 type = DBM_UNKNOWN;
2941 break;
2942 }
f089fc42 2943
6526f30e
DW
2944 id->isreflink = !!(diflags2 & XFS_DIFLAG2_REFLINK);
2945 setlink_inode(id, nlink, type == DBM_DIR, security);
f089fc42 2946
6526f30e 2947 switch (dip->di_format) {
2bd0ea18
NS
2948 case XFS_DINODE_FMT_LOCAL:
2949 process_lclinode(id, dip, type, &totdblocks, &totiblocks,
2950 &nextents, &blkmap, XFS_DATA_FORK);
2951 break;
2952 case XFS_DINODE_FMT_EXTENTS:
2953 process_exinode(id, dip, type, &totdblocks, &totiblocks,
2954 &nextents, &blkmap, XFS_DATA_FORK);
2955 break;
2956 case XFS_DINODE_FMT_BTREE:
2957 process_btinode(id, dip, type, &totdblocks, &totiblocks,
2958 &nextents, &blkmap, XFS_DATA_FORK);
2959 break;
2960 }
8c6cccd7 2961 if (dip->di_forkoff) {
2bd0ea18 2962 sbversion |= XFS_SB_VERSION_ATTRBIT;
6526f30e 2963 switch (dip->di_aformat) {
2bd0ea18
NS
2964 case XFS_DINODE_FMT_LOCAL:
2965 process_lclinode(id, dip, DBM_ATTR, &atotdblocks,
2966 &atotiblocks, &anextents, NULL, XFS_ATTR_FORK);
2967 break;
2968 case XFS_DINODE_FMT_EXTENTS:
2969 process_exinode(id, dip, DBM_ATTR, &atotdblocks,
2970 &atotiblocks, &anextents, NULL, XFS_ATTR_FORK);
2971 break;
2972 case XFS_DINODE_FMT_BTREE:
2973 process_btinode(id, dip, DBM_ATTR, &atotdblocks,
2974 &atotiblocks, &anextents, NULL, XFS_ATTR_FORK);
2975 break;
2976 }
2977 }
9b27bdbb 2978 if (qgdo || qpdo || qudo) {
2bd0ea18
NS
2979 switch (type) {
2980 case DBM_DATA:
2981 case DBM_DIR:
2982 case DBM_RTBITMAP:
2983 case DBM_RTSUM:
2984 case DBM_SYMLINK:
2985 case DBM_UNKNOWN:
2986 bc = totdblocks + totiblocks +
2987 atotdblocks + atotiblocks;
2988 ic = 1;
2989 break;
2990 case DBM_RTDATA:
2991 bc = totiblocks + atotdblocks + atotiblocks;
2992 rc = totdblocks;
2993 ic = 1;
2994 break;
2995 default:
6bef826c 2996 break;
2bd0ea18 2997 }
6526f30e
DW
2998 if (ic)
2999 quota_add(&prid, &gid, &uid, 0, bc, ic, rc);
2bd0ea18
NS
3000 }
3001 totblocks = totdblocks + totiblocks + atotdblocks + atotiblocks;
6526f30e 3002 if (totblocks != be64_to_cpu(dip->di_nblocks)) {
527d1f42 3003 if (v)
9ee7055c
AM
3004 dbprintf(_("bad nblocks %lld for inode %lld, counted "
3005 "%lld\n"),
6526f30e 3006 be64_to_cpu(dip->di_nblocks), id->ino, totblocks);
2bd0ea18
NS
3007 error++;
3008 }
5f70c91b 3009 if (nextents != dnextents) {
527d1f42 3010 if (v)
9ee7055c 3011 dbprintf(_("bad nextents %d for inode %lld, counted %d\n"),
5f70c91b 3012 dnextents, id->ino, nextents);
2bd0ea18
NS
3013 error++;
3014 }
5f70c91b 3015 if (anextents != danextents) {
527d1f42 3016 if (v)
9ee7055c
AM
3017 dbprintf(_("bad anextents %d for inode %lld, counted "
3018 "%d\n"),
5f70c91b 3019 danextents, id->ino, anextents);
2bd0ea18
NS
3020 error++;
3021 }
3022 if (type == DBM_DIR)
3023 process_dir(dip, blkmap, id);
3024 else if (type == DBM_RTBITMAP)
3025 process_rtbitmap(blkmap);
3026 else if (type == DBM_RTSUM)
3027 process_rtsummary(blkmap);
3028 /*
3029 * If the CHKD flag is not set, this can legitimately contain garbage;
3030 * xfs_repair may have cleared that bit.
3031 */
b36eef04
NS
3032 else if (type == DBM_QUOTA) {
3033 if (id->ino == mp->m_sb.sb_uquotino &&
3034 (mp->m_sb.sb_qflags & XFS_UQUOTA_ACCT) &&
3035 (mp->m_sb.sb_qflags & XFS_UQUOTA_CHKD))
9b27bdbb 3036 process_quota(IS_USER_QUOTA, id, blkmap);
b36eef04
NS
3037 else if (id->ino == mp->m_sb.sb_gquotino &&
3038 (mp->m_sb.sb_qflags & XFS_GQUOTA_ACCT) &&
342aef1e 3039 (mp->m_sb.sb_qflags & XFS_GQUOTA_CHKD))
9b27bdbb 3040 process_quota(IS_GROUP_QUOTA, id, blkmap);
0340d706 3041 else if (id->ino == mp->m_sb.sb_pquotino &&
9b27bdbb 3042 (mp->m_sb.sb_qflags & XFS_PQUOTA_ACCT) &&
342aef1e 3043 (mp->m_sb.sb_qflags & XFS_PQUOTA_CHKD))
9b27bdbb 3044 process_quota(IS_PROJECT_QUOTA, id, blkmap);
b36eef04 3045 }
2bd0ea18
NS
3046 if (blkmap)
3047 blkmap_free(blkmap);
3048}
3049
3050/* ARGSUSED */
3051static void
3052process_lclinode(
2fd09353 3053 inodata_t *id,
7328ea6e 3054 struct xfs_dinode *dip,
2fd09353
CM
3055 dbm_t type,
3056 xfs_rfsblock_t *totd,
3057 xfs_rfsblock_t *toti,
3058 xfs_extnum_t *nex,
3059 blkmap_t **blkmapp,
3060 int whichfork)
3061{
3062 struct xfs_attr_shortform *asf;
3063 xfs_fsblock_t bno;
2bd0ea18 3064
2bd0ea18 3065 bno = XFS_INO_TO_FSB(mp, id->ino);
56b2de80 3066 if (whichfork == XFS_DATA_FORK && be64_to_cpu(dip->di_size) >
5e656dbb 3067 XFS_DFORK_DSIZE(dip, mp)) {
2bd0ea18 3068 if (!sflag || id->ilist || CHECK_BLIST(bno))
9ee7055c
AM
3069 dbprintf(_("local inode %lld data is too large (size "
3070 "%lld)\n"),
56b2de80 3071 id->ino, be64_to_cpu(dip->di_size));
2bd0ea18
NS
3072 error++;
3073 }
3074 else if (whichfork == XFS_ATTR_FORK) {
2fd09353 3075 asf = (struct xfs_attr_shortform *)XFS_DFORK_APTR(dip);
5e656dbb 3076 if (be16_to_cpu(asf->hdr.totsize) > XFS_DFORK_ASIZE(dip, mp)) {
2bd0ea18 3077 if (!sflag || id->ilist || CHECK_BLIST(bno))
9ee7055c
AM
3078 dbprintf(_("local inode %lld attr is too large "
3079 "(size %d)\n"),
5e656dbb 3080 id->ino, be16_to_cpu(asf->hdr.totsize));
2bd0ea18
NS
3081 error++;
3082 }
3083 }
3084}
3085
2bd0ea18
NS
3086static xfs_ino_t
3087process_leaf_node_dir_v2(
3088 blkmap_t *blkmap,
3089 int *dot,
3090 int *dotdot,
3091 inodata_t *id,
3092 xfs_fsize_t dirsize)
3093{
3094 xfs_fsblock_t b;
3095 bbmap_t bbmap;
3096 bmap_ext_t *bmp;
3097 xfs_fileoff_t dbno;
3098 freetab_t *freetab;
3099 int i;
3100 xfs_ino_t lino;
3101 int nex;
3102 xfs_ino_t parent;
bb38a39f 3103 int t = 0;
2bd0ea18
NS
3104 int v;
3105 int v2;
2bd0ea18
NS
3106
3107 v2 = verbose || id->ilist;
3108 v = parent = 0;
3109 dbno = NULLFILEOFF;
ff105f75
DC
3110 freetab = malloc(FREETAB_SIZE(dirsize / mp->m_dir_geo->blksize));
3111 freetab->naents = (int)(dirsize / mp->m_dir_geo->blksize);
2bd0ea18
NS
3112 freetab->nents = 0;
3113 for (i = 0; i < freetab->naents; i++)
3114 freetab->ents[i] = NULLDATAOFF;
3115 dir_hash_init();
3116 while ((dbno = blkmap_next_off(blkmap, dbno, &t)) != NULLFILEOFF) {
ff105f75 3117 nex = blkmap_getn(blkmap, dbno, mp->m_dir_geo->fsbcount, &bmp);
2bd0ea18 3118 ASSERT(nex > 0);
4add9d50
ES
3119 for (v = v2, i = 0; !v && i < nex; i++) {
3120 for (b = bmp[i].startblock;
3121 !v && b < bmp[i].startblock + bmp[i].blockcount;
2bd0ea18
NS
3122 b++)
3123 v = CHECK_BLIST(b);
3124 }
3125 if (v)
9ee7055c 3126 dbprintf(_("dir inode %lld block %u=%llu\n"), id->ino,
14f8b681 3127 (uint32_t)dbno,
5a35bf2c 3128 (xfs_fsblock_t)bmp->startblock);
2bd0ea18
NS
3129 push_cur();
3130 if (nex > 1)
3131 make_bbmap(&bbmap, nex, bmp);
9a048535 3132 set_cur(&typtab[TYP_DIR2], XFS_FSB_TO_DADDR(mp, bmp->startblock),
ff105f75 3133 mp->m_dir_geo->fsbcount * blkbb, DB_RING_IGN,
2bd0ea18
NS
3134 nex > 1 ? &bbmap : NULL);
3135 free(bmp);
3136 if (iocur_top->data == NULL) {
3137 if (!sflag || v)
9ee7055c
AM
3138 dbprintf(_("can't read block %u for directory "
3139 "inode %lld\n"),
14f8b681 3140 (uint32_t)dbno, id->ino);
2bd0ea18
NS
3141 error++;
3142 pop_cur();
ff105f75 3143 dbno += mp->m_dir_geo->fsbcount - 1;
2bd0ea18
NS
3144 continue;
3145 }
ff105f75 3146 if (dbno < mp->m_dir_geo->leafblk) {
2bd0ea18
NS
3147 lino = process_data_dir_v2(dot, dotdot, id, v,
3148 (xfs_dablk_t)dbno, &freetab);
3149 if (lino) {
3150 if (parent) {
3151 if (!sflag || v)
9ee7055c
AM
3152 dbprintf(_("multiple .. entries "
3153 "in dir %lld\n"),
2bd0ea18
NS
3154 id->ino);
3155 error++;
3156 } else
3157 parent = lino;
3158 }
ff105f75 3159 } else if (dbno < mp->m_dir_geo->freeblk) {
2bd0ea18
NS
3160 process_leaf_node_dir_v2_int(id, v, (xfs_dablk_t)dbno,
3161 freetab);
3162 } else {
3163 process_leaf_node_dir_v2_free(id, v, (xfs_dablk_t)dbno,
3164 freetab);
3165 }
3166 pop_cur();
ff105f75 3167 dbno += mp->m_dir_geo->fsbcount - 1;
2bd0ea18
NS
3168 }
3169 dir_hash_check(id, v);
3170 dir_hash_done();
3171 for (i = 0; i < freetab->nents; i++) {
3172 if (freetab->ents[i] != NULLDATAOFF) {
3173 if (!sflag || v)
9ee7055c
AM
3174 dbprintf(_("missing free index for data block %d "
3175 "in dir ino %lld\n"),
ff105f75 3176 xfs_dir2_db_to_da(mp->m_dir_geo, i), id->ino);
2bd0ea18
NS
3177 error++;
3178 }
3179 }
3180 free(freetab);
3181 return parent;
3182}
3183
e96864ff
DW
3184static void
3185process_leaf_node_dir_v3_free(
3186 inodata_t *id,
3187 int v,
3188 xfs_dablk_t dabno,
3189 freetab_t *freetab)
3190{
3191 xfs_dir2_data_off_t ent;
3192 struct xfs_dir3_free *free;
3193 int i;
3194 int maxent;
3195 int used;
3196
3197 free = iocur_top->data;
ae3cd5b1 3198 maxent = mp->m_dir_geo->free_max_bests;
f8149110 3199 if (be32_to_cpu(free->hdr.firstdb) != xfs_dir2_da_to_db(mp->m_dir_geo,
e96864ff
DW
3200 dabno - mp->m_dir_geo->freeblk) * maxent) {
3201 if (!sflag || v)
3202 dbprintf(_("bad free block firstdb %d for dir ino %lld "
3203 "block %d\n"),
3204 be32_to_cpu(free->hdr.firstdb), id->ino, dabno);
3205 error++;
3206 return;
3207 }
f8149110
JT
3208 if (be32_to_cpu(free->hdr.nvalid) > maxent ||
3209 be32_to_cpu(free->hdr.nused) > maxent ||
3210 be32_to_cpu(free->hdr.nused) >
e96864ff
DW
3211 be32_to_cpu(free->hdr.nvalid)) {
3212 if (!sflag || v)
3213 dbprintf(_("bad free block nvalid/nused %d/%d for dir "
3214 "ino %lld block %d\n"),
f8149110 3215 be32_to_cpu(free->hdr.nvalid),
e96864ff
DW
3216 be32_to_cpu(free->hdr.nused), id->ino, dabno);
3217 error++;
3218 return;
3219 }
3220 for (used = i = 0; i < be32_to_cpu(free->hdr.nvalid); i++) {
3221 if (freetab->nents <= be32_to_cpu(free->hdr.firstdb) + i)
3222 ent = NULLDATAOFF;
3223 else
3224 ent = freetab->ents[be32_to_cpu(free->hdr.firstdb) + i];
3225 if (ent != be16_to_cpu(free->bests[i])) {
3226 if (!sflag || v)
3227 dbprintf(_("bad free block ent %d is %d should "
3228 "be %d for dir ino %lld block %d\n"),
f8149110 3229 i, be16_to_cpu(free->bests[i]), ent,
e96864ff
DW
3230 id->ino, dabno);
3231 error++;
3232 }
3233 if (be16_to_cpu(free->bests[i]) != NULLDATAOFF)
3234 used++;
3235 if (ent != NULLDATAOFF)
f8149110 3236 freetab->ents[be32_to_cpu(free->hdr.firstdb) + i] =
e96864ff
DW
3237 NULLDATAOFF;
3238 }
3239 if (used != be32_to_cpu(free->hdr.nused)) {
3240 if (!sflag || v)
3241 dbprintf(_("bad free block nused %d should be %d for dir "
3242 "ino %lld block %d\n"),
f8149110 3243 be32_to_cpu(free->hdr.nused), used, id->ino,
e96864ff
DW
3244 dabno);
3245 error++;
3246 }
3247}
3248
2bd0ea18
NS
3249static void
3250process_leaf_node_dir_v2_free(
3251 inodata_t *id,
3252 int v,
3253 xfs_dablk_t dabno,
3254 freetab_t *freetab)
3255{
3256 xfs_dir2_data_off_t ent;
3257 xfs_dir2_free_t *free;
3258 int i;
3259 int maxent;
3260 int used;
3261
3262 free = iocur_top->data;
e96864ff
DW
3263 if (be32_to_cpu(free->hdr.magic) != XFS_DIR2_FREE_MAGIC &&
3264 be32_to_cpu(free->hdr.magic) != XFS_DIR3_FREE_MAGIC) {
2bd0ea18 3265 if (!sflag || v)
9ee7055c
AM
3266 dbprintf(_("bad free block magic # %#x for dir ino %lld "
3267 "block %d\n"),
5e656dbb 3268 be32_to_cpu(free->hdr.magic), id->ino, dabno);
2bd0ea18
NS
3269 error++;
3270 return;
3271 }
e96864ff
DW
3272 if (be32_to_cpu(free->hdr.magic) == XFS_DIR3_FREE_MAGIC) {
3273 process_leaf_node_dir_v3_free(id, v, dabno, freetab);
3274 return;
3275 }
ae3cd5b1 3276 maxent = mp->m_dir_geo->free_max_bests;
f8149110 3277 if (be32_to_cpu(free->hdr.firstdb) != xfs_dir2_da_to_db(mp->m_dir_geo,
ff105f75 3278 dabno - mp->m_dir_geo->freeblk) * maxent) {
2bd0ea18 3279 if (!sflag || v)
9ee7055c
AM
3280 dbprintf(_("bad free block firstdb %d for dir ino %lld "
3281 "block %d\n"),
5e656dbb 3282 be32_to_cpu(free->hdr.firstdb), id->ino, dabno);
2bd0ea18
NS
3283 error++;
3284 return;
3285 }
f8149110 3286 if (be32_to_cpu(free->hdr.nvalid) > maxent ||
f8149110 3287 be32_to_cpu(free->hdr.nused) > maxent ||
f8149110 3288 be32_to_cpu(free->hdr.nused) >
5e656dbb 3289 be32_to_cpu(free->hdr.nvalid)) {
2bd0ea18 3290 if (!sflag || v)
9ee7055c
AM
3291 dbprintf(_("bad free block nvalid/nused %d/%d for dir "
3292 "ino %lld block %d\n"),
f8149110 3293 be32_to_cpu(free->hdr.nvalid),
5e656dbb 3294 be32_to_cpu(free->hdr.nused), id->ino, dabno);
2bd0ea18
NS
3295 error++;
3296 return;
3297 }
5e656dbb
BN
3298 for (used = i = 0; i < be32_to_cpu(free->hdr.nvalid); i++) {
3299 if (freetab->nents <= be32_to_cpu(free->hdr.firstdb) + i)
2bd0ea18
NS
3300 ent = NULLDATAOFF;
3301 else
5e656dbb
BN
3302 ent = freetab->ents[be32_to_cpu(free->hdr.firstdb) + i];
3303 if (ent != be16_to_cpu(free->bests[i])) {
2bd0ea18 3304 if (!sflag || v)
9ee7055c
AM
3305 dbprintf(_("bad free block ent %d is %d should "
3306 "be %d for dir ino %lld block %d\n"),
f8149110 3307 i, be16_to_cpu(free->bests[i]), ent,
5e656dbb 3308 id->ino, dabno);
2bd0ea18
NS
3309 error++;
3310 }
5e656dbb 3311 if (be16_to_cpu(free->bests[i]) != NULLDATAOFF)
2bd0ea18
NS
3312 used++;
3313 if (ent != NULLDATAOFF)
f8149110 3314 freetab->ents[be32_to_cpu(free->hdr.firstdb) + i] =
5e656dbb 3315 NULLDATAOFF;
2bd0ea18 3316 }
5e656dbb 3317 if (used != be32_to_cpu(free->hdr.nused)) {
2bd0ea18 3318 if (!sflag || v)
9ee7055c
AM
3319 dbprintf(_("bad free block nused %d should be %d for dir "
3320 "ino %lld block %d\n"),
f8149110 3321 be32_to_cpu(free->hdr.nused), used, id->ino,
5e656dbb 3322 dabno);
2bd0ea18
NS
3323 error++;
3324 }
3325}
3326
e96864ff
DW
3327/*
3328 * Get address of the bestcount field in the single-leaf block.
3329 */
3330static inline int
3331xfs_dir3_leaf_ents_count(struct xfs_dir2_leaf *lp)
3332{
3333 if (lp->hdr.info.magic == cpu_to_be16(XFS_DIR3_LEAF1_MAGIC) ||
3334 lp->hdr.info.magic == cpu_to_be16(XFS_DIR3_LEAFN_MAGIC)) {
3335 struct xfs_dir3_leaf *lp3 = (struct xfs_dir3_leaf *)lp;
3336
3337 return be16_to_cpu(lp3->hdr.count);
3338 }
3339 return be16_to_cpu(lp->hdr.count);
3340}
3341
2bd0ea18
NS
3342static void
3343process_leaf_node_dir_v2_int(
3344 inodata_t *id,
3345 int v,
3346 xfs_dablk_t dabno,
3347 freetab_t *freetab)
3348{
3349 int i;
5e656dbb 3350 __be16 *lbp;
2bd0ea18 3351 xfs_dir2_leaf_t *leaf;
e96864ff 3352 struct xfs_dir3_leaf *leaf3 = NULL;
2bd0ea18
NS
3353 xfs_dir2_leaf_entry_t *lep;
3354 xfs_dir2_leaf_tail_t *ltp;
3355 xfs_da_intnode_t *node;
3356 int stale;
88b32f06 3357 struct xfs_da3_icnode_hdr nodehdr;
a2279497 3358 struct xfs_dir3_icleaf_hdr leafhdr;
2bd0ea18
NS
3359
3360 leaf = iocur_top->data;
a2279497
CH
3361 libxfs_dir2_leaf_hdr_from_disk(mp, &leafhdr, leaf);
3362
5e656dbb 3363 switch (be16_to_cpu(leaf->hdr.info.magic)) {
e96864ff
DW
3364 case XFS_DIR3_LEAF1_MAGIC:
3365 case XFS_DIR3_LEAFN_MAGIC:
3366 case XFS_DA3_NODE_MAGIC:
3367 leaf3 = iocur_top->data;
3368 break;
3369 }
3370 switch (be16_to_cpu(leaf->hdr.info.magic)) {
2bd0ea18 3371 case XFS_DIR2_LEAF1_MAGIC:
e96864ff 3372 case XFS_DIR3_LEAF1_MAGIC:
f8149110 3373 if (be32_to_cpu(leaf->hdr.info.forw) ||
5e656dbb 3374 be32_to_cpu(leaf->hdr.info.back)) {
2bd0ea18 3375 if (!sflag || v)
9ee7055c
AM
3376 dbprintf(_("bad leaf block forw/back pointers "
3377 "%d/%d for dir ino %lld block %d\n"),
5e656dbb 3378 be32_to_cpu(leaf->hdr.info.forw),
f8149110 3379 be32_to_cpu(leaf->hdr.info.back),
5e656dbb 3380 id->ino, dabno);
2bd0ea18
NS
3381 error++;
3382 }
ff105f75 3383 if (dabno != mp->m_dir_geo->leafblk) {
2bd0ea18 3384 if (!sflag || v)
9ee7055c
AM
3385 dbprintf(_("single leaf block for dir ino %lld "
3386 "block %d should be at block %d\n"),
2bd0ea18 3387 id->ino, dabno,
ff105f75 3388 (xfs_dablk_t)mp->m_dir_geo->leafblk);
2bd0ea18
NS
3389 error++;
3390 }
ff105f75 3391 ltp = xfs_dir2_leaf_tail_p(mp->m_dir_geo, leaf);
5e656dbb
BN
3392 lbp = xfs_dir2_leaf_bests_p(ltp);
3393 for (i = 0; i < be32_to_cpu(ltp->bestcount); i++) {
f8149110 3394 if (freetab->nents <= i || freetab->ents[i] !=
5e656dbb 3395 be16_to_cpu(lbp[i])) {
2bd0ea18 3396 if (!sflag || v)
9ee7055c 3397 dbprintf(_("bestfree %d for dir ino %lld "
2bd0ea18 3398 "block %d doesn't match table "
9ee7055c 3399 "value %d\n"),
2bd0ea18
NS
3400 freetab->nents <= i ?
3401 NULLDATAOFF :
3402 freetab->ents[i],
3403 id->ino,
ff105f75 3404 xfs_dir2_db_to_da(mp->m_dir_geo, i),
5e656dbb 3405 be16_to_cpu(lbp[i]));
2bd0ea18
NS
3406 }
3407 if (freetab->nents > i)
3408 freetab->ents[i] = NULLDATAOFF;
3409 }
3410 break;
3411 case XFS_DIR2_LEAFN_MAGIC:
e96864ff 3412 case XFS_DIR3_LEAFN_MAGIC:
dfc130f3 3413 /* if it's at the root location then we can check the
2bd0ea18
NS
3414 * pointers are null XXX */
3415 break;
3416 case XFS_DA_NODE_MAGIC:
e96864ff 3417 case XFS_DA3_NODE_MAGIC:
2bd0ea18 3418 node = iocur_top->data;
08c16786 3419 libxfs_da3_node_hdr_from_disk(mp, &nodehdr, node);
88b32f06 3420 if (nodehdr.level < 1 || nodehdr.level > XFS_DA_NODE_MAXDEPTH) {
2bd0ea18 3421 if (!sflag || v)
9ee7055c
AM
3422 dbprintf(_("bad node block level %d for dir ino "
3423 "%lld block %d\n"),
f8149110 3424 nodehdr.level, id->ino,
5e656dbb 3425 dabno);
2bd0ea18
NS
3426 error++;
3427 }
3428 return;
3429 default:
3430 if (!sflag || v)
9ee7055c
AM
3431 dbprintf(_("bad directory data magic # %#x for dir ino "
3432 "%lld block %d\n"),
f8149110 3433 be16_to_cpu(leaf->hdr.info.magic), id->ino,
5e656dbb 3434 dabno);
2bd0ea18
NS
3435 error++;
3436 return;
3437 }
a2279497 3438 lep = leafhdr.ents;
e96864ff 3439 for (i = stale = 0; i < xfs_dir3_leaf_ents_count(leaf); i++) {
5e656dbb 3440 if (be32_to_cpu(lep[i].address) == XFS_DIR2_NULL_DATAPTR)
2bd0ea18 3441 stale++;
f8149110 3442 else if (dir_hash_see(be32_to_cpu(lep[i].hashval),
5e656dbb 3443 be32_to_cpu(lep[i].address))) {
2bd0ea18 3444 if (!sflag || v)
9ee7055c 3445 dbprintf(_("dir %lld block %d extra leaf entry "
f8149110 3446 "%x %x\n"), id->ino, dabno,
5e656dbb
BN
3447 be32_to_cpu(lep[i].hashval),
3448 be32_to_cpu(lep[i].address));
2bd0ea18
NS
3449 error++;
3450 }
3451 }
e96864ff
DW
3452 if (leaf3 && stale != be16_to_cpu(leaf3->hdr.stale)) {
3453 if (!sflag || v)
3454 dbprintf(_("dir3 %lld block %d stale mismatch "
3455 "%d/%d\n"),
3456 id->ino, dabno, stale,
3457 be16_to_cpu(leaf3->hdr.stale));
3458 error++;
f4e6c243 3459 } else if (!leaf3 && stale != be16_to_cpu(leaf->hdr.stale)) {
2bd0ea18 3460 if (!sflag || v)
9ee7055c
AM
3461 dbprintf(_("dir %lld block %d stale mismatch "
3462 "%d/%d\n"),
2bd0ea18 3463 id->ino, dabno, stale,
5e656dbb 3464 be16_to_cpu(leaf->hdr.stale));
2bd0ea18
NS
3465 error++;
3466 }
3467}
3468
2bd0ea18
NS
3469static void
3470process_quota(
bf0f6e17
CH
3471 qtype_t qtype,
3472 inodata_t *id,
3473 blkmap_t *blkmap)
2bd0ea18 3474{
bf0f6e17
CH
3475 xfs_fsblock_t bno;
3476 int cb;
3477 struct xfs_dqblk *dqb;
3478 xfs_dqid_t dqid;
3479 uint8_t exp_flags = 0;
3480 uint i;
3481 uint perblock;
3482 xfs_fileoff_t qbno;
3483 char *s = NULL;
3484 int scicb;
3485 int t = 0;
2bd0ea18 3486
9b27bdbb
NS
3487 switch (qtype) {
3488 case IS_USER_QUOTA:
3489 s = "user";
8e4128a7 3490 exp_flags = XFS_DQTYPE_USER;
9b27bdbb
NS
3491 break;
3492 case IS_PROJECT_QUOTA:
3493 s = "project";
8e4128a7 3494 exp_flags = XFS_DQTYPE_PROJ;
9b27bdbb
NS
3495 break;
3496 case IS_GROUP_QUOTA:
3497 s = "group";
8e4128a7 3498 exp_flags = XFS_DQTYPE_GROUP;
9b27bdbb
NS
3499 break;
3500 default:
3501 ASSERT(0);
3502 }
3503
be8e601c 3504 perblock = (uint)(mp->m_sb.sb_blocksize / sizeof(*dqb));
2bd0ea18
NS
3505 dqid = 0;
3506 qbno = NULLFILEOFF;
d24c0a90 3507 while ((qbno = blkmap_next_off(blkmap, qbno, &t)) != NULLFILEOFF) {
2bd0ea18
NS
3508 bno = blkmap_get(blkmap, qbno);
3509 dqid = (xfs_dqid_t)qbno * perblock;
3510 cb = CHECK_BLIST(bno);
3511 scicb = !sflag || id->ilist || cb;
3512 push_cur();
3513 set_cur(&typtab[TYP_DQBLK], XFS_FSB_TO_DADDR(mp, bno), blkbb,
3514 DB_RING_IGN, NULL);
3515 if ((dqb = iocur_top->data) == NULL) {
2bd0ea18 3516 if (scicb)
9ee7055c
AM
3517 dbprintf(_("can't read block %lld for %s quota "
3518 "inode (fsblock %lld)\n"),
5a35bf2c
DC
3519 (xfs_fileoff_t)qbno, s,
3520 (xfs_fsblock_t)bno);
2bd0ea18 3521 error++;
d24c0a90 3522 pop_cur();
2bd0ea18
NS
3523 continue;
3524 }
3525 for (i = 0; i < perblock; i++, dqid++, dqb++) {
3526 if (verbose || id->ilist || cb)
9ee7055c
AM
3527 dbprintf(_("%s dqblk %lld entry %d id %u bc "
3528 "%lld ic %lld rc %lld\n"),
5a35bf2c 3529 s, (xfs_fileoff_t)qbno, i, dqid,
5e656dbb
BN
3530 be64_to_cpu(dqb->dd_diskdq.d_bcount),
3531 be64_to_cpu(dqb->dd_diskdq.d_icount),
3532 be64_to_cpu(dqb->dd_diskdq.d_rtbcount));
3533 if (be16_to_cpu(dqb->dd_diskdq.d_magic) != XFS_DQUOT_MAGIC) {
2bd0ea18 3534 if (scicb)
9ee7055c
AM
3535 dbprintf(_("bad magic number %#x for %s "
3536 "dqblk %lld entry %d id %u\n"),
5e656dbb 3537 be16_to_cpu(dqb->dd_diskdq.d_magic), s,
5a35bf2c 3538 (xfs_fileoff_t)qbno, i, dqid);
2bd0ea18
NS
3539 error++;
3540 continue;
3541 }
5e656dbb 3542 if (dqb->dd_diskdq.d_version != XFS_DQUOT_VERSION) {
2bd0ea18 3543 if (scicb)
9ee7055c 3544 dbprintf(_("bad version number %#x for "
2bd0ea18 3545 "%s dqblk %lld entry %d id "
9ee7055c 3546 "%u\n"),
5e656dbb 3547 dqb->dd_diskdq.d_version, s,
5a35bf2c 3548 (xfs_fileoff_t)qbno, i, dqid);
2bd0ea18
NS
3549 error++;
3550 continue;
3551 }
cde0e6a6 3552 if (dqb->dd_diskdq.d_type & ~XFS_DQTYPE_ANY) {
2bd0ea18 3553 if (scicb)
9ee7055c
AM
3554 dbprintf(_("bad flags %#x for %s dqblk "
3555 "%lld entry %d id %u\n"),
cde0e6a6 3556 dqb->dd_diskdq.d_type, s,
5a35bf2c 3557 (xfs_fileoff_t)qbno, i, dqid);
28518f77
DW
3558 error++;
3559 continue;
3560 }
cde0e6a6 3561 if ((dqb->dd_diskdq.d_type & XFS_DQTYPE_REC_MASK)
28518f77
DW
3562 != exp_flags) {
3563 if (scicb)
3564 dbprintf(_("wrong type %#x for %s dqblk "
3565 "%lld entry %d id %u\n"),
cde0e6a6 3566 dqb->dd_diskdq.d_type &
28518f77
DW
3567 XFS_DQTYPE_REC_MASK, s,
3568 (xfs_fileoff_t)qbno, i, dqid);
2bd0ea18
NS
3569 error++;
3570 continue;
3571 }
5e656dbb 3572 if (be32_to_cpu(dqb->dd_diskdq.d_id) != dqid) {
2bd0ea18 3573 if (scicb)
9ee7055c
AM
3574 dbprintf(_("bad id %u for %s dqblk %lld "
3575 "entry %d id %u\n"),
5e656dbb 3576 be32_to_cpu(dqb->dd_diskdq.d_id), s,
5a35bf2c 3577 (xfs_fileoff_t)qbno, i, dqid);
2bd0ea18
NS
3578 error++;
3579 continue;
3580 }
be8e601c
NS
3581 quota_add((qtype == IS_PROJECT_QUOTA) ? &dqid : NULL,
3582 (qtype == IS_GROUP_QUOTA) ? &dqid : NULL,
3583 (qtype == IS_USER_QUOTA) ? &dqid : NULL,
9b27bdbb 3584 1,
5e656dbb
BN
3585 be64_to_cpu(dqb->dd_diskdq.d_bcount),
3586 be64_to_cpu(dqb->dd_diskdq.d_icount),
3587 be64_to_cpu(dqb->dd_diskdq.d_rtbcount));
2bd0ea18
NS
3588 }
3589 pop_cur();
3590 }
3591}
3592
3593static void
3594process_rtbitmap(
3595 blkmap_t *blkmap)
3596{
2bd0ea18
NS
3597 int bit;
3598 int bitsperblock;
3599 xfs_fileoff_t bmbno;
3600 xfs_fsblock_t bno;
2e62ddc4 3601 xfs_rtxnum_t extno;
2bd0ea18
NS
3602 int len;
3603 int log;
3604 int offs;
3605 int prevbit;
5a35bf2c 3606 xfs_rfsblock_t rtbno;
2bd0ea18
NS
3607 int start_bmbno;
3608 int start_bit;
3609 int t;
3610 xfs_rtword_t *words;
3611
3612 bitsperblock = mp->m_sb.sb_blocksize * NBBY;
0457cd25
DW
3613 words = malloc(mp->m_blockwsize << XFS_WORDLOG);
3614 if (!words) {
3615 dbprintf(_("could not allocate rtwords buffer\n"));
3616 error++;
3617 return;
3618 }
2bd0ea18
NS
3619 bit = extno = prevbit = start_bmbno = start_bit = 0;
3620 bmbno = NULLFILEOFF;
61b7c5fd
DW
3621 while ((bmbno = blkmap_next_off(blkmap, bmbno, &t)) != NULLFILEOFF) {
3622 struct xfs_rtalloc_args args = {
3623 .mp = mp,
3624 };
0457cd25
DW
3625 xfs_rtword_t *incore = words;
3626 unsigned int i;
61b7c5fd 3627
2bd0ea18
NS
3628 bno = blkmap_get(blkmap, bmbno);
3629 if (bno == NULLFSBLOCK) {
3630 if (!sflag)
9ee7055c
AM
3631 dbprintf(_("block %lld for rtbitmap inode is "
3632 "missing\n"),
5a35bf2c 3633 (xfs_fileoff_t)bmbno);
2bd0ea18
NS
3634 error++;
3635 continue;
3636 }
3637 push_cur();
3638 set_cur(&typtab[TYP_RTBITMAP], XFS_FSB_TO_DADDR(mp, bno), blkbb,
3639 DB_RING_IGN, NULL);
61b7c5fd 3640 if (!iocur_top->bp) {
2bd0ea18 3641 if (!sflag)
9ee7055c
AM
3642 dbprintf(_("can't read block %lld for rtbitmap "
3643 "inode\n"),
5a35bf2c 3644 (xfs_fileoff_t)bmbno);
2bd0ea18 3645 error++;
d24c0a90 3646 pop_cur();
2bd0ea18
NS
3647 continue;
3648 }
61b7c5fd
DW
3649
3650 args.rbmbp = iocur_top->bp;
0457cd25
DW
3651 for (i = 0; i < mp->m_blockwsize; i++, incore++)
3652 *incore = libxfs_rtbitmap_getword(&args, i);
3653
2bd0ea18
NS
3654 for (bit = 0;
3655 bit < bitsperblock && extno < mp->m_sb.sb_rextents;
3656 bit++, extno++) {
a580302f 3657 if (xfs_isset(words, bit)) {
2bd0ea18
NS
3658 rtbno = extno * mp->m_sb.sb_rextsize;
3659 set_rdbmap(rtbno, mp->m_sb.sb_rextsize,
3660 DBM_RTFREE);
3661 frextents++;
3662 if (prevbit == 0) {
3663 start_bmbno = (int)bmbno;
3664 start_bit = bit;
3665 prevbit = 1;
3666 }
3667 } else if (prevbit == 1) {
3668 len = ((int)bmbno - start_bmbno) *
3669 bitsperblock + (bit - start_bit);
3670 log = XFS_RTBLOCKLOG(len);
ccffd2f9 3671 offs = xfs_rtsumoffs(mp, log, start_bmbno);
2bd0ea18
NS
3672 sumcompute[offs]++;
3673 prevbit = 0;
3674 }
3675 }
3676 pop_cur();
3677 if (extno == mp->m_sb.sb_rextents)
3678 break;
3679 }
3680 if (prevbit == 1) {
3681 len = ((int)bmbno - start_bmbno) * bitsperblock +
3682 (bit - start_bit);
3683 log = XFS_RTBLOCKLOG(len);
ccffd2f9 3684 offs = xfs_rtsumoffs(mp, log, start_bmbno);
2bd0ea18
NS
3685 sumcompute[offs]++;
3686 }
0457cd25 3687 free(words);
2bd0ea18
NS
3688}
3689
3690static void
3691process_rtsummary(
3692 blkmap_t *blkmap)
3693{
3694 xfs_fsblock_t bno;
3695 char *bytes;
3696 xfs_fileoff_t sumbno;
3697 int t;
3698
3699 sumbno = NULLFILEOFF;
d24c0a90 3700 while ((sumbno = blkmap_next_off(blkmap, sumbno, &t)) != NULLFILEOFF) {
2bd0ea18
NS
3701 bno = blkmap_get(blkmap, sumbno);
3702 if (bno == NULLFSBLOCK) {
3703 if (!sflag)
9ee7055c
AM
3704 dbprintf(_("block %lld for rtsummary inode is "
3705 "missing\n"),
5a35bf2c 3706 (xfs_fileoff_t)sumbno);
2bd0ea18
NS
3707 error++;
3708 continue;
3709 }
3710 push_cur();
3711 set_cur(&typtab[TYP_RTSUMMARY], XFS_FSB_TO_DADDR(mp, bno),
3712 blkbb, DB_RING_IGN, NULL);
3713 if ((bytes = iocur_top->data) == NULL) {
3714 if (!sflag)
9ee7055c
AM
3715 dbprintf(_("can't read block %lld for rtsummary "
3716 "inode\n"),
5a35bf2c 3717 (xfs_fileoff_t)sumbno);
2bd0ea18 3718 error++;
d24c0a90 3719 pop_cur();
2bd0ea18
NS
3720 continue;
3721 }
3722 memcpy((char *)sumfile + sumbno * mp->m_sb.sb_blocksize, bytes,
3723 mp->m_sb.sb_blocksize);
3724 pop_cur();
3725 }
3726}
3727
3728static xfs_ino_t
3729process_sf_dir_v2(
7328ea6e 3730 struct xfs_dinode *dip,
2bd0ea18
NS
3731 int *dot,
3732 int *dotdot,
3733 inodata_t *id)
3734{
3735 inodata_t *cid;
3736 int i;
3737 int i8;
3738 xfs_ino_t lino;
3739 int offset;
eb0cb950 3740 struct xfs_dir2_sf_hdr *sf;
2bd0ea18
NS
3741 xfs_dir2_sf_entry_t *sfe;
3742 int v;
3743
eb0cb950 3744 sf = (struct xfs_dir2_sf_hdr *)XFS_DFORK_DPTR(dip);
2bd0ea18
NS
3745 addlink_inode(id);
3746 v = verbose || id->ilist;
3747 if (v)
9ee7055c 3748 dbprintf(_("dir %lld entry . %lld\n"), id->ino, id->ino);
2bd0ea18 3749 (*dot)++;
eb0cb950 3750 sfe = xfs_dir2_sf_firstentry(sf);
58a1d356 3751 offset = mp->m_dir_geo->data_first_offset;
eb0cb950 3752 for (i = sf->count - 1, i8 = 0; i >= 0; i--) {
660836c9
CH
3753 if ((intptr_t)sfe +
3754 libxfs_dir2_sf_entsize(mp, sf, sfe->namelen) -
ee6cd73e 3755 (intptr_t)sf > be64_to_cpu(dip->di_size)) {
2bd0ea18 3756 if (!sflag)
9ee7055c 3757 dbprintf(_("dir %llu bad size in entry at %d\n"),
2bd0ea18
NS
3758 id->ino,
3759 (int)((char *)sfe - (char *)sf));
3760 error++;
3761 break;
3762 }
e96bd2d3 3763 lino = libxfs_dir2_sf_get_ino(mp, sf, sfe);
2bd0ea18
NS
3764 if (lino > XFS_DIR2_MAX_SHORT_INUM)
3765 i8++;
3766 cid = find_inode(lino, 1);
3767 if (cid == NULL) {
3768 if (!sflag)
9ee7055c
AM
3769 dbprintf(_("dir %lld entry %*.*s bad inode "
3770 "number %lld\n"),
2bd0ea18
NS
3771 id->ino, sfe->namelen, sfe->namelen,
3772 sfe->name, lino);
3773 error++;
3774 } else {
3775 addlink_inode(cid);
3776 if (!cid->parent)
3777 cid->parent = id;
3778 addname_inode(cid, (char *)sfe->name, sfe->namelen);
3779 }
3780 if (v)
9ee7055c 3781 dbprintf(_("dir %lld entry %*.*s offset %d %lld\n"),
2bd0ea18 3782 id->ino, sfe->namelen, sfe->namelen, sfe->name,
5e656dbb
BN
3783 xfs_dir2_sf_get_offset(sfe), lino);
3784 if (xfs_dir2_sf_get_offset(sfe) < offset) {
2bd0ea18 3785 if (!sflag)
9ee7055c 3786 dbprintf(_("dir %lld entry %*.*s bad offset %d\n"),
2bd0ea18 3787 id->ino, sfe->namelen, sfe->namelen,
5e656dbb 3788 sfe->name, xfs_dir2_sf_get_offset(sfe));
2bd0ea18
NS
3789 error++;
3790 }
3791 offset =
5e656dbb 3792 xfs_dir2_sf_get_offset(sfe) +
660836c9
CH
3793 libxfs_dir2_sf_entsize(mp, sf, sfe->namelen);
3794 sfe = libxfs_dir2_sf_nextentry(mp, sf, sfe);
2bd0ea18 3795 }
f8149110 3796 if (i < 0 && (intptr_t)sfe - (intptr_t)sf !=
56b2de80 3797 be64_to_cpu(dip->di_size)) {
2bd0ea18 3798 if (!sflag)
9ee7055c 3799 dbprintf(_("dir %llu size is %lld, should be %u\n"),
56b2de80 3800 id->ino, be64_to_cpu(dip->di_size),
2bd0ea18
NS
3801 (uint)((char *)sfe - (char *)sf));
3802 error++;
3803 }
eb0cb950 3804 if (offset + (sf->count + 2) * sizeof(xfs_dir2_leaf_entry_t) +
ff105f75 3805 sizeof(xfs_dir2_block_tail_t) > mp->m_dir_geo->blksize) {
2bd0ea18 3806 if (!sflag)
9ee7055c 3807 dbprintf(_("dir %llu offsets too high\n"), id->ino);
2bd0ea18
NS
3808 error++;
3809 }
8a7190bd 3810 lino = libxfs_dir2_sf_get_parent_ino(sf);
2bd0ea18
NS
3811 if (lino > XFS_DIR2_MAX_SHORT_INUM)
3812 i8++;
3813 cid = find_inode(lino, 1);
3814 if (cid)
3815 addlink_inode(cid);
3816 else {
3817 if (!sflag)
9ee7055c 3818 dbprintf(_("dir %lld entry .. bad inode number %lld\n"),
2bd0ea18
NS
3819 id->ino, lino);
3820 error++;
3821 }
3822 if (v)
9ee7055c 3823 dbprintf(_("dir %lld entry .. %lld\n"), id->ino, lino);
eb0cb950 3824 if (i8 != sf->i8count) {
2bd0ea18 3825 if (!sflag)
9ee7055c
AM
3826 dbprintf(_("dir %lld i8count mismatch is %d should be "
3827 "%d\n"),
eb0cb950 3828 id->ino, sf->i8count, i8);
2bd0ea18
NS
3829 error++;
3830 }
3831 (*dotdot)++;
3832 return cid ? lino : NULLFSINO;
3833}
3834
2bd0ea18
NS
3835
3836static void
3837quota_add(
be8e601c
NS
3838 xfs_dqid_t *prjid,
3839 xfs_dqid_t *grpid,
3840 xfs_dqid_t *usrid,
2bd0ea18
NS
3841 int dq,
3842 xfs_qcnt_t bc,
3843 xfs_qcnt_t ic,
3844 xfs_qcnt_t rc)
3845{
be8e601c
NS
3846 if (qudo && usrid != NULL)
3847 quota_add1(qudata, *usrid, dq, bc, ic, rc);
3848 if (qgdo && grpid != NULL)
3849 quota_add1(qgdata, *grpid, dq, bc, ic, rc);
3850 if (qpdo && prjid != NULL)
3851 quota_add1(qpdata, *prjid, dq, bc, ic, rc);
2bd0ea18
NS
3852}
3853
3854static void
3855quota_add1(
3856 qdata_t **qt,
3857 xfs_dqid_t id,
3858 int dq,
3859 xfs_qcnt_t bc,
3860 xfs_qcnt_t ic,
3861 xfs_qcnt_t rc)
3862{
3863 qdata_t *qe;
3864 int qh;
3865 qinfo_t *qi;
3866
be8e601c 3867 qh = (int)(id % QDATA_HASH_SIZE);
2bd0ea18
NS
3868 qe = qt[qh];
3869 while (qe) {
3870 if (qe->id == id) {
3871 qi = dq ? &qe->dq : &qe->count;
3872 qi->bc += bc;
3873 qi->ic += ic;
3874 qi->rc += rc;
3875 return;
3876 }
3877 qe = qe->next;
3878 }
3879 qe = xmalloc(sizeof(*qe));
3880 qe->id = id;
3881 qi = dq ? &qe->dq : &qe->count;
3882 qi->bc = bc;
3883 qi->ic = ic;
3884 qi->rc = rc;
3885 qi = dq ? &qe->count : &qe->dq;
3886 qi->bc = qi->ic = qi->rc = 0;
3887 qe->next = qt[qh];
3888 qt[qh] = qe;
3889}
3890
3891static void
3892quota_check(
3893 char *s,
3894 qdata_t **qt)
3895{
3896 int i;
3897 qdata_t *next;
3898 qdata_t *qp;
3899
3900 for (i = 0; i < QDATA_HASH_SIZE; i++) {
3901 qp = qt[i];
3902 while (qp) {
3903 next = qp->next;
3904 if (qp->count.bc != qp->dq.bc ||
3905 qp->count.ic != qp->dq.ic ||
3906 qp->count.rc != qp->dq.rc) {
3907 if (!sflag) {
9ee7055c 3908 dbprintf(_("%s quota id %u, have/exp"),
2bd0ea18
NS
3909 s, qp->id);
3910 if (qp->count.bc != qp->dq.bc)
9ee7055c 3911 dbprintf(_(" bc %lld/%lld"),
2bd0ea18
NS
3912 qp->dq.bc,
3913 qp->count.bc);
3914 if (qp->count.ic != qp->dq.ic)
9ee7055c 3915 dbprintf(_(" ic %lld/%lld"),
2bd0ea18
NS
3916 qp->dq.ic,
3917 qp->count.ic);
3918 if (qp->count.rc != qp->dq.rc)
9ee7055c 3919 dbprintf(_(" rc %lld/%lld"),
2bd0ea18
NS
3920 qp->dq.rc,
3921 qp->count.rc);
3922 dbprintf("\n");
3923 }
3924 error++;
3925 }
3926 xfree(qp);
3927 qp = next;
3928 }
3929 }
3930 xfree(qt);
3931}
3932
3933static void
3934quota_init(void)
3935{
3936 qudo = mp->m_sb.sb_uquotino != 0 &&
3937 mp->m_sb.sb_uquotino != NULLFSINO &&
b36eef04 3938 (mp->m_sb.sb_qflags & XFS_UQUOTA_ACCT) &&
2bd0ea18 3939 (mp->m_sb.sb_qflags & XFS_UQUOTA_CHKD);
b36eef04
NS
3940 qgdo = mp->m_sb.sb_gquotino != 0 &&
3941 mp->m_sb.sb_gquotino != NULLFSINO &&
3942 (mp->m_sb.sb_qflags & XFS_GQUOTA_ACCT) &&
342aef1e 3943 (mp->m_sb.sb_qflags & XFS_GQUOTA_CHKD);
0340d706
CS
3944 qpdo = mp->m_sb.sb_pquotino != 0 &&
3945 mp->m_sb.sb_pquotino != NULLFSINO &&
9b27bdbb 3946 (mp->m_sb.sb_qflags & XFS_PQUOTA_ACCT) &&
342aef1e 3947 (mp->m_sb.sb_qflags & XFS_PQUOTA_CHKD);
2bd0ea18
NS
3948 if (qudo)
3949 qudata = xcalloc(QDATA_HASH_SIZE, sizeof(qdata_t *));
b36eef04
NS
3950 if (qgdo)
3951 qgdata = xcalloc(QDATA_HASH_SIZE, sizeof(qdata_t *));
9b27bdbb
NS
3952 if (qpdo)
3953 qpdata = xcalloc(QDATA_HASH_SIZE, sizeof(qdata_t *));
2bd0ea18
NS
3954}
3955
3956static void
3957scan_ag(
3958 xfs_agnumber_t agno)
3959{
3960 xfs_agf_t *agf;
3961 xfs_agi_t *agi;
3962 int i;
3963 xfs_sb_t tsb;
5e656dbb 3964 xfs_sb_t *sb = &tsb;
2bd0ea18
NS
3965
3966 agffreeblks = agflongest = 0;
cdded3d8 3967 agfbtreeblks = -2;
2bd0ea18 3968 agicount = agifreecount = 0;
d24c0a90 3969 push_cur(); /* 1 pushed */
9440d84d
NS
3970 set_cur(&typtab[TYP_SB],
3971 XFS_AG_DADDR(mp, agno, XFS_SB_DADDR),
3972 XFS_FSS_TO_BB(mp, 1), DB_RING_IGN, NULL);
dfc130f3 3973
2bd0ea18 3974 if (!iocur_top->data) {
9ee7055c 3975 dbprintf(_("can't read superblock for ag %u\n"), agno);
2bd0ea18 3976 serious_error++;
d24c0a90 3977 goto pop1_out;
2bd0ea18 3978 }
dfc130f3 3979
5e656dbb 3980 libxfs_sb_from_disk(sb, iocur_top->data);
dfc130f3 3981
2bd0ea18
NS
3982 if (sb->sb_magicnum != XFS_SB_MAGIC) {
3983 if (!sflag)
9ee7055c 3984 dbprintf(_("bad sb magic # %#x in ag %u\n"),
2bd0ea18
NS
3985 sb->sb_magicnum, agno);
3986 error++;
3987 }
5e656dbb 3988 if (!xfs_sb_good_version(sb)) {
2bd0ea18 3989 if (!sflag)
9ee7055c 3990 dbprintf(_("bad sb version # %#x in ag %u\n"),
2bd0ea18
NS
3991 sb->sb_versionnum, agno);
3992 error++;
3993 sbver_err++;
3994 }
5e656dbb 3995 if (!lazycount && xfs_sb_version_haslazysbcount(sb)) {
cdded3d8
DC
3996 lazycount = 1;
3997 }
2bd0ea18
NS
3998 if (agno == 0 && sb->sb_inprogress != 0) {
3999 if (!sflag)
9ee7055c 4000 dbprintf(_("mkfs not completed successfully\n"));
2bd0ea18
NS
4001 error++;
4002 }
67b8ca98
DW
4003 if (xfs_sb_version_needsrepair(sb)) {
4004 if (!sflag)
4005 dbprintf(_("filesystem needs xfs_repair\n"));
4006 error++;
4007 }
2bd0ea18
NS
4008 set_dbmap(agno, XFS_SB_BLOCK(mp), 1, DBM_SB, agno, XFS_SB_BLOCK(mp));
4009 if (sb->sb_logstart && XFS_FSB_TO_AGNO(mp, sb->sb_logstart) == agno)
4010 set_dbmap(agno, XFS_FSB_TO_AGBNO(mp, sb->sb_logstart),
4011 sb->sb_logblocks, DBM_LOG, agno, XFS_SB_BLOCK(mp));
d24c0a90 4012 push_cur(); /* 2 pushed */
9440d84d
NS
4013 set_cur(&typtab[TYP_AGF],
4014 XFS_AG_DADDR(mp, agno, XFS_AGF_DADDR(mp)),
4015 XFS_FSS_TO_BB(mp, 1), DB_RING_IGN, NULL);
2bd0ea18 4016 if ((agf = iocur_top->data) == NULL) {
9ee7055c 4017 dbprintf(_("can't read agf block for ag %u\n"), agno);
2bd0ea18 4018 serious_error++;
d24c0a90 4019 goto pop2_out;
2bd0ea18 4020 }
5e656dbb 4021 if (be32_to_cpu(agf->agf_magicnum) != XFS_AGF_MAGIC) {
2bd0ea18 4022 if (!sflag)
9ee7055c 4023 dbprintf(_("bad agf magic # %#x in ag %u\n"),
5e656dbb 4024 be32_to_cpu(agf->agf_magicnum), agno);
2bd0ea18
NS
4025 error++;
4026 }
5e656dbb 4027 if (!XFS_AGF_GOOD_VERSION(be32_to_cpu(agf->agf_versionnum))) {
2bd0ea18 4028 if (!sflag)
9ee7055c 4029 dbprintf(_("bad agf version # %#x in ag %u\n"),
5e656dbb 4030 be32_to_cpu(agf->agf_versionnum), agno);
2bd0ea18
NS
4031 error++;
4032 }
4033 if (XFS_SB_BLOCK(mp) != XFS_AGF_BLOCK(mp))
4034 set_dbmap(agno, XFS_AGF_BLOCK(mp), 1, DBM_AGF, agno,
4035 XFS_SB_BLOCK(mp));
5e656dbb
BN
4036 if (sb->sb_agblocks > be32_to_cpu(agf->agf_length))
4037 set_dbmap(agno, be32_to_cpu(agf->agf_length),
4038 sb->sb_agblocks - be32_to_cpu(agf->agf_length),
2bd0ea18 4039 DBM_MISSING, agno, XFS_SB_BLOCK(mp));
d24c0a90 4040 push_cur(); /* 3 pushed */
9440d84d
NS
4041 set_cur(&typtab[TYP_AGI],
4042 XFS_AG_DADDR(mp, agno, XFS_AGI_DADDR(mp)),
4043 XFS_FSS_TO_BB(mp, 1), DB_RING_IGN, NULL);
2bd0ea18 4044 if ((agi = iocur_top->data) == NULL) {
9ee7055c 4045 dbprintf(_("can't read agi block for ag %u\n"), agno);
2bd0ea18 4046 serious_error++;
d24c0a90 4047 goto pop3_out;
2bd0ea18 4048 }
5e656dbb 4049 if (be32_to_cpu(agi->agi_magicnum) != XFS_AGI_MAGIC) {
2bd0ea18 4050 if (!sflag)
9ee7055c 4051 dbprintf(_("bad agi magic # %#x in ag %u\n"),
5e656dbb 4052 be32_to_cpu(agi->agi_magicnum), agno);
2bd0ea18
NS
4053 error++;
4054 }
5e656dbb 4055 if (!XFS_AGI_GOOD_VERSION(be32_to_cpu(agi->agi_versionnum))) {
2bd0ea18 4056 if (!sflag)
9ee7055c 4057 dbprintf(_("bad agi version # %#x in ag %u\n"),
5e656dbb 4058 be32_to_cpu(agi->agi_versionnum), agno);
2bd0ea18
NS
4059 error++;
4060 }
4061 if (XFS_SB_BLOCK(mp) != XFS_AGI_BLOCK(mp) &&
4062 XFS_AGF_BLOCK(mp) != XFS_AGI_BLOCK(mp))
4063 set_dbmap(agno, XFS_AGI_BLOCK(mp), 1, DBM_AGI, agno,
4064 XFS_SB_BLOCK(mp));
4065 scan_freelist(agf);
4066 fdblocks--;
4067 scan_sbtree(agf,
5e656dbb
BN
4068 be32_to_cpu(agf->agf_roots[XFS_BTNUM_BNO]),
4069 be32_to_cpu(agf->agf_levels[XFS_BTNUM_BNO]),
2bd0ea18
NS
4070 1, scanfunc_bno, TYP_BNOBT);
4071 fdblocks--;
4072 scan_sbtree(agf,
5e656dbb
BN
4073 be32_to_cpu(agf->agf_roots[XFS_BTNUM_CNT]),
4074 be32_to_cpu(agf->agf_levels[XFS_BTNUM_CNT]),
2bd0ea18 4075 1, scanfunc_cnt, TYP_CNTBT);
e3dcc17b
DW
4076 if (agf->agf_roots[XFS_BTNUM_RMAP]) {
4077 scan_sbtree(agf,
4078 be32_to_cpu(agf->agf_roots[XFS_BTNUM_RMAP]),
4079 be32_to_cpu(agf->agf_levels[XFS_BTNUM_RMAP]),
4080 1, scanfunc_rmap, TYP_RMAPBT);
4081 }
757ad8c7
DW
4082 if (agf->agf_refcount_root) {
4083 scan_sbtree(agf,
4084 be32_to_cpu(agf->agf_refcount_root),
4085 be32_to_cpu(agf->agf_refcount_level),
4086 1, scanfunc_refcnt, TYP_REFCBT);
4087 }
2bd0ea18 4088 scan_sbtree(agf,
5e656dbb
BN
4089 be32_to_cpu(agi->agi_root),
4090 be32_to_cpu(agi->agi_level),
2bd0ea18 4091 1, scanfunc_ino, TYP_INOBT);
e96864ff
DW
4092 if (agi->agi_free_root) {
4093 scan_sbtree(agf,
4094 be32_to_cpu(agi->agi_free_root),
4095 be32_to_cpu(agi->agi_free_level),
4096 1, scanfunc_fino, TYP_FINOBT);
4097 }
5e656dbb 4098 if (be32_to_cpu(agf->agf_freeblks) != agffreeblks) {
2bd0ea18 4099 if (!sflag)
9ee7055c 4100 dbprintf(_("agf_freeblks %u, counted %u in ag %u\n"),
5e656dbb 4101 be32_to_cpu(agf->agf_freeblks),
2bd0ea18
NS
4102 agffreeblks, agno);
4103 error++;
4104 }
5e656dbb 4105 if (be32_to_cpu(agf->agf_longest) != agflongest) {
2bd0ea18 4106 if (!sflag)
9ee7055c 4107 dbprintf(_("agf_longest %u, counted %u in ag %u\n"),
5e656dbb 4108 be32_to_cpu(agf->agf_longest),
2bd0ea18
NS
4109 agflongest, agno);
4110 error++;
4111 }
cdded3d8 4112 if (lazycount &&
5e656dbb 4113 be32_to_cpu(agf->agf_btreeblks) != agfbtreeblks) {
cdded3d8 4114 if (!sflag)
9ee7055c 4115 dbprintf(_("agf_btreeblks %u, counted %u in ag %u\n"),
5e656dbb 4116 be32_to_cpu(agf->agf_btreeblks),
cdded3d8
DC
4117 agfbtreeblks, agno);
4118 error++;
4119 }
4120 agf_aggr_freeblks += agffreeblks + agfbtreeblks;
5e656dbb 4121 if (be32_to_cpu(agi->agi_count) != agicount) {
2bd0ea18 4122 if (!sflag)
9ee7055c 4123 dbprintf(_("agi_count %u, counted %u in ag %u\n"),
5e656dbb 4124 be32_to_cpu(agi->agi_count),
2bd0ea18
NS
4125 agicount, agno);
4126 error++;
4127 }
5e656dbb 4128 if (be32_to_cpu(agi->agi_freecount) != agifreecount) {
2bd0ea18 4129 if (!sflag)
9ee7055c 4130 dbprintf(_("agi_freecount %u, counted %u in ag %u\n"),
5e656dbb 4131 be32_to_cpu(agi->agi_freecount),
2bd0ea18
NS
4132 agifreecount, agno);
4133 error++;
4134 }
4135 for (i = 0; i < XFS_AGI_UNLINKED_BUCKETS; i++) {
5e656dbb 4136 if (be32_to_cpu(agi->agi_unlinked[i]) != NULLAGINO) {
2bd0ea18 4137 if (!sflag) {
5e656dbb 4138 xfs_agino_t agino=be32_to_cpu(agi->agi_unlinked[i]);
9ee7055c
AM
4139 dbprintf(_("agi unlinked bucket %d is %u in ag "
4140 "%u (inode=%lld)\n"), i, agino, agno,
dfc130f3
RC
4141 XFS_AGINO_TO_INO(mp, agno, agino));
4142 }
2bd0ea18
NS
4143 error++;
4144 }
4145 }
d24c0a90 4146pop3_out:
2bd0ea18 4147 pop_cur();
d24c0a90 4148pop2_out:
2bd0ea18 4149 pop_cur();
d24c0a90 4150pop1_out:
2bd0ea18
NS
4151 pop_cur();
4152}
4153
581c24aa
DW
4154struct agfl_state {
4155 xfs_agnumber_t agno;
4156 unsigned int count;
4157};
4158
4159static int
4160scan_agfl(
4161 struct xfs_mount *mp,
4162 xfs_agblock_t bno,
4163 void *priv)
4164{
4165 struct agfl_state *as = priv;
4166
4167 set_dbmap(as->agno, bno, 1, DBM_FREELIST, as->agno, XFS_AGFL_BLOCK(mp));
4168 as->count++;
4169 return 0;
4170}
4171
2bd0ea18
NS
4172static void
4173scan_freelist(
581c24aa 4174 xfs_agf_t *agf)
2bd0ea18 4175{
581c24aa
DW
4176 xfs_agnumber_t seqno = be32_to_cpu(agf->agf_seqno);
4177 struct agfl_state state;
2bd0ea18
NS
4178
4179 if (XFS_SB_BLOCK(mp) != XFS_AGFL_BLOCK(mp) &&
4180 XFS_AGF_BLOCK(mp) != XFS_AGFL_BLOCK(mp) &&
4181 XFS_AGI_BLOCK(mp) != XFS_AGFL_BLOCK(mp))
4182 set_dbmap(seqno, XFS_AGFL_BLOCK(mp), 1, DBM_AGFL, seqno,
4183 XFS_SB_BLOCK(mp));
5e656dbb 4184 if (be32_to_cpu(agf->agf_flcount) == 0)
2bd0ea18
NS
4185 return;
4186 push_cur();
4187 set_cur(&typtab[TYP_AGFL],
9440d84d
NS
4188 XFS_AG_DADDR(mp, seqno, XFS_AGFL_DADDR(mp)),
4189 XFS_FSS_TO_BB(mp, 1), DB_RING_IGN, NULL);
581c24aa 4190 if (iocur_top->data == NULL) {
9ee7055c 4191 dbprintf(_("can't read agfl block for ag %u\n"), seqno);
2bd0ea18 4192 serious_error++;
d24c0a90 4193 pop_cur();
2bd0ea18
NS
4194 return;
4195 }
a529cc7f
ES
4196
4197 /* verify agf values before proceeding */
b8165508
DC
4198 if (be32_to_cpu(agf->agf_flfirst) >= libxfs_agfl_size(mp) ||
4199 be32_to_cpu(agf->agf_fllast) >= libxfs_agfl_size(mp)) {
a529cc7f 4200 dbprintf(_("agf %d freelist blocks bad, skipping "
581c24aa 4201 "freelist scan\n"), seqno);
a529cc7f
ES
4202 pop_cur();
4203 return;
4204 }
4205
30f8e916 4206 /* open coded xfs_buf_to_agfl_bno */
581c24aa
DW
4207 state.count = 0;
4208 state.agno = seqno;
4209 libxfs_agfl_walk(mp, agf, iocur_top->bp, scan_agfl, &state);
4210 if (state.count != be32_to_cpu(agf->agf_flcount)) {
2bd0ea18 4211 if (!sflag)
9ee7055c 4212 dbprintf(_("freeblk count %u != flcount %u in ag %u\n"),
581c24aa
DW
4213 state.count,
4214 be32_to_cpu(agf->agf_flcount),
4215 seqno);
2bd0ea18
NS
4216 error++;
4217 }
581c24aa
DW
4218 fdblocks += state.count;
4219 agf_aggr_freeblks += state.count;
2bd0ea18
NS
4220 pop_cur();
4221}
4222
4223static void
4224scan_lbtree(
4225 xfs_fsblock_t root,
4226 int nlevels,
4227 scan_lbtree_f_t func,
4228 dbm_t type,
4229 inodata_t *id,
5a35bf2c
DC
4230 xfs_rfsblock_t *totd,
4231 xfs_rfsblock_t *toti,
2bd0ea18
NS
4232 xfs_extnum_t *nex,
4233 blkmap_t **blkmapp,
4234 int isroot,
4235 typnm_t btype)
4236{
4237 push_cur();
4238 set_cur(&typtab[btype], XFS_FSB_TO_DADDR(mp, root), blkbb, DB_RING_IGN,
4239 NULL);
4240 if (iocur_top->data == NULL) {
4241 if (!sflag)
9ee7055c 4242 dbprintf(_("can't read btree block %u/%u\n"),
2bd0ea18
NS
4243 XFS_FSB_TO_AGNO(mp, root),
4244 XFS_FSB_TO_AGBNO(mp, root));
4245 error++;
d24c0a90 4246 pop_cur();
2bd0ea18
NS
4247 return;
4248 }
4249 (*func)(iocur_top->data, nlevels - 1, type, root, id, totd, toti, nex,
4250 blkmapp, isroot, btype);
4251 pop_cur();
4252}
4253
4254static void
4255scan_sbtree(
4256 xfs_agf_t *agf,
4257 xfs_agblock_t root,
4258 int nlevels,
4259 int isroot,
4260 scan_sbtree_f_t func,
4261 typnm_t btype)
4262{
5e656dbb 4263 xfs_agnumber_t seqno = be32_to_cpu(agf->agf_seqno);
2bd0ea18
NS
4264
4265 push_cur();
4266 set_cur(&typtab[btype],
4267 XFS_AGB_TO_DADDR(mp, seqno, root), blkbb, DB_RING_IGN, NULL);
4268 if (iocur_top->data == NULL) {
4269 if (!sflag)
9ee7055c 4270 dbprintf(_("can't read btree block %u/%u\n"), seqno, root);
2bd0ea18 4271 error++;
d24c0a90 4272 pop_cur();
2bd0ea18
NS
4273 return;
4274 }
4275 (*func)(iocur_top->data, nlevels - 1, agf, root, isroot);
4276 pop_cur();
4277}
4278
4279static void
4280scanfunc_bmap(
b3563c19 4281 struct xfs_btree_block *block,
2bd0ea18
NS
4282 int level,
4283 dbm_t type,
4284 xfs_fsblock_t bno,
4285 inodata_t *id,
5a35bf2c
DC
4286 xfs_rfsblock_t *totd,
4287 xfs_rfsblock_t *toti,
2bd0ea18
NS
4288 xfs_extnum_t *nex,
4289 blkmap_t **blkmapp,
4290 int isroot,
4291 typnm_t btype)
4292{
4293 xfs_agblock_t agbno;
4294 xfs_agnumber_t agno;
2bd0ea18
NS
4295 int i;
4296 xfs_bmbt_ptr_t *pp;
b9652a81 4297 xfs_bmbt_rec_t *rp;
2bd0ea18
NS
4298
4299 agno = XFS_FSB_TO_AGNO(mp, bno);
4300 agbno = XFS_FSB_TO_AGBNO(mp, bno);
e96864ff
DW
4301 if (be32_to_cpu(block->bb_magic) != XFS_BMAP_MAGIC &&
4302 be32_to_cpu(block->bb_magic) != XFS_BMAP_CRC_MAGIC) {
2bd0ea18 4303 if (!sflag || id->ilist || CHECK_BLIST(bno))
9ee7055c
AM
4304 dbprintf(_("bad magic # %#x in inode %lld bmbt block "
4305 "%u/%u\n"),
5e656dbb 4306 be32_to_cpu(block->bb_magic), id->ino, agno, agbno);
2bd0ea18
NS
4307 error++;
4308 }
5e656dbb 4309 if (be16_to_cpu(block->bb_level) != level) {
2bd0ea18 4310 if (!sflag || id->ilist || CHECK_BLIST(bno))
9ee7055c
AM
4311 dbprintf(_("expected level %d got %d in inode %lld bmbt "
4312 "block %u/%u\n"),
5e656dbb 4313 level, be16_to_cpu(block->bb_level), id->ino, agno, agbno);
2bd0ea18
NS
4314 error++;
4315 }
4316 set_dbmap(agno, agbno, 1, type, agno, agbno);
4317 set_inomap(agno, agbno, 1, id);
4318 (*toti)++;
4319 if (level == 0) {
5e656dbb
BN
4320 if (be16_to_cpu(block->bb_numrecs) > mp->m_bmap_dmxr[0] ||
4321 (isroot == 0 && be16_to_cpu(block->bb_numrecs) < mp->m_bmap_dmnr[0])) {
2bd0ea18 4322 if (!sflag || id->ilist || CHECK_BLIST(bno))
9ee7055c
AM
4323 dbprintf(_("bad btree nrecs (%u, min=%u, max=%u) "
4324 "in inode %lld bmap block %lld\n"),
5e656dbb 4325 be16_to_cpu(block->bb_numrecs), mp->m_bmap_dmnr[0],
2bd0ea18 4326 mp->m_bmap_dmxr[0], id->ino,
5a35bf2c 4327 (xfs_fsblock_t)bno);
2bd0ea18
NS
4328 error++;
4329 return;
4330 }
b9652a81 4331 rp = XFS_BMBT_REC_ADDR(mp, block, 1);
5e656dbb
BN
4332 *nex += be16_to_cpu(block->bb_numrecs);
4333 process_bmbt_reclist(rp, be16_to_cpu(block->bb_numrecs), type, id, totd,
2bd0ea18
NS
4334 blkmapp);
4335 return;
4336 }
5e656dbb
BN
4337 if (be16_to_cpu(block->bb_numrecs) > mp->m_bmap_dmxr[1] ||
4338 (isroot == 0 && be16_to_cpu(block->bb_numrecs) < mp->m_bmap_dmnr[1])) {
2bd0ea18 4339 if (!sflag || id->ilist || CHECK_BLIST(bno))
9ee7055c
AM
4340 dbprintf(_("bad btree nrecs (%u, min=%u, max=%u) in "
4341 "inode %lld bmap block %lld\n"),
5e656dbb 4342 be16_to_cpu(block->bb_numrecs), mp->m_bmap_dmnr[1],
5a35bf2c 4343 mp->m_bmap_dmxr[1], id->ino, (xfs_fsblock_t)bno);
2bd0ea18
NS
4344 error++;
4345 return;
4346 }
b3563c19 4347 pp = XFS_BMBT_PTR_ADDR(mp, block, 1, mp->m_bmap_dmxr[0]);
5e656dbb 4348 for (i = 0; i < be16_to_cpu(block->bb_numrecs); i++)
f8149110 4349 scan_lbtree(be64_to_cpu(pp[i]), level, scanfunc_bmap, type, id,
5e656dbb 4350 totd, toti, nex, blkmapp, 0, btype);
2bd0ea18
NS
4351}
4352
4353static void
4354scanfunc_bno(
b3563c19 4355 struct xfs_btree_block *block,
2bd0ea18
NS
4356 int level,
4357 xfs_agf_t *agf,
4358 xfs_agblock_t bno,
4359 int isroot)
4360{
2bd0ea18
NS
4361 int i;
4362 xfs_alloc_ptr_t *pp;
4363 xfs_alloc_rec_t *rp;
5e656dbb 4364 xfs_agnumber_t seqno = be32_to_cpu(agf->agf_seqno);
9ac8ea13 4365 xfs_agblock_t lastblock;
2bd0ea18 4366
e96864ff
DW
4367 if (be32_to_cpu(block->bb_magic) != XFS_ABTB_MAGIC &&
4368 be32_to_cpu(block->bb_magic) != XFS_ABTB_CRC_MAGIC) {
9ee7055c 4369 dbprintf(_("bad magic # %#x in btbno block %u/%u\n"),
5e656dbb 4370 be32_to_cpu(block->bb_magic), seqno, bno);
2bd0ea18
NS
4371 serious_error++;
4372 return;
4373 }
4374 fdblocks++;
cdded3d8 4375 agfbtreeblks++;
5e656dbb 4376 if (be16_to_cpu(block->bb_level) != level) {
2bd0ea18 4377 if (!sflag)
9ee7055c
AM
4378 dbprintf(_("expected level %d got %d in btbno block "
4379 "%u/%u\n"),
5e656dbb 4380 level, be16_to_cpu(block->bb_level), seqno, bno);
2bd0ea18
NS
4381 error++;
4382 }
4383 set_dbmap(seqno, bno, 1, DBM_BTBNO, seqno, bno);
4384 if (level == 0) {
5e656dbb
BN
4385 if (be16_to_cpu(block->bb_numrecs) > mp->m_alloc_mxr[0] ||
4386 (isroot == 0 && be16_to_cpu(block->bb_numrecs) < mp->m_alloc_mnr[0])) {
9ee7055c
AM
4387 dbprintf(_("bad btree nrecs (%u, min=%u, max=%u) in "
4388 "btbno block %u/%u\n"),
5e656dbb 4389 be16_to_cpu(block->bb_numrecs), mp->m_alloc_mnr[0],
2bd0ea18
NS
4390 mp->m_alloc_mxr[0], seqno, bno);
4391 serious_error++;
4392 return;
4393 }
b3563c19 4394 rp = XFS_ALLOC_REC_ADDR(mp, block, 1);
9ac8ea13 4395 lastblock = 0;
5e656dbb
BN
4396 for (i = 0; i < be16_to_cpu(block->bb_numrecs); i++) {
4397 set_dbmap(seqno, be32_to_cpu(rp[i].ar_startblock),
4398 be32_to_cpu(rp[i].ar_blockcount), DBM_FREE1,
2bd0ea18 4399 seqno, bno);
5e656dbb 4400 if (be32_to_cpu(rp[i].ar_startblock) <= lastblock) {
9ee7055c
AM
4401 dbprintf(_(
4402 "out-of-order bno btree record %d (%u %u) block %u/%u\n"),
5e656dbb
BN
4403 i, be32_to_cpu(rp[i].ar_startblock),
4404 be32_to_cpu(rp[i].ar_blockcount),
4405 be32_to_cpu(agf->agf_seqno), bno);
9ac8ea13
GO
4406 serious_error++;
4407 } else {
5e656dbb 4408 lastblock = be32_to_cpu(rp[i].ar_startblock);
9ac8ea13 4409 }
2bd0ea18
NS
4410 }
4411 return;
4412 }
5e656dbb
BN
4413 if (be16_to_cpu(block->bb_numrecs) > mp->m_alloc_mxr[1] ||
4414 (isroot == 0 && be16_to_cpu(block->bb_numrecs) < mp->m_alloc_mnr[1])) {
9ee7055c
AM
4415 dbprintf(_("bad btree nrecs (%u, min=%u, max=%u) in btbno block "
4416 "%u/%u\n"),
5e656dbb 4417 be16_to_cpu(block->bb_numrecs), mp->m_alloc_mnr[1],
2bd0ea18
NS
4418 mp->m_alloc_mxr[1], seqno, bno);
4419 serious_error++;
4420 return;
4421 }
b3563c19 4422 pp = XFS_ALLOC_PTR_ADDR(mp, block, 1, mp->m_alloc_mxr[1]);
5e656dbb
BN
4423 for (i = 0; i < be16_to_cpu(block->bb_numrecs); i++)
4424 scan_sbtree(agf, be32_to_cpu(pp[i]), level, 0, scanfunc_bno, TYP_BNOBT);
2bd0ea18
NS
4425}
4426
4427static void
4428scanfunc_cnt(
b3563c19 4429 struct xfs_btree_block *block,
2bd0ea18
NS
4430 int level,
4431 xfs_agf_t *agf,
4432 xfs_agblock_t bno,
4433 int isroot)
4434{
5e656dbb 4435 xfs_agnumber_t seqno = be32_to_cpu(agf->agf_seqno);
2bd0ea18
NS
4436 int i;
4437 xfs_alloc_ptr_t *pp;
4438 xfs_alloc_rec_t *rp;
9ac8ea13 4439 xfs_extlen_t lastcount;
2bd0ea18 4440
e96864ff
DW
4441 if (be32_to_cpu(block->bb_magic) != XFS_ABTC_MAGIC &&
4442 be32_to_cpu(block->bb_magic) != XFS_ABTC_CRC_MAGIC) {
9ee7055c 4443 dbprintf(_("bad magic # %#x in btcnt block %u/%u\n"),
5e656dbb 4444 be32_to_cpu(block->bb_magic), seqno, bno);
2bd0ea18
NS
4445 serious_error++;
4446 return;
4447 }
4448 fdblocks++;
cdded3d8 4449 agfbtreeblks++;
5e656dbb 4450 if (be16_to_cpu(block->bb_level) != level) {
2bd0ea18 4451 if (!sflag)
9ee7055c
AM
4452 dbprintf(_("expected level %d got %d in btcnt block "
4453 "%u/%u\n"),
5e656dbb 4454 level, be16_to_cpu(block->bb_level), seqno, bno);
2bd0ea18
NS
4455 error++;
4456 }
4457 set_dbmap(seqno, bno, 1, DBM_BTCNT, seqno, bno);
4458 if (level == 0) {
5e656dbb
BN
4459 if (be16_to_cpu(block->bb_numrecs) > mp->m_alloc_mxr[0] ||
4460 (isroot == 0 && be16_to_cpu(block->bb_numrecs) < mp->m_alloc_mnr[0])) {
9ee7055c
AM
4461 dbprintf(_("bad btree nrecs (%u, min=%u, max=%u) in "
4462 "btbno block %u/%u\n"),
5e656dbb 4463 be16_to_cpu(block->bb_numrecs), mp->m_alloc_mnr[0],
2bd0ea18
NS
4464 mp->m_alloc_mxr[0], seqno, bno);
4465 serious_error++;
4466 return;
4467 }
b3563c19 4468 rp = XFS_ALLOC_REC_ADDR(mp, block, 1);
9ac8ea13 4469 lastcount = 0;
5e656dbb
BN
4470 for (i = 0; i < be16_to_cpu(block->bb_numrecs); i++) {
4471 check_set_dbmap(seqno, be32_to_cpu(rp[i].ar_startblock),
4472 be32_to_cpu(rp[i].ar_blockcount), DBM_FREE1, DBM_FREE2,
2bd0ea18 4473 seqno, bno);
5e656dbb
BN
4474 fdblocks += be32_to_cpu(rp[i].ar_blockcount);
4475 agffreeblks += be32_to_cpu(rp[i].ar_blockcount);
4476 if (be32_to_cpu(rp[i].ar_blockcount) > agflongest)
4477 agflongest = be32_to_cpu(rp[i].ar_blockcount);
4478 if (be32_to_cpu(rp[i].ar_blockcount) < lastcount) {
9ee7055c
AM
4479 dbprintf(_(
4480 "out-of-order cnt btree record %d (%u %u) block %u/%u\n"),
5e656dbb
BN
4481 i, be32_to_cpu(rp[i].ar_startblock),
4482 be32_to_cpu(rp[i].ar_blockcount),
4483 be32_to_cpu(agf->agf_seqno), bno);
9ac8ea13 4484 } else {
5e656dbb 4485 lastcount = be32_to_cpu(rp[i].ar_blockcount);
9ac8ea13 4486 }
2bd0ea18
NS
4487 }
4488 return;
4489 }
5e656dbb
BN
4490 if (be16_to_cpu(block->bb_numrecs) > mp->m_alloc_mxr[1] ||
4491 (isroot == 0 && be16_to_cpu(block->bb_numrecs) < mp->m_alloc_mnr[1])) {
9ee7055c
AM
4492 dbprintf(_("bad btree nrecs (%u, min=%u, max=%u) in btbno block "
4493 "%u/%u\n"),
5e656dbb 4494 be16_to_cpu(block->bb_numrecs), mp->m_alloc_mnr[1],
2bd0ea18
NS
4495 mp->m_alloc_mxr[1], seqno, bno);
4496 serious_error++;
4497 return;
4498 }
b3563c19 4499 pp = XFS_ALLOC_PTR_ADDR(mp, block, 1, mp->m_alloc_mxr[1]);
5e656dbb
BN
4500 for (i = 0; i < be16_to_cpu(block->bb_numrecs); i++)
4501 scan_sbtree(agf, be32_to_cpu(pp[i]), level, 0, scanfunc_cnt, TYP_CNTBT);
2bd0ea18
NS
4502}
4503
4504static void
4505scanfunc_ino(
b3563c19 4506 struct xfs_btree_block *block,
2bd0ea18
NS
4507 int level,
4508 xfs_agf_t *agf,
4509 xfs_agblock_t bno,
4510 int isroot)
4511{
4512 xfs_agino_t agino;
5e656dbb 4513 xfs_agnumber_t seqno = be32_to_cpu(agf->agf_seqno);
2bd0ea18
NS
4514 int i;
4515 int isfree;
4516 int j;
ea8a48fa 4517 int freecount;
2bd0ea18
NS
4518 int nfree;
4519 int off;
4520 xfs_inobt_ptr_t *pp;
4521 xfs_inobt_rec_t *rp;
ea8a48fa
BF
4522 xfs_agblock_t agbno;
4523 xfs_agblock_t end_agbno;
4524 struct xfs_dinode *dip;
4525 int blks_per_buf;
4526 int inodes_per_buf;
4527 int ioff;
e7fd2b6f 4528 struct xfs_ino_geometry *igeo = M_IGEO(mp);
ea8a48fa 4529
2660e653 4530 if (xfs_has_sparseinodes(mp))
e7fd2b6f 4531 blks_per_buf = igeo->blocks_per_cluster;
ea8a48fa 4532 else
e7fd2b6f 4533 blks_per_buf = igeo->ialloc_blks;
7516da71 4534 inodes_per_buf = min(XFS_FSB_TO_INO(mp, blks_per_buf),
ea8a48fa 4535 XFS_INODES_PER_CHUNK);
2bd0ea18 4536
e96864ff
DW
4537 if (be32_to_cpu(block->bb_magic) != XFS_IBT_MAGIC &&
4538 be32_to_cpu(block->bb_magic) != XFS_IBT_CRC_MAGIC) {
9ee7055c 4539 dbprintf(_("bad magic # %#x in inobt block %u/%u\n"),
5e656dbb 4540 be32_to_cpu(block->bb_magic), seqno, bno);
2bd0ea18
NS
4541 serious_error++;
4542 return;
4543 }
5e656dbb 4544 if (be16_to_cpu(block->bb_level) != level) {
2bd0ea18 4545 if (!sflag)
9ee7055c
AM
4546 dbprintf(_("expected level %d got %d in inobt block "
4547 "%u/%u\n"),
5e656dbb 4548 level, be16_to_cpu(block->bb_level), seqno, bno);
2bd0ea18
NS
4549 error++;
4550 }
4551 set_dbmap(seqno, bno, 1, DBM_BTINO, seqno, bno);
4552 if (level == 0) {
e7fd2b6f
DW
4553 if (be16_to_cpu(block->bb_numrecs) > igeo->inobt_mxr[0] ||
4554 (isroot == 0 && be16_to_cpu(block->bb_numrecs) < igeo->inobt_mnr[0])) {
9ee7055c
AM
4555 dbprintf(_("bad btree nrecs (%u, min=%u, max=%u) in "
4556 "inobt block %u/%u\n"),
e7fd2b6f
DW
4557 be16_to_cpu(block->bb_numrecs), igeo->inobt_mnr[0],
4558 igeo->inobt_mxr[0], seqno, bno);
2bd0ea18
NS
4559 serious_error++;
4560 return;
4561 }
b3563c19 4562 rp = XFS_INOBT_REC_ADDR(mp, block, 1);
5e656dbb
BN
4563 for (i = 0; i < be16_to_cpu(block->bb_numrecs); i++) {
4564 agino = be32_to_cpu(rp[i].ir_startino);
ea8a48fa
BF
4565 agbno = XFS_AGINO_TO_AGBNO(mp, agino);
4566 off = XFS_AGINO_TO_OFFSET(mp, agino);
e7fd2b6f 4567 end_agbno = agbno + igeo->ialloc_blks;
09c93e56
BF
4568 if (off == 0) {
4569 if ((sbversion & XFS_SB_VERSION_ALIGNBIT) &&
4570 mp->m_sb.sb_inoalignmt &&
4571 (XFS_INO_TO_AGBNO(mp, agino) %
4572 mp->m_sb.sb_inoalignmt))
2bd0ea18 4573 sbversion &= ~XFS_SB_VERSION_ALIGNBIT;
2bd0ea18 4574 }
ea8a48fa 4575
09c93e56 4576 push_cur();
ea8a48fa
BF
4577
4578 ioff = 0;
4579 nfree = 0;
4580 while (agbno < end_agbno &&
4581 ioff < XFS_INODES_PER_CHUNK) {
4582 if (xfs_inobt_is_sparse_disk(&rp[i], ioff))
4583 goto next_buf;
4584
4585 if (off < XFS_INODES_PER_CHUNK)
4586 set_dbmap(seqno, agbno, blks_per_buf,
4587 DBM_INODE, seqno, bno);
4588
4589 icount += inodes_per_buf;
4590 agicount += inodes_per_buf;
4591
4592 set_cur(&typtab[TYP_INODE],
4593 XFS_AGB_TO_DADDR(mp, seqno, agbno),
4594 XFS_FSB_TO_BB(mp, blks_per_buf),
4595 DB_RING_IGN, NULL);
4596 if (iocur_top->data == NULL) {
4597 if (!sflag)
4598 dbprintf(_("can't read inode block "
4599 "%u/%u\n"), seqno,
4600 agbno);
4601 error++;
4602 goto next_buf;
4603 }
4604
4605 for (j = 0; j < inodes_per_buf; j++) {
4606 isfree = XFS_INOBT_IS_FREE_DISK(&rp[i], ioff + j);
4607 if (isfree)
4608 nfree++;
7328ea6e 4609 dip = (struct xfs_dinode *)((char *)iocur_top->data +
ea8a48fa
BF
4610 ((off + j) << mp->m_sb.sb_inodelog));
4611 process_inode(agf, agino + ioff + j, dip, isfree);
4612 }
4613
4614next_buf:
4615 agbno += blks_per_buf;
4616 ioff += inodes_per_buf;
09c93e56 4617 }
ea8a48fa 4618
2660e653 4619 if (xfs_has_sparseinodes(mp))
ea8a48fa
BF
4620 freecount = rp[i].ir_u.sp.ir_freecount;
4621 else
4622 freecount = be32_to_cpu(rp[i].ir_u.f.ir_freecount);
4623
4624 ifree += freecount;
4625 agifreecount += freecount;
4626
4627 if (nfree != freecount) {
2bd0ea18 4628 if (!sflag)
9ee7055c 4629 dbprintf(_("ir_freecount/free mismatch, "
2bd0ea18 4630 "inode chunk %u/%u, freecount "
9ee7055c 4631 "%d nfree %d\n"),
ea8a48fa 4632 seqno, agino, freecount, nfree);
2bd0ea18
NS
4633 error++;
4634 }
09c93e56 4635 pop_cur();
2bd0ea18
NS
4636 }
4637 return;
4638 }
e7fd2b6f
DW
4639 if (be16_to_cpu(block->bb_numrecs) > igeo->inobt_mxr[1] ||
4640 (isroot == 0 && be16_to_cpu(block->bb_numrecs) < igeo->inobt_mnr[1])) {
9ee7055c
AM
4641 dbprintf(_("bad btree nrecs (%u, min=%u, max=%u) in inobt block "
4642 "%u/%u\n"),
e7fd2b6f
DW
4643 be16_to_cpu(block->bb_numrecs), igeo->inobt_mnr[1],
4644 igeo->inobt_mxr[1], seqno, bno);
2bd0ea18
NS
4645 serious_error++;
4646 return;
4647 }
e7fd2b6f 4648 pp = XFS_INOBT_PTR_ADDR(mp, block, 1, igeo->inobt_mxr[1]);
5e656dbb
BN
4649 for (i = 0; i < be16_to_cpu(block->bb_numrecs); i++)
4650 scan_sbtree(agf, be32_to_cpu(pp[i]), level, 0, scanfunc_ino, TYP_INOBT);
2bd0ea18
NS
4651}
4652
e96864ff
DW
4653static void
4654scanfunc_fino(
4655 struct xfs_btree_block *block,
4656 int level,
4657 struct xfs_agf *agf,
4658 xfs_agblock_t bno,
4659 int isroot)
4660{
4661 xfs_agino_t agino;
4662 xfs_agnumber_t seqno = be32_to_cpu(agf->agf_seqno);
4663 int i;
4664 int off;
4665 xfs_inobt_ptr_t *pp;
4666 struct xfs_inobt_rec *rp;
ea8a48fa
BF
4667 xfs_agblock_t agbno;
4668 xfs_agblock_t end_agbno;
4669 int blks_per_buf;
4670 int inodes_per_buf;
4671 int ioff;
e7fd2b6f 4672 struct xfs_ino_geometry *igeo = M_IGEO(mp);
ea8a48fa 4673
2660e653 4674 if (xfs_has_sparseinodes(mp))
e7fd2b6f 4675 blks_per_buf = igeo->blocks_per_cluster;
ea8a48fa 4676 else
e7fd2b6f 4677 blks_per_buf = igeo->ialloc_blks;
7516da71 4678 inodes_per_buf = min(XFS_FSB_TO_INO(mp, blks_per_buf),
ea8a48fa 4679 XFS_INODES_PER_CHUNK);
e96864ff
DW
4680
4681 if (be32_to_cpu(block->bb_magic) != XFS_FIBT_MAGIC &&
4682 be32_to_cpu(block->bb_magic) != XFS_FIBT_CRC_MAGIC) {
4683 dbprintf(_("bad magic # %#x in finobt block %u/%u\n"),
4684 be32_to_cpu(block->bb_magic), seqno, bno);
4685 serious_error++;
4686 return;
4687 }
4688 if (be16_to_cpu(block->bb_level) != level) {
4689 if (!sflag)
4690 dbprintf(_("expected level %d got %d in finobt block "
4691 "%u/%u\n"),
4692 level, be16_to_cpu(block->bb_level), seqno, bno);
4693 error++;
4694 }
4695 set_dbmap(seqno, bno, 1, DBM_BTFINO, seqno, bno);
4696 if (level == 0) {
e7fd2b6f
DW
4697 if (be16_to_cpu(block->bb_numrecs) > igeo->inobt_mxr[0] ||
4698 (isroot == 0 && be16_to_cpu(block->bb_numrecs) < igeo->inobt_mnr[0])) {
e96864ff
DW
4699 dbprintf(_("bad btree nrecs (%u, min=%u, max=%u) in "
4700 "finobt block %u/%u\n"),
e7fd2b6f
DW
4701 be16_to_cpu(block->bb_numrecs), igeo->inobt_mnr[0],
4702 igeo->inobt_mxr[0], seqno, bno);
e96864ff
DW
4703 serious_error++;
4704 return;
4705 }
4706 rp = XFS_INOBT_REC_ADDR(mp, block, 1);
4707 for (i = 0; i < be16_to_cpu(block->bb_numrecs); i++) {
4708 agino = be32_to_cpu(rp[i].ir_startino);
ea8a48fa
BF
4709 agbno = XFS_AGINO_TO_AGBNO(mp, agino);
4710 off = XFS_AGINO_TO_OFFSET(mp, agino);
e7fd2b6f 4711 end_agbno = agbno + igeo->ialloc_blks;
09c93e56
BF
4712 if (off == 0) {
4713 if ((sbversion & XFS_SB_VERSION_ALIGNBIT) &&
4714 mp->m_sb.sb_inoalignmt &&
4715 (XFS_INO_TO_AGBNO(mp, agino) %
4716 mp->m_sb.sb_inoalignmt))
e96864ff 4717 sbversion &= ~XFS_SB_VERSION_ALIGNBIT;
e96864ff 4718 }
ea8a48fa
BF
4719
4720 ioff = 0;
4721 while (agbno < end_agbno &&
4722 ioff < XFS_INODES_PER_CHUNK) {
4723 if (xfs_inobt_is_sparse_disk(&rp[i], ioff))
4724 goto next_buf;
4725
4726 check_set_dbmap(seqno, agbno,
68d16907 4727 (xfs_extlen_t)max(1,
ea8a48fa
BF
4728 inodes_per_buf >>
4729 mp->m_sb.sb_inopblog),
4730 DBM_INODE, DBM_INODE, seqno, bno);
4731
4732next_buf:
4733 agbno += blks_per_buf;
4734 ioff += inodes_per_buf;
4735 }
4736
e96864ff
DW
4737 }
4738 return;
4739 }
e7fd2b6f
DW
4740 if (be16_to_cpu(block->bb_numrecs) > igeo->inobt_mxr[1] ||
4741 (isroot == 0 && be16_to_cpu(block->bb_numrecs) < igeo->inobt_mnr[1])) {
e96864ff
DW
4742 dbprintf(_("bad btree nrecs (%u, min=%u, max=%u) in finobt block "
4743 "%u/%u\n"),
e7fd2b6f
DW
4744 be16_to_cpu(block->bb_numrecs), igeo->inobt_mnr[1],
4745 igeo->inobt_mxr[1], seqno, bno);
e96864ff
DW
4746 serious_error++;
4747 return;
4748 }
e7fd2b6f 4749 pp = XFS_INOBT_PTR_ADDR(mp, block, 1, igeo->inobt_mxr[1]);
e96864ff
DW
4750 for (i = 0; i < be16_to_cpu(block->bb_numrecs); i++)
4751 scan_sbtree(agf, be32_to_cpu(pp[i]), level, 0, scanfunc_fino, TYP_FINOBT);
4752}
4753
e3dcc17b
DW
4754static void
4755scanfunc_rmap(
4756 struct xfs_btree_block *block,
4757 int level,
4758 struct xfs_agf *agf,
4759 xfs_agblock_t bno,
4760 int isroot)
4761{
4762 xfs_agnumber_t seqno = be32_to_cpu(agf->agf_seqno);
4763 int i;
4764 xfs_rmap_ptr_t *pp;
4765 struct xfs_rmap_rec *rp;
4766 xfs_agblock_t lastblock;
4767
4768 if (be32_to_cpu(block->bb_magic) != XFS_RMAP_CRC_MAGIC) {
4769 dbprintf(_("bad magic # %#x in rmapbt block %u/%u\n"),
4770 be32_to_cpu(block->bb_magic), seqno, bno);
4771 serious_error++;
4772 return;
4773 }
4774 if (be16_to_cpu(block->bb_level) != level) {
4775 if (!sflag)
4776 dbprintf(_("expected level %d got %d in rmapbt block "
4777 "%u/%u\n"),
4778 level, be16_to_cpu(block->bb_level), seqno, bno);
4779 error++;
4780 }
4781 if (!isroot) {
4782 fdblocks++;
4783 agfbtreeblks++;
4784 }
4785 set_dbmap(seqno, bno, 1, DBM_BTRMAP, seqno, bno);
4786 if (level == 0) {
4787 if (be16_to_cpu(block->bb_numrecs) > mp->m_rmap_mxr[0] ||
4788 (isroot == 0 && be16_to_cpu(block->bb_numrecs) < mp->m_rmap_mnr[0])) {
4789 dbprintf(_("bad btree nrecs (%u, min=%u, max=%u) in "
4790 "rmapbt block %u/%u\n"),
4791 be16_to_cpu(block->bb_numrecs), mp->m_rmap_mnr[0],
4792 mp->m_rmap_mxr[0], seqno, bno);
4793 serious_error++;
4794 return;
4795 }
4796 rp = XFS_RMAP_REC_ADDR(block, 1);
4797 lastblock = 0;
4798 for (i = 0; i < be16_to_cpu(block->bb_numrecs); i++) {
4799 if (be32_to_cpu(rp[i].rm_startblock) < lastblock) {
4800 dbprintf(_(
4801 "out-of-order rmap btree record %d (%u %u) block %u/%u\n"),
4802 i, be32_to_cpu(rp[i].rm_startblock),
4803 be32_to_cpu(rp[i].rm_startblock),
4804 be32_to_cpu(agf->agf_seqno), bno);
4805 } else {
4806 lastblock = be32_to_cpu(rp[i].rm_startblock);
4807 }
4808 }
4809 return;
4810 }
4811 if (be16_to_cpu(block->bb_numrecs) > mp->m_rmap_mxr[1] ||
4812 (isroot == 0 && be16_to_cpu(block->bb_numrecs) < mp->m_rmap_mnr[1])) {
4813 dbprintf(_("bad btree nrecs (%u, min=%u, max=%u) in rmapbt "
4814 "block %u/%u\n"),
4815 be16_to_cpu(block->bb_numrecs), mp->m_rmap_mnr[1],
4816 mp->m_rmap_mxr[1], seqno, bno);
4817 serious_error++;
4818 return;
4819 }
4820 pp = XFS_RMAP_PTR_ADDR(block, 1, mp->m_rmap_mxr[1]);
4821 for (i = 0; i < be16_to_cpu(block->bb_numrecs); i++)
4822 scan_sbtree(agf, be32_to_cpu(pp[i]), level, 0, scanfunc_rmap,
4823 TYP_RMAPBT);
4824}
4825
757ad8c7
DW
4826static void
4827scanfunc_refcnt(
4828 struct xfs_btree_block *block,
4829 int level,
4830 struct xfs_agf *agf,
4831 xfs_agblock_t bno,
4832 int isroot)
4833{
4834 xfs_agnumber_t seqno = be32_to_cpu(agf->agf_seqno);
4835 int i;
4836 xfs_refcount_ptr_t *pp;
4837 struct xfs_refcount_rec *rp;
4838 xfs_agblock_t lastblock;
4839
4840 if (be32_to_cpu(block->bb_magic) != XFS_REFC_CRC_MAGIC) {
4841 dbprintf(_("bad magic # %#x in refcntbt block %u/%u\n"),
4842 be32_to_cpu(block->bb_magic), seqno, bno);
4843 serious_error++;
4844 return;
4845 }
4846 if (be16_to_cpu(block->bb_level) != level) {
4847 if (!sflag)
4848 dbprintf(_("expected level %d got %d in refcntbt block "
4849 "%u/%u\n"),
4850 level, be16_to_cpu(block->bb_level), seqno, bno);
4851 error++;
4852 }
4853 set_dbmap(seqno, bno, 1, DBM_BTREFC, seqno, bno);
4854 if (level == 0) {
4855 if (be16_to_cpu(block->bb_numrecs) > mp->m_refc_mxr[0] ||
4856 (isroot == 0 && be16_to_cpu(block->bb_numrecs) < mp->m_refc_mnr[0])) {
4857 dbprintf(_("bad btree nrecs (%u, min=%u, max=%u) in "
4858 "refcntbt block %u/%u\n"),
4859 be16_to_cpu(block->bb_numrecs), mp->m_refc_mnr[0],
4860 mp->m_refc_mxr[0], seqno, bno);
4861 serious_error++;
4862 return;
4863 }
4864 rp = XFS_REFCOUNT_REC_ADDR(block, 1);
4865 lastblock = 0;
4866 for (i = 0; i < be16_to_cpu(block->bb_numrecs); i++) {
13ef9674 4867 if (be32_to_cpu(rp[i].rc_refcount) == 1) {
b638281f
DW
4868 xfs_agblock_t agbno;
4869 char *msg;
4870
4871 agbno = be32_to_cpu(rp[i].rc_startblock);
2b9d6f15
DW
4872 if (agbno & XFS_REFC_COWFLAG) {
4873 agbno &= ~XFS_REFC_COWFLAG;
b638281f
DW
4874 msg = _(
4875 "leftover CoW extent (%u/%u) len %u\n");
4876 } else {
4877 msg = _(
4878 "leftover CoW extent at unexpected address (%u/%u) len %u\n");
4879 }
4880 dbprintf(msg,
13ef9674 4881 seqno,
b638281f 4882 agbno,
13ef9674
DW
4883 be32_to_cpu(rp[i].rc_blockcount));
4884 set_dbmap(seqno,
b638281f 4885 agbno,
13ef9674
DW
4886 be32_to_cpu(rp[i].rc_blockcount),
4887 DBM_COWDATA, seqno, bno);
4888 } else {
4889 set_dbmap(seqno,
4890 be32_to_cpu(rp[i].rc_startblock),
4891 be32_to_cpu(rp[i].rc_blockcount),
4892 DBM_RLDATA, seqno, bno);
4893 }
757ad8c7
DW
4894 if (be32_to_cpu(rp[i].rc_startblock) < lastblock) {
4895 dbprintf(_(
4896 "out-of-order refcnt btree record %d (%u %u) block %u/%u\n"),
4897 i, be32_to_cpu(rp[i].rc_startblock),
4898 be32_to_cpu(rp[i].rc_startblock),
4899 be32_to_cpu(agf->agf_seqno), bno);
4900 } else {
4901 lastblock = be32_to_cpu(rp[i].rc_startblock) +
4902 be32_to_cpu(rp[i].rc_blockcount);
4903 }
4904 }
4905 return;
4906 }
4907 if (be16_to_cpu(block->bb_numrecs) > mp->m_refc_mxr[1] ||
4908 (isroot == 0 && be16_to_cpu(block->bb_numrecs) < mp->m_refc_mnr[1])) {
4909 dbprintf(_("bad btree nrecs (%u, min=%u, max=%u) in refcntbt "
4910 "block %u/%u\n"),
4911 be16_to_cpu(block->bb_numrecs), mp->m_refc_mnr[1],
4912 mp->m_refc_mxr[1], seqno, bno);
4913 serious_error++;
4914 return;
4915 }
4916 pp = XFS_REFCOUNT_PTR_ADDR(block, 1, mp->m_refc_mxr[1]);
4917 for (i = 0; i < be16_to_cpu(block->bb_numrecs); i++)
4918 scan_sbtree(agf, be32_to_cpu(pp[i]), level, 0, scanfunc_refcnt,
4919 TYP_REFCBT);
4920}
4921
2bd0ea18
NS
4922static void
4923set_dbmap(
4924 xfs_agnumber_t agno,
4925 xfs_agblock_t agbno,
4926 xfs_extlen_t len,
4927 dbm_t type,
4928 xfs_agnumber_t c_agno,
4929 xfs_agblock_t c_agbno)
4930{
4931 check_set_dbmap(agno, agbno, len, DBM_UNKNOWN, type, c_agno, c_agbno);
4932}
4933
4934static void
4935set_inomap(
4936 xfs_agnumber_t agno,
4937 xfs_agblock_t agbno,
4938 xfs_extlen_t len,
4939 inodata_t *id)
4940{
4941 xfs_extlen_t i;
4942 inodata_t **idp;
4943 int mayprint;
4944
4945 if (!check_inomap(agno, agbno, len, id->ino))
4946 return;
4947 mayprint = verbose | id->ilist | blist_size;
4948 for (i = 0, idp = &inomap[agno][agbno]; i < len; i++, idp++) {
4949 *idp = id;
4950 if (mayprint &&
4951 (verbose || id->ilist || CHECK_BLISTA(agno, agbno + i)))
9ee7055c 4952 dbprintf(_("setting inode to %lld for block %u/%u\n"),
2bd0ea18
NS
4953 id->ino, agno, agbno + i);
4954 }
4955}
4956
4957static void
4958set_rdbmap(
5a35bf2c 4959 xfs_rfsblock_t bno,
2bd0ea18
NS
4960 xfs_extlen_t len,
4961 dbm_t type)
4962{
4963 check_set_rdbmap(bno, len, DBM_UNKNOWN, type);
4964}
4965
4966static void
4967set_rinomap(
5a35bf2c 4968 xfs_rfsblock_t bno,
2bd0ea18
NS
4969 xfs_extlen_t len,
4970 inodata_t *id)
4971{
4972 xfs_extlen_t i;
4973 inodata_t **idp;
4974 int mayprint;
4975
4976 if (!check_rinomap(bno, len, id->ino))
4977 return;
4978 mayprint = verbose | id->ilist | blist_size;
4979 for (i = 0, idp = &inomap[mp->m_sb.sb_agcount][bno];
4980 i < len;
4981 i++, idp++) {
4982 *idp = id;
4983 if (mayprint && (verbose || id->ilist || CHECK_BLIST(bno + i)))
9ee7055c 4984 dbprintf(_("setting inode to %lld for rtblock %llu\n"),
2bd0ea18
NS
4985 id->ino, bno + i);
4986 }
4987}
4988
4989static void
4990setlink_inode(
4991 inodata_t *id,
4992 nlink_t nlink,
4993 int isdir,
4994 int security)
4995{
4996 id->link_set = nlink;
4997 id->isdir = isdir;
4998 id->security = security;
4999 if (verbose || id->ilist)
9ee7055c 5000 dbprintf(_("inode %lld nlink %u %s dir\n"), id->ino, nlink,
2bd0ea18
NS
5001 isdir ? "is" : "not");
5002}