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