0001
0002
0003
0004
0005
0006 #include "xfs.h"
0007 #include "xfs_fs.h"
0008 #include "xfs_shared.h"
0009 #include "xfs_format.h"
0010 #include "xfs_trans_resv.h"
0011 #include "xfs_mount.h"
0012 #include "xfs_alloc.h"
0013 #include "xfs_ialloc.h"
0014 #include "xfs_health.h"
0015 #include "xfs_btree.h"
0016 #include "xfs_ag.h"
0017 #include "scrub/scrub.h"
0018 #include "scrub/common.h"
0019 #include "scrub/trace.h"
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047
0048
0049
0050
0051 #define XCHK_FSCOUNT_MIN_VARIANCE (512)
0052
0053
0054
0055
0056
0057
0058
0059
0060
0061
0062
0063 STATIC int
0064 xchk_fscount_warmup(
0065 struct xfs_scrub *sc)
0066 {
0067 struct xfs_mount *mp = sc->mp;
0068 struct xfs_buf *agi_bp = NULL;
0069 struct xfs_buf *agf_bp = NULL;
0070 struct xfs_perag *pag = NULL;
0071 xfs_agnumber_t agno;
0072 int error = 0;
0073
0074 for_each_perag(mp, agno, pag) {
0075 if (xchk_should_terminate(sc, &error))
0076 break;
0077 if (pag->pagi_init && pag->pagf_init)
0078 continue;
0079
0080
0081 error = xfs_ialloc_read_agi(pag, sc->tp, &agi_bp);
0082 if (error)
0083 break;
0084 error = xfs_alloc_read_agf(pag, sc->tp, 0, &agf_bp);
0085 if (error)
0086 break;
0087
0088
0089
0090
0091
0092 if (!pag->pagi_init || !pag->pagf_init) {
0093 error = -EFSCORRUPTED;
0094 break;
0095 }
0096
0097 xfs_buf_relse(agf_bp);
0098 agf_bp = NULL;
0099 xfs_buf_relse(agi_bp);
0100 agi_bp = NULL;
0101 }
0102
0103 if (agf_bp)
0104 xfs_buf_relse(agf_bp);
0105 if (agi_bp)
0106 xfs_buf_relse(agi_bp);
0107 if (pag)
0108 xfs_perag_put(pag);
0109 return error;
0110 }
0111
0112 int
0113 xchk_setup_fscounters(
0114 struct xfs_scrub *sc)
0115 {
0116 struct xchk_fscounters *fsc;
0117 int error;
0118
0119 sc->buf = kmem_zalloc(sizeof(struct xchk_fscounters), 0);
0120 if (!sc->buf)
0121 return -ENOMEM;
0122 fsc = sc->buf;
0123
0124 xfs_icount_range(sc->mp, &fsc->icount_min, &fsc->icount_max);
0125
0126
0127 error = xchk_fscount_warmup(sc);
0128 if (error)
0129 return error;
0130
0131
0132
0133
0134
0135
0136 xchk_stop_reaping(sc);
0137
0138 return xchk_trans_alloc(sc, 0);
0139 }
0140
0141
0142 static int
0143 xchk_fscount_btreeblks(
0144 struct xfs_scrub *sc,
0145 struct xchk_fscounters *fsc,
0146 xfs_agnumber_t agno)
0147 {
0148 xfs_extlen_t blocks;
0149 int error;
0150
0151 error = xchk_ag_init_existing(sc, agno, &sc->sa);
0152 if (error)
0153 goto out_free;
0154
0155 error = xfs_btree_count_blocks(sc->sa.bno_cur, &blocks);
0156 if (error)
0157 goto out_free;
0158 fsc->fdblocks += blocks - 1;
0159
0160 error = xfs_btree_count_blocks(sc->sa.cnt_cur, &blocks);
0161 if (error)
0162 goto out_free;
0163 fsc->fdblocks += blocks - 1;
0164
0165 out_free:
0166 xchk_ag_free(sc, &sc->sa);
0167 return error;
0168 }
0169
0170
0171
0172
0173
0174
0175
0176 STATIC int
0177 xchk_fscount_aggregate_agcounts(
0178 struct xfs_scrub *sc,
0179 struct xchk_fscounters *fsc)
0180 {
0181 struct xfs_mount *mp = sc->mp;
0182 struct xfs_perag *pag;
0183 uint64_t delayed;
0184 xfs_agnumber_t agno;
0185 int tries = 8;
0186 int error = 0;
0187
0188 retry:
0189 fsc->icount = 0;
0190 fsc->ifree = 0;
0191 fsc->fdblocks = 0;
0192
0193 for_each_perag(mp, agno, pag) {
0194 if (xchk_should_terminate(sc, &error))
0195 break;
0196
0197
0198 if (!pag->pagi_init || !pag->pagf_init) {
0199 error = -EFSCORRUPTED;
0200 break;
0201 }
0202
0203
0204 fsc->icount += pag->pagi_count;
0205 fsc->ifree += pag->pagi_freecount;
0206
0207
0208 fsc->fdblocks += pag->pagf_freeblks;
0209 fsc->fdblocks += pag->pagf_flcount;
0210 if (xfs_has_lazysbcount(sc->mp)) {
0211 fsc->fdblocks += pag->pagf_btreeblks;
0212 } else {
0213 error = xchk_fscount_btreeblks(sc, fsc, agno);
0214 if (error)
0215 break;
0216 }
0217
0218
0219
0220
0221
0222 fsc->fdblocks -= pag->pag_meta_resv.ar_reserved;
0223 fsc->fdblocks -= pag->pag_rmapbt_resv.ar_orig_reserved;
0224
0225 }
0226 if (pag)
0227 xfs_perag_put(pag);
0228 if (error)
0229 return error;
0230
0231
0232
0233
0234
0235 fsc->fdblocks -= mp->m_resblks_avail;
0236
0237
0238
0239
0240
0241
0242 delayed = percpu_counter_sum(&mp->m_delalloc_blks);
0243 fsc->fdblocks -= delayed;
0244
0245 trace_xchk_fscounters_calc(mp, fsc->icount, fsc->ifree, fsc->fdblocks,
0246 delayed);
0247
0248
0249
0250 if (fsc->icount < fsc->icount_min || fsc->icount > fsc->icount_max ||
0251 fsc->fdblocks > mp->m_sb.sb_dblocks ||
0252 fsc->ifree > fsc->icount_max)
0253 return -EFSCORRUPTED;
0254
0255
0256
0257
0258
0259
0260 if (fsc->ifree > fsc->icount) {
0261 if (tries--)
0262 goto retry;
0263 xchk_set_incomplete(sc);
0264 return 0;
0265 }
0266
0267 return 0;
0268 }
0269
0270
0271
0272
0273
0274
0275
0276
0277
0278
0279
0280
0281
0282
0283 static inline bool
0284 xchk_fscount_within_range(
0285 struct xfs_scrub *sc,
0286 const int64_t old_value,
0287 struct percpu_counter *counter,
0288 uint64_t expected)
0289 {
0290 int64_t min_value, max_value;
0291 int64_t curr_value = percpu_counter_sum(counter);
0292
0293 trace_xchk_fscounters_within_range(sc->mp, expected, curr_value,
0294 old_value);
0295
0296
0297 if (curr_value < 0)
0298 return false;
0299
0300
0301 if (curr_value == expected)
0302 return true;
0303
0304 min_value = min(old_value, curr_value);
0305 max_value = max(old_value, curr_value);
0306
0307
0308 if (expected >= min_value && expected <= max_value)
0309 return true;
0310
0311
0312
0313
0314
0315
0316
0317
0318
0319
0320
0321 if (max_value - min_value >= XCHK_FSCOUNT_MIN_VARIANCE) {
0322 xchk_set_incomplete(sc);
0323 return true;
0324 }
0325
0326 return false;
0327 }
0328
0329
0330 int
0331 xchk_fscounters(
0332 struct xfs_scrub *sc)
0333 {
0334 struct xfs_mount *mp = sc->mp;
0335 struct xchk_fscounters *fsc = sc->buf;
0336 int64_t icount, ifree, fdblocks;
0337 int error;
0338
0339
0340 icount = percpu_counter_sum(&mp->m_icount);
0341 ifree = percpu_counter_sum(&mp->m_ifree);
0342 fdblocks = percpu_counter_sum(&mp->m_fdblocks);
0343
0344
0345 if (icount < 0 || ifree < 0 || fdblocks < 0)
0346 xchk_set_corrupt(sc);
0347
0348
0349 if (icount < fsc->icount_min || icount > fsc->icount_max)
0350 xchk_set_corrupt(sc);
0351
0352
0353 if (fdblocks > mp->m_sb.sb_dblocks)
0354 xchk_set_corrupt(sc);
0355
0356
0357
0358
0359
0360 if (ifree > icount && ifree - icount > XCHK_FSCOUNT_MIN_VARIANCE)
0361 xchk_set_corrupt(sc);
0362
0363
0364 error = xchk_fscount_aggregate_agcounts(sc, fsc);
0365 if (!xchk_process_error(sc, 0, XFS_SB_BLOCK(mp), &error))
0366 return error;
0367 if (sc->sm->sm_flags & XFS_SCRUB_OFLAG_INCOMPLETE)
0368 return 0;
0369
0370
0371 if (!xchk_fscount_within_range(sc, icount, &mp->m_icount, fsc->icount))
0372 xchk_set_corrupt(sc);
0373
0374 if (!xchk_fscount_within_range(sc, ifree, &mp->m_ifree, fsc->ifree))
0375 xchk_set_corrupt(sc);
0376
0377 if (!xchk_fscount_within_range(sc, fdblocks, &mp->m_fdblocks,
0378 fsc->fdblocks))
0379 xchk_set_corrupt(sc);
0380
0381 return 0;
0382 }