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