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