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