]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blob - db/check.c
xfsprogs: sync code to current kernel code
[thirdparty/xfsprogs-dev.git] / db / check.c
1 /*
2 * Copyright (c) 2000-2002,2005 Silicon Graphics, Inc.
3 * All Rights Reserved.
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
7 * published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope that it would be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write the Free Software Foundation,
16 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17 */
18
19 #include <xfs/libxfs.h>
20 #include <math.h>
21 #include <sys/time.h>
22 #include "bmap.h"
23 #include "check.h"
24 #include "command.h"
25 #include "io.h"
26 #include "type.h"
27 #include "fprint.h"
28 #include "faddr.h"
29 #include "field.h"
30 #include "sb.h"
31 #include "output.h"
32 #include "init.h"
33 #include "malloc.h"
34 #include "dir2.h"
35
36 typedef enum {
37 IS_USER_QUOTA, IS_PROJECT_QUOTA, IS_GROUP_QUOTA,
38 } qtype_t;
39
40 typedef enum {
41 DBM_UNKNOWN, DBM_AGF, DBM_AGFL, DBM_AGI,
42 DBM_ATTR, DBM_BTBMAPA, DBM_BTBMAPD, DBM_BTBNO,
43 DBM_BTCNT, DBM_BTINO, DBM_DATA, DBM_DIR,
44 DBM_FREE1, DBM_FREE2, DBM_FREELIST, DBM_INODE,
45 DBM_LOG, DBM_MISSING, DBM_QUOTA, DBM_RTBITMAP,
46 DBM_RTDATA, DBM_RTFREE, DBM_RTSUM, DBM_SB,
47 DBM_SYMLINK,
48 DBM_NDBM
49 } dbm_t;
50
51 typedef struct inodata {
52 struct inodata *next;
53 nlink_t link_set;
54 nlink_t link_add;
55 char isdir;
56 char security;
57 char ilist;
58 xfs_ino_t ino;
59 struct inodata *parent;
60 char *name;
61 } inodata_t;
62 #define MIN_INODATA_HASH_SIZE 256
63 #define MAX_INODATA_HASH_SIZE 65536
64 #define INODATA_AVG_HASH_LENGTH 8
65
66 typedef struct qinfo {
67 xfs_qcnt_t bc;
68 xfs_qcnt_t ic;
69 xfs_qcnt_t rc;
70 } qinfo_t;
71
72 #define QDATA_HASH_SIZE 256
73 typedef struct qdata {
74 struct qdata *next;
75 xfs_dqid_t id;
76 qinfo_t count;
77 qinfo_t dq;
78 } qdata_t;
79
80 typedef struct blkent {
81 xfs_fileoff_t startoff;
82 int nblks;
83 xfs_fsblock_t blks[1];
84 } blkent_t;
85 #define BLKENT_SIZE(n) \
86 (offsetof(blkent_t, blks) + (sizeof(xfs_fsblock_t) * (n)))
87
88 typedef struct blkmap {
89 int naents;
90 int nents;
91 blkent_t *ents[1];
92 } blkmap_t;
93 #define BLKMAP_SIZE(n) \
94 (offsetof(blkmap_t, ents) + (sizeof(blkent_t *) * (n)))
95
96 typedef struct freetab {
97 int naents;
98 int nents;
99 xfs_dir2_data_off_t ents[1];
100 } freetab_t;
101 #define FREETAB_SIZE(n) \
102 (offsetof(freetab_t, ents) + (sizeof(xfs_dir2_data_off_t) * (n)))
103
104 typedef struct dirhash {
105 struct dirhash *next;
106 __u32 hashval;
107 __u32 address;
108 int seen;
109 } dirhash_t;
110 #define DIR_HASH_SIZE 1024
111 #define DIR_HASH_FUNC(h,a) (((h) ^ (a)) % DIR_HASH_SIZE)
112
113 static xfs_extlen_t agffreeblks;
114 static xfs_extlen_t agflongest;
115 static __uint64_t agf_aggr_freeblks; /* aggregate count over all */
116 static __uint32_t agfbtreeblks;
117 static int lazycount;
118 static xfs_agino_t agicount;
119 static xfs_agino_t agifreecount;
120 static xfs_fsblock_t *blist;
121 static int blist_size;
122 static char **dbmap; /* really dbm_t:8 */
123 static dirhash_t **dirhash;
124 static int error;
125 static __uint64_t fdblocks;
126 static __uint64_t frextents;
127 static __uint64_t icount;
128 static __uint64_t ifree;
129 static inodata_t ***inodata;
130 static int inodata_hash_size;
131 static inodata_t ***inomap;
132 static int nflag;
133 static int pflag;
134 static int tflag;
135 static qdata_t **qpdata;
136 static int qpdo;
137 static qdata_t **qudata;
138 static int qudo;
139 static qdata_t **qgdata;
140 static int qgdo;
141 static unsigned sbversion;
142 static int sbver_err;
143 static int serious_error;
144 static int sflag;
145 static xfs_suminfo_t *sumcompute;
146 static xfs_suminfo_t *sumfile;
147 static const char *typename[] = {
148 "unknown",
149 "agf",
150 "agfl",
151 "agi",
152 "attr",
153 "btbmapa",
154 "btbmapd",
155 "btbno",
156 "btcnt",
157 "btino",
158 "data",
159 "dir",
160 "free1",
161 "free2",
162 "freelist",
163 "inode",
164 "log",
165 "missing",
166 "quota",
167 "rtbitmap",
168 "rtdata",
169 "rtfree",
170 "rtsum",
171 "sb",
172 "symlink",
173 NULL
174 };
175 static int verbose;
176
177 #define CHECK_BLIST(b) (blist_size && check_blist(b))
178 #define CHECK_BLISTA(a,b) \
179 (blist_size && check_blist(XFS_AGB_TO_FSB(mp, a, b)))
180
181 typedef void (*scan_lbtree_f_t)(struct xfs_btree_block *block,
182 int level,
183 dbm_t type,
184 xfs_fsblock_t bno,
185 inodata_t *id,
186 xfs_drfsbno_t *totd,
187 xfs_drfsbno_t *toti,
188 xfs_extnum_t *nex,
189 blkmap_t **blkmapp,
190 int isroot,
191 typnm_t btype);
192
193 typedef void (*scan_sbtree_f_t)(struct xfs_btree_block *block,
194 int level,
195 xfs_agf_t *agf,
196 xfs_agblock_t bno,
197 int isroot);
198
199 static void add_blist(xfs_fsblock_t bno);
200 static void add_ilist(xfs_ino_t ino);
201 static void addlink_inode(inodata_t *id);
202 static void addname_inode(inodata_t *id, char *name, int namelen);
203 static void addparent_inode(inodata_t *id, xfs_ino_t parent);
204 static void blkent_append(blkent_t **entp, xfs_fsblock_t b,
205 xfs_extlen_t c);
206 static blkent_t *blkent_new(xfs_fileoff_t o, xfs_fsblock_t b,
207 xfs_extlen_t c);
208 static void blkent_prepend(blkent_t **entp, xfs_fsblock_t b,
209 xfs_extlen_t c);
210 static blkmap_t *blkmap_alloc(xfs_extnum_t);
211 static void blkmap_free(blkmap_t *blkmap);
212 static xfs_fsblock_t blkmap_get(blkmap_t *blkmap, xfs_fileoff_t o);
213 static int blkmap_getn(blkmap_t *blkmap, xfs_fileoff_t o, int nb,
214 bmap_ext_t **bmpp);
215 static void blkmap_grow(blkmap_t **blkmapp, blkent_t **entp,
216 blkent_t *newent);
217 static xfs_fileoff_t blkmap_next_off(blkmap_t *blkmap, xfs_fileoff_t o,
218 int *t);
219 static void blkmap_set_blk(blkmap_t **blkmapp, xfs_fileoff_t o,
220 xfs_fsblock_t b);
221 static void blkmap_set_ext(blkmap_t **blkmapp, xfs_fileoff_t o,
222 xfs_fsblock_t b, xfs_extlen_t c);
223 static void blkmap_shrink(blkmap_t *blkmap, blkent_t **entp);
224 static int blockfree_f(int argc, char **argv);
225 static int blockget_f(int argc, char **argv);
226 static int blocktrash_f(int argc, char **argv);
227 static int blockuse_f(int argc, char **argv);
228 static int check_blist(xfs_fsblock_t bno);
229 static void check_dbmap(xfs_agnumber_t agno, xfs_agblock_t agbno,
230 xfs_extlen_t len, dbm_t type);
231 static int check_inomap(xfs_agnumber_t agno, xfs_agblock_t agbno,
232 xfs_extlen_t len, xfs_ino_t c_ino);
233 static void check_linkcounts(xfs_agnumber_t agno);
234 static int check_range(xfs_agnumber_t agno, xfs_agblock_t agbno,
235 xfs_extlen_t len);
236 static void check_rdbmap(xfs_drfsbno_t bno, xfs_extlen_t len,
237 dbm_t type);
238 static int check_rinomap(xfs_drfsbno_t bno, xfs_extlen_t len,
239 xfs_ino_t c_ino);
240 static void check_rootdir(void);
241 static int check_rrange(xfs_drfsbno_t bno, xfs_extlen_t len);
242 static void check_set_dbmap(xfs_agnumber_t agno,
243 xfs_agblock_t agbno, xfs_extlen_t len,
244 dbm_t type1, dbm_t type2,
245 xfs_agnumber_t c_agno,
246 xfs_agblock_t c_agbno);
247 static void check_set_rdbmap(xfs_drfsbno_t bno, xfs_extlen_t len,
248 dbm_t type1, dbm_t type2);
249 static void check_summary(void);
250 static void checknot_dbmap(xfs_agnumber_t agno, xfs_agblock_t agbno,
251 xfs_extlen_t len, int typemask);
252 static void checknot_rdbmap(xfs_drfsbno_t bno, xfs_extlen_t len,
253 int typemask);
254 static void dir_hash_add(xfs_dahash_t hash,
255 xfs_dir2_dataptr_t addr);
256 static void dir_hash_check(inodata_t *id, int v);
257 static void dir_hash_done(void);
258 static void dir_hash_init(void);
259 static int dir_hash_see(xfs_dahash_t hash,
260 xfs_dir2_dataptr_t addr);
261 static inodata_t *find_inode(xfs_ino_t ino, int add);
262 static void free_inodata(xfs_agnumber_t agno);
263 static int init(int argc, char **argv);
264 static char *inode_name(xfs_ino_t ino, inodata_t **ipp);
265 static int ncheck_f(int argc, char **argv);
266 static char *prepend_path(char *oldpath, char *parent);
267 static xfs_ino_t process_block_dir_v2(blkmap_t *blkmap, int *dot,
268 int *dotdot, inodata_t *id);
269 static void process_bmbt_reclist(xfs_bmbt_rec_t *rp, int numrecs,
270 dbm_t type, inodata_t *id,
271 xfs_drfsbno_t *tot,
272 blkmap_t **blkmapp);
273 static void process_btinode(inodata_t *id, xfs_dinode_t *dip,
274 dbm_t type, xfs_drfsbno_t *totd,
275 xfs_drfsbno_t *toti, xfs_extnum_t *nex,
276 blkmap_t **blkmapp, int whichfork);
277 static xfs_ino_t process_data_dir_v2(int *dot, int *dotdot,
278 inodata_t *id, int v,
279 xfs_dablk_t dabno,
280 freetab_t **freetabp);
281 static xfs_dir2_data_free_t
282 *process_data_dir_v2_freefind(xfs_dir2_data_t *data,
283 xfs_dir2_data_unused_t *dup);
284 static void process_dir(xfs_dinode_t *dip, blkmap_t *blkmap,
285 inodata_t *id);
286 static int process_dir_v2(xfs_dinode_t *dip, blkmap_t *blkmap,
287 int *dot, int *dotdot, inodata_t *id,
288 xfs_ino_t *parent);
289 static void process_exinode(inodata_t *id, xfs_dinode_t *dip,
290 dbm_t type, xfs_drfsbno_t *totd,
291 xfs_drfsbno_t *toti, xfs_extnum_t *nex,
292 blkmap_t **blkmapp, int whichfork);
293 static void process_inode(xfs_agf_t *agf, xfs_agino_t agino,
294 xfs_dinode_t *dip, int isfree);
295 static void process_lclinode(inodata_t *id, xfs_dinode_t *dip,
296 dbm_t type, xfs_drfsbno_t *totd,
297 xfs_drfsbno_t *toti, xfs_extnum_t *nex,
298 blkmap_t **blkmapp, int whichfork);
299 static xfs_ino_t process_leaf_node_dir_v2(blkmap_t *blkmap, int *dot,
300 int *dotdot, inodata_t *id,
301 xfs_fsize_t dirsize);
302 static void process_leaf_node_dir_v2_free(inodata_t *id, int v,
303 xfs_dablk_t dbno,
304 freetab_t *freetab);
305 static void process_leaf_node_dir_v2_int(inodata_t *id, int v,
306 xfs_dablk_t dbno,
307 freetab_t *freetab);
308 static void process_quota(qtype_t qtype, inodata_t *id,
309 blkmap_t *blkmap);
310 static void process_rtbitmap(blkmap_t *blkmap);
311 static void process_rtsummary(blkmap_t *blkmap);
312 static xfs_ino_t process_sf_dir_v2(xfs_dinode_t *dip, int *dot,
313 int *dotdot, inodata_t *id);
314 static void quota_add(xfs_dqid_t *p, xfs_dqid_t *g, xfs_dqid_t *u,
315 int dq, xfs_qcnt_t bc, xfs_qcnt_t ic,
316 xfs_qcnt_t rc);
317 static void quota_add1(qdata_t **qt, xfs_dqid_t id, int dq,
318 xfs_qcnt_t bc, xfs_qcnt_t ic,
319 xfs_qcnt_t rc);
320 static void quota_check(char *s, qdata_t **qt);
321 static void quota_init(void);
322 static void scan_ag(xfs_agnumber_t agno);
323 static void scan_freelist(xfs_agf_t *agf);
324 static void scan_lbtree(xfs_fsblock_t root, int nlevels,
325 scan_lbtree_f_t func, dbm_t type,
326 inodata_t *id, xfs_drfsbno_t *totd,
327 xfs_drfsbno_t *toti, xfs_extnum_t *nex,
328 blkmap_t **blkmapp, int isroot,
329 typnm_t btype);
330 static void scan_sbtree(xfs_agf_t *agf, xfs_agblock_t root,
331 int nlevels, int isroot,
332 scan_sbtree_f_t func, typnm_t btype);
333 static void scanfunc_bmap(struct xfs_btree_block *block,
334 int level, dbm_t type, xfs_fsblock_t bno,
335 inodata_t *id, xfs_drfsbno_t *totd,
336 xfs_drfsbno_t *toti, xfs_extnum_t *nex,
337 blkmap_t **blkmapp, int isroot,
338 typnm_t btype);
339 static void scanfunc_bno(struct xfs_btree_block *block, int level,
340 xfs_agf_t *agf, xfs_agblock_t bno,
341 int isroot);
342 static void scanfunc_cnt(struct xfs_btree_block *block, int level,
343 xfs_agf_t *agf, xfs_agblock_t bno,
344 int isroot);
345 static void scanfunc_ino(struct xfs_btree_block *block, int level,
346 xfs_agf_t *agf, xfs_agblock_t bno,
347 int isroot);
348 static void set_dbmap(xfs_agnumber_t agno, xfs_agblock_t agbno,
349 xfs_extlen_t len, dbm_t type,
350 xfs_agnumber_t c_agno, xfs_agblock_t c_agbno);
351 static void set_inomap(xfs_agnumber_t agno, xfs_agblock_t agbno,
352 xfs_extlen_t len, inodata_t *id);
353 static void set_rdbmap(xfs_drfsbno_t bno, xfs_extlen_t len,
354 dbm_t type);
355 static void set_rinomap(xfs_drfsbno_t bno, xfs_extlen_t len,
356 inodata_t *id);
357 static void setlink_inode(inodata_t *id, nlink_t nlink, int isdir,
358 int security);
359
360 static const cmdinfo_t blockfree_cmd =
361 { "blockfree", NULL, blockfree_f, 0, 0, 0,
362 NULL, N_("free block usage information"), NULL };
363 static const cmdinfo_t blockget_cmd =
364 { "blockget", "check", blockget_f, 0, -1, 0,
365 N_("[-s|-v] [-n] [-t] [-b bno]... [-i ino] ..."),
366 N_("get block usage and check consistency"), NULL };
367 static const cmdinfo_t blocktrash_cmd =
368 { "blocktrash", NULL, blocktrash_f, 0, -1, 0,
369 N_("[-n count] [-x minlen] [-y maxlen] [-s seed] [-0123] [-t type] ..."),
370 N_("trash randomly selected block(s)"), NULL };
371 static const cmdinfo_t blockuse_cmd =
372 { "blockuse", NULL, blockuse_f, 0, 3, 0,
373 N_("[-n] [-c blockcount]"),
374 N_("print usage for current block(s)"), NULL };
375 static const cmdinfo_t ncheck_cmd =
376 { "ncheck", NULL, ncheck_f, 0, -1, 0,
377 N_("[-s] [-i ino] ..."),
378 N_("print inode-name pairs"), NULL };
379
380
381 static void
382 add_blist(
383 xfs_fsblock_t bno)
384 {
385 blist_size++;
386 blist = xrealloc(blist, blist_size * sizeof(bno));
387 blist[blist_size - 1] = bno;
388 }
389
390 static void
391 add_ilist(
392 xfs_ino_t ino)
393 {
394 inodata_t *id;
395
396 id = find_inode(ino, 1);
397 if (id == NULL) {
398 dbprintf(_("-i %lld bad inode number\n"), ino);
399 return;
400 }
401 id->ilist = 1;
402 }
403
404 static void
405 addlink_inode(
406 inodata_t *id)
407 {
408 id->link_add++;
409 if (verbose || id->ilist)
410 dbprintf(_("inode %lld add link, now %u\n"), id->ino,
411 id->link_add);
412 }
413
414 static void
415 addname_inode(
416 inodata_t *id,
417 char *name,
418 int namelen)
419 {
420 if (!nflag || id->name)
421 return;
422 id->name = xmalloc(namelen + 1);
423 memcpy(id->name, name, namelen);
424 id->name[namelen] = '\0';
425 }
426
427 static void
428 addparent_inode(
429 inodata_t *id,
430 xfs_ino_t parent)
431 {
432 inodata_t *pid;
433
434 pid = find_inode(parent, 1);
435 id->parent = pid;
436 if (verbose || id->ilist || (pid && pid->ilist))
437 dbprintf(_("inode %lld parent %lld\n"), id->ino, parent);
438 }
439
440 static void
441 blkent_append(
442 blkent_t **entp,
443 xfs_fsblock_t b,
444 xfs_extlen_t c)
445 {
446 blkent_t *ent;
447 int i;
448
449 ent = *entp;
450 *entp = ent = xrealloc(ent, BLKENT_SIZE(c + ent->nblks));
451 for (i = 0; i < c; i++)
452 ent->blks[ent->nblks + i] = b + i;
453 ent->nblks += c;
454 }
455
456 static blkent_t *
457 blkent_new(
458 xfs_fileoff_t o,
459 xfs_fsblock_t b,
460 xfs_extlen_t c)
461 {
462 blkent_t *ent;
463 int i;
464
465 ent = xmalloc(BLKENT_SIZE(c));
466 ent->nblks = c;
467 ent->startoff = o;
468 for (i = 0; i < c; i++)
469 ent->blks[i] = b + i;
470 return ent;
471 }
472
473 static void
474 blkent_prepend(
475 blkent_t **entp,
476 xfs_fsblock_t b,
477 xfs_extlen_t c)
478 {
479 int i;
480 blkent_t *newent;
481 blkent_t *oldent;
482
483 oldent = *entp;
484 newent = xmalloc(BLKENT_SIZE(oldent->nblks + c));
485 newent->nblks = oldent->nblks + c;
486 newent->startoff = oldent->startoff - c;
487 for (i = 0; i < c; i++)
488 newent->blks[i] = b + c;
489 for (; i < oldent->nblks + c; i++)
490 newent->blks[i] = oldent->blks[i - c];
491 xfree(oldent);
492 *entp = newent;
493 }
494
495 static blkmap_t *
496 blkmap_alloc(
497 xfs_extnum_t nex)
498 {
499 blkmap_t *blkmap;
500
501 if (nex < 1)
502 nex = 1;
503 blkmap = xmalloc(BLKMAP_SIZE(nex));
504 blkmap->naents = nex;
505 blkmap->nents = 0;
506 return blkmap;
507 }
508
509 static void
510 blkmap_free(
511 blkmap_t *blkmap)
512 {
513 blkent_t **entp;
514 xfs_extnum_t i;
515
516 for (i = 0, entp = blkmap->ents; i < blkmap->nents; i++, entp++)
517 xfree(*entp);
518 xfree(blkmap);
519 }
520
521 static xfs_fsblock_t
522 blkmap_get(
523 blkmap_t *blkmap,
524 xfs_fileoff_t o)
525 {
526 blkent_t *ent;
527 blkent_t **entp;
528 int i;
529
530 for (i = 0, entp = blkmap->ents; i < blkmap->nents; i++, entp++) {
531 ent = *entp;
532 if (o >= ent->startoff && o < ent->startoff + ent->nblks)
533 return ent->blks[o - ent->startoff];
534 }
535 return NULLFSBLOCK;
536 }
537
538 static int
539 blkmap_getn(
540 blkmap_t *blkmap,
541 xfs_fileoff_t o,
542 int nb,
543 bmap_ext_t **bmpp)
544 {
545 bmap_ext_t *bmp;
546 blkent_t *ent;
547 xfs_fileoff_t ento;
548 blkent_t **entp;
549 int i;
550 int nex;
551
552 for (i = nex = 0, bmp = NULL, entp = blkmap->ents;
553 i < blkmap->nents;
554 i++, entp++) {
555 ent = *entp;
556 if (ent->startoff >= o + nb)
557 break;
558 if (ent->startoff + ent->nblks <= o)
559 continue;
560 for (ento = ent->startoff;
561 ento < ent->startoff + ent->nblks && ento < o + nb;
562 ento++) {
563 if (ento < o)
564 continue;
565 if (bmp &&
566 bmp[nex - 1].startoff + bmp[nex - 1].blockcount ==
567 ento &&
568 bmp[nex - 1].startblock + bmp[nex - 1].blockcount ==
569 ent->blks[ento - ent->startoff])
570 bmp[nex - 1].blockcount++;
571 else {
572 bmp = realloc(bmp, ++nex * sizeof(*bmp));
573 bmp[nex - 1].startoff = ento;
574 bmp[nex - 1].startblock =
575 ent->blks[ento - ent->startoff];
576 bmp[nex - 1].blockcount = 1;
577 bmp[nex - 1].flag = 0;
578 }
579 }
580 }
581 *bmpp = bmp;
582 return nex;
583 }
584
585 static void
586 blkmap_grow(
587 blkmap_t **blkmapp,
588 blkent_t **entp,
589 blkent_t *newent)
590 {
591 blkmap_t *blkmap;
592 int i;
593 int idx;
594
595 blkmap = *blkmapp;
596 idx = (int)(entp - blkmap->ents);
597 if (blkmap->naents == blkmap->nents) {
598 blkmap = xrealloc(blkmap, BLKMAP_SIZE(blkmap->nents + 1));
599 *blkmapp = blkmap;
600 blkmap->naents++;
601 }
602 for (i = blkmap->nents; i > idx; i--)
603 blkmap->ents[i] = blkmap->ents[i - 1];
604 blkmap->ents[idx] = newent;
605 blkmap->nents++;
606 }
607
608 static xfs_fileoff_t
609 blkmap_last_off(
610 blkmap_t *blkmap)
611 {
612 blkent_t *ent;
613
614 if (!blkmap->nents)
615 return NULLFILEOFF;
616 ent = blkmap->ents[blkmap->nents - 1];
617 return ent->startoff + ent->nblks;
618 }
619
620 static xfs_fileoff_t
621 blkmap_next_off(
622 blkmap_t *blkmap,
623 xfs_fileoff_t o,
624 int *t)
625 {
626 blkent_t *ent;
627 blkent_t **entp;
628
629 if (!blkmap->nents)
630 return NULLFILEOFF;
631 if (o == NULLFILEOFF) {
632 *t = 0;
633 ent = blkmap->ents[0];
634 return ent->startoff;
635 }
636 entp = &blkmap->ents[*t];
637 ent = *entp;
638 if (o < ent->startoff + ent->nblks - 1)
639 return o + 1;
640 entp++;
641 if (entp >= &blkmap->ents[blkmap->nents])
642 return NULLFILEOFF;
643 (*t)++;
644 ent = *entp;
645 return ent->startoff;
646 }
647
648 static void
649 blkmap_set_blk(
650 blkmap_t **blkmapp,
651 xfs_fileoff_t o,
652 xfs_fsblock_t b)
653 {
654 blkmap_t *blkmap;
655 blkent_t *ent;
656 blkent_t **entp;
657 blkent_t *nextent;
658
659 blkmap = *blkmapp;
660 for (entp = blkmap->ents; entp < &blkmap->ents[blkmap->nents]; entp++) {
661 ent = *entp;
662 if (o < ent->startoff - 1) {
663 ent = blkent_new(o, b, 1);
664 blkmap_grow(blkmapp, entp, ent);
665 return;
666 }
667 if (o == ent->startoff - 1) {
668 blkent_prepend(entp, b, 1);
669 return;
670 }
671 if (o >= ent->startoff && o < ent->startoff + ent->nblks) {
672 ent->blks[o - ent->startoff] = b;
673 return;
674 }
675 if (o > ent->startoff + ent->nblks)
676 continue;
677 blkent_append(entp, b, 1);
678 if (entp == &blkmap->ents[blkmap->nents - 1])
679 return;
680 ent = *entp;
681 nextent = entp[1];
682 if (ent->startoff + ent->nblks < nextent->startoff)
683 return;
684 blkent_append(entp, nextent->blks[0], nextent->nblks);
685 blkmap_shrink(blkmap, &entp[1]);
686 return;
687 }
688 ent = blkent_new(o, b, 1);
689 blkmap_grow(blkmapp, entp, ent);
690 }
691
692 static void
693 blkmap_set_ext(
694 blkmap_t **blkmapp,
695 xfs_fileoff_t o,
696 xfs_fsblock_t b,
697 xfs_extlen_t c)
698 {
699 blkmap_t *blkmap;
700 blkent_t *ent;
701 blkent_t **entp;
702 xfs_extnum_t i;
703
704 blkmap = *blkmapp;
705 if (!blkmap->nents) {
706 blkmap->ents[0] = blkent_new(o, b, c);
707 blkmap->nents = 1;
708 return;
709 }
710 entp = &blkmap->ents[blkmap->nents - 1];
711 ent = *entp;
712 if (ent->startoff + ent->nblks == o) {
713 blkent_append(entp, b, c);
714 return;
715 }
716 if (ent->startoff + ent->nblks < o) {
717 ent = blkent_new(o, b, c);
718 blkmap_grow(blkmapp, &blkmap->ents[blkmap->nents], ent);
719 return;
720 }
721 for (i = 0; i < c; i++)
722 blkmap_set_blk(blkmapp, o + i, b + i);
723 }
724
725 static void
726 blkmap_shrink(
727 blkmap_t *blkmap,
728 blkent_t **entp)
729 {
730 int i;
731 int idx;
732
733 xfree(*entp);
734 idx = (int)(entp - blkmap->ents);
735 for (i = idx + 1; i < blkmap->nents; i++)
736 blkmap->ents[i] = blkmap->ents[i - 1];
737 blkmap->nents--;
738 }
739
740 /* ARGSUSED */
741 static int
742 blockfree_f(
743 int argc,
744 char **argv)
745 {
746 xfs_agnumber_t c;
747 int rt;
748
749 if (!dbmap) {
750 dbprintf(_("block usage information not allocated\n"));
751 return 0;
752 }
753 rt = mp->m_sb.sb_rextents != 0;
754 for (c = 0; c < mp->m_sb.sb_agcount; c++) {
755 xfree(dbmap[c]);
756 xfree(inomap[c]);
757 free_inodata(c);
758 }
759 if (rt) {
760 xfree(dbmap[c]);
761 xfree(inomap[c]);
762 xfree(sumcompute);
763 xfree(sumfile);
764 sumcompute = sumfile = NULL;
765 }
766 xfree(dbmap);
767 xfree(inomap);
768 xfree(inodata);
769 dbmap = NULL;
770 inomap = NULL;
771 inodata = NULL;
772 return 0;
773 }
774
775 /*
776 * Check consistency of xfs filesystem contents.
777 */
778 static int
779 blockget_f(
780 int argc,
781 char **argv)
782 {
783 xfs_agnumber_t agno;
784 int oldprefix;
785 int sbyell;
786
787 if (dbmap) {
788 dbprintf(_("already have block usage information\n"));
789 return 0;
790 }
791 if (!init(argc, argv)) {
792 if (serious_error)
793 exitcode = 3;
794 else
795 exitcode = 1;
796 return 0;
797 }
798 oldprefix = dbprefix;
799 dbprefix |= pflag;
800 for (agno = 0, sbyell = 0; agno < mp->m_sb.sb_agcount; agno++) {
801 scan_ag(agno);
802 if (sbver_err > 4 && !sbyell && sbver_err >= agno) {
803 sbyell = 1;
804 dbprintf(_("WARNING: this may be a newer XFS "
805 "filesystem.\n"));
806 }
807 }
808 if (blist_size) {
809 xfree(blist);
810 blist = NULL;
811 blist_size = 0;
812 }
813 if (serious_error) {
814 exitcode = 2;
815 dbprefix = oldprefix;
816 return 0;
817 }
818 check_rootdir();
819 /*
820 * Check that there are no blocks either
821 * a) unaccounted for or
822 * b) bno-free but not cnt-free
823 */
824 if (!tflag) { /* are we in test mode, faking out freespace? */
825 for (agno = 0; agno < mp->m_sb.sb_agcount; agno++)
826 checknot_dbmap(agno, 0, mp->m_sb.sb_agblocks,
827 (1 << DBM_UNKNOWN) | (1 << DBM_FREE1));
828 }
829 for (agno = 0; agno < mp->m_sb.sb_agcount; agno++)
830 check_linkcounts(agno);
831 if (mp->m_sb.sb_rblocks) {
832 checknot_rdbmap(0,
833 (xfs_extlen_t)(mp->m_sb.sb_rextents *
834 mp->m_sb.sb_rextsize),
835 1 << DBM_UNKNOWN);
836 check_summary();
837 }
838 if (mp->m_sb.sb_icount != icount) {
839 if (!sflag)
840 dbprintf(_("sb_icount %lld, counted %lld\n"),
841 mp->m_sb.sb_icount, icount);
842 error++;
843 }
844 if (mp->m_sb.sb_ifree != ifree) {
845 if (!sflag)
846 dbprintf(_("sb_ifree %lld, counted %lld\n"),
847 mp->m_sb.sb_ifree, ifree);
848 error++;
849 }
850 if (mp->m_sb.sb_fdblocks != fdblocks) {
851 if (!sflag)
852 dbprintf(_("sb_fdblocks %lld, counted %lld\n"),
853 mp->m_sb.sb_fdblocks, fdblocks);
854 error++;
855 }
856 if (lazycount && mp->m_sb.sb_fdblocks != agf_aggr_freeblks) {
857 if (!sflag)
858 dbprintf(_("sb_fdblocks %lld, aggregate AGF count %lld\n"),
859 mp->m_sb.sb_fdblocks, agf_aggr_freeblks);
860 error++;
861 }
862 if (mp->m_sb.sb_frextents != frextents) {
863 if (!sflag)
864 dbprintf(_("sb_frextents %lld, counted %lld\n"),
865 mp->m_sb.sb_frextents, frextents);
866 error++;
867 }
868 if (mp->m_sb.sb_bad_features2 != 0 &&
869 mp->m_sb.sb_bad_features2 != mp->m_sb.sb_features2) {
870 if (!sflag)
871 dbprintf(_("sb_features2 (0x%x) not same as "
872 "sb_bad_features2 (0x%x)\n"),
873 mp->m_sb.sb_features2,
874 mp->m_sb.sb_bad_features2);
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 N_("zeroed"), N_("set"), N_("flipped"), N_("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->hashval = hash;
1624 p->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->hashval, p->address);
1644 error++;
1645 }
1646 }
1647 }
1648
1649 static void
1650 dir_hash_done(void)
1651 {
1652 int i;
1653 dirhash_t *n;
1654 dirhash_t *p;
1655
1656 for (i = 0; i < DIR_HASH_SIZE; i++) {
1657 for (p = dirhash[i]; p; p = n) {
1658 n = p->next;
1659 free(p);
1660 }
1661 dirhash[i] = NULL;
1662 }
1663 }
1664
1665 static void
1666 dir_hash_init(void)
1667 {
1668 if (!dirhash)
1669 dirhash = calloc(DIR_HASH_SIZE, sizeof(*dirhash));
1670 }
1671
1672 static int
1673 dir_hash_see(
1674 xfs_dahash_t hash,
1675 xfs_dir2_dataptr_t addr)
1676 {
1677 int i;
1678 dirhash_t *p;
1679
1680 i = DIR_HASH_FUNC(hash, addr);
1681 for (p = dirhash[i]; p; p = p->next) {
1682 if (p->hashval == hash && p->address == addr) {
1683 if (p->seen)
1684 return 1;
1685 p->seen = 1;
1686 return 0;
1687 }
1688 }
1689 return -1;
1690 }
1691
1692 static inodata_t *
1693 find_inode(
1694 xfs_ino_t ino,
1695 int add)
1696 {
1697 xfs_agino_t agino;
1698 xfs_agnumber_t agno;
1699 inodata_t *ent;
1700 inodata_t **htab;
1701 xfs_agino_t ih;
1702
1703 agno = XFS_INO_TO_AGNO(mp, ino);
1704 agino = XFS_INO_TO_AGINO(mp, ino);
1705 if (agno >= mp->m_sb.sb_agcount ||
1706 XFS_AGINO_TO_INO(mp, agno, agino) != ino)
1707 return NULL;
1708 htab = inodata[agno];
1709 ih = agino % inodata_hash_size;
1710 ent = htab[ih];
1711 while (ent) {
1712 if (ent->ino == ino)
1713 return ent;
1714 ent = ent->next;
1715 }
1716 if (!add)
1717 return NULL;
1718 ent = xcalloc(1, sizeof(*ent));
1719 ent->ino = ino;
1720 ent->next = htab[ih];
1721 htab[ih] = ent;
1722 return ent;
1723 }
1724
1725 static void
1726 free_inodata(
1727 xfs_agnumber_t agno)
1728 {
1729 inodata_t *hp;
1730 inodata_t **ht;
1731 int i;
1732 inodata_t *next;
1733
1734 ht = inodata[agno];
1735 for (i = 0; i < inodata_hash_size; i++) {
1736 hp = ht[i];
1737 while (hp) {
1738 next = hp->next;
1739 if (hp->name)
1740 xfree(hp->name);
1741 xfree(hp);
1742 hp = next;
1743 }
1744 }
1745 xfree(ht);
1746 }
1747
1748 static int
1749 init(
1750 int argc,
1751 char **argv)
1752 {
1753 xfs_fsblock_t bno;
1754 int c;
1755 xfs_ino_t ino;
1756 int rt;
1757
1758 serious_error = 0;
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 serious_error = 1;
1763 return 0;
1764 }
1765 if (!sb_logcheck())
1766 return 0;
1767 rt = mp->m_sb.sb_rextents != 0;
1768 dbmap = xmalloc((mp->m_sb.sb_agcount + rt) * sizeof(*dbmap));
1769 inomap = xmalloc((mp->m_sb.sb_agcount + rt) * sizeof(*inomap));
1770 inodata = xmalloc(mp->m_sb.sb_agcount * sizeof(*inodata));
1771 inodata_hash_size =
1772 (int)MAX(MIN(mp->m_sb.sb_icount /
1773 (INODATA_AVG_HASH_LENGTH * mp->m_sb.sb_agcount),
1774 MAX_INODATA_HASH_SIZE),
1775 MIN_INODATA_HASH_SIZE);
1776 for (c = 0; c < mp->m_sb.sb_agcount; c++) {
1777 dbmap[c] = xcalloc(mp->m_sb.sb_agblocks, sizeof(**dbmap));
1778 inomap[c] = xcalloc(mp->m_sb.sb_agblocks, sizeof(**inomap));
1779 inodata[c] = xcalloc(inodata_hash_size, sizeof(**inodata));
1780 }
1781 if (rt) {
1782 dbmap[c] = xcalloc(mp->m_sb.sb_rblocks, sizeof(**dbmap));
1783 inomap[c] = xcalloc(mp->m_sb.sb_rblocks, sizeof(**inomap));
1784 sumfile = xcalloc(mp->m_rsumsize, 1);
1785 sumcompute = xcalloc(mp->m_rsumsize, 1);
1786 }
1787 nflag = sflag = tflag = verbose = optind = 0;
1788 while ((c = getopt(argc, argv, "b:i:npstv")) != EOF) {
1789 switch (c) {
1790 case 'b':
1791 bno = strtoll(optarg, NULL, 10);
1792 add_blist(bno);
1793 break;
1794 case 'i':
1795 ino = strtoll(optarg, NULL, 10);
1796 add_ilist(ino);
1797 break;
1798 case 'n':
1799 nflag = 1;
1800 break;
1801 case 'p':
1802 pflag = 1;
1803 break;
1804 case 's':
1805 sflag = 1;
1806 break;
1807 case 't':
1808 tflag = 1;
1809 break;
1810 case 'v':
1811 verbose = 1;
1812 break;
1813 default:
1814 dbprintf(_("bad option for blockget command\n"));
1815 return 0;
1816 }
1817 }
1818 error = sbver_err = serious_error = 0;
1819 fdblocks = frextents = icount = ifree = 0;
1820 sbversion = XFS_SB_VERSION_4;
1821 if (mp->m_sb.sb_inoalignmt)
1822 sbversion |= XFS_SB_VERSION_ALIGNBIT;
1823 if ((mp->m_sb.sb_uquotino && mp->m_sb.sb_uquotino != NULLFSINO) ||
1824 (mp->m_sb.sb_gquotino && mp->m_sb.sb_gquotino != NULLFSINO))
1825 sbversion |= XFS_SB_VERSION_QUOTABIT;
1826 quota_init();
1827 return 1;
1828 }
1829
1830 static char *
1831 inode_name(
1832 xfs_ino_t ino,
1833 inodata_t **ipp)
1834 {
1835 inodata_t *id;
1836 char *npath;
1837 char *path;
1838
1839 id = find_inode(ino, 0);
1840 if (ipp)
1841 *ipp = id;
1842 if (id == NULL)
1843 return NULL;
1844 if (id->name == NULL)
1845 return NULL;
1846 path = xstrdup(id->name);
1847 while (id->parent) {
1848 id = id->parent;
1849 if (id->name == NULL)
1850 break;
1851 npath = prepend_path(path, id->name);
1852 xfree(path);
1853 path = npath;
1854 }
1855 return path;
1856 }
1857
1858 static int
1859 ncheck_f(
1860 int argc,
1861 char **argv)
1862 {
1863 xfs_agnumber_t agno;
1864 int c;
1865 inodata_t *hp;
1866 inodata_t **ht;
1867 int i;
1868 inodata_t *id;
1869 xfs_ino_t *ilist;
1870 int ilist_size;
1871 xfs_ino_t *ilp;
1872 xfs_ino_t ino;
1873 char *p;
1874 int security;
1875
1876 if (!inodata || !nflag) {
1877 dbprintf(_("must run blockget -n first\n"));
1878 return 0;
1879 }
1880 security = optind = ilist_size = 0;
1881 ilist = NULL;
1882 while ((c = getopt(argc, argv, "i:s")) != EOF) {
1883 switch (c) {
1884 case 'i':
1885 ino = strtoll(optarg, NULL, 10);
1886 ilist = xrealloc(ilist, (ilist_size + 1) *
1887 sizeof(*ilist));
1888 ilist[ilist_size++] = ino;
1889 break;
1890 case 's':
1891 security = 1;
1892 break;
1893 default:
1894 dbprintf(_("bad option -%c for ncheck command\n"), c);
1895 return 0;
1896 }
1897 }
1898 if (ilist) {
1899 for (ilp = ilist; ilp < &ilist[ilist_size]; ilp++) {
1900 ino = *ilp;
1901 if ((p = inode_name(ino, &hp))) {
1902 dbprintf("%11llu %s", ino, p);
1903 if (hp->isdir)
1904 dbprintf("/.");
1905 dbprintf("\n");
1906 xfree(p);
1907 }
1908 }
1909 xfree(ilist);
1910 return 0;
1911 }
1912 for (agno = 0; agno < mp->m_sb.sb_agcount; agno++) {
1913 ht = inodata[agno];
1914 for (i = 0; i < inodata_hash_size; i++) {
1915 hp = ht[i];
1916 for (hp = ht[i]; hp; hp = hp->next) {
1917 ino = XFS_AGINO_TO_INO(mp, agno, hp->ino);
1918 p = inode_name(ino, &id);
1919 if (!p || !id)
1920 continue;
1921 if (!security || id->security) {
1922 dbprintf("%11llu %s", ino, p);
1923 if (hp->isdir)
1924 dbprintf("/.");
1925 dbprintf("\n");
1926 }
1927 xfree(p);
1928 }
1929 }
1930 }
1931 return 0;
1932 }
1933
1934 static char *
1935 prepend_path(
1936 char *oldpath,
1937 char *parent)
1938 {
1939 int len;
1940 char *path;
1941
1942 len = (int)(strlen(oldpath) + strlen(parent) + 2);
1943 path = xmalloc(len);
1944 snprintf(path, len, "%s/%s", parent, oldpath);
1945 return path;
1946 }
1947
1948 static xfs_ino_t
1949 process_block_dir_v2(
1950 blkmap_t *blkmap,
1951 int *dot,
1952 int *dotdot,
1953 inodata_t *id)
1954 {
1955 xfs_fsblock_t b;
1956 bbmap_t bbmap;
1957 bmap_ext_t *bmp;
1958 int nex;
1959 xfs_ino_t parent;
1960 int v;
1961 int x;
1962
1963 nex = blkmap_getn(blkmap, 0, mp->m_dirblkfsbs, &bmp);
1964 v = id->ilist || verbose;
1965 if (nex == 0) {
1966 if (!sflag || v)
1967 dbprintf(_("block 0 for directory inode %lld is "
1968 "missing\n"),
1969 id->ino);
1970 error++;
1971 return 0;
1972 }
1973 push_cur();
1974 if (nex > 1)
1975 make_bbmap(&bbmap, nex, bmp);
1976 set_cur(&typtab[TYP_DIR2], XFS_FSB_TO_DADDR(mp, bmp->startblock),
1977 mp->m_dirblkfsbs * blkbb, DB_RING_IGN, nex > 1 ? &bbmap : NULL);
1978 for (x = 0; !v && x < nex; x++) {
1979 for (b = bmp[x].startblock;
1980 !v && b < bmp[x].startblock + bmp[x].blockcount;
1981 b++)
1982 v = CHECK_BLIST(b);
1983 }
1984 free(bmp);
1985 if (iocur_top->data == NULL) {
1986 if (!sflag || id->ilist || v)
1987 dbprintf(_("can't read block 0 for directory inode "
1988 "%lld\n"),
1989 id->ino);
1990 error++;
1991 pop_cur();
1992 return 0;
1993 }
1994 dir_hash_init();
1995 parent = process_data_dir_v2(dot, dotdot, id, v, mp->m_dirdatablk,
1996 NULL);
1997 dir_hash_check(id, v);
1998 dir_hash_done();
1999 pop_cur();
2000 return parent;
2001 }
2002
2003 static void
2004 process_bmbt_reclist(
2005 xfs_bmbt_rec_t *rp,
2006 int numrecs,
2007 dbm_t type,
2008 inodata_t *id,
2009 xfs_drfsbno_t *tot,
2010 blkmap_t **blkmapp)
2011 {
2012 xfs_agblock_t agbno;
2013 xfs_agnumber_t agno;
2014 xfs_fsblock_t b;
2015 xfs_dfilblks_t c;
2016 xfs_dfilblks_t cp;
2017 int f;
2018 int i;
2019 xfs_agblock_t iagbno;
2020 xfs_agnumber_t iagno;
2021 xfs_dfiloff_t o;
2022 xfs_dfiloff_t op;
2023 xfs_dfsbno_t s;
2024 int v;
2025
2026 cp = op = 0;
2027 v = verbose || id->ilist;
2028 iagno = XFS_INO_TO_AGNO(mp, id->ino);
2029 iagbno = XFS_INO_TO_AGBNO(mp, id->ino);
2030 for (i = 0; i < numrecs; i++, rp++) {
2031 convert_extent(rp, &o, &s, &c, &f);
2032 if (v)
2033 dbprintf(_("inode %lld extent [%lld,%lld,%lld,%d]\n"),
2034 id->ino, o, s, c, f);
2035 if (!sflag && i > 0 && op + cp > o)
2036 dbprintf(_("bmap rec out of order, inode %lld entry %d\n"),
2037 id->ino, i);
2038 op = o;
2039 cp = c;
2040 if (type == DBM_RTDATA) {
2041 if (!sflag && s >= mp->m_sb.sb_rblocks) {
2042 dbprintf(_("inode %lld bad rt block number %lld, "
2043 "offset %lld\n"),
2044 id->ino, s, o);
2045 continue;
2046 }
2047 } else if (!sflag) {
2048 agno = XFS_FSB_TO_AGNO(mp, s);
2049 agbno = XFS_FSB_TO_AGBNO(mp, s);
2050 if (agno >= mp->m_sb.sb_agcount ||
2051 agbno >= mp->m_sb.sb_agblocks) {
2052 dbprintf(_("inode %lld bad block number %lld "
2053 "[%d,%d], offset %lld\n"),
2054 id->ino, s, agno, agbno, o);
2055 continue;
2056 }
2057 if (agbno + c - 1 >= mp->m_sb.sb_agblocks) {
2058 dbprintf(_("inode %lld bad block number %lld "
2059 "[%d,%d], offset %lld\n"),
2060 id->ino, s + c - 1, agno,
2061 agbno + (xfs_agblock_t)c - 1, o);
2062 continue;
2063 }
2064 }
2065 if (blkmapp && *blkmapp)
2066 blkmap_set_ext(blkmapp, (xfs_fileoff_t)o,
2067 (xfs_fsblock_t)s, (xfs_extlen_t)c);
2068 if (type == DBM_RTDATA) {
2069 set_rdbmap((xfs_fsblock_t)s, (xfs_extlen_t)c,
2070 DBM_RTDATA);
2071 set_rinomap((xfs_fsblock_t)s, (xfs_extlen_t)c, id);
2072 for (b = (xfs_fsblock_t)s;
2073 blist_size && b < s + c;
2074 b++, o++) {
2075 if (CHECK_BLIST(b))
2076 dbprintf(_("inode %lld block %lld at "
2077 "offset %lld\n"),
2078 id->ino, (xfs_dfsbno_t)b, o);
2079 }
2080 } else {
2081 agno = XFS_FSB_TO_AGNO(mp, (xfs_fsblock_t)s);
2082 agbno = XFS_FSB_TO_AGBNO(mp, (xfs_fsblock_t)s);
2083 set_dbmap(agno, agbno, (xfs_extlen_t)c, type, iagno,
2084 iagbno);
2085 set_inomap(agno, agbno, (xfs_extlen_t)c, id);
2086 for (b = (xfs_fsblock_t)s;
2087 blist_size && b < s + c;
2088 b++, o++, agbno++) {
2089 if (CHECK_BLIST(b))
2090 dbprintf(_("inode %lld block %lld at "
2091 "offset %lld\n"),
2092 id->ino, (xfs_dfsbno_t)b, o);
2093 }
2094 }
2095 *tot += c;
2096 }
2097 }
2098
2099 static void
2100 process_btinode(
2101 inodata_t *id,
2102 xfs_dinode_t *dip,
2103 dbm_t type,
2104 xfs_drfsbno_t *totd,
2105 xfs_drfsbno_t *toti,
2106 xfs_extnum_t *nex,
2107 blkmap_t **blkmapp,
2108 int whichfork)
2109 {
2110 xfs_bmdr_block_t *dib;
2111 int i;
2112 xfs_bmbt_ptr_t *pp;
2113
2114 dib = (xfs_bmdr_block_t *)XFS_DFORK_PTR(dip, whichfork);
2115 if (be16_to_cpu(dib->bb_level) >= XFS_BM_MAXLEVELS(mp, whichfork)) {
2116 if (!sflag || id->ilist)
2117 dbprintf(_("level for ino %lld %s fork bmap root too "
2118 "large (%u)\n"),
2119 id->ino,
2120 whichfork == XFS_DATA_FORK ? _("data") : _("attr"),
2121 be16_to_cpu(dib->bb_level));
2122 error++;
2123 return;
2124 }
2125 if (be16_to_cpu(dib->bb_numrecs) >
2126 xfs_bmdr_maxrecs(mp, XFS_DFORK_SIZE(dip, mp, whichfork),
2127 be16_to_cpu(dib->bb_level) == 0)) {
2128 if (!sflag || id->ilist)
2129 dbprintf(_("numrecs for ino %lld %s fork bmap root too "
2130 "large (%u)\n"),
2131 id->ino,
2132 whichfork == XFS_DATA_FORK ? _("data") : _("attr"),
2133 be16_to_cpu(dib->bb_numrecs));
2134 error++;
2135 return;
2136 }
2137 if (be16_to_cpu(dib->bb_level) == 0) {
2138 xfs_bmbt_rec_t *rp = XFS_BMDR_REC_ADDR(dib, 1);
2139 process_bmbt_reclist(rp, be16_to_cpu(dib->bb_numrecs), type,
2140 id, totd, blkmapp);
2141 *nex += be16_to_cpu(dib->bb_numrecs);
2142 return;
2143 } else {
2144 pp = XFS_BMDR_PTR_ADDR(dib, 1, xfs_bmdr_maxrecs(mp,
2145 XFS_DFORK_SIZE(dip, mp, whichfork), 0));
2146 for (i = 0; i < be16_to_cpu(dib->bb_numrecs); i++)
2147 scan_lbtree(be64_to_cpu(pp[i]),
2148 be16_to_cpu(dib->bb_level),
2149 scanfunc_bmap, type, id, totd, toti,
2150 nex, blkmapp, 1,
2151 whichfork == XFS_DATA_FORK ?
2152 TYP_BMAPBTD : TYP_BMAPBTA);
2153 }
2154 if (*nex <= XFS_DFORK_SIZE(dip, mp, whichfork) / sizeof(xfs_bmbt_rec_t)) {
2155 if (!sflag || id->ilist)
2156 dbprintf(_("extent count for ino %lld %s fork too low "
2157 "(%d) for file format\n"),
2158 id->ino,
2159 whichfork == XFS_DATA_FORK ? _("data") : _("attr"),
2160 *nex);
2161 error++;
2162 }
2163 }
2164
2165 static xfs_ino_t
2166 process_data_dir_v2(
2167 int *dot,
2168 int *dotdot,
2169 inodata_t *id,
2170 int v,
2171 xfs_dablk_t dabno,
2172 freetab_t **freetabp)
2173 {
2174 xfs_dir2_dataptr_t addr;
2175 xfs_dir2_data_free_t *bf;
2176 int bf_err;
2177 xfs_dir2_block_t *block;
2178 xfs_dir2_block_tail_t *btp = NULL;
2179 inodata_t *cid;
2180 int count;
2181 xfs_dir2_data_t *data;
2182 xfs_dir2_db_t db;
2183 xfs_dir2_data_entry_t *dep;
2184 xfs_dir2_data_free_t *dfp;
2185 xfs_dir2_data_unused_t *dup;
2186 char *endptr;
2187 int freeseen;
2188 freetab_t *freetab;
2189 int i;
2190 int lastfree;
2191 int lastfree_err;
2192 xfs_dir2_leaf_entry_t *lep = NULL;
2193 xfs_ino_t lino;
2194 xfs_ino_t parent = 0;
2195 char *ptr;
2196 int stale = 0;
2197 int tag_err;
2198 __be16 *tagp;
2199 struct xfs_name xname;
2200
2201 data = iocur_top->data;
2202 block = iocur_top->data;
2203 if (be32_to_cpu(block->hdr.magic) != XFS_DIR2_BLOCK_MAGIC &&
2204 be32_to_cpu(data->hdr.magic) != XFS_DIR2_DATA_MAGIC) {
2205 if (!sflag || v)
2206 dbprintf(_("bad directory data magic # %#x for dir ino "
2207 "%lld block %d\n"),
2208 be32_to_cpu(data->hdr.magic), id->ino, dabno);
2209 error++;
2210 return NULLFSINO;
2211 }
2212 db = xfs_dir2_da_to_db(mp, dabno);
2213 bf = data->hdr.bestfree;
2214 ptr = (char *)data->u;
2215 if (be32_to_cpu(block->hdr.magic) == XFS_DIR2_BLOCK_MAGIC) {
2216 btp = xfs_dir2_block_tail_p(mp, &block->hdr);
2217 lep = xfs_dir2_block_leaf_p(btp);
2218 endptr = (char *)lep;
2219 if (endptr <= ptr || endptr > (char *)btp) {
2220 endptr = (char *)data + mp->m_dirblksize;
2221 lep = NULL;
2222 if (!sflag || v)
2223 dbprintf(_("bad block directory tail for dir ino "
2224 "%lld\n"),
2225 id->ino);
2226 error++;
2227 }
2228 } else
2229 endptr = (char *)data + mp->m_dirblksize;
2230 bf_err = lastfree_err = tag_err = 0;
2231 count = lastfree = freeseen = 0;
2232 if (be16_to_cpu(bf[0].length) == 0) {
2233 bf_err += be16_to_cpu(bf[0].offset) != 0;
2234 freeseen |= 1 << 0;
2235 }
2236 if (be16_to_cpu(bf[1].length) == 0) {
2237 bf_err += be16_to_cpu(bf[1].offset) != 0;
2238 freeseen |= 1 << 1;
2239 }
2240 if (be16_to_cpu(bf[2].length) == 0) {
2241 bf_err += be16_to_cpu(bf[2].offset) != 0;
2242 freeseen |= 1 << 2;
2243 }
2244 bf_err += be16_to_cpu(bf[0].length) < be16_to_cpu(bf[1].length);
2245 bf_err += be16_to_cpu(bf[1].length) < be16_to_cpu(bf[2].length);
2246 if (freetabp) {
2247 freetab = *freetabp;
2248 if (freetab->naents <= db) {
2249 *freetabp = freetab =
2250 realloc(freetab, FREETAB_SIZE(db + 1));
2251 for (i = freetab->naents; i < db; i++)
2252 freetab->ents[i] = NULLDATAOFF;
2253 freetab->naents = db + 1;
2254 }
2255 if (freetab->nents < db + 1)
2256 freetab->nents = db + 1;
2257 freetab->ents[db] = be16_to_cpu(bf[0].length);
2258 }
2259 while (ptr < endptr) {
2260 dup = (xfs_dir2_data_unused_t *)ptr;
2261 if (be16_to_cpu(dup->freetag) == XFS_DIR2_DATA_FREE_TAG) {
2262 lastfree_err += lastfree != 0;
2263 tagp = xfs_dir2_data_unused_tag_p(dup);
2264 if ((be16_to_cpu(dup->length) & (XFS_DIR2_DATA_ALIGN - 1)) ||
2265 be16_to_cpu(dup->length) == 0 ||
2266 (char *)tagp >= endptr) {
2267 if (!sflag || v)
2268 dbprintf(_("dir %lld block %d bad free "
2269 "entry at %d\n"),
2270 id->ino, dabno,
2271 (int)((char *)dup -
2272 (char *)data));
2273 error++;
2274 break;
2275 }
2276 tag_err += be16_to_cpu(*tagp) != (char *)dup - (char *)data;
2277 dfp = process_data_dir_v2_freefind(data, dup);
2278 if (dfp) {
2279 i = (int)(dfp - bf);
2280 bf_err += (freeseen & (1 << i)) != 0;
2281 freeseen |= 1 << i;
2282 } else
2283 bf_err += be16_to_cpu(dup->length) >
2284 be16_to_cpu(bf[2].length);
2285 ptr += be16_to_cpu(dup->length);
2286 lastfree = 1;
2287 continue;
2288 }
2289 dep = (xfs_dir2_data_entry_t *)dup;
2290 if (dep->namelen == 0) {
2291 if (!sflag || v)
2292 dbprintf(_("dir %lld block %d zero length entry "
2293 "at %d\n"),
2294 id->ino, dabno,
2295 (int)((char *)dep - (char *)data));
2296 error++;
2297 }
2298 tagp = xfs_dir2_data_entry_tag_p(dep);
2299 if ((char *)tagp >= endptr) {
2300 if (!sflag || v)
2301 dbprintf(_("dir %lld block %d bad entry at %d\n"),
2302 id->ino, dabno,
2303 (int)((char *)dep - (char *)data));
2304 error++;
2305 break;
2306 }
2307 tag_err += be16_to_cpu(*tagp) != (char *)dep - (char *)data;
2308 addr = xfs_dir2_db_off_to_dataptr(mp, db,
2309 (char *)dep - (char *)data);
2310 xname.name = dep->name;
2311 xname.len = dep->namelen;
2312 dir_hash_add(mp->m_dirnameops->hashname(&xname), addr);
2313 ptr += xfs_dir2_data_entsize(dep->namelen);
2314 count++;
2315 lastfree = 0;
2316 lino = be64_to_cpu(dep->inumber);
2317 cid = find_inode(lino, 1);
2318 if (v)
2319 dbprintf(_("dir %lld block %d entry %*.*s %lld\n"),
2320 id->ino, dabno, dep->namelen, dep->namelen,
2321 dep->name, lino);
2322 if (cid)
2323 addlink_inode(cid);
2324 else {
2325 if (!sflag || v)
2326 dbprintf(_("dir %lld block %d entry %*.*s bad "
2327 "inode number %lld\n"),
2328 id->ino, dabno, dep->namelen,
2329 dep->namelen, dep->name, lino);
2330 error++;
2331 }
2332 if (dep->namelen == 2 && dep->name[0] == '.' &&
2333 dep->name[1] == '.') {
2334 if (parent) {
2335 if (!sflag || v)
2336 dbprintf(_("multiple .. entries in dir "
2337 "%lld (%lld, %lld)\n"),
2338 id->ino, parent, lino);
2339 error++;
2340 } else
2341 parent = cid ? lino : NULLFSINO;
2342 (*dotdot)++;
2343 } else if (dep->namelen != 1 || dep->name[0] != '.') {
2344 if (cid != NULL) {
2345 if (!cid->parent)
2346 cid->parent = id;
2347 addname_inode(cid, (char *)dep->name,
2348 dep->namelen);
2349 }
2350 } else {
2351 if (lino != id->ino) {
2352 if (!sflag || v)
2353 dbprintf(_("dir %lld entry . inode "
2354 "number mismatch (%lld)\n"),
2355 id->ino, lino);
2356 error++;
2357 }
2358 (*dot)++;
2359 }
2360 }
2361 if (be32_to_cpu(data->hdr.magic) == XFS_DIR2_BLOCK_MAGIC) {
2362 endptr = (char *)data + mp->m_dirblksize;
2363 for (i = stale = 0; lep && i < be32_to_cpu(btp->count); i++) {
2364 if ((char *)&lep[i] >= endptr) {
2365 if (!sflag || v)
2366 dbprintf(_("dir %lld block %d bad count "
2367 "%u\n"), id->ino, dabno,
2368 be32_to_cpu(btp->count));
2369 error++;
2370 break;
2371 }
2372 if (be32_to_cpu(lep[i].address) == XFS_DIR2_NULL_DATAPTR)
2373 stale++;
2374 else if (dir_hash_see(be32_to_cpu(lep[i].hashval),
2375 be32_to_cpu(lep[i].address))) {
2376 if (!sflag || v)
2377 dbprintf(_("dir %lld block %d extra leaf "
2378 "entry %x %x\n"),
2379 id->ino, dabno,
2380 be32_to_cpu(lep[i].hashval),
2381 be32_to_cpu(lep[i].address));
2382 error++;
2383 }
2384 }
2385 }
2386 bf_err += freeseen != 7;
2387 if (bf_err) {
2388 if (!sflag || v)
2389 dbprintf(_("dir %lld block %d bad bestfree data\n"),
2390 id->ino, dabno);
2391 error++;
2392 }
2393 if (be32_to_cpu(data->hdr.magic) == XFS_DIR2_BLOCK_MAGIC &&
2394 count != be32_to_cpu(btp->count) -
2395 be32_to_cpu(btp->stale)) {
2396 if (!sflag || v)
2397 dbprintf(_("dir %lld block %d bad block tail count %d "
2398 "(stale %d)\n"),
2399 id->ino, dabno, be32_to_cpu(btp->count),
2400 be32_to_cpu(btp->stale));
2401 error++;
2402 }
2403 if (be32_to_cpu(data->hdr.magic) == XFS_DIR2_BLOCK_MAGIC &&
2404 stale != be32_to_cpu(btp->stale)) {
2405 if (!sflag || v)
2406 dbprintf(_("dir %lld block %d bad stale tail count %d\n"),
2407 id->ino, dabno, be32_to_cpu(btp->stale));
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 (be16_to_cpu(dup->length) < be16_to_cpu(data->hdr.
2436 bestfree[XFS_DIR2_DATA_FD_COUNT - 1].length))
2437 return NULL;
2438 for (dfp = &data->hdr.bestfree[0]; dfp < &data->hdr.
2439 bestfree[XFS_DIR2_DATA_FD_COUNT]; dfp++) {
2440 if (be16_to_cpu(dfp->offset) == 0)
2441 return NULL;
2442 if (be16_to_cpu(dfp->offset) == 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 (process_dir_v2(dip, blkmap, &dot, &dotdot, id, &parent))
2461 return;
2462
2463 bno = XFS_INO_TO_FSB(mp, id->ino);
2464 if (dot == 0) {
2465 if (!sflag || id->ilist || CHECK_BLIST(bno))
2466 dbprintf(_("no . entry for directory %lld\n"), id->ino);
2467 error++;
2468 }
2469 if (dotdot == 0) {
2470 if (!sflag || id->ilist || CHECK_BLIST(bno))
2471 dbprintf(_("no .. entry for directory %lld\n"), id->ino);
2472 error++;
2473 } else if (parent == id->ino && id->ino != mp->m_sb.sb_rootino) {
2474 if (!sflag || id->ilist || CHECK_BLIST(bno))
2475 dbprintf(_(". and .. same for non-root directory %lld\n"),
2476 id->ino);
2477 error++;
2478 } else if (id->ino == mp->m_sb.sb_rootino && id->ino != parent) {
2479 if (!sflag || id->ilist || CHECK_BLIST(bno))
2480 dbprintf(_("root directory %lld has .. %lld\n"), id->ino,
2481 parent);
2482 error++;
2483 } else if (parent != NULLFSINO && id->ino != parent)
2484 addparent_inode(id, parent);
2485 }
2486
2487 static int
2488 process_dir_v2(
2489 xfs_dinode_t *dip,
2490 blkmap_t *blkmap,
2491 int *dot,
2492 int *dotdot,
2493 inodata_t *id,
2494 xfs_ino_t *parent)
2495 {
2496 xfs_fileoff_t last = 0;
2497 xfs_fsize_t size = be64_to_cpu(dip->di_size);
2498
2499 if (blkmap)
2500 last = blkmap_last_off(blkmap);
2501 if (size <= XFS_DFORK_DSIZE(dip, mp) &&
2502 dip->di_format == XFS_DINODE_FMT_LOCAL)
2503 *parent = process_sf_dir_v2(dip, dot, dotdot, id);
2504 else if (last == mp->m_dirblkfsbs &&
2505 (dip->di_format == XFS_DINODE_FMT_EXTENTS ||
2506 dip->di_format == XFS_DINODE_FMT_BTREE))
2507 *parent = process_block_dir_v2(blkmap, dot, dotdot, id);
2508 else if (last >= mp->m_dirleafblk + mp->m_dirblkfsbs &&
2509 (dip->di_format == XFS_DINODE_FMT_EXTENTS ||
2510 dip->di_format == XFS_DINODE_FMT_BTREE))
2511 *parent = process_leaf_node_dir_v2(blkmap, dot, dotdot, id, size);
2512 else {
2513 dbprintf(_("bad size (%lld) or format (%d) for directory inode "
2514 "%lld\n"),
2515 size, dip->di_format, id->ino);
2516 error++;
2517 return 1;
2518 }
2519 return 0;
2520 }
2521
2522 /* ARGSUSED */
2523 static void
2524 process_exinode(
2525 inodata_t *id,
2526 xfs_dinode_t *dip,
2527 dbm_t type,
2528 xfs_drfsbno_t *totd,
2529 xfs_drfsbno_t *toti,
2530 xfs_extnum_t *nex,
2531 blkmap_t **blkmapp,
2532 int whichfork)
2533 {
2534 xfs_bmbt_rec_t *rp;
2535
2536 rp = (xfs_bmbt_rec_t *)XFS_DFORK_PTR(dip, whichfork);
2537 *nex = XFS_DFORK_NEXTENTS(dip, whichfork);
2538 if (*nex < 0 || *nex > XFS_DFORK_SIZE(dip, mp, whichfork) /
2539 sizeof(xfs_bmbt_rec_t)) {
2540 if (!sflag || id->ilist)
2541 dbprintf(_("bad number of extents %d for inode %lld\n"),
2542 *nex, id->ino);
2543 error++;
2544 return;
2545 }
2546 process_bmbt_reclist(rp, *nex, type, id, totd, blkmapp);
2547 }
2548
2549 static void
2550 process_inode(
2551 xfs_agf_t *agf,
2552 xfs_agino_t agino,
2553 xfs_dinode_t *dip,
2554 int isfree)
2555 {
2556 blkmap_t *blkmap;
2557 xfs_fsblock_t bno = 0;
2558 xfs_icdinode_t idic;
2559 inodata_t *id = NULL;
2560 xfs_ino_t ino;
2561 xfs_extnum_t nextents = 0;
2562 int nlink;
2563 int security;
2564 xfs_drfsbno_t totblocks;
2565 xfs_drfsbno_t totdblocks = 0;
2566 xfs_drfsbno_t totiblocks = 0;
2567 dbm_t type;
2568 xfs_extnum_t anextents = 0;
2569 xfs_drfsbno_t atotdblocks = 0;
2570 xfs_drfsbno_t atotiblocks = 0;
2571 xfs_qcnt_t bc = 0;
2572 xfs_qcnt_t ic = 0;
2573 xfs_qcnt_t rc = 0;
2574 xfs_dqid_t dqprid;
2575 int v = 0;
2576 static char okfmts[] = {
2577 0, /* type 0 unused */
2578 1 << XFS_DINODE_FMT_DEV, /* FIFO */
2579 1 << XFS_DINODE_FMT_DEV, /* CHR */
2580 0, /* type 3 unused */
2581 (1 << XFS_DINODE_FMT_LOCAL) |
2582 (1 << XFS_DINODE_FMT_EXTENTS) |
2583 (1 << XFS_DINODE_FMT_BTREE), /* DIR */
2584 0, /* type 5 unused */
2585 1 << XFS_DINODE_FMT_DEV, /* BLK */
2586 0, /* type 7 unused */
2587 (1 << XFS_DINODE_FMT_EXTENTS) |
2588 (1 << XFS_DINODE_FMT_BTREE), /* REG */
2589 0, /* type 9 unused */
2590 (1 << XFS_DINODE_FMT_LOCAL) |
2591 (1 << XFS_DINODE_FMT_EXTENTS), /* LNK */
2592 0, /* type 11 unused */
2593 1 << XFS_DINODE_FMT_DEV, /* SOCK */
2594 0, /* type 13 unused */
2595 1 << XFS_DINODE_FMT_UUID, /* MNT */
2596 0 /* type 15 unused */
2597 };
2598 static char *fmtnames[] = {
2599 "dev", "local", "extents", "btree", "uuid"
2600 };
2601
2602 libxfs_dinode_from_disk(&idic, dip);
2603
2604 ino = XFS_AGINO_TO_INO(mp, be32_to_cpu(agf->agf_seqno), agino);
2605 if (!isfree) {
2606 id = find_inode(ino, 1);
2607 bno = XFS_INO_TO_FSB(mp, ino);
2608 blkmap = NULL;
2609 }
2610 v = (!sflag || (id && id->ilist) || CHECK_BLIST(bno));
2611 if (idic.di_magic != XFS_DINODE_MAGIC) {
2612 if (isfree || v)
2613 dbprintf(_("bad magic number %#x for inode %lld\n"),
2614 idic.di_magic, ino);
2615 error++;
2616 return;
2617 }
2618 if (!XFS_DINODE_GOOD_VERSION(idic.di_version)) {
2619 if (isfree || v)
2620 dbprintf(_("bad version number %#x for inode %lld\n"),
2621 idic.di_version, ino);
2622 error++;
2623 return;
2624 }
2625 if (isfree) {
2626 if (idic.di_nblocks != 0) {
2627 if (v)
2628 dbprintf(_("bad nblocks %lld for free inode "
2629 "%lld\n"),
2630 idic.di_nblocks, ino);
2631 error++;
2632 }
2633 if (idic.di_version == 1)
2634 nlink = idic.di_onlink;
2635 else
2636 nlink = idic.di_nlink;
2637 if (nlink != 0) {
2638 if (v)
2639 dbprintf(_("bad nlink %d for free inode %lld\n"),
2640 nlink, ino);
2641 error++;
2642 }
2643 if (idic.di_mode != 0) {
2644 if (v)
2645 dbprintf(_("bad mode %#o for free inode %lld\n"),
2646 idic.di_mode, ino);
2647 error++;
2648 }
2649 return;
2650 }
2651
2652 if (be32_to_cpu(dip->di_next_unlinked) != NULLAGINO) {
2653 if (v)
2654 dbprintf(_("bad next unlinked %#x for inode %lld\n"),
2655 be32_to_cpu(dip->di_next_unlinked), ino);
2656 error++;
2657 }
2658 /*
2659 * di_mode is a 16-bit uint so no need to check the < 0 case
2660 */
2661 if ((((idic.di_mode & S_IFMT) >> 12) > 15) ||
2662 (!(okfmts[(idic.di_mode & S_IFMT) >> 12] & (1 << idic.di_format)))) {
2663 if (v)
2664 dbprintf(_("bad format %d for inode %lld type %#o\n"),
2665 idic.di_format, id->ino, idic.di_mode & S_IFMT);
2666 error++;
2667 return;
2668 }
2669 if ((unsigned int)XFS_DFORK_ASIZE(dip, mp) >= XFS_LITINO(mp)) {
2670 if (v)
2671 dbprintf(_("bad fork offset %d for inode %lld\n"),
2672 idic.di_forkoff, id->ino);
2673 error++;
2674 return;
2675 }
2676 if ((unsigned int)idic.di_aformat > XFS_DINODE_FMT_BTREE) {
2677 if (v)
2678 dbprintf(_("bad attribute format %d for inode %lld\n"),
2679 idic.di_aformat, id->ino);
2680 error++;
2681 return;
2682 }
2683 if (verbose || (id && id->ilist) || CHECK_BLIST(bno))
2684 dbprintf(_("inode %lld mode %#o fmt %s "
2685 "afmt %s "
2686 "nex %d anex %d nblk %lld sz %lld%s%s%s%s%s%s%s\n"),
2687 id->ino, idic.di_mode, fmtnames[(int)idic.di_format],
2688 fmtnames[(int)idic.di_aformat],
2689 idic.di_nextents,
2690 idic.di_anextents,
2691 idic.di_nblocks, idic.di_size,
2692 idic.di_flags & XFS_DIFLAG_REALTIME ? " rt" : "",
2693 idic.di_flags & XFS_DIFLAG_PREALLOC ? " pre" : "",
2694 idic.di_flags & XFS_DIFLAG_IMMUTABLE? " imm" : "",
2695 idic.di_flags & XFS_DIFLAG_APPEND ? " app" : "",
2696 idic.di_flags & XFS_DIFLAG_SYNC ? " syn" : "",
2697 idic.di_flags & XFS_DIFLAG_NOATIME ? " noa" : "",
2698 idic.di_flags & XFS_DIFLAG_NODUMP ? " nod" : "");
2699 security = 0;
2700 switch (idic.di_mode & S_IFMT) {
2701 case S_IFDIR:
2702 type = DBM_DIR;
2703 if (idic.di_format == XFS_DINODE_FMT_LOCAL)
2704 break;
2705 blkmap = blkmap_alloc(idic.di_nextents);
2706 break;
2707 case S_IFREG:
2708 if (idic.di_flags & XFS_DIFLAG_REALTIME)
2709 type = DBM_RTDATA;
2710 else if (id->ino == mp->m_sb.sb_rbmino) {
2711 type = DBM_RTBITMAP;
2712 blkmap = blkmap_alloc(idic.di_nextents);
2713 addlink_inode(id);
2714 } else if (id->ino == mp->m_sb.sb_rsumino) {
2715 type = DBM_RTSUM;
2716 blkmap = blkmap_alloc(idic.di_nextents);
2717 addlink_inode(id);
2718 }
2719 else if (id->ino == mp->m_sb.sb_uquotino ||
2720 id->ino == mp->m_sb.sb_gquotino) {
2721 type = DBM_QUOTA;
2722 blkmap = blkmap_alloc(idic.di_nextents);
2723 addlink_inode(id);
2724 }
2725 else
2726 type = DBM_DATA;
2727 if (idic.di_mode & (S_ISUID | S_ISGID))
2728 security = 1;
2729 break;
2730 case S_IFLNK:
2731 type = DBM_SYMLINK;
2732 break;
2733 default:
2734 security = 1;
2735 type = DBM_UNKNOWN;
2736 break;
2737 }
2738 if (idic.di_version == 1)
2739 setlink_inode(id, idic.di_onlink, type == DBM_DIR, security);
2740 else {
2741 sbversion |= XFS_SB_VERSION_NLINKBIT;
2742 setlink_inode(id, idic.di_nlink, type == DBM_DIR, security);
2743 }
2744 switch (idic.di_format) {
2745 case XFS_DINODE_FMT_LOCAL:
2746 process_lclinode(id, dip, type, &totdblocks, &totiblocks,
2747 &nextents, &blkmap, XFS_DATA_FORK);
2748 break;
2749 case XFS_DINODE_FMT_EXTENTS:
2750 process_exinode(id, dip, type, &totdblocks, &totiblocks,
2751 &nextents, &blkmap, XFS_DATA_FORK);
2752 break;
2753 case XFS_DINODE_FMT_BTREE:
2754 process_btinode(id, dip, type, &totdblocks, &totiblocks,
2755 &nextents, &blkmap, XFS_DATA_FORK);
2756 break;
2757 }
2758 if (XFS_DFORK_Q(dip)) {
2759 sbversion |= XFS_SB_VERSION_ATTRBIT;
2760 switch (idic.di_aformat) {
2761 case XFS_DINODE_FMT_LOCAL:
2762 process_lclinode(id, dip, DBM_ATTR, &atotdblocks,
2763 &atotiblocks, &anextents, NULL, XFS_ATTR_FORK);
2764 break;
2765 case XFS_DINODE_FMT_EXTENTS:
2766 process_exinode(id, dip, DBM_ATTR, &atotdblocks,
2767 &atotiblocks, &anextents, NULL, XFS_ATTR_FORK);
2768 break;
2769 case XFS_DINODE_FMT_BTREE:
2770 process_btinode(id, dip, DBM_ATTR, &atotdblocks,
2771 &atotiblocks, &anextents, NULL, XFS_ATTR_FORK);
2772 break;
2773 }
2774 }
2775 if (qgdo || qpdo || qudo) {
2776 switch (type) {
2777 case DBM_DATA:
2778 case DBM_DIR:
2779 case DBM_RTBITMAP:
2780 case DBM_RTSUM:
2781 case DBM_SYMLINK:
2782 case DBM_UNKNOWN:
2783 bc = totdblocks + totiblocks +
2784 atotdblocks + atotiblocks;
2785 ic = 1;
2786 break;
2787 case DBM_RTDATA:
2788 bc = totiblocks + atotdblocks + atotiblocks;
2789 rc = totdblocks;
2790 ic = 1;
2791 break;
2792 default:
2793 break;
2794 }
2795 if (ic) {
2796 dqprid = xfs_get_projid(&idic); /* dquot ID is u32 */
2797 quota_add(&dqprid, &idic.di_gid, &idic.di_uid,
2798 0, bc, ic, rc);
2799 }
2800 }
2801 totblocks = totdblocks + totiblocks + atotdblocks + atotiblocks;
2802 if (totblocks != idic.di_nblocks) {
2803 if (v)
2804 dbprintf(_("bad nblocks %lld for inode %lld, counted "
2805 "%lld\n"),
2806 idic.di_nblocks, id->ino, totblocks);
2807 error++;
2808 }
2809 if (nextents != idic.di_nextents) {
2810 if (v)
2811 dbprintf(_("bad nextents %d for inode %lld, counted %d\n"),
2812 idic.di_nextents, id->ino, nextents);
2813 error++;
2814 }
2815 if (anextents != idic.di_anextents) {
2816 if (v)
2817 dbprintf(_("bad anextents %d for inode %lld, counted "
2818 "%d\n"),
2819 idic.di_anextents, id->ino, anextents);
2820 error++;
2821 }
2822 if (type == DBM_DIR)
2823 process_dir(dip, blkmap, id);
2824 else if (type == DBM_RTBITMAP)
2825 process_rtbitmap(blkmap);
2826 else if (type == DBM_RTSUM)
2827 process_rtsummary(blkmap);
2828 /*
2829 * If the CHKD flag is not set, this can legitimately contain garbage;
2830 * xfs_repair may have cleared that bit.
2831 */
2832 else if (type == DBM_QUOTA) {
2833 if (id->ino == mp->m_sb.sb_uquotino &&
2834 (mp->m_sb.sb_qflags & XFS_UQUOTA_ACCT) &&
2835 (mp->m_sb.sb_qflags & XFS_UQUOTA_CHKD))
2836 process_quota(IS_USER_QUOTA, id, blkmap);
2837 else if (id->ino == mp->m_sb.sb_gquotino &&
2838 (mp->m_sb.sb_qflags & XFS_GQUOTA_ACCT) &&
2839 (mp->m_sb.sb_qflags & XFS_OQUOTA_CHKD))
2840 process_quota(IS_GROUP_QUOTA, id, blkmap);
2841 else if (id->ino == mp->m_sb.sb_gquotino &&
2842 (mp->m_sb.sb_qflags & XFS_PQUOTA_ACCT) &&
2843 (mp->m_sb.sb_qflags & XFS_OQUOTA_CHKD))
2844 process_quota(IS_PROJECT_QUOTA, id, blkmap);
2845 }
2846 if (blkmap)
2847 blkmap_free(blkmap);
2848 }
2849
2850 /* ARGSUSED */
2851 static void
2852 process_lclinode(
2853 inodata_t *id,
2854 xfs_dinode_t *dip,
2855 dbm_t type,
2856 xfs_drfsbno_t *totd,
2857 xfs_drfsbno_t *toti,
2858 xfs_extnum_t *nex,
2859 blkmap_t **blkmapp,
2860 int whichfork)
2861 {
2862 xfs_attr_shortform_t *asf;
2863 xfs_fsblock_t bno;
2864
2865 bno = XFS_INO_TO_FSB(mp, id->ino);
2866 if (whichfork == XFS_DATA_FORK && be64_to_cpu(dip->di_size) >
2867 XFS_DFORK_DSIZE(dip, mp)) {
2868 if (!sflag || id->ilist || CHECK_BLIST(bno))
2869 dbprintf(_("local inode %lld data is too large (size "
2870 "%lld)\n"),
2871 id->ino, be64_to_cpu(dip->di_size));
2872 error++;
2873 }
2874 else if (whichfork == XFS_ATTR_FORK) {
2875 asf = (xfs_attr_shortform_t *)XFS_DFORK_APTR(dip);
2876 if (be16_to_cpu(asf->hdr.totsize) > XFS_DFORK_ASIZE(dip, mp)) {
2877 if (!sflag || id->ilist || CHECK_BLIST(bno))
2878 dbprintf(_("local inode %lld attr is too large "
2879 "(size %d)\n"),
2880 id->ino, be16_to_cpu(asf->hdr.totsize));
2881 error++;
2882 }
2883 }
2884 }
2885
2886 static xfs_ino_t
2887 process_leaf_node_dir_v2(
2888 blkmap_t *blkmap,
2889 int *dot,
2890 int *dotdot,
2891 inodata_t *id,
2892 xfs_fsize_t dirsize)
2893 {
2894 xfs_fsblock_t b;
2895 bbmap_t bbmap;
2896 bmap_ext_t *bmp;
2897 xfs_fileoff_t dbno;
2898 freetab_t *freetab;
2899 int i;
2900 xfs_ino_t lino;
2901 int nex;
2902 xfs_ino_t parent;
2903 int t = 0;
2904 int v;
2905 int v2;
2906 int x;
2907
2908 v2 = verbose || id->ilist;
2909 v = parent = 0;
2910 dbno = NULLFILEOFF;
2911 freetab = malloc(FREETAB_SIZE(dirsize / mp->m_dirblksize));
2912 freetab->naents = (int)(dirsize / mp->m_dirblksize);
2913 freetab->nents = 0;
2914 for (i = 0; i < freetab->naents; i++)
2915 freetab->ents[i] = NULLDATAOFF;
2916 dir_hash_init();
2917 while ((dbno = blkmap_next_off(blkmap, dbno, &t)) != NULLFILEOFF) {
2918 nex = blkmap_getn(blkmap, dbno, mp->m_dirblkfsbs, &bmp);
2919 ASSERT(nex > 0);
2920 for (v = v2, x = 0; !v && x < nex; x++) {
2921 for (b = bmp[x].startblock;
2922 !v && b < bmp[x].startblock + bmp[x].blockcount;
2923 b++)
2924 v = CHECK_BLIST(b);
2925 }
2926 if (v)
2927 dbprintf(_("dir inode %lld block %u=%llu\n"), id->ino,
2928 (__uint32_t)dbno,
2929 (xfs_dfsbno_t)bmp->startblock);
2930 push_cur();
2931 if (nex > 1)
2932 make_bbmap(&bbmap, nex, bmp);
2933 set_cur(&typtab[TYP_DIR2], XFS_FSB_TO_DADDR(mp, bmp->startblock),
2934 mp->m_dirblkfsbs * blkbb, DB_RING_IGN,
2935 nex > 1 ? &bbmap : NULL);
2936 free(bmp);
2937 if (iocur_top->data == NULL) {
2938 if (!sflag || v)
2939 dbprintf(_("can't read block %u for directory "
2940 "inode %lld\n"),
2941 (__uint32_t)dbno, id->ino);
2942 error++;
2943 pop_cur();
2944 dbno += mp->m_dirblkfsbs - 1;
2945 continue;
2946 }
2947 if (dbno < mp->m_dirleafblk) {
2948 lino = process_data_dir_v2(dot, dotdot, id, v,
2949 (xfs_dablk_t)dbno, &freetab);
2950 if (lino) {
2951 if (parent) {
2952 if (!sflag || v)
2953 dbprintf(_("multiple .. entries "
2954 "in dir %lld\n"),
2955 id->ino);
2956 error++;
2957 } else
2958 parent = lino;
2959 }
2960 } else if (dbno < mp->m_dirfreeblk) {
2961 process_leaf_node_dir_v2_int(id, v, (xfs_dablk_t)dbno,
2962 freetab);
2963 } else {
2964 process_leaf_node_dir_v2_free(id, v, (xfs_dablk_t)dbno,
2965 freetab);
2966 }
2967 pop_cur();
2968 dbno += mp->m_dirblkfsbs - 1;
2969 }
2970 dir_hash_check(id, v);
2971 dir_hash_done();
2972 for (i = 0; i < freetab->nents; i++) {
2973 if (freetab->ents[i] != NULLDATAOFF) {
2974 if (!sflag || v)
2975 dbprintf(_("missing free index for data block %d "
2976 "in dir ino %lld\n"),
2977 xfs_dir2_db_to_da(mp, i), id->ino);
2978 error++;
2979 }
2980 }
2981 free(freetab);
2982 return parent;
2983 }
2984
2985 static void
2986 process_leaf_node_dir_v2_free(
2987 inodata_t *id,
2988 int v,
2989 xfs_dablk_t dabno,
2990 freetab_t *freetab)
2991 {
2992 xfs_dir2_data_off_t ent;
2993 xfs_dir2_free_t *free;
2994 int i;
2995 int maxent;
2996 int used;
2997
2998 free = iocur_top->data;
2999 if (be32_to_cpu(free->hdr.magic) != XFS_DIR2_FREE_MAGIC) {
3000 if (!sflag || v)
3001 dbprintf(_("bad free block magic # %#x for dir ino %lld "
3002 "block %d\n"),
3003 be32_to_cpu(free->hdr.magic), id->ino, dabno);
3004 error++;
3005 return;
3006 }
3007 maxent = xfs_dir2_free_max_bests(mp);
3008 if (be32_to_cpu(free->hdr.firstdb) != xfs_dir2_da_to_db(mp,
3009 dabno - mp->m_dirfreeblk) * maxent) {
3010 if (!sflag || v)
3011 dbprintf(_("bad free block firstdb %d for dir ino %lld "
3012 "block %d\n"),
3013 be32_to_cpu(free->hdr.firstdb), id->ino, dabno);
3014 error++;
3015 return;
3016 }
3017 if (be32_to_cpu(free->hdr.nvalid) > maxent ||
3018 be32_to_cpu(free->hdr.nvalid) < 0 ||
3019 be32_to_cpu(free->hdr.nused) > maxent ||
3020 be32_to_cpu(free->hdr.nused) < 0 ||
3021 be32_to_cpu(free->hdr.nused) >
3022 be32_to_cpu(free->hdr.nvalid)) {
3023 if (!sflag || v)
3024 dbprintf(_("bad free block nvalid/nused %d/%d for dir "
3025 "ino %lld block %d\n"),
3026 be32_to_cpu(free->hdr.nvalid),
3027 be32_to_cpu(free->hdr.nused), id->ino, dabno);
3028 error++;
3029 return;
3030 }
3031 for (used = i = 0; i < be32_to_cpu(free->hdr.nvalid); i++) {
3032 if (freetab->nents <= be32_to_cpu(free->hdr.firstdb) + i)
3033 ent = NULLDATAOFF;
3034 else
3035 ent = freetab->ents[be32_to_cpu(free->hdr.firstdb) + i];
3036 if (ent != be16_to_cpu(free->bests[i])) {
3037 if (!sflag || v)
3038 dbprintf(_("bad free block ent %d is %d should "
3039 "be %d for dir ino %lld block %d\n"),
3040 i, be16_to_cpu(free->bests[i]), ent,
3041 id->ino, dabno);
3042 error++;
3043 }
3044 if (be16_to_cpu(free->bests[i]) != NULLDATAOFF)
3045 used++;
3046 if (ent != NULLDATAOFF)
3047 freetab->ents[be32_to_cpu(free->hdr.firstdb) + i] =
3048 NULLDATAOFF;
3049 }
3050 if (used != be32_to_cpu(free->hdr.nused)) {
3051 if (!sflag || v)
3052 dbprintf(_("bad free block nused %d should be %d for dir "
3053 "ino %lld block %d\n"),
3054 be32_to_cpu(free->hdr.nused), used, id->ino,
3055 dabno);
3056 error++;
3057 }
3058 }
3059
3060 static void
3061 process_leaf_node_dir_v2_int(
3062 inodata_t *id,
3063 int v,
3064 xfs_dablk_t dabno,
3065 freetab_t *freetab)
3066 {
3067 int i;
3068 __be16 *lbp;
3069 xfs_dir2_leaf_t *leaf;
3070 xfs_dir2_leaf_entry_t *lep;
3071 xfs_dir2_leaf_tail_t *ltp;
3072 xfs_da_intnode_t *node;
3073 int stale;
3074
3075 leaf = iocur_top->data;
3076 switch (be16_to_cpu(leaf->hdr.info.magic)) {
3077 case XFS_DIR2_LEAF1_MAGIC:
3078 if (be32_to_cpu(leaf->hdr.info.forw) ||
3079 be32_to_cpu(leaf->hdr.info.back)) {
3080 if (!sflag || v)
3081 dbprintf(_("bad leaf block forw/back pointers "
3082 "%d/%d for dir ino %lld block %d\n"),
3083 be32_to_cpu(leaf->hdr.info.forw),
3084 be32_to_cpu(leaf->hdr.info.back),
3085 id->ino, dabno);
3086 error++;
3087 }
3088 if (dabno != mp->m_dirleafblk) {
3089 if (!sflag || v)
3090 dbprintf(_("single leaf block for dir ino %lld "
3091 "block %d should be at block %d\n"),
3092 id->ino, dabno,
3093 (xfs_dablk_t)mp->m_dirleafblk);
3094 error++;
3095 }
3096 ltp = xfs_dir2_leaf_tail_p(mp, leaf);
3097 lbp = xfs_dir2_leaf_bests_p(ltp);
3098 for (i = 0; i < be32_to_cpu(ltp->bestcount); i++) {
3099 if (freetab->nents <= i || freetab->ents[i] !=
3100 be16_to_cpu(lbp[i])) {
3101 if (!sflag || v)
3102 dbprintf(_("bestfree %d for dir ino %lld "
3103 "block %d doesn't match table "
3104 "value %d\n"),
3105 freetab->nents <= i ?
3106 NULLDATAOFF :
3107 freetab->ents[i],
3108 id->ino,
3109 xfs_dir2_db_to_da(mp, i),
3110 be16_to_cpu(lbp[i]));
3111 }
3112 if (freetab->nents > i)
3113 freetab->ents[i] = NULLDATAOFF;
3114 }
3115 break;
3116 case XFS_DIR2_LEAFN_MAGIC:
3117 /* if it's at the root location then we can check the
3118 * pointers are null XXX */
3119 break;
3120 case XFS_DA_NODE_MAGIC:
3121 node = iocur_top->data;
3122 if (be16_to_cpu(node->hdr.level) < 1 ||
3123 be16_to_cpu(node->hdr.level) >
3124 XFS_DA_NODE_MAXDEPTH) {
3125 if (!sflag || v)
3126 dbprintf(_("bad node block level %d for dir ino "
3127 "%lld block %d\n"),
3128 be16_to_cpu(node->hdr.level), id->ino,
3129 dabno);
3130 error++;
3131 }
3132 return;
3133 default:
3134 if (!sflag || v)
3135 dbprintf(_("bad directory data magic # %#x for dir ino "
3136 "%lld block %d\n"),
3137 be16_to_cpu(leaf->hdr.info.magic), id->ino,
3138 dabno);
3139 error++;
3140 return;
3141 }
3142 lep = leaf->ents;
3143 for (i = stale = 0; i < be16_to_cpu(leaf->hdr.count); i++) {
3144 if (be32_to_cpu(lep[i].address) == XFS_DIR2_NULL_DATAPTR)
3145 stale++;
3146 else if (dir_hash_see(be32_to_cpu(lep[i].hashval),
3147 be32_to_cpu(lep[i].address))) {
3148 if (!sflag || v)
3149 dbprintf(_("dir %lld block %d extra leaf entry "
3150 "%x %x\n"), id->ino, dabno,
3151 be32_to_cpu(lep[i].hashval),
3152 be32_to_cpu(lep[i].address));
3153 error++;
3154 }
3155 }
3156 if (stale != be16_to_cpu(leaf->hdr.stale)) {
3157 if (!sflag || v)
3158 dbprintf(_("dir %lld block %d stale mismatch "
3159 "%d/%d\n"),
3160 id->ino, dabno, stale,
3161 be16_to_cpu(leaf->hdr.stale));
3162 error++;
3163 }
3164 }
3165
3166 static void
3167 process_quota(
3168 qtype_t qtype,
3169 inodata_t *id,
3170 blkmap_t *blkmap)
3171 {
3172 xfs_fsblock_t bno;
3173 int cb;
3174 xfs_dqblk_t *dqb;
3175 xfs_dqid_t dqid;
3176 u_int8_t exp_flags = 0;
3177 uint i;
3178 uint perblock;
3179 xfs_fileoff_t qbno;
3180 char *s = NULL;
3181 int scicb;
3182 int t = 0;
3183
3184 switch (qtype) {
3185 case IS_USER_QUOTA:
3186 s = "user";
3187 exp_flags = XFS_DQ_USER;
3188 break;
3189 case IS_PROJECT_QUOTA:
3190 s = "project";
3191 exp_flags = XFS_DQ_PROJ;
3192 break;
3193 case IS_GROUP_QUOTA:
3194 s = "group";
3195 exp_flags = XFS_DQ_GROUP;
3196 break;
3197 default:
3198 ASSERT(0);
3199 }
3200
3201 perblock = (uint)(mp->m_sb.sb_blocksize / sizeof(*dqb));
3202 dqid = 0;
3203 qbno = NULLFILEOFF;
3204 while ((qbno = blkmap_next_off(blkmap, qbno, &t)) != NULLFILEOFF) {
3205 bno = blkmap_get(blkmap, qbno);
3206 dqid = (xfs_dqid_t)qbno * perblock;
3207 cb = CHECK_BLIST(bno);
3208 scicb = !sflag || id->ilist || cb;
3209 push_cur();
3210 set_cur(&typtab[TYP_DQBLK], XFS_FSB_TO_DADDR(mp, bno), blkbb,
3211 DB_RING_IGN, NULL);
3212 if ((dqb = iocur_top->data) == NULL) {
3213 if (scicb)
3214 dbprintf(_("can't read block %lld for %s quota "
3215 "inode (fsblock %lld)\n"),
3216 (xfs_dfiloff_t)qbno, s,
3217 (xfs_dfsbno_t)bno);
3218 error++;
3219 pop_cur();
3220 continue;
3221 }
3222 for (i = 0; i < perblock; i++, dqid++, dqb++) {
3223 if (verbose || id->ilist || cb)
3224 dbprintf(_("%s dqblk %lld entry %d id %u bc "
3225 "%lld ic %lld rc %lld\n"),
3226 s, (xfs_dfiloff_t)qbno, i, dqid,
3227 be64_to_cpu(dqb->dd_diskdq.d_bcount),
3228 be64_to_cpu(dqb->dd_diskdq.d_icount),
3229 be64_to_cpu(dqb->dd_diskdq.d_rtbcount));
3230 if (be16_to_cpu(dqb->dd_diskdq.d_magic) != XFS_DQUOT_MAGIC) {
3231 if (scicb)
3232 dbprintf(_("bad magic number %#x for %s "
3233 "dqblk %lld entry %d id %u\n"),
3234 be16_to_cpu(dqb->dd_diskdq.d_magic), s,
3235 (xfs_dfiloff_t)qbno, i, dqid);
3236 error++;
3237 continue;
3238 }
3239 if (dqb->dd_diskdq.d_version != XFS_DQUOT_VERSION) {
3240 if (scicb)
3241 dbprintf(_("bad version number %#x for "
3242 "%s dqblk %lld entry %d id "
3243 "%u\n"),
3244 dqb->dd_diskdq.d_version, s,
3245 (xfs_dfiloff_t)qbno, i, dqid);
3246 error++;
3247 continue;
3248 }
3249 if (dqb->dd_diskdq.d_flags != exp_flags) {
3250 if (scicb)
3251 dbprintf(_("bad flags %#x for %s dqblk "
3252 "%lld entry %d id %u\n"),
3253 dqb->dd_diskdq.d_flags, s,
3254 (xfs_dfiloff_t)qbno, i, dqid);
3255 error++;
3256 continue;
3257 }
3258 if (be32_to_cpu(dqb->dd_diskdq.d_id) != dqid) {
3259 if (scicb)
3260 dbprintf(_("bad id %u for %s dqblk %lld "
3261 "entry %d id %u\n"),
3262 be32_to_cpu(dqb->dd_diskdq.d_id), s,
3263 (xfs_dfiloff_t)qbno, i, dqid);
3264 error++;
3265 continue;
3266 }
3267 quota_add((qtype == IS_PROJECT_QUOTA) ? &dqid : NULL,
3268 (qtype == IS_GROUP_QUOTA) ? &dqid : NULL,
3269 (qtype == IS_USER_QUOTA) ? &dqid : NULL,
3270 1,
3271 be64_to_cpu(dqb->dd_diskdq.d_bcount),
3272 be64_to_cpu(dqb->dd_diskdq.d_icount),
3273 be64_to_cpu(dqb->dd_diskdq.d_rtbcount));
3274 }
3275 pop_cur();
3276 }
3277 }
3278
3279 static void
3280 process_rtbitmap(
3281 blkmap_t *blkmap)
3282 {
3283 int bit;
3284 int bitsperblock;
3285 xfs_fileoff_t bmbno;
3286 xfs_fsblock_t bno;
3287 xfs_drtbno_t extno;
3288 int len;
3289 int log;
3290 int offs;
3291 int prevbit;
3292 xfs_drfsbno_t rtbno;
3293 int start_bmbno;
3294 int start_bit;
3295 int t;
3296 xfs_rtword_t *words;
3297
3298 bitsperblock = mp->m_sb.sb_blocksize * NBBY;
3299 bit = extno = prevbit = start_bmbno = start_bit = 0;
3300 bmbno = NULLFILEOFF;
3301 while ((bmbno = blkmap_next_off(blkmap, bmbno, &t)) !=
3302 NULLFILEOFF) {
3303 bno = blkmap_get(blkmap, bmbno);
3304 if (bno == NULLFSBLOCK) {
3305 if (!sflag)
3306 dbprintf(_("block %lld for rtbitmap inode is "
3307 "missing\n"),
3308 (xfs_dfiloff_t)bmbno);
3309 error++;
3310 continue;
3311 }
3312 push_cur();
3313 set_cur(&typtab[TYP_RTBITMAP], XFS_FSB_TO_DADDR(mp, bno), blkbb,
3314 DB_RING_IGN, NULL);
3315 if ((words = iocur_top->data) == NULL) {
3316 if (!sflag)
3317 dbprintf(_("can't read block %lld for rtbitmap "
3318 "inode\n"),
3319 (xfs_dfiloff_t)bmbno);
3320 error++;
3321 pop_cur();
3322 continue;
3323 }
3324 for (bit = 0;
3325 bit < bitsperblock && extno < mp->m_sb.sb_rextents;
3326 bit++, extno++) {
3327 if (xfs_isset(words, bit)) {
3328 rtbno = extno * mp->m_sb.sb_rextsize;
3329 set_rdbmap(rtbno, mp->m_sb.sb_rextsize,
3330 DBM_RTFREE);
3331 frextents++;
3332 if (prevbit == 0) {
3333 start_bmbno = (int)bmbno;
3334 start_bit = bit;
3335 prevbit = 1;
3336 }
3337 } else if (prevbit == 1) {
3338 len = ((int)bmbno - start_bmbno) *
3339 bitsperblock + (bit - start_bit);
3340 log = XFS_RTBLOCKLOG(len);
3341 offs = XFS_SUMOFFS(mp, log, start_bmbno);
3342 sumcompute[offs]++;
3343 prevbit = 0;
3344 }
3345 }
3346 pop_cur();
3347 if (extno == mp->m_sb.sb_rextents)
3348 break;
3349 }
3350 if (prevbit == 1) {
3351 len = ((int)bmbno - start_bmbno) * bitsperblock +
3352 (bit - start_bit);
3353 log = XFS_RTBLOCKLOG(len);
3354 offs = XFS_SUMOFFS(mp, log, start_bmbno);
3355 sumcompute[offs]++;
3356 }
3357 }
3358
3359 static void
3360 process_rtsummary(
3361 blkmap_t *blkmap)
3362 {
3363 xfs_fsblock_t bno;
3364 char *bytes;
3365 xfs_fileoff_t sumbno;
3366 int t;
3367
3368 sumbno = NULLFILEOFF;
3369 while ((sumbno = blkmap_next_off(blkmap, sumbno, &t)) != NULLFILEOFF) {
3370 bno = blkmap_get(blkmap, sumbno);
3371 if (bno == NULLFSBLOCK) {
3372 if (!sflag)
3373 dbprintf(_("block %lld for rtsummary inode is "
3374 "missing\n"),
3375 (xfs_dfiloff_t)sumbno);
3376 error++;
3377 continue;
3378 }
3379 push_cur();
3380 set_cur(&typtab[TYP_RTSUMMARY], XFS_FSB_TO_DADDR(mp, bno),
3381 blkbb, DB_RING_IGN, NULL);
3382 if ((bytes = iocur_top->data) == NULL) {
3383 if (!sflag)
3384 dbprintf(_("can't read block %lld for rtsummary "
3385 "inode\n"),
3386 (xfs_dfiloff_t)sumbno);
3387 error++;
3388 pop_cur();
3389 continue;
3390 }
3391 memcpy((char *)sumfile + sumbno * mp->m_sb.sb_blocksize, bytes,
3392 mp->m_sb.sb_blocksize);
3393 pop_cur();
3394 }
3395 }
3396
3397 static xfs_ino_t
3398 process_sf_dir_v2(
3399 xfs_dinode_t *dip,
3400 int *dot,
3401 int *dotdot,
3402 inodata_t *id)
3403 {
3404 inodata_t *cid;
3405 int i;
3406 int i8;
3407 xfs_ino_t lino;
3408 int offset;
3409 xfs_dir2_sf_t *sf;
3410 xfs_dir2_sf_entry_t *sfe;
3411 int v;
3412
3413 sf = (xfs_dir2_sf_t *)XFS_DFORK_DPTR(dip);
3414 addlink_inode(id);
3415 v = verbose || id->ilist;
3416 if (v)
3417 dbprintf(_("dir %lld entry . %lld\n"), id->ino, id->ino);
3418 (*dot)++;
3419 sfe = xfs_dir2_sf_firstentry(&sf->hdr);
3420 offset = XFS_DIR2_DATA_FIRST_OFFSET;
3421 for (i = sf->hdr.count - 1, i8 = 0; i >= 0; i--) {
3422 if ((__psint_t)sfe + xfs_dir2_sf_entsize(&sf->hdr,sfe->namelen) -
3423 (__psint_t)sf > be64_to_cpu(dip->di_size)) {
3424 if (!sflag)
3425 dbprintf(_("dir %llu bad size in entry at %d\n"),
3426 id->ino,
3427 (int)((char *)sfe - (char *)sf));
3428 error++;
3429 break;
3430 }
3431 lino = xfs_dir2_sfe_get_ino(&sf->hdr, sfe);
3432 if (lino > XFS_DIR2_MAX_SHORT_INUM)
3433 i8++;
3434 cid = find_inode(lino, 1);
3435 if (cid == NULL) {
3436 if (!sflag)
3437 dbprintf(_("dir %lld entry %*.*s bad inode "
3438 "number %lld\n"),
3439 id->ino, sfe->namelen, sfe->namelen,
3440 sfe->name, lino);
3441 error++;
3442 } else {
3443 addlink_inode(cid);
3444 if (!cid->parent)
3445 cid->parent = id;
3446 addname_inode(cid, (char *)sfe->name, sfe->namelen);
3447 }
3448 if (v)
3449 dbprintf(_("dir %lld entry %*.*s offset %d %lld\n"),
3450 id->ino, sfe->namelen, sfe->namelen, sfe->name,
3451 xfs_dir2_sf_get_offset(sfe), lino);
3452 if (xfs_dir2_sf_get_offset(sfe) < offset) {
3453 if (!sflag)
3454 dbprintf(_("dir %lld entry %*.*s bad offset %d\n"),
3455 id->ino, sfe->namelen, sfe->namelen,
3456 sfe->name, xfs_dir2_sf_get_offset(sfe));
3457 error++;
3458 }
3459 offset =
3460 xfs_dir2_sf_get_offset(sfe) +
3461 xfs_dir2_sf_entsize(&sf->hdr, sfe->namelen);
3462 sfe = xfs_dir2_sf_nextentry(&sf->hdr, sfe);
3463 }
3464 if (i < 0 && (__psint_t)sfe - (__psint_t)sf !=
3465 be64_to_cpu(dip->di_size)) {
3466 if (!sflag)
3467 dbprintf(_("dir %llu size is %lld, should be %u\n"),
3468 id->ino, be64_to_cpu(dip->di_size),
3469 (uint)((char *)sfe - (char *)sf));
3470 error++;
3471 }
3472 if (offset + (sf->hdr.count + 2) * sizeof(xfs_dir2_leaf_entry_t) +
3473 sizeof(xfs_dir2_block_tail_t) > mp->m_dirblksize) {
3474 if (!sflag)
3475 dbprintf(_("dir %llu offsets too high\n"), id->ino);
3476 error++;
3477 }
3478 lino = xfs_dir2_sf_get_parent_ino(&sf->hdr);
3479 if (lino > XFS_DIR2_MAX_SHORT_INUM)
3480 i8++;
3481 cid = find_inode(lino, 1);
3482 if (cid)
3483 addlink_inode(cid);
3484 else {
3485 if (!sflag)
3486 dbprintf(_("dir %lld entry .. bad inode number %lld\n"),
3487 id->ino, lino);
3488 error++;
3489 }
3490 if (v)
3491 dbprintf(_("dir %lld entry .. %lld\n"), id->ino, lino);
3492 if (i8 != sf->hdr.i8count) {
3493 if (!sflag)
3494 dbprintf(_("dir %lld i8count mismatch is %d should be "
3495 "%d\n"),
3496 id->ino, sf->hdr.i8count, i8);
3497 error++;
3498 }
3499 (*dotdot)++;
3500 return cid ? lino : NULLFSINO;
3501 }
3502
3503
3504 static void
3505 quota_add(
3506 xfs_dqid_t *prjid,
3507 xfs_dqid_t *grpid,
3508 xfs_dqid_t *usrid,
3509 int dq,
3510 xfs_qcnt_t bc,
3511 xfs_qcnt_t ic,
3512 xfs_qcnt_t rc)
3513 {
3514 if (qudo && usrid != NULL)
3515 quota_add1(qudata, *usrid, dq, bc, ic, rc);
3516 if (qgdo && grpid != NULL)
3517 quota_add1(qgdata, *grpid, dq, bc, ic, rc);
3518 if (qpdo && prjid != NULL)
3519 quota_add1(qpdata, *prjid, dq, bc, ic, rc);
3520 }
3521
3522 static void
3523 quota_add1(
3524 qdata_t **qt,
3525 xfs_dqid_t id,
3526 int dq,
3527 xfs_qcnt_t bc,
3528 xfs_qcnt_t ic,
3529 xfs_qcnt_t rc)
3530 {
3531 qdata_t *qe;
3532 int qh;
3533 qinfo_t *qi;
3534
3535 qh = (int)(id % QDATA_HASH_SIZE);
3536 qe = qt[qh];
3537 while (qe) {
3538 if (qe->id == id) {
3539 qi = dq ? &qe->dq : &qe->count;
3540 qi->bc += bc;
3541 qi->ic += ic;
3542 qi->rc += rc;
3543 return;
3544 }
3545 qe = qe->next;
3546 }
3547 qe = xmalloc(sizeof(*qe));
3548 qe->id = id;
3549 qi = dq ? &qe->dq : &qe->count;
3550 qi->bc = bc;
3551 qi->ic = ic;
3552 qi->rc = rc;
3553 qi = dq ? &qe->count : &qe->dq;
3554 qi->bc = qi->ic = qi->rc = 0;
3555 qe->next = qt[qh];
3556 qt[qh] = qe;
3557 }
3558
3559 static void
3560 quota_check(
3561 char *s,
3562 qdata_t **qt)
3563 {
3564 int i;
3565 qdata_t *next;
3566 qdata_t *qp;
3567
3568 for (i = 0; i < QDATA_HASH_SIZE; i++) {
3569 qp = qt[i];
3570 while (qp) {
3571 next = qp->next;
3572 if (qp->count.bc != qp->dq.bc ||
3573 qp->count.ic != qp->dq.ic ||
3574 qp->count.rc != qp->dq.rc) {
3575 if (!sflag) {
3576 dbprintf(_("%s quota id %u, have/exp"),
3577 s, qp->id);
3578 if (qp->count.bc != qp->dq.bc)
3579 dbprintf(_(" bc %lld/%lld"),
3580 qp->dq.bc,
3581 qp->count.bc);
3582 if (qp->count.ic != qp->dq.ic)
3583 dbprintf(_(" ic %lld/%lld"),
3584 qp->dq.ic,
3585 qp->count.ic);
3586 if (qp->count.rc != qp->dq.rc)
3587 dbprintf(_(" rc %lld/%lld"),
3588 qp->dq.rc,
3589 qp->count.rc);
3590 dbprintf("\n");
3591 }
3592 error++;
3593 }
3594 xfree(qp);
3595 qp = next;
3596 }
3597 }
3598 xfree(qt);
3599 }
3600
3601 static void
3602 quota_init(void)
3603 {
3604 qudo = mp->m_sb.sb_uquotino != 0 &&
3605 mp->m_sb.sb_uquotino != NULLFSINO &&
3606 (mp->m_sb.sb_qflags & XFS_UQUOTA_ACCT) &&
3607 (mp->m_sb.sb_qflags & XFS_UQUOTA_CHKD);
3608 qgdo = mp->m_sb.sb_gquotino != 0 &&
3609 mp->m_sb.sb_gquotino != NULLFSINO &&
3610 (mp->m_sb.sb_qflags & XFS_GQUOTA_ACCT) &&
3611 (mp->m_sb.sb_qflags & XFS_OQUOTA_CHKD);
3612 qpdo = mp->m_sb.sb_gquotino != 0 &&
3613 mp->m_sb.sb_gquotino != NULLFSINO &&
3614 (mp->m_sb.sb_qflags & XFS_PQUOTA_ACCT) &&
3615 (mp->m_sb.sb_qflags & XFS_OQUOTA_CHKD);
3616 if (qudo)
3617 qudata = xcalloc(QDATA_HASH_SIZE, sizeof(qdata_t *));
3618 if (qgdo)
3619 qgdata = xcalloc(QDATA_HASH_SIZE, sizeof(qdata_t *));
3620 if (qpdo)
3621 qpdata = xcalloc(QDATA_HASH_SIZE, sizeof(qdata_t *));
3622 }
3623
3624 static void
3625 scan_ag(
3626 xfs_agnumber_t agno)
3627 {
3628 xfs_agf_t *agf;
3629 xfs_agi_t *agi;
3630 int i;
3631 xfs_sb_t tsb;
3632 xfs_sb_t *sb = &tsb;
3633
3634 agffreeblks = agflongest = 0;
3635 agfbtreeblks = -2;
3636 agicount = agifreecount = 0;
3637 push_cur(); /* 1 pushed */
3638 set_cur(&typtab[TYP_SB],
3639 XFS_AG_DADDR(mp, agno, XFS_SB_DADDR),
3640 XFS_FSS_TO_BB(mp, 1), DB_RING_IGN, NULL);
3641
3642 if (!iocur_top->data) {
3643 dbprintf(_("can't read superblock for ag %u\n"), agno);
3644 serious_error++;
3645 goto pop1_out;
3646 }
3647
3648 libxfs_sb_from_disk(sb, iocur_top->data);
3649
3650 if (sb->sb_magicnum != XFS_SB_MAGIC) {
3651 if (!sflag)
3652 dbprintf(_("bad sb magic # %#x in ag %u\n"),
3653 sb->sb_magicnum, agno);
3654 error++;
3655 }
3656 if (!xfs_sb_good_version(sb)) {
3657 if (!sflag)
3658 dbprintf(_("bad sb version # %#x in ag %u\n"),
3659 sb->sb_versionnum, agno);
3660 error++;
3661 sbver_err++;
3662 }
3663 if (!lazycount && xfs_sb_version_haslazysbcount(sb)) {
3664 lazycount = 1;
3665 }
3666 if (agno == 0 && sb->sb_inprogress != 0) {
3667 if (!sflag)
3668 dbprintf(_("mkfs not completed successfully\n"));
3669 error++;
3670 }
3671 set_dbmap(agno, XFS_SB_BLOCK(mp), 1, DBM_SB, agno, XFS_SB_BLOCK(mp));
3672 if (sb->sb_logstart && XFS_FSB_TO_AGNO(mp, sb->sb_logstart) == agno)
3673 set_dbmap(agno, XFS_FSB_TO_AGBNO(mp, sb->sb_logstart),
3674 sb->sb_logblocks, DBM_LOG, agno, XFS_SB_BLOCK(mp));
3675 push_cur(); /* 2 pushed */
3676 set_cur(&typtab[TYP_AGF],
3677 XFS_AG_DADDR(mp, agno, XFS_AGF_DADDR(mp)),
3678 XFS_FSS_TO_BB(mp, 1), DB_RING_IGN, NULL);
3679 if ((agf = iocur_top->data) == NULL) {
3680 dbprintf(_("can't read agf block for ag %u\n"), agno);
3681 serious_error++;
3682 goto pop2_out;
3683 }
3684 if (be32_to_cpu(agf->agf_magicnum) != XFS_AGF_MAGIC) {
3685 if (!sflag)
3686 dbprintf(_("bad agf magic # %#x in ag %u\n"),
3687 be32_to_cpu(agf->agf_magicnum), agno);
3688 error++;
3689 }
3690 if (!XFS_AGF_GOOD_VERSION(be32_to_cpu(agf->agf_versionnum))) {
3691 if (!sflag)
3692 dbprintf(_("bad agf version # %#x in ag %u\n"),
3693 be32_to_cpu(agf->agf_versionnum), agno);
3694 error++;
3695 }
3696 if (XFS_SB_BLOCK(mp) != XFS_AGF_BLOCK(mp))
3697 set_dbmap(agno, XFS_AGF_BLOCK(mp), 1, DBM_AGF, agno,
3698 XFS_SB_BLOCK(mp));
3699 if (sb->sb_agblocks > be32_to_cpu(agf->agf_length))
3700 set_dbmap(agno, be32_to_cpu(agf->agf_length),
3701 sb->sb_agblocks - be32_to_cpu(agf->agf_length),
3702 DBM_MISSING, agno, XFS_SB_BLOCK(mp));
3703 push_cur(); /* 3 pushed */
3704 set_cur(&typtab[TYP_AGI],
3705 XFS_AG_DADDR(mp, agno, XFS_AGI_DADDR(mp)),
3706 XFS_FSS_TO_BB(mp, 1), DB_RING_IGN, NULL);
3707 if ((agi = iocur_top->data) == NULL) {
3708 dbprintf(_("can't read agi block for ag %u\n"), agno);
3709 serious_error++;
3710 goto pop3_out;
3711 }
3712 if (be32_to_cpu(agi->agi_magicnum) != XFS_AGI_MAGIC) {
3713 if (!sflag)
3714 dbprintf(_("bad agi magic # %#x in ag %u\n"),
3715 be32_to_cpu(agi->agi_magicnum), agno);
3716 error++;
3717 }
3718 if (!XFS_AGI_GOOD_VERSION(be32_to_cpu(agi->agi_versionnum))) {
3719 if (!sflag)
3720 dbprintf(_("bad agi version # %#x in ag %u\n"),
3721 be32_to_cpu(agi->agi_versionnum), agno);
3722 error++;
3723 }
3724 if (XFS_SB_BLOCK(mp) != XFS_AGI_BLOCK(mp) &&
3725 XFS_AGF_BLOCK(mp) != XFS_AGI_BLOCK(mp))
3726 set_dbmap(agno, XFS_AGI_BLOCK(mp), 1, DBM_AGI, agno,
3727 XFS_SB_BLOCK(mp));
3728 scan_freelist(agf);
3729 fdblocks--;
3730 scan_sbtree(agf,
3731 be32_to_cpu(agf->agf_roots[XFS_BTNUM_BNO]),
3732 be32_to_cpu(agf->agf_levels[XFS_BTNUM_BNO]),
3733 1, scanfunc_bno, TYP_BNOBT);
3734 fdblocks--;
3735 scan_sbtree(agf,
3736 be32_to_cpu(agf->agf_roots[XFS_BTNUM_CNT]),
3737 be32_to_cpu(agf->agf_levels[XFS_BTNUM_CNT]),
3738 1, scanfunc_cnt, TYP_CNTBT);
3739 scan_sbtree(agf,
3740 be32_to_cpu(agi->agi_root),
3741 be32_to_cpu(agi->agi_level),
3742 1, scanfunc_ino, TYP_INOBT);
3743 if (be32_to_cpu(agf->agf_freeblks) != agffreeblks) {
3744 if (!sflag)
3745 dbprintf(_("agf_freeblks %u, counted %u in ag %u\n"),
3746 be32_to_cpu(agf->agf_freeblks),
3747 agffreeblks, agno);
3748 error++;
3749 }
3750 if (be32_to_cpu(agf->agf_longest) != agflongest) {
3751 if (!sflag)
3752 dbprintf(_("agf_longest %u, counted %u in ag %u\n"),
3753 be32_to_cpu(agf->agf_longest),
3754 agflongest, agno);
3755 error++;
3756 }
3757 if (lazycount &&
3758 be32_to_cpu(agf->agf_btreeblks) != agfbtreeblks) {
3759 if (!sflag)
3760 dbprintf(_("agf_btreeblks %u, counted %u in ag %u\n"),
3761 be32_to_cpu(agf->agf_btreeblks),
3762 agfbtreeblks, agno);
3763 error++;
3764 }
3765 agf_aggr_freeblks += agffreeblks + agfbtreeblks;
3766 if (be32_to_cpu(agi->agi_count) != agicount) {
3767 if (!sflag)
3768 dbprintf(_("agi_count %u, counted %u in ag %u\n"),
3769 be32_to_cpu(agi->agi_count),
3770 agicount, agno);
3771 error++;
3772 }
3773 if (be32_to_cpu(agi->agi_freecount) != agifreecount) {
3774 if (!sflag)
3775 dbprintf(_("agi_freecount %u, counted %u in ag %u\n"),
3776 be32_to_cpu(agi->agi_freecount),
3777 agifreecount, agno);
3778 error++;
3779 }
3780 for (i = 0; i < XFS_AGI_UNLINKED_BUCKETS; i++) {
3781 if (be32_to_cpu(agi->agi_unlinked[i]) != NULLAGINO) {
3782 if (!sflag) {
3783 xfs_agino_t agino=be32_to_cpu(agi->agi_unlinked[i]);
3784 dbprintf(_("agi unlinked bucket %d is %u in ag "
3785 "%u (inode=%lld)\n"), i, agino, agno,
3786 XFS_AGINO_TO_INO(mp, agno, agino));
3787 }
3788 error++;
3789 }
3790 }
3791 pop3_out:
3792 pop_cur();
3793 pop2_out:
3794 pop_cur();
3795 pop1_out:
3796 pop_cur();
3797 }
3798
3799 static void
3800 scan_freelist(
3801 xfs_agf_t *agf)
3802 {
3803 xfs_agnumber_t seqno = be32_to_cpu(agf->agf_seqno);
3804 xfs_agfl_t *agfl;
3805 xfs_agblock_t bno;
3806 uint count;
3807 int i;
3808
3809 if (XFS_SB_BLOCK(mp) != XFS_AGFL_BLOCK(mp) &&
3810 XFS_AGF_BLOCK(mp) != XFS_AGFL_BLOCK(mp) &&
3811 XFS_AGI_BLOCK(mp) != XFS_AGFL_BLOCK(mp))
3812 set_dbmap(seqno, XFS_AGFL_BLOCK(mp), 1, DBM_AGFL, seqno,
3813 XFS_SB_BLOCK(mp));
3814 if (be32_to_cpu(agf->agf_flcount) == 0)
3815 return;
3816 push_cur();
3817 set_cur(&typtab[TYP_AGFL],
3818 XFS_AG_DADDR(mp, seqno, XFS_AGFL_DADDR(mp)),
3819 XFS_FSS_TO_BB(mp, 1), DB_RING_IGN, NULL);
3820 if ((agfl = iocur_top->data) == NULL) {
3821 dbprintf(_("can't read agfl block for ag %u\n"), seqno);
3822 serious_error++;
3823 pop_cur();
3824 return;
3825 }
3826 i = be32_to_cpu(agf->agf_flfirst);
3827
3828 /* verify agf values before proceeding */
3829 if (be32_to_cpu(agf->agf_flfirst) >= XFS_AGFL_SIZE(mp) ||
3830 be32_to_cpu(agf->agf_fllast) >= XFS_AGFL_SIZE(mp)) {
3831 dbprintf(_("agf %d freelist blocks bad, skipping "
3832 "freelist scan\n"), i);
3833 pop_cur();
3834 return;
3835 }
3836
3837 count = 0;
3838 for (;;) {
3839 bno = be32_to_cpu(agfl->agfl_bno[i]);
3840 set_dbmap(seqno, bno, 1, DBM_FREELIST, seqno,
3841 XFS_AGFL_BLOCK(mp));
3842 count++;
3843 if (i == be32_to_cpu(agf->agf_fllast))
3844 break;
3845 if (++i == XFS_AGFL_SIZE(mp))
3846 i = 0;
3847 }
3848 if (count != be32_to_cpu(agf->agf_flcount)) {
3849 if (!sflag)
3850 dbprintf(_("freeblk count %u != flcount %u in ag %u\n"),
3851 count, be32_to_cpu(agf->agf_flcount),
3852 seqno);
3853 error++;
3854 }
3855 fdblocks += count;
3856 agf_aggr_freeblks += count;
3857 pop_cur();
3858 }
3859
3860 static void
3861 scan_lbtree(
3862 xfs_fsblock_t root,
3863 int nlevels,
3864 scan_lbtree_f_t func,
3865 dbm_t type,
3866 inodata_t *id,
3867 xfs_drfsbno_t *totd,
3868 xfs_drfsbno_t *toti,
3869 xfs_extnum_t *nex,
3870 blkmap_t **blkmapp,
3871 int isroot,
3872 typnm_t btype)
3873 {
3874 push_cur();
3875 set_cur(&typtab[btype], XFS_FSB_TO_DADDR(mp, root), blkbb, DB_RING_IGN,
3876 NULL);
3877 if (iocur_top->data == NULL) {
3878 if (!sflag)
3879 dbprintf(_("can't read btree block %u/%u\n"),
3880 XFS_FSB_TO_AGNO(mp, root),
3881 XFS_FSB_TO_AGBNO(mp, root));
3882 error++;
3883 pop_cur();
3884 return;
3885 }
3886 (*func)(iocur_top->data, nlevels - 1, type, root, id, totd, toti, nex,
3887 blkmapp, isroot, btype);
3888 pop_cur();
3889 }
3890
3891 static void
3892 scan_sbtree(
3893 xfs_agf_t *agf,
3894 xfs_agblock_t root,
3895 int nlevels,
3896 int isroot,
3897 scan_sbtree_f_t func,
3898 typnm_t btype)
3899 {
3900 xfs_agnumber_t seqno = be32_to_cpu(agf->agf_seqno);
3901
3902 push_cur();
3903 set_cur(&typtab[btype],
3904 XFS_AGB_TO_DADDR(mp, seqno, root), blkbb, DB_RING_IGN, NULL);
3905 if (iocur_top->data == NULL) {
3906 if (!sflag)
3907 dbprintf(_("can't read btree block %u/%u\n"), seqno, root);
3908 error++;
3909 pop_cur();
3910 return;
3911 }
3912 (*func)(iocur_top->data, nlevels - 1, agf, root, isroot);
3913 pop_cur();
3914 }
3915
3916 static void
3917 scanfunc_bmap(
3918 struct xfs_btree_block *block,
3919 int level,
3920 dbm_t type,
3921 xfs_fsblock_t bno,
3922 inodata_t *id,
3923 xfs_drfsbno_t *totd,
3924 xfs_drfsbno_t *toti,
3925 xfs_extnum_t *nex,
3926 blkmap_t **blkmapp,
3927 int isroot,
3928 typnm_t btype)
3929 {
3930 xfs_agblock_t agbno;
3931 xfs_agnumber_t agno;
3932 int i;
3933 xfs_bmbt_ptr_t *pp;
3934 xfs_bmbt_rec_t *rp;
3935
3936 agno = XFS_FSB_TO_AGNO(mp, bno);
3937 agbno = XFS_FSB_TO_AGBNO(mp, bno);
3938 if (be32_to_cpu(block->bb_magic) != XFS_BMAP_MAGIC) {
3939 if (!sflag || id->ilist || CHECK_BLIST(bno))
3940 dbprintf(_("bad magic # %#x in inode %lld bmbt block "
3941 "%u/%u\n"),
3942 be32_to_cpu(block->bb_magic), id->ino, agno, agbno);
3943 error++;
3944 }
3945 if (be16_to_cpu(block->bb_level) != level) {
3946 if (!sflag || id->ilist || CHECK_BLIST(bno))
3947 dbprintf(_("expected level %d got %d in inode %lld bmbt "
3948 "block %u/%u\n"),
3949 level, be16_to_cpu(block->bb_level), id->ino, agno, agbno);
3950 error++;
3951 }
3952 set_dbmap(agno, agbno, 1, type, agno, agbno);
3953 set_inomap(agno, agbno, 1, id);
3954 (*toti)++;
3955 if (level == 0) {
3956 if (be16_to_cpu(block->bb_numrecs) > mp->m_bmap_dmxr[0] ||
3957 (isroot == 0 && be16_to_cpu(block->bb_numrecs) < mp->m_bmap_dmnr[0])) {
3958 if (!sflag || id->ilist || CHECK_BLIST(bno))
3959 dbprintf(_("bad btree nrecs (%u, min=%u, max=%u) "
3960 "in inode %lld bmap block %lld\n"),
3961 be16_to_cpu(block->bb_numrecs), mp->m_bmap_dmnr[0],
3962 mp->m_bmap_dmxr[0], id->ino,
3963 (xfs_dfsbno_t)bno);
3964 error++;
3965 return;
3966 }
3967 rp = XFS_BMBT_REC_ADDR(mp, block, 1);
3968 *nex += be16_to_cpu(block->bb_numrecs);
3969 process_bmbt_reclist(rp, be16_to_cpu(block->bb_numrecs), type, id, totd,
3970 blkmapp);
3971 return;
3972 }
3973 if (be16_to_cpu(block->bb_numrecs) > mp->m_bmap_dmxr[1] ||
3974 (isroot == 0 && be16_to_cpu(block->bb_numrecs) < mp->m_bmap_dmnr[1])) {
3975 if (!sflag || id->ilist || CHECK_BLIST(bno))
3976 dbprintf(_("bad btree nrecs (%u, min=%u, max=%u) in "
3977 "inode %lld bmap block %lld\n"),
3978 be16_to_cpu(block->bb_numrecs), mp->m_bmap_dmnr[1],
3979 mp->m_bmap_dmxr[1], id->ino, (xfs_dfsbno_t)bno);
3980 error++;
3981 return;
3982 }
3983 pp = XFS_BMBT_PTR_ADDR(mp, block, 1, mp->m_bmap_dmxr[0]);
3984 for (i = 0; i < be16_to_cpu(block->bb_numrecs); i++)
3985 scan_lbtree(be64_to_cpu(pp[i]), level, scanfunc_bmap, type, id,
3986 totd, toti, nex, blkmapp, 0, btype);
3987 }
3988
3989 static void
3990 scanfunc_bno(
3991 struct xfs_btree_block *block,
3992 int level,
3993 xfs_agf_t *agf,
3994 xfs_agblock_t bno,
3995 int isroot)
3996 {
3997 int i;
3998 xfs_alloc_ptr_t *pp;
3999 xfs_alloc_rec_t *rp;
4000 xfs_agnumber_t seqno = be32_to_cpu(agf->agf_seqno);
4001 xfs_agblock_t lastblock;
4002
4003 if (be32_to_cpu(block->bb_magic) != XFS_ABTB_MAGIC) {
4004 dbprintf(_("bad magic # %#x in btbno block %u/%u\n"),
4005 be32_to_cpu(block->bb_magic), seqno, bno);
4006 serious_error++;
4007 return;
4008 }
4009 fdblocks++;
4010 agfbtreeblks++;
4011 if (be16_to_cpu(block->bb_level) != level) {
4012 if (!sflag)
4013 dbprintf(_("expected level %d got %d in btbno block "
4014 "%u/%u\n"),
4015 level, be16_to_cpu(block->bb_level), seqno, bno);
4016 error++;
4017 }
4018 set_dbmap(seqno, bno, 1, DBM_BTBNO, seqno, bno);
4019 if (level == 0) {
4020 if (be16_to_cpu(block->bb_numrecs) > mp->m_alloc_mxr[0] ||
4021 (isroot == 0 && be16_to_cpu(block->bb_numrecs) < mp->m_alloc_mnr[0])) {
4022 dbprintf(_("bad btree nrecs (%u, min=%u, max=%u) in "
4023 "btbno block %u/%u\n"),
4024 be16_to_cpu(block->bb_numrecs), mp->m_alloc_mnr[0],
4025 mp->m_alloc_mxr[0], seqno, bno);
4026 serious_error++;
4027 return;
4028 }
4029 rp = XFS_ALLOC_REC_ADDR(mp, block, 1);
4030 lastblock = 0;
4031 for (i = 0; i < be16_to_cpu(block->bb_numrecs); i++) {
4032 set_dbmap(seqno, be32_to_cpu(rp[i].ar_startblock),
4033 be32_to_cpu(rp[i].ar_blockcount), DBM_FREE1,
4034 seqno, bno);
4035 if (be32_to_cpu(rp[i].ar_startblock) <= lastblock) {
4036 dbprintf(_(
4037 "out-of-order bno btree record %d (%u %u) block %u/%u\n"),
4038 i, be32_to_cpu(rp[i].ar_startblock),
4039 be32_to_cpu(rp[i].ar_blockcount),
4040 be32_to_cpu(agf->agf_seqno), bno);
4041 serious_error++;
4042 } else {
4043 lastblock = be32_to_cpu(rp[i].ar_startblock);
4044 }
4045 }
4046 return;
4047 }
4048 if (be16_to_cpu(block->bb_numrecs) > mp->m_alloc_mxr[1] ||
4049 (isroot == 0 && be16_to_cpu(block->bb_numrecs) < mp->m_alloc_mnr[1])) {
4050 dbprintf(_("bad btree nrecs (%u, min=%u, max=%u) in btbno block "
4051 "%u/%u\n"),
4052 be16_to_cpu(block->bb_numrecs), mp->m_alloc_mnr[1],
4053 mp->m_alloc_mxr[1], seqno, bno);
4054 serious_error++;
4055 return;
4056 }
4057 pp = XFS_ALLOC_PTR_ADDR(mp, block, 1, mp->m_alloc_mxr[1]);
4058 for (i = 0; i < be16_to_cpu(block->bb_numrecs); i++)
4059 scan_sbtree(agf, be32_to_cpu(pp[i]), level, 0, scanfunc_bno, TYP_BNOBT);
4060 }
4061
4062 static void
4063 scanfunc_cnt(
4064 struct xfs_btree_block *block,
4065 int level,
4066 xfs_agf_t *agf,
4067 xfs_agblock_t bno,
4068 int isroot)
4069 {
4070 xfs_agnumber_t seqno = be32_to_cpu(agf->agf_seqno);
4071 int i;
4072 xfs_alloc_ptr_t *pp;
4073 xfs_alloc_rec_t *rp;
4074 xfs_extlen_t lastcount;
4075
4076 if (be32_to_cpu(block->bb_magic) != XFS_ABTC_MAGIC) {
4077 dbprintf(_("bad magic # %#x in btcnt block %u/%u\n"),
4078 be32_to_cpu(block->bb_magic), seqno, bno);
4079 serious_error++;
4080 return;
4081 }
4082 fdblocks++;
4083 agfbtreeblks++;
4084 if (be16_to_cpu(block->bb_level) != level) {
4085 if (!sflag)
4086 dbprintf(_("expected level %d got %d in btcnt block "
4087 "%u/%u\n"),
4088 level, be16_to_cpu(block->bb_level), seqno, bno);
4089 error++;
4090 }
4091 set_dbmap(seqno, bno, 1, DBM_BTCNT, seqno, bno);
4092 if (level == 0) {
4093 if (be16_to_cpu(block->bb_numrecs) > mp->m_alloc_mxr[0] ||
4094 (isroot == 0 && be16_to_cpu(block->bb_numrecs) < mp->m_alloc_mnr[0])) {
4095 dbprintf(_("bad btree nrecs (%u, min=%u, max=%u) in "
4096 "btbno block %u/%u\n"),
4097 be16_to_cpu(block->bb_numrecs), mp->m_alloc_mnr[0],
4098 mp->m_alloc_mxr[0], seqno, bno);
4099 serious_error++;
4100 return;
4101 }
4102 rp = XFS_ALLOC_REC_ADDR(mp, block, 1);
4103 lastcount = 0;
4104 for (i = 0; i < be16_to_cpu(block->bb_numrecs); i++) {
4105 check_set_dbmap(seqno, be32_to_cpu(rp[i].ar_startblock),
4106 be32_to_cpu(rp[i].ar_blockcount), DBM_FREE1, DBM_FREE2,
4107 seqno, bno);
4108 fdblocks += be32_to_cpu(rp[i].ar_blockcount);
4109 agffreeblks += be32_to_cpu(rp[i].ar_blockcount);
4110 if (be32_to_cpu(rp[i].ar_blockcount) > agflongest)
4111 agflongest = be32_to_cpu(rp[i].ar_blockcount);
4112 if (be32_to_cpu(rp[i].ar_blockcount) < lastcount) {
4113 dbprintf(_(
4114 "out-of-order cnt btree record %d (%u %u) block %u/%u\n"),
4115 i, be32_to_cpu(rp[i].ar_startblock),
4116 be32_to_cpu(rp[i].ar_blockcount),
4117 be32_to_cpu(agf->agf_seqno), bno);
4118 } else {
4119 lastcount = be32_to_cpu(rp[i].ar_blockcount);
4120 }
4121 }
4122 return;
4123 }
4124 if (be16_to_cpu(block->bb_numrecs) > mp->m_alloc_mxr[1] ||
4125 (isroot == 0 && be16_to_cpu(block->bb_numrecs) < mp->m_alloc_mnr[1])) {
4126 dbprintf(_("bad btree nrecs (%u, min=%u, max=%u) in btbno block "
4127 "%u/%u\n"),
4128 be16_to_cpu(block->bb_numrecs), mp->m_alloc_mnr[1],
4129 mp->m_alloc_mxr[1], seqno, bno);
4130 serious_error++;
4131 return;
4132 }
4133 pp = XFS_ALLOC_PTR_ADDR(mp, block, 1, mp->m_alloc_mxr[1]);
4134 for (i = 0; i < be16_to_cpu(block->bb_numrecs); i++)
4135 scan_sbtree(agf, be32_to_cpu(pp[i]), level, 0, scanfunc_cnt, TYP_CNTBT);
4136 }
4137
4138 static void
4139 scanfunc_ino(
4140 struct xfs_btree_block *block,
4141 int level,
4142 xfs_agf_t *agf,
4143 xfs_agblock_t bno,
4144 int isroot)
4145 {
4146 xfs_agino_t agino;
4147 xfs_agnumber_t seqno = be32_to_cpu(agf->agf_seqno);
4148 int i;
4149 int isfree;
4150 int j;
4151 int nfree;
4152 int off;
4153 xfs_inobt_ptr_t *pp;
4154 xfs_inobt_rec_t *rp;
4155
4156 if (be32_to_cpu(block->bb_magic) != XFS_IBT_MAGIC) {
4157 dbprintf(_("bad magic # %#x in inobt block %u/%u\n"),
4158 be32_to_cpu(block->bb_magic), seqno, bno);
4159 serious_error++;
4160 return;
4161 }
4162 if (be16_to_cpu(block->bb_level) != level) {
4163 if (!sflag)
4164 dbprintf(_("expected level %d got %d in inobt block "
4165 "%u/%u\n"),
4166 level, be16_to_cpu(block->bb_level), seqno, bno);
4167 error++;
4168 }
4169 set_dbmap(seqno, bno, 1, DBM_BTINO, seqno, bno);
4170 if (level == 0) {
4171 if (be16_to_cpu(block->bb_numrecs) > mp->m_inobt_mxr[0] ||
4172 (isroot == 0 && be16_to_cpu(block->bb_numrecs) < mp->m_inobt_mnr[0])) {
4173 dbprintf(_("bad btree nrecs (%u, min=%u, max=%u) in "
4174 "inobt block %u/%u\n"),
4175 be16_to_cpu(block->bb_numrecs), mp->m_inobt_mnr[0],
4176 mp->m_inobt_mxr[0], seqno, bno);
4177 serious_error++;
4178 return;
4179 }
4180 rp = XFS_INOBT_REC_ADDR(mp, block, 1);
4181 for (i = 0; i < be16_to_cpu(block->bb_numrecs); i++) {
4182 agino = be32_to_cpu(rp[i].ir_startino);
4183 off = XFS_INO_TO_OFFSET(mp, agino);
4184 if (off == 0) {
4185 if ((sbversion & XFS_SB_VERSION_ALIGNBIT) &&
4186 mp->m_sb.sb_inoalignmt &&
4187 (XFS_INO_TO_AGBNO(mp, agino) %
4188 mp->m_sb.sb_inoalignmt))
4189 sbversion &= ~XFS_SB_VERSION_ALIGNBIT;
4190 set_dbmap(seqno, XFS_AGINO_TO_AGBNO(mp, agino),
4191 (xfs_extlen_t)MAX(1,
4192 XFS_INODES_PER_CHUNK >>
4193 mp->m_sb.sb_inopblog),
4194 DBM_INODE, seqno, bno);
4195 }
4196 icount += XFS_INODES_PER_CHUNK;
4197 agicount += XFS_INODES_PER_CHUNK;
4198 ifree += be32_to_cpu(rp[i].ir_freecount);
4199 agifreecount += be32_to_cpu(rp[i].ir_freecount);
4200 push_cur();
4201 set_cur(&typtab[TYP_INODE],
4202 XFS_AGB_TO_DADDR(mp, seqno,
4203 XFS_AGINO_TO_AGBNO(mp, agino)),
4204 (int)XFS_FSB_TO_BB(mp, XFS_IALLOC_BLOCKS(mp)),
4205 DB_RING_IGN, NULL);
4206 if (iocur_top->data == NULL) {
4207 if (!sflag)
4208 dbprintf(_("can't read inode block "
4209 "%u/%u\n"),
4210 seqno,
4211 XFS_AGINO_TO_AGBNO(mp, agino));
4212 error++;
4213 pop_cur();
4214 continue;
4215 }
4216 for (j = 0, nfree = 0; j < XFS_INODES_PER_CHUNK; j++) {
4217 isfree = XFS_INOBT_IS_FREE_DISK(&rp[i], j);
4218 if (isfree)
4219 nfree++;
4220 process_inode(agf, agino + j,
4221 (xfs_dinode_t *)((char *)iocur_top->data + ((off + j) << mp->m_sb.sb_inodelog)),
4222 isfree);
4223 }
4224 if (nfree != be32_to_cpu(rp[i].ir_freecount)) {
4225 if (!sflag)
4226 dbprintf(_("ir_freecount/free mismatch, "
4227 "inode chunk %u/%u, freecount "
4228 "%d nfree %d\n"),
4229 seqno, agino,
4230 be32_to_cpu(rp[i].ir_freecount), nfree);
4231 error++;
4232 }
4233 pop_cur();
4234 }
4235 return;
4236 }
4237 if (be16_to_cpu(block->bb_numrecs) > mp->m_inobt_mxr[1] ||
4238 (isroot == 0 && be16_to_cpu(block->bb_numrecs) < mp->m_inobt_mnr[1])) {
4239 dbprintf(_("bad btree nrecs (%u, min=%u, max=%u) in inobt block "
4240 "%u/%u\n"),
4241 be16_to_cpu(block->bb_numrecs), mp->m_inobt_mnr[1],
4242 mp->m_inobt_mxr[1], seqno, bno);
4243 serious_error++;
4244 return;
4245 }
4246 pp = XFS_INOBT_PTR_ADDR(mp, block, 1, mp->m_inobt_mxr[1]);
4247 for (i = 0; i < be16_to_cpu(block->bb_numrecs); i++)
4248 scan_sbtree(agf, be32_to_cpu(pp[i]), level, 0, scanfunc_ino, TYP_INOBT);
4249 }
4250
4251 static void
4252 set_dbmap(
4253 xfs_agnumber_t agno,
4254 xfs_agblock_t agbno,
4255 xfs_extlen_t len,
4256 dbm_t type,
4257 xfs_agnumber_t c_agno,
4258 xfs_agblock_t c_agbno)
4259 {
4260 check_set_dbmap(agno, agbno, len, DBM_UNKNOWN, type, c_agno, c_agbno);
4261 }
4262
4263 static void
4264 set_inomap(
4265 xfs_agnumber_t agno,
4266 xfs_agblock_t agbno,
4267 xfs_extlen_t len,
4268 inodata_t *id)
4269 {
4270 xfs_extlen_t i;
4271 inodata_t **idp;
4272 int mayprint;
4273
4274 if (!check_inomap(agno, agbno, len, id->ino))
4275 return;
4276 mayprint = verbose | id->ilist | blist_size;
4277 for (i = 0, idp = &inomap[agno][agbno]; i < len; i++, idp++) {
4278 *idp = id;
4279 if (mayprint &&
4280 (verbose || id->ilist || CHECK_BLISTA(agno, agbno + i)))
4281 dbprintf(_("setting inode to %lld for block %u/%u\n"),
4282 id->ino, agno, agbno + i);
4283 }
4284 }
4285
4286 static void
4287 set_rdbmap(
4288 xfs_drfsbno_t bno,
4289 xfs_extlen_t len,
4290 dbm_t type)
4291 {
4292 check_set_rdbmap(bno, len, DBM_UNKNOWN, type);
4293 }
4294
4295 static void
4296 set_rinomap(
4297 xfs_drfsbno_t bno,
4298 xfs_extlen_t len,
4299 inodata_t *id)
4300 {
4301 xfs_extlen_t i;
4302 inodata_t **idp;
4303 int mayprint;
4304
4305 if (!check_rinomap(bno, len, id->ino))
4306 return;
4307 mayprint = verbose | id->ilist | blist_size;
4308 for (i = 0, idp = &inomap[mp->m_sb.sb_agcount][bno];
4309 i < len;
4310 i++, idp++) {
4311 *idp = id;
4312 if (mayprint && (verbose || id->ilist || CHECK_BLIST(bno + i)))
4313 dbprintf(_("setting inode to %lld for rtblock %llu\n"),
4314 id->ino, bno + i);
4315 }
4316 }
4317
4318 static void
4319 setlink_inode(
4320 inodata_t *id,
4321 nlink_t nlink,
4322 int isdir,
4323 int security)
4324 {
4325 id->link_set = nlink;
4326 id->isdir = isdir;
4327 id->security = security;
4328 if (verbose || id->ilist)
4329 dbprintf(_("inode %lld nlink %u %s dir\n"), id->ino, nlink,
4330 isdir ? "is" : "not");
4331 }