]> git.ipfire.org Git - thirdparty/e2fsprogs.git/blame - e2fsck/pass5.c
Fix typos in code comments and developer docs
[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;
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
84static 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
138static 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
194static 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
219static 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 271static 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
055866d8 305/* Just to be more succinct */
3385a254
TT
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 311static 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
368redo_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 557errout:
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 563static 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 619redo_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 708do_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 833errout:
c4e3d3f3
TT
834 ext2fs_free_mem(&free_array);
835 ext2fs_free_mem(&dir_array);
3839e657
TT
836}
837
1b6bf175 838static 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 882static 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