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