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