]>
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 | ||
d1154eb4 | 13 | #include "config.h" |
efa1a355 LC |
14 | #include <stdint.h> |
15 | #include <sys/types.h> | |
16 | #include <sys/stat.h> | |
17 | #include <sys/ioctl.h> | |
18 | #include <fcntl.h> | |
19 | #include <errno.h> | |
20 | ||
3839e657 | 21 | #include "e2fsck.h" |
1b6bf175 | 22 | #include "problem.h" |
3839e657 | 23 | |
efa1a355 LC |
24 | #define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d)) |
25 | ||
1b6bf175 TT |
26 | static void check_block_bitmaps(e2fsck_t ctx); |
27 | static void check_inode_bitmaps(e2fsck_t ctx); | |
28 | static void check_inode_end(e2fsck_t ctx); | |
29 | static void check_block_end(e2fsck_t ctx); | |
11ac780e | 30 | static void check_inode_bitmap_checksum(e2fsck_t ctx); |
da670fe0 | 31 | static void check_block_bitmap_checksum(e2fsck_t ctx); |
3839e657 | 32 | |
08b21301 | 33 | void e2fsck_pass5(e2fsck_t ctx) |
3839e657 | 34 | { |
8bf191e8 | 35 | #ifdef RESOURCE_TRACK |
3839e657 | 36 | struct resource_track rtrack; |
8bf191e8 | 37 | #endif |
1b6bf175 | 38 | struct problem_context pctx; |
efc6f628 | 39 | |
3839e657 TT |
40 | #ifdef MTRACE |
41 | mtrace_print("Pass 5"); | |
42 | #endif | |
43 | ||
6d96b00d | 44 | init_resource_track(&rtrack, ctx->fs->io); |
1b6bf175 | 45 | clear_problem_context(&pctx); |
3839e657 | 46 | |
1b6bf175 TT |
47 | if (!(ctx->options & E2F_OPT_PREEN)) |
48 | fix_problem(ctx, PR_5_PASS_HEADER, &pctx); | |
3839e657 | 49 | |
f8188fff | 50 | if (ctx->progress) |
efac9a1b | 51 | if ((ctx->progress)(ctx, 5, 0, ctx->fs->group_desc_count*2)) |
a02ce9df | 52 | return; |
f8188fff TT |
53 | |
54 | e2fsck_read_bitmaps(ctx); | |
55 | ||
1b6bf175 | 56 | check_block_bitmaps(ctx); |
a02ce9df | 57 | if (ctx->flags & E2F_FLAG_SIGNAL_MASK) |
08b21301 | 58 | return; |
1b6bf175 | 59 | check_inode_bitmaps(ctx); |
a02ce9df | 60 | if (ctx->flags & E2F_FLAG_SIGNAL_MASK) |
08b21301 | 61 | return; |
1b6bf175 | 62 | check_inode_end(ctx); |
a02ce9df | 63 | if (ctx->flags & E2F_FLAG_SIGNAL_MASK) |
08b21301 | 64 | return; |
1b6bf175 | 65 | check_block_end(ctx); |
a02ce9df | 66 | if (ctx->flags & E2F_FLAG_SIGNAL_MASK) |
08b21301 | 67 | return; |
3839e657 | 68 | |
11ac780e | 69 | check_inode_bitmap_checksum(ctx); |
da670fe0 | 70 | check_block_bitmap_checksum(ctx); |
11ac780e | 71 | |
1b6bf175 TT |
72 | ext2fs_free_inode_bitmap(ctx->inode_used_map); |
73 | ctx->inode_used_map = 0; | |
74 | ext2fs_free_inode_bitmap(ctx->inode_dir_map); | |
75 | ctx->inode_dir_map = 0; | |
76 | ext2fs_free_block_bitmap(ctx->block_found_map); | |
77 | ctx->block_found_map = 0; | |
35c8faaf DW |
78 | ext2fs_free_block_bitmap(ctx->block_metadata_map); |
79 | ctx->block_metadata_map = 0; | |
1b6bf175 | 80 | |
9facd076 | 81 | print_resource_track(ctx, _("Pass 5"), &rtrack, ctx->fs->io); |
3839e657 TT |
82 | } |
83 | ||
11ac780e DW |
84 | static void check_inode_bitmap_checksum(e2fsck_t ctx) |
85 | { | |
86 | struct problem_context pctx; | |
b9b76868 | 87 | char *buf = NULL; |
11ac780e DW |
88 | dgrp_t i; |
89 | int nbytes; | |
90 | ext2_ino_t ino_itr; | |
91 | errcode_t retval; | |
92 | ||
86f3b6cf | 93 | if (!ext2fs_has_feature_metadata_csum(ctx->fs->super)) |
11ac780e DW |
94 | return; |
95 | ||
96 | /* If bitmap is dirty from being fixed, checksum will be corrected */ | |
97 | if (ext2fs_test_ib_dirty(ctx->fs)) | |
98 | return; | |
99 | ||
100 | nbytes = (size_t)(EXT2_INODES_PER_GROUP(ctx->fs->super) / 8); | |
755a6083 | 101 | retval = ext2fs_get_mem(ctx->fs->blocksize, &buf); |
11ac780e | 102 | if (retval) { |
bbccc6f3 | 103 | com_err(ctx->program_name, 0, "%s", |
11ac780e DW |
104 | _("check_inode_bitmap_checksum: Memory allocation error")); |
105 | fatal_error(ctx, 0); | |
106 | } | |
107 | ||
108 | clear_problem_context(&pctx); | |
109 | for (i = 0; i < ctx->fs->group_desc_count; i++) { | |
110 | if (ext2fs_bg_flags_test(ctx->fs, i, EXT2_BG_INODE_UNINIT)) | |
111 | continue; | |
112 | ||
113 | ino_itr = 1 + (i * (nbytes << 3)); | |
11ac780e DW |
114 | retval = ext2fs_get_inode_bitmap_range2(ctx->fs->inode_map, |
115 | ino_itr, nbytes << 3, | |
116 | buf); | |
117 | if (retval) | |
118 | break; | |
119 | ||
120 | if (ext2fs_inode_bitmap_csum_verify(ctx->fs, i, buf, nbytes)) | |
121 | continue; | |
122 | pctx.group = i; | |
123 | if (!fix_problem(ctx, PR_5_INODE_BITMAP_CSUM_INVALID, &pctx)) | |
124 | continue; | |
125 | ||
126 | /* | |
127 | * Fixing one checksum will rewrite all of them. The bitmap | |
128 | * will be checked against the one we made during pass1 for | |
129 | * discrepancies, and fixed if need be. | |
130 | */ | |
131 | ext2fs_mark_ib_dirty(ctx->fs); | |
132 | break; | |
133 | } | |
134 | ||
135 | ext2fs_free_mem(&buf); | |
136 | } | |
137 | ||
da670fe0 DW |
138 | static void check_block_bitmap_checksum(e2fsck_t ctx) |
139 | { | |
140 | struct problem_context pctx; | |
b9b76868 | 141 | char *buf = NULL; |
da670fe0 DW |
142 | dgrp_t i; |
143 | int nbytes; | |
144 | blk64_t blk_itr; | |
145 | errcode_t retval; | |
146 | ||
86f3b6cf | 147 | if (!ext2fs_has_feature_metadata_csum(ctx->fs->super)) |
da670fe0 DW |
148 | return; |
149 | ||
150 | /* If bitmap is dirty from being fixed, checksum will be corrected */ | |
151 | if (ext2fs_test_bb_dirty(ctx->fs)) | |
152 | return; | |
153 | ||
154 | nbytes = (size_t)(EXT2_CLUSTERS_PER_GROUP(ctx->fs->super) / 8); | |
755a6083 | 155 | retval = ext2fs_get_mem(ctx->fs->blocksize, &buf); |
da670fe0 | 156 | if (retval) { |
bbccc6f3 | 157 | com_err(ctx->program_name, 0, "%s", |
da670fe0 DW |
158 | _("check_block_bitmap_checksum: Memory allocation error")); |
159 | fatal_error(ctx, 0); | |
160 | } | |
161 | ||
162 | clear_problem_context(&pctx); | |
163 | for (i = 0; i < ctx->fs->group_desc_count; i++) { | |
164 | if (ext2fs_bg_flags_test(ctx->fs, i, EXT2_BG_BLOCK_UNINIT)) | |
165 | continue; | |
166 | ||
167 | blk_itr = EXT2FS_B2C(ctx->fs, | |
168 | ctx->fs->super->s_first_data_block) + | |
2db19bce | 169 | ((blk64_t) i * (nbytes << 3)); |
da670fe0 DW |
170 | retval = ext2fs_get_block_bitmap_range2(ctx->fs->block_map, |
171 | blk_itr, nbytes << 3, | |
172 | buf); | |
173 | if (retval) | |
174 | break; | |
175 | ||
176 | if (ext2fs_block_bitmap_csum_verify(ctx->fs, i, buf, nbytes)) | |
177 | continue; | |
178 | pctx.group = i; | |
179 | if (!fix_problem(ctx, PR_5_BLOCK_BITMAP_CSUM_INVALID, &pctx)) | |
180 | continue; | |
181 | ||
182 | /* | |
183 | * Fixing one checksum will rewrite all of them. The bitmap | |
184 | * will be checked against the one we made during pass1 for | |
185 | * discrepancies, and fixed if need be. | |
186 | */ | |
187 | ext2fs_mark_bb_dirty(ctx->fs); | |
188 | break; | |
189 | } | |
190 | ||
191 | ext2fs_free_mem(&buf); | |
192 | } | |
193 | ||
46795326 LC |
194 | static void e2fsck_discard_blocks(e2fsck_t ctx, blk64_t start, |
195 | blk64_t count) | |
efa1a355 LC |
196 | { |
197 | ext2_filsys fs = ctx->fs; | |
efa1a355 LC |
198 | |
199 | /* | |
200 | * If the filesystem has changed it means that there was an corruption | |
201 | * which should be repaired, but in some cases just one e2fsck run is | |
202 | * not enough to fix the problem, hence it is not safe to run discard | |
203 | * in this case. | |
204 | */ | |
46795326 | 205 | if (ext2fs_test_changed(fs)) |
efa1a355 LC |
206 | ctx->options &= ~E2F_OPT_DISCARD; |
207 | ||
f0fe5dae | 208 | if ((ctx->options & E2F_OPT_DISCARD) && |
efa1a355 LC |
209 | (io_channel_discard(fs->io, start, count))) |
210 | ctx->options &= ~E2F_OPT_DISCARD; | |
211 | } | |
212 | ||
57581c10 LC |
213 | /* |
214 | * This will try to discard number 'count' inodes starting at | |
215 | * inode number 'start' within the 'group'. Note that 'start' | |
216 | * is 1-based, it means that we need to adjust it by -1 in this | |
217 | * function to compute right offset in the particular inode table. | |
218 | */ | |
e64e6761 TT |
219 | static void e2fsck_discard_inodes(e2fsck_t ctx, dgrp_t group, |
220 | ext2_ino_t start, int count) | |
57581c10 LC |
221 | { |
222 | ext2_filsys fs = ctx->fs; | |
223 | blk64_t blk, num; | |
57581c10 LC |
224 | |
225 | /* | |
226 | * Sanity check for 'start' | |
227 | */ | |
228 | if ((start < 1) || (start > EXT2_INODES_PER_GROUP(fs->super))) { | |
229 | printf("PROGRAMMING ERROR: Got start %d outside of group %d!" | |
230 | " Disabling discard\n", | |
231 | start, group); | |
232 | ctx->options &= ~E2F_OPT_DISCARD; | |
233 | } | |
234 | ||
c15386cd LC |
235 | /* |
236 | * Do not attempt to discard if E2F_OPT_DISCARD is not set. And also | |
237 | * skip the discard on this group if discard does not zero data. | |
238 | * The reason is that if the inode table is not zeroed discard would | |
239 | * no help us since we need to zero it anyway, or if the inode table | |
240 | * is zeroed then the read after discard would not be deterministic | |
241 | * anyway and we would not be able to assume that this inode table | |
242 | * was zeroed anymore so we would have to zero it again, which does | |
243 | * not really make sense. | |
244 | */ | |
245 | if (!(ctx->options & E2F_OPT_DISCARD) || | |
246 | !io_channel_discard_zeroes_data(fs->io)) | |
57581c10 LC |
247 | return; |
248 | ||
249 | /* | |
250 | * Start is inode number within the group which starts | |
251 | * counting from 1, so we need to adjust it. | |
252 | */ | |
253 | start -= 1; | |
254 | ||
255 | /* | |
256 | * We can discard only blocks containing only unused | |
257 | * inodes in the table. | |
258 | */ | |
259 | blk = DIV_ROUND_UP(start, | |
260 | EXT2_INODES_PER_BLOCK(fs->super)); | |
261 | count -= (blk * EXT2_INODES_PER_BLOCK(fs->super) - start); | |
262 | blk += ext2fs_inode_table_loc(fs, group); | |
263 | num = count / EXT2_INODES_PER_BLOCK(fs->super); | |
264 | ||
265 | if (num > 0) | |
46795326 | 266 | e2fsck_discard_blocks(ctx, blk, num); |
57581c10 LC |
267 | } |
268 | ||
6dc64392 | 269 | #define NO_BLK ((blk64_t) -1) |
f122632e | 270 | |
3c7c6d73 | 271 | static void print_bitmap_problem(e2fsck_t ctx, problem_t problem, |
f122632e TT |
272 | struct problem_context *pctx) |
273 | { | |
274 | switch (problem) { | |
275 | case PR_5_BLOCK_UNUSED: | |
276 | if (pctx->blk == pctx->blk2) | |
277 | pctx->blk2 = 0; | |
278 | else | |
279 | problem = PR_5_BLOCK_RANGE_UNUSED; | |
280 | break; | |
281 | case PR_5_BLOCK_USED: | |
282 | if (pctx->blk == pctx->blk2) | |
283 | pctx->blk2 = 0; | |
284 | else | |
285 | problem = PR_5_BLOCK_RANGE_USED; | |
286 | break; | |
287 | case PR_5_INODE_UNUSED: | |
288 | if (pctx->ino == pctx->ino2) | |
289 | pctx->ino2 = 0; | |
290 | else | |
291 | problem = PR_5_INODE_RANGE_UNUSED; | |
292 | break; | |
293 | case PR_5_INODE_USED: | |
294 | if (pctx->ino == pctx->ino2) | |
295 | pctx->ino2 = 0; | |
296 | else | |
297 | problem = PR_5_INODE_RANGE_USED; | |
298 | break; | |
299 | } | |
300 | fix_problem(ctx, problem, pctx); | |
301 | pctx->blk = pctx->blk2 = NO_BLK; | |
302 | pctx->ino = pctx->ino2 = 0; | |
303 | } | |
49e2df29 | 304 | |
3385a254 TT |
305 | /* Just to be more succint */ |
306 | #define B2C(x) EXT2FS_B2C(fs, (x)) | |
307 | #define EQ_CLSTR(x, y) (B2C(x) == B2C(y)) | |
308 | #define LE_CLSTR(x, y) (B2C(x) <= B2C(y)) | |
309 | #define GE_CLSTR(x, y) (B2C(x) >= B2C(y)) | |
310 | ||
1b6bf175 | 311 | static void check_block_bitmaps(e2fsck_t ctx) |
3839e657 | 312 | { |
1b6bf175 | 313 | ext2_filsys fs = ctx->fs; |
20f2ccb3 | 314 | blk64_t i; |
e64e6761 | 315 | unsigned int *free_array; |
3971bfe8 | 316 | dgrp_t g, group = 0; |
e64e6761 | 317 | unsigned int blocks = 0; |
6dc64392 | 318 | blk64_t free_blocks = 0; |
efa1a355 | 319 | blk64_t first_free = ext2fs_blocks_count(fs->super); |
e64e6761 | 320 | unsigned int group_free = 0; |
3839e657 | 321 | int actual, bitmap; |
1b6bf175 | 322 | struct problem_context pctx; |
3c7c6d73 TT |
323 | problem_t problem, save_problem; |
324 | int fixit, had_problem; | |
1b6bf175 | 325 | errcode_t retval; |
479463aa | 326 | int redo_flag = 0; |
53e3120c TT |
327 | char *actual_buf, *bitmap_buf; |
328 | ||
329 | actual_buf = (char *) e2fsck_allocate_memory(ctx, fs->blocksize, | |
330 | "actual bitmap buffer"); | |
331 | bitmap_buf = (char *) e2fsck_allocate_memory(ctx, fs->blocksize, | |
332 | "bitmap block buffer"); | |
49e2df29 | 333 | |
1b6bf175 | 334 | clear_problem_context(&pctx); |
e64e6761 TT |
335 | free_array = (unsigned int *) e2fsck_allocate_memory(ctx, |
336 | fs->group_desc_count * sizeof(unsigned int), "free block count array"); | |
50e1e10f | 337 | |
3385a254 | 338 | if ((B2C(fs->super->s_first_data_block) < |
c5d2f50d | 339 | ext2fs_get_block_bitmap_start2(ctx->block_found_map)) || |
3385a254 | 340 | (B2C(ext2fs_blocks_count(fs->super)-1) > |
c5d2f50d | 341 | ext2fs_get_block_bitmap_end2(ctx->block_found_map))) { |
1b6bf175 | 342 | pctx.num = 1; |
3385a254 TT |
343 | pctx.blk = B2C(fs->super->s_first_data_block); |
344 | pctx.blk2 = B2C(ext2fs_blocks_count(fs->super) - 1); | |
c5d2f50d VAH |
345 | pctx.ino = ext2fs_get_block_bitmap_start2(ctx->block_found_map); |
346 | pctx.ino2 = ext2fs_get_block_bitmap_end2(ctx->block_found_map); | |
1b6bf175 | 347 | fix_problem(ctx, PR_5_BMAP_ENDPOINTS, &pctx); |
08b21301 TT |
348 | |
349 | ctx->flags |= E2F_FLAG_ABORT; /* fatal */ | |
49e2df29 | 350 | goto errout; |
50e1e10f | 351 | } |
49e2df29 | 352 | |
3385a254 | 353 | if ((B2C(fs->super->s_first_data_block) < |
c5d2f50d | 354 | ext2fs_get_block_bitmap_start2(fs->block_map)) || |
3385a254 | 355 | (B2C(ext2fs_blocks_count(fs->super)-1) > |
c5d2f50d | 356 | ext2fs_get_block_bitmap_end2(fs->block_map))) { |
1b6bf175 | 357 | pctx.num = 2; |
3385a254 TT |
358 | pctx.blk = B2C(fs->super->s_first_data_block); |
359 | pctx.blk2 = B2C(ext2fs_blocks_count(fs->super) - 1); | |
c5d2f50d VAH |
360 | pctx.ino = ext2fs_get_block_bitmap_start2(fs->block_map); |
361 | pctx.ino2 = ext2fs_get_block_bitmap_end2(fs->block_map); | |
1b6bf175 | 362 | fix_problem(ctx, PR_5_BMAP_ENDPOINTS, &pctx); |
08b21301 TT |
363 | |
364 | ctx->flags |= E2F_FLAG_ABORT; /* fatal */ | |
49e2df29 | 365 | goto errout; |
50e1e10f | 366 | } |
49e2df29 | 367 | |
63c4969c TT |
368 | redo_counts: |
369 | had_problem = 0; | |
f122632e TT |
370 | save_problem = 0; |
371 | pctx.blk = pctx.blk2 = NO_BLK; | |
3385a254 | 372 | for (i = B2C(fs->super->s_first_data_block); |
4efbac6f | 373 | i < ext2fs_blocks_count(fs->super); |
44fe08f1 | 374 | i += EXT2FS_CLUSTER_RATIO(fs)) { |
53e3120c TT |
375 | int first_block_in_bg = (B2C(i) - |
376 | B2C(fs->super->s_first_data_block)) % | |
377 | fs->super->s_clusters_per_group == 0; | |
378 | int n, nbytes = fs->super->s_clusters_per_group / 8; | |
379 | ||
c5d2f50d | 380 | actual = ext2fs_fast_test_block_bitmap2(ctx->block_found_map, i); |
f5fa2007 | 381 | |
53e3120c TT |
382 | /* |
383 | * Try to optimize pass5 by extracting a bitmap block | |
384 | * as expected from what we have on disk, and then | |
385 | * comparing the two. If they are identical, then | |
386 | * update the free block counts and go on to the next | |
387 | * block group. This is much faster than doing the | |
388 | * individual bit-by-bit comparison. The one downside | |
389 | * is that this doesn't work if we are asking e2fsck | |
390 | * to do a discard operation. | |
391 | */ | |
392 | if (!first_block_in_bg || | |
62f9bd0e | 393 | (group == fs->group_desc_count - 1) || |
53e3120c TT |
394 | (ctx->options & E2F_OPT_DISCARD)) |
395 | goto no_optimize; | |
396 | ||
397 | retval = ext2fs_get_block_bitmap_range2(ctx->block_found_map, | |
398 | B2C(i), fs->super->s_clusters_per_group, | |
399 | actual_buf); | |
400 | if (retval) | |
401 | goto no_optimize; | |
a48da274 DW |
402 | retval = ext2fs_get_block_bitmap_range2(fs->block_map, |
403 | B2C(i), fs->super->s_clusters_per_group, | |
404 | bitmap_buf); | |
405 | if (retval) | |
406 | goto no_optimize; | |
53e3120c TT |
407 | if (memcmp(actual_buf, bitmap_buf, nbytes) != 0) |
408 | goto no_optimize; | |
409 | n = ext2fs_bitcount(actual_buf, nbytes); | |
410 | group_free = fs->super->s_clusters_per_group - n; | |
411 | free_blocks += group_free; | |
c7e29325 | 412 | i += EXT2FS_C2B(fs, fs->super->s_clusters_per_group - 1); |
53e3120c TT |
413 | goto next_group; |
414 | no_optimize: | |
415 | ||
a48da274 | 416 | if (redo_flag) |
479463aa KM |
417 | bitmap = actual; |
418 | else | |
c5d2f50d | 419 | bitmap = ext2fs_fast_test_block_bitmap2(fs->block_map, i); |
49e2df29 | 420 | |
e35ff9b9 | 421 | if (!actual == !bitmap) |
3839e657 | 422 | goto do_counts; |
f5fa2007 | 423 | |
3839e657 TT |
424 | if (!actual && bitmap) { |
425 | /* | |
426 | * Block not used, but marked in use in the bitmap. | |
427 | */ | |
f122632e | 428 | problem = PR_5_BLOCK_UNUSED; |
3839e657 TT |
429 | } else { |
430 | /* | |
431 | * Block used, but not marked in use in the bitmap. | |
432 | */ | |
1b6bf175 | 433 | problem = PR_5_BLOCK_USED; |
49a7360b | 434 | |
a48da274 DW |
435 | if (ext2fs_bg_flags_test(fs, group, |
436 | EXT2_BG_BLOCK_UNINIT)) { | |
49a7360b JS |
437 | struct problem_context pctx2; |
438 | pctx2.blk = i; | |
439 | pctx2.group = group; | |
a48da274 DW |
440 | if (fix_problem(ctx, PR_5_BLOCK_UNINIT, |
441 | &pctx2)) | |
442 | ext2fs_bg_flags_clear(fs, group, | |
443 | EXT2_BG_BLOCK_UNINIT); | |
49a7360b | 444 | } |
3839e657 | 445 | } |
f122632e TT |
446 | if (pctx.blk == NO_BLK) { |
447 | pctx.blk = pctx.blk2 = i; | |
448 | save_problem = problem; | |
449 | } else { | |
450 | if ((problem == save_problem) && | |
69beadcf DW |
451 | (pctx.blk2 == i - EXT2FS_CLUSTER_RATIO(fs))) |
452 | pctx.blk2 += EXT2FS_CLUSTER_RATIO(fs); | |
f122632e TT |
453 | else { |
454 | print_bitmap_problem(ctx, save_problem, &pctx); | |
455 | pctx.blk = pctx.blk2 = i; | |
456 | save_problem = problem; | |
457 | } | |
458 | } | |
5596defa | 459 | ctx->flags |= E2F_FLAG_PROG_SUPPRESS; |
63c4969c | 460 | had_problem++; |
49e2df29 | 461 | |
efa1a355 LC |
462 | /* |
463 | * If there a problem we should turn off the discard so we | |
464 | * do not compromise the filesystem. | |
465 | */ | |
466 | ctx->options &= ~E2F_OPT_DISCARD; | |
467 | ||
3839e657 | 468 | do_counts: |
d2c9c42a | 469 | if (!bitmap) { |
3839e657 TT |
470 | group_free++; |
471 | free_blocks++; | |
efa1a355 LC |
472 | if (first_free > i) |
473 | first_free = i; | |
d2c9c42a TT |
474 | } else if (i > first_free) { |
475 | e2fsck_discard_blocks(ctx, first_free, | |
476 | (i - first_free)); | |
efa1a355 | 477 | first_free = ext2fs_blocks_count(fs->super); |
3839e657 TT |
478 | } |
479 | blocks ++; | |
44fe08f1 TT |
480 | if ((blocks == fs->super->s_clusters_per_group) || |
481 | (EXT2FS_B2C(fs, i) == | |
482 | EXT2FS_B2C(fs, ext2fs_blocks_count(fs->super)-1))) { | |
deae60a0 LC |
483 | /* |
484 | * If the last block of this group is free, then we can | |
485 | * discard it as well. | |
486 | */ | |
487 | if (!bitmap && i >= first_free) | |
488 | e2fsck_discard_blocks(ctx, first_free, | |
489 | (i - first_free) + 1); | |
53e3120c | 490 | next_group: |
deae60a0 LC |
491 | first_free = ext2fs_blocks_count(fs->super); |
492 | ||
3839e657 TT |
493 | free_array[group] = group_free; |
494 | group ++; | |
495 | blocks = 0; | |
496 | group_free = 0; | |
efac9a1b TT |
497 | if (ctx->progress) |
498 | if ((ctx->progress)(ctx, 5, group, | |
499 | fs->group_desc_count*2)) | |
49e2df29 | 500 | goto errout; |
3839e657 TT |
501 | } |
502 | } | |
f122632e TT |
503 | if (pctx.blk != NO_BLK) |
504 | print_bitmap_problem(ctx, save_problem, &pctx); | |
63c4969c | 505 | if (had_problem) |
f122632e | 506 | fixit = end_problem_latch(ctx, PR_LATCH_BBITMAP); |
63c4969c TT |
507 | else |
508 | fixit = -1; | |
5596defa | 509 | ctx->flags &= ~E2F_FLAG_PROG_SUPPRESS; |
49e2df29 | 510 | |
1b6bf175 TT |
511 | if (fixit == 1) { |
512 | ext2fs_free_block_bitmap(fs->block_map); | |
513 | retval = ext2fs_copy_bitmap(ctx->block_found_map, | |
514 | &fs->block_map); | |
bbd47d76 TT |
515 | if (retval) { |
516 | clear_problem_context(&pctx); | |
517 | fix_problem(ctx, PR_5_COPY_BBITMAP_ERROR, &pctx); | |
518 | ctx->flags |= E2F_FLAG_ABORT; | |
49e2df29 | 519 | goto errout; |
bbd47d76 | 520 | } |
1b6bf175 TT |
521 | ext2fs_set_bitmap_padding(fs->block_map); |
522 | ext2fs_mark_bb_dirty(fs); | |
49e2df29 | 523 | |
1b6bf175 TT |
524 | /* Redo the counts */ |
525 | blocks = 0; free_blocks = 0; group_free = 0; group = 0; | |
526 | memset(free_array, 0, fs->group_desc_count * sizeof(int)); | |
479463aa | 527 | redo_flag++; |
1b6bf175 TT |
528 | goto redo_counts; |
529 | } else if (fixit == 0) | |
530 | ext2fs_unmark_valid(fs); | |
531 | ||
3971bfe8 TT |
532 | for (g = 0; g < fs->group_desc_count; g++) { |
533 | if (free_array[g] != ext2fs_bg_free_blocks_count(fs, g)) { | |
534 | pctx.group = g; | |
535 | pctx.blk = ext2fs_bg_free_blocks_count(fs, g); | |
536 | pctx.blk2 = free_array[g]; | |
1b6bf175 TT |
537 | |
538 | if (fix_problem(ctx, PR_5_FREE_BLOCK_COUNT_GROUP, | |
539 | &pctx)) { | |
3971bfe8 | 540 | ext2fs_bg_free_blocks_count_set(fs, g, free_array[g]); |
3839e657 TT |
541 | ext2fs_mark_super_dirty(fs); |
542 | } else | |
543 | ext2fs_unmark_valid(fs); | |
544 | } | |
545 | } | |
fe75afbf | 546 | free_blocks = EXT2FS_C2B(fs, free_blocks); |
4efbac6f | 547 | if (free_blocks != ext2fs_free_blocks_count(fs->super)) { |
1b6bf175 | 548 | pctx.group = 0; |
4efbac6f | 549 | pctx.blk = ext2fs_free_blocks_count(fs->super); |
1b6bf175 TT |
550 | pctx.blk2 = free_blocks; |
551 | ||
552 | if (fix_problem(ctx, PR_5_FREE_BLOCK_COUNT, &pctx)) { | |
4efbac6f | 553 | ext2fs_free_blocks_count_set(fs->super, free_blocks); |
3839e657 | 554 | ext2fs_mark_super_dirty(fs); |
2788cc87 | 555 | } |
3839e657 | 556 | } |
49e2df29 | 557 | errout: |
c4e3d3f3 | 558 | ext2fs_free_mem(&free_array); |
53e3120c TT |
559 | ext2fs_free_mem(&actual_buf); |
560 | ext2fs_free_mem(&bitmap_buf); | |
3839e657 | 561 | } |
49e2df29 | 562 | |
1b6bf175 | 563 | static void check_inode_bitmaps(e2fsck_t ctx) |
3839e657 | 564 | { |
1b6bf175 | 565 | ext2_filsys fs = ctx->fs; |
86c627ec | 566 | ext2_ino_t i; |
54434927 TT |
567 | unsigned int free_inodes = 0; |
568 | int group_free = 0; | |
569 | int dirs_count = 0; | |
3971bfe8 | 570 | dgrp_t group = 0; |
54434927 | 571 | unsigned int inodes = 0; |
e64e6761 TT |
572 | ext2_ino_t *free_array; |
573 | ext2_ino_t *dir_array; | |
54434927 | 574 | int actual, bitmap; |
1b6bf175 TT |
575 | errcode_t retval; |
576 | struct problem_context pctx; | |
3c7c6d73 TT |
577 | problem_t problem, save_problem; |
578 | int fixit, had_problem; | |
16b851cd | 579 | int csum_flag; |
f5fa2007 | 580 | int skip_group = 0; |
479463aa | 581 | int redo_flag = 0; |
e64e6761 | 582 | ext2_ino_t first_free = fs->super->s_inodes_per_group + 1; |
49e2df29 | 583 | |
1b6bf175 | 584 | clear_problem_context(&pctx); |
e64e6761 TT |
585 | free_array = (ext2_ino_t *) e2fsck_allocate_memory(ctx, |
586 | fs->group_desc_count * sizeof(ext2_ino_t), "free inode count array"); | |
49e2df29 | 587 | |
e64e6761 TT |
588 | dir_array = (ext2_ino_t *) e2fsck_allocate_memory(ctx, |
589 | fs->group_desc_count * sizeof(ext2_ino_t), "directory count array"); | |
49e2df29 | 590 | |
c5d2f50d | 591 | if ((1 < ext2fs_get_inode_bitmap_start2(ctx->inode_used_map)) || |
49e2df29 | 592 | (fs->super->s_inodes_count > |
c5d2f50d | 593 | ext2fs_get_inode_bitmap_end2(ctx->inode_used_map))) { |
1b6bf175 TT |
594 | pctx.num = 3; |
595 | pctx.blk = 1; | |
596 | pctx.blk2 = fs->super->s_inodes_count; | |
c5d2f50d VAH |
597 | pctx.ino = ext2fs_get_inode_bitmap_start2(ctx->inode_used_map); |
598 | pctx.ino2 = ext2fs_get_inode_bitmap_end2(ctx->inode_used_map); | |
1b6bf175 | 599 | fix_problem(ctx, PR_5_BMAP_ENDPOINTS, &pctx); |
08b21301 TT |
600 | |
601 | ctx->flags |= E2F_FLAG_ABORT; /* fatal */ | |
49e2df29 | 602 | goto errout; |
50e1e10f | 603 | } |
c5d2f50d | 604 | if ((1 < ext2fs_get_inode_bitmap_start2(fs->inode_map)) || |
49e2df29 | 605 | (fs->super->s_inodes_count > |
c5d2f50d | 606 | ext2fs_get_inode_bitmap_end2(fs->inode_map))) { |
1b6bf175 TT |
607 | pctx.num = 4; |
608 | pctx.blk = 1; | |
609 | pctx.blk2 = fs->super->s_inodes_count; | |
c5d2f50d VAH |
610 | pctx.ino = ext2fs_get_inode_bitmap_start2(fs->inode_map); |
611 | pctx.ino2 = ext2fs_get_inode_bitmap_end2(fs->inode_map); | |
1b6bf175 | 612 | fix_problem(ctx, PR_5_BMAP_ENDPOINTS, &pctx); |
08b21301 TT |
613 | |
614 | ctx->flags |= E2F_FLAG_ABORT; /* fatal */ | |
49e2df29 | 615 | goto errout; |
50e1e10f TT |
616 | } |
617 | ||
387e6384 | 618 | csum_flag = ext2fs_has_group_desc_csum(fs); |
1b6bf175 | 619 | redo_counts: |
63c4969c | 620 | had_problem = 0; |
f122632e TT |
621 | save_problem = 0; |
622 | pctx.ino = pctx.ino2 = 0; | |
16b851cd | 623 | if (csum_flag && |
cd65a24e | 624 | (ext2fs_bg_flags_test(fs, group, EXT2_BG_INODE_UNINIT))) |
f5fa2007 TT |
625 | skip_group++; |
626 | ||
5830d6be ES |
627 | /* Protect loop from wrap-around if inodes_count is maxed */ |
628 | for (i = 1; i <= fs->super->s_inodes_count && i > 0; i++) { | |
479463aa KM |
629 | bitmap = 0; |
630 | if (skip_group && | |
631 | i % fs->super->s_inodes_per_group == 1) { | |
632 | /* | |
633 | * Current inode is the first inode | |
634 | * in the current block group. | |
635 | */ | |
636 | if (ext2fs_test_inode_bitmap_range( | |
637 | ctx->inode_used_map, i, | |
638 | fs->super->s_inodes_per_group)) { | |
639 | /* | |
640 | * When the compared inodes in inodes bitmap | |
641 | * are 0, count the free inode, | |
642 | * skip the current block group. | |
643 | */ | |
57581c10 | 644 | first_free = 1; |
479463aa KM |
645 | inodes = fs->super->s_inodes_per_group - 1; |
646 | group_free = inodes; | |
647 | free_inodes += inodes; | |
648 | i += inodes; | |
649 | skip_group = 0; | |
650 | goto do_counts; | |
651 | } | |
652 | } | |
653 | ||
c5d2f50d | 654 | actual = ext2fs_fast_test_inode_bitmap2(ctx->inode_used_map, i); |
479463aa KM |
655 | if (redo_flag) |
656 | bitmap = actual; | |
657 | else if (!skip_group) | |
c5d2f50d | 658 | bitmap = ext2fs_fast_test_inode_bitmap2(fs->inode_map, i); |
e35ff9b9 | 659 | if (!actual == !bitmap) |
3839e657 | 660 | goto do_counts; |
49e2df29 | 661 | |
3839e657 TT |
662 | if (!actual && bitmap) { |
663 | /* | |
664 | * Inode wasn't used, but marked in bitmap | |
665 | */ | |
f122632e | 666 | problem = PR_5_INODE_UNUSED; |
1b6bf175 | 667 | } else /* if (actual && !bitmap) */ { |
3839e657 TT |
668 | /* |
669 | * Inode used, but not in bitmap | |
670 | */ | |
1b6bf175 | 671 | problem = PR_5_INODE_USED; |
49a7360b JS |
672 | |
673 | /* We should never hit this, because it means that | |
674 | * inodes were marked in use that weren't noticed | |
675 | * in pass1 or pass 2. It is easier to fix the problem | |
676 | * than to kill e2fsck and leave the user stuck. */ | |
677 | if (skip_group) { | |
678 | struct problem_context pctx2; | |
679 | pctx2.blk = i; | |
680 | pctx2.group = group; | |
681 | if (fix_problem(ctx, PR_5_INODE_UNINIT,&pctx2)){ | |
e633b58a | 682 | ext2fs_bg_flags_clear(fs, group, EXT2_BG_INODE_UNINIT); |
49a7360b JS |
683 | skip_group = 0; |
684 | } | |
685 | } | |
3839e657 | 686 | } |
f122632e TT |
687 | if (pctx.ino == 0) { |
688 | pctx.ino = pctx.ino2 = i; | |
689 | save_problem = problem; | |
690 | } else { | |
691 | if ((problem == save_problem) && | |
692 | (pctx.ino2 == i-1)) | |
693 | pctx.ino2++; | |
694 | else { | |
695 | print_bitmap_problem(ctx, save_problem, &pctx); | |
696 | pctx.ino = pctx.ino2 = i; | |
697 | save_problem = problem; | |
698 | } | |
699 | } | |
5596defa | 700 | ctx->flags |= E2F_FLAG_PROG_SUPPRESS; |
63c4969c | 701 | had_problem++; |
efa1a355 LC |
702 | /* |
703 | * If there a problem we should turn off the discard so we | |
704 | * do not compromise the filesystem. | |
705 | */ | |
706 | ctx->options &= ~E2F_OPT_DISCARD; | |
49e2df29 | 707 | |
3839e657 | 708 | do_counts: |
57581c10 | 709 | inodes++; |
f5fa2007 | 710 | if (bitmap) { |
c5d2f50d | 711 | if (ext2fs_test_inode_bitmap2(ctx->inode_dir_map, i)) |
3839e657 | 712 | dirs_count++; |
57581c10 LC |
713 | if (inodes > first_free) { |
714 | e2fsck_discard_inodes(ctx, group, first_free, | |
715 | inodes - first_free); | |
716 | first_free = fs->super->s_inodes_per_group + 1; | |
717 | } | |
d2c9c42a | 718 | } else { |
f5fa2007 TT |
719 | group_free++; |
720 | free_inodes++; | |
57581c10 LC |
721 | if (first_free > inodes) |
722 | first_free = inodes; | |
3839e657 | 723 | } |
efa1a355 | 724 | |
3839e657 TT |
725 | if ((inodes == fs->super->s_inodes_per_group) || |
726 | (i == fs->super->s_inodes_count)) { | |
57581c10 LC |
727 | /* |
728 | * If the last inode is free, we can discard it as well. | |
729 | */ | |
730 | if (!bitmap && inodes >= first_free) | |
731 | e2fsck_discard_inodes(ctx, group, first_free, | |
732 | inodes - first_free + 1); | |
efa1a355 LC |
733 | /* |
734 | * If discard zeroes data and the group inode table | |
735 | * was not zeroed yet, set itable as zeroed | |
736 | */ | |
737 | if ((ctx->options & E2F_OPT_DISCARD) && | |
57581c10 | 738 | io_channel_discard_zeroes_data(fs->io) && |
efa1a355 | 739 | !(ext2fs_bg_flags_test(fs, group, |
57581c10 | 740 | EXT2_BG_INODE_ZEROED))) { |
efa1a355 LC |
741 | ext2fs_bg_flags_set(fs, group, |
742 | EXT2_BG_INODE_ZEROED); | |
743 | ext2fs_group_desc_csum_set(fs, group); | |
744 | } | |
745 | ||
57581c10 LC |
746 | first_free = fs->super->s_inodes_per_group + 1; |
747 | free_array[group] = group_free; | |
748 | dir_array[group] = dirs_count; | |
3839e657 TT |
749 | group ++; |
750 | inodes = 0; | |
f5fa2007 | 751 | skip_group = 0; |
3839e657 TT |
752 | group_free = 0; |
753 | dirs_count = 0; | |
efac9a1b TT |
754 | if (ctx->progress) |
755 | if ((ctx->progress)(ctx, 5, | |
756 | group + fs->group_desc_count, | |
757 | fs->group_desc_count*2)) | |
49e2df29 | 758 | goto errout; |
16b851cd | 759 | if (csum_flag && |
f5fa2007 | 760 | (i != fs->super->s_inodes_count) && |
cd65a24e | 761 | (ext2fs_bg_flags_test(fs, group, EXT2_BG_INODE_UNINIT) |
732c8cd5 | 762 | )) |
f5fa2007 | 763 | skip_group++; |
3839e657 TT |
764 | } |
765 | } | |
f122632e TT |
766 | if (pctx.ino) |
767 | print_bitmap_problem(ctx, save_problem, &pctx); | |
49e2df29 | 768 | |
63c4969c TT |
769 | if (had_problem) |
770 | fixit = end_problem_latch(ctx, PR_LATCH_IBITMAP); | |
771 | else | |
772 | fixit = -1; | |
5596defa | 773 | ctx->flags &= ~E2F_FLAG_PROG_SUPPRESS; |
49e2df29 | 774 | |
1b6bf175 TT |
775 | if (fixit == 1) { |
776 | ext2fs_free_inode_bitmap(fs->inode_map); | |
777 | retval = ext2fs_copy_bitmap(ctx->inode_used_map, | |
778 | &fs->inode_map); | |
bbd47d76 TT |
779 | if (retval) { |
780 | clear_problem_context(&pctx); | |
781 | fix_problem(ctx, PR_5_COPY_IBITMAP_ERROR, &pctx); | |
782 | ctx->flags |= E2F_FLAG_ABORT; | |
49e2df29 | 783 | goto errout; |
bbd47d76 | 784 | } |
1b6bf175 TT |
785 | ext2fs_set_bitmap_padding(fs->inode_map); |
786 | ext2fs_mark_ib_dirty(fs); | |
787 | ||
788 | /* redo counts */ | |
789 | inodes = 0; free_inodes = 0; group_free = 0; | |
790 | dirs_count = 0; group = 0; | |
791 | memset(free_array, 0, fs->group_desc_count * sizeof(int)); | |
792 | memset(dir_array, 0, fs->group_desc_count * sizeof(int)); | |
479463aa | 793 | redo_flag++; |
1b6bf175 TT |
794 | goto redo_counts; |
795 | } else if (fixit == 0) | |
796 | ext2fs_unmark_valid(fs); | |
49e2df29 | 797 | |
3839e657 | 798 | for (i = 0; i < fs->group_desc_count; i++) { |
d7cca6b0 | 799 | if (free_array[i] != ext2fs_bg_free_inodes_count(fs, i)) { |
1b6bf175 | 800 | pctx.group = i; |
d7cca6b0 | 801 | pctx.ino = ext2fs_bg_free_inodes_count(fs, i); |
1b6bf175 TT |
802 | pctx.ino2 = free_array[i]; |
803 | if (fix_problem(ctx, PR_5_FREE_INODE_COUNT_GROUP, | |
804 | &pctx)) { | |
d7cca6b0 | 805 | ext2fs_bg_free_inodes_count_set(fs, i, free_array[i]); |
3839e657 TT |
806 | ext2fs_mark_super_dirty(fs); |
807 | } else | |
808 | ext2fs_unmark_valid(fs); | |
809 | } | |
d7cca6b0 | 810 | if (dir_array[i] != ext2fs_bg_used_dirs_count(fs, i)) { |
1b6bf175 | 811 | pctx.group = i; |
d7cca6b0 | 812 | pctx.ino = ext2fs_bg_used_dirs_count(fs, i); |
1b6bf175 TT |
813 | pctx.ino2 = dir_array[i]; |
814 | ||
815 | if (fix_problem(ctx, PR_5_FREE_DIR_COUNT_GROUP, | |
816 | &pctx)) { | |
d7cca6b0 | 817 | ext2fs_bg_used_dirs_count_set(fs, i, dir_array[i]); |
3839e657 TT |
818 | ext2fs_mark_super_dirty(fs); |
819 | } else | |
820 | ext2fs_unmark_valid(fs); | |
821 | } | |
822 | } | |
823 | if (free_inodes != fs->super->s_free_inodes_count) { | |
1b6bf175 TT |
824 | pctx.group = -1; |
825 | pctx.ino = fs->super->s_free_inodes_count; | |
826 | pctx.ino2 = free_inodes; | |
827 | ||
828 | if (fix_problem(ctx, PR_5_FREE_INODE_COUNT, &pctx)) { | |
3839e657 TT |
829 | fs->super->s_free_inodes_count = free_inodes; |
830 | ext2fs_mark_super_dirty(fs); | |
2788cc87 | 831 | } |
3839e657 | 832 | } |
49e2df29 | 833 | errout: |
c4e3d3f3 TT |
834 | ext2fs_free_mem(&free_array); |
835 | ext2fs_free_mem(&dir_array); | |
3839e657 TT |
836 | } |
837 | ||
1b6bf175 | 838 | static void check_inode_end(e2fsck_t ctx) |
3839e657 | 839 | { |
1b6bf175 | 840 | ext2_filsys fs = ctx->fs; |
86c627ec | 841 | ext2_ino_t end, save_inodes_count, i; |
1b6bf175 TT |
842 | struct problem_context pctx; |
843 | ||
844 | clear_problem_context(&pctx); | |
3839e657 TT |
845 | |
846 | end = EXT2_INODES_PER_GROUP(fs->super) * fs->group_desc_count; | |
1b6bf175 TT |
847 | pctx.errcode = ext2fs_fudge_inode_bitmap_end(fs->inode_map, end, |
848 | &save_inodes_count); | |
849 | if (pctx.errcode) { | |
850 | pctx.num = 1; | |
851 | fix_problem(ctx, PR_5_FUDGE_BITMAP_ERROR, &pctx); | |
08b21301 TT |
852 | ctx->flags |= E2F_FLAG_ABORT; /* fatal */ |
853 | return; | |
f3db3566 | 854 | } |
3839e657 TT |
855 | if (save_inodes_count == end) |
856 | return; | |
5830d6be | 857 | |
efc6f628 | 858 | /* protect loop from wrap-around if end is maxed */ |
5830d6be | 859 | for (i = save_inodes_count + 1; i <= end && i > save_inodes_count; i++) { |
f3db3566 | 860 | if (!ext2fs_test_inode_bitmap(fs->inode_map, i)) { |
1b6bf175 | 861 | if (fix_problem(ctx, PR_5_INODE_BMAP_PADDING, &pctx)) { |
01ec1268 | 862 | for (; i <= end; i++) |
f3db3566 | 863 | ext2fs_mark_inode_bitmap(fs->inode_map, |
3839e657 TT |
864 | i); |
865 | ext2fs_mark_ib_dirty(fs); | |
866 | } else | |
867 | ext2fs_unmark_valid(fs); | |
868 | break; | |
869 | } | |
870 | } | |
871 | ||
1b6bf175 TT |
872 | pctx.errcode = ext2fs_fudge_inode_bitmap_end(fs->inode_map, |
873 | save_inodes_count, 0); | |
874 | if (pctx.errcode) { | |
875 | pctx.num = 2; | |
876 | fix_problem(ctx, PR_5_FUDGE_BITMAP_ERROR, &pctx); | |
08b21301 TT |
877 | ctx->flags |= E2F_FLAG_ABORT; /* fatal */ |
878 | return; | |
f3db3566 | 879 | } |
3839e657 TT |
880 | } |
881 | ||
1b6bf175 | 882 | static void check_block_end(e2fsck_t ctx) |
3839e657 | 883 | { |
1b6bf175 | 884 | ext2_filsys fs = ctx->fs; |
c5d2f50d | 885 | blk64_t end, save_blocks_count, i; |
1b6bf175 TT |
886 | struct problem_context pctx; |
887 | ||
888 | clear_problem_context(&pctx); | |
3839e657 | 889 | |
c5d2f50d | 890 | end = ext2fs_get_block_bitmap_start2(fs->block_map) + |
1e33a8b4 | 891 | EXT2_GROUPS_TO_CLUSTERS(fs->super, fs->group_desc_count) - 1; |
c5d2f50d | 892 | pctx.errcode = ext2fs_fudge_block_bitmap_end2(fs->block_map, end, |
1b6bf175 TT |
893 | &save_blocks_count); |
894 | if (pctx.errcode) { | |
895 | pctx.num = 3; | |
896 | fix_problem(ctx, PR_5_FUDGE_BITMAP_ERROR, &pctx); | |
08b21301 TT |
897 | ctx->flags |= E2F_FLAG_ABORT; /* fatal */ |
898 | return; | |
f3db3566 | 899 | } |
3839e657 TT |
900 | if (save_blocks_count == end) |
901 | return; | |
5830d6be | 902 | |
efc6f628 | 903 | /* Protect loop from wrap-around if end is maxed */ |
5830d6be | 904 | for (i = save_blocks_count + 1; i <= end && i > save_blocks_count; i++) { |
44fe08f1 TT |
905 | if (!ext2fs_test_block_bitmap2(fs->block_map, |
906 | EXT2FS_C2B(fs, i))) { | |
1b6bf175 | 907 | if (fix_problem(ctx, PR_5_BLOCK_BMAP_PADDING, &pctx)) { |
01ec1268 | 908 | for (; i <= end; i++) |
c5d2f50d | 909 | ext2fs_mark_block_bitmap2(fs->block_map, |
44fe08f1 | 910 | EXT2FS_C2B(fs, i)); |
3839e657 TT |
911 | ext2fs_mark_bb_dirty(fs); |
912 | } else | |
913 | ext2fs_unmark_valid(fs); | |
914 | break; | |
915 | } | |
916 | } | |
917 | ||
c5d2f50d | 918 | pctx.errcode = ext2fs_fudge_block_bitmap_end2(fs->block_map, |
1b6bf175 TT |
919 | save_blocks_count, 0); |
920 | if (pctx.errcode) { | |
921 | pctx.num = 4; | |
922 | fix_problem(ctx, PR_5_FUDGE_BITMAP_ERROR, &pctx); | |
08b21301 TT |
923 | ctx->flags |= E2F_FLAG_ABORT; /* fatal */ |
924 | return; | |
f3db3566 | 925 | } |
3839e657 TT |
926 | } |
927 | ||
1b6bf175 TT |
928 | |
929 |