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