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