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