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