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