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