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