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