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