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