2 * pass5.c --- check block and inode bitmaps against on-disk bitmaps
4 * Copyright (C) 1993, 1994, 1995, 1996, 1997 Theodore Ts'o.
7 * This file may be redistributed under the terms of the GNU Public
16 static void check_block_bitmaps(e2fsck_t ctx);
17 static void check_inode_bitmaps(e2fsck_t ctx);
18 static void check_inode_end(e2fsck_t ctx);
19 static void check_block_end(e2fsck_t ctx);
21 void e2fsck_pass5(e2fsck_t ctx)
24 struct resource_track rtrack;
26 struct problem_context pctx;
29 mtrace_print("Pass 5");
33 init_resource_track(&rtrack, ctx->fs->io);
36 clear_problem_context(&pctx);
38 if (!(ctx->options & E2F_OPT_PREEN))
39 fix_problem(ctx, PR_5_PASS_HEADER, &pctx);
42 if ((ctx->progress)(ctx, 5, 0, ctx->fs->group_desc_count*2))
45 e2fsck_read_bitmaps(ctx);
47 check_block_bitmaps(ctx);
48 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
50 check_inode_bitmaps(ctx);
51 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
54 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
57 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
60 ext2fs_free_inode_bitmap(ctx->inode_used_map);
61 ctx->inode_used_map = 0;
62 ext2fs_free_inode_bitmap(ctx->inode_dir_map);
63 ctx->inode_dir_map = 0;
64 ext2fs_free_block_bitmap(ctx->block_found_map);
65 ctx->block_found_map = 0;
68 if (ctx->options & E2F_OPT_TIME2) {
69 e2fsck_clear_progbar(ctx);
70 print_resource_track(_("Pass 5"), &rtrack, ctx->fs->io);
75 #define NO_BLK ((blk_t) -1)
77 static void print_bitmap_problem(e2fsck_t ctx, int problem,
78 struct problem_context *pctx)
81 case PR_5_BLOCK_UNUSED:
82 if (pctx->blk == pctx->blk2)
85 problem = PR_5_BLOCK_RANGE_UNUSED;
88 if (pctx->blk == pctx->blk2)
91 problem = PR_5_BLOCK_RANGE_USED;
93 case PR_5_INODE_UNUSED:
94 if (pctx->ino == pctx->ino2)
97 problem = PR_5_INODE_RANGE_UNUSED;
100 if (pctx->ino == pctx->ino2)
103 problem = PR_5_INODE_RANGE_USED;
106 fix_problem(ctx, problem, pctx);
107 pctx->blk = pctx->blk2 = NO_BLK;
108 pctx->ino = pctx->ino2 = 0;
111 static void check_block_bitmaps(e2fsck_t ctx)
113 ext2_filsys fs = ctx->fs;
117 unsigned int blocks = 0;
118 unsigned int free_blocks = 0;
121 struct problem_context pctx;
122 int problem, save_problem, fixit, had_problem;
127 clear_problem_context(&pctx);
128 free_array = (int *) e2fsck_allocate_memory(ctx,
129 fs->group_desc_count * sizeof(int), "free block count array");
131 if ((fs->super->s_first_data_block <
132 ext2fs_get_block_bitmap_start(ctx->block_found_map)) ||
133 (fs->super->s_blocks_count-1 >
134 ext2fs_get_block_bitmap_end(ctx->block_found_map))) {
136 pctx.blk = fs->super->s_first_data_block;
137 pctx.blk2 = fs->super->s_blocks_count -1;
138 pctx.ino = ext2fs_get_block_bitmap_start(ctx->block_found_map);
139 pctx.ino2 = ext2fs_get_block_bitmap_end(ctx->block_found_map);
140 fix_problem(ctx, PR_5_BMAP_ENDPOINTS, &pctx);
142 ctx->flags |= E2F_FLAG_ABORT; /* fatal */
146 if ((fs->super->s_first_data_block <
147 ext2fs_get_block_bitmap_start(fs->block_map)) ||
148 (fs->super->s_blocks_count-1 >
149 ext2fs_get_block_bitmap_end(fs->block_map))) {
151 pctx.blk = fs->super->s_first_data_block;
152 pctx.blk2 = fs->super->s_blocks_count -1;
153 pctx.ino = ext2fs_get_block_bitmap_start(fs->block_map);
154 pctx.ino2 = ext2fs_get_block_bitmap_end(fs->block_map);
155 fix_problem(ctx, PR_5_BMAP_ENDPOINTS, &pctx);
157 ctx->flags |= E2F_FLAG_ABORT; /* fatal */
161 if (EXT2_HAS_COMPAT_FEATURE(fs->super, EXT2_FEATURE_COMPAT_LAZY_BG))
167 pctx.blk = pctx.blk2 = NO_BLK;
168 if (lazy_bg && (fs->group_desc[group].bg_flags &
169 EXT2_BG_BLOCK_UNINIT))
171 super = fs->super->s_first_data_block;
172 for (i = fs->super->s_first_data_block;
173 i < fs->super->s_blocks_count;
175 actual = ext2fs_fast_test_block_bitmap(ctx->block_found_map, i);
179 (i <= super + fs->desc_blocks) &&
180 ext2fs_bg_has_super(fs, group))
182 else if (i == fs->group_desc[group].bg_block_bitmap)
184 else if (i == fs->group_desc[group].bg_inode_bitmap)
186 else if (i >= fs->group_desc[group].bg_inode_table &&
187 (i < fs->group_desc[group].bg_inode_table
188 + fs->inode_blocks_per_group))
192 actual = (actual != 0);
194 bitmap = ext2fs_fast_test_block_bitmap(fs->block_map, i);
196 if (actual == bitmap)
199 if (!actual && bitmap) {
201 * Block not used, but marked in use in the bitmap.
203 problem = PR_5_BLOCK_UNUSED;
206 * Block used, but not marked in use in the bitmap.
208 problem = PR_5_BLOCK_USED;
210 if (pctx.blk == NO_BLK) {
211 pctx.blk = pctx.blk2 = i;
212 save_problem = problem;
214 if ((problem == save_problem) &&
218 print_bitmap_problem(ctx, save_problem, &pctx);
219 pctx.blk = pctx.blk2 = i;
220 save_problem = problem;
223 ctx->flags |= E2F_FLAG_PROG_SUPPRESS;
227 if (!bitmap && !skip_group) {
232 if ((blocks == fs->super->s_blocks_per_group) ||
233 (i == fs->super->s_blocks_count-1)) {
234 free_array[group] = group_free;
239 super += fs->super->s_blocks_per_group;
241 if ((ctx->progress)(ctx, 5, group,
242 fs->group_desc_count*2))
245 (i != fs->super->s_blocks_count-1) &&
246 (fs->group_desc[group].bg_flags &
247 EXT2_BG_BLOCK_UNINIT))
251 if (pctx.blk != NO_BLK)
252 print_bitmap_problem(ctx, save_problem, &pctx);
254 fixit = end_problem_latch(ctx, PR_LATCH_BBITMAP);
257 ctx->flags &= ~E2F_FLAG_PROG_SUPPRESS;
260 ext2fs_free_block_bitmap(fs->block_map);
261 retval = ext2fs_copy_bitmap(ctx->block_found_map,
264 clear_problem_context(&pctx);
265 fix_problem(ctx, PR_5_COPY_BBITMAP_ERROR, &pctx);
266 ctx->flags |= E2F_FLAG_ABORT;
269 ext2fs_set_bitmap_padding(fs->block_map);
270 ext2fs_mark_bb_dirty(fs);
272 /* Redo the counts */
273 blocks = 0; free_blocks = 0; group_free = 0; group = 0;
274 memset(free_array, 0, fs->group_desc_count * sizeof(int));
276 } else if (fixit == 0)
277 ext2fs_unmark_valid(fs);
279 for (i = 0; i < fs->group_desc_count; i++) {
280 if (free_array[i] != fs->group_desc[i].bg_free_blocks_count) {
282 pctx.blk = fs->group_desc[i].bg_free_blocks_count;
283 pctx.blk2 = free_array[i];
285 if (fix_problem(ctx, PR_5_FREE_BLOCK_COUNT_GROUP,
287 fs->group_desc[i].bg_free_blocks_count =
289 ext2fs_mark_super_dirty(fs);
291 ext2fs_unmark_valid(fs);
294 if (free_blocks != fs->super->s_free_blocks_count) {
296 pctx.blk = fs->super->s_free_blocks_count;
297 pctx.blk2 = free_blocks;
299 if (fix_problem(ctx, PR_5_FREE_BLOCK_COUNT, &pctx)) {
300 fs->super->s_free_blocks_count = free_blocks;
301 ext2fs_mark_super_dirty(fs);
303 ext2fs_unmark_valid(fs);
306 ext2fs_free_mem(&free_array);
309 static void check_inode_bitmaps(e2fsck_t ctx)
311 ext2_filsys fs = ctx->fs;
313 unsigned int free_inodes = 0;
317 unsigned int inodes = 0;
322 struct problem_context pctx;
323 int problem, save_problem, fixit, had_problem;
327 clear_problem_context(&pctx);
328 free_array = (int *) e2fsck_allocate_memory(ctx,
329 fs->group_desc_count * sizeof(int), "free inode count array");
331 dir_array = (int *) e2fsck_allocate_memory(ctx,
332 fs->group_desc_count * sizeof(int), "directory count array");
334 if ((1 < ext2fs_get_inode_bitmap_start(ctx->inode_used_map)) ||
335 (fs->super->s_inodes_count >
336 ext2fs_get_inode_bitmap_end(ctx->inode_used_map))) {
339 pctx.blk2 = fs->super->s_inodes_count;
340 pctx.ino = ext2fs_get_inode_bitmap_start(ctx->inode_used_map);
341 pctx.ino2 = ext2fs_get_inode_bitmap_end(ctx->inode_used_map);
342 fix_problem(ctx, PR_5_BMAP_ENDPOINTS, &pctx);
344 ctx->flags |= E2F_FLAG_ABORT; /* fatal */
347 if ((1 < ext2fs_get_inode_bitmap_start(fs->inode_map)) ||
348 (fs->super->s_inodes_count >
349 ext2fs_get_inode_bitmap_end(fs->inode_map))) {
352 pctx.blk2 = fs->super->s_inodes_count;
353 pctx.ino = ext2fs_get_inode_bitmap_start(fs->inode_map);
354 pctx.ino2 = ext2fs_get_inode_bitmap_end(fs->inode_map);
355 fix_problem(ctx, PR_5_BMAP_ENDPOINTS, &pctx);
357 ctx->flags |= E2F_FLAG_ABORT; /* fatal */
361 if (EXT2_HAS_COMPAT_FEATURE(fs->super,
362 EXT2_FEATURE_COMPAT_LAZY_BG))
368 pctx.ino = pctx.ino2 = 0;
369 if (lazy_bg && (fs->group_desc[group].bg_flags &
370 EXT2_BG_INODE_UNINIT))
373 /* Protect loop from wrap-around if inodes_count is maxed */
374 for (i = 1; i <= fs->super->s_inodes_count && i > 0; i++) {
375 actual = ext2fs_fast_test_inode_bitmap(ctx->inode_used_map, i);
379 bitmap = ext2fs_fast_test_inode_bitmap(fs->inode_map, i);
380 if (actual == bitmap)
383 if (!actual && bitmap) {
385 * Inode wasn't used, but marked in bitmap
387 problem = PR_5_INODE_UNUSED;
388 } else /* if (actual && !bitmap) */ {
390 * Inode used, but not in bitmap
392 problem = PR_5_INODE_USED;
395 pctx.ino = pctx.ino2 = i;
396 save_problem = problem;
398 if ((problem == save_problem) &&
402 print_bitmap_problem(ctx, save_problem, &pctx);
403 pctx.ino = pctx.ino2 = i;
404 save_problem = problem;
407 ctx->flags |= E2F_FLAG_PROG_SUPPRESS;
412 if (ext2fs_test_inode_bitmap(ctx->inode_dir_map, i))
414 } else if (!skip_group) {
419 if ((inodes == fs->super->s_inodes_per_group) ||
420 (i == fs->super->s_inodes_count)) {
421 free_array[group] = group_free;
422 dir_array[group] = dirs_count;
429 if ((ctx->progress)(ctx, 5,
430 group + fs->group_desc_count,
431 fs->group_desc_count*2))
434 (i != fs->super->s_inodes_count) &&
435 (fs->group_desc[group].bg_flags &
436 EXT2_BG_INODE_UNINIT))
441 print_bitmap_problem(ctx, save_problem, &pctx);
444 fixit = end_problem_latch(ctx, PR_LATCH_IBITMAP);
447 ctx->flags &= ~E2F_FLAG_PROG_SUPPRESS;
450 ext2fs_free_inode_bitmap(fs->inode_map);
451 retval = ext2fs_copy_bitmap(ctx->inode_used_map,
454 clear_problem_context(&pctx);
455 fix_problem(ctx, PR_5_COPY_IBITMAP_ERROR, &pctx);
456 ctx->flags |= E2F_FLAG_ABORT;
459 ext2fs_set_bitmap_padding(fs->inode_map);
460 ext2fs_mark_ib_dirty(fs);
463 inodes = 0; free_inodes = 0; group_free = 0;
464 dirs_count = 0; group = 0;
465 memset(free_array, 0, fs->group_desc_count * sizeof(int));
466 memset(dir_array, 0, fs->group_desc_count * sizeof(int));
468 } else if (fixit == 0)
469 ext2fs_unmark_valid(fs);
471 for (i = 0; i < fs->group_desc_count; i++) {
472 if (free_array[i] != fs->group_desc[i].bg_free_inodes_count) {
474 pctx.ino = fs->group_desc[i].bg_free_inodes_count;
475 pctx.ino2 = free_array[i];
476 if (fix_problem(ctx, PR_5_FREE_INODE_COUNT_GROUP,
478 fs->group_desc[i].bg_free_inodes_count =
480 ext2fs_mark_super_dirty(fs);
482 ext2fs_unmark_valid(fs);
484 if (dir_array[i] != fs->group_desc[i].bg_used_dirs_count) {
486 pctx.ino = fs->group_desc[i].bg_used_dirs_count;
487 pctx.ino2 = dir_array[i];
489 if (fix_problem(ctx, PR_5_FREE_DIR_COUNT_GROUP,
491 fs->group_desc[i].bg_used_dirs_count =
493 ext2fs_mark_super_dirty(fs);
495 ext2fs_unmark_valid(fs);
498 if (free_inodes != fs->super->s_free_inodes_count) {
500 pctx.ino = fs->super->s_free_inodes_count;
501 pctx.ino2 = free_inodes;
503 if (fix_problem(ctx, PR_5_FREE_INODE_COUNT, &pctx)) {
504 fs->super->s_free_inodes_count = free_inodes;
505 ext2fs_mark_super_dirty(fs);
507 ext2fs_unmark_valid(fs);
510 ext2fs_free_mem(&free_array);
511 ext2fs_free_mem(&dir_array);
514 static void check_inode_end(e2fsck_t ctx)
516 ext2_filsys fs = ctx->fs;
517 ext2_ino_t end, save_inodes_count, i;
518 struct problem_context pctx;
520 clear_problem_context(&pctx);
522 end = EXT2_INODES_PER_GROUP(fs->super) * fs->group_desc_count;
523 pctx.errcode = ext2fs_fudge_inode_bitmap_end(fs->inode_map, end,
527 fix_problem(ctx, PR_5_FUDGE_BITMAP_ERROR, &pctx);
528 ctx->flags |= E2F_FLAG_ABORT; /* fatal */
531 if (save_inodes_count == end)
534 /* protect loop from wrap-around if end is maxed */
535 for (i = save_inodes_count + 1; i <= end && i > save_inodes_count; i++) {
536 if (!ext2fs_test_inode_bitmap(fs->inode_map, i)) {
537 if (fix_problem(ctx, PR_5_INODE_BMAP_PADDING, &pctx)) {
538 for (i = save_inodes_count + 1; i <= end; i++)
539 ext2fs_mark_inode_bitmap(fs->inode_map,
541 ext2fs_mark_ib_dirty(fs);
543 ext2fs_unmark_valid(fs);
548 pctx.errcode = ext2fs_fudge_inode_bitmap_end(fs->inode_map,
549 save_inodes_count, 0);
552 fix_problem(ctx, PR_5_FUDGE_BITMAP_ERROR, &pctx);
553 ctx->flags |= E2F_FLAG_ABORT; /* fatal */
558 static void check_block_end(e2fsck_t ctx)
560 ext2_filsys fs = ctx->fs;
561 blk_t end, save_blocks_count, i;
562 struct problem_context pctx;
564 clear_problem_context(&pctx);
566 end = ext2fs_get_block_bitmap_start(fs->block_map) +
567 (EXT2_BLOCKS_PER_GROUP(fs->super) * fs->group_desc_count) - 1;
568 pctx.errcode = ext2fs_fudge_block_bitmap_end(fs->block_map, end,
572 fix_problem(ctx, PR_5_FUDGE_BITMAP_ERROR, &pctx);
573 ctx->flags |= E2F_FLAG_ABORT; /* fatal */
576 if (save_blocks_count == end)
579 /* Protect loop from wrap-around if end is maxed */
580 for (i = save_blocks_count + 1; i <= end && i > save_blocks_count; i++) {
581 if (!ext2fs_test_block_bitmap(fs->block_map, i)) {
582 if (fix_problem(ctx, PR_5_BLOCK_BMAP_PADDING, &pctx)) {
583 for (i = save_blocks_count + 1; i <= end; i++)
584 ext2fs_mark_block_bitmap(fs->block_map,
586 ext2fs_mark_bb_dirty(fs);
588 ext2fs_unmark_valid(fs);
593 pctx.errcode = ext2fs_fudge_block_bitmap_end(fs->block_map,
594 save_blocks_count, 0);
597 fix_problem(ctx, PR_5_FUDGE_BITMAP_ERROR, &pctx);
598 ctx->flags |= E2F_FLAG_ABORT; /* fatal */