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