Whamcloud - gitweb
Many files:
[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                 if (retval) {
179                         clear_problem_context(&pctx);
180                         fix_problem(ctx, PR_5_COPY_BBITMAP_ERROR, &pctx);
181                         ctx->flags |= E2F_FLAG_ABORT;
182                         return;
183                 }
184                 ext2fs_set_bitmap_padding(fs->block_map);
185                 ext2fs_mark_bb_dirty(fs);
186                 
187                 /* Redo the counts */
188                 blocks = 0; free_blocks = 0; group_free = 0; group = 0;
189                 memset(free_array, 0, fs->group_desc_count * sizeof(int));
190                 goto redo_counts;
191         } else if (fixit == 0)
192                 ext2fs_unmark_valid(fs);
193
194         for (i = 0; i < fs->group_desc_count; i++) {
195                 if (free_array[i] != fs->group_desc[i].bg_free_blocks_count) {
196                         pctx.group = i;
197                         pctx.blk = fs->group_desc[i].bg_free_blocks_count;
198                         pctx.blk2 = free_array[i];
199
200                         if (fix_problem(ctx, PR_5_FREE_BLOCK_COUNT_GROUP,
201                                         &pctx)) {
202                                 fs->group_desc[i].bg_free_blocks_count =
203                                         free_array[i];
204                                 ext2fs_mark_super_dirty(fs);
205                         } else
206                                 ext2fs_unmark_valid(fs);
207                 }
208         }
209         if (free_blocks != fs->super->s_free_blocks_count) {
210                 pctx.group = 0;
211                 pctx.blk = fs->super->s_free_blocks_count;
212                 pctx.blk2 = free_blocks;
213
214                 if (fix_problem(ctx, PR_5_FREE_BLOCK_COUNT, &pctx)) {
215                         fs->super->s_free_blocks_count = free_blocks;
216                         ext2fs_mark_super_dirty(fs);
217                 } else
218                         ext2fs_unmark_valid(fs);
219         }
220         ext2fs_free_mem((void **) &free_array);
221 }
222                         
223 static void check_inode_bitmaps(e2fsck_t ctx)
224 {
225         ext2_filsys fs = ctx->fs;
226         ext2_ino_t      i;
227         int     free_inodes = 0;
228         int     group_free = 0;
229         int     dirs_count = 0;
230         int     group = 0;
231         int     inodes = 0;
232         int     *free_array;
233         int     *dir_array;
234         int     actual, bitmap;
235         errcode_t       retval;
236         struct problem_context  pctx;
237         int     problem, fixit, had_problem;
238         
239         clear_problem_context(&pctx);
240         free_array = (int *) e2fsck_allocate_memory(ctx,
241             fs->group_desc_count * sizeof(int), "free inode count array");
242                                      
243         dir_array = (int *) e2fsck_allocate_memory(ctx,
244            fs->group_desc_count * sizeof(int), "directory count array");
245                                      
246         if ((1 < ext2fs_get_inode_bitmap_start(ctx->inode_used_map)) ||
247             (fs->super->s_inodes_count > 
248              ext2fs_get_inode_bitmap_end(ctx->inode_used_map))) {
249                 pctx.num = 3;
250                 pctx.blk = 1;
251                 pctx.blk2 = fs->super->s_inodes_count;
252                 pctx.ino = ext2fs_get_inode_bitmap_start(ctx->inode_used_map);
253                 pctx.ino2 = ext2fs_get_inode_bitmap_end(ctx->inode_used_map);
254                 fix_problem(ctx, PR_5_BMAP_ENDPOINTS, &pctx);
255
256                 ctx->flags |= E2F_FLAG_ABORT; /* fatal */
257                 return;
258         }
259         if ((1 < ext2fs_get_inode_bitmap_start(fs->inode_map)) ||
260             (fs->super->s_inodes_count > 
261              ext2fs_get_inode_bitmap_end(fs->inode_map))) {
262                 pctx.num = 4;
263                 pctx.blk = 1;
264                 pctx.blk2 = fs->super->s_inodes_count;
265                 pctx.ino = ext2fs_get_inode_bitmap_start(fs->inode_map);
266                 pctx.ino2 = ext2fs_get_inode_bitmap_end(fs->inode_map);
267                 fix_problem(ctx, PR_5_BMAP_ENDPOINTS, &pctx);
268
269                 ctx->flags |= E2F_FLAG_ABORT; /* fatal */
270                 return;
271         }
272
273 redo_counts:
274         had_problem = 0;
275         for (i = 1; i <= fs->super->s_inodes_count; i++) {
276                 actual = ext2fs_fast_test_inode_bitmap(ctx->inode_used_map, i);
277                 bitmap = ext2fs_fast_test_inode_bitmap(fs->inode_map, i);
278                 
279                 if (actual == bitmap)
280                         goto do_counts;
281                 
282                 if (!actual && bitmap) {
283                         /*
284                          * Inode wasn't used, but marked in bitmap
285                          */
286                         problem = PR_5_UNUSED_INODE;
287                 } else /* if (actual && !bitmap) */ {
288                         /*
289                          * Inode used, but not in bitmap
290                          */
291                         problem = PR_5_INODE_USED;
292                 }
293                 pctx.ino = i;
294                 fix_problem(ctx, problem, &pctx);
295                 ctx->flags |= E2F_FLAG_PROG_SUPPRESS;
296                 had_problem++;
297                 
298 do_counts:
299                 if (!bitmap) {
300                         group_free++;
301                         free_inodes++;
302                 } else {
303                         if (ext2fs_test_inode_bitmap(ctx->inode_dir_map, i))
304                                 dirs_count++;
305                 }
306                 inodes++;
307                 if ((inodes == fs->super->s_inodes_per_group) ||
308                     (i == fs->super->s_inodes_count)) {
309                         free_array[group] = group_free;
310                         dir_array[group] = dirs_count;
311                         group ++;
312                         inodes = 0;
313                         group_free = 0;
314                         dirs_count = 0;
315                         if (ctx->progress)
316                                 if ((ctx->progress)(ctx, 5,
317                                             group + fs->group_desc_count,
318                                             fs->group_desc_count*2))
319                                         return;
320                 }
321         }
322         if (had_problem)
323                 fixit = end_problem_latch(ctx, PR_LATCH_IBITMAP);
324         else
325                 fixit = -1;
326         ctx->flags &= ~E2F_FLAG_PROG_SUPPRESS;
327         
328         if (fixit == 1) {
329                 ext2fs_free_inode_bitmap(fs->inode_map);
330                 retval = ext2fs_copy_bitmap(ctx->inode_used_map,
331                                                   &fs->inode_map);
332                 if (retval) {
333                         clear_problem_context(&pctx);
334                         fix_problem(ctx, PR_5_COPY_IBITMAP_ERROR, &pctx);
335                         ctx->flags |= E2F_FLAG_ABORT;
336                         return;
337                 }
338                 ext2fs_set_bitmap_padding(fs->inode_map);
339                 ext2fs_mark_ib_dirty(fs);
340
341                 /* redo counts */
342                 inodes = 0; free_inodes = 0; group_free = 0;
343                 dirs_count = 0; group = 0;
344                 memset(free_array, 0, fs->group_desc_count * sizeof(int));
345                 memset(dir_array, 0, fs->group_desc_count * sizeof(int));
346                 goto redo_counts;
347         } else if (fixit == 0)
348                 ext2fs_unmark_valid(fs);
349         
350         for (i = 0; i < fs->group_desc_count; i++) {
351                 if (free_array[i] != fs->group_desc[i].bg_free_inodes_count) {
352                         pctx.group = i;
353                         pctx.ino = fs->group_desc[i].bg_free_inodes_count;
354                         pctx.ino2 = free_array[i];
355                         if (fix_problem(ctx, PR_5_FREE_INODE_COUNT_GROUP,
356                                         &pctx)) {
357                                 fs->group_desc[i].bg_free_inodes_count =
358                                         free_array[i];
359                                 ext2fs_mark_super_dirty(fs);
360                         } else
361                                 ext2fs_unmark_valid(fs);
362                 }
363                 if (dir_array[i] != fs->group_desc[i].bg_used_dirs_count) {
364                         pctx.group = i;
365                         pctx.ino = fs->group_desc[i].bg_used_dirs_count;
366                         pctx.ino2 = dir_array[i];
367
368                         if (fix_problem(ctx, PR_5_FREE_DIR_COUNT_GROUP,
369                                         &pctx)) {
370                                 fs->group_desc[i].bg_used_dirs_count =
371                                         dir_array[i];
372                                 ext2fs_mark_super_dirty(fs);
373                         } else
374                                 ext2fs_unmark_valid(fs);
375                 }
376         }
377         if (free_inodes != fs->super->s_free_inodes_count) {
378                 pctx.group = -1;
379                 pctx.ino = fs->super->s_free_inodes_count;
380                 pctx.ino2 = free_inodes;
381
382                 if (fix_problem(ctx, PR_5_FREE_INODE_COUNT, &pctx)) {
383                         fs->super->s_free_inodes_count = free_inodes;
384                         ext2fs_mark_super_dirty(fs);
385                 } else
386                         ext2fs_unmark_valid(fs);
387         }
388         ext2fs_free_mem((void **) &free_array);
389         ext2fs_free_mem((void **) &dir_array);
390 }
391
392 static void check_inode_end(e2fsck_t ctx)
393 {
394         ext2_filsys fs = ctx->fs;
395         ext2_ino_t      end, save_inodes_count, i;
396         struct problem_context  pctx;
397
398         clear_problem_context(&pctx);
399
400         end = EXT2_INODES_PER_GROUP(fs->super) * fs->group_desc_count;
401         pctx.errcode = ext2fs_fudge_inode_bitmap_end(fs->inode_map, end,
402                                                      &save_inodes_count);
403         if (pctx.errcode) {
404                 pctx.num = 1;
405                 fix_problem(ctx, PR_5_FUDGE_BITMAP_ERROR, &pctx);
406                 ctx->flags |= E2F_FLAG_ABORT; /* fatal */
407                 return;
408         }
409         if (save_inodes_count == end)
410                 return;
411         
412         for (i = save_inodes_count + 1; i <= end; i++) {
413                 if (!ext2fs_test_inode_bitmap(fs->inode_map, i)) {
414                         if (fix_problem(ctx, PR_5_INODE_BMAP_PADDING, &pctx)) {
415                                 for (i = save_inodes_count + 1; i <= end; i++)
416                                         ext2fs_mark_inode_bitmap(fs->inode_map,
417                                                                  i);
418                                 ext2fs_mark_ib_dirty(fs);
419                         } else
420                                 ext2fs_unmark_valid(fs);
421                         break;
422                 }
423         }
424
425         pctx.errcode = ext2fs_fudge_inode_bitmap_end(fs->inode_map,
426                                                      save_inodes_count, 0);
427         if (pctx.errcode) {
428                 pctx.num = 2;
429                 fix_problem(ctx, PR_5_FUDGE_BITMAP_ERROR, &pctx);
430                 ctx->flags |= E2F_FLAG_ABORT; /* fatal */
431                 return;
432         }
433 }
434
435 static void check_block_end(e2fsck_t ctx)
436 {
437         ext2_filsys fs = ctx->fs;
438         blk_t   end, save_blocks_count, i;
439         struct problem_context  pctx;
440
441         clear_problem_context(&pctx);
442
443         end = fs->block_map->start +
444                 (EXT2_BLOCKS_PER_GROUP(fs->super) * fs->group_desc_count) - 1;
445         pctx.errcode = ext2fs_fudge_block_bitmap_end(fs->block_map, end,
446                                                      &save_blocks_count);
447         if (pctx.errcode) {
448                 pctx.num = 3;
449                 fix_problem(ctx, PR_5_FUDGE_BITMAP_ERROR, &pctx);
450                 ctx->flags |= E2F_FLAG_ABORT; /* fatal */
451                 return;
452         }
453         if (save_blocks_count == end)
454                 return;
455         
456         for (i = save_blocks_count + 1; i <= end; i++) {
457                 if (!ext2fs_test_block_bitmap(fs->block_map, i)) {
458                         if (fix_problem(ctx, PR_5_BLOCK_BMAP_PADDING, &pctx)) {
459                                 for (i = save_blocks_count + 1; i <= end; i++)
460                                         ext2fs_mark_block_bitmap(fs->block_map,
461                                                                  i);
462                                 ext2fs_mark_bb_dirty(fs);
463                         } else
464                                 ext2fs_unmark_valid(fs);
465                         break;
466                 }
467         }
468
469         pctx.errcode = ext2fs_fudge_block_bitmap_end(fs->block_map,
470                                                      save_blocks_count, 0);
471         if (pctx.errcode) {
472                 pctx.num = 4;
473                 fix_problem(ctx, PR_5_FUDGE_BITMAP_ERROR, &pctx);
474                 ctx->flags |= E2F_FLAG_ABORT; /* fatal */
475                 return;
476         }
477 }
478
479
480