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