~ubuntu-branches/ubuntu/utopic/xfsprogs/utopic-proposed

« back to all changes in this revision

Viewing changes to db/check.c

  • Committer: Bazaar Package Importer
  • Author(s): Nathan Scott
  • Date: 2002-04-13 09:45:06 UTC
  • Revision ID: james.westby@ubuntu.com-20020413094506-t8dhemv41gkeg4kx
Tags: 2.0.3-1
New upstream bugfix release

Show diffs side-by-side

added added

removed removed

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