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