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);
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);
75 static void check_block_bitmaps(e2fsck_t ctx)
77 ext2_filsys fs = ctx->fs;
85 struct problem_context pctx;
86 int problem, fixit, had_problem;
89 clear_problem_context(&pctx);
90 free_array = (int *) e2fsck_allocate_memory(ctx,
91 fs->group_desc_count * sizeof(int), "free block count array");
93 if ((fs->super->s_first_data_block <
94 ext2fs_get_block_bitmap_start(ctx->block_found_map)) ||
95 (fs->super->s_blocks_count-1 >
96 ext2fs_get_block_bitmap_end(ctx->block_found_map))) {
98 pctx.blk = fs->super->s_first_data_block;
99 pctx.blk2 = fs->super->s_blocks_count -1;
100 pctx.ino = ext2fs_get_block_bitmap_start(ctx->block_found_map);
101 pctx.ino2 = ext2fs_get_block_bitmap_end(ctx->block_found_map);
102 fix_problem(ctx, PR_5_BMAP_ENDPOINTS, &pctx);
104 ctx->flags |= E2F_FLAG_ABORT; /* fatal */
108 if ((fs->super->s_first_data_block <
109 ext2fs_get_block_bitmap_start(fs->block_map)) ||
110 (fs->super->s_blocks_count-1 >
111 ext2fs_get_block_bitmap_end(fs->block_map))) {
113 pctx.blk = fs->super->s_first_data_block;
114 pctx.blk2 = fs->super->s_blocks_count -1;
115 pctx.ino = ext2fs_get_block_bitmap_start(fs->block_map);
116 pctx.ino2 = ext2fs_get_block_bitmap_end(fs->block_map);
117 fix_problem(ctx, PR_5_BMAP_ENDPOINTS, &pctx);
119 ctx->flags |= E2F_FLAG_ABORT; /* fatal */
125 for (i = fs->super->s_first_data_block;
126 i < fs->super->s_blocks_count;
128 actual = ext2fs_fast_test_block_bitmap(ctx->block_found_map, i);
129 bitmap = ext2fs_fast_test_block_bitmap(fs->block_map, i);
131 if (actual == bitmap)
134 if (!actual && bitmap) {
136 * Block not used, but marked in use in the bitmap.
138 problem = PR_5_UNUSED_BLOCK;
141 * Block used, but not marked in use in the bitmap.
143 problem = PR_5_BLOCK_USED;
146 fix_problem(ctx, problem, &pctx);
147 ctx->flags |= E2F_FLAG_PROG_SUPPRESS;
156 if ((blocks == fs->super->s_blocks_per_group) ||
157 (i == fs->super->s_blocks_count-1)) {
158 free_array[group] = group_free;
163 if ((ctx->progress)(ctx, 5, group,
164 fs->group_desc_count*2))
169 fixit = end_problem_latch(ctx, PR_LATCH_BBITMAP);
172 ctx->flags &= ~E2F_FLAG_PROG_SUPPRESS;
175 ext2fs_free_block_bitmap(fs->block_map);
176 retval = ext2fs_copy_bitmap(ctx->block_found_map,
178 /* XXX check retval --- should never fail! */
179 ext2fs_set_bitmap_padding(fs->block_map);
180 ext2fs_mark_bb_dirty(fs);
182 /* Redo the counts */
183 blocks = 0; free_blocks = 0; group_free = 0; group = 0;
184 memset(free_array, 0, fs->group_desc_count * sizeof(int));
186 } else if (fixit == 0)
187 ext2fs_unmark_valid(fs);
189 for (i = 0; i < fs->group_desc_count; i++) {
190 if (free_array[i] != fs->group_desc[i].bg_free_blocks_count) {
192 pctx.blk = fs->group_desc[i].bg_free_blocks_count;
193 pctx.blk2 = free_array[i];
195 if (fix_problem(ctx, PR_5_FREE_BLOCK_COUNT_GROUP,
197 fs->group_desc[i].bg_free_blocks_count =
199 ext2fs_mark_super_dirty(fs);
201 ext2fs_unmark_valid(fs);
204 if (free_blocks != fs->super->s_free_blocks_count) {
206 pctx.blk = fs->super->s_free_blocks_count;
207 pctx.blk2 = free_blocks;
209 if (fix_problem(ctx, PR_5_FREE_BLOCK_COUNT, &pctx)) {
210 fs->super->s_free_blocks_count = free_blocks;
211 ext2fs_mark_super_dirty(fs);
213 ext2fs_unmark_valid(fs);
215 ext2fs_free_mem((void **) &free_array);
218 static void check_inode_bitmaps(e2fsck_t ctx)
220 ext2_filsys fs = ctx->fs;
231 struct problem_context pctx;
232 int problem, fixit, had_problem;
234 clear_problem_context(&pctx);
235 free_array = (int *) e2fsck_allocate_memory(ctx,
236 fs->group_desc_count * sizeof(int), "free inode count array");
238 dir_array = (int *) e2fsck_allocate_memory(ctx,
239 fs->group_desc_count * sizeof(int), "directory count array");
241 if ((1 < ext2fs_get_inode_bitmap_start(ctx->inode_used_map)) ||
242 (fs->super->s_inodes_count >
243 ext2fs_get_inode_bitmap_end(ctx->inode_used_map))) {
246 pctx.blk2 = fs->super->s_inodes_count;
247 pctx.ino = ext2fs_get_inode_bitmap_start(ctx->inode_used_map);
248 pctx.ino2 = ext2fs_get_inode_bitmap_end(ctx->inode_used_map);
249 fix_problem(ctx, PR_5_BMAP_ENDPOINTS, &pctx);
251 ctx->flags |= E2F_FLAG_ABORT; /* fatal */
254 if ((1 < ext2fs_get_inode_bitmap_start(fs->inode_map)) ||
255 (fs->super->s_inodes_count >
256 ext2fs_get_inode_bitmap_end(fs->inode_map))) {
259 pctx.blk2 = fs->super->s_inodes_count;
260 pctx.ino = ext2fs_get_inode_bitmap_start(fs->inode_map);
261 pctx.ino2 = ext2fs_get_inode_bitmap_end(fs->inode_map);
262 fix_problem(ctx, PR_5_BMAP_ENDPOINTS, &pctx);
264 ctx->flags |= E2F_FLAG_ABORT; /* fatal */
270 for (i = 1; i <= fs->super->s_inodes_count; i++) {
271 actual = ext2fs_fast_test_inode_bitmap(ctx->inode_used_map, i);
272 bitmap = ext2fs_fast_test_inode_bitmap(fs->inode_map, i);
274 if (actual == bitmap)
277 if (!actual && bitmap) {
279 * Inode wasn't used, but marked in bitmap
281 problem = PR_5_UNUSED_INODE;
282 } else /* if (actual && !bitmap) */ {
284 * Inode used, but not in bitmap
286 problem = PR_5_INODE_USED;
289 fix_problem(ctx, problem, &pctx);
290 ctx->flags |= E2F_FLAG_PROG_SUPPRESS;
298 if (ext2fs_test_inode_bitmap(ctx->inode_dir_map, i))
302 if ((inodes == fs->super->s_inodes_per_group) ||
303 (i == fs->super->s_inodes_count)) {
304 free_array[group] = group_free;
305 dir_array[group] = dirs_count;
311 if ((ctx->progress)(ctx, 5,
312 group + fs->group_desc_count,
313 fs->group_desc_count*2))
318 fixit = end_problem_latch(ctx, PR_LATCH_IBITMAP);
321 ctx->flags &= ~E2F_FLAG_PROG_SUPPRESS;
324 ext2fs_free_inode_bitmap(fs->inode_map);
325 retval = ext2fs_copy_bitmap(ctx->inode_used_map,
327 /* XXX check retval --- should never fail! */
328 ext2fs_set_bitmap_padding(fs->inode_map);
329 ext2fs_mark_ib_dirty(fs);
332 inodes = 0; free_inodes = 0; group_free = 0;
333 dirs_count = 0; group = 0;
334 memset(free_array, 0, fs->group_desc_count * sizeof(int));
335 memset(dir_array, 0, fs->group_desc_count * sizeof(int));
337 } else if (fixit == 0)
338 ext2fs_unmark_valid(fs);
340 for (i = 0; i < fs->group_desc_count; i++) {
341 if (free_array[i] != fs->group_desc[i].bg_free_inodes_count) {
343 pctx.ino = fs->group_desc[i].bg_free_inodes_count;
344 pctx.ino2 = free_array[i];
345 if (fix_problem(ctx, PR_5_FREE_INODE_COUNT_GROUP,
347 fs->group_desc[i].bg_free_inodes_count =
349 ext2fs_mark_super_dirty(fs);
351 ext2fs_unmark_valid(fs);
353 if (dir_array[i] != fs->group_desc[i].bg_used_dirs_count) {
355 pctx.ino = fs->group_desc[i].bg_used_dirs_count;
356 pctx.ino2 = dir_array[i];
358 if (fix_problem(ctx, PR_5_FREE_DIR_COUNT_GROUP,
360 fs->group_desc[i].bg_used_dirs_count =
362 ext2fs_mark_super_dirty(fs);
364 ext2fs_unmark_valid(fs);
367 if (free_inodes != fs->super->s_free_inodes_count) {
369 pctx.ino = fs->super->s_free_inodes_count;
370 pctx.ino2 = free_inodes;
372 if (fix_problem(ctx, PR_5_FREE_INODE_COUNT, &pctx)) {
373 fs->super->s_free_inodes_count = free_inodes;
374 ext2fs_mark_super_dirty(fs);
376 ext2fs_unmark_valid(fs);
378 ext2fs_free_mem((void **) &free_array);
379 ext2fs_free_mem((void **) &dir_array);
382 static void check_inode_end(e2fsck_t ctx)
384 ext2_filsys fs = ctx->fs;
385 ino_t end, save_inodes_count, i;
386 struct problem_context pctx;
388 clear_problem_context(&pctx);
390 end = EXT2_INODES_PER_GROUP(fs->super) * fs->group_desc_count;
391 pctx.errcode = ext2fs_fudge_inode_bitmap_end(fs->inode_map, end,
395 fix_problem(ctx, PR_5_FUDGE_BITMAP_ERROR, &pctx);
396 ctx->flags |= E2F_FLAG_ABORT; /* fatal */
399 if (save_inodes_count == end)
402 for (i = save_inodes_count + 1; i <= end; i++) {
403 if (!ext2fs_test_inode_bitmap(fs->inode_map, i)) {
404 if (fix_problem(ctx, PR_5_INODE_BMAP_PADDING, &pctx)) {
405 for (i = save_inodes_count + 1; i <= end; i++)
406 ext2fs_mark_inode_bitmap(fs->inode_map,
408 ext2fs_mark_ib_dirty(fs);
410 ext2fs_unmark_valid(fs);
415 pctx.errcode = ext2fs_fudge_inode_bitmap_end(fs->inode_map,
416 save_inodes_count, 0);
419 fix_problem(ctx, PR_5_FUDGE_BITMAP_ERROR, &pctx);
420 ctx->flags |= E2F_FLAG_ABORT; /* fatal */
425 static void check_block_end(e2fsck_t ctx)
427 ext2_filsys fs = ctx->fs;
428 blk_t end, save_blocks_count, i;
429 struct problem_context pctx;
431 clear_problem_context(&pctx);
433 end = fs->block_map->start +
434 (EXT2_BLOCKS_PER_GROUP(fs->super) * fs->group_desc_count) - 1;
435 pctx.errcode = ext2fs_fudge_block_bitmap_end(fs->block_map, end,
439 fix_problem(ctx, PR_5_FUDGE_BITMAP_ERROR, &pctx);
440 ctx->flags |= E2F_FLAG_ABORT; /* fatal */
443 if (save_blocks_count == end)
446 for (i = save_blocks_count + 1; i <= end; i++) {
447 if (!ext2fs_test_block_bitmap(fs->block_map, i)) {
448 if (fix_problem(ctx, PR_5_BLOCK_BMAP_PADDING, &pctx)) {
449 for (i = save_blocks_count + 1; i <= end; i++)
450 ext2fs_mark_block_bitmap(fs->block_map,
452 ext2fs_mark_bb_dirty(fs);
454 ext2fs_unmark_valid(fs);
459 pctx.errcode = ext2fs_fudge_block_bitmap_end(fs->block_map,
460 save_blocks_count, 0);
463 fix_problem(ctx, PR_5_FUDGE_BITMAP_ERROR, &pctx);
464 ctx->flags |= E2F_FLAG_ABORT; /* fatal */