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