]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blob - db/check.c
libxfs: update to 3.16 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 *process_data_dir_v2_freefind(
282 struct xfs_dir2_data_hdr *data,
283 struct xfs_dir2_data_unused *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
792 /*
793 * XXX: check does not support CRC enabled filesystems. Return
794 * immediately, silently, with success but without doing anything here
795 * initially so that xfstests can run without modification on metadata
796 * enabled filesystems.
797 *
798 * XXX: ultimately we need to dump an error message here that xfstests
799 * filters out, or we need to actually do the work to make check support
800 * crc enabled filesystems.
801 */
802 if (xfs_sb_version_hascrc(&mp->m_sb))
803 return 0;
804
805 if (!init(argc, argv)) {
806 if (serious_error)
807 exitcode = 3;
808 else
809 exitcode = 1;
810 return 0;
811 }
812 oldprefix = dbprefix;
813 dbprefix |= pflag;
814 for (agno = 0, sbyell = 0; agno < mp->m_sb.sb_agcount; agno++) {
815 scan_ag(agno);
816 if (sbver_err > 4 && !sbyell && sbver_err >= agno) {
817 sbyell = 1;
818 dbprintf(_("WARNING: this may be a newer XFS "
819 "filesystem.\n"));
820 }
821 }
822 if (blist_size) {
823 xfree(blist);
824 blist = NULL;
825 blist_size = 0;
826 }
827 if (serious_error) {
828 exitcode = 2;
829 dbprefix = oldprefix;
830 return 0;
831 }
832 check_rootdir();
833 /*
834 * Check that there are no blocks either
835 * a) unaccounted for or
836 * b) bno-free but not cnt-free
837 */
838 if (!tflag) { /* are we in test mode, faking out freespace? */
839 for (agno = 0; agno < mp->m_sb.sb_agcount; agno++)
840 checknot_dbmap(agno, 0, mp->m_sb.sb_agblocks,
841 (1 << DBM_UNKNOWN) | (1 << DBM_FREE1));
842 }
843 for (agno = 0; agno < mp->m_sb.sb_agcount; agno++)
844 check_linkcounts(agno);
845 if (mp->m_sb.sb_rblocks) {
846 checknot_rdbmap(0,
847 (xfs_extlen_t)(mp->m_sb.sb_rextents *
848 mp->m_sb.sb_rextsize),
849 1 << DBM_UNKNOWN);
850 check_summary();
851 }
852 if (mp->m_sb.sb_icount != icount) {
853 if (!sflag)
854 dbprintf(_("sb_icount %lld, counted %lld\n"),
855 mp->m_sb.sb_icount, icount);
856 error++;
857 }
858 if (mp->m_sb.sb_ifree != ifree) {
859 if (!sflag)
860 dbprintf(_("sb_ifree %lld, counted %lld\n"),
861 mp->m_sb.sb_ifree, ifree);
862 error++;
863 }
864 if (mp->m_sb.sb_fdblocks != fdblocks) {
865 if (!sflag)
866 dbprintf(_("sb_fdblocks %lld, counted %lld\n"),
867 mp->m_sb.sb_fdblocks, fdblocks);
868 error++;
869 }
870 if (lazycount && mp->m_sb.sb_fdblocks != agf_aggr_freeblks) {
871 if (!sflag)
872 dbprintf(_("sb_fdblocks %lld, aggregate AGF count %lld\n"),
873 mp->m_sb.sb_fdblocks, agf_aggr_freeblks);
874 error++;
875 }
876 if (mp->m_sb.sb_frextents != frextents) {
877 if (!sflag)
878 dbprintf(_("sb_frextents %lld, counted %lld\n"),
879 mp->m_sb.sb_frextents, frextents);
880 error++;
881 }
882 if (mp->m_sb.sb_bad_features2 != 0 &&
883 mp->m_sb.sb_bad_features2 != mp->m_sb.sb_features2) {
884 if (!sflag)
885 dbprintf(_("sb_features2 (0x%x) not same as "
886 "sb_bad_features2 (0x%x)\n"),
887 mp->m_sb.sb_features2,
888 mp->m_sb.sb_bad_features2);
889 error++;
890 }
891 if ((sbversion & XFS_SB_VERSION_ATTRBIT) &&
892 !xfs_sb_version_hasattr(&mp->m_sb)) {
893 if (!sflag)
894 dbprintf(_("sb versionnum missing attr bit %x\n"),
895 XFS_SB_VERSION_ATTRBIT);
896 error++;
897 }
898 if ((sbversion & XFS_SB_VERSION_QUOTABIT) &&
899 !xfs_sb_version_hasquota(&mp->m_sb)) {
900 if (!sflag)
901 dbprintf(_("sb versionnum missing quota bit %x\n"),
902 XFS_SB_VERSION_QUOTABIT);
903 error++;
904 }
905 if (!(sbversion & XFS_SB_VERSION_ALIGNBIT) &&
906 xfs_sb_version_hasalign(&mp->m_sb)) {
907 if (!sflag)
908 dbprintf(_("sb versionnum extra align bit %x\n"),
909 XFS_SB_VERSION_ALIGNBIT);
910 error++;
911 }
912 if (qudo)
913 quota_check("user", qudata);
914 if (qpdo)
915 quota_check("project", qpdata);
916 if (qgdo)
917 quota_check("group", qgdata);
918 if (sbver_err > mp->m_sb.sb_agcount / 2)
919 dbprintf(_("WARNING: this may be a newer XFS filesystem.\n"));
920 if (error)
921 exitcode = 3;
922 dbprefix = oldprefix;
923 return 0;
924 }
925
926 typedef struct ltab {
927 int min;
928 int max;
929 } ltab_t;
930
931 static void
932 blocktrash_b(
933 xfs_agnumber_t agno,
934 xfs_agblock_t agbno,
935 dbm_t type,
936 ltab_t *ltabp,
937 int mode)
938 {
939 int bit;
940 int bitno;
941 char *buf;
942 int byte;
943 int len;
944 int mask;
945 int newbit;
946 int offset;
947 static char *modestr[] = {
948 N_("zeroed"), N_("set"), N_("flipped"), N_("randomized")
949 };
950
951 len = (int)((random() % (ltabp->max - ltabp->min + 1)) + ltabp->min);
952 offset = (int)(random() % (int)(mp->m_sb.sb_blocksize * NBBY));
953 newbit = 0;
954 push_cur();
955 set_cur(&typtab[DBM_UNKNOWN],
956 XFS_AGB_TO_DADDR(mp, agno, agbno), blkbb, DB_RING_IGN, NULL);
957 if ((buf = iocur_top->data) == NULL) {
958 dbprintf(_("can't read block %u/%u for trashing\n"), agno, agbno);
959 pop_cur();
960 return;
961 }
962 for (bitno = 0; bitno < len; bitno++) {
963 bit = (offset + bitno) % (mp->m_sb.sb_blocksize * NBBY);
964 byte = bit / NBBY;
965 bit %= NBBY;
966 mask = 1 << bit;
967 switch (mode) {
968 case 0:
969 newbit = 0;
970 break;
971 case 1:
972 newbit = 1;
973 break;
974 case 2:
975 newbit = (buf[byte] & mask) == 0;
976 break;
977 case 3:
978 newbit = (int)random() & 1;
979 break;
980 }
981 if (newbit)
982 buf[byte] |= mask;
983 else
984 buf[byte] &= ~mask;
985 }
986 write_cur();
987 pop_cur();
988 printf(_("blocktrash: %u/%u %s block %d bit%s starting %d:%d %s\n"),
989 agno, agbno, typename[type], len, len == 1 ? "" : "s",
990 offset / NBBY, offset % NBBY, modestr[mode]);
991 }
992
993 int
994 blocktrash_f(
995 int argc,
996 char **argv)
997 {
998 xfs_agblock_t agbno;
999 xfs_agnumber_t agno;
1000 xfs_drfsbno_t bi;
1001 xfs_drfsbno_t blocks;
1002 int c;
1003 int count;
1004 int done;
1005 int goodmask;
1006 int i;
1007 ltab_t *lentab;
1008 int lentablen;
1009 int max;
1010 int min;
1011 int mode;
1012 struct timeval now;
1013 char *p;
1014 xfs_drfsbno_t randb;
1015 uint seed;
1016 int sopt;
1017 int tmask;
1018
1019 if (!dbmap) {
1020 dbprintf(_("must run blockget first\n"));
1021 return 0;
1022 }
1023 optind = 0;
1024 count = 1;
1025 min = 1;
1026 max = 128 * NBBY;
1027 mode = 2;
1028 gettimeofday(&now, NULL);
1029 seed = (unsigned int)(now.tv_sec ^ now.tv_usec);
1030 sopt = 0;
1031 tmask = 0;
1032 goodmask = (1 << DBM_AGF) |
1033 (1 << DBM_AGFL) |
1034 (1 << DBM_AGI) |
1035 (1 << DBM_ATTR) |
1036 (1 << DBM_BTBMAPA) |
1037 (1 << DBM_BTBMAPD) |
1038 (1 << DBM_BTBNO) |
1039 (1 << DBM_BTCNT) |
1040 (1 << DBM_BTINO) |
1041 (1 << DBM_DIR) |
1042 (1 << DBM_INODE) |
1043 (1 << DBM_QUOTA) |
1044 (1 << DBM_RTBITMAP) |
1045 (1 << DBM_RTSUM) |
1046 (1 << DBM_SB);
1047 while ((c = getopt(argc, argv, "0123n:s:t:x:y:")) != EOF) {
1048 switch (c) {
1049 case '0':
1050 mode = 0;
1051 break;
1052 case '1':
1053 mode = 1;
1054 break;
1055 case '2':
1056 mode = 2;
1057 break;
1058 case '3':
1059 mode = 3;
1060 break;
1061 case 'n':
1062 count = (int)strtol(optarg, &p, 0);
1063 if (*p != '\0' || count <= 0) {
1064 dbprintf(_("bad blocktrash count %s\n"), optarg);
1065 return 0;
1066 }
1067 break;
1068 case 's':
1069 seed = (uint)strtoul(optarg, &p, 0);
1070 sopt = 1;
1071 break;
1072 case 't':
1073 for (i = 0; typename[i]; i++) {
1074 if (strcmp(typename[i], optarg) == 0)
1075 break;
1076 }
1077 if (!typename[i] || (((1 << i) & goodmask) == 0)) {
1078 dbprintf(_("bad blocktrash type %s\n"), optarg);
1079 return 0;
1080 }
1081 tmask |= 1 << i;
1082 break;
1083 case 'x':
1084 min = (int)strtol(optarg, &p, 0);
1085 if (*p != '\0' || min <= 0 ||
1086 min > mp->m_sb.sb_blocksize * NBBY) {
1087 dbprintf(_("bad blocktrash min %s\n"), optarg);
1088 return 0;
1089 }
1090 break;
1091 case 'y':
1092 max = (int)strtol(optarg, &p, 0);
1093 if (*p != '\0' || max <= 0 ||
1094 max > mp->m_sb.sb_blocksize * NBBY) {
1095 dbprintf(_("bad blocktrash max %s\n"), optarg);
1096 return 0;
1097 }
1098 break;
1099 default:
1100 dbprintf(_("bad option for blocktrash command\n"));
1101 return 0;
1102 }
1103 }
1104 if (min > max) {
1105 dbprintf(_("bad min/max for blocktrash command\n"));
1106 return 0;
1107 }
1108 if (tmask == 0)
1109 tmask = goodmask;
1110 lentab = xmalloc(sizeof(ltab_t));
1111 lentab->min = lentab->max = min;
1112 lentablen = 1;
1113 for (i = min + 1; i <= max; i++) {
1114 if ((i & (i - 1)) == 0) {
1115 lentab = xrealloc(lentab,
1116 sizeof(ltab_t) * (lentablen + 1));
1117 lentab[lentablen].min = lentab[lentablen].max = i;
1118 lentablen++;
1119 } else
1120 lentab[lentablen - 1].max = i;
1121 }
1122 for (blocks = 0, agno = 0; agno < mp->m_sb.sb_agcount; agno++) {
1123 for (agbno = 0, p = dbmap[agno];
1124 agbno < mp->m_sb.sb_agblocks;
1125 agbno++, p++) {
1126 if ((1 << *p) & tmask)
1127 blocks++;
1128 }
1129 }
1130 if (blocks == 0) {
1131 dbprintf(_("blocktrash: no matching blocks\n"));
1132 goto out;
1133 }
1134 if (!sopt)
1135 dbprintf(_("blocktrash: seed %u\n"), seed);
1136 srandom(seed);
1137 for (i = 0; i < count; i++) {
1138 randb = (xfs_drfsbno_t)((((__int64_t)random() << 32) |
1139 random()) % blocks);
1140 for (bi = 0, agno = 0, done = 0;
1141 !done && agno < mp->m_sb.sb_agcount;
1142 agno++) {
1143 for (agbno = 0, p = dbmap[agno];
1144 agbno < mp->m_sb.sb_agblocks;
1145 agbno++, p++) {
1146 if (!((1 << *p) & tmask))
1147 continue;
1148 if (bi++ < randb)
1149 continue;
1150 blocktrash_b(agno, agbno, (dbm_t)*p,
1151 &lentab[random() % lentablen], mode);
1152 done = 1;
1153 break;
1154 }
1155 }
1156 }
1157 out:
1158 xfree(lentab);
1159 return 0;
1160 }
1161
1162 int
1163 blockuse_f(
1164 int argc,
1165 char **argv)
1166 {
1167 xfs_agblock_t agbno;
1168 xfs_agnumber_t agno;
1169 int c;
1170 int count;
1171 xfs_agblock_t end;
1172 xfs_fsblock_t fsb;
1173 inodata_t *i;
1174 char *p;
1175 int shownames;
1176
1177 if (!dbmap) {
1178 dbprintf(_("must run blockget first\n"));
1179 return 0;
1180 }
1181 optind = 0;
1182 shownames = 0;
1183 fsb = XFS_DADDR_TO_FSB(mp, iocur_top->off >> BBSHIFT);
1184 agno = XFS_FSB_TO_AGNO(mp, fsb);
1185 end = agbno = XFS_FSB_TO_AGBNO(mp, fsb);
1186 while ((c = getopt(argc, argv, "c:n")) != EOF) {
1187 switch (c) {
1188 case 'c':
1189 count = (int)strtol(optarg, &p, 0);
1190 end = agbno + count - 1;
1191 if (*p != '\0' || count <= 0 ||
1192 end >= mp->m_sb.sb_agblocks) {
1193 dbprintf(_("bad blockuse count %s\n"), optarg);
1194 return 0;
1195 }
1196 break;
1197 case 'n':
1198 if (!nflag) {
1199 dbprintf(_("must run blockget -n first\n"));
1200 return 0;
1201 }
1202 shownames = 1;
1203 break;
1204 default:
1205 dbprintf(_("bad option for blockuse command\n"));
1206 return 0;
1207 }
1208 }
1209 while (agbno <= end) {
1210 p = &dbmap[agno][agbno];
1211 i = inomap[agno][agbno];
1212 dbprintf(_("block %llu (%u/%u) type %s"),
1213 (xfs_dfsbno_t)XFS_AGB_TO_FSB(mp, agno, agbno),
1214 agno, agbno, typename[(dbm_t)*p]);
1215 if (i) {
1216 dbprintf(_(" inode %lld"), i->ino);
1217 if (shownames && (p = inode_name(i->ino, NULL))) {
1218 dbprintf(" %s", p);
1219 xfree(p);
1220 }
1221 }
1222 dbprintf("\n");
1223 agbno++;
1224 }
1225 return 0;
1226 }
1227
1228 static int
1229 check_blist(
1230 xfs_fsblock_t bno)
1231 {
1232 int i;
1233
1234 for (i = 0; i < blist_size; i++) {
1235 if (blist[i] == bno)
1236 return 1;
1237 }
1238 return 0;
1239 }
1240
1241 static void
1242 check_dbmap(
1243 xfs_agnumber_t agno,
1244 xfs_agblock_t agbno,
1245 xfs_extlen_t len,
1246 dbm_t type)
1247 {
1248 xfs_extlen_t i;
1249 char *p;
1250
1251 for (i = 0, p = &dbmap[agno][agbno]; i < len; i++, p++) {
1252 if ((dbm_t)*p != type) {
1253 if (!sflag || CHECK_BLISTA(agno, agbno + i))
1254 dbprintf(_("block %u/%u expected type %s got "
1255 "%s\n"),
1256 agno, agbno + i, typename[type],
1257 typename[(dbm_t)*p]);
1258 error++;
1259 }
1260 }
1261 }
1262
1263 void
1264 check_init(void)
1265 {
1266 add_command(&blockfree_cmd);
1267 add_command(&blockget_cmd);
1268 if (expert_mode)
1269 add_command(&blocktrash_cmd);
1270 add_command(&blockuse_cmd);
1271 add_command(&ncheck_cmd);
1272 }
1273
1274 static int
1275 check_inomap(
1276 xfs_agnumber_t agno,
1277 xfs_agblock_t agbno,
1278 xfs_extlen_t len,
1279 xfs_ino_t c_ino)
1280 {
1281 xfs_extlen_t i;
1282 inodata_t **idp;
1283 int rval;
1284
1285 if (!check_range(agno, agbno, len)) {
1286 dbprintf(_("blocks %u/%u..%u claimed by inode %lld\n"),
1287 agno, agbno, agbno + len - 1, c_ino);
1288 return 0;
1289 }
1290 for (i = 0, rval = 1, idp = &inomap[agno][agbno]; i < len; i++, idp++) {
1291 if (*idp) {
1292 if (!sflag || (*idp)->ilist ||
1293 CHECK_BLISTA(agno, agbno + i))
1294 dbprintf(_("block %u/%u claimed by inode %lld, "
1295 "previous inum %lld\n"),
1296 agno, agbno + i, c_ino, (*idp)->ino);
1297 error++;
1298 rval = 0;
1299 }
1300 }
1301 return rval;
1302 }
1303
1304 static void
1305 check_linkcounts(
1306 xfs_agnumber_t agno)
1307 {
1308 inodata_t *ep;
1309 inodata_t **ht;
1310 int idx;
1311 char *path;
1312
1313 ht = inodata[agno];
1314 for (idx = 0; idx < inodata_hash_size; ht++, idx++) {
1315 ep = *ht;
1316 while (ep) {
1317 if (ep->link_set != ep->link_add || ep->link_set == 0) {
1318 path = inode_name(ep->ino, NULL);
1319 if (!path && ep->link_add)
1320 path = xstrdup("?");
1321 if (!sflag || ep->ilist) {
1322 if (ep->link_add)
1323 dbprintf(_("link count mismatch "
1324 "for inode %lld (name "
1325 "%s), nlink %d, "
1326 "counted %d\n"),
1327 ep->ino, path,
1328 ep->link_set,
1329 ep->link_add);
1330 else if (ep->link_set)
1331 dbprintf(_("disconnected inode "
1332 "%lld, nlink %d\n"),
1333 ep->ino, ep->link_set);
1334 else
1335 dbprintf(_("allocated inode %lld "
1336 "has 0 link count\n"),
1337 ep->ino);
1338 }
1339 if (path)
1340 xfree(path);
1341 error++;
1342 } else if (verbose || ep->ilist) {
1343 path = inode_name(ep->ino, NULL);
1344 if (path) {
1345 dbprintf(_("inode %lld name %s\n"),
1346 ep->ino, path);
1347 xfree(path);
1348 }
1349 }
1350 ep = ep->next;
1351 }
1352 }
1353
1354 }
1355
1356 static int
1357 check_range(
1358 xfs_agnumber_t agno,
1359 xfs_agblock_t agbno,
1360 xfs_extlen_t len)
1361 {
1362 xfs_extlen_t i;
1363 xfs_agblock_t low = 0;
1364 xfs_agblock_t high = 0;
1365 int valid_range = 0;
1366 int cur, prev = 0;
1367
1368 if (agno >= mp->m_sb.sb_agcount ||
1369 agbno + len - 1 >= mp->m_sb.sb_agblocks) {
1370 for (i = 0; i < len; i++) {
1371 cur = !sflag || CHECK_BLISTA(agno, agbno + i) ? 1 : 0;
1372 if (cur == 1 && prev == 0) {
1373 low = high = agbno + i;
1374 valid_range = 1;
1375 } else if (cur == 0 && prev == 0) {
1376 /* Do nothing */
1377 } else if (cur == 0 && prev == 1) {
1378 if (low == high) {
1379 dbprintf(_("block %u/%u out of range\n"),
1380 agno, low);
1381 } else {
1382 dbprintf(_("blocks %u/%u..%u "
1383 "out of range\n"),
1384 agno, low, high);
1385 }
1386 valid_range = 0;
1387 } else if (cur == 1 && prev == 1) {
1388 high = agbno + i;
1389 }
1390 prev = cur;
1391 }
1392 if (valid_range) {
1393 if (low == high) {
1394 dbprintf(_("block %u/%u out of range\n"),
1395 agno, low);
1396 } else {
1397 dbprintf(_("blocks %u/%u..%u "
1398 "out of range\n"),
1399 agno, low, high);
1400 }
1401 }
1402 error++;
1403 return 0;
1404 }
1405 return 1;
1406 }
1407
1408 static void
1409 check_rdbmap(
1410 xfs_drfsbno_t bno,
1411 xfs_extlen_t len,
1412 dbm_t type)
1413 {
1414 xfs_extlen_t i;
1415 char *p;
1416
1417 for (i = 0, p = &dbmap[mp->m_sb.sb_agcount][bno]; i < len; i++, p++) {
1418 if ((dbm_t)*p != type) {
1419 if (!sflag || CHECK_BLIST(bno + i))
1420 dbprintf(_("rtblock %llu expected type %s got "
1421 "%s\n"),
1422 bno + i, typename[type],
1423 typename[(dbm_t)*p]);
1424 error++;
1425 }
1426 }
1427 }
1428
1429 static int
1430 check_rinomap(
1431 xfs_drfsbno_t bno,
1432 xfs_extlen_t len,
1433 xfs_ino_t c_ino)
1434 {
1435 xfs_extlen_t i;
1436 inodata_t **idp;
1437 int rval;
1438
1439 if (!check_rrange(bno, len)) {
1440 dbprintf(_("rtblocks %llu..%llu claimed by inode %lld\n"),
1441 bno, bno + len - 1, c_ino);
1442 return 0;
1443 }
1444 for (i = 0, rval = 1, idp = &inomap[mp->m_sb.sb_agcount][bno];
1445 i < len;
1446 i++, idp++) {
1447 if (*idp) {
1448 if (!sflag || (*idp)->ilist || CHECK_BLIST(bno + i))
1449 dbprintf(_("rtblock %llu claimed by inode %lld, "
1450 "previous inum %lld\n"),
1451 bno + i, c_ino, (*idp)->ino);
1452 error++;
1453 rval = 0;
1454 }
1455 }
1456 return rval;
1457 }
1458
1459 static void
1460 check_rootdir(void)
1461 {
1462 inodata_t *id;
1463
1464 id = find_inode(mp->m_sb.sb_rootino, 0);
1465 if (id == NULL) {
1466 if (!sflag)
1467 dbprintf(_("root inode %lld is missing\n"),
1468 mp->m_sb.sb_rootino);
1469 error++;
1470 } else if (!id->isdir) {
1471 if (!sflag || id->ilist)
1472 dbprintf(_("root inode %lld is not a directory\n"),
1473 mp->m_sb.sb_rootino);
1474 error++;
1475 }
1476 }
1477
1478 static int
1479 check_rrange(
1480 xfs_drfsbno_t bno,
1481 xfs_extlen_t len)
1482 {
1483 xfs_extlen_t i;
1484
1485 if (bno + len - 1 >= mp->m_sb.sb_rblocks) {
1486 for (i = 0; i < len; i++) {
1487 if (!sflag || CHECK_BLIST(bno + i))
1488 dbprintf(_("rtblock %llu out of range\n"),
1489 bno + i);
1490 }
1491 error++;
1492 return 0;
1493 }
1494 return 1;
1495 }
1496
1497 static void
1498 check_set_dbmap(
1499 xfs_agnumber_t agno,
1500 xfs_agblock_t agbno,
1501 xfs_extlen_t len,
1502 dbm_t type1,
1503 dbm_t type2,
1504 xfs_agnumber_t c_agno,
1505 xfs_agblock_t c_agbno)
1506 {
1507 xfs_extlen_t i;
1508 int mayprint;
1509 char *p;
1510
1511 if (!check_range(agno, agbno, len)) {
1512 dbprintf(_("blocks %u/%u..%u claimed by block %u/%u\n"), agno,
1513 agbno, agbno + len - 1, c_agno, c_agbno);
1514 return;
1515 }
1516 check_dbmap(agno, agbno, len, type1);
1517 mayprint = verbose | blist_size;
1518 for (i = 0, p = &dbmap[agno][agbno]; i < len; i++, p++) {
1519 *p = (char)type2;
1520 if (mayprint && (verbose || CHECK_BLISTA(agno, agbno + i)))
1521 dbprintf(_("setting block %u/%u to %s\n"), agno, agbno + i,
1522 typename[type2]);
1523 }
1524 }
1525
1526 static void
1527 check_set_rdbmap(
1528 xfs_drfsbno_t bno,
1529 xfs_extlen_t len,
1530 dbm_t type1,
1531 dbm_t type2)
1532 {
1533 xfs_extlen_t i;
1534 int mayprint;
1535 char *p;
1536
1537 if (!check_rrange(bno, len))
1538 return;
1539 check_rdbmap(bno, len, type1);
1540 mayprint = verbose | blist_size;
1541 for (i = 0, p = &dbmap[mp->m_sb.sb_agcount][bno]; i < len; i++, p++) {
1542 *p = (char)type2;
1543 if (mayprint && (verbose || CHECK_BLIST(bno + i)))
1544 dbprintf(_("setting rtblock %llu to %s\n"),
1545 bno + i, typename[type2]);
1546 }
1547 }
1548
1549 static void
1550 check_summary(void)
1551 {
1552 xfs_drfsbno_t bno;
1553 xfs_suminfo_t *csp;
1554 xfs_suminfo_t *fsp;
1555 int log;
1556
1557 csp = sumcompute;
1558 fsp = sumfile;
1559 for (log = 0; log < mp->m_rsumlevels; log++) {
1560 for (bno = 0;
1561 bno < mp->m_sb.sb_rbmblocks;
1562 bno++, csp++, fsp++) {
1563 if (*csp != *fsp) {
1564 if (!sflag)
1565 dbprintf(_("rt summary mismatch, size %d "
1566 "block %llu, file: %d, "
1567 "computed: %d\n"),
1568 log, bno, *fsp, *csp);
1569 error++;
1570 }
1571 }
1572 }
1573 }
1574
1575 static void
1576 checknot_dbmap(
1577 xfs_agnumber_t agno,
1578 xfs_agblock_t agbno,
1579 xfs_extlen_t len,
1580 int typemask)
1581 {
1582 xfs_extlen_t i;
1583 char *p;
1584
1585 if (!check_range(agno, agbno, len))
1586 return;
1587 for (i = 0, p = &dbmap[agno][agbno]; i < len; i++, p++) {
1588 if ((1 << *p) & typemask) {
1589 if (!sflag || CHECK_BLISTA(agno, agbno + i))
1590 dbprintf(_("block %u/%u type %s not expected\n"),
1591 agno, agbno + i, typename[(dbm_t)*p]);
1592 error++;
1593 }
1594 }
1595 }
1596
1597 static void
1598 checknot_rdbmap(
1599 xfs_drfsbno_t bno,
1600 xfs_extlen_t len,
1601 int typemask)
1602 {
1603 xfs_extlen_t i;
1604 char *p;
1605
1606 if (!check_rrange(bno, len))
1607 return;
1608 for (i = 0, p = &dbmap[mp->m_sb.sb_agcount][bno]; i < len; i++, p++) {
1609 if ((1 << *p) & typemask) {
1610 if (!sflag || CHECK_BLIST(bno + i))
1611 dbprintf(_("rtblock %llu type %s not expected\n"),
1612 bno + i, typename[(dbm_t)*p]);
1613 error++;
1614 }
1615 }
1616 }
1617
1618 static void
1619 dir_hash_add(
1620 xfs_dahash_t hash,
1621 xfs_dir2_dataptr_t addr)
1622 {
1623 int i;
1624 dirhash_t *p;
1625
1626 i = DIR_HASH_FUNC(hash, addr);
1627 p = malloc(sizeof(*p));
1628 p->next = dirhash[i];
1629 dirhash[i] = p;
1630 p->hashval = hash;
1631 p->address = addr;
1632 p->seen = 0;
1633 }
1634
1635 static void
1636 dir_hash_check(
1637 inodata_t *id,
1638 int v)
1639 {
1640 int i;
1641 dirhash_t *p;
1642
1643 for (i = 0; i < DIR_HASH_SIZE; i++) {
1644 for (p = dirhash[i]; p; p = p->next) {
1645 if (p->seen)
1646 continue;
1647 if (!sflag || id->ilist || v)
1648 dbprintf(_("dir ino %lld missing leaf entry for "
1649 "%x/%x\n"),
1650 id->ino, p->hashval, p->address);
1651 error++;
1652 }
1653 }
1654 }
1655
1656 static void
1657 dir_hash_done(void)
1658 {
1659 int i;
1660 dirhash_t *n;
1661 dirhash_t *p;
1662
1663 for (i = 0; i < DIR_HASH_SIZE; i++) {
1664 for (p = dirhash[i]; p; p = n) {
1665 n = p->next;
1666 free(p);
1667 }
1668 dirhash[i] = NULL;
1669 }
1670 }
1671
1672 static void
1673 dir_hash_init(void)
1674 {
1675 if (!dirhash)
1676 dirhash = calloc(DIR_HASH_SIZE, sizeof(*dirhash));
1677 }
1678
1679 static int
1680 dir_hash_see(
1681 xfs_dahash_t hash,
1682 xfs_dir2_dataptr_t addr)
1683 {
1684 int i;
1685 dirhash_t *p;
1686
1687 i = DIR_HASH_FUNC(hash, addr);
1688 for (p = dirhash[i]; p; p = p->next) {
1689 if (p->hashval == hash && p->address == addr) {
1690 if (p->seen)
1691 return 1;
1692 p->seen = 1;
1693 return 0;
1694 }
1695 }
1696 return -1;
1697 }
1698
1699 static inodata_t *
1700 find_inode(
1701 xfs_ino_t ino,
1702 int add)
1703 {
1704 xfs_agino_t agino;
1705 xfs_agnumber_t agno;
1706 inodata_t *ent;
1707 inodata_t **htab;
1708 xfs_agino_t ih;
1709
1710 agno = XFS_INO_TO_AGNO(mp, ino);
1711 agino = XFS_INO_TO_AGINO(mp, ino);
1712 if (agno >= mp->m_sb.sb_agcount ||
1713 XFS_AGINO_TO_INO(mp, agno, agino) != ino)
1714 return NULL;
1715 htab = inodata[agno];
1716 ih = agino % inodata_hash_size;
1717 ent = htab[ih];
1718 while (ent) {
1719 if (ent->ino == ino)
1720 return ent;
1721 ent = ent->next;
1722 }
1723 if (!add)
1724 return NULL;
1725 ent = xcalloc(1, sizeof(*ent));
1726 ent->ino = ino;
1727 ent->next = htab[ih];
1728 htab[ih] = ent;
1729 return ent;
1730 }
1731
1732 static void
1733 free_inodata(
1734 xfs_agnumber_t agno)
1735 {
1736 inodata_t *hp;
1737 inodata_t **ht;
1738 int i;
1739 inodata_t *next;
1740
1741 ht = inodata[agno];
1742 for (i = 0; i < inodata_hash_size; i++) {
1743 hp = ht[i];
1744 while (hp) {
1745 next = hp->next;
1746 if (hp->name)
1747 xfree(hp->name);
1748 xfree(hp);
1749 hp = next;
1750 }
1751 }
1752 xfree(ht);
1753 }
1754
1755 static int
1756 init(
1757 int argc,
1758 char **argv)
1759 {
1760 xfs_fsblock_t bno;
1761 int c;
1762 xfs_ino_t ino;
1763 int rt;
1764
1765 serious_error = 0;
1766 if (mp->m_sb.sb_magicnum != XFS_SB_MAGIC) {
1767 dbprintf(_("bad superblock magic number %x, giving up\n"),
1768 mp->m_sb.sb_magicnum);
1769 serious_error = 1;
1770 return 0;
1771 }
1772 if (!sb_logcheck())
1773 return 0;
1774 rt = mp->m_sb.sb_rextents != 0;
1775 dbmap = xmalloc((mp->m_sb.sb_agcount + rt) * sizeof(*dbmap));
1776 inomap = xmalloc((mp->m_sb.sb_agcount + rt) * sizeof(*inomap));
1777 inodata = xmalloc(mp->m_sb.sb_agcount * sizeof(*inodata));
1778 inodata_hash_size =
1779 (int)MAX(MIN(mp->m_sb.sb_icount /
1780 (INODATA_AVG_HASH_LENGTH * mp->m_sb.sb_agcount),
1781 MAX_INODATA_HASH_SIZE),
1782 MIN_INODATA_HASH_SIZE);
1783 for (c = 0; c < mp->m_sb.sb_agcount; c++) {
1784 dbmap[c] = xcalloc(mp->m_sb.sb_agblocks, sizeof(**dbmap));
1785 inomap[c] = xcalloc(mp->m_sb.sb_agblocks, sizeof(**inomap));
1786 inodata[c] = xcalloc(inodata_hash_size, sizeof(**inodata));
1787 }
1788 if (rt) {
1789 dbmap[c] = xcalloc(mp->m_sb.sb_rblocks, sizeof(**dbmap));
1790 inomap[c] = xcalloc(mp->m_sb.sb_rblocks, sizeof(**inomap));
1791 sumfile = xcalloc(mp->m_rsumsize, 1);
1792 sumcompute = xcalloc(mp->m_rsumsize, 1);
1793 }
1794 nflag = sflag = tflag = verbose = optind = 0;
1795 while ((c = getopt(argc, argv, "b:i:npstv")) != EOF) {
1796 switch (c) {
1797 case 'b':
1798 bno = strtoll(optarg, NULL, 10);
1799 add_blist(bno);
1800 break;
1801 case 'i':
1802 ino = strtoll(optarg, NULL, 10);
1803 add_ilist(ino);
1804 break;
1805 case 'n':
1806 nflag = 1;
1807 break;
1808 case 'p':
1809 pflag = 1;
1810 break;
1811 case 's':
1812 sflag = 1;
1813 break;
1814 case 't':
1815 tflag = 1;
1816 break;
1817 case 'v':
1818 verbose = 1;
1819 break;
1820 default:
1821 dbprintf(_("bad option for blockget command\n"));
1822 return 0;
1823 }
1824 }
1825 error = sbver_err = serious_error = 0;
1826 fdblocks = frextents = icount = ifree = 0;
1827 sbversion = XFS_SB_VERSION_4;
1828 /*
1829 * Note that inoalignmt == 0 is valid when fsb size is large enough for
1830 * at least one full inode record per block. Check this case explicitly.
1831 */
1832 if (mp->m_sb.sb_inoalignmt ||
1833 (xfs_sb_version_hasalign(&mp->m_sb) &&
1834 mp->m_sb.sb_inopblock >= XFS_INODES_PER_CHUNK))
1835 sbversion |= XFS_SB_VERSION_ALIGNBIT;
1836 if ((mp->m_sb.sb_uquotino && mp->m_sb.sb_uquotino != NULLFSINO) ||
1837 (mp->m_sb.sb_gquotino && mp->m_sb.sb_gquotino != NULLFSINO) ||
1838 (mp->m_sb.sb_pquotino && mp->m_sb.sb_pquotino != NULLFSINO))
1839 sbversion |= XFS_SB_VERSION_QUOTABIT;
1840 quota_init();
1841 return 1;
1842 }
1843
1844 static char *
1845 inode_name(
1846 xfs_ino_t ino,
1847 inodata_t **ipp)
1848 {
1849 inodata_t *id;
1850 char *npath;
1851 char *path;
1852
1853 id = find_inode(ino, 0);
1854 if (ipp)
1855 *ipp = id;
1856 if (id == NULL)
1857 return NULL;
1858 if (id->name == NULL)
1859 return NULL;
1860 path = xstrdup(id->name);
1861 while (id->parent) {
1862 id = id->parent;
1863 if (id->name == NULL)
1864 break;
1865 npath = prepend_path(path, id->name);
1866 xfree(path);
1867 path = npath;
1868 }
1869 return path;
1870 }
1871
1872 static int
1873 ncheck_f(
1874 int argc,
1875 char **argv)
1876 {
1877 xfs_agnumber_t agno;
1878 int c;
1879 inodata_t *hp;
1880 inodata_t **ht;
1881 int i;
1882 inodata_t *id;
1883 xfs_ino_t *ilist;
1884 int ilist_size;
1885 xfs_ino_t *ilp;
1886 xfs_ino_t ino;
1887 char *p;
1888 int security;
1889
1890 if (!inodata || !nflag) {
1891 dbprintf(_("must run blockget -n first\n"));
1892 return 0;
1893 }
1894 security = optind = ilist_size = 0;
1895 ilist = NULL;
1896 while ((c = getopt(argc, argv, "i:s")) != EOF) {
1897 switch (c) {
1898 case 'i':
1899 ino = strtoll(optarg, NULL, 10);
1900 ilist = xrealloc(ilist, (ilist_size + 1) *
1901 sizeof(*ilist));
1902 ilist[ilist_size++] = ino;
1903 break;
1904 case 's':
1905 security = 1;
1906 break;
1907 default:
1908 dbprintf(_("bad option -%c for ncheck command\n"), c);
1909 xfree(ilist);
1910 return 0;
1911 }
1912 }
1913 if (ilist) {
1914 for (ilp = ilist; ilp < &ilist[ilist_size]; ilp++) {
1915 ino = *ilp;
1916 if ((p = inode_name(ino, &hp))) {
1917 dbprintf("%11llu %s", ino, p);
1918 if (hp->isdir)
1919 dbprintf("/.");
1920 dbprintf("\n");
1921 xfree(p);
1922 }
1923 }
1924 xfree(ilist);
1925 return 0;
1926 }
1927 for (agno = 0; agno < mp->m_sb.sb_agcount; agno++) {
1928 ht = inodata[agno];
1929 for (i = 0; i < inodata_hash_size; i++) {
1930 hp = ht[i];
1931 for (hp = ht[i]; hp; hp = hp->next) {
1932 ino = XFS_AGINO_TO_INO(mp, agno, hp->ino);
1933 p = inode_name(ino, &id);
1934 if (!p || !id)
1935 continue;
1936 if (!security || id->security) {
1937 dbprintf("%11llu %s", ino, p);
1938 if (hp->isdir)
1939 dbprintf("/.");
1940 dbprintf("\n");
1941 }
1942 xfree(p);
1943 }
1944 }
1945 }
1946 return 0;
1947 }
1948
1949 static char *
1950 prepend_path(
1951 char *oldpath,
1952 char *parent)
1953 {
1954 int len;
1955 char *path;
1956
1957 len = (int)(strlen(oldpath) + strlen(parent) + 2);
1958 path = xmalloc(len);
1959 snprintf(path, len, "%s/%s", parent, oldpath);
1960 return path;
1961 }
1962
1963 static xfs_ino_t
1964 process_block_dir_v2(
1965 blkmap_t *blkmap,
1966 int *dot,
1967 int *dotdot,
1968 inodata_t *id)
1969 {
1970 xfs_fsblock_t b;
1971 bbmap_t bbmap;
1972 bmap_ext_t *bmp;
1973 int nex;
1974 xfs_ino_t parent;
1975 int v;
1976 int x;
1977
1978 nex = blkmap_getn(blkmap, 0, mp->m_dir_geo->fsbcount, &bmp);
1979 v = id->ilist || verbose;
1980 if (nex == 0) {
1981 if (!sflag || v)
1982 dbprintf(_("block 0 for directory inode %lld is "
1983 "missing\n"),
1984 id->ino);
1985 error++;
1986 return 0;
1987 }
1988 push_cur();
1989 if (nex > 1)
1990 make_bbmap(&bbmap, nex, bmp);
1991 set_cur(&typtab[TYP_DIR2], XFS_FSB_TO_DADDR(mp, bmp->startblock),
1992 mp->m_dir_geo->fsbcount * blkbb, DB_RING_IGN, nex > 1 ? &bbmap : NULL);
1993 for (x = 0; !v && x < nex; x++) {
1994 for (b = bmp[x].startblock;
1995 !v && b < bmp[x].startblock + bmp[x].blockcount;
1996 b++)
1997 v = CHECK_BLIST(b);
1998 }
1999 free(bmp);
2000 if (iocur_top->data == NULL) {
2001 if (!sflag || id->ilist || v)
2002 dbprintf(_("can't read block 0 for directory inode "
2003 "%lld\n"),
2004 id->ino);
2005 error++;
2006 pop_cur();
2007 return 0;
2008 }
2009 dir_hash_init();
2010 parent = process_data_dir_v2(dot, dotdot, id, v, mp->m_dir_geo->datablk,
2011 NULL);
2012 dir_hash_check(id, v);
2013 dir_hash_done();
2014 pop_cur();
2015 return parent;
2016 }
2017
2018 static void
2019 process_bmbt_reclist(
2020 xfs_bmbt_rec_t *rp,
2021 int numrecs,
2022 dbm_t type,
2023 inodata_t *id,
2024 xfs_drfsbno_t *tot,
2025 blkmap_t **blkmapp)
2026 {
2027 xfs_agblock_t agbno;
2028 xfs_agnumber_t agno;
2029 xfs_fsblock_t b;
2030 xfs_dfilblks_t c;
2031 xfs_dfilblks_t cp;
2032 int f;
2033 int i;
2034 xfs_agblock_t iagbno;
2035 xfs_agnumber_t iagno;
2036 xfs_dfiloff_t o;
2037 xfs_dfiloff_t op;
2038 xfs_dfsbno_t s;
2039 int v;
2040
2041 cp = op = 0;
2042 v = verbose || id->ilist;
2043 iagno = XFS_INO_TO_AGNO(mp, id->ino);
2044 iagbno = XFS_INO_TO_AGBNO(mp, id->ino);
2045 for (i = 0; i < numrecs; i++, rp++) {
2046 convert_extent(rp, &o, &s, &c, &f);
2047 if (v)
2048 dbprintf(_("inode %lld extent [%lld,%lld,%lld,%d]\n"),
2049 id->ino, o, s, c, f);
2050 if (!sflag && i > 0 && op + cp > o)
2051 dbprintf(_("bmap rec out of order, inode %lld entry %d\n"),
2052 id->ino, i);
2053 op = o;
2054 cp = c;
2055 if (type == DBM_RTDATA) {
2056 if (!sflag && s >= mp->m_sb.sb_rblocks) {
2057 dbprintf(_("inode %lld bad rt block number %lld, "
2058 "offset %lld\n"),
2059 id->ino, s, o);
2060 continue;
2061 }
2062 } else if (!sflag) {
2063 agno = XFS_FSB_TO_AGNO(mp, s);
2064 agbno = XFS_FSB_TO_AGBNO(mp, s);
2065 if (agno >= mp->m_sb.sb_agcount ||
2066 agbno >= mp->m_sb.sb_agblocks) {
2067 dbprintf(_("inode %lld bad block number %lld "
2068 "[%d,%d], offset %lld\n"),
2069 id->ino, s, agno, agbno, o);
2070 continue;
2071 }
2072 if (agbno + c - 1 >= mp->m_sb.sb_agblocks) {
2073 dbprintf(_("inode %lld bad block number %lld "
2074 "[%d,%d], offset %lld\n"),
2075 id->ino, s + c - 1, agno,
2076 agbno + (xfs_agblock_t)c - 1, o);
2077 continue;
2078 }
2079 }
2080 if (blkmapp && *blkmapp)
2081 blkmap_set_ext(blkmapp, (xfs_fileoff_t)o,
2082 (xfs_fsblock_t)s, (xfs_extlen_t)c);
2083 if (type == DBM_RTDATA) {
2084 set_rdbmap((xfs_fsblock_t)s, (xfs_extlen_t)c,
2085 DBM_RTDATA);
2086 set_rinomap((xfs_fsblock_t)s, (xfs_extlen_t)c, id);
2087 for (b = (xfs_fsblock_t)s;
2088 blist_size && b < s + c;
2089 b++, o++) {
2090 if (CHECK_BLIST(b))
2091 dbprintf(_("inode %lld block %lld at "
2092 "offset %lld\n"),
2093 id->ino, (xfs_dfsbno_t)b, o);
2094 }
2095 } else {
2096 agno = XFS_FSB_TO_AGNO(mp, (xfs_fsblock_t)s);
2097 agbno = XFS_FSB_TO_AGBNO(mp, (xfs_fsblock_t)s);
2098 set_dbmap(agno, agbno, (xfs_extlen_t)c, type, iagno,
2099 iagbno);
2100 set_inomap(agno, agbno, (xfs_extlen_t)c, id);
2101 for (b = (xfs_fsblock_t)s;
2102 blist_size && b < s + c;
2103 b++, o++, agbno++) {
2104 if (CHECK_BLIST(b))
2105 dbprintf(_("inode %lld block %lld at "
2106 "offset %lld\n"),
2107 id->ino, (xfs_dfsbno_t)b, o);
2108 }
2109 }
2110 *tot += c;
2111 }
2112 }
2113
2114 static void
2115 process_btinode(
2116 inodata_t *id,
2117 xfs_dinode_t *dip,
2118 dbm_t type,
2119 xfs_drfsbno_t *totd,
2120 xfs_drfsbno_t *toti,
2121 xfs_extnum_t *nex,
2122 blkmap_t **blkmapp,
2123 int whichfork)
2124 {
2125 xfs_bmdr_block_t *dib;
2126 int i;
2127 xfs_bmbt_ptr_t *pp;
2128
2129 dib = (xfs_bmdr_block_t *)XFS_DFORK_PTR(dip, whichfork);
2130 if (be16_to_cpu(dib->bb_level) >= XFS_BM_MAXLEVELS(mp, whichfork)) {
2131 if (!sflag || id->ilist)
2132 dbprintf(_("level for ino %lld %s fork bmap root too "
2133 "large (%u)\n"),
2134 id->ino,
2135 whichfork == XFS_DATA_FORK ? _("data") : _("attr"),
2136 be16_to_cpu(dib->bb_level));
2137 error++;
2138 return;
2139 }
2140 if (be16_to_cpu(dib->bb_numrecs) >
2141 xfs_bmdr_maxrecs(XFS_DFORK_SIZE(dip, mp, whichfork),
2142 be16_to_cpu(dib->bb_level) == 0)) {
2143 if (!sflag || id->ilist)
2144 dbprintf(_("numrecs for ino %lld %s fork bmap root too "
2145 "large (%u)\n"),
2146 id->ino,
2147 whichfork == XFS_DATA_FORK ? _("data") : _("attr"),
2148 be16_to_cpu(dib->bb_numrecs));
2149 error++;
2150 return;
2151 }
2152 if (be16_to_cpu(dib->bb_level) == 0) {
2153 xfs_bmbt_rec_t *rp = XFS_BMDR_REC_ADDR(dib, 1);
2154 process_bmbt_reclist(rp, be16_to_cpu(dib->bb_numrecs), type,
2155 id, totd, blkmapp);
2156 *nex += be16_to_cpu(dib->bb_numrecs);
2157 return;
2158 } else {
2159 pp = XFS_BMDR_PTR_ADDR(dib, 1, xfs_bmdr_maxrecs(
2160 XFS_DFORK_SIZE(dip, mp, whichfork), 0));
2161 for (i = 0; i < be16_to_cpu(dib->bb_numrecs); i++)
2162 scan_lbtree(be64_to_cpu(pp[i]),
2163 be16_to_cpu(dib->bb_level),
2164 scanfunc_bmap, type, id, totd, toti,
2165 nex, blkmapp, 1,
2166 whichfork == XFS_DATA_FORK ?
2167 TYP_BMAPBTD : TYP_BMAPBTA);
2168 }
2169 if (*nex <= XFS_DFORK_SIZE(dip, mp, whichfork) / sizeof(xfs_bmbt_rec_t)) {
2170 if (!sflag || id->ilist)
2171 dbprintf(_("extent count for ino %lld %s fork too low "
2172 "(%d) for file format\n"),
2173 id->ino,
2174 whichfork == XFS_DATA_FORK ? _("data") : _("attr"),
2175 *nex);
2176 error++;
2177 }
2178 }
2179
2180 static xfs_ino_t
2181 process_data_dir_v2(
2182 int *dot,
2183 int *dotdot,
2184 inodata_t *id,
2185 int v,
2186 xfs_dablk_t dabno,
2187 freetab_t **freetabp)
2188 {
2189 xfs_dir2_dataptr_t addr;
2190 xfs_dir2_data_free_t *bf;
2191 int bf_err;
2192 struct xfs_dir2_data_hdr *block;
2193 xfs_dir2_block_tail_t *btp = NULL;
2194 inodata_t *cid;
2195 int count;
2196 struct xfs_dir2_data_hdr *data;
2197 xfs_dir2_db_t db;
2198 xfs_dir2_data_entry_t *dep;
2199 xfs_dir2_data_free_t *dfp;
2200 xfs_dir2_data_unused_t *dup;
2201 char *endptr;
2202 int freeseen;
2203 freetab_t *freetab;
2204 int i;
2205 int lastfree;
2206 int lastfree_err;
2207 xfs_dir2_leaf_entry_t *lep = NULL;
2208 xfs_ino_t lino;
2209 xfs_ino_t parent = 0;
2210 char *ptr;
2211 int stale = 0;
2212 int tag_err;
2213 __be16 *tagp;
2214 struct xfs_name xname;
2215
2216 data = iocur_top->data;
2217 block = iocur_top->data;
2218 if (be32_to_cpu(block->magic) != XFS_DIR2_BLOCK_MAGIC &&
2219 be32_to_cpu(data->magic) != XFS_DIR2_DATA_MAGIC) {
2220 if (!sflag || v)
2221 dbprintf(_("bad directory data magic # %#x for dir ino "
2222 "%lld block %d\n"),
2223 be32_to_cpu(data->magic), id->ino, dabno);
2224 error++;
2225 return NULLFSINO;
2226 }
2227 db = xfs_dir2_da_to_db(mp->m_dir_geo, dabno);
2228 bf = M_DIROPS(mp)->data_bestfree_p(data);
2229 ptr = (char *)M_DIROPS(mp)->data_unused_p(data);
2230 if (be32_to_cpu(block->magic) == XFS_DIR2_BLOCK_MAGIC) {
2231 btp = xfs_dir2_block_tail_p(mp->m_dir_geo, block);
2232 lep = xfs_dir2_block_leaf_p(btp);
2233 endptr = (char *)lep;
2234 if (endptr <= ptr || endptr > (char *)btp) {
2235 endptr = (char *)data + mp->m_dir_geo->blksize;
2236 lep = NULL;
2237 if (!sflag || v)
2238 dbprintf(_("bad block directory tail for dir ino "
2239 "%lld\n"),
2240 id->ino);
2241 error++;
2242 }
2243 } else
2244 endptr = (char *)data + mp->m_dir_geo->blksize;
2245 bf_err = lastfree_err = tag_err = 0;
2246 count = lastfree = freeseen = 0;
2247 if (be16_to_cpu(bf[0].length) == 0) {
2248 bf_err += be16_to_cpu(bf[0].offset) != 0;
2249 freeseen |= 1 << 0;
2250 }
2251 if (be16_to_cpu(bf[1].length) == 0) {
2252 bf_err += be16_to_cpu(bf[1].offset) != 0;
2253 freeseen |= 1 << 1;
2254 }
2255 if (be16_to_cpu(bf[2].length) == 0) {
2256 bf_err += be16_to_cpu(bf[2].offset) != 0;
2257 freeseen |= 1 << 2;
2258 }
2259 bf_err += be16_to_cpu(bf[0].length) < be16_to_cpu(bf[1].length);
2260 bf_err += be16_to_cpu(bf[1].length) < be16_to_cpu(bf[2].length);
2261 if (freetabp) {
2262 freetab = *freetabp;
2263 if (freetab->naents <= db) {
2264 *freetabp = freetab =
2265 realloc(freetab, FREETAB_SIZE(db + 1));
2266 for (i = freetab->naents; i < db; i++)
2267 freetab->ents[i] = NULLDATAOFF;
2268 freetab->naents = db + 1;
2269 }
2270 if (freetab->nents < db + 1)
2271 freetab->nents = db + 1;
2272 freetab->ents[db] = be16_to_cpu(bf[0].length);
2273 }
2274 while (ptr < endptr) {
2275 dup = (xfs_dir2_data_unused_t *)ptr;
2276 if (be16_to_cpu(dup->freetag) == XFS_DIR2_DATA_FREE_TAG) {
2277 lastfree_err += lastfree != 0;
2278 tagp = xfs_dir2_data_unused_tag_p(dup);
2279 if ((be16_to_cpu(dup->length) & (XFS_DIR2_DATA_ALIGN - 1)) ||
2280 be16_to_cpu(dup->length) == 0 ||
2281 (char *)tagp >= endptr) {
2282 if (!sflag || v)
2283 dbprintf(_("dir %lld block %d bad free "
2284 "entry at %d\n"),
2285 id->ino, dabno,
2286 (int)((char *)dup -
2287 (char *)data));
2288 error++;
2289 break;
2290 }
2291 tag_err += be16_to_cpu(*tagp) != (char *)dup - (char *)data;
2292 dfp = process_data_dir_v2_freefind(data, dup);
2293 if (dfp) {
2294 i = (int)(dfp - bf);
2295 bf_err += (freeseen & (1 << i)) != 0;
2296 freeseen |= 1 << i;
2297 } else
2298 bf_err += be16_to_cpu(dup->length) >
2299 be16_to_cpu(bf[2].length);
2300 ptr += be16_to_cpu(dup->length);
2301 lastfree = 1;
2302 continue;
2303 }
2304 dep = (xfs_dir2_data_entry_t *)dup;
2305 if (dep->namelen == 0) {
2306 if (!sflag || v)
2307 dbprintf(_("dir %lld block %d zero length entry "
2308 "at %d\n"),
2309 id->ino, dabno,
2310 (int)((char *)dep - (char *)data));
2311 error++;
2312 }
2313 tagp = M_DIROPS(mp)->data_entry_tag_p(dep);
2314 if ((char *)tagp >= endptr) {
2315 if (!sflag || v)
2316 dbprintf(_("dir %lld block %d bad entry at %d\n"),
2317 id->ino, dabno,
2318 (int)((char *)dep - (char *)data));
2319 error++;
2320 break;
2321 }
2322 tag_err += be16_to_cpu(*tagp) != (char *)dep - (char *)data;
2323 addr = xfs_dir2_db_off_to_dataptr(mp->m_dir_geo, db,
2324 (char *)dep - (char *)data);
2325 xname.name = dep->name;
2326 xname.len = dep->namelen;
2327 dir_hash_add(mp->m_dirnameops->hashname(&xname), addr);
2328 ptr += M_DIROPS(mp)->data_entsize(dep->namelen);
2329 count++;
2330 lastfree = 0;
2331 lino = be64_to_cpu(dep->inumber);
2332 cid = find_inode(lino, 1);
2333 if (v)
2334 dbprintf(_("dir %lld block %d entry %*.*s %lld\n"),
2335 id->ino, dabno, dep->namelen, dep->namelen,
2336 dep->name, lino);
2337 if (cid)
2338 addlink_inode(cid);
2339 else {
2340 if (!sflag || v)
2341 dbprintf(_("dir %lld block %d entry %*.*s bad "
2342 "inode number %lld\n"),
2343 id->ino, dabno, dep->namelen,
2344 dep->namelen, dep->name, lino);
2345 error++;
2346 }
2347 if (dep->namelen == 2 && dep->name[0] == '.' &&
2348 dep->name[1] == '.') {
2349 if (parent) {
2350 if (!sflag || v)
2351 dbprintf(_("multiple .. entries in dir "
2352 "%lld (%lld, %lld)\n"),
2353 id->ino, parent, lino);
2354 error++;
2355 } else
2356 parent = cid ? lino : NULLFSINO;
2357 (*dotdot)++;
2358 } else if (dep->namelen != 1 || dep->name[0] != '.') {
2359 if (cid != NULL) {
2360 if (!cid->parent)
2361 cid->parent = id;
2362 addname_inode(cid, (char *)dep->name,
2363 dep->namelen);
2364 }
2365 } else {
2366 if (lino != id->ino) {
2367 if (!sflag || v)
2368 dbprintf(_("dir %lld entry . inode "
2369 "number mismatch (%lld)\n"),
2370 id->ino, lino);
2371 error++;
2372 }
2373 (*dot)++;
2374 }
2375 }
2376 if (be32_to_cpu(data->magic) == XFS_DIR2_BLOCK_MAGIC) {
2377 endptr = (char *)data + mp->m_dir_geo->blksize;
2378 for (i = stale = 0; lep && i < be32_to_cpu(btp->count); i++) {
2379 if ((char *)&lep[i] >= endptr) {
2380 if (!sflag || v)
2381 dbprintf(_("dir %lld block %d bad count "
2382 "%u\n"), id->ino, dabno,
2383 be32_to_cpu(btp->count));
2384 error++;
2385 break;
2386 }
2387 if (be32_to_cpu(lep[i].address) == XFS_DIR2_NULL_DATAPTR)
2388 stale++;
2389 else if (dir_hash_see(be32_to_cpu(lep[i].hashval),
2390 be32_to_cpu(lep[i].address))) {
2391 if (!sflag || v)
2392 dbprintf(_("dir %lld block %d extra leaf "
2393 "entry %x %x\n"),
2394 id->ino, dabno,
2395 be32_to_cpu(lep[i].hashval),
2396 be32_to_cpu(lep[i].address));
2397 error++;
2398 }
2399 }
2400 }
2401 bf_err += freeseen != 7;
2402 if (bf_err) {
2403 if (!sflag || v)
2404 dbprintf(_("dir %lld block %d bad bestfree data\n"),
2405 id->ino, dabno);
2406 error++;
2407 }
2408 if (be32_to_cpu(data->magic) == XFS_DIR2_BLOCK_MAGIC &&
2409 count != be32_to_cpu(btp->count) - be32_to_cpu(btp->stale)) {
2410 if (!sflag || v)
2411 dbprintf(_("dir %lld block %d bad block tail count %d "
2412 "(stale %d)\n"),
2413 id->ino, dabno, be32_to_cpu(btp->count),
2414 be32_to_cpu(btp->stale));
2415 error++;
2416 }
2417 if (be32_to_cpu(data->magic) == XFS_DIR2_BLOCK_MAGIC &&
2418 stale != be32_to_cpu(btp->stale)) {
2419 if (!sflag || v)
2420 dbprintf(_("dir %lld block %d bad stale tail count %d\n"),
2421 id->ino, dabno, be32_to_cpu(btp->stale));
2422 error++;
2423 }
2424 if (lastfree_err) {
2425 if (!sflag || v)
2426 dbprintf(_("dir %lld block %d consecutive free entries\n"),
2427 id->ino, dabno);
2428 error++;
2429 }
2430 if (tag_err) {
2431 if (!sflag || v)
2432 dbprintf(_("dir %lld block %d entry/unused tag "
2433 "mismatch\n"),
2434 id->ino, dabno);
2435 error++;
2436 }
2437 return parent;
2438 }
2439
2440 static xfs_dir2_data_free_t *
2441 process_data_dir_v2_freefind(
2442 struct xfs_dir2_data_hdr *data,
2443 xfs_dir2_data_unused_t *dup)
2444 {
2445 struct xfs_dir2_data_free *bf;
2446 struct xfs_dir2_data_free *dfp;
2447 xfs_dir2_data_aoff_t off;
2448
2449 off = (xfs_dir2_data_aoff_t)((char *)dup - (char *)data);
2450 bf = M_DIROPS(mp)->data_bestfree_p(data);
2451 if (be16_to_cpu(dup->length) <
2452 be16_to_cpu(bf[XFS_DIR2_DATA_FD_COUNT - 1].length))
2453 return NULL;
2454 for (dfp = bf; dfp < &bf[XFS_DIR2_DATA_FD_COUNT]; dfp++) {
2455 if (be16_to_cpu(dfp->offset) == 0)
2456 return NULL;
2457 if (be16_to_cpu(dfp->offset) == off)
2458 return dfp;
2459 }
2460 return NULL;
2461 }
2462
2463 static void
2464 process_dir(
2465 xfs_dinode_t *dip,
2466 blkmap_t *blkmap,
2467 inodata_t *id)
2468 {
2469 xfs_fsblock_t bno;
2470 int dot;
2471 int dotdot;
2472 xfs_ino_t parent;
2473
2474 dot = dotdot = 0;
2475 if (process_dir_v2(dip, blkmap, &dot, &dotdot, id, &parent))
2476 return;
2477
2478 bno = XFS_INO_TO_FSB(mp, id->ino);
2479 if (dot == 0) {
2480 if (!sflag || id->ilist || CHECK_BLIST(bno))
2481 dbprintf(_("no . entry for directory %lld\n"), id->ino);
2482 error++;
2483 }
2484 if (dotdot == 0) {
2485 if (!sflag || id->ilist || CHECK_BLIST(bno))
2486 dbprintf(_("no .. entry for directory %lld\n"), id->ino);
2487 error++;
2488 } else if (parent == id->ino && id->ino != mp->m_sb.sb_rootino) {
2489 if (!sflag || id->ilist || CHECK_BLIST(bno))
2490 dbprintf(_(". and .. same for non-root directory %lld\n"),
2491 id->ino);
2492 error++;
2493 } else if (id->ino == mp->m_sb.sb_rootino && id->ino != parent) {
2494 if (!sflag || id->ilist || CHECK_BLIST(bno))
2495 dbprintf(_("root directory %lld has .. %lld\n"), id->ino,
2496 parent);
2497 error++;
2498 } else if (parent != NULLFSINO && id->ino != parent)
2499 addparent_inode(id, parent);
2500 }
2501
2502 static int
2503 process_dir_v2(
2504 xfs_dinode_t *dip,
2505 blkmap_t *blkmap,
2506 int *dot,
2507 int *dotdot,
2508 inodata_t *id,
2509 xfs_ino_t *parent)
2510 {
2511 xfs_fileoff_t last = 0;
2512 xfs_fsize_t size = be64_to_cpu(dip->di_size);
2513
2514 if (blkmap)
2515 last = blkmap_last_off(blkmap);
2516 if (size <= XFS_DFORK_DSIZE(dip, mp) &&
2517 dip->di_format == XFS_DINODE_FMT_LOCAL)
2518 *parent = process_sf_dir_v2(dip, dot, dotdot, id);
2519 else if (last == mp->m_dir_geo->fsbcount &&
2520 (dip->di_format == XFS_DINODE_FMT_EXTENTS ||
2521 dip->di_format == XFS_DINODE_FMT_BTREE))
2522 *parent = process_block_dir_v2(blkmap, dot, dotdot, id);
2523 else if (last >= mp->m_dir_geo->leafblk + mp->m_dir_geo->fsbcount &&
2524 (dip->di_format == XFS_DINODE_FMT_EXTENTS ||
2525 dip->di_format == XFS_DINODE_FMT_BTREE))
2526 *parent = process_leaf_node_dir_v2(blkmap, dot, dotdot, id, size);
2527 else {
2528 dbprintf(_("bad size (%lld) or format (%d) for directory inode "
2529 "%lld\n"),
2530 size, dip->di_format, id->ino);
2531 error++;
2532 return 1;
2533 }
2534 return 0;
2535 }
2536
2537 /* ARGSUSED */
2538 static void
2539 process_exinode(
2540 inodata_t *id,
2541 xfs_dinode_t *dip,
2542 dbm_t type,
2543 xfs_drfsbno_t *totd,
2544 xfs_drfsbno_t *toti,
2545 xfs_extnum_t *nex,
2546 blkmap_t **blkmapp,
2547 int whichfork)
2548 {
2549 xfs_bmbt_rec_t *rp;
2550
2551 rp = (xfs_bmbt_rec_t *)XFS_DFORK_PTR(dip, whichfork);
2552 *nex = XFS_DFORK_NEXTENTS(dip, whichfork);
2553 if (*nex < 0 || *nex > XFS_DFORK_SIZE(dip, mp, whichfork) /
2554 sizeof(xfs_bmbt_rec_t)) {
2555 if (!sflag || id->ilist)
2556 dbprintf(_("bad number of extents %d for inode %lld\n"),
2557 *nex, id->ino);
2558 error++;
2559 return;
2560 }
2561 process_bmbt_reclist(rp, *nex, type, id, totd, blkmapp);
2562 }
2563
2564 static void
2565 process_inode(
2566 xfs_agf_t *agf,
2567 xfs_agino_t agino,
2568 xfs_dinode_t *dip,
2569 int isfree)
2570 {
2571 blkmap_t *blkmap;
2572 xfs_fsblock_t bno = 0;
2573 xfs_icdinode_t idic;
2574 inodata_t *id = NULL;
2575 xfs_ino_t ino;
2576 xfs_extnum_t nextents = 0;
2577 int nlink;
2578 int security;
2579 xfs_drfsbno_t totblocks;
2580 xfs_drfsbno_t totdblocks = 0;
2581 xfs_drfsbno_t totiblocks = 0;
2582 dbm_t type;
2583 xfs_extnum_t anextents = 0;
2584 xfs_drfsbno_t atotdblocks = 0;
2585 xfs_drfsbno_t atotiblocks = 0;
2586 xfs_qcnt_t bc = 0;
2587 xfs_qcnt_t ic = 0;
2588 xfs_qcnt_t rc = 0;
2589 xfs_dqid_t dqprid;
2590 int v = 0;
2591 static char okfmts[] = {
2592 0, /* type 0 unused */
2593 1 << XFS_DINODE_FMT_DEV, /* FIFO */
2594 1 << XFS_DINODE_FMT_DEV, /* CHR */
2595 0, /* type 3 unused */
2596 (1 << XFS_DINODE_FMT_LOCAL) |
2597 (1 << XFS_DINODE_FMT_EXTENTS) |
2598 (1 << XFS_DINODE_FMT_BTREE), /* DIR */
2599 0, /* type 5 unused */
2600 1 << XFS_DINODE_FMT_DEV, /* BLK */
2601 0, /* type 7 unused */
2602 (1 << XFS_DINODE_FMT_EXTENTS) |
2603 (1 << XFS_DINODE_FMT_BTREE), /* REG */
2604 0, /* type 9 unused */
2605 (1 << XFS_DINODE_FMT_LOCAL) |
2606 (1 << XFS_DINODE_FMT_EXTENTS), /* LNK */
2607 0, /* type 11 unused */
2608 1 << XFS_DINODE_FMT_DEV, /* SOCK */
2609 0, /* type 13 unused */
2610 1 << XFS_DINODE_FMT_UUID, /* MNT */
2611 0 /* type 15 unused */
2612 };
2613 static char *fmtnames[] = {
2614 "dev", "local", "extents", "btree", "uuid"
2615 };
2616
2617 libxfs_dinode_from_disk(&idic, dip);
2618
2619 ino = XFS_AGINO_TO_INO(mp, be32_to_cpu(agf->agf_seqno), agino);
2620 if (!isfree) {
2621 id = find_inode(ino, 1);
2622 bno = XFS_INO_TO_FSB(mp, ino);
2623 blkmap = NULL;
2624 }
2625 v = (!sflag || (id && id->ilist) || CHECK_BLIST(bno));
2626 if (idic.di_magic != XFS_DINODE_MAGIC) {
2627 if (isfree || v)
2628 dbprintf(_("bad magic number %#x for inode %lld\n"),
2629 idic.di_magic, ino);
2630 error++;
2631 return;
2632 }
2633 if (!XFS_DINODE_GOOD_VERSION(idic.di_version)) {
2634 if (isfree || v)
2635 dbprintf(_("bad version number %#x for inode %lld\n"),
2636 idic.di_version, ino);
2637 error++;
2638 return;
2639 }
2640 if (isfree) {
2641 if (idic.di_nblocks != 0) {
2642 if (v)
2643 dbprintf(_("bad nblocks %lld for free inode "
2644 "%lld\n"),
2645 idic.di_nblocks, ino);
2646 error++;
2647 }
2648 if (idic.di_version == 1)
2649 nlink = idic.di_onlink;
2650 else
2651 nlink = idic.di_nlink;
2652 if (nlink != 0) {
2653 if (v)
2654 dbprintf(_("bad nlink %d for free inode %lld\n"),
2655 nlink, ino);
2656 error++;
2657 }
2658 if (idic.di_mode != 0) {
2659 if (v)
2660 dbprintf(_("bad mode %#o for free inode %lld\n"),
2661 idic.di_mode, ino);
2662 error++;
2663 }
2664 return;
2665 }
2666
2667 if (be32_to_cpu(dip->di_next_unlinked) != NULLAGINO) {
2668 if (v)
2669 dbprintf(_("bad next unlinked %#x for inode %lld\n"),
2670 be32_to_cpu(dip->di_next_unlinked), ino);
2671 error++;
2672 }
2673 /*
2674 * di_mode is a 16-bit uint so no need to check the < 0 case
2675 */
2676 if ((((idic.di_mode & S_IFMT) >> 12) > 15) ||
2677 (!(okfmts[(idic.di_mode & S_IFMT) >> 12] & (1 << idic.di_format)))) {
2678 if (v)
2679 dbprintf(_("bad format %d for inode %lld type %#o\n"),
2680 idic.di_format, id->ino, idic.di_mode & S_IFMT);
2681 error++;
2682 return;
2683 }
2684 if ((unsigned int)XFS_DFORK_ASIZE(dip, mp) >=
2685 XFS_LITINO(mp, idic.di_version)) {
2686 if (v)
2687 dbprintf(_("bad fork offset %d for inode %lld\n"),
2688 idic.di_forkoff, id->ino);
2689 error++;
2690 return;
2691 }
2692 if ((unsigned int)idic.di_aformat > XFS_DINODE_FMT_BTREE) {
2693 if (v)
2694 dbprintf(_("bad attribute format %d for inode %lld\n"),
2695 idic.di_aformat, id->ino);
2696 error++;
2697 return;
2698 }
2699 if (verbose || (id && id->ilist) || CHECK_BLIST(bno))
2700 dbprintf(_("inode %lld mode %#o fmt %s "
2701 "afmt %s "
2702 "nex %d anex %d nblk %lld sz %lld%s%s%s%s%s%s%s\n"),
2703 id->ino, idic.di_mode, fmtnames[(int)idic.di_format],
2704 fmtnames[(int)idic.di_aformat],
2705 idic.di_nextents,
2706 idic.di_anextents,
2707 idic.di_nblocks, idic.di_size,
2708 idic.di_flags & XFS_DIFLAG_REALTIME ? " rt" : "",
2709 idic.di_flags & XFS_DIFLAG_PREALLOC ? " pre" : "",
2710 idic.di_flags & XFS_DIFLAG_IMMUTABLE? " imm" : "",
2711 idic.di_flags & XFS_DIFLAG_APPEND ? " app" : "",
2712 idic.di_flags & XFS_DIFLAG_SYNC ? " syn" : "",
2713 idic.di_flags & XFS_DIFLAG_NOATIME ? " noa" : "",
2714 idic.di_flags & XFS_DIFLAG_NODUMP ? " nod" : "");
2715 security = 0;
2716 switch (idic.di_mode & S_IFMT) {
2717 case S_IFDIR:
2718 type = DBM_DIR;
2719 if (idic.di_format == XFS_DINODE_FMT_LOCAL)
2720 break;
2721 blkmap = blkmap_alloc(idic.di_nextents);
2722 break;
2723 case S_IFREG:
2724 if (idic.di_flags & XFS_DIFLAG_REALTIME)
2725 type = DBM_RTDATA;
2726 else if (id->ino == mp->m_sb.sb_rbmino) {
2727 type = DBM_RTBITMAP;
2728 blkmap = blkmap_alloc(idic.di_nextents);
2729 addlink_inode(id);
2730 } else if (id->ino == mp->m_sb.sb_rsumino) {
2731 type = DBM_RTSUM;
2732 blkmap = blkmap_alloc(idic.di_nextents);
2733 addlink_inode(id);
2734 }
2735 else if (id->ino == mp->m_sb.sb_uquotino ||
2736 id->ino == mp->m_sb.sb_gquotino ||
2737 id->ino == mp->m_sb.sb_pquotino) {
2738 type = DBM_QUOTA;
2739 blkmap = blkmap_alloc(idic.di_nextents);
2740 addlink_inode(id);
2741 }
2742 else
2743 type = DBM_DATA;
2744 if (idic.di_mode & (S_ISUID | S_ISGID))
2745 security = 1;
2746 break;
2747 case S_IFLNK:
2748 type = DBM_SYMLINK;
2749 break;
2750 default:
2751 security = 1;
2752 type = DBM_UNKNOWN;
2753 break;
2754 }
2755 if (idic.di_version == 1)
2756 setlink_inode(id, idic.di_onlink, type == DBM_DIR, security);
2757 else {
2758 sbversion |= XFS_SB_VERSION_NLINKBIT;
2759 setlink_inode(id, idic.di_nlink, type == DBM_DIR, security);
2760 }
2761 switch (idic.di_format) {
2762 case XFS_DINODE_FMT_LOCAL:
2763 process_lclinode(id, dip, type, &totdblocks, &totiblocks,
2764 &nextents, &blkmap, XFS_DATA_FORK);
2765 break;
2766 case XFS_DINODE_FMT_EXTENTS:
2767 process_exinode(id, dip, type, &totdblocks, &totiblocks,
2768 &nextents, &blkmap, XFS_DATA_FORK);
2769 break;
2770 case XFS_DINODE_FMT_BTREE:
2771 process_btinode(id, dip, type, &totdblocks, &totiblocks,
2772 &nextents, &blkmap, XFS_DATA_FORK);
2773 break;
2774 }
2775 if (XFS_DFORK_Q(dip)) {
2776 sbversion |= XFS_SB_VERSION_ATTRBIT;
2777 switch (idic.di_aformat) {
2778 case XFS_DINODE_FMT_LOCAL:
2779 process_lclinode(id, dip, DBM_ATTR, &atotdblocks,
2780 &atotiblocks, &anextents, NULL, XFS_ATTR_FORK);
2781 break;
2782 case XFS_DINODE_FMT_EXTENTS:
2783 process_exinode(id, dip, DBM_ATTR, &atotdblocks,
2784 &atotiblocks, &anextents, NULL, XFS_ATTR_FORK);
2785 break;
2786 case XFS_DINODE_FMT_BTREE:
2787 process_btinode(id, dip, DBM_ATTR, &atotdblocks,
2788 &atotiblocks, &anextents, NULL, XFS_ATTR_FORK);
2789 break;
2790 }
2791 }
2792 if (qgdo || qpdo || qudo) {
2793 switch (type) {
2794 case DBM_DATA:
2795 case DBM_DIR:
2796 case DBM_RTBITMAP:
2797 case DBM_RTSUM:
2798 case DBM_SYMLINK:
2799 case DBM_UNKNOWN:
2800 bc = totdblocks + totiblocks +
2801 atotdblocks + atotiblocks;
2802 ic = 1;
2803 break;
2804 case DBM_RTDATA:
2805 bc = totiblocks + atotdblocks + atotiblocks;
2806 rc = totdblocks;
2807 ic = 1;
2808 break;
2809 default:
2810 break;
2811 }
2812 if (ic) {
2813 dqprid = xfs_get_projid(&idic); /* dquot ID is u32 */
2814 quota_add(&dqprid, &idic.di_gid, &idic.di_uid,
2815 0, bc, ic, rc);
2816 }
2817 }
2818 totblocks = totdblocks + totiblocks + atotdblocks + atotiblocks;
2819 if (totblocks != idic.di_nblocks) {
2820 if (v)
2821 dbprintf(_("bad nblocks %lld for inode %lld, counted "
2822 "%lld\n"),
2823 idic.di_nblocks, id->ino, totblocks);
2824 error++;
2825 }
2826 if (nextents != idic.di_nextents) {
2827 if (v)
2828 dbprintf(_("bad nextents %d for inode %lld, counted %d\n"),
2829 idic.di_nextents, id->ino, nextents);
2830 error++;
2831 }
2832 if (anextents != idic.di_anextents) {
2833 if (v)
2834 dbprintf(_("bad anextents %d for inode %lld, counted "
2835 "%d\n"),
2836 idic.di_anextents, id->ino, anextents);
2837 error++;
2838 }
2839 if (type == DBM_DIR)
2840 process_dir(dip, blkmap, id);
2841 else if (type == DBM_RTBITMAP)
2842 process_rtbitmap(blkmap);
2843 else if (type == DBM_RTSUM)
2844 process_rtsummary(blkmap);
2845 /*
2846 * If the CHKD flag is not set, this can legitimately contain garbage;
2847 * xfs_repair may have cleared that bit.
2848 */
2849 else if (type == DBM_QUOTA) {
2850 if (id->ino == mp->m_sb.sb_uquotino &&
2851 (mp->m_sb.sb_qflags & XFS_UQUOTA_ACCT) &&
2852 (mp->m_sb.sb_qflags & XFS_UQUOTA_CHKD))
2853 process_quota(IS_USER_QUOTA, id, blkmap);
2854 else if (id->ino == mp->m_sb.sb_gquotino &&
2855 (mp->m_sb.sb_qflags & XFS_GQUOTA_ACCT) &&
2856 (mp->m_sb.sb_qflags & XFS_GQUOTA_CHKD))
2857 process_quota(IS_GROUP_QUOTA, id, blkmap);
2858 else if (id->ino == mp->m_sb.sb_pquotino &&
2859 (mp->m_sb.sb_qflags & XFS_PQUOTA_ACCT) &&
2860 (mp->m_sb.sb_qflags & XFS_PQUOTA_CHKD))
2861 process_quota(IS_PROJECT_QUOTA, id, blkmap);
2862 }
2863 if (blkmap)
2864 blkmap_free(blkmap);
2865 }
2866
2867 /* ARGSUSED */
2868 static void
2869 process_lclinode(
2870 inodata_t *id,
2871 xfs_dinode_t *dip,
2872 dbm_t type,
2873 xfs_drfsbno_t *totd,
2874 xfs_drfsbno_t *toti,
2875 xfs_extnum_t *nex,
2876 blkmap_t **blkmapp,
2877 int whichfork)
2878 {
2879 xfs_attr_shortform_t *asf;
2880 xfs_fsblock_t bno;
2881
2882 bno = XFS_INO_TO_FSB(mp, id->ino);
2883 if (whichfork == XFS_DATA_FORK && be64_to_cpu(dip->di_size) >
2884 XFS_DFORK_DSIZE(dip, mp)) {
2885 if (!sflag || id->ilist || CHECK_BLIST(bno))
2886 dbprintf(_("local inode %lld data is too large (size "
2887 "%lld)\n"),
2888 id->ino, be64_to_cpu(dip->di_size));
2889 error++;
2890 }
2891 else if (whichfork == XFS_ATTR_FORK) {
2892 asf = (xfs_attr_shortform_t *)XFS_DFORK_APTR(dip);
2893 if (be16_to_cpu(asf->hdr.totsize) > XFS_DFORK_ASIZE(dip, mp)) {
2894 if (!sflag || id->ilist || CHECK_BLIST(bno))
2895 dbprintf(_("local inode %lld attr is too large "
2896 "(size %d)\n"),
2897 id->ino, be16_to_cpu(asf->hdr.totsize));
2898 error++;
2899 }
2900 }
2901 }
2902
2903 static xfs_ino_t
2904 process_leaf_node_dir_v2(
2905 blkmap_t *blkmap,
2906 int *dot,
2907 int *dotdot,
2908 inodata_t *id,
2909 xfs_fsize_t dirsize)
2910 {
2911 xfs_fsblock_t b;
2912 bbmap_t bbmap;
2913 bmap_ext_t *bmp;
2914 xfs_fileoff_t dbno;
2915 freetab_t *freetab;
2916 int i;
2917 xfs_ino_t lino;
2918 int nex;
2919 xfs_ino_t parent;
2920 int t = 0;
2921 int v;
2922 int v2;
2923 int x;
2924
2925 v2 = verbose || id->ilist;
2926 v = parent = 0;
2927 dbno = NULLFILEOFF;
2928 freetab = malloc(FREETAB_SIZE(dirsize / mp->m_dir_geo->blksize));
2929 freetab->naents = (int)(dirsize / mp->m_dir_geo->blksize);
2930 freetab->nents = 0;
2931 for (i = 0; i < freetab->naents; i++)
2932 freetab->ents[i] = NULLDATAOFF;
2933 dir_hash_init();
2934 while ((dbno = blkmap_next_off(blkmap, dbno, &t)) != NULLFILEOFF) {
2935 nex = blkmap_getn(blkmap, dbno, mp->m_dir_geo->fsbcount, &bmp);
2936 ASSERT(nex > 0);
2937 for (v = v2, x = 0; !v && x < nex; x++) {
2938 for (b = bmp[x].startblock;
2939 !v && b < bmp[x].startblock + bmp[x].blockcount;
2940 b++)
2941 v = CHECK_BLIST(b);
2942 }
2943 if (v)
2944 dbprintf(_("dir inode %lld block %u=%llu\n"), id->ino,
2945 (__uint32_t)dbno,
2946 (xfs_dfsbno_t)bmp->startblock);
2947 push_cur();
2948 if (nex > 1)
2949 make_bbmap(&bbmap, nex, bmp);
2950 set_cur(&typtab[TYP_DIR2], XFS_FSB_TO_DADDR(mp, bmp->startblock),
2951 mp->m_dir_geo->fsbcount * blkbb, DB_RING_IGN,
2952 nex > 1 ? &bbmap : NULL);
2953 free(bmp);
2954 if (iocur_top->data == NULL) {
2955 if (!sflag || v)
2956 dbprintf(_("can't read block %u for directory "
2957 "inode %lld\n"),
2958 (__uint32_t)dbno, id->ino);
2959 error++;
2960 pop_cur();
2961 dbno += mp->m_dir_geo->fsbcount - 1;
2962 continue;
2963 }
2964 if (dbno < mp->m_dir_geo->leafblk) {
2965 lino = process_data_dir_v2(dot, dotdot, id, v,
2966 (xfs_dablk_t)dbno, &freetab);
2967 if (lino) {
2968 if (parent) {
2969 if (!sflag || v)
2970 dbprintf(_("multiple .. entries "
2971 "in dir %lld\n"),
2972 id->ino);
2973 error++;
2974 } else
2975 parent = lino;
2976 }
2977 } else if (dbno < mp->m_dir_geo->freeblk) {
2978 process_leaf_node_dir_v2_int(id, v, (xfs_dablk_t)dbno,
2979 freetab);
2980 } else {
2981 process_leaf_node_dir_v2_free(id, v, (xfs_dablk_t)dbno,
2982 freetab);
2983 }
2984 pop_cur();
2985 dbno += mp->m_dir_geo->fsbcount - 1;
2986 }
2987 dir_hash_check(id, v);
2988 dir_hash_done();
2989 for (i = 0; i < freetab->nents; i++) {
2990 if (freetab->ents[i] != NULLDATAOFF) {
2991 if (!sflag || v)
2992 dbprintf(_("missing free index for data block %d "
2993 "in dir ino %lld\n"),
2994 xfs_dir2_db_to_da(mp->m_dir_geo, i), id->ino);
2995 error++;
2996 }
2997 }
2998 free(freetab);
2999 return parent;
3000 }
3001
3002 static void
3003 process_leaf_node_dir_v2_free(
3004 inodata_t *id,
3005 int v,
3006 xfs_dablk_t dabno,
3007 freetab_t *freetab)
3008 {
3009 xfs_dir2_data_off_t ent;
3010 xfs_dir2_free_t *free;
3011 int i;
3012 int maxent;
3013 int used;
3014
3015 free = iocur_top->data;
3016 if (be32_to_cpu(free->hdr.magic) != XFS_DIR2_FREE_MAGIC) {
3017 if (!sflag || v)
3018 dbprintf(_("bad free block magic # %#x for dir ino %lld "
3019 "block %d\n"),
3020 be32_to_cpu(free->hdr.magic), id->ino, dabno);
3021 error++;
3022 return;
3023 }
3024 maxent = M_DIROPS(mp)->free_max_bests(mp->m_dir_geo);
3025 if (be32_to_cpu(free->hdr.firstdb) != xfs_dir2_da_to_db(mp->m_dir_geo,
3026 dabno - mp->m_dir_geo->freeblk) * maxent) {
3027 if (!sflag || v)
3028 dbprintf(_("bad free block firstdb %d for dir ino %lld "
3029 "block %d\n"),
3030 be32_to_cpu(free->hdr.firstdb), id->ino, dabno);
3031 error++;
3032 return;
3033 }
3034 if (be32_to_cpu(free->hdr.nvalid) > maxent ||
3035 be32_to_cpu(free->hdr.nvalid) < 0 ||
3036 be32_to_cpu(free->hdr.nused) > maxent ||
3037 be32_to_cpu(free->hdr.nused) < 0 ||
3038 be32_to_cpu(free->hdr.nused) >
3039 be32_to_cpu(free->hdr.nvalid)) {
3040 if (!sflag || v)
3041 dbprintf(_("bad free block nvalid/nused %d/%d for dir "
3042 "ino %lld block %d\n"),
3043 be32_to_cpu(free->hdr.nvalid),
3044 be32_to_cpu(free->hdr.nused), id->ino, dabno);
3045 error++;
3046 return;
3047 }
3048 for (used = i = 0; i < be32_to_cpu(free->hdr.nvalid); i++) {
3049 if (freetab->nents <= be32_to_cpu(free->hdr.firstdb) + i)
3050 ent = NULLDATAOFF;
3051 else
3052 ent = freetab->ents[be32_to_cpu(free->hdr.firstdb) + i];
3053 if (ent != be16_to_cpu(free->bests[i])) {
3054 if (!sflag || v)
3055 dbprintf(_("bad free block ent %d is %d should "
3056 "be %d for dir ino %lld block %d\n"),
3057 i, be16_to_cpu(free->bests[i]), ent,
3058 id->ino, dabno);
3059 error++;
3060 }
3061 if (be16_to_cpu(free->bests[i]) != NULLDATAOFF)
3062 used++;
3063 if (ent != NULLDATAOFF)
3064 freetab->ents[be32_to_cpu(free->hdr.firstdb) + i] =
3065 NULLDATAOFF;
3066 }
3067 if (used != be32_to_cpu(free->hdr.nused)) {
3068 if (!sflag || v)
3069 dbprintf(_("bad free block nused %d should be %d for dir "
3070 "ino %lld block %d\n"),
3071 be32_to_cpu(free->hdr.nused), used, id->ino,
3072 dabno);
3073 error++;
3074 }
3075 }
3076
3077 static void
3078 process_leaf_node_dir_v2_int(
3079 inodata_t *id,
3080 int v,
3081 xfs_dablk_t dabno,
3082 freetab_t *freetab)
3083 {
3084 int i;
3085 __be16 *lbp;
3086 xfs_dir2_leaf_t *leaf;
3087 xfs_dir2_leaf_entry_t *lep;
3088 xfs_dir2_leaf_tail_t *ltp;
3089 xfs_da_intnode_t *node;
3090 int stale;
3091 struct xfs_da3_icnode_hdr nodehdr;
3092
3093 leaf = iocur_top->data;
3094 switch (be16_to_cpu(leaf->hdr.info.magic)) {
3095 case XFS_DIR2_LEAF1_MAGIC:
3096 if (be32_to_cpu(leaf->hdr.info.forw) ||
3097 be32_to_cpu(leaf->hdr.info.back)) {
3098 if (!sflag || v)
3099 dbprintf(_("bad leaf block forw/back pointers "
3100 "%d/%d for dir ino %lld block %d\n"),
3101 be32_to_cpu(leaf->hdr.info.forw),
3102 be32_to_cpu(leaf->hdr.info.back),
3103 id->ino, dabno);
3104 error++;
3105 }
3106 if (dabno != mp->m_dir_geo->leafblk) {
3107 if (!sflag || v)
3108 dbprintf(_("single leaf block for dir ino %lld "
3109 "block %d should be at block %d\n"),
3110 id->ino, dabno,
3111 (xfs_dablk_t)mp->m_dir_geo->leafblk);
3112 error++;
3113 }
3114 ltp = xfs_dir2_leaf_tail_p(mp->m_dir_geo, leaf);
3115 lbp = xfs_dir2_leaf_bests_p(ltp);
3116 for (i = 0; i < be32_to_cpu(ltp->bestcount); i++) {
3117 if (freetab->nents <= i || freetab->ents[i] !=
3118 be16_to_cpu(lbp[i])) {
3119 if (!sflag || v)
3120 dbprintf(_("bestfree %d for dir ino %lld "
3121 "block %d doesn't match table "
3122 "value %d\n"),
3123 freetab->nents <= i ?
3124 NULLDATAOFF :
3125 freetab->ents[i],
3126 id->ino,
3127 xfs_dir2_db_to_da(mp->m_dir_geo, i),
3128 be16_to_cpu(lbp[i]));
3129 }
3130 if (freetab->nents > i)
3131 freetab->ents[i] = NULLDATAOFF;
3132 }
3133 break;
3134 case XFS_DIR2_LEAFN_MAGIC:
3135 /* if it's at the root location then we can check the
3136 * pointers are null XXX */
3137 break;
3138 case XFS_DA_NODE_MAGIC:
3139 node = iocur_top->data;
3140 M_DIROPS(mp)->node_hdr_from_disk(&nodehdr, node);
3141 if (nodehdr.level < 1 || nodehdr.level > XFS_DA_NODE_MAXDEPTH) {
3142 if (!sflag || v)
3143 dbprintf(_("bad node block level %d for dir ino "
3144 "%lld block %d\n"),
3145 nodehdr.level, id->ino,
3146 dabno);
3147 error++;
3148 }
3149 return;
3150 default:
3151 if (!sflag || v)
3152 dbprintf(_("bad directory data magic # %#x for dir ino "
3153 "%lld block %d\n"),
3154 be16_to_cpu(leaf->hdr.info.magic), id->ino,
3155 dabno);
3156 error++;
3157 return;
3158 }
3159 lep = M_DIROPS(mp)->leaf_ents_p(leaf);
3160 for (i = stale = 0; i < be16_to_cpu(leaf->hdr.count); i++) {
3161 if (be32_to_cpu(lep[i].address) == XFS_DIR2_NULL_DATAPTR)
3162 stale++;
3163 else if (dir_hash_see(be32_to_cpu(lep[i].hashval),
3164 be32_to_cpu(lep[i].address))) {
3165 if (!sflag || v)
3166 dbprintf(_("dir %lld block %d extra leaf entry "
3167 "%x %x\n"), id->ino, dabno,
3168 be32_to_cpu(lep[i].hashval),
3169 be32_to_cpu(lep[i].address));
3170 error++;
3171 }
3172 }
3173 if (stale != be16_to_cpu(leaf->hdr.stale)) {
3174 if (!sflag || v)
3175 dbprintf(_("dir %lld block %d stale mismatch "
3176 "%d/%d\n"),
3177 id->ino, dabno, stale,
3178 be16_to_cpu(leaf->hdr.stale));
3179 error++;
3180 }
3181 }
3182
3183 static void
3184 process_quota(
3185 qtype_t qtype,
3186 inodata_t *id,
3187 blkmap_t *blkmap)
3188 {
3189 xfs_fsblock_t bno;
3190 int cb;
3191 xfs_dqblk_t *dqb;
3192 xfs_dqid_t dqid;
3193 u_int8_t exp_flags = 0;
3194 uint i;
3195 uint perblock;
3196 xfs_fileoff_t qbno;
3197 char *s = NULL;
3198 int scicb;
3199 int t = 0;
3200
3201 switch (qtype) {
3202 case IS_USER_QUOTA:
3203 s = "user";
3204 exp_flags = XFS_DQ_USER;
3205 break;
3206 case IS_PROJECT_QUOTA:
3207 s = "project";
3208 exp_flags = XFS_DQ_PROJ;
3209 break;
3210 case IS_GROUP_QUOTA:
3211 s = "group";
3212 exp_flags = XFS_DQ_GROUP;
3213 break;
3214 default:
3215 ASSERT(0);
3216 }
3217
3218 perblock = (uint)(mp->m_sb.sb_blocksize / sizeof(*dqb));
3219 dqid = 0;
3220 qbno = NULLFILEOFF;
3221 while ((qbno = blkmap_next_off(blkmap, qbno, &t)) != NULLFILEOFF) {
3222 bno = blkmap_get(blkmap, qbno);
3223 dqid = (xfs_dqid_t)qbno * perblock;
3224 cb = CHECK_BLIST(bno);
3225 scicb = !sflag || id->ilist || cb;
3226 push_cur();
3227 set_cur(&typtab[TYP_DQBLK], XFS_FSB_TO_DADDR(mp, bno), blkbb,
3228 DB_RING_IGN, NULL);
3229 if ((dqb = iocur_top->data) == NULL) {
3230 if (scicb)
3231 dbprintf(_("can't read block %lld for %s quota "
3232 "inode (fsblock %lld)\n"),
3233 (xfs_dfiloff_t)qbno, s,
3234 (xfs_dfsbno_t)bno);
3235 error++;
3236 pop_cur();
3237 continue;
3238 }
3239 for (i = 0; i < perblock; i++, dqid++, dqb++) {
3240 if (verbose || id->ilist || cb)
3241 dbprintf(_("%s dqblk %lld entry %d id %u bc "
3242 "%lld ic %lld rc %lld\n"),
3243 s, (xfs_dfiloff_t)qbno, i, dqid,
3244 be64_to_cpu(dqb->dd_diskdq.d_bcount),
3245 be64_to_cpu(dqb->dd_diskdq.d_icount),
3246 be64_to_cpu(dqb->dd_diskdq.d_rtbcount));
3247 if (be16_to_cpu(dqb->dd_diskdq.d_magic) != XFS_DQUOT_MAGIC) {
3248 if (scicb)
3249 dbprintf(_("bad magic number %#x for %s "
3250 "dqblk %lld entry %d id %u\n"),
3251 be16_to_cpu(dqb->dd_diskdq.d_magic), s,
3252 (xfs_dfiloff_t)qbno, i, dqid);
3253 error++;
3254 continue;
3255 }
3256 if (dqb->dd_diskdq.d_version != XFS_DQUOT_VERSION) {
3257 if (scicb)
3258 dbprintf(_("bad version number %#x for "
3259 "%s dqblk %lld entry %d id "
3260 "%u\n"),
3261 dqb->dd_diskdq.d_version, s,
3262 (xfs_dfiloff_t)qbno, i, dqid);
3263 error++;
3264 continue;
3265 }
3266 if (dqb->dd_diskdq.d_flags != exp_flags) {
3267 if (scicb)
3268 dbprintf(_("bad flags %#x for %s dqblk "
3269 "%lld entry %d id %u\n"),
3270 dqb->dd_diskdq.d_flags, s,
3271 (xfs_dfiloff_t)qbno, i, dqid);
3272 error++;
3273 continue;
3274 }
3275 if (be32_to_cpu(dqb->dd_diskdq.d_id) != dqid) {
3276 if (scicb)
3277 dbprintf(_("bad id %u for %s dqblk %lld "
3278 "entry %d id %u\n"),
3279 be32_to_cpu(dqb->dd_diskdq.d_id), s,
3280 (xfs_dfiloff_t)qbno, i, dqid);
3281 error++;
3282 continue;
3283 }
3284 quota_add((qtype == IS_PROJECT_QUOTA) ? &dqid : NULL,
3285 (qtype == IS_GROUP_QUOTA) ? &dqid : NULL,
3286 (qtype == IS_USER_QUOTA) ? &dqid : NULL,
3287 1,
3288 be64_to_cpu(dqb->dd_diskdq.d_bcount),
3289 be64_to_cpu(dqb->dd_diskdq.d_icount),
3290 be64_to_cpu(dqb->dd_diskdq.d_rtbcount));
3291 }
3292 pop_cur();
3293 }
3294 }
3295
3296 static void
3297 process_rtbitmap(
3298 blkmap_t *blkmap)
3299 {
3300 int bit;
3301 int bitsperblock;
3302 xfs_fileoff_t bmbno;
3303 xfs_fsblock_t bno;
3304 xfs_drtbno_t extno;
3305 int len;
3306 int log;
3307 int offs;
3308 int prevbit;
3309 xfs_drfsbno_t rtbno;
3310 int start_bmbno;
3311 int start_bit;
3312 int t;
3313 xfs_rtword_t *words;
3314
3315 bitsperblock = mp->m_sb.sb_blocksize * NBBY;
3316 bit = extno = prevbit = start_bmbno = start_bit = 0;
3317 bmbno = NULLFILEOFF;
3318 while ((bmbno = blkmap_next_off(blkmap, bmbno, &t)) !=
3319 NULLFILEOFF) {
3320 bno = blkmap_get(blkmap, bmbno);
3321 if (bno == NULLFSBLOCK) {
3322 if (!sflag)
3323 dbprintf(_("block %lld for rtbitmap inode is "
3324 "missing\n"),
3325 (xfs_dfiloff_t)bmbno);
3326 error++;
3327 continue;
3328 }
3329 push_cur();
3330 set_cur(&typtab[TYP_RTBITMAP], XFS_FSB_TO_DADDR(mp, bno), blkbb,
3331 DB_RING_IGN, NULL);
3332 if ((words = iocur_top->data) == NULL) {
3333 if (!sflag)
3334 dbprintf(_("can't read block %lld for rtbitmap "
3335 "inode\n"),
3336 (xfs_dfiloff_t)bmbno);
3337 error++;
3338 pop_cur();
3339 continue;
3340 }
3341 for (bit = 0;
3342 bit < bitsperblock && extno < mp->m_sb.sb_rextents;
3343 bit++, extno++) {
3344 if (xfs_isset(words, bit)) {
3345 rtbno = extno * mp->m_sb.sb_rextsize;
3346 set_rdbmap(rtbno, mp->m_sb.sb_rextsize,
3347 DBM_RTFREE);
3348 frextents++;
3349 if (prevbit == 0) {
3350 start_bmbno = (int)bmbno;
3351 start_bit = bit;
3352 prevbit = 1;
3353 }
3354 } else if (prevbit == 1) {
3355 len = ((int)bmbno - start_bmbno) *
3356 bitsperblock + (bit - start_bit);
3357 log = XFS_RTBLOCKLOG(len);
3358 offs = XFS_SUMOFFS(mp, log, start_bmbno);
3359 sumcompute[offs]++;
3360 prevbit = 0;
3361 }
3362 }
3363 pop_cur();
3364 if (extno == mp->m_sb.sb_rextents)
3365 break;
3366 }
3367 if (prevbit == 1) {
3368 len = ((int)bmbno - start_bmbno) * bitsperblock +
3369 (bit - start_bit);
3370 log = XFS_RTBLOCKLOG(len);
3371 offs = XFS_SUMOFFS(mp, log, start_bmbno);
3372 sumcompute[offs]++;
3373 }
3374 }
3375
3376 static void
3377 process_rtsummary(
3378 blkmap_t *blkmap)
3379 {
3380 xfs_fsblock_t bno;
3381 char *bytes;
3382 xfs_fileoff_t sumbno;
3383 int t;
3384
3385 sumbno = NULLFILEOFF;
3386 while ((sumbno = blkmap_next_off(blkmap, sumbno, &t)) != NULLFILEOFF) {
3387 bno = blkmap_get(blkmap, sumbno);
3388 if (bno == NULLFSBLOCK) {
3389 if (!sflag)
3390 dbprintf(_("block %lld for rtsummary inode is "
3391 "missing\n"),
3392 (xfs_dfiloff_t)sumbno);
3393 error++;
3394 continue;
3395 }
3396 push_cur();
3397 set_cur(&typtab[TYP_RTSUMMARY], XFS_FSB_TO_DADDR(mp, bno),
3398 blkbb, DB_RING_IGN, NULL);
3399 if ((bytes = iocur_top->data) == NULL) {
3400 if (!sflag)
3401 dbprintf(_("can't read block %lld for rtsummary "
3402 "inode\n"),
3403 (xfs_dfiloff_t)sumbno);
3404 error++;
3405 pop_cur();
3406 continue;
3407 }
3408 memcpy((char *)sumfile + sumbno * mp->m_sb.sb_blocksize, bytes,
3409 mp->m_sb.sb_blocksize);
3410 pop_cur();
3411 }
3412 }
3413
3414 static xfs_ino_t
3415 process_sf_dir_v2(
3416 xfs_dinode_t *dip,
3417 int *dot,
3418 int *dotdot,
3419 inodata_t *id)
3420 {
3421 inodata_t *cid;
3422 int i;
3423 int i8;
3424 xfs_ino_t lino;
3425 int offset;
3426 struct xfs_dir2_sf_hdr *sf;
3427 xfs_dir2_sf_entry_t *sfe;
3428 int v;
3429
3430 sf = (struct xfs_dir2_sf_hdr *)XFS_DFORK_DPTR(dip);
3431 addlink_inode(id);
3432 v = verbose || id->ilist;
3433 if (v)
3434 dbprintf(_("dir %lld entry . %lld\n"), id->ino, id->ino);
3435 (*dot)++;
3436 sfe = xfs_dir2_sf_firstentry(sf);
3437 offset = M_DIROPS(mp)->data_first_offset;
3438 for (i = sf->count - 1, i8 = 0; i >= 0; i--) {
3439 if ((__psint_t)sfe + M_DIROPS(mp)->sf_entsize(sf, sfe->namelen) -
3440 (__psint_t)sf > be64_to_cpu(dip->di_size)) {
3441 if (!sflag)
3442 dbprintf(_("dir %llu bad size in entry at %d\n"),
3443 id->ino,
3444 (int)((char *)sfe - (char *)sf));
3445 error++;
3446 break;
3447 }
3448 lino = M_DIROPS(mp)->sf_get_ino(sf, sfe);
3449 if (lino > XFS_DIR2_MAX_SHORT_INUM)
3450 i8++;
3451 cid = find_inode(lino, 1);
3452 if (cid == NULL) {
3453 if (!sflag)
3454 dbprintf(_("dir %lld entry %*.*s bad inode "
3455 "number %lld\n"),
3456 id->ino, sfe->namelen, sfe->namelen,
3457 sfe->name, lino);
3458 error++;
3459 } else {
3460 addlink_inode(cid);
3461 if (!cid->parent)
3462 cid->parent = id;
3463 addname_inode(cid, (char *)sfe->name, sfe->namelen);
3464 }
3465 if (v)
3466 dbprintf(_("dir %lld entry %*.*s offset %d %lld\n"),
3467 id->ino, sfe->namelen, sfe->namelen, sfe->name,
3468 xfs_dir2_sf_get_offset(sfe), lino);
3469 if (xfs_dir2_sf_get_offset(sfe) < offset) {
3470 if (!sflag)
3471 dbprintf(_("dir %lld entry %*.*s bad offset %d\n"),
3472 id->ino, sfe->namelen, sfe->namelen,
3473 sfe->name, xfs_dir2_sf_get_offset(sfe));
3474 error++;
3475 }
3476 offset =
3477 xfs_dir2_sf_get_offset(sfe) +
3478 M_DIROPS(mp)->sf_entsize(sf, sfe->namelen);
3479 sfe = M_DIROPS(mp)->sf_nextentry(sf, sfe);
3480 }
3481 if (i < 0 && (__psint_t)sfe - (__psint_t)sf !=
3482 be64_to_cpu(dip->di_size)) {
3483 if (!sflag)
3484 dbprintf(_("dir %llu size is %lld, should be %u\n"),
3485 id->ino, be64_to_cpu(dip->di_size),
3486 (uint)((char *)sfe - (char *)sf));
3487 error++;
3488 }
3489 if (offset + (sf->count + 2) * sizeof(xfs_dir2_leaf_entry_t) +
3490 sizeof(xfs_dir2_block_tail_t) > mp->m_dir_geo->blksize) {
3491 if (!sflag)
3492 dbprintf(_("dir %llu offsets too high\n"), id->ino);
3493 error++;
3494 }
3495 lino = M_DIROPS(mp)->sf_get_parent_ino(sf);
3496 if (lino > XFS_DIR2_MAX_SHORT_INUM)
3497 i8++;
3498 cid = find_inode(lino, 1);
3499 if (cid)
3500 addlink_inode(cid);
3501 else {
3502 if (!sflag)
3503 dbprintf(_("dir %lld entry .. bad inode number %lld\n"),
3504 id->ino, lino);
3505 error++;
3506 }
3507 if (v)
3508 dbprintf(_("dir %lld entry .. %lld\n"), id->ino, lino);
3509 if (i8 != sf->i8count) {
3510 if (!sflag)
3511 dbprintf(_("dir %lld i8count mismatch is %d should be "
3512 "%d\n"),
3513 id->ino, sf->i8count, i8);
3514 error++;
3515 }
3516 (*dotdot)++;
3517 return cid ? lino : NULLFSINO;
3518 }
3519
3520
3521 static void
3522 quota_add(
3523 xfs_dqid_t *prjid,
3524 xfs_dqid_t *grpid,
3525 xfs_dqid_t *usrid,
3526 int dq,
3527 xfs_qcnt_t bc,
3528 xfs_qcnt_t ic,
3529 xfs_qcnt_t rc)
3530 {
3531 if (qudo && usrid != NULL)
3532 quota_add1(qudata, *usrid, dq, bc, ic, rc);
3533 if (qgdo && grpid != NULL)
3534 quota_add1(qgdata, *grpid, dq, bc, ic, rc);
3535 if (qpdo && prjid != NULL)
3536 quota_add1(qpdata, *prjid, dq, bc, ic, rc);
3537 }
3538
3539 static void
3540 quota_add1(
3541 qdata_t **qt,
3542 xfs_dqid_t id,
3543 int dq,
3544 xfs_qcnt_t bc,
3545 xfs_qcnt_t ic,
3546 xfs_qcnt_t rc)
3547 {
3548 qdata_t *qe;
3549 int qh;
3550 qinfo_t *qi;
3551
3552 qh = (int)(id % QDATA_HASH_SIZE);
3553 qe = qt[qh];
3554 while (qe) {
3555 if (qe->id == id) {
3556 qi = dq ? &qe->dq : &qe->count;
3557 qi->bc += bc;
3558 qi->ic += ic;
3559 qi->rc += rc;
3560 return;
3561 }
3562 qe = qe->next;
3563 }
3564 qe = xmalloc(sizeof(*qe));
3565 qe->id = id;
3566 qi = dq ? &qe->dq : &qe->count;
3567 qi->bc = bc;
3568 qi->ic = ic;
3569 qi->rc = rc;
3570 qi = dq ? &qe->count : &qe->dq;
3571 qi->bc = qi->ic = qi->rc = 0;
3572 qe->next = qt[qh];
3573 qt[qh] = qe;
3574 }
3575
3576 static void
3577 quota_check(
3578 char *s,
3579 qdata_t **qt)
3580 {
3581 int i;
3582 qdata_t *next;
3583 qdata_t *qp;
3584
3585 for (i = 0; i < QDATA_HASH_SIZE; i++) {
3586 qp = qt[i];
3587 while (qp) {
3588 next = qp->next;
3589 if (qp->count.bc != qp->dq.bc ||
3590 qp->count.ic != qp->dq.ic ||
3591 qp->count.rc != qp->dq.rc) {
3592 if (!sflag) {
3593 dbprintf(_("%s quota id %u, have/exp"),
3594 s, qp->id);
3595 if (qp->count.bc != qp->dq.bc)
3596 dbprintf(_(" bc %lld/%lld"),
3597 qp->dq.bc,
3598 qp->count.bc);
3599 if (qp->count.ic != qp->dq.ic)
3600 dbprintf(_(" ic %lld/%lld"),
3601 qp->dq.ic,
3602 qp->count.ic);
3603 if (qp->count.rc != qp->dq.rc)
3604 dbprintf(_(" rc %lld/%lld"),
3605 qp->dq.rc,
3606 qp->count.rc);
3607 dbprintf("\n");
3608 }
3609 error++;
3610 }
3611 xfree(qp);
3612 qp = next;
3613 }
3614 }
3615 xfree(qt);
3616 }
3617
3618 static void
3619 quota_init(void)
3620 {
3621 qudo = mp->m_sb.sb_uquotino != 0 &&
3622 mp->m_sb.sb_uquotino != NULLFSINO &&
3623 (mp->m_sb.sb_qflags & XFS_UQUOTA_ACCT) &&
3624 (mp->m_sb.sb_qflags & XFS_UQUOTA_CHKD);
3625 qgdo = mp->m_sb.sb_gquotino != 0 &&
3626 mp->m_sb.sb_gquotino != NULLFSINO &&
3627 (mp->m_sb.sb_qflags & XFS_GQUOTA_ACCT) &&
3628 (mp->m_sb.sb_qflags & XFS_GQUOTA_CHKD);
3629 qpdo = mp->m_sb.sb_pquotino != 0 &&
3630 mp->m_sb.sb_pquotino != NULLFSINO &&
3631 (mp->m_sb.sb_qflags & XFS_PQUOTA_ACCT) &&
3632 (mp->m_sb.sb_qflags & XFS_PQUOTA_CHKD);
3633 if (qudo)
3634 qudata = xcalloc(QDATA_HASH_SIZE, sizeof(qdata_t *));
3635 if (qgdo)
3636 qgdata = xcalloc(QDATA_HASH_SIZE, sizeof(qdata_t *));
3637 if (qpdo)
3638 qpdata = xcalloc(QDATA_HASH_SIZE, sizeof(qdata_t *));
3639 }
3640
3641 static void
3642 scan_ag(
3643 xfs_agnumber_t agno)
3644 {
3645 xfs_agf_t *agf;
3646 xfs_agi_t *agi;
3647 int i;
3648 xfs_sb_t tsb;
3649 xfs_sb_t *sb = &tsb;
3650
3651 agffreeblks = agflongest = 0;
3652 agfbtreeblks = -2;
3653 agicount = agifreecount = 0;
3654 push_cur(); /* 1 pushed */
3655 set_cur(&typtab[TYP_SB],
3656 XFS_AG_DADDR(mp, agno, XFS_SB_DADDR),
3657 XFS_FSS_TO_BB(mp, 1), DB_RING_IGN, NULL);
3658
3659 if (!iocur_top->data) {
3660 dbprintf(_("can't read superblock for ag %u\n"), agno);
3661 serious_error++;
3662 goto pop1_out;
3663 }
3664
3665 libxfs_sb_from_disk(sb, iocur_top->data);
3666
3667 if (sb->sb_magicnum != XFS_SB_MAGIC) {
3668 if (!sflag)
3669 dbprintf(_("bad sb magic # %#x in ag %u\n"),
3670 sb->sb_magicnum, agno);
3671 error++;
3672 }
3673 if (!xfs_sb_good_version(sb)) {
3674 if (!sflag)
3675 dbprintf(_("bad sb version # %#x in ag %u\n"),
3676 sb->sb_versionnum, agno);
3677 error++;
3678 sbver_err++;
3679 }
3680 if (!lazycount && xfs_sb_version_haslazysbcount(sb)) {
3681 lazycount = 1;
3682 }
3683 if (agno == 0 && sb->sb_inprogress != 0) {
3684 if (!sflag)
3685 dbprintf(_("mkfs not completed successfully\n"));
3686 error++;
3687 }
3688 set_dbmap(agno, XFS_SB_BLOCK(mp), 1, DBM_SB, agno, XFS_SB_BLOCK(mp));
3689 if (sb->sb_logstart && XFS_FSB_TO_AGNO(mp, sb->sb_logstart) == agno)
3690 set_dbmap(agno, XFS_FSB_TO_AGBNO(mp, sb->sb_logstart),
3691 sb->sb_logblocks, DBM_LOG, agno, XFS_SB_BLOCK(mp));
3692 push_cur(); /* 2 pushed */
3693 set_cur(&typtab[TYP_AGF],
3694 XFS_AG_DADDR(mp, agno, XFS_AGF_DADDR(mp)),
3695 XFS_FSS_TO_BB(mp, 1), DB_RING_IGN, NULL);
3696 if ((agf = iocur_top->data) == NULL) {
3697 dbprintf(_("can't read agf block for ag %u\n"), agno);
3698 serious_error++;
3699 goto pop2_out;
3700 }
3701 if (be32_to_cpu(agf->agf_magicnum) != XFS_AGF_MAGIC) {
3702 if (!sflag)
3703 dbprintf(_("bad agf magic # %#x in ag %u\n"),
3704 be32_to_cpu(agf->agf_magicnum), agno);
3705 error++;
3706 }
3707 if (!XFS_AGF_GOOD_VERSION(be32_to_cpu(agf->agf_versionnum))) {
3708 if (!sflag)
3709 dbprintf(_("bad agf version # %#x in ag %u\n"),
3710 be32_to_cpu(agf->agf_versionnum), agno);
3711 error++;
3712 }
3713 if (XFS_SB_BLOCK(mp) != XFS_AGF_BLOCK(mp))
3714 set_dbmap(agno, XFS_AGF_BLOCK(mp), 1, DBM_AGF, agno,
3715 XFS_SB_BLOCK(mp));
3716 if (sb->sb_agblocks > be32_to_cpu(agf->agf_length))
3717 set_dbmap(agno, be32_to_cpu(agf->agf_length),
3718 sb->sb_agblocks - be32_to_cpu(agf->agf_length),
3719 DBM_MISSING, agno, XFS_SB_BLOCK(mp));
3720 push_cur(); /* 3 pushed */
3721 set_cur(&typtab[TYP_AGI],
3722 XFS_AG_DADDR(mp, agno, XFS_AGI_DADDR(mp)),
3723 XFS_FSS_TO_BB(mp, 1), DB_RING_IGN, NULL);
3724 if ((agi = iocur_top->data) == NULL) {
3725 dbprintf(_("can't read agi block for ag %u\n"), agno);
3726 serious_error++;
3727 goto pop3_out;
3728 }
3729 if (be32_to_cpu(agi->agi_magicnum) != XFS_AGI_MAGIC) {
3730 if (!sflag)
3731 dbprintf(_("bad agi magic # %#x in ag %u\n"),
3732 be32_to_cpu(agi->agi_magicnum), agno);
3733 error++;
3734 }
3735 if (!XFS_AGI_GOOD_VERSION(be32_to_cpu(agi->agi_versionnum))) {
3736 if (!sflag)
3737 dbprintf(_("bad agi version # %#x in ag %u\n"),
3738 be32_to_cpu(agi->agi_versionnum), agno);
3739 error++;
3740 }
3741 if (XFS_SB_BLOCK(mp) != XFS_AGI_BLOCK(mp) &&
3742 XFS_AGF_BLOCK(mp) != XFS_AGI_BLOCK(mp))
3743 set_dbmap(agno, XFS_AGI_BLOCK(mp), 1, DBM_AGI, agno,
3744 XFS_SB_BLOCK(mp));
3745 scan_freelist(agf);
3746 fdblocks--;
3747 scan_sbtree(agf,
3748 be32_to_cpu(agf->agf_roots[XFS_BTNUM_BNO]),
3749 be32_to_cpu(agf->agf_levels[XFS_BTNUM_BNO]),
3750 1, scanfunc_bno, TYP_BNOBT);
3751 fdblocks--;
3752 scan_sbtree(agf,
3753 be32_to_cpu(agf->agf_roots[XFS_BTNUM_CNT]),
3754 be32_to_cpu(agf->agf_levels[XFS_BTNUM_CNT]),
3755 1, scanfunc_cnt, TYP_CNTBT);
3756 scan_sbtree(agf,
3757 be32_to_cpu(agi->agi_root),
3758 be32_to_cpu(agi->agi_level),
3759 1, scanfunc_ino, TYP_INOBT);
3760 if (be32_to_cpu(agf->agf_freeblks) != agffreeblks) {
3761 if (!sflag)
3762 dbprintf(_("agf_freeblks %u, counted %u in ag %u\n"),
3763 be32_to_cpu(agf->agf_freeblks),
3764 agffreeblks, agno);
3765 error++;
3766 }
3767 if (be32_to_cpu(agf->agf_longest) != agflongest) {
3768 if (!sflag)
3769 dbprintf(_("agf_longest %u, counted %u in ag %u\n"),
3770 be32_to_cpu(agf->agf_longest),
3771 agflongest, agno);
3772 error++;
3773 }
3774 if (lazycount &&
3775 be32_to_cpu(agf->agf_btreeblks) != agfbtreeblks) {
3776 if (!sflag)
3777 dbprintf(_("agf_btreeblks %u, counted %u in ag %u\n"),
3778 be32_to_cpu(agf->agf_btreeblks),
3779 agfbtreeblks, agno);
3780 error++;
3781 }
3782 agf_aggr_freeblks += agffreeblks + agfbtreeblks;
3783 if (be32_to_cpu(agi->agi_count) != agicount) {
3784 if (!sflag)
3785 dbprintf(_("agi_count %u, counted %u in ag %u\n"),
3786 be32_to_cpu(agi->agi_count),
3787 agicount, agno);
3788 error++;
3789 }
3790 if (be32_to_cpu(agi->agi_freecount) != agifreecount) {
3791 if (!sflag)
3792 dbprintf(_("agi_freecount %u, counted %u in ag %u\n"),
3793 be32_to_cpu(agi->agi_freecount),
3794 agifreecount, agno);
3795 error++;
3796 }
3797 for (i = 0; i < XFS_AGI_UNLINKED_BUCKETS; i++) {
3798 if (be32_to_cpu(agi->agi_unlinked[i]) != NULLAGINO) {
3799 if (!sflag) {
3800 xfs_agino_t agino=be32_to_cpu(agi->agi_unlinked[i]);
3801 dbprintf(_("agi unlinked bucket %d is %u in ag "
3802 "%u (inode=%lld)\n"), i, agino, agno,
3803 XFS_AGINO_TO_INO(mp, agno, agino));
3804 }
3805 error++;
3806 }
3807 }
3808 pop3_out:
3809 pop_cur();
3810 pop2_out:
3811 pop_cur();
3812 pop1_out:
3813 pop_cur();
3814 }
3815
3816 static void
3817 scan_freelist(
3818 xfs_agf_t *agf)
3819 {
3820 xfs_agnumber_t seqno = be32_to_cpu(agf->agf_seqno);
3821 xfs_agfl_t *agfl;
3822 xfs_agblock_t bno;
3823 uint count;
3824 int i;
3825 __be32 *freelist;
3826
3827 if (XFS_SB_BLOCK(mp) != XFS_AGFL_BLOCK(mp) &&
3828 XFS_AGF_BLOCK(mp) != XFS_AGFL_BLOCK(mp) &&
3829 XFS_AGI_BLOCK(mp) != XFS_AGFL_BLOCK(mp))
3830 set_dbmap(seqno, XFS_AGFL_BLOCK(mp), 1, DBM_AGFL, seqno,
3831 XFS_SB_BLOCK(mp));
3832 if (be32_to_cpu(agf->agf_flcount) == 0)
3833 return;
3834 push_cur();
3835 set_cur(&typtab[TYP_AGFL],
3836 XFS_AG_DADDR(mp, seqno, XFS_AGFL_DADDR(mp)),
3837 XFS_FSS_TO_BB(mp, 1), DB_RING_IGN, NULL);
3838 if ((agfl = iocur_top->data) == NULL) {
3839 dbprintf(_("can't read agfl block for ag %u\n"), seqno);
3840 serious_error++;
3841 pop_cur();
3842 return;
3843 }
3844 i = be32_to_cpu(agf->agf_flfirst);
3845
3846 /* verify agf values before proceeding */
3847 if (be32_to_cpu(agf->agf_flfirst) >= XFS_AGFL_SIZE(mp) ||
3848 be32_to_cpu(agf->agf_fllast) >= XFS_AGFL_SIZE(mp)) {
3849 dbprintf(_("agf %d freelist blocks bad, skipping "
3850 "freelist scan\n"), i);
3851 pop_cur();
3852 return;
3853 }
3854
3855 /* open coded XFS_BUF_TO_AGFL_BNO */
3856 freelist = xfs_sb_version_hascrc(&((mp)->m_sb)) ? &agfl->agfl_bno[0]
3857 : (__be32 *)agfl;
3858 count = 0;
3859 for (;;) {
3860 bno = be32_to_cpu(freelist[i]);
3861 set_dbmap(seqno, bno, 1, DBM_FREELIST, seqno,
3862 XFS_AGFL_BLOCK(mp));
3863 count++;
3864 if (i == be32_to_cpu(agf->agf_fllast))
3865 break;
3866 if (++i == XFS_AGFL_SIZE(mp))
3867 i = 0;
3868 }
3869 if (count != be32_to_cpu(agf->agf_flcount)) {
3870 if (!sflag)
3871 dbprintf(_("freeblk count %u != flcount %u in ag %u\n"),
3872 count, be32_to_cpu(agf->agf_flcount),
3873 seqno);
3874 error++;
3875 }
3876 fdblocks += count;
3877 agf_aggr_freeblks += count;
3878 pop_cur();
3879 }
3880
3881 static void
3882 scan_lbtree(
3883 xfs_fsblock_t root,
3884 int nlevels,
3885 scan_lbtree_f_t func,
3886 dbm_t type,
3887 inodata_t *id,
3888 xfs_drfsbno_t *totd,
3889 xfs_drfsbno_t *toti,
3890 xfs_extnum_t *nex,
3891 blkmap_t **blkmapp,
3892 int isroot,
3893 typnm_t btype)
3894 {
3895 push_cur();
3896 set_cur(&typtab[btype], XFS_FSB_TO_DADDR(mp, root), blkbb, DB_RING_IGN,
3897 NULL);
3898 if (iocur_top->data == NULL) {
3899 if (!sflag)
3900 dbprintf(_("can't read btree block %u/%u\n"),
3901 XFS_FSB_TO_AGNO(mp, root),
3902 XFS_FSB_TO_AGBNO(mp, root));
3903 error++;
3904 pop_cur();
3905 return;
3906 }
3907 (*func)(iocur_top->data, nlevels - 1, type, root, id, totd, toti, nex,
3908 blkmapp, isroot, btype);
3909 pop_cur();
3910 }
3911
3912 static void
3913 scan_sbtree(
3914 xfs_agf_t *agf,
3915 xfs_agblock_t root,
3916 int nlevels,
3917 int isroot,
3918 scan_sbtree_f_t func,
3919 typnm_t btype)
3920 {
3921 xfs_agnumber_t seqno = be32_to_cpu(agf->agf_seqno);
3922
3923 push_cur();
3924 set_cur(&typtab[btype],
3925 XFS_AGB_TO_DADDR(mp, seqno, root), blkbb, DB_RING_IGN, NULL);
3926 if (iocur_top->data == NULL) {
3927 if (!sflag)
3928 dbprintf(_("can't read btree block %u/%u\n"), seqno, root);
3929 error++;
3930 pop_cur();
3931 return;
3932 }
3933 (*func)(iocur_top->data, nlevels - 1, agf, root, isroot);
3934 pop_cur();
3935 }
3936
3937 static void
3938 scanfunc_bmap(
3939 struct xfs_btree_block *block,
3940 int level,
3941 dbm_t type,
3942 xfs_fsblock_t bno,
3943 inodata_t *id,
3944 xfs_drfsbno_t *totd,
3945 xfs_drfsbno_t *toti,
3946 xfs_extnum_t *nex,
3947 blkmap_t **blkmapp,
3948 int isroot,
3949 typnm_t btype)
3950 {
3951 xfs_agblock_t agbno;
3952 xfs_agnumber_t agno;
3953 int i;
3954 xfs_bmbt_ptr_t *pp;
3955 xfs_bmbt_rec_t *rp;
3956
3957 agno = XFS_FSB_TO_AGNO(mp, bno);
3958 agbno = XFS_FSB_TO_AGBNO(mp, bno);
3959 if (be32_to_cpu(block->bb_magic) != XFS_BMAP_MAGIC) {
3960 if (!sflag || id->ilist || CHECK_BLIST(bno))
3961 dbprintf(_("bad magic # %#x in inode %lld bmbt block "
3962 "%u/%u\n"),
3963 be32_to_cpu(block->bb_magic), id->ino, agno, agbno);
3964 error++;
3965 }
3966 if (be16_to_cpu(block->bb_level) != level) {
3967 if (!sflag || id->ilist || CHECK_BLIST(bno))
3968 dbprintf(_("expected level %d got %d in inode %lld bmbt "
3969 "block %u/%u\n"),
3970 level, be16_to_cpu(block->bb_level), id->ino, agno, agbno);
3971 error++;
3972 }
3973 set_dbmap(agno, agbno, 1, type, agno, agbno);
3974 set_inomap(agno, agbno, 1, id);
3975 (*toti)++;
3976 if (level == 0) {
3977 if (be16_to_cpu(block->bb_numrecs) > mp->m_bmap_dmxr[0] ||
3978 (isroot == 0 && be16_to_cpu(block->bb_numrecs) < mp->m_bmap_dmnr[0])) {
3979 if (!sflag || id->ilist || CHECK_BLIST(bno))
3980 dbprintf(_("bad btree nrecs (%u, min=%u, max=%u) "
3981 "in inode %lld bmap block %lld\n"),
3982 be16_to_cpu(block->bb_numrecs), mp->m_bmap_dmnr[0],
3983 mp->m_bmap_dmxr[0], id->ino,
3984 (xfs_dfsbno_t)bno);
3985 error++;
3986 return;
3987 }
3988 rp = XFS_BMBT_REC_ADDR(mp, block, 1);
3989 *nex += be16_to_cpu(block->bb_numrecs);
3990 process_bmbt_reclist(rp, be16_to_cpu(block->bb_numrecs), type, id, totd,
3991 blkmapp);
3992 return;
3993 }
3994 if (be16_to_cpu(block->bb_numrecs) > mp->m_bmap_dmxr[1] ||
3995 (isroot == 0 && be16_to_cpu(block->bb_numrecs) < mp->m_bmap_dmnr[1])) {
3996 if (!sflag || id->ilist || CHECK_BLIST(bno))
3997 dbprintf(_("bad btree nrecs (%u, min=%u, max=%u) in "
3998 "inode %lld bmap block %lld\n"),
3999 be16_to_cpu(block->bb_numrecs), mp->m_bmap_dmnr[1],
4000 mp->m_bmap_dmxr[1], id->ino, (xfs_dfsbno_t)bno);
4001 error++;
4002 return;
4003 }
4004 pp = XFS_BMBT_PTR_ADDR(mp, block, 1, mp->m_bmap_dmxr[0]);
4005 for (i = 0; i < be16_to_cpu(block->bb_numrecs); i++)
4006 scan_lbtree(be64_to_cpu(pp[i]), level, scanfunc_bmap, type, id,
4007 totd, toti, nex, blkmapp, 0, btype);
4008 }
4009
4010 static void
4011 scanfunc_bno(
4012 struct xfs_btree_block *block,
4013 int level,
4014 xfs_agf_t *agf,
4015 xfs_agblock_t bno,
4016 int isroot)
4017 {
4018 int i;
4019 xfs_alloc_ptr_t *pp;
4020 xfs_alloc_rec_t *rp;
4021 xfs_agnumber_t seqno = be32_to_cpu(agf->agf_seqno);
4022 xfs_agblock_t lastblock;
4023
4024 if (be32_to_cpu(block->bb_magic) != XFS_ABTB_MAGIC) {
4025 dbprintf(_("bad magic # %#x in btbno block %u/%u\n"),
4026 be32_to_cpu(block->bb_magic), seqno, bno);
4027 serious_error++;
4028 return;
4029 }
4030 fdblocks++;
4031 agfbtreeblks++;
4032 if (be16_to_cpu(block->bb_level) != level) {
4033 if (!sflag)
4034 dbprintf(_("expected level %d got %d in btbno block "
4035 "%u/%u\n"),
4036 level, be16_to_cpu(block->bb_level), seqno, bno);
4037 error++;
4038 }
4039 set_dbmap(seqno, bno, 1, DBM_BTBNO, seqno, bno);
4040 if (level == 0) {
4041 if (be16_to_cpu(block->bb_numrecs) > mp->m_alloc_mxr[0] ||
4042 (isroot == 0 && be16_to_cpu(block->bb_numrecs) < mp->m_alloc_mnr[0])) {
4043 dbprintf(_("bad btree nrecs (%u, min=%u, max=%u) in "
4044 "btbno block %u/%u\n"),
4045 be16_to_cpu(block->bb_numrecs), mp->m_alloc_mnr[0],
4046 mp->m_alloc_mxr[0], seqno, bno);
4047 serious_error++;
4048 return;
4049 }
4050 rp = XFS_ALLOC_REC_ADDR(mp, block, 1);
4051 lastblock = 0;
4052 for (i = 0; i < be16_to_cpu(block->bb_numrecs); i++) {
4053 set_dbmap(seqno, be32_to_cpu(rp[i].ar_startblock),
4054 be32_to_cpu(rp[i].ar_blockcount), DBM_FREE1,
4055 seqno, bno);
4056 if (be32_to_cpu(rp[i].ar_startblock) <= lastblock) {
4057 dbprintf(_(
4058 "out-of-order bno btree record %d (%u %u) block %u/%u\n"),
4059 i, be32_to_cpu(rp[i].ar_startblock),
4060 be32_to_cpu(rp[i].ar_blockcount),
4061 be32_to_cpu(agf->agf_seqno), bno);
4062 serious_error++;
4063 } else {
4064 lastblock = be32_to_cpu(rp[i].ar_startblock);
4065 }
4066 }
4067 return;
4068 }
4069 if (be16_to_cpu(block->bb_numrecs) > mp->m_alloc_mxr[1] ||
4070 (isroot == 0 && be16_to_cpu(block->bb_numrecs) < mp->m_alloc_mnr[1])) {
4071 dbprintf(_("bad btree nrecs (%u, min=%u, max=%u) in btbno block "
4072 "%u/%u\n"),
4073 be16_to_cpu(block->bb_numrecs), mp->m_alloc_mnr[1],
4074 mp->m_alloc_mxr[1], seqno, bno);
4075 serious_error++;
4076 return;
4077 }
4078 pp = XFS_ALLOC_PTR_ADDR(mp, block, 1, mp->m_alloc_mxr[1]);
4079 for (i = 0; i < be16_to_cpu(block->bb_numrecs); i++)
4080 scan_sbtree(agf, be32_to_cpu(pp[i]), level, 0, scanfunc_bno, TYP_BNOBT);
4081 }
4082
4083 static void
4084 scanfunc_cnt(
4085 struct xfs_btree_block *block,
4086 int level,
4087 xfs_agf_t *agf,
4088 xfs_agblock_t bno,
4089 int isroot)
4090 {
4091 xfs_agnumber_t seqno = be32_to_cpu(agf->agf_seqno);
4092 int i;
4093 xfs_alloc_ptr_t *pp;
4094 xfs_alloc_rec_t *rp;
4095 xfs_extlen_t lastcount;
4096
4097 if (be32_to_cpu(block->bb_magic) != XFS_ABTC_MAGIC) {
4098 dbprintf(_("bad magic # %#x in btcnt block %u/%u\n"),
4099 be32_to_cpu(block->bb_magic), seqno, bno);
4100 serious_error++;
4101 return;
4102 }
4103 fdblocks++;
4104 agfbtreeblks++;
4105 if (be16_to_cpu(block->bb_level) != level) {
4106 if (!sflag)
4107 dbprintf(_("expected level %d got %d in btcnt block "
4108 "%u/%u\n"),
4109 level, be16_to_cpu(block->bb_level), seqno, bno);
4110 error++;
4111 }
4112 set_dbmap(seqno, bno, 1, DBM_BTCNT, seqno, bno);
4113 if (level == 0) {
4114 if (be16_to_cpu(block->bb_numrecs) > mp->m_alloc_mxr[0] ||
4115 (isroot == 0 && be16_to_cpu(block->bb_numrecs) < mp->m_alloc_mnr[0])) {
4116 dbprintf(_("bad btree nrecs (%u, min=%u, max=%u) in "
4117 "btbno block %u/%u\n"),
4118 be16_to_cpu(block->bb_numrecs), mp->m_alloc_mnr[0],
4119 mp->m_alloc_mxr[0], seqno, bno);
4120 serious_error++;
4121 return;
4122 }
4123 rp = XFS_ALLOC_REC_ADDR(mp, block, 1);
4124 lastcount = 0;
4125 for (i = 0; i < be16_to_cpu(block->bb_numrecs); i++) {
4126 check_set_dbmap(seqno, be32_to_cpu(rp[i].ar_startblock),
4127 be32_to_cpu(rp[i].ar_blockcount), DBM_FREE1, DBM_FREE2,
4128 seqno, bno);
4129 fdblocks += be32_to_cpu(rp[i].ar_blockcount);
4130 agffreeblks += be32_to_cpu(rp[i].ar_blockcount);
4131 if (be32_to_cpu(rp[i].ar_blockcount) > agflongest)
4132 agflongest = be32_to_cpu(rp[i].ar_blockcount);
4133 if (be32_to_cpu(rp[i].ar_blockcount) < lastcount) {
4134 dbprintf(_(
4135 "out-of-order cnt btree record %d (%u %u) block %u/%u\n"),
4136 i, be32_to_cpu(rp[i].ar_startblock),
4137 be32_to_cpu(rp[i].ar_blockcount),
4138 be32_to_cpu(agf->agf_seqno), bno);
4139 } else {
4140 lastcount = be32_to_cpu(rp[i].ar_blockcount);
4141 }
4142 }
4143 return;
4144 }
4145 if (be16_to_cpu(block->bb_numrecs) > mp->m_alloc_mxr[1] ||
4146 (isroot == 0 && be16_to_cpu(block->bb_numrecs) < mp->m_alloc_mnr[1])) {
4147 dbprintf(_("bad btree nrecs (%u, min=%u, max=%u) in btbno block "
4148 "%u/%u\n"),
4149 be16_to_cpu(block->bb_numrecs), mp->m_alloc_mnr[1],
4150 mp->m_alloc_mxr[1], seqno, bno);
4151 serious_error++;
4152 return;
4153 }
4154 pp = XFS_ALLOC_PTR_ADDR(mp, block, 1, mp->m_alloc_mxr[1]);
4155 for (i = 0; i < be16_to_cpu(block->bb_numrecs); i++)
4156 scan_sbtree(agf, be32_to_cpu(pp[i]), level, 0, scanfunc_cnt, TYP_CNTBT);
4157 }
4158
4159 static void
4160 scanfunc_ino(
4161 struct xfs_btree_block *block,
4162 int level,
4163 xfs_agf_t *agf,
4164 xfs_agblock_t bno,
4165 int isroot)
4166 {
4167 xfs_agino_t agino;
4168 xfs_agnumber_t seqno = be32_to_cpu(agf->agf_seqno);
4169 int i;
4170 int isfree;
4171 int j;
4172 int nfree;
4173 int off;
4174 xfs_inobt_ptr_t *pp;
4175 xfs_inobt_rec_t *rp;
4176
4177 if (be32_to_cpu(block->bb_magic) != XFS_IBT_MAGIC) {
4178 dbprintf(_("bad magic # %#x in inobt block %u/%u\n"),
4179 be32_to_cpu(block->bb_magic), seqno, bno);
4180 serious_error++;
4181 return;
4182 }
4183 if (be16_to_cpu(block->bb_level) != level) {
4184 if (!sflag)
4185 dbprintf(_("expected level %d got %d in inobt block "
4186 "%u/%u\n"),
4187 level, be16_to_cpu(block->bb_level), seqno, bno);
4188 error++;
4189 }
4190 set_dbmap(seqno, bno, 1, DBM_BTINO, seqno, bno);
4191 if (level == 0) {
4192 if (be16_to_cpu(block->bb_numrecs) > mp->m_inobt_mxr[0] ||
4193 (isroot == 0 && be16_to_cpu(block->bb_numrecs) < mp->m_inobt_mnr[0])) {
4194 dbprintf(_("bad btree nrecs (%u, min=%u, max=%u) in "
4195 "inobt block %u/%u\n"),
4196 be16_to_cpu(block->bb_numrecs), mp->m_inobt_mnr[0],
4197 mp->m_inobt_mxr[0], seqno, bno);
4198 serious_error++;
4199 return;
4200 }
4201 rp = XFS_INOBT_REC_ADDR(mp, block, 1);
4202 for (i = 0; i < be16_to_cpu(block->bb_numrecs); i++) {
4203 agino = be32_to_cpu(rp[i].ir_startino);
4204 off = XFS_INO_TO_OFFSET(mp, agino);
4205 if (off == 0) {
4206 if ((sbversion & XFS_SB_VERSION_ALIGNBIT) &&
4207 mp->m_sb.sb_inoalignmt &&
4208 (XFS_INO_TO_AGBNO(mp, agino) %
4209 mp->m_sb.sb_inoalignmt))
4210 sbversion &= ~XFS_SB_VERSION_ALIGNBIT;
4211 set_dbmap(seqno, XFS_AGINO_TO_AGBNO(mp, agino),
4212 (xfs_extlen_t)MAX(1,
4213 XFS_INODES_PER_CHUNK >>
4214 mp->m_sb.sb_inopblog),
4215 DBM_INODE, seqno, bno);
4216 }
4217 icount += XFS_INODES_PER_CHUNK;
4218 agicount += XFS_INODES_PER_CHUNK;
4219 ifree += be32_to_cpu(rp[i].ir_freecount);
4220 agifreecount += be32_to_cpu(rp[i].ir_freecount);
4221 push_cur();
4222 set_cur(&typtab[TYP_INODE],
4223 XFS_AGB_TO_DADDR(mp, seqno,
4224 XFS_AGINO_TO_AGBNO(mp, agino)),
4225 (int)XFS_FSB_TO_BB(mp, mp->m_ialloc_blks),
4226 DB_RING_IGN, NULL);
4227 if (iocur_top->data == NULL) {
4228 if (!sflag)
4229 dbprintf(_("can't read inode block "
4230 "%u/%u\n"),
4231 seqno,
4232 XFS_AGINO_TO_AGBNO(mp, agino));
4233 error++;
4234 pop_cur();
4235 continue;
4236 }
4237 for (j = 0, nfree = 0; j < XFS_INODES_PER_CHUNK; j++) {
4238 isfree = XFS_INOBT_IS_FREE_DISK(&rp[i], j);
4239 if (isfree)
4240 nfree++;
4241 process_inode(agf, agino + j,
4242 (xfs_dinode_t *)((char *)iocur_top->data + ((off + j) << mp->m_sb.sb_inodelog)),
4243 isfree);
4244 }
4245 if (nfree != be32_to_cpu(rp[i].ir_freecount)) {
4246 if (!sflag)
4247 dbprintf(_("ir_freecount/free mismatch, "
4248 "inode chunk %u/%u, freecount "
4249 "%d nfree %d\n"),
4250 seqno, agino,
4251 be32_to_cpu(rp[i].ir_freecount), nfree);
4252 error++;
4253 }
4254 pop_cur();
4255 }
4256 return;
4257 }
4258 if (be16_to_cpu(block->bb_numrecs) > mp->m_inobt_mxr[1] ||
4259 (isroot == 0 && be16_to_cpu(block->bb_numrecs) < mp->m_inobt_mnr[1])) {
4260 dbprintf(_("bad btree nrecs (%u, min=%u, max=%u) in inobt block "
4261 "%u/%u\n"),
4262 be16_to_cpu(block->bb_numrecs), mp->m_inobt_mnr[1],
4263 mp->m_inobt_mxr[1], seqno, bno);
4264 serious_error++;
4265 return;
4266 }
4267 pp = XFS_INOBT_PTR_ADDR(mp, block, 1, mp->m_inobt_mxr[1]);
4268 for (i = 0; i < be16_to_cpu(block->bb_numrecs); i++)
4269 scan_sbtree(agf, be32_to_cpu(pp[i]), level, 0, scanfunc_ino, TYP_INOBT);
4270 }
4271
4272 static void
4273 set_dbmap(
4274 xfs_agnumber_t agno,
4275 xfs_agblock_t agbno,
4276 xfs_extlen_t len,
4277 dbm_t type,
4278 xfs_agnumber_t c_agno,
4279 xfs_agblock_t c_agbno)
4280 {
4281 check_set_dbmap(agno, agbno, len, DBM_UNKNOWN, type, c_agno, c_agbno);
4282 }
4283
4284 static void
4285 set_inomap(
4286 xfs_agnumber_t agno,
4287 xfs_agblock_t agbno,
4288 xfs_extlen_t len,
4289 inodata_t *id)
4290 {
4291 xfs_extlen_t i;
4292 inodata_t **idp;
4293 int mayprint;
4294
4295 if (!check_inomap(agno, agbno, len, id->ino))
4296 return;
4297 mayprint = verbose | id->ilist | blist_size;
4298 for (i = 0, idp = &inomap[agno][agbno]; i < len; i++, idp++) {
4299 *idp = id;
4300 if (mayprint &&
4301 (verbose || id->ilist || CHECK_BLISTA(agno, agbno + i)))
4302 dbprintf(_("setting inode to %lld for block %u/%u\n"),
4303 id->ino, agno, agbno + i);
4304 }
4305 }
4306
4307 static void
4308 set_rdbmap(
4309 xfs_drfsbno_t bno,
4310 xfs_extlen_t len,
4311 dbm_t type)
4312 {
4313 check_set_rdbmap(bno, len, DBM_UNKNOWN, type);
4314 }
4315
4316 static void
4317 set_rinomap(
4318 xfs_drfsbno_t bno,
4319 xfs_extlen_t len,
4320 inodata_t *id)
4321 {
4322 xfs_extlen_t i;
4323 inodata_t **idp;
4324 int mayprint;
4325
4326 if (!check_rinomap(bno, len, id->ino))
4327 return;
4328 mayprint = verbose | id->ilist | blist_size;
4329 for (i = 0, idp = &inomap[mp->m_sb.sb_agcount][bno];
4330 i < len;
4331 i++, idp++) {
4332 *idp = id;
4333 if (mayprint && (verbose || id->ilist || CHECK_BLIST(bno + i)))
4334 dbprintf(_("setting inode to %lld for rtblock %llu\n"),
4335 id->ino, bno + i);
4336 }
4337 }
4338
4339 static void
4340 setlink_inode(
4341 inodata_t *id,
4342 nlink_t nlink,
4343 int isdir,
4344 int security)
4345 {
4346 id->link_set = nlink;
4347 id->isdir = isdir;
4348 id->security = security;
4349 if (verbose || id->ilist)
4350 dbprintf(_("inode %lld nlink %u %s dir\n"), id->ino, nlink,
4351 isdir ? "is" : "not");
4352 }