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