]> git.ipfire.org Git - thirdparty/e2fsprogs.git/blame - e2fsck/pass5.c
e2fsck: fix mysterious "FILE SYSTEM WAS MODIFIED" with no changes
[thirdparty/e2fsprogs.git] / e2fsck / pass5.c
CommitLineData
3839e657
TT
1/*
2 * pass5.c --- check block and inode bitmaps against on-disk bitmaps
efc6f628 3 *
21c84b71
TT
4 * Copyright (C) 1993, 1994, 1995, 1996, 1997 Theodore Ts'o.
5 *
6 * %Begin-Header%
7 * This file may be redistributed under the terms of the GNU Public
8 * License.
9 * %End-Header%
efc6f628 10 *
3839e657
TT
11 */
12
efa1a355
LC
13#include <stdint.h>
14#include <sys/types.h>
15#include <sys/stat.h>
16#include <sys/ioctl.h>
17#include <fcntl.h>
18#include <errno.h>
19
3839e657 20#include "e2fsck.h"
1b6bf175 21#include "problem.h"
3839e657 22
efa1a355
LC
23#define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d))
24
1b6bf175
TT
25static void check_block_bitmaps(e2fsck_t ctx);
26static void check_inode_bitmaps(e2fsck_t ctx);
27static void check_inode_end(e2fsck_t ctx);
28static void check_block_end(e2fsck_t ctx);
3839e657 29
08b21301 30void e2fsck_pass5(e2fsck_t ctx)
3839e657 31{
8bf191e8 32#ifdef RESOURCE_TRACK
3839e657 33 struct resource_track rtrack;
8bf191e8 34#endif
1b6bf175 35 struct problem_context pctx;
efc6f628 36
3839e657
TT
37#ifdef MTRACE
38 mtrace_print("Pass 5");
39#endif
40
6d96b00d 41 init_resource_track(&rtrack, ctx->fs->io);
1b6bf175 42 clear_problem_context(&pctx);
3839e657 43
1b6bf175
TT
44 if (!(ctx->options & E2F_OPT_PREEN))
45 fix_problem(ctx, PR_5_PASS_HEADER, &pctx);
3839e657 46
f8188fff 47 if (ctx->progress)
efac9a1b 48 if ((ctx->progress)(ctx, 5, 0, ctx->fs->group_desc_count*2))
a02ce9df 49 return;
f8188fff
TT
50
51 e2fsck_read_bitmaps(ctx);
52
1b6bf175 53 check_block_bitmaps(ctx);
a02ce9df 54 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
08b21301 55 return;
1b6bf175 56 check_inode_bitmaps(ctx);
a02ce9df 57 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
08b21301 58 return;
1b6bf175 59 check_inode_end(ctx);
a02ce9df 60 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
08b21301 61 return;
1b6bf175 62 check_block_end(ctx);
a02ce9df 63 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
08b21301 64 return;
3839e657 65
1b6bf175
TT
66 ext2fs_free_inode_bitmap(ctx->inode_used_map);
67 ctx->inode_used_map = 0;
68 ext2fs_free_inode_bitmap(ctx->inode_dir_map);
69 ctx->inode_dir_map = 0;
70 ext2fs_free_block_bitmap(ctx->block_found_map);
71 ctx->block_found_map = 0;
72
9facd076 73 print_resource_track(ctx, _("Pass 5"), &rtrack, ctx->fs->io);
3839e657
TT
74}
75
efa1a355
LC
76static void e2fsck_discard_blocks(e2fsck_t ctx, io_manager manager,
77 blk64_t start, blk64_t count)
78{
79 ext2_filsys fs = ctx->fs;
efa1a355
LC
80
81 /*
82 * If the filesystem has changed it means that there was an corruption
83 * which should be repaired, but in some cases just one e2fsck run is
84 * not enough to fix the problem, hence it is not safe to run discard
85 * in this case.
86 */
87 if (ext2fs_test_changed(ctx->fs))
88 ctx->options &= ~E2F_OPT_DISCARD;
89
90 if ((ctx->options & E2F_OPT_DISCARD) &&
91 (io_channel_discard(fs->io, start, count)))
92 ctx->options &= ~E2F_OPT_DISCARD;
93}
94
6dc64392 95#define NO_BLK ((blk64_t) -1)
f122632e 96
546a1ff1 97static void print_bitmap_problem(e2fsck_t ctx, int problem,
f122632e
TT
98 struct problem_context *pctx)
99{
100 switch (problem) {
101 case PR_5_BLOCK_UNUSED:
102 if (pctx->blk == pctx->blk2)
103 pctx->blk2 = 0;
104 else
105 problem = PR_5_BLOCK_RANGE_UNUSED;
106 break;
107 case PR_5_BLOCK_USED:
108 if (pctx->blk == pctx->blk2)
109 pctx->blk2 = 0;
110 else
111 problem = PR_5_BLOCK_RANGE_USED;
112 break;
113 case PR_5_INODE_UNUSED:
114 if (pctx->ino == pctx->ino2)
115 pctx->ino2 = 0;
116 else
117 problem = PR_5_INODE_RANGE_UNUSED;
118 break;
119 case PR_5_INODE_USED:
120 if (pctx->ino == pctx->ino2)
121 pctx->ino2 = 0;
122 else
123 problem = PR_5_INODE_RANGE_USED;
124 break;
125 }
126 fix_problem(ctx, problem, pctx);
127 pctx->blk = pctx->blk2 = NO_BLK;
128 pctx->ino = pctx->ino2 = 0;
129}
49e2df29 130
3385a254
TT
131/* Just to be more succint */
132#define B2C(x) EXT2FS_B2C(fs, (x))
133#define EQ_CLSTR(x, y) (B2C(x) == B2C(y))
134#define LE_CLSTR(x, y) (B2C(x) <= B2C(y))
135#define GE_CLSTR(x, y) (B2C(x) >= B2C(y))
136
1b6bf175 137static void check_block_bitmaps(e2fsck_t ctx)
3839e657 138{
1b6bf175 139 ext2_filsys fs = ctx->fs;
20f2ccb3 140 blk64_t i;
3839e657
TT
141 int *free_array;
142 int group = 0;
6dc64392
VAH
143 int blocks = 0;
144 blk64_t free_blocks = 0;
efa1a355 145 blk64_t first_free = ext2fs_blocks_count(fs->super);
3839e657
TT
146 int group_free = 0;
147 int actual, bitmap;
1b6bf175 148 struct problem_context pctx;
f122632e 149 int problem, save_problem, fixit, had_problem;
1b6bf175 150 errcode_t retval;
16b851cd 151 int csum_flag;
f5fa2007 152 int skip_group = 0;
479463aa
KM
153 int old_desc_blocks = 0;
154 int count = 0;
155 int cmp_block = 0;
156 int redo_flag = 0;
20f2ccb3 157 blk64_t super_blk, old_desc_blk, new_desc_blk;
efa1a355 158 io_manager manager = ctx->fs->io->manager;
49e2df29 159
1b6bf175 160 clear_problem_context(&pctx);
54dc7ca2 161 free_array = (int *) e2fsck_allocate_memory(ctx,
f8188fff 162 fs->group_desc_count * sizeof(int), "free block count array");
50e1e10f 163
3385a254 164 if ((B2C(fs->super->s_first_data_block) <
c5d2f50d 165 ext2fs_get_block_bitmap_start2(ctx->block_found_map)) ||
3385a254 166 (B2C(ext2fs_blocks_count(fs->super)-1) >
c5d2f50d 167 ext2fs_get_block_bitmap_end2(ctx->block_found_map))) {
1b6bf175 168 pctx.num = 1;
3385a254
TT
169 pctx.blk = B2C(fs->super->s_first_data_block);
170 pctx.blk2 = B2C(ext2fs_blocks_count(fs->super) - 1);
c5d2f50d
VAH
171 pctx.ino = ext2fs_get_block_bitmap_start2(ctx->block_found_map);
172 pctx.ino2 = ext2fs_get_block_bitmap_end2(ctx->block_found_map);
1b6bf175 173 fix_problem(ctx, PR_5_BMAP_ENDPOINTS, &pctx);
08b21301
TT
174
175 ctx->flags |= E2F_FLAG_ABORT; /* fatal */
49e2df29 176 goto errout;
50e1e10f 177 }
49e2df29 178
3385a254 179 if ((B2C(fs->super->s_first_data_block) <
c5d2f50d 180 ext2fs_get_block_bitmap_start2(fs->block_map)) ||
3385a254 181 (B2C(ext2fs_blocks_count(fs->super)-1) >
c5d2f50d 182 ext2fs_get_block_bitmap_end2(fs->block_map))) {
1b6bf175 183 pctx.num = 2;
3385a254
TT
184 pctx.blk = B2C(fs->super->s_first_data_block);
185 pctx.blk2 = B2C(ext2fs_blocks_count(fs->super) - 1);
c5d2f50d
VAH
186 pctx.ino = ext2fs_get_block_bitmap_start2(fs->block_map);
187 pctx.ino2 = ext2fs_get_block_bitmap_end2(fs->block_map);
1b6bf175 188 fix_problem(ctx, PR_5_BMAP_ENDPOINTS, &pctx);
08b21301
TT
189
190 ctx->flags |= E2F_FLAG_ABORT; /* fatal */
49e2df29 191 goto errout;
50e1e10f 192 }
49e2df29 193
49a7360b
JS
194 csum_flag = EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
195 EXT4_FEATURE_RO_COMPAT_GDT_CSUM);
63c4969c
TT
196redo_counts:
197 had_problem = 0;
f122632e
TT
198 save_problem = 0;
199 pctx.blk = pctx.blk2 = NO_BLK;
16b851cd 200 if (csum_flag &&
cd65a24e 201 (ext2fs_bg_flags_test(fs, group, EXT2_BG_BLOCK_UNINIT)))
f5fa2007 202 skip_group++;
3385a254 203 for (i = B2C(fs->super->s_first_data_block);
4efbac6f 204 i < ext2fs_blocks_count(fs->super);
44fe08f1 205 i += EXT2FS_CLUSTER_RATIO(fs)) {
c5d2f50d 206 actual = ext2fs_fast_test_block_bitmap2(ctx->block_found_map, i);
f5fa2007
TT
207
208 if (skip_group) {
3385a254
TT
209 if ((B2C(i) - B2C(fs->super->s_first_data_block)) %
210 fs->super->s_clusters_per_group == 0) {
479463aa
KM
211 super_blk = 0;
212 old_desc_blk = 0;
213 new_desc_blk = 0;
20f2ccb3 214 ext2fs_super_and_bgd_loc2(fs, group, &super_blk,
4a2924ea
TT
215 &old_desc_blk, &new_desc_blk, 0);
216
479463aa
KM
217 if (fs->super->s_feature_incompat &
218 EXT2_FEATURE_INCOMPAT_META_BG)
219 old_desc_blocks =
220 fs->super->s_first_meta_bg;
221 else
222 old_desc_blocks = fs->desc_blocks +
4a2924ea
TT
223 fs->super->s_reserved_gdt_blocks;
224
479463aa 225 count = 0;
3385a254 226 cmp_block = fs->super->s_clusters_per_group;
479463aa
KM
227 if (group == (int)fs->group_desc_count - 1)
228 cmp_block =
3385a254
TT
229 EXT2FS_NUM_B2C(fs,
230 ext2fs_blocks_count(fs->super) % fs->super->s_blocks_per_group);
479463aa
KM
231 }
232
4a2924ea 233 bitmap = 0;
3385a254 234 if (EQ_CLSTR(i, super_blk) ||
d7cca6b0 235 (old_desc_blk && old_desc_blocks &&
3385a254
TT
236 GE_CLSTR(i, old_desc_blk) &&
237 LE_CLSTR(i, old_desc_blk + old_desc_blocks-1)) ||
238 (new_desc_blk && EQ_CLSTR(i, new_desc_blk)) ||
239 EQ_CLSTR(i, ext2fs_block_bitmap_loc(fs, group)) ||
240 EQ_CLSTR(i, ext2fs_inode_bitmap_loc(fs, group)) ||
241 (GE_CLSTR(i, ext2fs_inode_table_loc(fs, group)) &&
242 LE_CLSTR(i, (ext2fs_inode_table_loc(fs, group) +
243 fs->inode_blocks_per_group - 1)))) {
4a2924ea 244 bitmap = 1;
479463aa
KM
245 actual = (actual != 0);
246 count++;
247 cmp_block--;
3385a254
TT
248 } else if ((EXT2FS_B2C(fs, i) - count -
249 EXT2FS_B2C(fs, fs->super->s_first_data_block)) %
250 fs->super->s_clusters_per_group == 0) {
479463aa
KM
251 /*
252 * When the compare data blocks in block bitmap
253 * are 0, count the free block,
254 * skip the current block group.
255 */
c5d2f50d 256 if (ext2fs_test_block_bitmap_range2(
3385a254
TT
257 ctx->block_found_map,
258 EXT2FS_B2C(fs, i),
479463aa
KM
259 cmp_block)) {
260 /*
261 * -1 means to skip the current block
262 * group.
263 */
3385a254 264 blocks = fs->super->s_clusters_per_group - 1;
479463aa
KM
265 group_free = cmp_block;
266 free_blocks += cmp_block;
267 /*
268 * The current block group's last block
269 * is set to i.
270 */
3385a254 271 i += EXT2FS_C2B(fs, cmp_block - 1);
479463aa
KM
272 bitmap = 1;
273 goto do_counts;
274 }
275 }
276 } else if (redo_flag)
277 bitmap = actual;
278 else
c5d2f50d 279 bitmap = ext2fs_fast_test_block_bitmap2(fs->block_map, i);
49e2df29 280
3839e657
TT
281 if (actual == bitmap)
282 goto do_counts;
f5fa2007 283
3839e657
TT
284 if (!actual && bitmap) {
285 /*
286 * Block not used, but marked in use in the bitmap.
287 */
f122632e 288 problem = PR_5_BLOCK_UNUSED;
3839e657
TT
289 } else {
290 /*
291 * Block used, but not marked in use in the bitmap.
292 */
1b6bf175 293 problem = PR_5_BLOCK_USED;
49a7360b
JS
294
295 if (skip_group) {
296 struct problem_context pctx2;
297 pctx2.blk = i;
298 pctx2.group = group;
299 if (fix_problem(ctx, PR_5_BLOCK_UNINIT,&pctx2)){
e633b58a 300 ext2fs_bg_flags_clear(fs, group, EXT2_BG_BLOCK_UNINIT);
49a7360b
JS
301 skip_group = 0;
302 }
303 }
3839e657 304 }
f122632e
TT
305 if (pctx.blk == NO_BLK) {
306 pctx.blk = pctx.blk2 = i;
307 save_problem = problem;
308 } else {
309 if ((problem == save_problem) &&
310 (pctx.blk2 == i-1))
311 pctx.blk2++;
312 else {
313 print_bitmap_problem(ctx, save_problem, &pctx);
314 pctx.blk = pctx.blk2 = i;
315 save_problem = problem;
316 }
317 }
5596defa 318 ctx->flags |= E2F_FLAG_PROG_SUPPRESS;
63c4969c 319 had_problem++;
49e2df29 320
efa1a355
LC
321 /*
322 * If there a problem we should turn off the discard so we
323 * do not compromise the filesystem.
324 */
325 ctx->options &= ~E2F_OPT_DISCARD;
326
3839e657 327 do_counts:
49a7360b 328 if (!bitmap && (!skip_group || csum_flag)) {
3839e657
TT
329 group_free++;
330 free_blocks++;
efa1a355
LC
331 if (first_free > i)
332 first_free = i;
333 } else {
334 if ((i > first_free) &&
335 (ctx->options & E2F_OPT_DISCARD)) {
336 e2fsck_discard_blocks(ctx, manager, first_free,
337 (i - first_free));
338 }
339 first_free = ext2fs_blocks_count(fs->super);
3839e657
TT
340 }
341 blocks ++;
44fe08f1
TT
342 if ((blocks == fs->super->s_clusters_per_group) ||
343 (EXT2FS_B2C(fs, i) ==
344 EXT2FS_B2C(fs, ext2fs_blocks_count(fs->super)-1))) {
3839e657
TT
345 free_array[group] = group_free;
346 group ++;
347 blocks = 0;
348 group_free = 0;
f5fa2007 349 skip_group = 0;
efac9a1b
TT
350 if (ctx->progress)
351 if ((ctx->progress)(ctx, 5, group,
352 fs->group_desc_count*2))
49e2df29 353 goto errout;
16b851cd 354 if (csum_flag &&
4efbac6f 355 (i != ext2fs_blocks_count(fs->super)-1) &&
cd65a24e 356 ext2fs_bg_flags_test(fs, group,
732c8cd5 357 EXT2_BG_BLOCK_UNINIT))
f5fa2007 358 skip_group++;
3839e657
TT
359 }
360 }
f122632e
TT
361 if (pctx.blk != NO_BLK)
362 print_bitmap_problem(ctx, save_problem, &pctx);
63c4969c 363 if (had_problem)
f122632e 364 fixit = end_problem_latch(ctx, PR_LATCH_BBITMAP);
63c4969c
TT
365 else
366 fixit = -1;
5596defa 367 ctx->flags &= ~E2F_FLAG_PROG_SUPPRESS;
49e2df29 368
1b6bf175
TT
369 if (fixit == 1) {
370 ext2fs_free_block_bitmap(fs->block_map);
371 retval = ext2fs_copy_bitmap(ctx->block_found_map,
372 &fs->block_map);
bbd47d76
TT
373 if (retval) {
374 clear_problem_context(&pctx);
375 fix_problem(ctx, PR_5_COPY_BBITMAP_ERROR, &pctx);
376 ctx->flags |= E2F_FLAG_ABORT;
49e2df29 377 goto errout;
bbd47d76 378 }
1b6bf175
TT
379 ext2fs_set_bitmap_padding(fs->block_map);
380 ext2fs_mark_bb_dirty(fs);
49e2df29 381
1b6bf175
TT
382 /* Redo the counts */
383 blocks = 0; free_blocks = 0; group_free = 0; group = 0;
384 memset(free_array, 0, fs->group_desc_count * sizeof(int));
479463aa 385 redo_flag++;
1b6bf175
TT
386 goto redo_counts;
387 } else if (fixit == 0)
388 ext2fs_unmark_valid(fs);
389
3839e657 390 for (i = 0; i < fs->group_desc_count; i++) {
d7cca6b0 391 if (free_array[i] != ext2fs_bg_free_blocks_count(fs, i)) {
1b6bf175 392 pctx.group = i;
d7cca6b0 393 pctx.blk = ext2fs_bg_free_blocks_count(fs, i);
1b6bf175
TT
394 pctx.blk2 = free_array[i];
395
396 if (fix_problem(ctx, PR_5_FREE_BLOCK_COUNT_GROUP,
397 &pctx)) {
e633b58a 398 ext2fs_bg_free_blocks_count_set(fs, i, free_array[i]);
3839e657
TT
399 ext2fs_mark_super_dirty(fs);
400 } else
401 ext2fs_unmark_valid(fs);
402 }
403 }
4efbac6f 404 if (free_blocks != ext2fs_free_blocks_count(fs->super)) {
1b6bf175 405 pctx.group = 0;
4efbac6f 406 pctx.blk = ext2fs_free_blocks_count(fs->super);
1b6bf175
TT
407 pctx.blk2 = free_blocks;
408
409 if (fix_problem(ctx, PR_5_FREE_BLOCK_COUNT, &pctx)) {
4efbac6f 410 ext2fs_free_blocks_count_set(fs->super, free_blocks);
3839e657
TT
411 ext2fs_mark_super_dirty(fs);
412 } else
413 ext2fs_unmark_valid(fs);
414 }
49e2df29 415errout:
c4e3d3f3 416 ext2fs_free_mem(&free_array);
3839e657 417}
49e2df29 418
1b6bf175 419static void check_inode_bitmaps(e2fsck_t ctx)
3839e657 420{
1b6bf175 421 ext2_filsys fs = ctx->fs;
86c627ec 422 ext2_ino_t i;
54434927
TT
423 unsigned int free_inodes = 0;
424 int group_free = 0;
425 int dirs_count = 0;
426 int group = 0;
427 unsigned int inodes = 0;
428 int *free_array;
429 int *dir_array;
430 int actual, bitmap;
1b6bf175
TT
431 errcode_t retval;
432 struct problem_context pctx;
54434927 433 int problem, save_problem, fixit, had_problem;
16b851cd 434 int csum_flag;
f5fa2007 435 int skip_group = 0;
479463aa 436 int redo_flag = 0;
efa1a355 437 io_manager manager = ctx->fs->io->manager;
49e2df29 438
1b6bf175 439 clear_problem_context(&pctx);
54dc7ca2 440 free_array = (int *) e2fsck_allocate_memory(ctx,
f8188fff 441 fs->group_desc_count * sizeof(int), "free inode count array");
49e2df29 442
54dc7ca2 443 dir_array = (int *) e2fsck_allocate_memory(ctx,
f8188fff 444 fs->group_desc_count * sizeof(int), "directory count array");
49e2df29 445
c5d2f50d 446 if ((1 < ext2fs_get_inode_bitmap_start2(ctx->inode_used_map)) ||
49e2df29 447 (fs->super->s_inodes_count >
c5d2f50d 448 ext2fs_get_inode_bitmap_end2(ctx->inode_used_map))) {
1b6bf175
TT
449 pctx.num = 3;
450 pctx.blk = 1;
451 pctx.blk2 = fs->super->s_inodes_count;
c5d2f50d
VAH
452 pctx.ino = ext2fs_get_inode_bitmap_start2(ctx->inode_used_map);
453 pctx.ino2 = ext2fs_get_inode_bitmap_end2(ctx->inode_used_map);
1b6bf175 454 fix_problem(ctx, PR_5_BMAP_ENDPOINTS, &pctx);
08b21301
TT
455
456 ctx->flags |= E2F_FLAG_ABORT; /* fatal */
49e2df29 457 goto errout;
50e1e10f 458 }
c5d2f50d 459 if ((1 < ext2fs_get_inode_bitmap_start2(fs->inode_map)) ||
49e2df29 460 (fs->super->s_inodes_count >
c5d2f50d 461 ext2fs_get_inode_bitmap_end2(fs->inode_map))) {
1b6bf175
TT
462 pctx.num = 4;
463 pctx.blk = 1;
464 pctx.blk2 = fs->super->s_inodes_count;
c5d2f50d
VAH
465 pctx.ino = ext2fs_get_inode_bitmap_start2(fs->inode_map);
466 pctx.ino2 = ext2fs_get_inode_bitmap_end2(fs->inode_map);
1b6bf175 467 fix_problem(ctx, PR_5_BMAP_ENDPOINTS, &pctx);
08b21301
TT
468
469 ctx->flags |= E2F_FLAG_ABORT; /* fatal */
49e2df29 470 goto errout;
50e1e10f
TT
471 }
472
49a7360b
JS
473 csum_flag = EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
474 EXT4_FEATURE_RO_COMPAT_GDT_CSUM);
1b6bf175 475redo_counts:
63c4969c 476 had_problem = 0;
f122632e
TT
477 save_problem = 0;
478 pctx.ino = pctx.ino2 = 0;
16b851cd 479 if (csum_flag &&
cd65a24e 480 (ext2fs_bg_flags_test(fs, group, EXT2_BG_INODE_UNINIT)))
f5fa2007
TT
481 skip_group++;
482
5830d6be
ES
483 /* Protect loop from wrap-around if inodes_count is maxed */
484 for (i = 1; i <= fs->super->s_inodes_count && i > 0; i++) {
479463aa
KM
485 bitmap = 0;
486 if (skip_group &&
487 i % fs->super->s_inodes_per_group == 1) {
488 /*
489 * Current inode is the first inode
490 * in the current block group.
491 */
492 if (ext2fs_test_inode_bitmap_range(
493 ctx->inode_used_map, i,
494 fs->super->s_inodes_per_group)) {
495 /*
496 * When the compared inodes in inodes bitmap
497 * are 0, count the free inode,
498 * skip the current block group.
499 */
500 inodes = fs->super->s_inodes_per_group - 1;
501 group_free = inodes;
502 free_inodes += inodes;
503 i += inodes;
504 skip_group = 0;
505 goto do_counts;
506 }
507 }
508
c5d2f50d 509 actual = ext2fs_fast_test_inode_bitmap2(ctx->inode_used_map, i);
479463aa
KM
510 if (redo_flag)
511 bitmap = actual;
512 else if (!skip_group)
c5d2f50d 513 bitmap = ext2fs_fast_test_inode_bitmap2(fs->inode_map, i);
3839e657
TT
514 if (actual == bitmap)
515 goto do_counts;
49e2df29 516
3839e657
TT
517 if (!actual && bitmap) {
518 /*
519 * Inode wasn't used, but marked in bitmap
520 */
f122632e 521 problem = PR_5_INODE_UNUSED;
1b6bf175 522 } else /* if (actual && !bitmap) */ {
3839e657
TT
523 /*
524 * Inode used, but not in bitmap
525 */
1b6bf175 526 problem = PR_5_INODE_USED;
49a7360b
JS
527
528 /* We should never hit this, because it means that
529 * inodes were marked in use that weren't noticed
530 * in pass1 or pass 2. It is easier to fix the problem
531 * than to kill e2fsck and leave the user stuck. */
532 if (skip_group) {
533 struct problem_context pctx2;
534 pctx2.blk = i;
535 pctx2.group = group;
536 if (fix_problem(ctx, PR_5_INODE_UNINIT,&pctx2)){
e633b58a 537 ext2fs_bg_flags_clear(fs, group, EXT2_BG_INODE_UNINIT);
49a7360b
JS
538 skip_group = 0;
539 }
540 }
3839e657 541 }
f122632e
TT
542 if (pctx.ino == 0) {
543 pctx.ino = pctx.ino2 = i;
544 save_problem = problem;
545 } else {
546 if ((problem == save_problem) &&
547 (pctx.ino2 == i-1))
548 pctx.ino2++;
549 else {
550 print_bitmap_problem(ctx, save_problem, &pctx);
551 pctx.ino = pctx.ino2 = i;
552 save_problem = problem;
553 }
554 }
5596defa 555 ctx->flags |= E2F_FLAG_PROG_SUPPRESS;
63c4969c 556 had_problem++;
efa1a355
LC
557 /*
558 * If there a problem we should turn off the discard so we
559 * do not compromise the filesystem.
560 */
561 ctx->options &= ~E2F_OPT_DISCARD;
49e2df29 562
3839e657 563do_counts:
f5fa2007 564 if (bitmap) {
c5d2f50d 565 if (ext2fs_test_inode_bitmap2(ctx->inode_dir_map, i))
3839e657 566 dirs_count++;
49a7360b 567 } else if (!skip_group || csum_flag) {
f5fa2007
TT
568 group_free++;
569 free_inodes++;
3839e657 570 }
efa1a355 571
3839e657
TT
572 inodes++;
573 if ((inodes == fs->super->s_inodes_per_group) ||
574 (i == fs->super->s_inodes_count)) {
efa1a355 575
3839e657
TT
576 free_array[group] = group_free;
577 dir_array[group] = dirs_count;
efa1a355
LC
578
579 /* Discard inode table */
580 if (ctx->options & E2F_OPT_DISCARD) {
581 blk64_t used_blks, blk, num;
582
583 used_blks = DIV_ROUND_UP(
584 (EXT2_INODES_PER_GROUP(fs->super) -
585 group_free),
586 EXT2_INODES_PER_BLOCK(fs->super));
587
588 blk = ext2fs_inode_table_loc(fs, group) +
589 used_blks;
590 num = fs->inode_blocks_per_group -
591 used_blks;
592 e2fsck_discard_blocks(ctx, manager, blk, num);
593 }
594
595 /*
596 * If discard zeroes data and the group inode table
597 * was not zeroed yet, set itable as zeroed
598 */
599 if ((ctx->options & E2F_OPT_DISCARD) &&
600 (io_channel_discard_zeroes_data(fs->io)) &&
601 !(ext2fs_bg_flags_test(fs, group,
602 EXT2_BG_INODE_ZEROED))) {
603 ext2fs_bg_flags_set(fs, group,
604 EXT2_BG_INODE_ZEROED);
605 ext2fs_group_desc_csum_set(fs, group);
606 }
607
3839e657
TT
608 group ++;
609 inodes = 0;
f5fa2007 610 skip_group = 0;
3839e657
TT
611 group_free = 0;
612 dirs_count = 0;
efac9a1b
TT
613 if (ctx->progress)
614 if ((ctx->progress)(ctx, 5,
615 group + fs->group_desc_count,
616 fs->group_desc_count*2))
49e2df29 617 goto errout;
16b851cd 618 if (csum_flag &&
f5fa2007 619 (i != fs->super->s_inodes_count) &&
cd65a24e 620 (ext2fs_bg_flags_test(fs, group, EXT2_BG_INODE_UNINIT)
732c8cd5 621 ))
f5fa2007 622 skip_group++;
3839e657
TT
623 }
624 }
f122632e
TT
625 if (pctx.ino)
626 print_bitmap_problem(ctx, save_problem, &pctx);
49e2df29 627
63c4969c
TT
628 if (had_problem)
629 fixit = end_problem_latch(ctx, PR_LATCH_IBITMAP);
630 else
631 fixit = -1;
5596defa 632 ctx->flags &= ~E2F_FLAG_PROG_SUPPRESS;
49e2df29 633
1b6bf175
TT
634 if (fixit == 1) {
635 ext2fs_free_inode_bitmap(fs->inode_map);
636 retval = ext2fs_copy_bitmap(ctx->inode_used_map,
637 &fs->inode_map);
bbd47d76
TT
638 if (retval) {
639 clear_problem_context(&pctx);
640 fix_problem(ctx, PR_5_COPY_IBITMAP_ERROR, &pctx);
641 ctx->flags |= E2F_FLAG_ABORT;
49e2df29 642 goto errout;
bbd47d76 643 }
1b6bf175
TT
644 ext2fs_set_bitmap_padding(fs->inode_map);
645 ext2fs_mark_ib_dirty(fs);
646
647 /* redo counts */
648 inodes = 0; free_inodes = 0; group_free = 0;
649 dirs_count = 0; group = 0;
650 memset(free_array, 0, fs->group_desc_count * sizeof(int));
651 memset(dir_array, 0, fs->group_desc_count * sizeof(int));
479463aa 652 redo_flag++;
1b6bf175
TT
653 goto redo_counts;
654 } else if (fixit == 0)
655 ext2fs_unmark_valid(fs);
49e2df29 656
3839e657 657 for (i = 0; i < fs->group_desc_count; i++) {
d7cca6b0 658 if (free_array[i] != ext2fs_bg_free_inodes_count(fs, i)) {
1b6bf175 659 pctx.group = i;
d7cca6b0 660 pctx.ino = ext2fs_bg_free_inodes_count(fs, i);
1b6bf175
TT
661 pctx.ino2 = free_array[i];
662 if (fix_problem(ctx, PR_5_FREE_INODE_COUNT_GROUP,
663 &pctx)) {
d7cca6b0 664 ext2fs_bg_free_inodes_count_set(fs, i, free_array[i]);
3839e657
TT
665 ext2fs_mark_super_dirty(fs);
666 } else
667 ext2fs_unmark_valid(fs);
668 }
d7cca6b0 669 if (dir_array[i] != ext2fs_bg_used_dirs_count(fs, i)) {
1b6bf175 670 pctx.group = i;
d7cca6b0 671 pctx.ino = ext2fs_bg_used_dirs_count(fs, i);
1b6bf175
TT
672 pctx.ino2 = dir_array[i];
673
674 if (fix_problem(ctx, PR_5_FREE_DIR_COUNT_GROUP,
675 &pctx)) {
d7cca6b0 676 ext2fs_bg_used_dirs_count_set(fs, i, dir_array[i]);
3839e657
TT
677 ext2fs_mark_super_dirty(fs);
678 } else
679 ext2fs_unmark_valid(fs);
680 }
681 }
682 if (free_inodes != fs->super->s_free_inodes_count) {
1b6bf175
TT
683 pctx.group = -1;
684 pctx.ino = fs->super->s_free_inodes_count;
685 pctx.ino2 = free_inodes;
686
687 if (fix_problem(ctx, PR_5_FREE_INODE_COUNT, &pctx)) {
3839e657
TT
688 fs->super->s_free_inodes_count = free_inodes;
689 ext2fs_mark_super_dirty(fs);
690 } else
691 ext2fs_unmark_valid(fs);
692 }
49e2df29 693errout:
c4e3d3f3
TT
694 ext2fs_free_mem(&free_array);
695 ext2fs_free_mem(&dir_array);
3839e657
TT
696}
697
1b6bf175 698static void check_inode_end(e2fsck_t ctx)
3839e657 699{
1b6bf175 700 ext2_filsys fs = ctx->fs;
86c627ec 701 ext2_ino_t end, save_inodes_count, i;
1b6bf175
TT
702 struct problem_context pctx;
703
704 clear_problem_context(&pctx);
3839e657
TT
705
706 end = EXT2_INODES_PER_GROUP(fs->super) * fs->group_desc_count;
1b6bf175
TT
707 pctx.errcode = ext2fs_fudge_inode_bitmap_end(fs->inode_map, end,
708 &save_inodes_count);
709 if (pctx.errcode) {
710 pctx.num = 1;
711 fix_problem(ctx, PR_5_FUDGE_BITMAP_ERROR, &pctx);
08b21301
TT
712 ctx->flags |= E2F_FLAG_ABORT; /* fatal */
713 return;
f3db3566 714 }
3839e657
TT
715 if (save_inodes_count == end)
716 return;
5830d6be 717
efc6f628 718 /* protect loop from wrap-around if end is maxed */
5830d6be 719 for (i = save_inodes_count + 1; i <= end && i > save_inodes_count; i++) {
f3db3566 720 if (!ext2fs_test_inode_bitmap(fs->inode_map, i)) {
1b6bf175 721 if (fix_problem(ctx, PR_5_INODE_BMAP_PADDING, &pctx)) {
01ec1268 722 for (; i <= end; i++)
f3db3566 723 ext2fs_mark_inode_bitmap(fs->inode_map,
3839e657
TT
724 i);
725 ext2fs_mark_ib_dirty(fs);
726 } else
727 ext2fs_unmark_valid(fs);
728 break;
729 }
730 }
731
1b6bf175
TT
732 pctx.errcode = ext2fs_fudge_inode_bitmap_end(fs->inode_map,
733 save_inodes_count, 0);
734 if (pctx.errcode) {
735 pctx.num = 2;
736 fix_problem(ctx, PR_5_FUDGE_BITMAP_ERROR, &pctx);
08b21301
TT
737 ctx->flags |= E2F_FLAG_ABORT; /* fatal */
738 return;
f3db3566 739 }
3839e657
TT
740}
741
1b6bf175 742static void check_block_end(e2fsck_t ctx)
3839e657 743{
1b6bf175 744 ext2_filsys fs = ctx->fs;
c5d2f50d 745 blk64_t end, save_blocks_count, i;
1b6bf175
TT
746 struct problem_context pctx;
747
748 clear_problem_context(&pctx);
3839e657 749
c5d2f50d 750 end = ext2fs_get_block_bitmap_start2(fs->block_map) +
44fe08f1 751 ((blk64_t)EXT2_CLUSTERS_PER_GROUP(fs->super) * fs->group_desc_count) - 1;
c5d2f50d 752 pctx.errcode = ext2fs_fudge_block_bitmap_end2(fs->block_map, end,
1b6bf175
TT
753 &save_blocks_count);
754 if (pctx.errcode) {
755 pctx.num = 3;
756 fix_problem(ctx, PR_5_FUDGE_BITMAP_ERROR, &pctx);
08b21301
TT
757 ctx->flags |= E2F_FLAG_ABORT; /* fatal */
758 return;
f3db3566 759 }
3839e657
TT
760 if (save_blocks_count == end)
761 return;
5830d6be 762
efc6f628 763 /* Protect loop from wrap-around if end is maxed */
5830d6be 764 for (i = save_blocks_count + 1; i <= end && i > save_blocks_count; i++) {
44fe08f1
TT
765 if (!ext2fs_test_block_bitmap2(fs->block_map,
766 EXT2FS_C2B(fs, i))) {
1b6bf175 767 if (fix_problem(ctx, PR_5_BLOCK_BMAP_PADDING, &pctx)) {
01ec1268 768 for (; i <= end; i++)
c5d2f50d 769 ext2fs_mark_block_bitmap2(fs->block_map,
44fe08f1 770 EXT2FS_C2B(fs, i));
3839e657
TT
771 ext2fs_mark_bb_dirty(fs);
772 } else
773 ext2fs_unmark_valid(fs);
774 break;
775 }
776 }
777
c5d2f50d 778 pctx.errcode = ext2fs_fudge_block_bitmap_end2(fs->block_map,
1b6bf175
TT
779 save_blocks_count, 0);
780 if (pctx.errcode) {
781 pctx.num = 4;
782 fix_problem(ctx, PR_5_FUDGE_BITMAP_ERROR, &pctx);
08b21301
TT
783 ctx->flags |= E2F_FLAG_ABORT; /* fatal */
784 return;
f3db3566 785 }
3839e657
TT
786}
787
1b6bf175
TT
788
789