OSDN Git Service

Merge branch 'maint' into next
[android-x86/external-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         int ret = 0;
81
82         /*
83          * If the filesystem has changed it means that there was an corruption
84          * which should be repaired, but in some cases just one e2fsck run is
85          * not enough to fix the problem, hence it is not safe to run discard
86          * in this case.
87          */
88         if (ext2fs_test_changed(ctx->fs))
89                 ctx->options &= ~E2F_OPT_DISCARD;
90
91         if ((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 static void check_block_bitmaps(e2fsck_t ctx)
133 {
134         ext2_filsys fs = ctx->fs;
135         blk64_t i;
136         int     *free_array;
137         int     group = 0;
138         int     blocks = 0;
139         blk64_t free_blocks = 0;
140         blk64_t first_free = ext2fs_blocks_count(fs->super);
141         int     group_free = 0;
142         int     actual, bitmap;
143         struct problem_context  pctx;
144         int     problem, save_problem, fixit, had_problem;
145         errcode_t       retval;
146         int             csum_flag;
147         int             skip_group = 0;
148         int     old_desc_blocks = 0;
149         int     count = 0;
150         int     cmp_block = 0;
151         int     redo_flag = 0;
152         blk64_t super_blk, old_desc_blk, new_desc_blk;
153         io_manager      manager = ctx->fs->io->manager;
154
155         clear_problem_context(&pctx);
156         free_array = (int *) e2fsck_allocate_memory(ctx,
157             fs->group_desc_count * sizeof(int), "free block count array");
158
159         if ((fs->super->s_first_data_block <
160              ext2fs_get_block_bitmap_start2(ctx->block_found_map)) ||
161             (ext2fs_blocks_count(fs->super)-1 >
162              ext2fs_get_block_bitmap_end2(ctx->block_found_map))) {
163                 pctx.num = 1;
164                 pctx.blk = fs->super->s_first_data_block;
165                 pctx.blk2 = ext2fs_blocks_count(fs->super) -1;
166                 pctx.ino = ext2fs_get_block_bitmap_start2(ctx->block_found_map);
167                 pctx.ino2 = ext2fs_get_block_bitmap_end2(ctx->block_found_map);
168                 fix_problem(ctx, PR_5_BMAP_ENDPOINTS, &pctx);
169
170                 ctx->flags |= E2F_FLAG_ABORT; /* fatal */
171                 goto errout;
172         }
173
174         if ((fs->super->s_first_data_block <
175              ext2fs_get_block_bitmap_start2(fs->block_map)) ||
176             (ext2fs_blocks_count(fs->super)-1 >
177              ext2fs_get_block_bitmap_end2(fs->block_map))) {
178                 pctx.num = 2;
179                 pctx.blk = fs->super->s_first_data_block;
180                 pctx.blk2 = ext2fs_blocks_count(fs->super) -1;
181                 pctx.ino = ext2fs_get_block_bitmap_start2(fs->block_map);
182                 pctx.ino2 = ext2fs_get_block_bitmap_end2(fs->block_map);
183                 fix_problem(ctx, PR_5_BMAP_ENDPOINTS, &pctx);
184
185                 ctx->flags |= E2F_FLAG_ABORT; /* fatal */
186                 goto errout;
187         }
188
189         csum_flag = EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
190                                                EXT4_FEATURE_RO_COMPAT_GDT_CSUM);
191 redo_counts:
192         had_problem = 0;
193         save_problem = 0;
194         pctx.blk = pctx.blk2 = NO_BLK;
195         if (csum_flag &&
196             (ext2fs_bg_flags_test(fs, group, EXT2_BG_BLOCK_UNINIT)))
197                 skip_group++;
198         for (i = fs->super->s_first_data_block;
199              i < ext2fs_blocks_count(fs->super);
200              i++) {
201                 actual = ext2fs_fast_test_block_bitmap2(ctx->block_found_map, i);
202
203                 if (skip_group) {
204                         if ((i - fs->super->s_first_data_block) %
205                             fs->super->s_blocks_per_group == 0) {
206                                 super_blk = 0;
207                                 old_desc_blk = 0;
208                                 new_desc_blk = 0;
209                                 ext2fs_super_and_bgd_loc2(fs, group, &super_blk,
210                                          &old_desc_blk, &new_desc_blk, 0);
211
212                                 if (fs->super->s_feature_incompat &
213                                                 EXT2_FEATURE_INCOMPAT_META_BG)
214                                         old_desc_blocks =
215                                                 fs->super->s_first_meta_bg;
216                                 else
217                                         old_desc_blocks = fs->desc_blocks +
218                                         fs->super->s_reserved_gdt_blocks;
219
220                                 count = 0;
221                                 cmp_block = fs->super->s_blocks_per_group;
222                                 if (group == (int)fs->group_desc_count - 1)
223                                         cmp_block =
224                                                 ext2fs_blocks_count(fs->super) %
225                                                 fs->super->s_blocks_per_group;
226                         }
227
228                         bitmap = 0;
229                         if ((i == super_blk) ||
230                             (old_desc_blk && old_desc_blocks &&
231                              (i >= old_desc_blk) &&
232                              (i < old_desc_blk + old_desc_blocks)) ||
233                             (new_desc_blk && (i == new_desc_blk)) ||
234                             (i == ext2fs_block_bitmap_loc(fs, group)) ||
235                             (i == ext2fs_inode_bitmap_loc(fs, group)) ||
236                             (i >= ext2fs_inode_table_loc(fs, group) &&
237                              (i < ext2fs_inode_table_loc(fs, group) +
238                               fs->inode_blocks_per_group))) {
239                                 bitmap = 1;
240                                 actual = (actual != 0);
241                                 count++;
242                                 cmp_block--;
243                         } else if ((i - count - fs->super->s_first_data_block) %
244                                   fs->super->s_blocks_per_group == 0) {
245                                 /*
246                                  * When the compare data blocks in block bitmap
247                                  * are 0, count the free block,
248                                  * skip the current block group.
249                                  */
250                                 if (ext2fs_test_block_bitmap_range2(
251                                             ctx->block_found_map, i,
252                                             cmp_block)) {
253                                         /*
254                                          * -1 means to skip the current block
255                                          * group.
256                                          */
257                                         blocks = fs->super->s_blocks_per_group
258                                                                         - 1;
259                                         group_free = cmp_block;
260                                         free_blocks += cmp_block;
261                                         /*
262                                          * The current block group's last block
263                                          * is set to i.
264                                          */
265                                         i += cmp_block - 1;
266                                         bitmap = 1;
267                                         goto do_counts;
268                                 }
269                         }
270                 } else if (redo_flag)
271                         bitmap = actual;
272                 else
273                         bitmap = ext2fs_fast_test_block_bitmap2(fs->block_map, i);
274
275                 if (actual == bitmap)
276                         goto do_counts;
277
278                 if (!actual && bitmap) {
279                         /*
280                          * Block not used, but marked in use in the bitmap.
281                          */
282                         problem = PR_5_BLOCK_UNUSED;
283                 } else {
284                         /*
285                          * Block used, but not marked in use in the bitmap.
286                          */
287                         problem = PR_5_BLOCK_USED;
288
289                         if (skip_group) {
290                                 struct problem_context pctx2;
291                                 pctx2.blk = i;
292                                 pctx2.group = group;
293                                 if (fix_problem(ctx, PR_5_BLOCK_UNINIT,&pctx2)){
294                                         ext2fs_bg_flags_clear(fs, group, EXT2_BG_BLOCK_UNINIT);
295                                         skip_group = 0;
296                                 }
297                         }
298                 }
299                 if (pctx.blk == NO_BLK) {
300                         pctx.blk = pctx.blk2 = i;
301                         save_problem = problem;
302                 } else {
303                         if ((problem == save_problem) &&
304                             (pctx.blk2 == i-1))
305                                 pctx.blk2++;
306                         else {
307                                 print_bitmap_problem(ctx, save_problem, &pctx);
308                                 pctx.blk = pctx.blk2 = i;
309                                 save_problem = problem;
310                         }
311                 }
312                 ctx->flags |= E2F_FLAG_PROG_SUPPRESS;
313                 had_problem++;
314
315                 /*
316                  * If there a problem we should turn off the discard so we
317                  * do not compromise the filesystem.
318                  */
319                 ctx->options &= ~E2F_OPT_DISCARD;
320
321         do_counts:
322                 if (!bitmap && (!skip_group || csum_flag)) {
323                         group_free++;
324                         free_blocks++;
325                         if (first_free > i)
326                                 first_free = i;
327                 } else {
328                         if ((i > first_free) &&
329                            (ctx->options & E2F_OPT_DISCARD)) {
330                                 e2fsck_discard_blocks(ctx, manager, first_free,
331                                                       (i - first_free));
332                         }
333                         first_free = ext2fs_blocks_count(fs->super);
334                 }
335                 blocks ++;
336                 if ((blocks == fs->super->s_blocks_per_group) ||
337                     (i == ext2fs_blocks_count(fs->super)-1)) {
338                         free_array[group] = group_free;
339                         group ++;
340                         blocks = 0;
341                         group_free = 0;
342                         skip_group = 0;
343                         if (ctx->progress)
344                                 if ((ctx->progress)(ctx, 5, group,
345                                                     fs->group_desc_count*2))
346                                         goto errout;
347                         if (csum_flag &&
348                             (i != ext2fs_blocks_count(fs->super)-1) &&
349                             ext2fs_bg_flags_test(fs, group, 
350                                                 EXT2_BG_BLOCK_UNINIT))
351                                 skip_group++;
352                 }
353         }
354         if (pctx.blk != NO_BLK)
355                 print_bitmap_problem(ctx, save_problem, &pctx);
356         if (had_problem)
357                 fixit = end_problem_latch(ctx, PR_LATCH_BBITMAP);
358         else
359                 fixit = -1;
360         ctx->flags &= ~E2F_FLAG_PROG_SUPPRESS;
361
362         if (fixit == 1) {
363                 ext2fs_free_block_bitmap(fs->block_map);
364                 retval = ext2fs_copy_bitmap(ctx->block_found_map,
365                                                   &fs->block_map);
366                 if (retval) {
367                         clear_problem_context(&pctx);
368                         fix_problem(ctx, PR_5_COPY_BBITMAP_ERROR, &pctx);
369                         ctx->flags |= E2F_FLAG_ABORT;
370                         goto errout;
371                 }
372                 ext2fs_set_bitmap_padding(fs->block_map);
373                 ext2fs_mark_bb_dirty(fs);
374
375                 /* Redo the counts */
376                 blocks = 0; free_blocks = 0; group_free = 0; group = 0;
377                 memset(free_array, 0, fs->group_desc_count * sizeof(int));
378                 redo_flag++;
379                 goto redo_counts;
380         } else if (fixit == 0)
381                 ext2fs_unmark_valid(fs);
382
383         for (i = 0; i < fs->group_desc_count; i++) {
384                 if (free_array[i] != ext2fs_bg_free_blocks_count(fs, i)) {
385                         pctx.group = i;
386                         pctx.blk = ext2fs_bg_free_blocks_count(fs, i);
387                         pctx.blk2 = free_array[i];
388
389                         if (fix_problem(ctx, PR_5_FREE_BLOCK_COUNT_GROUP,
390                                         &pctx)) {
391                                 ext2fs_bg_free_blocks_count_set(fs, i, free_array[i]);
392                                 ext2fs_mark_super_dirty(fs);
393                         } else
394                                 ext2fs_unmark_valid(fs);
395                 }
396         }
397         if (free_blocks != ext2fs_free_blocks_count(fs->super)) {
398                 pctx.group = 0;
399                 pctx.blk = ext2fs_free_blocks_count(fs->super);
400                 pctx.blk2 = free_blocks;
401
402                 if (fix_problem(ctx, PR_5_FREE_BLOCK_COUNT, &pctx)) {
403                         ext2fs_free_blocks_count_set(fs->super, free_blocks);
404                         ext2fs_mark_super_dirty(fs);
405                 } else
406                         ext2fs_unmark_valid(fs);
407         }
408 errout:
409         ext2fs_free_mem(&free_array);
410 }
411
412 static void check_inode_bitmaps(e2fsck_t ctx)
413 {
414         ext2_filsys fs = ctx->fs;
415         ext2_ino_t      i;
416         unsigned int    free_inodes = 0;
417         int             group_free = 0;
418         int             dirs_count = 0;
419         int             group = 0;
420         unsigned int    inodes = 0;
421         int             *free_array;
422         int             *dir_array;
423         int             actual, bitmap;
424         errcode_t       retval;
425         struct problem_context  pctx;
426         int             problem, save_problem, fixit, had_problem;
427         int             csum_flag;
428         int             skip_group = 0;
429         int             redo_flag = 0;
430         io_manager      manager = ctx->fs->io->manager;
431
432         clear_problem_context(&pctx);
433         free_array = (int *) e2fsck_allocate_memory(ctx,
434             fs->group_desc_count * sizeof(int), "free inode count array");
435
436         dir_array = (int *) e2fsck_allocate_memory(ctx,
437            fs->group_desc_count * sizeof(int), "directory count array");
438
439         if ((1 < ext2fs_get_inode_bitmap_start2(ctx->inode_used_map)) ||
440             (fs->super->s_inodes_count >
441              ext2fs_get_inode_bitmap_end2(ctx->inode_used_map))) {
442                 pctx.num = 3;
443                 pctx.blk = 1;
444                 pctx.blk2 = fs->super->s_inodes_count;
445                 pctx.ino = ext2fs_get_inode_bitmap_start2(ctx->inode_used_map);
446                 pctx.ino2 = ext2fs_get_inode_bitmap_end2(ctx->inode_used_map);
447                 fix_problem(ctx, PR_5_BMAP_ENDPOINTS, &pctx);
448
449                 ctx->flags |= E2F_FLAG_ABORT; /* fatal */
450                 goto errout;
451         }
452         if ((1 < ext2fs_get_inode_bitmap_start2(fs->inode_map)) ||
453             (fs->super->s_inodes_count >
454              ext2fs_get_inode_bitmap_end2(fs->inode_map))) {
455                 pctx.num = 4;
456                 pctx.blk = 1;
457                 pctx.blk2 = fs->super->s_inodes_count;
458                 pctx.ino = ext2fs_get_inode_bitmap_start2(fs->inode_map);
459                 pctx.ino2 = ext2fs_get_inode_bitmap_end2(fs->inode_map);
460                 fix_problem(ctx, PR_5_BMAP_ENDPOINTS, &pctx);
461
462                 ctx->flags |= E2F_FLAG_ABORT; /* fatal */
463                 goto errout;
464         }
465
466         csum_flag = EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
467                                                EXT4_FEATURE_RO_COMPAT_GDT_CSUM);
468 redo_counts:
469         had_problem = 0;
470         save_problem = 0;
471         pctx.ino = pctx.ino2 = 0;
472         if (csum_flag &&
473             (ext2fs_bg_flags_test(fs, group, EXT2_BG_INODE_UNINIT)))
474                 skip_group++;
475
476         /* Protect loop from wrap-around if inodes_count is maxed */
477         for (i = 1; i <= fs->super->s_inodes_count && i > 0; i++) {
478                 bitmap = 0;
479                 if (skip_group &&
480                     i % fs->super->s_inodes_per_group == 1) {
481                         /*
482                          * Current inode is the first inode
483                          * in the current block group.
484                          */
485                         if (ext2fs_test_inode_bitmap_range(
486                                     ctx->inode_used_map, i,
487                                     fs->super->s_inodes_per_group)) {
488                                 /*
489                                  * When the compared inodes in inodes bitmap
490                                  * are 0, count the free inode,
491                                  * skip the current block group.
492                                  */
493                                 inodes = fs->super->s_inodes_per_group - 1;
494                                 group_free = inodes;
495                                 free_inodes += inodes;
496                                 i += inodes;
497                                 skip_group = 0;
498                                 goto do_counts;
499                         }
500                 }
501
502                 actual = ext2fs_fast_test_inode_bitmap2(ctx->inode_used_map, i);
503                 if (redo_flag)
504                         bitmap = actual;
505                 else if (!skip_group)
506                         bitmap = ext2fs_fast_test_inode_bitmap2(fs->inode_map, i);
507                 if (actual == bitmap)
508                         goto do_counts;
509
510                 if (!actual && bitmap) {
511                         /*
512                          * Inode wasn't used, but marked in bitmap
513                          */
514                         problem = PR_5_INODE_UNUSED;
515                 } else /* if (actual && !bitmap) */ {
516                         /*
517                          * Inode used, but not in bitmap
518                          */
519                         problem = PR_5_INODE_USED;
520
521                         /* We should never hit this, because it means that
522                          * inodes were marked in use that weren't noticed
523                          * in pass1 or pass 2. It is easier to fix the problem
524                          * than to kill e2fsck and leave the user stuck. */
525                         if (skip_group) {
526                                 struct problem_context pctx2;
527                                 pctx2.blk = i;
528                                 pctx2.group = group;
529                                 if (fix_problem(ctx, PR_5_INODE_UNINIT,&pctx2)){
530                                         ext2fs_bg_flags_clear(fs, group, EXT2_BG_INODE_UNINIT);
531                                         skip_group = 0;
532                                 }
533                         }
534                 }
535                 if (pctx.ino == 0) {
536                         pctx.ino = pctx.ino2 = i;
537                         save_problem = problem;
538                 } else {
539                         if ((problem == save_problem) &&
540                             (pctx.ino2 == i-1))
541                                 pctx.ino2++;
542                         else {
543                                 print_bitmap_problem(ctx, save_problem, &pctx);
544                                 pctx.ino = pctx.ino2 = i;
545                                 save_problem = problem;
546                         }
547                 }
548                 ctx->flags |= E2F_FLAG_PROG_SUPPRESS;
549                 had_problem++;
550                 /*
551                  * If there a problem we should turn off the discard so we
552                  * do not compromise the filesystem.
553                  */
554                 ctx->options &= ~E2F_OPT_DISCARD;
555
556 do_counts:
557                 if (bitmap) {
558                         if (ext2fs_test_inode_bitmap2(ctx->inode_dir_map, i))
559                                 dirs_count++;
560                 } else if (!skip_group || csum_flag) {
561                         group_free++;
562                         free_inodes++;
563                 }
564
565                 inodes++;
566                 if ((inodes == fs->super->s_inodes_per_group) ||
567                     (i == fs->super->s_inodes_count)) {
568
569                         free_array[group] = group_free;
570                         dir_array[group] = dirs_count;
571
572                         /* Discard inode table */
573                         if (ctx->options & E2F_OPT_DISCARD) {
574                                 blk64_t used_blks, blk, num;
575
576                                 used_blks = DIV_ROUND_UP(
577                                         (EXT2_INODES_PER_GROUP(fs->super) -
578                                         group_free),
579                                         EXT2_INODES_PER_BLOCK(fs->super));
580
581                                 blk = ext2fs_inode_table_loc(fs, group) +
582                                       used_blks;
583                                 num = fs->inode_blocks_per_group -
584                                       used_blks;
585                                 e2fsck_discard_blocks(ctx, manager, blk, num);
586                         }
587
588                         /*
589                          * If discard zeroes data and the group inode table
590                          * was not zeroed yet, set itable as zeroed
591                          */
592                         if ((ctx->options & E2F_OPT_DISCARD) &&
593                             (io_channel_discard_zeroes_data(fs->io)) &&
594                             !(ext2fs_bg_flags_test(fs, group,
595                                                   EXT2_BG_INODE_ZEROED))) {
596                                 ext2fs_bg_flags_set(fs, group,
597                                                     EXT2_BG_INODE_ZEROED);
598                                 ext2fs_group_desc_csum_set(fs, group);
599                         }
600
601                         group ++;
602                         inodes = 0;
603                         skip_group = 0;
604                         group_free = 0;
605                         dirs_count = 0;
606                         if (ctx->progress)
607                                 if ((ctx->progress)(ctx, 5,
608                                             group + fs->group_desc_count,
609                                             fs->group_desc_count*2))
610                                         goto errout;
611                         if (csum_flag &&
612                             (i != fs->super->s_inodes_count) &&
613                             (ext2fs_bg_flags_test(fs, group, EXT2_BG_INODE_UNINIT)
614                              ))
615                                 skip_group++;
616                 }
617         }
618         if (pctx.ino)
619                 print_bitmap_problem(ctx, save_problem, &pctx);
620
621         if (had_problem)
622                 fixit = end_problem_latch(ctx, PR_LATCH_IBITMAP);
623         else
624                 fixit = -1;
625         ctx->flags &= ~E2F_FLAG_PROG_SUPPRESS;
626
627         if (fixit == 1) {
628                 ext2fs_free_inode_bitmap(fs->inode_map);
629                 retval = ext2fs_copy_bitmap(ctx->inode_used_map,
630                                                   &fs->inode_map);
631                 if (retval) {
632                         clear_problem_context(&pctx);
633                         fix_problem(ctx, PR_5_COPY_IBITMAP_ERROR, &pctx);
634                         ctx->flags |= E2F_FLAG_ABORT;
635                         goto errout;
636                 }
637                 ext2fs_set_bitmap_padding(fs->inode_map);
638                 ext2fs_mark_ib_dirty(fs);
639
640                 /* redo counts */
641                 inodes = 0; free_inodes = 0; group_free = 0;
642                 dirs_count = 0; group = 0;
643                 memset(free_array, 0, fs->group_desc_count * sizeof(int));
644                 memset(dir_array, 0, fs->group_desc_count * sizeof(int));
645                 redo_flag++;
646                 goto redo_counts;
647         } else if (fixit == 0)
648                 ext2fs_unmark_valid(fs);
649
650         for (i = 0; i < fs->group_desc_count; i++) {
651                 if (free_array[i] != ext2fs_bg_free_inodes_count(fs, i)) {
652                         pctx.group = i;
653                         pctx.ino = ext2fs_bg_free_inodes_count(fs, i);
654                         pctx.ino2 = free_array[i];
655                         if (fix_problem(ctx, PR_5_FREE_INODE_COUNT_GROUP,
656                                         &pctx)) {
657                                 ext2fs_bg_free_inodes_count_set(fs, i, free_array[i]);
658                                 ext2fs_mark_super_dirty(fs);
659                         } else
660                                 ext2fs_unmark_valid(fs);
661                 }
662                 if (dir_array[i] != ext2fs_bg_used_dirs_count(fs, i)) {
663                         pctx.group = i;
664                         pctx.ino = ext2fs_bg_used_dirs_count(fs, i);
665                         pctx.ino2 = dir_array[i];
666
667                         if (fix_problem(ctx, PR_5_FREE_DIR_COUNT_GROUP,
668                                         &pctx)) {
669                                 ext2fs_bg_used_dirs_count_set(fs, i, dir_array[i]);
670                                 ext2fs_mark_super_dirty(fs);
671                         } else
672                                 ext2fs_unmark_valid(fs);
673                 }
674         }
675         if (free_inodes != fs->super->s_free_inodes_count) {
676                 pctx.group = -1;
677                 pctx.ino = fs->super->s_free_inodes_count;
678                 pctx.ino2 = free_inodes;
679
680                 if (fix_problem(ctx, PR_5_FREE_INODE_COUNT, &pctx)) {
681                         fs->super->s_free_inodes_count = free_inodes;
682                         ext2fs_mark_super_dirty(fs);
683                 } else
684                         ext2fs_unmark_valid(fs);
685         }
686 errout:
687         ext2fs_free_mem(&free_array);
688         ext2fs_free_mem(&dir_array);
689 }
690
691 static void check_inode_end(e2fsck_t ctx)
692 {
693         ext2_filsys fs = ctx->fs;
694         ext2_ino_t      end, save_inodes_count, i;
695         struct problem_context  pctx;
696
697         clear_problem_context(&pctx);
698
699         end = EXT2_INODES_PER_GROUP(fs->super) * fs->group_desc_count;
700         pctx.errcode = ext2fs_fudge_inode_bitmap_end(fs->inode_map, end,
701                                                      &save_inodes_count);
702         if (pctx.errcode) {
703                 pctx.num = 1;
704                 fix_problem(ctx, PR_5_FUDGE_BITMAP_ERROR, &pctx);
705                 ctx->flags |= E2F_FLAG_ABORT; /* fatal */
706                 return;
707         }
708         if (save_inodes_count == end)
709                 return;
710
711         /* protect loop from wrap-around if end is maxed */
712         for (i = save_inodes_count + 1; i <= end && i > save_inodes_count; i++) {
713                 if (!ext2fs_test_inode_bitmap(fs->inode_map, i)) {
714                         if (fix_problem(ctx, PR_5_INODE_BMAP_PADDING, &pctx)) {
715                                 for (; i <= end; i++)
716                                         ext2fs_mark_inode_bitmap(fs->inode_map,
717                                                                  i);
718                                 ext2fs_mark_ib_dirty(fs);
719                         } else
720                                 ext2fs_unmark_valid(fs);
721                         break;
722                 }
723         }
724
725         pctx.errcode = ext2fs_fudge_inode_bitmap_end(fs->inode_map,
726                                                      save_inodes_count, 0);
727         if (pctx.errcode) {
728                 pctx.num = 2;
729                 fix_problem(ctx, PR_5_FUDGE_BITMAP_ERROR, &pctx);
730                 ctx->flags |= E2F_FLAG_ABORT; /* fatal */
731                 return;
732         }
733 }
734
735 static void check_block_end(e2fsck_t ctx)
736 {
737         ext2_filsys fs = ctx->fs;
738         blk64_t end, save_blocks_count, i;
739         struct problem_context  pctx;
740
741         clear_problem_context(&pctx);
742
743         end = ext2fs_get_block_bitmap_start2(fs->block_map) +
744                 ((blk64_t)EXT2_BLOCKS_PER_GROUP(fs->super) * fs->group_desc_count) - 1;
745         pctx.errcode = ext2fs_fudge_block_bitmap_end2(fs->block_map, end,
746                                                      &save_blocks_count);
747         if (pctx.errcode) {
748                 pctx.num = 3;
749                 fix_problem(ctx, PR_5_FUDGE_BITMAP_ERROR, &pctx);
750                 ctx->flags |= E2F_FLAG_ABORT; /* fatal */
751                 return;
752         }
753         if (save_blocks_count == end)
754                 return;
755
756         /* Protect loop from wrap-around if end is maxed */
757         for (i = save_blocks_count + 1; i <= end && i > save_blocks_count; i++) {
758                 if (!ext2fs_test_block_bitmap2(fs->block_map, i)) {
759                         if (fix_problem(ctx, PR_5_BLOCK_BMAP_PADDING, &pctx)) {
760                                 for (; i <= end; i++)
761                                         ext2fs_mark_block_bitmap2(fs->block_map,
762                                                                   i);
763                                 ext2fs_mark_bb_dirty(fs);
764                         } else
765                                 ext2fs_unmark_valid(fs);
766                         break;
767                 }
768         }
769
770         pctx.errcode = ext2fs_fudge_block_bitmap_end2(fs->block_map,
771                                                      save_blocks_count, 0);
772         if (pctx.errcode) {
773                 pctx.num = 4;
774                 fix_problem(ctx, PR_5_FUDGE_BITMAP_ERROR, &pctx);
775                 ctx->flags |= E2F_FLAG_ABORT; /* fatal */
776                 return;
777         }
778 }
779
780
781