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