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