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