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