Whamcloud - gitweb
b39b3134355430201f1e3555de9d943f782c8373
[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 "e2fsck.h"
14 #include "problem.h"
15
16 static void check_block_bitmaps(e2fsck_t ctx);
17 static void check_inode_bitmaps(e2fsck_t ctx);
18 static void check_inode_end(e2fsck_t ctx);
19 static void check_block_end(e2fsck_t ctx);
20
21 void e2fsck_pass5(e2fsck_t ctx)
22 {
23 #ifdef RESOURCE_TRACK
24         struct resource_track   rtrack;
25 #endif
26         struct problem_context  pctx;
27         
28 #ifdef MTRACE
29         mtrace_print("Pass 5");
30 #endif
31
32 #ifdef RESOURCE_TRACK
33         init_resource_track(&rtrack);
34 #endif
35         
36         clear_problem_context(&pctx);
37
38         if (!(ctx->options & E2F_OPT_PREEN))
39                 fix_problem(ctx, PR_5_PASS_HEADER, &pctx);
40
41         if (ctx->progress)
42                 if ((ctx->progress)(ctx, 5, 0, ctx->fs->group_desc_count*2))
43                         return;
44
45         e2fsck_read_bitmaps(ctx);
46
47         check_block_bitmaps(ctx);
48         if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
49                 return;
50         check_inode_bitmaps(ctx);
51         if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
52                 return;
53         check_inode_end(ctx);
54         if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
55                 return;
56         check_block_end(ctx);
57         if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
58                 return;
59
60         ext2fs_free_inode_bitmap(ctx->inode_used_map);
61         ctx->inode_used_map = 0;
62         ext2fs_free_inode_bitmap(ctx->inode_dir_map);
63         ctx->inode_dir_map = 0;
64         ext2fs_free_block_bitmap(ctx->block_found_map);
65         ctx->block_found_map = 0;
66
67 #ifdef RESOURCE_TRACK
68         if (ctx->options & E2F_OPT_TIME2) {
69                 e2fsck_clear_progbar(ctx);
70                 print_resource_track("Pass 5", &rtrack);
71         }
72 #endif
73 }
74
75 static void check_block_bitmaps(e2fsck_t ctx)
76 {
77         ext2_filsys fs = ctx->fs;
78         blk_t   i;
79         int     *free_array;
80         int     group = 0;
81         int     blocks = 0;
82         int     free_blocks = 0;
83         int     group_free = 0;
84         int     actual, bitmap;
85         struct problem_context  pctx;
86         int     problem, fixit, had_problem;
87         errcode_t       retval;
88         
89         clear_problem_context(&pctx);
90         free_array = (int *) e2fsck_allocate_memory(ctx,
91             fs->group_desc_count * sizeof(int), "free block count array");
92
93         if ((fs->super->s_first_data_block <
94              ext2fs_get_block_bitmap_start(ctx->block_found_map)) ||
95             (fs->super->s_blocks_count-1 >
96              ext2fs_get_block_bitmap_end(ctx->block_found_map))) {
97                 pctx.num = 1;
98                 pctx.blk = fs->super->s_first_data_block;
99                 pctx.blk2 = fs->super->s_blocks_count -1;
100                 pctx.ino = ext2fs_get_block_bitmap_start(ctx->block_found_map);
101                 pctx.ino2 = ext2fs_get_block_bitmap_end(ctx->block_found_map);
102                 fix_problem(ctx, PR_5_BMAP_ENDPOINTS, &pctx);
103
104                 ctx->flags |= E2F_FLAG_ABORT; /* fatal */
105                 return;
106         }
107                        
108         if ((fs->super->s_first_data_block <
109              ext2fs_get_block_bitmap_start(fs->block_map)) ||
110             (fs->super->s_blocks_count-1 >
111              ext2fs_get_block_bitmap_end(fs->block_map))) {
112                 pctx.num = 2;
113                 pctx.blk = fs->super->s_first_data_block;
114                 pctx.blk2 = fs->super->s_blocks_count -1;
115                 pctx.ino = ext2fs_get_block_bitmap_start(fs->block_map);
116                 pctx.ino2 = ext2fs_get_block_bitmap_end(fs->block_map);
117                 fix_problem(ctx, PR_5_BMAP_ENDPOINTS, &pctx);
118
119                 ctx->flags |= E2F_FLAG_ABORT; /* fatal */
120                 return;
121         }
122                        
123 redo_counts:
124         had_problem = 0;
125         for (i = fs->super->s_first_data_block;
126              i < fs->super->s_blocks_count;
127              i++) {
128                 actual = ext2fs_fast_test_block_bitmap(ctx->block_found_map, i);
129                 bitmap = ext2fs_fast_test_block_bitmap(fs->block_map, i);
130                 
131                 if (actual == bitmap)
132                         goto do_counts;
133                 
134                 if (!actual && bitmap) {
135                         /*
136                          * Block not used, but marked in use in the bitmap.
137                          */
138                         problem = PR_5_UNUSED_BLOCK;
139                 } else {
140                         /*
141                          * Block used, but not marked in use in the bitmap.
142                          */
143                         problem = PR_5_BLOCK_USED;
144                 }
145                 pctx.blk = i;
146                 fix_problem(ctx, problem, &pctx);
147                 ctx->flags |= E2F_FLAG_PROG_SUPPRESS;
148                 had_problem++;
149                 
150         do_counts:
151                 if (!bitmap) {
152                         group_free++;
153                         free_blocks++;
154                 }
155                 blocks ++;
156                 if ((blocks == fs->super->s_blocks_per_group) ||
157                     (i == fs->super->s_blocks_count-1)) {
158                         free_array[group] = group_free;
159                         group ++;
160                         blocks = 0;
161                         group_free = 0;
162                         if (ctx->progress)
163                                 if ((ctx->progress)(ctx, 5, group,
164                                                     fs->group_desc_count*2))
165                                         return;
166                 }
167         }
168         if (had_problem)
169                 fixit = end_problem_latch(ctx,  PR_LATCH_BBITMAP);
170         else
171                 fixit = -1;
172         ctx->flags &= ~E2F_FLAG_PROG_SUPPRESS;
173         
174         if (fixit == 1) {
175                 ext2fs_free_block_bitmap(fs->block_map);
176                 retval = ext2fs_copy_bitmap(ctx->block_found_map,
177                                                   &fs->block_map);
178                 /* XXX check retval --- should never fail! */
179                 ext2fs_set_bitmap_padding(fs->block_map);
180                 ext2fs_mark_bb_dirty(fs);
181                 
182                 /* Redo the counts */
183                 blocks = 0; free_blocks = 0; group_free = 0; group = 0;
184                 memset(free_array, 0, fs->group_desc_count * sizeof(int));
185                 goto redo_counts;
186         } else if (fixit == 0)
187                 ext2fs_unmark_valid(fs);
188
189         for (i = 0; i < fs->group_desc_count; i++) {
190                 if (free_array[i] != fs->group_desc[i].bg_free_blocks_count) {
191                         pctx.group = i;
192                         pctx.blk = fs->group_desc[i].bg_free_blocks_count;
193                         pctx.blk2 = free_array[i];
194
195                         if (fix_problem(ctx, PR_5_FREE_BLOCK_COUNT_GROUP,
196                                         &pctx)) {
197                                 fs->group_desc[i].bg_free_blocks_count =
198                                         free_array[i];
199                                 ext2fs_mark_super_dirty(fs);
200                         } else
201                                 ext2fs_unmark_valid(fs);
202                 }
203         }
204         if (free_blocks != fs->super->s_free_blocks_count) {
205                 pctx.group = 0;
206                 pctx.blk = fs->super->s_free_blocks_count;
207                 pctx.blk2 = free_blocks;
208
209                 if (fix_problem(ctx, PR_5_FREE_BLOCK_COUNT, &pctx)) {
210                         fs->super->s_free_blocks_count = free_blocks;
211                         ext2fs_mark_super_dirty(fs);
212                 } else
213                         ext2fs_unmark_valid(fs);
214         }
215         ext2fs_free_mem((void **) &free_array);
216 }
217                         
218 static void check_inode_bitmaps(e2fsck_t ctx)
219 {
220         ext2_filsys fs = ctx->fs;
221         ino_t   i;
222         int     free_inodes = 0;
223         int     group_free = 0;
224         int     dirs_count = 0;
225         int     group = 0;
226         int     inodes = 0;
227         int     *free_array;
228         int     *dir_array;
229         int     actual, bitmap;
230         errcode_t       retval;
231         struct problem_context  pctx;
232         int     problem, fixit, had_problem;
233         
234         clear_problem_context(&pctx);
235         free_array = (int *) e2fsck_allocate_memory(ctx,
236             fs->group_desc_count * sizeof(int), "free inode count array");
237                                      
238         dir_array = (int *) e2fsck_allocate_memory(ctx,
239            fs->group_desc_count * sizeof(int), "directory count array");
240                                      
241         if ((1 < ext2fs_get_inode_bitmap_start(ctx->inode_used_map)) ||
242             (fs->super->s_inodes_count > 
243              ext2fs_get_inode_bitmap_end(ctx->inode_used_map))) {
244                 pctx.num = 3;
245                 pctx.blk = 1;
246                 pctx.blk2 = fs->super->s_inodes_count;
247                 pctx.ino = ext2fs_get_inode_bitmap_start(ctx->inode_used_map);
248                 pctx.ino2 = ext2fs_get_inode_bitmap_end(ctx->inode_used_map);
249                 fix_problem(ctx, PR_5_BMAP_ENDPOINTS, &pctx);
250
251                 ctx->flags |= E2F_FLAG_ABORT; /* fatal */
252                 return;
253         }
254         if ((1 < ext2fs_get_inode_bitmap_start(fs->inode_map)) ||
255             (fs->super->s_inodes_count > 
256              ext2fs_get_inode_bitmap_end(fs->inode_map))) {
257                 pctx.num = 4;
258                 pctx.blk = 1;
259                 pctx.blk2 = fs->super->s_inodes_count;
260                 pctx.ino = ext2fs_get_inode_bitmap_start(fs->inode_map);
261                 pctx.ino2 = ext2fs_get_inode_bitmap_end(fs->inode_map);
262                 fix_problem(ctx, PR_5_BMAP_ENDPOINTS, &pctx);
263
264                 ctx->flags |= E2F_FLAG_ABORT; /* fatal */
265                 return;
266         }
267
268 redo_counts:
269         had_problem = 0;
270         for (i = 1; i <= fs->super->s_inodes_count; i++) {
271                 actual = ext2fs_fast_test_inode_bitmap(ctx->inode_used_map, i);
272                 bitmap = ext2fs_fast_test_inode_bitmap(fs->inode_map, i);
273                 
274                 if (actual == bitmap)
275                         goto do_counts;
276                 
277                 if (!actual && bitmap) {
278                         /*
279                          * Inode wasn't used, but marked in bitmap
280                          */
281                         problem = PR_5_UNUSED_INODE;
282                 } else /* if (actual && !bitmap) */ {
283                         /*
284                          * Inode used, but not in bitmap
285                          */
286                         problem = PR_5_INODE_USED;
287                 }
288                 pctx.ino = i;
289                 fix_problem(ctx, problem, &pctx);
290                 ctx->flags |= E2F_FLAG_PROG_SUPPRESS;
291                 had_problem++;
292                 
293 do_counts:
294                 if (!bitmap) {
295                         group_free++;
296                         free_inodes++;
297                 } else {
298                         if (ext2fs_test_inode_bitmap(ctx->inode_dir_map, i))
299                                 dirs_count++;
300                 }
301                 inodes++;
302                 if ((inodes == fs->super->s_inodes_per_group) ||
303                     (i == fs->super->s_inodes_count)) {
304                         free_array[group] = group_free;
305                         dir_array[group] = dirs_count;
306                         group ++;
307                         inodes = 0;
308                         group_free = 0;
309                         dirs_count = 0;
310                         if (ctx->progress)
311                                 if ((ctx->progress)(ctx, 5,
312                                             group + fs->group_desc_count,
313                                             fs->group_desc_count*2))
314                                         return;
315                 }
316         }
317         if (had_problem)
318                 fixit = end_problem_latch(ctx, PR_LATCH_IBITMAP);
319         else
320                 fixit = -1;
321         ctx->flags &= ~E2F_FLAG_PROG_SUPPRESS;
322         
323         if (fixit == 1) {
324                 ext2fs_free_inode_bitmap(fs->inode_map);
325                 retval = ext2fs_copy_bitmap(ctx->inode_used_map,
326                                                   &fs->inode_map);
327                 /* XXX check retval --- should never fail! */
328                 ext2fs_set_bitmap_padding(fs->inode_map);
329                 ext2fs_mark_ib_dirty(fs);
330
331                 /* redo counts */
332                 inodes = 0; free_inodes = 0; group_free = 0;
333                 dirs_count = 0; group = 0;
334                 memset(free_array, 0, fs->group_desc_count * sizeof(int));
335                 memset(dir_array, 0, fs->group_desc_count * sizeof(int));
336                 goto redo_counts;
337         } else if (fixit == 0)
338                 ext2fs_unmark_valid(fs);
339         
340         for (i = 0; i < fs->group_desc_count; i++) {
341                 if (free_array[i] != fs->group_desc[i].bg_free_inodes_count) {
342                         pctx.group = i;
343                         pctx.ino = fs->group_desc[i].bg_free_inodes_count;
344                         pctx.ino2 = free_array[i];
345                         if (fix_problem(ctx, PR_5_FREE_INODE_COUNT_GROUP,
346                                         &pctx)) {
347                                 fs->group_desc[i].bg_free_inodes_count =
348                                         free_array[i];
349                                 ext2fs_mark_super_dirty(fs);
350                         } else
351                                 ext2fs_unmark_valid(fs);
352                 }
353                 if (dir_array[i] != fs->group_desc[i].bg_used_dirs_count) {
354                         pctx.group = i;
355                         pctx.ino = fs->group_desc[i].bg_used_dirs_count;
356                         pctx.ino2 = dir_array[i];
357
358                         if (fix_problem(ctx, PR_5_FREE_DIR_COUNT_GROUP,
359                                         &pctx)) {
360                                 fs->group_desc[i].bg_used_dirs_count =
361                                         dir_array[i];
362                                 ext2fs_mark_super_dirty(fs);
363                         } else
364                                 ext2fs_unmark_valid(fs);
365                 }
366         }
367         if (free_inodes != fs->super->s_free_inodes_count) {
368                 pctx.group = -1;
369                 pctx.ino = fs->super->s_free_inodes_count;
370                 pctx.ino2 = free_inodes;
371
372                 if (fix_problem(ctx, PR_5_FREE_INODE_COUNT, &pctx)) {
373                         fs->super->s_free_inodes_count = free_inodes;
374                         ext2fs_mark_super_dirty(fs);
375                 } else
376                         ext2fs_unmark_valid(fs);
377         }
378         ext2fs_free_mem((void **) &free_array);
379         ext2fs_free_mem((void **) &dir_array);
380 }
381
382 static void check_inode_end(e2fsck_t ctx)
383 {
384         ext2_filsys fs = ctx->fs;
385         ino_t   end, save_inodes_count, i;
386         struct problem_context  pctx;
387
388         clear_problem_context(&pctx);
389
390         end = EXT2_INODES_PER_GROUP(fs->super) * fs->group_desc_count;
391         pctx.errcode = ext2fs_fudge_inode_bitmap_end(fs->inode_map, end,
392                                                      &save_inodes_count);
393         if (pctx.errcode) {
394                 pctx.num = 1;
395                 fix_problem(ctx, PR_5_FUDGE_BITMAP_ERROR, &pctx);
396                 ctx->flags |= E2F_FLAG_ABORT; /* fatal */
397                 return;
398         }
399         if (save_inodes_count == end)
400                 return;
401         
402         for (i = save_inodes_count + 1; i <= end; i++) {
403                 if (!ext2fs_test_inode_bitmap(fs->inode_map, i)) {
404                         if (fix_problem(ctx, PR_5_INODE_BMAP_PADDING, &pctx)) {
405                                 for (i = save_inodes_count + 1; i <= end; i++)
406                                         ext2fs_mark_inode_bitmap(fs->inode_map,
407                                                                  i);
408                                 ext2fs_mark_ib_dirty(fs);
409                         } else
410                                 ext2fs_unmark_valid(fs);
411                         break;
412                 }
413         }
414
415         pctx.errcode = ext2fs_fudge_inode_bitmap_end(fs->inode_map,
416                                                      save_inodes_count, 0);
417         if (pctx.errcode) {
418                 pctx.num = 2;
419                 fix_problem(ctx, PR_5_FUDGE_BITMAP_ERROR, &pctx);
420                 ctx->flags |= E2F_FLAG_ABORT; /* fatal */
421                 return;
422         }
423 }
424
425 static void check_block_end(e2fsck_t ctx)
426 {
427         ext2_filsys fs = ctx->fs;
428         blk_t   end, save_blocks_count, i;
429         struct problem_context  pctx;
430
431         clear_problem_context(&pctx);
432
433         end = fs->block_map->start +
434                 (EXT2_BLOCKS_PER_GROUP(fs->super) * fs->group_desc_count) - 1;
435         pctx.errcode = ext2fs_fudge_block_bitmap_end(fs->block_map, end,
436                                                      &save_blocks_count);
437         if (pctx.errcode) {
438                 pctx.num = 3;
439                 fix_problem(ctx, PR_5_FUDGE_BITMAP_ERROR, &pctx);
440                 ctx->flags |= E2F_FLAG_ABORT; /* fatal */
441                 return;
442         }
443         if (save_blocks_count == end)
444                 return;
445         
446         for (i = save_blocks_count + 1; i <= end; i++) {
447                 if (!ext2fs_test_block_bitmap(fs->block_map, i)) {
448                         if (fix_problem(ctx, PR_5_BLOCK_BMAP_PADDING, &pctx)) {
449                                 for (i = save_blocks_count + 1; i <= end; i++)
450                                         ext2fs_mark_block_bitmap(fs->block_map,
451                                                                  i);
452                                 ext2fs_mark_bb_dirty(fs);
453                         } else
454                                 ext2fs_unmark_valid(fs);
455                         break;
456                 }
457         }
458
459         pctx.errcode = ext2fs_fudge_block_bitmap_end(fs->block_map,
460                                                      save_blocks_count, 0);
461         if (pctx.errcode) {
462                 pctx.num = 4;
463                 fix_problem(ctx, PR_5_FUDGE_BITMAP_ERROR, &pctx);
464                 ctx->flags |= E2F_FLAG_ABORT; /* fatal */
465                 return;
466         }
467 }
468
469
470