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