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