blob: c04ffbd27011f0c1556b75b2772f54c48e01e11c [file] [log] [blame]
Theodore Ts'o3839e651997-04-26 13:21:57 +00001/*
2 * pass5.c --- check block and inode bitmaps against on-disk bitmaps
Theodore Ts'oefc6f622008-08-27 23:07:54 -04003 *
Theodore Ts'o21c84b71997-04-29 16:15:03 +00004 * 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%
Theodore Ts'oefc6f622008-08-27 23:07:54 -040010 *
Theodore Ts'o3839e651997-04-26 13:21:57 +000011 */
12
JP Abgralle0ed7402014-03-19 19:08:39 -070013#include <stdint.h>
14#include <sys/types.h>
15#include <sys/stat.h>
16#include <sys/ioctl.h>
17#include <fcntl.h>
18#include <errno.h>
19
Theodore Ts'o3839e651997-04-26 13:21:57 +000020#include "e2fsck.h"
Theodore Ts'o1b6bf171997-10-03 17:48:10 +000021#include "problem.h"
Theodore Ts'o3839e651997-04-26 13:21:57 +000022
JP Abgralle0ed7402014-03-19 19:08:39 -070023#define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d))
24
Theodore Ts'o1b6bf171997-10-03 17:48:10 +000025static void check_block_bitmaps(e2fsck_t ctx);
26static void check_inode_bitmaps(e2fsck_t ctx);
27static void check_inode_end(e2fsck_t ctx);
28static void check_block_end(e2fsck_t ctx);
Theodore Ts'o3839e651997-04-26 13:21:57 +000029
Theodore Ts'o08b21301997-11-03 19:42:40 +000030void e2fsck_pass5(e2fsck_t ctx)
Theodore Ts'o3839e651997-04-26 13:21:57 +000031{
Theodore Ts'o8bf191e1997-10-20 01:38:32 +000032#ifdef RESOURCE_TRACK
Theodore Ts'o3839e651997-04-26 13:21:57 +000033 struct resource_track rtrack;
Theodore Ts'o8bf191e1997-10-20 01:38:32 +000034#endif
Theodore Ts'o1b6bf171997-10-03 17:48:10 +000035 struct problem_context pctx;
Theodore Ts'oefc6f622008-08-27 23:07:54 -040036
Theodore Ts'o3839e651997-04-26 13:21:57 +000037#ifdef MTRACE
38 mtrace_print("Pass 5");
39#endif
40
Theodore Ts'o6d96b002007-08-03 20:07:09 -040041 init_resource_track(&rtrack, ctx->fs->io);
Theodore Ts'o1b6bf171997-10-03 17:48:10 +000042 clear_problem_context(&pctx);
Theodore Ts'o3839e651997-04-26 13:21:57 +000043
Theodore Ts'o1b6bf171997-10-03 17:48:10 +000044 if (!(ctx->options & E2F_OPT_PREEN))
45 fix_problem(ctx, PR_5_PASS_HEADER, &pctx);
Theodore Ts'o3839e651997-04-26 13:21:57 +000046
Theodore Ts'of8188ff1997-11-14 05:23:04 +000047 if (ctx->progress)
Theodore Ts'oefac9a11998-05-07 05:02:00 +000048 if ((ctx->progress)(ctx, 5, 0, ctx->fs->group_desc_count*2))
Theodore Ts'oa02ce9d1998-02-24 20:22:23 +000049 return;
Theodore Ts'of8188ff1997-11-14 05:23:04 +000050
51 e2fsck_read_bitmaps(ctx);
52
Theodore Ts'o1b6bf171997-10-03 17:48:10 +000053 check_block_bitmaps(ctx);
Theodore Ts'oa02ce9d1998-02-24 20:22:23 +000054 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
Theodore Ts'o08b21301997-11-03 19:42:40 +000055 return;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +000056 check_inode_bitmaps(ctx);
Theodore Ts'oa02ce9d1998-02-24 20:22:23 +000057 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
Theodore Ts'o08b21301997-11-03 19:42:40 +000058 return;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +000059 check_inode_end(ctx);
Theodore Ts'oa02ce9d1998-02-24 20:22:23 +000060 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
Theodore Ts'o08b21301997-11-03 19:42:40 +000061 return;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +000062 check_block_end(ctx);
Theodore Ts'oa02ce9d1998-02-24 20:22:23 +000063 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
Theodore Ts'o08b21301997-11-03 19:42:40 +000064 return;
Theodore Ts'o3839e651997-04-26 13:21:57 +000065
Theodore Ts'o1b6bf171997-10-03 17:48:10 +000066 ext2fs_free_inode_bitmap(ctx->inode_used_map);
67 ctx->inode_used_map = 0;
68 ext2fs_free_inode_bitmap(ctx->inode_dir_map);
69 ctx->inode_dir_map = 0;
70 ext2fs_free_block_bitmap(ctx->block_found_map);
71 ctx->block_found_map = 0;
72
Ken Chen9facd072009-05-28 09:55:10 -040073 print_resource_track(ctx, _("Pass 5"), &rtrack, ctx->fs->io);
Theodore Ts'o3839e651997-04-26 13:21:57 +000074}
75
JP Abgralle0ed7402014-03-19 19:08:39 -070076static void e2fsck_discard_blocks(e2fsck_t ctx, blk64_t start,
77 blk64_t count)
78{
79 ext2_filsys fs = ctx->fs;
Lukas Czernerefa1a352010-11-18 03:38:38 +000080
JP Abgralle0ed7402014-03-19 19:08:39 -070081 /*
82 * If the filesystem has changed it means that there was an corruption
83 * which should be repaired, but in some cases just one e2fsck run is
84 * not enough to fix the problem, hence it is not safe to run discard
85 * in this case.
86 */
87 if (ext2fs_test_changed(fs))
88 ctx->options &= ~E2F_OPT_DISCARD;
89
90 if ((ctx->options & E2F_OPT_DISCARD) &&
91 (io_channel_discard(fs->io, start, count)))
92 ctx->options &= ~E2F_OPT_DISCARD;
93}
94
95/*
96 * This will try to discard number 'count' inodes starting at
97 * inode number 'start' within the 'group'. Note that 'start'
98 * is 1-based, it means that we need to adjust it by -1 in this
99 * function to compute right offset in the particular inode table.
100 */
101static void e2fsck_discard_inodes(e2fsck_t ctx, dgrp_t group,
102 ext2_ino_t start, int count)
103{
104 ext2_filsys fs = ctx->fs;
105 blk64_t blk, num;
106
107 /*
108 * Sanity check for 'start'
109 */
110 if ((start < 1) || (start > EXT2_INODES_PER_GROUP(fs->super))) {
111 printf("PROGRAMMING ERROR: Got start %d outside of group %d!"
112 " Disabling discard\n",
113 start, group);
114 ctx->options &= ~E2F_OPT_DISCARD;
115 }
116
117 /*
118 * Do not attempt to discard if E2F_OPT_DISCARD is not set. And also
119 * skip the discard on this group if discard does not zero data.
120 * The reason is that if the inode table is not zeroed discard would
121 * no help us since we need to zero it anyway, or if the inode table
122 * is zeroed then the read after discard would not be deterministic
123 * anyway and we would not be able to assume that this inode table
124 * was zeroed anymore so we would have to zero it again, which does
125 * not really make sense.
126 */
127 if (!(ctx->options & E2F_OPT_DISCARD) ||
128 !io_channel_discard_zeroes_data(fs->io))
129 return;
130
131 /*
132 * Start is inode number within the group which starts
133 * counting from 1, so we need to adjust it.
134 */
135 start -= 1;
136
137 /*
138 * We can discard only blocks containing only unused
139 * inodes in the table.
140 */
141 blk = DIV_ROUND_UP(start,
142 EXT2_INODES_PER_BLOCK(fs->super));
143 count -= (blk * EXT2_INODES_PER_BLOCK(fs->super) - start);
144 blk += ext2fs_inode_table_loc(fs, group);
145 num = count / EXT2_INODES_PER_BLOCK(fs->super);
146
147 if (num > 0)
148 e2fsck_discard_blocks(ctx, blk, num);
149}
150
151#define NO_BLK ((blk64_t) -1)
152
153static void print_bitmap_problem(e2fsck_t ctx, problem_t problem,
Theodore Ts'of1226322002-03-07 02:47:07 -0500154 struct problem_context *pctx)
155{
156 switch (problem) {
157 case PR_5_BLOCK_UNUSED:
158 if (pctx->blk == pctx->blk2)
159 pctx->blk2 = 0;
160 else
161 problem = PR_5_BLOCK_RANGE_UNUSED;
162 break;
163 case PR_5_BLOCK_USED:
164 if (pctx->blk == pctx->blk2)
165 pctx->blk2 = 0;
166 else
167 problem = PR_5_BLOCK_RANGE_USED;
168 break;
169 case PR_5_INODE_UNUSED:
170 if (pctx->ino == pctx->ino2)
171 pctx->ino2 = 0;
172 else
173 problem = PR_5_INODE_RANGE_UNUSED;
174 break;
175 case PR_5_INODE_USED:
176 if (pctx->ino == pctx->ino2)
177 pctx->ino2 = 0;
178 else
179 problem = PR_5_INODE_RANGE_USED;
180 break;
181 }
182 fix_problem(ctx, problem, pctx);
183 pctx->blk = pctx->blk2 = NO_BLK;
184 pctx->ino = pctx->ino2 = 0;
185}
Brian Behlendorf49e2df22007-03-28 12:07:41 -0400186
JP Abgralle0ed7402014-03-19 19:08:39 -0700187/* Just to be more succint */
188#define B2C(x) EXT2FS_B2C(fs, (x))
189#define EQ_CLSTR(x, y) (B2C(x) == B2C(y))
190#define LE_CLSTR(x, y) (B2C(x) <= B2C(y))
191#define GE_CLSTR(x, y) (B2C(x) >= B2C(y))
192
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000193static void check_block_bitmaps(e2fsck_t ctx)
Theodore Ts'o3839e651997-04-26 13:21:57 +0000194{
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000195 ext2_filsys fs = ctx->fs;
JP Abgralle0ed7402014-03-19 19:08:39 -0700196 blk64_t i;
197 unsigned int *free_array;
198 dgrp_t g, group = 0;
199 unsigned int blocks = 0;
200 blk64_t free_blocks = 0;
201 blk64_t first_free = ext2fs_blocks_count(fs->super);
202 unsigned int group_free = 0;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000203 int actual, bitmap;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000204 struct problem_context pctx;
JP Abgralle0ed7402014-03-19 19:08:39 -0700205 problem_t problem, save_problem;
206 int fixit, had_problem;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000207 errcode_t retval;
Theodore Ts'o16b851c2008-04-20 23:33:34 -0400208 int csum_flag;
Theodore Ts'of5fa2002006-05-08 20:17:26 -0400209 int skip_group = 0;
JP Abgralle0ed7402014-03-19 19:08:39 -0700210 int old_desc_blocks = 0;
211 int count = 0;
212 int cmp_block = 0;
213 int redo_flag = 0;
214 blk64_t super_blk, old_desc_blk, new_desc_blk;
215 char *actual_buf, *bitmap_buf;
216
217 actual_buf = (char *) e2fsck_allocate_memory(ctx, fs->blocksize,
218 "actual bitmap buffer");
219 bitmap_buf = (char *) e2fsck_allocate_memory(ctx, fs->blocksize,
220 "bitmap block buffer");
Brian Behlendorf49e2df22007-03-28 12:07:41 -0400221
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000222 clear_problem_context(&pctx);
JP Abgralle0ed7402014-03-19 19:08:39 -0700223 free_array = (unsigned int *) e2fsck_allocate_memory(ctx,
224 fs->group_desc_count * sizeof(unsigned int), "free block count array");
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000225
JP Abgralle0ed7402014-03-19 19:08:39 -0700226 if ((B2C(fs->super->s_first_data_block) <
227 ext2fs_get_block_bitmap_start2(ctx->block_found_map)) ||
228 (B2C(ext2fs_blocks_count(fs->super)-1) >
229 ext2fs_get_block_bitmap_end2(ctx->block_found_map))) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000230 pctx.num = 1;
JP Abgralle0ed7402014-03-19 19:08:39 -0700231 pctx.blk = B2C(fs->super->s_first_data_block);
232 pctx.blk2 = B2C(ext2fs_blocks_count(fs->super) - 1);
233 pctx.ino = ext2fs_get_block_bitmap_start2(ctx->block_found_map);
234 pctx.ino2 = ext2fs_get_block_bitmap_end2(ctx->block_found_map);
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000235 fix_problem(ctx, PR_5_BMAP_ENDPOINTS, &pctx);
Theodore Ts'o08b21301997-11-03 19:42:40 +0000236
237 ctx->flags |= E2F_FLAG_ABORT; /* fatal */
Brian Behlendorf49e2df22007-03-28 12:07:41 -0400238 goto errout;
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000239 }
Brian Behlendorf49e2df22007-03-28 12:07:41 -0400240
JP Abgralle0ed7402014-03-19 19:08:39 -0700241 if ((B2C(fs->super->s_first_data_block) <
242 ext2fs_get_block_bitmap_start2(fs->block_map)) ||
243 (B2C(ext2fs_blocks_count(fs->super)-1) >
244 ext2fs_get_block_bitmap_end2(fs->block_map))) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000245 pctx.num = 2;
JP Abgralle0ed7402014-03-19 19:08:39 -0700246 pctx.blk = B2C(fs->super->s_first_data_block);
247 pctx.blk2 = B2C(ext2fs_blocks_count(fs->super) - 1);
248 pctx.ino = ext2fs_get_block_bitmap_start2(fs->block_map);
249 pctx.ino2 = ext2fs_get_block_bitmap_end2(fs->block_map);
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000250 fix_problem(ctx, PR_5_BMAP_ENDPOINTS, &pctx);
Theodore Ts'o08b21301997-11-03 19:42:40 +0000251
252 ctx->flags |= E2F_FLAG_ABORT; /* fatal */
Brian Behlendorf49e2df22007-03-28 12:07:41 -0400253 goto errout;
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000254 }
Brian Behlendorf49e2df22007-03-28 12:07:41 -0400255
Jose R. Santos49a73602007-10-21 21:04:03 -0500256 csum_flag = EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
257 EXT4_FEATURE_RO_COMPAT_GDT_CSUM);
Theodore Ts'o63c49691998-02-20 05:24:59 +0000258redo_counts:
259 had_problem = 0;
Theodore Ts'of1226322002-03-07 02:47:07 -0500260 save_problem = 0;
261 pctx.blk = pctx.blk2 = NO_BLK;
Theodore Ts'o16b851c2008-04-20 23:33:34 -0400262 if (csum_flag &&
JP Abgralle0ed7402014-03-19 19:08:39 -0700263 (ext2fs_bg_flags_test(fs, group, EXT2_BG_BLOCK_UNINIT)))
Theodore Ts'of5fa2002006-05-08 20:17:26 -0400264 skip_group++;
JP Abgralle0ed7402014-03-19 19:08:39 -0700265 for (i = B2C(fs->super->s_first_data_block);
266 i < ext2fs_blocks_count(fs->super);
267 i += EXT2FS_CLUSTER_RATIO(fs)) {
268 int first_block_in_bg = (B2C(i) -
269 B2C(fs->super->s_first_data_block)) %
270 fs->super->s_clusters_per_group == 0;
271 int n, nbytes = fs->super->s_clusters_per_group / 8;
272
273 actual = ext2fs_fast_test_block_bitmap2(ctx->block_found_map, i);
274
275 /*
276 * Try to optimize pass5 by extracting a bitmap block
277 * as expected from what we have on disk, and then
278 * comparing the two. If they are identical, then
279 * update the free block counts and go on to the next
280 * block group. This is much faster than doing the
281 * individual bit-by-bit comparison. The one downside
282 * is that this doesn't work if we are asking e2fsck
283 * to do a discard operation.
284 */
285 if (!first_block_in_bg ||
286 (group == (int)fs->group_desc_count - 1) ||
287 (ctx->options & E2F_OPT_DISCARD))
288 goto no_optimize;
289
290 retval = ext2fs_get_block_bitmap_range2(ctx->block_found_map,
291 B2C(i), fs->super->s_clusters_per_group,
292 actual_buf);
293 if (retval)
294 goto no_optimize;
295 if (ext2fs_bg_flags_test(fs, group, EXT2_BG_BLOCK_UNINIT))
296 memset(bitmap_buf, 0, nbytes);
297 else {
298 retval = ext2fs_get_block_bitmap_range2(fs->block_map,
299 B2C(i), fs->super->s_clusters_per_group,
300 bitmap_buf);
301 if (retval)
302 goto no_optimize;
303 }
304 if (memcmp(actual_buf, bitmap_buf, nbytes) != 0)
305 goto no_optimize;
306 n = ext2fs_bitcount(actual_buf, nbytes);
307 group_free = fs->super->s_clusters_per_group - n;
308 free_blocks += group_free;
309 i += EXT2FS_C2B(fs, fs->super->s_clusters_per_group - 1);
310 goto next_group;
311 no_optimize:
Theodore Ts'o53e31202012-11-24 19:17:44 -0500312
Theodore Ts'of5fa2002006-05-08 20:17:26 -0400313 if (skip_group) {
JP Abgralle0ed7402014-03-19 19:08:39 -0700314 if (first_block_in_bg) {
315 super_blk = 0;
316 old_desc_blk = 0;
317 new_desc_blk = 0;
318 ext2fs_super_and_bgd_loc2(fs, group, &super_blk,
Theodore Ts'o4a2924e2008-04-19 10:30:59 -0400319 &old_desc_blk, &new_desc_blk, 0);
320
JP Abgralle0ed7402014-03-19 19:08:39 -0700321 if (fs->super->s_feature_incompat &
322 EXT2_FEATURE_INCOMPAT_META_BG)
323 old_desc_blocks =
324 fs->super->s_first_meta_bg;
325 else
326 old_desc_blocks = fs->desc_blocks +
Theodore Ts'o4a2924e2008-04-19 10:30:59 -0400327 fs->super->s_reserved_gdt_blocks;
328
JP Abgralle0ed7402014-03-19 19:08:39 -0700329 count = 0;
330 cmp_block = fs->super->s_clusters_per_group;
331 if (group == (int)fs->group_desc_count - 1)
332 cmp_block = EXT2FS_NUM_B2C(fs,
333 ext2fs_group_blocks_count(fs, group));
334 }
Brian Behlendorf49e2df22007-03-28 12:07:41 -0400335
JP Abgralle0ed7402014-03-19 19:08:39 -0700336 bitmap = 0;
337 if (EQ_CLSTR(i, super_blk) ||
338 (old_desc_blk && old_desc_blocks &&
339 GE_CLSTR(i, old_desc_blk) &&
340 LE_CLSTR(i, old_desc_blk + old_desc_blocks-1)) ||
341 (new_desc_blk && EQ_CLSTR(i, new_desc_blk)) ||
342 EQ_CLSTR(i, ext2fs_block_bitmap_loc(fs, group)) ||
343 EQ_CLSTR(i, ext2fs_inode_bitmap_loc(fs, group)) ||
344 (GE_CLSTR(i, ext2fs_inode_table_loc(fs, group)) &&
345 LE_CLSTR(i, (ext2fs_inode_table_loc(fs, group) +
346 fs->inode_blocks_per_group - 1)))) {
347 bitmap = 1;
348 actual = (actual != 0);
349 count++;
350 cmp_block--;
351 } else if ((EXT2FS_B2C(fs, i) - count -
352 EXT2FS_B2C(fs, fs->super->s_first_data_block)) %
353 fs->super->s_clusters_per_group == 0) {
354 /*
355 * When the compare data blocks in block bitmap
356 * are 0, count the free block,
357 * skip the current block group.
358 */
359 if (ext2fs_test_block_bitmap_range2(
360 ctx->block_found_map,
361 EXT2FS_B2C(fs, i),
362 cmp_block)) {
363 /*
364 * -1 means to skip the current block
365 * group.
366 */
367 blocks = fs->super->s_clusters_per_group - 1;
368 group_free = cmp_block;
369 free_blocks += cmp_block;
370 /*
371 * The current block group's last block
372 * is set to i.
373 */
374 i += EXT2FS_C2B(fs, cmp_block - 1);
375 bitmap = 1;
376 goto do_counts;
377 }
378 }
379 } else if (redo_flag)
380 bitmap = actual;
381 else
382 bitmap = ext2fs_fast_test_block_bitmap2(fs->block_map, i);
383
384 if (!actual == !bitmap)
Theodore Ts'o3839e651997-04-26 13:21:57 +0000385 goto do_counts;
Theodore Ts'of5fa2002006-05-08 20:17:26 -0400386
Theodore Ts'o3839e651997-04-26 13:21:57 +0000387 if (!actual && bitmap) {
388 /*
389 * Block not used, but marked in use in the bitmap.
390 */
Theodore Ts'of1226322002-03-07 02:47:07 -0500391 problem = PR_5_BLOCK_UNUSED;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000392 } else {
393 /*
394 * Block used, but not marked in use in the bitmap.
395 */
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000396 problem = PR_5_BLOCK_USED;
Jose R. Santos49a73602007-10-21 21:04:03 -0500397
398 if (skip_group) {
399 struct problem_context pctx2;
400 pctx2.blk = i;
401 pctx2.group = group;
402 if (fix_problem(ctx, PR_5_BLOCK_UNINIT,&pctx2)){
JP Abgralle0ed7402014-03-19 19:08:39 -0700403 ext2fs_bg_flags_clear(fs, group, EXT2_BG_BLOCK_UNINIT);
Jose R. Santos49a73602007-10-21 21:04:03 -0500404 skip_group = 0;
405 }
406 }
Theodore Ts'o3839e651997-04-26 13:21:57 +0000407 }
Theodore Ts'of1226322002-03-07 02:47:07 -0500408 if (pctx.blk == NO_BLK) {
409 pctx.blk = pctx.blk2 = i;
410 save_problem = problem;
411 } else {
412 if ((problem == save_problem) &&
JP Abgralle0ed7402014-03-19 19:08:39 -0700413 (pctx.blk2 == i - EXT2FS_CLUSTER_RATIO(fs)))
414 pctx.blk2 += EXT2FS_CLUSTER_RATIO(fs);
Theodore Ts'of1226322002-03-07 02:47:07 -0500415 else {
416 print_bitmap_problem(ctx, save_problem, &pctx);
417 pctx.blk = pctx.blk2 = i;
418 save_problem = problem;
419 }
420 }
Theodore Ts'o5596def1999-07-19 15:27:37 +0000421 ctx->flags |= E2F_FLAG_PROG_SUPPRESS;
Theodore Ts'o63c49691998-02-20 05:24:59 +0000422 had_problem++;
Brian Behlendorf49e2df22007-03-28 12:07:41 -0400423
JP Abgralle0ed7402014-03-19 19:08:39 -0700424 /*
425 * If there a problem we should turn off the discard so we
426 * do not compromise the filesystem.
427 */
428 ctx->options &= ~E2F_OPT_DISCARD;
429
Theodore Ts'o3839e651997-04-26 13:21:57 +0000430 do_counts:
JP Abgralle0ed7402014-03-19 19:08:39 -0700431 if (!bitmap) {
Theodore Ts'o3839e651997-04-26 13:21:57 +0000432 group_free++;
433 free_blocks++;
JP Abgralle0ed7402014-03-19 19:08:39 -0700434 if (first_free > i)
435 first_free = i;
436 } else if (i > first_free) {
437 e2fsck_discard_blocks(ctx, first_free,
438 (i - first_free));
439 first_free = ext2fs_blocks_count(fs->super);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000440 }
441 blocks ++;
JP Abgralle0ed7402014-03-19 19:08:39 -0700442 if ((blocks == fs->super->s_clusters_per_group) ||
443 (EXT2FS_B2C(fs, i) ==
444 EXT2FS_B2C(fs, ext2fs_blocks_count(fs->super)-1))) {
445 /*
446 * If the last block of this group is free, then we can
447 * discard it as well.
448 */
449 if (!bitmap && i >= first_free)
450 e2fsck_discard_blocks(ctx, first_free,
451 (i - first_free) + 1);
452 next_group:
453 first_free = ext2fs_blocks_count(fs->super);
454
Theodore Ts'o3839e651997-04-26 13:21:57 +0000455 free_array[group] = group_free;
456 group ++;
457 blocks = 0;
458 group_free = 0;
Theodore Ts'of5fa2002006-05-08 20:17:26 -0400459 skip_group = 0;
Theodore Ts'oefac9a11998-05-07 05:02:00 +0000460 if (ctx->progress)
461 if ((ctx->progress)(ctx, 5, group,
462 fs->group_desc_count*2))
Brian Behlendorf49e2df22007-03-28 12:07:41 -0400463 goto errout;
Theodore Ts'o16b851c2008-04-20 23:33:34 -0400464 if (csum_flag &&
JP Abgralle0ed7402014-03-19 19:08:39 -0700465 (i != ext2fs_blocks_count(fs->super)-1) &&
466 ext2fs_bg_flags_test(fs, group,
467 EXT2_BG_BLOCK_UNINIT))
Theodore Ts'of5fa2002006-05-08 20:17:26 -0400468 skip_group++;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000469 }
470 }
Theodore Ts'of1226322002-03-07 02:47:07 -0500471 if (pctx.blk != NO_BLK)
472 print_bitmap_problem(ctx, save_problem, &pctx);
Theodore Ts'o63c49691998-02-20 05:24:59 +0000473 if (had_problem)
Theodore Ts'of1226322002-03-07 02:47:07 -0500474 fixit = end_problem_latch(ctx, PR_LATCH_BBITMAP);
Theodore Ts'o63c49691998-02-20 05:24:59 +0000475 else
476 fixit = -1;
Theodore Ts'o5596def1999-07-19 15:27:37 +0000477 ctx->flags &= ~E2F_FLAG_PROG_SUPPRESS;
Brian Behlendorf49e2df22007-03-28 12:07:41 -0400478
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000479 if (fixit == 1) {
480 ext2fs_free_block_bitmap(fs->block_map);
481 retval = ext2fs_copy_bitmap(ctx->block_found_map,
482 &fs->block_map);
Theodore Ts'obbd47d72000-06-10 19:21:33 +0000483 if (retval) {
484 clear_problem_context(&pctx);
485 fix_problem(ctx, PR_5_COPY_BBITMAP_ERROR, &pctx);
486 ctx->flags |= E2F_FLAG_ABORT;
Brian Behlendorf49e2df22007-03-28 12:07:41 -0400487 goto errout;
Theodore Ts'obbd47d72000-06-10 19:21:33 +0000488 }
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000489 ext2fs_set_bitmap_padding(fs->block_map);
490 ext2fs_mark_bb_dirty(fs);
Brian Behlendorf49e2df22007-03-28 12:07:41 -0400491
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000492 /* Redo the counts */
493 blocks = 0; free_blocks = 0; group_free = 0; group = 0;
494 memset(free_array, 0, fs->group_desc_count * sizeof(int));
JP Abgralle0ed7402014-03-19 19:08:39 -0700495 redo_flag++;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000496 goto redo_counts;
497 } else if (fixit == 0)
498 ext2fs_unmark_valid(fs);
499
JP Abgralle0ed7402014-03-19 19:08:39 -0700500 for (g = 0; g < fs->group_desc_count; g++) {
501 if (free_array[g] != ext2fs_bg_free_blocks_count(fs, g)) {
502 pctx.group = g;
503 pctx.blk = ext2fs_bg_free_blocks_count(fs, g);
504 pctx.blk2 = free_array[g];
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000505
506 if (fix_problem(ctx, PR_5_FREE_BLOCK_COUNT_GROUP,
507 &pctx)) {
JP Abgralle0ed7402014-03-19 19:08:39 -0700508 ext2fs_bg_free_blocks_count_set(fs, g, free_array[g]);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000509 ext2fs_mark_super_dirty(fs);
510 } else
511 ext2fs_unmark_valid(fs);
512 }
513 }
JP Abgralle0ed7402014-03-19 19:08:39 -0700514 free_blocks = EXT2FS_C2B(fs, free_blocks);
515 if (free_blocks != ext2fs_free_blocks_count(fs->super)) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000516 pctx.group = 0;
JP Abgralle0ed7402014-03-19 19:08:39 -0700517 pctx.blk = ext2fs_free_blocks_count(fs->super);
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000518 pctx.blk2 = free_blocks;
519
520 if (fix_problem(ctx, PR_5_FREE_BLOCK_COUNT, &pctx)) {
JP Abgralle0ed7402014-03-19 19:08:39 -0700521 ext2fs_free_blocks_count_set(fs->super, free_blocks);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000522 ext2fs_mark_super_dirty(fs);
JP Abgralle0ed7402014-03-19 19:08:39 -0700523 }
Theodore Ts'o3839e651997-04-26 13:21:57 +0000524 }
Brian Behlendorf49e2df22007-03-28 12:07:41 -0400525errout:
Theodore Ts'oc4e3d3f2003-08-01 09:41:07 -0400526 ext2fs_free_mem(&free_array);
JP Abgralle0ed7402014-03-19 19:08:39 -0700527 ext2fs_free_mem(&actual_buf);
528 ext2fs_free_mem(&bitmap_buf);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000529}
Brian Behlendorf49e2df22007-03-28 12:07:41 -0400530
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000531static void check_inode_bitmaps(e2fsck_t ctx)
Theodore Ts'o3839e651997-04-26 13:21:57 +0000532{
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000533 ext2_filsys fs = ctx->fs;
Theodore Ts'o86c627e2001-01-11 15:12:14 +0000534 ext2_ino_t i;
Theodore Ts'o54434922003-12-07 01:28:50 -0500535 unsigned int free_inodes = 0;
536 int group_free = 0;
537 int dirs_count = 0;
JP Abgralle0ed7402014-03-19 19:08:39 -0700538 dgrp_t group = 0;
Theodore Ts'o54434922003-12-07 01:28:50 -0500539 unsigned int inodes = 0;
JP Abgralle0ed7402014-03-19 19:08:39 -0700540 ext2_ino_t *free_array;
541 ext2_ino_t *dir_array;
Theodore Ts'o54434922003-12-07 01:28:50 -0500542 int actual, bitmap;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000543 errcode_t retval;
544 struct problem_context pctx;
JP Abgralle0ed7402014-03-19 19:08:39 -0700545 problem_t problem, save_problem;
546 int fixit, had_problem;
Theodore Ts'o16b851c2008-04-20 23:33:34 -0400547 int csum_flag;
Theodore Ts'of5fa2002006-05-08 20:17:26 -0400548 int skip_group = 0;
JP Abgralle0ed7402014-03-19 19:08:39 -0700549 int redo_flag = 0;
550 ext2_ino_t first_free = fs->super->s_inodes_per_group + 1;
Brian Behlendorf49e2df22007-03-28 12:07:41 -0400551
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000552 clear_problem_context(&pctx);
JP Abgralle0ed7402014-03-19 19:08:39 -0700553 free_array = (ext2_ino_t *) e2fsck_allocate_memory(ctx,
554 fs->group_desc_count * sizeof(ext2_ino_t), "free inode count array");
Brian Behlendorf49e2df22007-03-28 12:07:41 -0400555
JP Abgralle0ed7402014-03-19 19:08:39 -0700556 dir_array = (ext2_ino_t *) e2fsck_allocate_memory(ctx,
557 fs->group_desc_count * sizeof(ext2_ino_t), "directory count array");
Brian Behlendorf49e2df22007-03-28 12:07:41 -0400558
JP Abgralle0ed7402014-03-19 19:08:39 -0700559 if ((1 < ext2fs_get_inode_bitmap_start2(ctx->inode_used_map)) ||
Brian Behlendorf49e2df22007-03-28 12:07:41 -0400560 (fs->super->s_inodes_count >
JP Abgralle0ed7402014-03-19 19:08:39 -0700561 ext2fs_get_inode_bitmap_end2(ctx->inode_used_map))) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000562 pctx.num = 3;
563 pctx.blk = 1;
564 pctx.blk2 = fs->super->s_inodes_count;
JP Abgralle0ed7402014-03-19 19:08:39 -0700565 pctx.ino = ext2fs_get_inode_bitmap_start2(ctx->inode_used_map);
566 pctx.ino2 = ext2fs_get_inode_bitmap_end2(ctx->inode_used_map);
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000567 fix_problem(ctx, PR_5_BMAP_ENDPOINTS, &pctx);
Theodore Ts'o08b21301997-11-03 19:42:40 +0000568
569 ctx->flags |= E2F_FLAG_ABORT; /* fatal */
Brian Behlendorf49e2df22007-03-28 12:07:41 -0400570 goto errout;
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000571 }
JP Abgralle0ed7402014-03-19 19:08:39 -0700572 if ((1 < ext2fs_get_inode_bitmap_start2(fs->inode_map)) ||
Brian Behlendorf49e2df22007-03-28 12:07:41 -0400573 (fs->super->s_inodes_count >
JP Abgralle0ed7402014-03-19 19:08:39 -0700574 ext2fs_get_inode_bitmap_end2(fs->inode_map))) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000575 pctx.num = 4;
576 pctx.blk = 1;
577 pctx.blk2 = fs->super->s_inodes_count;
JP Abgralle0ed7402014-03-19 19:08:39 -0700578 pctx.ino = ext2fs_get_inode_bitmap_start2(fs->inode_map);
579 pctx.ino2 = ext2fs_get_inode_bitmap_end2(fs->inode_map);
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000580 fix_problem(ctx, PR_5_BMAP_ENDPOINTS, &pctx);
Theodore Ts'o08b21301997-11-03 19:42:40 +0000581
582 ctx->flags |= E2F_FLAG_ABORT; /* fatal */
Brian Behlendorf49e2df22007-03-28 12:07:41 -0400583 goto errout;
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000584 }
585
Jose R. Santos49a73602007-10-21 21:04:03 -0500586 csum_flag = EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
587 EXT4_FEATURE_RO_COMPAT_GDT_CSUM);
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000588redo_counts:
Theodore Ts'o63c49691998-02-20 05:24:59 +0000589 had_problem = 0;
Theodore Ts'of1226322002-03-07 02:47:07 -0500590 save_problem = 0;
591 pctx.ino = pctx.ino2 = 0;
Theodore Ts'o16b851c2008-04-20 23:33:34 -0400592 if (csum_flag &&
JP Abgralle0ed7402014-03-19 19:08:39 -0700593 (ext2fs_bg_flags_test(fs, group, EXT2_BG_INODE_UNINIT)))
Theodore Ts'of5fa2002006-05-08 20:17:26 -0400594 skip_group++;
595
Eric Sandeen5830d6b2006-08-30 02:16:55 -0400596 /* Protect loop from wrap-around if inodes_count is maxed */
597 for (i = 1; i <= fs->super->s_inodes_count && i > 0; i++) {
JP Abgralle0ed7402014-03-19 19:08:39 -0700598 bitmap = 0;
599 if (skip_group &&
600 i % fs->super->s_inodes_per_group == 1) {
601 /*
602 * Current inode is the first inode
603 * in the current block group.
604 */
605 if (ext2fs_test_inode_bitmap_range(
606 ctx->inode_used_map, i,
607 fs->super->s_inodes_per_group)) {
608 /*
609 * When the compared inodes in inodes bitmap
610 * are 0, count the free inode,
611 * skip the current block group.
612 */
613 first_free = 1;
614 inodes = fs->super->s_inodes_per_group - 1;
615 group_free = inodes;
616 free_inodes += inodes;
617 i += inodes;
618 skip_group = 0;
619 goto do_counts;
620 }
621 }
622
623 actual = ext2fs_fast_test_inode_bitmap2(ctx->inode_used_map, i);
624 if (redo_flag)
625 bitmap = actual;
626 else if (!skip_group)
627 bitmap = ext2fs_fast_test_inode_bitmap2(fs->inode_map, i);
628 if (!actual == !bitmap)
Theodore Ts'o3839e651997-04-26 13:21:57 +0000629 goto do_counts;
Brian Behlendorf49e2df22007-03-28 12:07:41 -0400630
Theodore Ts'o3839e651997-04-26 13:21:57 +0000631 if (!actual && bitmap) {
632 /*
633 * Inode wasn't used, but marked in bitmap
634 */
Theodore Ts'of1226322002-03-07 02:47:07 -0500635 problem = PR_5_INODE_UNUSED;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000636 } else /* if (actual && !bitmap) */ {
Theodore Ts'o3839e651997-04-26 13:21:57 +0000637 /*
638 * Inode used, but not in bitmap
639 */
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000640 problem = PR_5_INODE_USED;
Jose R. Santos49a73602007-10-21 21:04:03 -0500641
642 /* We should never hit this, because it means that
643 * inodes were marked in use that weren't noticed
644 * in pass1 or pass 2. It is easier to fix the problem
645 * than to kill e2fsck and leave the user stuck. */
646 if (skip_group) {
647 struct problem_context pctx2;
648 pctx2.blk = i;
649 pctx2.group = group;
650 if (fix_problem(ctx, PR_5_INODE_UNINIT,&pctx2)){
JP Abgralle0ed7402014-03-19 19:08:39 -0700651 ext2fs_bg_flags_clear(fs, group, EXT2_BG_INODE_UNINIT);
Jose R. Santos49a73602007-10-21 21:04:03 -0500652 skip_group = 0;
653 }
654 }
Theodore Ts'o3839e651997-04-26 13:21:57 +0000655 }
Theodore Ts'of1226322002-03-07 02:47:07 -0500656 if (pctx.ino == 0) {
657 pctx.ino = pctx.ino2 = i;
658 save_problem = problem;
659 } else {
660 if ((problem == save_problem) &&
661 (pctx.ino2 == i-1))
662 pctx.ino2++;
663 else {
664 print_bitmap_problem(ctx, save_problem, &pctx);
665 pctx.ino = pctx.ino2 = i;
666 save_problem = problem;
667 }
668 }
Theodore Ts'o5596def1999-07-19 15:27:37 +0000669 ctx->flags |= E2F_FLAG_PROG_SUPPRESS;
Theodore Ts'o63c49691998-02-20 05:24:59 +0000670 had_problem++;
JP Abgralle0ed7402014-03-19 19:08:39 -0700671 /*
672 * If there a problem we should turn off the discard so we
673 * do not compromise the filesystem.
674 */
675 ctx->options &= ~E2F_OPT_DISCARD;
Brian Behlendorf49e2df22007-03-28 12:07:41 -0400676
Theodore Ts'o3839e651997-04-26 13:21:57 +0000677do_counts:
JP Abgralle0ed7402014-03-19 19:08:39 -0700678 inodes++;
Theodore Ts'of5fa2002006-05-08 20:17:26 -0400679 if (bitmap) {
JP Abgralle0ed7402014-03-19 19:08:39 -0700680 if (ext2fs_test_inode_bitmap2(ctx->inode_dir_map, i))
Theodore Ts'o3839e651997-04-26 13:21:57 +0000681 dirs_count++;
JP Abgralle0ed7402014-03-19 19:08:39 -0700682 if (inodes > first_free) {
683 e2fsck_discard_inodes(ctx, group, first_free,
684 inodes - first_free);
685 first_free = fs->super->s_inodes_per_group + 1;
686 }
687 } else {
Theodore Ts'of5fa2002006-05-08 20:17:26 -0400688 group_free++;
689 free_inodes++;
JP Abgralle0ed7402014-03-19 19:08:39 -0700690 if (first_free > inodes)
691 first_free = inodes;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000692 }
JP Abgralle0ed7402014-03-19 19:08:39 -0700693
Theodore Ts'o3839e651997-04-26 13:21:57 +0000694 if ((inodes == fs->super->s_inodes_per_group) ||
695 (i == fs->super->s_inodes_count)) {
JP Abgralle0ed7402014-03-19 19:08:39 -0700696 /*
697 * If the last inode is free, we can discard it as well.
698 */
699 if (!bitmap && inodes >= first_free)
700 e2fsck_discard_inodes(ctx, group, first_free,
701 inodes - first_free + 1);
702 /*
703 * If discard zeroes data and the group inode table
704 * was not zeroed yet, set itable as zeroed
705 */
706 if ((ctx->options & E2F_OPT_DISCARD) &&
707 io_channel_discard_zeroes_data(fs->io) &&
708 !(ext2fs_bg_flags_test(fs, group,
709 EXT2_BG_INODE_ZEROED))) {
710 ext2fs_bg_flags_set(fs, group,
711 EXT2_BG_INODE_ZEROED);
712 ext2fs_group_desc_csum_set(fs, group);
713 }
714
715 first_free = fs->super->s_inodes_per_group + 1;
Lukas Czerner57581c12012-03-11 12:55:45 -0400716 free_array[group] = group_free;
717 dir_array[group] = dirs_count;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000718 group ++;
719 inodes = 0;
Theodore Ts'of5fa2002006-05-08 20:17:26 -0400720 skip_group = 0;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000721 group_free = 0;
722 dirs_count = 0;
Theodore Ts'oefac9a11998-05-07 05:02:00 +0000723 if (ctx->progress)
724 if ((ctx->progress)(ctx, 5,
725 group + fs->group_desc_count,
726 fs->group_desc_count*2))
Brian Behlendorf49e2df22007-03-28 12:07:41 -0400727 goto errout;
Theodore Ts'o16b851c2008-04-20 23:33:34 -0400728 if (csum_flag &&
Theodore Ts'of5fa2002006-05-08 20:17:26 -0400729 (i != fs->super->s_inodes_count) &&
JP Abgralle0ed7402014-03-19 19:08:39 -0700730 (ext2fs_bg_flags_test(fs, group, EXT2_BG_INODE_UNINIT)
731 ))
Theodore Ts'of5fa2002006-05-08 20:17:26 -0400732 skip_group++;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000733 }
734 }
Theodore Ts'of1226322002-03-07 02:47:07 -0500735 if (pctx.ino)
736 print_bitmap_problem(ctx, save_problem, &pctx);
Brian Behlendorf49e2df22007-03-28 12:07:41 -0400737
Theodore Ts'o63c49691998-02-20 05:24:59 +0000738 if (had_problem)
739 fixit = end_problem_latch(ctx, PR_LATCH_IBITMAP);
740 else
741 fixit = -1;
Theodore Ts'o5596def1999-07-19 15:27:37 +0000742 ctx->flags &= ~E2F_FLAG_PROG_SUPPRESS;
Brian Behlendorf49e2df22007-03-28 12:07:41 -0400743
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000744 if (fixit == 1) {
745 ext2fs_free_inode_bitmap(fs->inode_map);
746 retval = ext2fs_copy_bitmap(ctx->inode_used_map,
747 &fs->inode_map);
Theodore Ts'obbd47d72000-06-10 19:21:33 +0000748 if (retval) {
749 clear_problem_context(&pctx);
750 fix_problem(ctx, PR_5_COPY_IBITMAP_ERROR, &pctx);
751 ctx->flags |= E2F_FLAG_ABORT;
Brian Behlendorf49e2df22007-03-28 12:07:41 -0400752 goto errout;
Theodore Ts'obbd47d72000-06-10 19:21:33 +0000753 }
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000754 ext2fs_set_bitmap_padding(fs->inode_map);
755 ext2fs_mark_ib_dirty(fs);
756
757 /* redo counts */
758 inodes = 0; free_inodes = 0; group_free = 0;
759 dirs_count = 0; group = 0;
760 memset(free_array, 0, fs->group_desc_count * sizeof(int));
761 memset(dir_array, 0, fs->group_desc_count * sizeof(int));
JP Abgralle0ed7402014-03-19 19:08:39 -0700762 redo_flag++;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000763 goto redo_counts;
764 } else if (fixit == 0)
765 ext2fs_unmark_valid(fs);
Brian Behlendorf49e2df22007-03-28 12:07:41 -0400766
Theodore Ts'o3839e651997-04-26 13:21:57 +0000767 for (i = 0; i < fs->group_desc_count; i++) {
JP Abgralle0ed7402014-03-19 19:08:39 -0700768 if (free_array[i] != ext2fs_bg_free_inodes_count(fs, i)) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000769 pctx.group = i;
JP Abgralle0ed7402014-03-19 19:08:39 -0700770 pctx.ino = ext2fs_bg_free_inodes_count(fs, i);
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000771 pctx.ino2 = free_array[i];
772 if (fix_problem(ctx, PR_5_FREE_INODE_COUNT_GROUP,
773 &pctx)) {
JP Abgralle0ed7402014-03-19 19:08:39 -0700774 ext2fs_bg_free_inodes_count_set(fs, i, free_array[i]);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000775 ext2fs_mark_super_dirty(fs);
776 } else
777 ext2fs_unmark_valid(fs);
778 }
JP Abgralle0ed7402014-03-19 19:08:39 -0700779 if (dir_array[i] != ext2fs_bg_used_dirs_count(fs, i)) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000780 pctx.group = i;
JP Abgralle0ed7402014-03-19 19:08:39 -0700781 pctx.ino = ext2fs_bg_used_dirs_count(fs, i);
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000782 pctx.ino2 = dir_array[i];
783
784 if (fix_problem(ctx, PR_5_FREE_DIR_COUNT_GROUP,
785 &pctx)) {
JP Abgralle0ed7402014-03-19 19:08:39 -0700786 ext2fs_bg_used_dirs_count_set(fs, i, dir_array[i]);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000787 ext2fs_mark_super_dirty(fs);
788 } else
789 ext2fs_unmark_valid(fs);
790 }
791 }
792 if (free_inodes != fs->super->s_free_inodes_count) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000793 pctx.group = -1;
794 pctx.ino = fs->super->s_free_inodes_count;
795 pctx.ino2 = free_inodes;
796
797 if (fix_problem(ctx, PR_5_FREE_INODE_COUNT, &pctx)) {
Theodore Ts'o3839e651997-04-26 13:21:57 +0000798 fs->super->s_free_inodes_count = free_inodes;
799 ext2fs_mark_super_dirty(fs);
JP Abgralle0ed7402014-03-19 19:08:39 -0700800 }
Theodore Ts'o3839e651997-04-26 13:21:57 +0000801 }
Brian Behlendorf49e2df22007-03-28 12:07:41 -0400802errout:
Theodore Ts'oc4e3d3f2003-08-01 09:41:07 -0400803 ext2fs_free_mem(&free_array);
804 ext2fs_free_mem(&dir_array);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000805}
806
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000807static void check_inode_end(e2fsck_t ctx)
Theodore Ts'o3839e651997-04-26 13:21:57 +0000808{
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000809 ext2_filsys fs = ctx->fs;
Theodore Ts'o86c627e2001-01-11 15:12:14 +0000810 ext2_ino_t end, save_inodes_count, i;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000811 struct problem_context pctx;
812
813 clear_problem_context(&pctx);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000814
815 end = EXT2_INODES_PER_GROUP(fs->super) * fs->group_desc_count;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000816 pctx.errcode = ext2fs_fudge_inode_bitmap_end(fs->inode_map, end,
817 &save_inodes_count);
818 if (pctx.errcode) {
819 pctx.num = 1;
820 fix_problem(ctx, PR_5_FUDGE_BITMAP_ERROR, &pctx);
Theodore Ts'o08b21301997-11-03 19:42:40 +0000821 ctx->flags |= E2F_FLAG_ABORT; /* fatal */
822 return;
Theodore Ts'of3db3561997-04-26 13:34:30 +0000823 }
Theodore Ts'o3839e651997-04-26 13:21:57 +0000824 if (save_inodes_count == end)
825 return;
Eric Sandeen5830d6b2006-08-30 02:16:55 -0400826
Theodore Ts'oefc6f622008-08-27 23:07:54 -0400827 /* protect loop from wrap-around if end is maxed */
Eric Sandeen5830d6b2006-08-30 02:16:55 -0400828 for (i = save_inodes_count + 1; i <= end && i > save_inodes_count; i++) {
Theodore Ts'of3db3561997-04-26 13:34:30 +0000829 if (!ext2fs_test_inode_bitmap(fs->inode_map, i)) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000830 if (fix_problem(ctx, PR_5_INODE_BMAP_PADDING, &pctx)) {
Kazuya Mio01ec1262009-07-06 17:15:24 +0900831 for (; i <= end; i++)
Theodore Ts'of3db3561997-04-26 13:34:30 +0000832 ext2fs_mark_inode_bitmap(fs->inode_map,
Theodore Ts'o3839e651997-04-26 13:21:57 +0000833 i);
834 ext2fs_mark_ib_dirty(fs);
835 } else
836 ext2fs_unmark_valid(fs);
837 break;
838 }
839 }
840
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000841 pctx.errcode = ext2fs_fudge_inode_bitmap_end(fs->inode_map,
842 save_inodes_count, 0);
843 if (pctx.errcode) {
844 pctx.num = 2;
845 fix_problem(ctx, PR_5_FUDGE_BITMAP_ERROR, &pctx);
Theodore Ts'o08b21301997-11-03 19:42:40 +0000846 ctx->flags |= E2F_FLAG_ABORT; /* fatal */
847 return;
Theodore Ts'of3db3561997-04-26 13:34:30 +0000848 }
Theodore Ts'o3839e651997-04-26 13:21:57 +0000849}
850
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000851static void check_block_end(e2fsck_t ctx)
Theodore Ts'o3839e651997-04-26 13:21:57 +0000852{
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000853 ext2_filsys fs = ctx->fs;
JP Abgralle0ed7402014-03-19 19:08:39 -0700854 blk64_t end, save_blocks_count, i;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000855 struct problem_context pctx;
856
857 clear_problem_context(&pctx);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000858
JP Abgralle0ed7402014-03-19 19:08:39 -0700859 end = ext2fs_get_block_bitmap_start2(fs->block_map) +
860 ((blk64_t)EXT2_CLUSTERS_PER_GROUP(fs->super) * fs->group_desc_count) - 1;
861 pctx.errcode = ext2fs_fudge_block_bitmap_end2(fs->block_map, end,
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000862 &save_blocks_count);
863 if (pctx.errcode) {
864 pctx.num = 3;
865 fix_problem(ctx, PR_5_FUDGE_BITMAP_ERROR, &pctx);
Theodore Ts'o08b21301997-11-03 19:42:40 +0000866 ctx->flags |= E2F_FLAG_ABORT; /* fatal */
867 return;
Theodore Ts'of3db3561997-04-26 13:34:30 +0000868 }
Theodore Ts'o3839e651997-04-26 13:21:57 +0000869 if (save_blocks_count == end)
870 return;
Eric Sandeen5830d6b2006-08-30 02:16:55 -0400871
Theodore Ts'oefc6f622008-08-27 23:07:54 -0400872 /* Protect loop from wrap-around if end is maxed */
Eric Sandeen5830d6b2006-08-30 02:16:55 -0400873 for (i = save_blocks_count + 1; i <= end && i > save_blocks_count; i++) {
JP Abgralle0ed7402014-03-19 19:08:39 -0700874 if (!ext2fs_test_block_bitmap2(fs->block_map,
875 EXT2FS_C2B(fs, i))) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000876 if (fix_problem(ctx, PR_5_BLOCK_BMAP_PADDING, &pctx)) {
Kazuya Mio01ec1262009-07-06 17:15:24 +0900877 for (; i <= end; i++)
JP Abgralle0ed7402014-03-19 19:08:39 -0700878 ext2fs_mark_block_bitmap2(fs->block_map,
879 EXT2FS_C2B(fs, i));
Theodore Ts'o3839e651997-04-26 13:21:57 +0000880 ext2fs_mark_bb_dirty(fs);
881 } else
882 ext2fs_unmark_valid(fs);
883 break;
884 }
885 }
886
JP Abgralle0ed7402014-03-19 19:08:39 -0700887 pctx.errcode = ext2fs_fudge_block_bitmap_end2(fs->block_map,
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000888 save_blocks_count, 0);
889 if (pctx.errcode) {
890 pctx.num = 4;
891 fix_problem(ctx, PR_5_FUDGE_BITMAP_ERROR, &pctx);
Theodore Ts'o08b21301997-11-03 19:42:40 +0000892 ctx->flags |= E2F_FLAG_ABORT; /* fatal */
893 return;
Theodore Ts'of3db3561997-04-26 13:34:30 +0000894 }
Theodore Ts'o3839e651997-04-26 13:21:57 +0000895}
896
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000897
898