Whamcloud - gitweb
cf37556e10a496631fb266f2642c904b34616061
[tools/e2fsprogs.git] / e2fsck / pass5.c
1 /*
2  * pass5.c --- check block and inode bitmaps against on-disk bitmaps
3  *
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%
10  *
11  */
12
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
20 #include "e2fsck.h"
21 #include "problem.h"
22
23 #define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d))
24
25 static void check_block_bitmaps(e2fsck_t ctx);
26 static void check_inode_bitmaps(e2fsck_t ctx);
27 static void check_inode_end(e2fsck_t ctx);
28 static void check_block_end(e2fsck_t ctx);
29
30 void e2fsck_pass5(e2fsck_t ctx)
31 {
32 #ifdef RESOURCE_TRACK
33         struct resource_track   rtrack;
34 #endif
35         struct problem_context  pctx;
36
37 #ifdef MTRACE
38         mtrace_print("Pass 5");
39 #endif
40
41         init_resource_track(&rtrack, ctx->fs->io);
42         clear_problem_context(&pctx);
43
44         if (!(ctx->options & E2F_OPT_PREEN))
45                 fix_problem(ctx, PR_5_PASS_HEADER, &pctx);
46
47         if (ctx->progress)
48                 if ((ctx->progress)(ctx, 5, 0, ctx->fs->group_desc_count*2))
49                         return;
50
51         e2fsck_read_bitmaps(ctx);
52
53         check_block_bitmaps(ctx);
54         if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
55                 return;
56         check_inode_bitmaps(ctx);
57         if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
58                 return;
59         check_inode_end(ctx);
60         if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
61                 return;
62         check_block_end(ctx);
63         if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
64                 return;
65
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
73         print_resource_track(ctx, _("Pass 5"), &rtrack, ctx->fs->io);
74 }
75
76 static void e2fsck_discard_blocks(e2fsck_t ctx, io_manager manager,
77                                   blk64_t start, blk64_t count)
78 {
79         ext2_filsys fs = ctx->fs;
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_NO) &&
91             (ctx->options & E2F_OPT_DISCARD) &&
92             (io_channel_discard(fs->io, start, count)))
93                 ctx->options &= ~E2F_OPT_DISCARD;
94 }
95
96 #define NO_BLK ((blk64_t) -1)
97
98 static void print_bitmap_problem(e2fsck_t ctx, int problem,
99                             struct problem_context *pctx)
100 {
101         switch (problem) {
102         case PR_5_BLOCK_UNUSED:
103                 if (pctx->blk == pctx->blk2)
104                         pctx->blk2 = 0;
105                 else
106                         problem = PR_5_BLOCK_RANGE_UNUSED;
107                 break;
108         case PR_5_BLOCK_USED:
109                 if (pctx->blk == pctx->blk2)
110                         pctx->blk2 = 0;
111                 else
112                         problem = PR_5_BLOCK_RANGE_USED;
113                 break;
114         case PR_5_INODE_UNUSED:
115                 if (pctx->ino == pctx->ino2)
116                         pctx->ino2 = 0;
117                 else
118                         problem = PR_5_INODE_RANGE_UNUSED;
119                 break;
120         case PR_5_INODE_USED:
121                 if (pctx->ino == pctx->ino2)
122                         pctx->ino2 = 0;
123                 else
124                         problem = PR_5_INODE_RANGE_USED;
125                 break;
126         }
127         fix_problem(ctx, problem, pctx);
128         pctx->blk = pctx->blk2 = NO_BLK;
129         pctx->ino = pctx->ino2 = 0;
130 }
131
132 /* Just to be more succint */
133 #define B2C(x)  EXT2FS_B2C(fs, (x))
134 #define EQ_CLSTR(x, y) (B2C(x) == B2C(y))
135 #define LE_CLSTR(x, y) (B2C(x) <= B2C(y))
136 #define GE_CLSTR(x, y) (B2C(x) >= B2C(y))
137
138 static void check_block_bitmaps(e2fsck_t ctx)
139 {
140         ext2_filsys fs = ctx->fs;
141         blk64_t i;
142         int     *free_array;
143         int     group = 0;
144         int     blocks = 0;
145         blk64_t free_blocks = 0;
146         blk64_t first_free = ext2fs_blocks_count(fs->super);
147         int     group_free = 0;
148         int     actual, bitmap;
149         struct problem_context  pctx;
150         int     problem, save_problem, fixit, had_problem;
151         errcode_t       retval;
152         int             csum_flag;
153         int             skip_group = 0;
154         int     old_desc_blocks = 0;
155         int     count = 0;
156         int     cmp_block = 0;
157         int     redo_flag = 0;
158         blk64_t super_blk, old_desc_blk, new_desc_blk;
159         io_manager      manager = ctx->fs->io->manager;
160
161         clear_problem_context(&pctx);
162         free_array = (int *) e2fsck_allocate_memory(ctx,
163             fs->group_desc_count * sizeof(int), "free block count array");
164
165         if ((B2C(fs->super->s_first_data_block) <
166              ext2fs_get_block_bitmap_start2(ctx->block_found_map)) ||
167             (B2C(ext2fs_blocks_count(fs->super)-1) >
168              ext2fs_get_block_bitmap_end2(ctx->block_found_map))) {
169                 pctx.num = 1;
170                 pctx.blk = B2C(fs->super->s_first_data_block);
171                 pctx.blk2 = B2C(ext2fs_blocks_count(fs->super) - 1);
172                 pctx.ino = ext2fs_get_block_bitmap_start2(ctx->block_found_map);
173                 pctx.ino2 = ext2fs_get_block_bitmap_end2(ctx->block_found_map);
174                 fix_problem(ctx, PR_5_BMAP_ENDPOINTS, &pctx);
175
176                 ctx->flags |= E2F_FLAG_ABORT; /* fatal */
177                 goto errout;
178         }
179
180         if ((B2C(fs->super->s_first_data_block) <
181              ext2fs_get_block_bitmap_start2(fs->block_map)) ||
182             (B2C(ext2fs_blocks_count(fs->super)-1) >
183              ext2fs_get_block_bitmap_end2(fs->block_map))) {
184                 pctx.num = 2;
185                 pctx.blk = B2C(fs->super->s_first_data_block);
186                 pctx.blk2 = B2C(ext2fs_blocks_count(fs->super) - 1);
187                 pctx.ino = ext2fs_get_block_bitmap_start2(fs->block_map);
188                 pctx.ino2 = ext2fs_get_block_bitmap_end2(fs->block_map);
189                 fix_problem(ctx, PR_5_BMAP_ENDPOINTS, &pctx);
190
191                 ctx->flags |= E2F_FLAG_ABORT; /* fatal */
192                 goto errout;
193         }
194
195         csum_flag = EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
196                                                EXT4_FEATURE_RO_COMPAT_GDT_CSUM);
197 redo_counts:
198         had_problem = 0;
199         save_problem = 0;
200         pctx.blk = pctx.blk2 = NO_BLK;
201         if (csum_flag &&
202             (ext2fs_bg_flags_test(fs, group, EXT2_BG_BLOCK_UNINIT)))
203                 skip_group++;
204         for (i = B2C(fs->super->s_first_data_block);
205              i < ext2fs_blocks_count(fs->super);
206              i += EXT2FS_CLUSTER_RATIO(fs)) {
207                 actual = ext2fs_fast_test_block_bitmap2(ctx->block_found_map, i);
208
209                 if (skip_group) {
210                         if ((B2C(i) - B2C(fs->super->s_first_data_block)) %
211                             fs->super->s_clusters_per_group == 0) {
212                                 super_blk = 0;
213                                 old_desc_blk = 0;
214                                 new_desc_blk = 0;
215                                 ext2fs_super_and_bgd_loc2(fs, group, &super_blk,
216                                          &old_desc_blk, &new_desc_blk, 0);
217
218                                 if (fs->super->s_feature_incompat &
219                                                 EXT2_FEATURE_INCOMPAT_META_BG)
220                                         old_desc_blocks =
221                                                 fs->super->s_first_meta_bg;
222                                 else
223                                         old_desc_blocks = fs->desc_blocks +
224                                         fs->super->s_reserved_gdt_blocks;
225
226                                 count = 0;
227                                 cmp_block = fs->super->s_clusters_per_group;
228                                 if (group == (int)fs->group_desc_count - 1)
229                                         cmp_block =
230                                                 EXT2FS_NUM_B2C(fs,
231                 ext2fs_blocks_count(fs->super) % fs->super->s_blocks_per_group);
232                         }
233
234                         bitmap = 0;
235                         if (EQ_CLSTR(i, super_blk) ||
236                             (old_desc_blk && old_desc_blocks &&
237                              GE_CLSTR(i, old_desc_blk) &&
238                              LE_CLSTR(i, old_desc_blk + old_desc_blocks-1)) ||
239                             (new_desc_blk && EQ_CLSTR(i, new_desc_blk)) ||
240                             EQ_CLSTR(i, ext2fs_block_bitmap_loc(fs, group)) ||
241                             EQ_CLSTR(i, ext2fs_inode_bitmap_loc(fs, group)) ||
242                             (GE_CLSTR(i, ext2fs_inode_table_loc(fs, group)) &&
243                              LE_CLSTR(i, (ext2fs_inode_table_loc(fs, group) +
244                                           fs->inode_blocks_per_group - 1)))) {
245                                 bitmap = 1;
246                                 actual = (actual != 0);
247                                 count++;
248                                 cmp_block--;
249                         } else if ((EXT2FS_B2C(fs, i) - count -
250                                     EXT2FS_B2C(fs, fs->super->s_first_data_block)) %
251                                    fs->super->s_clusters_per_group == 0) {
252                                 /*
253                                  * When the compare data blocks in block bitmap
254                                  * are 0, count the free block,
255                                  * skip the current block group.
256                                  */
257                                 if (ext2fs_test_block_bitmap_range2(
258                                             ctx->block_found_map,
259                                             EXT2FS_B2C(fs, i),
260                                             cmp_block)) {
261                                         /*
262                                          * -1 means to skip the current block
263                                          * group.
264                                          */
265                                         blocks = fs->super->s_clusters_per_group - 1;
266                                         group_free = cmp_block;
267                                         free_blocks += cmp_block;
268                                         /*
269                                          * The current block group's last block
270                                          * is set to i.
271                                          */
272                                         i += EXT2FS_C2B(fs, cmp_block - 1);
273                                         bitmap = 1;
274                                         goto do_counts;
275                                 }
276                         }
277                 } else if (redo_flag)
278                         bitmap = actual;
279                 else
280                         bitmap = ext2fs_fast_test_block_bitmap2(fs->block_map, i);
281
282                 if (actual == bitmap)
283                         goto do_counts;
284
285                 if (!actual && bitmap) {
286                         /*
287                          * Block not used, but marked in use in the bitmap.
288                          */
289                         problem = PR_5_BLOCK_UNUSED;
290                 } else {
291                         /*
292                          * Block used, but not marked in use in the bitmap.
293                          */
294                         problem = PR_5_BLOCK_USED;
295
296                         if (skip_group) {
297                                 struct problem_context pctx2;
298                                 pctx2.blk = i;
299                                 pctx2.group = group;
300                                 if (fix_problem(ctx, PR_5_BLOCK_UNINIT,&pctx2)){
301                                         ext2fs_bg_flags_clear(fs, group, EXT2_BG_BLOCK_UNINIT);
302                                         skip_group = 0;
303                                 }
304                         }
305                 }
306                 if (pctx.blk == NO_BLK) {
307                         pctx.blk = pctx.blk2 = i;
308                         save_problem = problem;
309                 } else {
310                         if ((problem == save_problem) &&
311                             (pctx.blk2 == i-1))
312                                 pctx.blk2++;
313                         else {
314                                 print_bitmap_problem(ctx, save_problem, &pctx);
315                                 pctx.blk = pctx.blk2 = i;
316                                 save_problem = problem;
317                         }
318                 }
319                 ctx->flags |= E2F_FLAG_PROG_SUPPRESS;
320                 had_problem++;
321
322                 /*
323                  * If there a problem we should turn off the discard so we
324                  * do not compromise the filesystem.
325                  */
326                 ctx->options &= ~E2F_OPT_DISCARD;
327
328         do_counts:
329                 if (!bitmap && (!skip_group || csum_flag)) {
330                         group_free++;
331                         free_blocks++;
332                         if (first_free > i)
333                                 first_free = i;
334                 } else {
335                         if (i > first_free)
336                                 e2fsck_discard_blocks(ctx, manager, first_free,
337                                                       (i - first_free));
338                         first_free = ext2fs_blocks_count(fs->super);
339                 }
340                 blocks ++;
341                 if ((blocks == fs->super->s_clusters_per_group) ||
342                     (EXT2FS_B2C(fs, i) ==
343                      EXT2FS_B2C(fs, ext2fs_blocks_count(fs->super)-1))) {
344                         free_array[group] = group_free;
345                         group ++;
346                         blocks = 0;
347                         group_free = 0;
348                         skip_group = 0;
349                         if (ctx->progress)
350                                 if ((ctx->progress)(ctx, 5, group,
351                                                     fs->group_desc_count*2))
352                                         goto errout;
353                         if (csum_flag &&
354                             (i != ext2fs_blocks_count(fs->super)-1) &&
355                             ext2fs_bg_flags_test(fs, group, 
356                                                 EXT2_BG_BLOCK_UNINIT))
357                                 skip_group++;
358                 }
359         }
360         if (pctx.blk != NO_BLK)
361                 print_bitmap_problem(ctx, save_problem, &pctx);
362         if (had_problem)
363                 fixit = end_problem_latch(ctx, PR_LATCH_BBITMAP);
364         else
365                 fixit = -1;
366         ctx->flags &= ~E2F_FLAG_PROG_SUPPRESS;
367
368         if (fixit == 1) {
369                 ext2fs_free_block_bitmap(fs->block_map);
370                 retval = ext2fs_copy_bitmap(ctx->block_found_map,
371                                                   &fs->block_map);
372                 if (retval) {
373                         clear_problem_context(&pctx);
374                         fix_problem(ctx, PR_5_COPY_BBITMAP_ERROR, &pctx);
375                         ctx->flags |= E2F_FLAG_ABORT;
376                         goto errout;
377                 }
378                 ext2fs_set_bitmap_padding(fs->block_map);
379                 ext2fs_mark_bb_dirty(fs);
380
381                 /* Redo the counts */
382                 blocks = 0; free_blocks = 0; group_free = 0; group = 0;
383                 memset(free_array, 0, fs->group_desc_count * sizeof(int));
384                 redo_flag++;
385                 goto redo_counts;
386         } else if (fixit == 0)
387                 ext2fs_unmark_valid(fs);
388
389         for (i = 0; i < fs->group_desc_count; i++) {
390                 if (free_array[i] != ext2fs_bg_free_blocks_count(fs, i)) {
391                         pctx.group = i;
392                         pctx.blk = ext2fs_bg_free_blocks_count(fs, i);
393                         pctx.blk2 = free_array[i];
394
395                         if (fix_problem(ctx, PR_5_FREE_BLOCK_COUNT_GROUP,
396                                         &pctx)) {
397                                 ext2fs_bg_free_blocks_count_set(fs, i, free_array[i]);
398                                 ext2fs_mark_super_dirty(fs);
399                         } else
400                                 ext2fs_unmark_valid(fs);
401                 }
402         }
403         free_blocks = EXT2FS_C2B(fs, free_blocks);
404         if (free_blocks != ext2fs_free_blocks_count(fs->super)) {
405                 pctx.group = 0;
406                 pctx.blk = ext2fs_free_blocks_count(fs->super);
407                 pctx.blk2 = free_blocks;
408
409                 if (fix_problem(ctx, PR_5_FREE_BLOCK_COUNT, &pctx)) {
410                         ext2fs_free_blocks_count_set(fs->super, free_blocks);
411                         ext2fs_mark_super_dirty(fs);
412                 } else
413                         ext2fs_unmark_valid(fs);
414         }
415 errout:
416         ext2fs_free_mem(&free_array);
417 }
418
419 static void check_inode_bitmaps(e2fsck_t ctx)
420 {
421         ext2_filsys fs = ctx->fs;
422         ext2_ino_t      i;
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;
431         errcode_t       retval;
432         struct problem_context  pctx;
433         int             problem, save_problem, fixit, had_problem;
434         int             csum_flag;
435         int             skip_group = 0;
436         int             redo_flag = 0;
437         io_manager      manager = ctx->fs->io->manager;
438
439         clear_problem_context(&pctx);
440         free_array = (int *) e2fsck_allocate_memory(ctx,
441             fs->group_desc_count * sizeof(int), "free inode count array");
442
443         dir_array = (int *) e2fsck_allocate_memory(ctx,
444            fs->group_desc_count * sizeof(int), "directory count array");
445
446         if ((1 < ext2fs_get_inode_bitmap_start2(ctx->inode_used_map)) ||
447             (fs->super->s_inodes_count >
448              ext2fs_get_inode_bitmap_end2(ctx->inode_used_map))) {
449                 pctx.num = 3;
450                 pctx.blk = 1;
451                 pctx.blk2 = fs->super->s_inodes_count;
452                 pctx.ino = ext2fs_get_inode_bitmap_start2(ctx->inode_used_map);
453                 pctx.ino2 = ext2fs_get_inode_bitmap_end2(ctx->inode_used_map);
454                 fix_problem(ctx, PR_5_BMAP_ENDPOINTS, &pctx);
455
456                 ctx->flags |= E2F_FLAG_ABORT; /* fatal */
457                 goto errout;
458         }
459         if ((1 < ext2fs_get_inode_bitmap_start2(fs->inode_map)) ||
460             (fs->super->s_inodes_count >
461              ext2fs_get_inode_bitmap_end2(fs->inode_map))) {
462                 pctx.num = 4;
463                 pctx.blk = 1;
464                 pctx.blk2 = fs->super->s_inodes_count;
465                 pctx.ino = ext2fs_get_inode_bitmap_start2(fs->inode_map);
466                 pctx.ino2 = ext2fs_get_inode_bitmap_end2(fs->inode_map);
467                 fix_problem(ctx, PR_5_BMAP_ENDPOINTS, &pctx);
468
469                 ctx->flags |= E2F_FLAG_ABORT; /* fatal */
470                 goto errout;
471         }
472
473         csum_flag = EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
474                                                EXT4_FEATURE_RO_COMPAT_GDT_CSUM);
475 redo_counts:
476         had_problem = 0;
477         save_problem = 0;
478         pctx.ino = pctx.ino2 = 0;
479         if (csum_flag &&
480             (ext2fs_bg_flags_test(fs, group, EXT2_BG_INODE_UNINIT)))
481                 skip_group++;
482
483         /* Protect loop from wrap-around if inodes_count is maxed */
484         for (i = 1; i <= fs->super->s_inodes_count && i > 0; i++) {
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
509                 actual = ext2fs_fast_test_inode_bitmap2(ctx->inode_used_map, i);
510                 if (redo_flag)
511                         bitmap = actual;
512                 else if (!skip_group)
513                         bitmap = ext2fs_fast_test_inode_bitmap2(fs->inode_map, i);
514                 if (actual == bitmap)
515                         goto do_counts;
516
517                 if (!actual && bitmap) {
518                         /*
519                          * Inode wasn't used, but marked in bitmap
520                          */
521                         problem = PR_5_INODE_UNUSED;
522                 } else /* if (actual && !bitmap) */ {
523                         /*
524                          * Inode used, but not in bitmap
525                          */
526                         problem = PR_5_INODE_USED;
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)){
537                                         ext2fs_bg_flags_clear(fs, group, EXT2_BG_INODE_UNINIT);
538                                         skip_group = 0;
539                                 }
540                         }
541                 }
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                 }
555                 ctx->flags |= E2F_FLAG_PROG_SUPPRESS;
556                 had_problem++;
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;
562
563 do_counts:
564                 if (bitmap) {
565                         if (ext2fs_test_inode_bitmap2(ctx->inode_dir_map, i))
566                                 dirs_count++;
567                 } else if (!skip_group || csum_flag) {
568                         group_free++;
569                         free_inodes++;
570                 }
571
572                 inodes++;
573                 if ((inodes == fs->super->s_inodes_per_group) ||
574                     (i == fs->super->s_inodes_count)) {
575
576                         free_array[group] = group_free;
577                         dir_array[group] = dirs_count;
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
608                         group ++;
609                         inodes = 0;
610                         skip_group = 0;
611                         group_free = 0;
612                         dirs_count = 0;
613                         if (ctx->progress)
614                                 if ((ctx->progress)(ctx, 5,
615                                             group + fs->group_desc_count,
616                                             fs->group_desc_count*2))
617                                         goto errout;
618                         if (csum_flag &&
619                             (i != fs->super->s_inodes_count) &&
620                             (ext2fs_bg_flags_test(fs, group, EXT2_BG_INODE_UNINIT)
621                              ))
622                                 skip_group++;
623                 }
624         }
625         if (pctx.ino)
626                 print_bitmap_problem(ctx, save_problem, &pctx);
627
628         if (had_problem)
629                 fixit = end_problem_latch(ctx, PR_LATCH_IBITMAP);
630         else
631                 fixit = -1;
632         ctx->flags &= ~E2F_FLAG_PROG_SUPPRESS;
633
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);
638                 if (retval) {
639                         clear_problem_context(&pctx);
640                         fix_problem(ctx, PR_5_COPY_IBITMAP_ERROR, &pctx);
641                         ctx->flags |= E2F_FLAG_ABORT;
642                         goto errout;
643                 }
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));
652                 redo_flag++;
653                 goto redo_counts;
654         } else if (fixit == 0)
655                 ext2fs_unmark_valid(fs);
656
657         for (i = 0; i < fs->group_desc_count; i++) {
658                 if (free_array[i] != ext2fs_bg_free_inodes_count(fs, i)) {
659                         pctx.group = i;
660                         pctx.ino = ext2fs_bg_free_inodes_count(fs, i);
661                         pctx.ino2 = free_array[i];
662                         if (fix_problem(ctx, PR_5_FREE_INODE_COUNT_GROUP,
663                                         &pctx)) {
664                                 ext2fs_bg_free_inodes_count_set(fs, i, free_array[i]);
665                                 ext2fs_mark_super_dirty(fs);
666                         } else
667                                 ext2fs_unmark_valid(fs);
668                 }
669                 if (dir_array[i] != ext2fs_bg_used_dirs_count(fs, i)) {
670                         pctx.group = i;
671                         pctx.ino = ext2fs_bg_used_dirs_count(fs, i);
672                         pctx.ino2 = dir_array[i];
673
674                         if (fix_problem(ctx, PR_5_FREE_DIR_COUNT_GROUP,
675                                         &pctx)) {
676                                 ext2fs_bg_used_dirs_count_set(fs, i, dir_array[i]);
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) {
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)) {
688                         fs->super->s_free_inodes_count = free_inodes;
689                         ext2fs_mark_super_dirty(fs);
690                 } else
691                         ext2fs_unmark_valid(fs);
692         }
693 errout:
694         ext2fs_free_mem(&free_array);
695         ext2fs_free_mem(&dir_array);
696 }
697
698 static void check_inode_end(e2fsck_t ctx)
699 {
700         ext2_filsys fs = ctx->fs;
701         ext2_ino_t      end, save_inodes_count, i;
702         struct problem_context  pctx;
703
704         clear_problem_context(&pctx);
705
706         end = EXT2_INODES_PER_GROUP(fs->super) * fs->group_desc_count;
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);
712                 ctx->flags |= E2F_FLAG_ABORT; /* fatal */
713                 return;
714         }
715         if (save_inodes_count == end)
716                 return;
717
718         /* protect loop from wrap-around if end is maxed */
719         for (i = save_inodes_count + 1; i <= end && i > save_inodes_count; i++) {
720                 if (!ext2fs_test_inode_bitmap(fs->inode_map, i)) {
721                         if (fix_problem(ctx, PR_5_INODE_BMAP_PADDING, &pctx)) {
722                                 for (; i <= end; i++)
723                                         ext2fs_mark_inode_bitmap(fs->inode_map,
724                                                                  i);
725                                 ext2fs_mark_ib_dirty(fs);
726                         } else
727                                 ext2fs_unmark_valid(fs);
728                         break;
729                 }
730         }
731
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);
737                 ctx->flags |= E2F_FLAG_ABORT; /* fatal */
738                 return;
739         }
740 }
741
742 static void check_block_end(e2fsck_t ctx)
743 {
744         ext2_filsys fs = ctx->fs;
745         blk64_t end, save_blocks_count, i;
746         struct problem_context  pctx;
747
748         clear_problem_context(&pctx);
749
750         end = ext2fs_get_block_bitmap_start2(fs->block_map) +
751                 ((blk64_t)EXT2_CLUSTERS_PER_GROUP(fs->super) * fs->group_desc_count) - 1;
752         pctx.errcode = ext2fs_fudge_block_bitmap_end2(fs->block_map, end,
753                                                      &save_blocks_count);
754         if (pctx.errcode) {
755                 pctx.num = 3;
756                 fix_problem(ctx, PR_5_FUDGE_BITMAP_ERROR, &pctx);
757                 ctx->flags |= E2F_FLAG_ABORT; /* fatal */
758                 return;
759         }
760         if (save_blocks_count == end)
761                 return;
762
763         /* Protect loop from wrap-around if end is maxed */
764         for (i = save_blocks_count + 1; i <= end && i > save_blocks_count; i++) {
765                 if (!ext2fs_test_block_bitmap2(fs->block_map,
766                                                EXT2FS_C2B(fs, i))) {
767                         if (fix_problem(ctx, PR_5_BLOCK_BMAP_PADDING, &pctx)) {
768                                 for (; i <= end; i++)
769                                         ext2fs_mark_block_bitmap2(fs->block_map,
770                                                         EXT2FS_C2B(fs, i));
771                                 ext2fs_mark_bb_dirty(fs);
772                         } else
773                                 ext2fs_unmark_valid(fs);
774                         break;
775                 }
776         }
777
778         pctx.errcode = ext2fs_fudge_block_bitmap_end2(fs->block_map,
779                                                      save_blocks_count, 0);
780         if (pctx.errcode) {
781                 pctx.num = 4;
782                 fix_problem(ctx, PR_5_FUDGE_BITMAP_ERROR, &pctx);
783                 ctx->flags |= E2F_FLAG_ABORT; /* fatal */
784                 return;
785         }
786 }
787
788
789