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