blob: bc9a32a321e08ab286fd516cb2e0fe1310e76c4a [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
Theodore Ts'od1154eb2011-09-18 17:34:37 -040013#include "config.h"
Lukas Czernerefa1a352010-11-18 03:38:38 +000014#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
Theodore Ts'o3839e651997-04-26 13:21:57 +000021#include "e2fsck.h"
Theodore Ts'o1b6bf171997-10-03 17:48:10 +000022#include "problem.h"
Theodore Ts'o3839e651997-04-26 13:21:57 +000023
Lukas Czernerefa1a352010-11-18 03:38:38 +000024#define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d))
25
Theodore Ts'o1b6bf171997-10-03 17:48:10 +000026static 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);
Theodore Ts'o3839e651997-04-26 13:21:57 +000030
Theodore Ts'o08b21301997-11-03 19:42:40 +000031void e2fsck_pass5(e2fsck_t ctx)
Theodore Ts'o3839e651997-04-26 13:21:57 +000032{
Theodore Ts'o8bf191e1997-10-20 01:38:32 +000033#ifdef RESOURCE_TRACK
Theodore Ts'o3839e651997-04-26 13:21:57 +000034 struct resource_track rtrack;
Theodore Ts'o8bf191e1997-10-20 01:38:32 +000035#endif
Theodore Ts'o1b6bf171997-10-03 17:48:10 +000036 struct problem_context pctx;
Theodore Ts'oefc6f622008-08-27 23:07:54 -040037
Theodore Ts'o3839e651997-04-26 13:21:57 +000038#ifdef MTRACE
39 mtrace_print("Pass 5");
40#endif
41
Theodore Ts'o6d96b002007-08-03 20:07:09 -040042 init_resource_track(&rtrack, ctx->fs->io);
Theodore Ts'o1b6bf171997-10-03 17:48:10 +000043 clear_problem_context(&pctx);
Theodore Ts'o3839e651997-04-26 13:21:57 +000044
Theodore Ts'o1b6bf171997-10-03 17:48:10 +000045 if (!(ctx->options & E2F_OPT_PREEN))
46 fix_problem(ctx, PR_5_PASS_HEADER, &pctx);
Theodore Ts'o3839e651997-04-26 13:21:57 +000047
Theodore Ts'of8188ff1997-11-14 05:23:04 +000048 if (ctx->progress)
Theodore Ts'oefac9a11998-05-07 05:02:00 +000049 if ((ctx->progress)(ctx, 5, 0, ctx->fs->group_desc_count*2))
Theodore Ts'oa02ce9d1998-02-24 20:22:23 +000050 return;
Theodore Ts'of8188ff1997-11-14 05:23:04 +000051
52 e2fsck_read_bitmaps(ctx);
53
Theodore Ts'o1b6bf171997-10-03 17:48:10 +000054 check_block_bitmaps(ctx);
Theodore Ts'oa02ce9d1998-02-24 20:22:23 +000055 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
Theodore Ts'o08b21301997-11-03 19:42:40 +000056 return;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +000057 check_inode_bitmaps(ctx);
Theodore Ts'oa02ce9d1998-02-24 20:22:23 +000058 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
Theodore Ts'o08b21301997-11-03 19:42:40 +000059 return;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +000060 check_inode_end(ctx);
Theodore Ts'oa02ce9d1998-02-24 20:22:23 +000061 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
Theodore Ts'o08b21301997-11-03 19:42:40 +000062 return;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +000063 check_block_end(ctx);
Theodore Ts'oa02ce9d1998-02-24 20:22:23 +000064 if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
Theodore Ts'o08b21301997-11-03 19:42:40 +000065 return;
Theodore Ts'o3839e651997-04-26 13:21:57 +000066
Theodore Ts'o1b6bf171997-10-03 17:48:10 +000067 ext2fs_free_inode_bitmap(ctx->inode_used_map);
68 ctx->inode_used_map = 0;
69 ext2fs_free_inode_bitmap(ctx->inode_dir_map);
70 ctx->inode_dir_map = 0;
71 ext2fs_free_block_bitmap(ctx->block_found_map);
72 ctx->block_found_map = 0;
73
Ken Chen9facd072009-05-28 09:55:10 -040074 print_resource_track(ctx, _("Pass 5"), &rtrack, ctx->fs->io);
Theodore Ts'o3839e651997-04-26 13:21:57 +000075}
76
Lukas Czerner46795322012-03-11 13:39:45 -040077static void e2fsck_discard_blocks(e2fsck_t ctx, blk64_t start,
78 blk64_t count)
Lukas Czernerefa1a352010-11-18 03:38:38 +000079{
80 ext2_filsys fs = ctx->fs;
Lukas Czernerefa1a352010-11-18 03:38:38 +000081
82 /*
83 * If the filesystem has changed it means that there was an corruption
84 * which should be repaired, but in some cases just one e2fsck run is
85 * not enough to fix the problem, hence it is not safe to run discard
86 * in this case.
87 */
Lukas Czerner46795322012-03-11 13:39:45 -040088 if (ext2fs_test_changed(fs))
Lukas Czernerefa1a352010-11-18 03:38:38 +000089 ctx->options &= ~E2F_OPT_DISCARD;
90
Lukas Czernerf0fe5da2012-03-11 15:35:06 -040091 if ((ctx->options & E2F_OPT_DISCARD) &&
Lukas Czernerefa1a352010-11-18 03:38:38 +000092 (io_channel_discard(fs->io, start, count)))
93 ctx->options &= ~E2F_OPT_DISCARD;
94}
95
Lukas Czerner57581c12012-03-11 12:55:45 -040096/*
97 * This will try to discard number 'count' inodes starting at
98 * inode number 'start' within the 'group'. Note that 'start'
99 * is 1-based, it means that we need to adjust it by -1 in this
100 * function to compute right offset in the particular inode table.
101 */
Theodore Ts'oe64e6762012-04-05 12:13:05 -0700102static void e2fsck_discard_inodes(e2fsck_t ctx, dgrp_t group,
103 ext2_ino_t start, int count)
Lukas Czerner57581c12012-03-11 12:55:45 -0400104{
105 ext2_filsys fs = ctx->fs;
106 blk64_t blk, num;
Lukas Czerner57581c12012-03-11 12:55:45 -0400107
108 /*
109 * Sanity check for 'start'
110 */
111 if ((start < 1) || (start > EXT2_INODES_PER_GROUP(fs->super))) {
112 printf("PROGRAMMING ERROR: Got start %d outside of group %d!"
113 " Disabling discard\n",
114 start, group);
115 ctx->options &= ~E2F_OPT_DISCARD;
116 }
117
Lukas Czernerc15386c2012-03-11 15:36:45 -0400118 /*
119 * Do not attempt to discard if E2F_OPT_DISCARD is not set. And also
120 * skip the discard on this group if discard does not zero data.
121 * The reason is that if the inode table is not zeroed discard would
122 * no help us since we need to zero it anyway, or if the inode table
123 * is zeroed then the read after discard would not be deterministic
124 * anyway and we would not be able to assume that this inode table
125 * was zeroed anymore so we would have to zero it again, which does
126 * not really make sense.
127 */
128 if (!(ctx->options & E2F_OPT_DISCARD) ||
129 !io_channel_discard_zeroes_data(fs->io))
Lukas Czerner57581c12012-03-11 12:55:45 -0400130 return;
131
132 /*
133 * Start is inode number within the group which starts
134 * counting from 1, so we need to adjust it.
135 */
136 start -= 1;
137
138 /*
139 * We can discard only blocks containing only unused
140 * inodes in the table.
141 */
142 blk = DIV_ROUND_UP(start,
143 EXT2_INODES_PER_BLOCK(fs->super));
144 count -= (blk * EXT2_INODES_PER_BLOCK(fs->super) - start);
145 blk += ext2fs_inode_table_loc(fs, group);
146 num = count / EXT2_INODES_PER_BLOCK(fs->super);
147
148 if (num > 0)
Lukas Czerner46795322012-03-11 13:39:45 -0400149 e2fsck_discard_blocks(ctx, blk, num);
Lukas Czerner57581c12012-03-11 12:55:45 -0400150}
151
Valerie Aurora Henson6dc64392010-06-13 17:00:00 -0400152#define NO_BLK ((blk64_t) -1)
Theodore Ts'of1226322002-03-07 02:47:07 -0500153
Theodore Ts'o3c7c6d72013-12-02 20:52:43 -0500154static void print_bitmap_problem(e2fsck_t ctx, problem_t problem,
Theodore Ts'of1226322002-03-07 02:47:07 -0500155 struct problem_context *pctx)
156{
157 switch (problem) {
158 case PR_5_BLOCK_UNUSED:
159 if (pctx->blk == pctx->blk2)
160 pctx->blk2 = 0;
161 else
162 problem = PR_5_BLOCK_RANGE_UNUSED;
163 break;
164 case PR_5_BLOCK_USED:
165 if (pctx->blk == pctx->blk2)
166 pctx->blk2 = 0;
167 else
168 problem = PR_5_BLOCK_RANGE_USED;
169 break;
170 case PR_5_INODE_UNUSED:
171 if (pctx->ino == pctx->ino2)
172 pctx->ino2 = 0;
173 else
174 problem = PR_5_INODE_RANGE_UNUSED;
175 break;
176 case PR_5_INODE_USED:
177 if (pctx->ino == pctx->ino2)
178 pctx->ino2 = 0;
179 else
180 problem = PR_5_INODE_RANGE_USED;
181 break;
182 }
183 fix_problem(ctx, problem, pctx);
184 pctx->blk = pctx->blk2 = NO_BLK;
185 pctx->ino = pctx->ino2 = 0;
186}
Brian Behlendorf49e2df22007-03-28 12:07:41 -0400187
Theodore Ts'o3385a252011-06-15 22:15:34 -0400188/* Just to be more succint */
189#define B2C(x) EXT2FS_B2C(fs, (x))
190#define EQ_CLSTR(x, y) (B2C(x) == B2C(y))
191#define LE_CLSTR(x, y) (B2C(x) <= B2C(y))
192#define GE_CLSTR(x, y) (B2C(x) >= B2C(y))
193
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000194static void check_block_bitmaps(e2fsck_t ctx)
Theodore Ts'o3839e651997-04-26 13:21:57 +0000195{
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000196 ext2_filsys fs = ctx->fs;
Jose R. Santos20f2ccb2009-07-11 21:29:30 -0400197 blk64_t i;
Theodore Ts'oe64e6762012-04-05 12:13:05 -0700198 unsigned int *free_array;
Theodore Ts'o3971bfe2013-12-02 23:21:31 -0500199 dgrp_t g, group = 0;
Theodore Ts'oe64e6762012-04-05 12:13:05 -0700200 unsigned int blocks = 0;
Valerie Aurora Henson6dc64392010-06-13 17:00:00 -0400201 blk64_t free_blocks = 0;
Lukas Czernerefa1a352010-11-18 03:38:38 +0000202 blk64_t first_free = ext2fs_blocks_count(fs->super);
Theodore Ts'oe64e6762012-04-05 12:13:05 -0700203 unsigned int group_free = 0;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000204 int actual, bitmap;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000205 struct problem_context pctx;
Theodore Ts'o3c7c6d72013-12-02 20:52:43 -0500206 problem_t problem, save_problem;
207 int fixit, had_problem;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000208 errcode_t retval;
Kazuya Mio479463a2009-07-09 13:46:59 -0400209 int old_desc_blocks = 0;
210 int count = 0;
211 int cmp_block = 0;
212 int redo_flag = 0;
Jose R. Santos20f2ccb2009-07-11 21:29:30 -0400213 blk64_t super_blk, old_desc_blk, new_desc_blk;
Theodore Ts'o53e31202012-11-24 19:17:44 -0500214 char *actual_buf, *bitmap_buf;
215
216 actual_buf = (char *) e2fsck_allocate_memory(ctx, fs->blocksize,
217 "actual bitmap buffer");
218 bitmap_buf = (char *) e2fsck_allocate_memory(ctx, fs->blocksize,
219 "bitmap block buffer");
Brian Behlendorf49e2df22007-03-28 12:07:41 -0400220
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000221 clear_problem_context(&pctx);
Theodore Ts'oe64e6762012-04-05 12:13:05 -0700222 free_array = (unsigned int *) e2fsck_allocate_memory(ctx,
223 fs->group_desc_count * sizeof(unsigned int), "free block count array");
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000224
Theodore Ts'o3385a252011-06-15 22:15:34 -0400225 if ((B2C(fs->super->s_first_data_block) <
Valerie Aurora Hensonc5d2f502009-08-22 22:29:02 -0400226 ext2fs_get_block_bitmap_start2(ctx->block_found_map)) ||
Theodore Ts'o3385a252011-06-15 22:15:34 -0400227 (B2C(ext2fs_blocks_count(fs->super)-1) >
Valerie Aurora Hensonc5d2f502009-08-22 22:29:02 -0400228 ext2fs_get_block_bitmap_end2(ctx->block_found_map))) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000229 pctx.num = 1;
Theodore Ts'o3385a252011-06-15 22:15:34 -0400230 pctx.blk = B2C(fs->super->s_first_data_block);
231 pctx.blk2 = B2C(ext2fs_blocks_count(fs->super) - 1);
Valerie Aurora Hensonc5d2f502009-08-22 22:29:02 -0400232 pctx.ino = ext2fs_get_block_bitmap_start2(ctx->block_found_map);
233 pctx.ino2 = ext2fs_get_block_bitmap_end2(ctx->block_found_map);
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000234 fix_problem(ctx, PR_5_BMAP_ENDPOINTS, &pctx);
Theodore Ts'o08b21301997-11-03 19:42:40 +0000235
236 ctx->flags |= E2F_FLAG_ABORT; /* fatal */
Brian Behlendorf49e2df22007-03-28 12:07:41 -0400237 goto errout;
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000238 }
Brian Behlendorf49e2df22007-03-28 12:07:41 -0400239
Theodore Ts'o3385a252011-06-15 22:15:34 -0400240 if ((B2C(fs->super->s_first_data_block) <
Valerie Aurora Hensonc5d2f502009-08-22 22:29:02 -0400241 ext2fs_get_block_bitmap_start2(fs->block_map)) ||
Theodore Ts'o3385a252011-06-15 22:15:34 -0400242 (B2C(ext2fs_blocks_count(fs->super)-1) >
Valerie Aurora Hensonc5d2f502009-08-22 22:29:02 -0400243 ext2fs_get_block_bitmap_end2(fs->block_map))) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000244 pctx.num = 2;
Theodore Ts'o3385a252011-06-15 22:15:34 -0400245 pctx.blk = B2C(fs->super->s_first_data_block);
246 pctx.blk2 = B2C(ext2fs_blocks_count(fs->super) - 1);
Valerie Aurora Hensonc5d2f502009-08-22 22:29:02 -0400247 pctx.ino = ext2fs_get_block_bitmap_start2(fs->block_map);
248 pctx.ino2 = ext2fs_get_block_bitmap_end2(fs->block_map);
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000249 fix_problem(ctx, PR_5_BMAP_ENDPOINTS, &pctx);
Theodore Ts'o08b21301997-11-03 19:42:40 +0000250
251 ctx->flags |= E2F_FLAG_ABORT; /* fatal */
Brian Behlendorf49e2df22007-03-28 12:07:41 -0400252 goto errout;
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000253 }
Brian Behlendorf49e2df22007-03-28 12:07:41 -0400254
Theodore Ts'o63c49691998-02-20 05:24:59 +0000255redo_counts:
256 had_problem = 0;
Theodore Ts'of1226322002-03-07 02:47:07 -0500257 save_problem = 0;
258 pctx.blk = pctx.blk2 = NO_BLK;
Theodore Ts'o3385a252011-06-15 22:15:34 -0400259 for (i = B2C(fs->super->s_first_data_block);
Valerie Aurora Henson4efbac62009-09-07 20:46:34 -0400260 i < ext2fs_blocks_count(fs->super);
Theodore Ts'o44fe08f2011-06-10 18:58:16 -0400261 i += EXT2FS_CLUSTER_RATIO(fs)) {
Theodore Ts'o53e31202012-11-24 19:17:44 -0500262 int first_block_in_bg = (B2C(i) -
263 B2C(fs->super->s_first_data_block)) %
264 fs->super->s_clusters_per_group == 0;
265 int n, nbytes = fs->super->s_clusters_per_group / 8;
266
Valerie Aurora Hensonc5d2f502009-08-22 22:29:02 -0400267 actual = ext2fs_fast_test_block_bitmap2(ctx->block_found_map, i);
Theodore Ts'of5fa2002006-05-08 20:17:26 -0400268
Theodore Ts'o53e31202012-11-24 19:17:44 -0500269 /*
270 * Try to optimize pass5 by extracting a bitmap block
271 * as expected from what we have on disk, and then
272 * comparing the two. If they are identical, then
273 * update the free block counts and go on to the next
274 * block group. This is much faster than doing the
275 * individual bit-by-bit comparison. The one downside
276 * is that this doesn't work if we are asking e2fsck
277 * to do a discard operation.
278 */
279 if (!first_block_in_bg ||
280 (group == (int)fs->group_desc_count - 1) ||
281 (ctx->options & E2F_OPT_DISCARD))
282 goto no_optimize;
283
284 retval = ext2fs_get_block_bitmap_range2(ctx->block_found_map,
285 B2C(i), fs->super->s_clusters_per_group,
286 actual_buf);
287 if (retval)
288 goto no_optimize;
Darrick J. Wonga48da272014-01-11 14:05:02 -0500289 retval = ext2fs_get_block_bitmap_range2(fs->block_map,
290 B2C(i), fs->super->s_clusters_per_group,
291 bitmap_buf);
292 if (retval)
293 goto no_optimize;
Theodore Ts'o53e31202012-11-24 19:17:44 -0500294 if (memcmp(actual_buf, bitmap_buf, nbytes) != 0)
295 goto no_optimize;
296 n = ext2fs_bitcount(actual_buf, nbytes);
297 group_free = fs->super->s_clusters_per_group - n;
298 free_blocks += group_free;
Theodore Ts'oc7e29322012-12-15 22:32:23 -0500299 i += EXT2FS_C2B(fs, fs->super->s_clusters_per_group - 1);
Theodore Ts'o53e31202012-11-24 19:17:44 -0500300 goto next_group;
301 no_optimize:
302
Darrick J. Wonga48da272014-01-11 14:05:02 -0500303 if (redo_flag)
Kazuya Mio479463a2009-07-09 13:46:59 -0400304 bitmap = actual;
305 else
Valerie Aurora Hensonc5d2f502009-08-22 22:29:02 -0400306 bitmap = ext2fs_fast_test_block_bitmap2(fs->block_map, i);
Brian Behlendorf49e2df22007-03-28 12:07:41 -0400307
Theodore Ts'oe35ff9b2011-12-17 11:56:35 -0500308 if (!actual == !bitmap)
Theodore Ts'o3839e651997-04-26 13:21:57 +0000309 goto do_counts;
Theodore Ts'of5fa2002006-05-08 20:17:26 -0400310
Theodore Ts'o3839e651997-04-26 13:21:57 +0000311 if (!actual && bitmap) {
312 /*
313 * Block not used, but marked in use in the bitmap.
314 */
Theodore Ts'of1226322002-03-07 02:47:07 -0500315 problem = PR_5_BLOCK_UNUSED;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000316 } else {
317 /*
318 * Block used, but not marked in use in the bitmap.
319 */
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000320 problem = PR_5_BLOCK_USED;
Jose R. Santos49a73602007-10-21 21:04:03 -0500321
Darrick J. Wonga48da272014-01-11 14:05:02 -0500322 if (ext2fs_bg_flags_test(fs, group,
323 EXT2_BG_BLOCK_UNINIT)) {
Jose R. Santos49a73602007-10-21 21:04:03 -0500324 struct problem_context pctx2;
325 pctx2.blk = i;
326 pctx2.group = group;
Darrick J. Wonga48da272014-01-11 14:05:02 -0500327 if (fix_problem(ctx, PR_5_BLOCK_UNINIT,
328 &pctx2))
329 ext2fs_bg_flags_clear(fs, group,
330 EXT2_BG_BLOCK_UNINIT);
Jose R. Santos49a73602007-10-21 21:04:03 -0500331 }
Theodore Ts'o3839e651997-04-26 13:21:57 +0000332 }
Theodore Ts'of1226322002-03-07 02:47:07 -0500333 if (pctx.blk == NO_BLK) {
334 pctx.blk = pctx.blk2 = i;
335 save_problem = problem;
336 } else {
337 if ((problem == save_problem) &&
Darrick J. Wong69beadc2013-12-15 23:53:32 -0500338 (pctx.blk2 == i - EXT2FS_CLUSTER_RATIO(fs)))
339 pctx.blk2 += EXT2FS_CLUSTER_RATIO(fs);
Theodore Ts'of1226322002-03-07 02:47:07 -0500340 else {
341 print_bitmap_problem(ctx, save_problem, &pctx);
342 pctx.blk = pctx.blk2 = i;
343 save_problem = problem;
344 }
345 }
Theodore Ts'o5596def1999-07-19 15:27:37 +0000346 ctx->flags |= E2F_FLAG_PROG_SUPPRESS;
Theodore Ts'o63c49691998-02-20 05:24:59 +0000347 had_problem++;
Brian Behlendorf49e2df22007-03-28 12:07:41 -0400348
Lukas Czernerefa1a352010-11-18 03:38:38 +0000349 /*
350 * If there a problem we should turn off the discard so we
351 * do not compromise the filesystem.
352 */
353 ctx->options &= ~E2F_OPT_DISCARD;
354
Theodore Ts'o3839e651997-04-26 13:21:57 +0000355 do_counts:
Theodore Ts'od2c9c422012-03-11 14:15:19 -0400356 if (!bitmap) {
Theodore Ts'o3839e651997-04-26 13:21:57 +0000357 group_free++;
358 free_blocks++;
Lukas Czernerefa1a352010-11-18 03:38:38 +0000359 if (first_free > i)
360 first_free = i;
Theodore Ts'od2c9c422012-03-11 14:15:19 -0400361 } else if (i > first_free) {
362 e2fsck_discard_blocks(ctx, first_free,
363 (i - first_free));
Lukas Czernerefa1a352010-11-18 03:38:38 +0000364 first_free = ext2fs_blocks_count(fs->super);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000365 }
366 blocks ++;
Theodore Ts'o44fe08f2011-06-10 18:58:16 -0400367 if ((blocks == fs->super->s_clusters_per_group) ||
368 (EXT2FS_B2C(fs, i) ==
369 EXT2FS_B2C(fs, ext2fs_blocks_count(fs->super)-1))) {
Lukas Czernerdeae60a2012-03-05 08:49:34 +0100370 /*
371 * If the last block of this group is free, then we can
372 * discard it as well.
373 */
374 if (!bitmap && i >= first_free)
375 e2fsck_discard_blocks(ctx, first_free,
376 (i - first_free) + 1);
Theodore Ts'o53e31202012-11-24 19:17:44 -0500377 next_group:
Lukas Czernerdeae60a2012-03-05 08:49:34 +0100378 first_free = ext2fs_blocks_count(fs->super);
379
Theodore Ts'o3839e651997-04-26 13:21:57 +0000380 free_array[group] = group_free;
381 group ++;
382 blocks = 0;
383 group_free = 0;
Theodore Ts'oefac9a11998-05-07 05:02:00 +0000384 if (ctx->progress)
385 if ((ctx->progress)(ctx, 5, group,
386 fs->group_desc_count*2))
Brian Behlendorf49e2df22007-03-28 12:07:41 -0400387 goto errout;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000388 }
389 }
Theodore Ts'of1226322002-03-07 02:47:07 -0500390 if (pctx.blk != NO_BLK)
391 print_bitmap_problem(ctx, save_problem, &pctx);
Theodore Ts'o63c49691998-02-20 05:24:59 +0000392 if (had_problem)
Theodore Ts'of1226322002-03-07 02:47:07 -0500393 fixit = end_problem_latch(ctx, PR_LATCH_BBITMAP);
Theodore Ts'o63c49691998-02-20 05:24:59 +0000394 else
395 fixit = -1;
Theodore Ts'o5596def1999-07-19 15:27:37 +0000396 ctx->flags &= ~E2F_FLAG_PROG_SUPPRESS;
Brian Behlendorf49e2df22007-03-28 12:07:41 -0400397
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000398 if (fixit == 1) {
399 ext2fs_free_block_bitmap(fs->block_map);
400 retval = ext2fs_copy_bitmap(ctx->block_found_map,
401 &fs->block_map);
Theodore Ts'obbd47d72000-06-10 19:21:33 +0000402 if (retval) {
403 clear_problem_context(&pctx);
404 fix_problem(ctx, PR_5_COPY_BBITMAP_ERROR, &pctx);
405 ctx->flags |= E2F_FLAG_ABORT;
Brian Behlendorf49e2df22007-03-28 12:07:41 -0400406 goto errout;
Theodore Ts'obbd47d72000-06-10 19:21:33 +0000407 }
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000408 ext2fs_set_bitmap_padding(fs->block_map);
409 ext2fs_mark_bb_dirty(fs);
Brian Behlendorf49e2df22007-03-28 12:07:41 -0400410
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000411 /* Redo the counts */
412 blocks = 0; free_blocks = 0; group_free = 0; group = 0;
413 memset(free_array, 0, fs->group_desc_count * sizeof(int));
Kazuya Mio479463a2009-07-09 13:46:59 -0400414 redo_flag++;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000415 goto redo_counts;
416 } else if (fixit == 0)
417 ext2fs_unmark_valid(fs);
418
Theodore Ts'o3971bfe2013-12-02 23:21:31 -0500419 for (g = 0; g < fs->group_desc_count; g++) {
420 if (free_array[g] != ext2fs_bg_free_blocks_count(fs, g)) {
421 pctx.group = g;
422 pctx.blk = ext2fs_bg_free_blocks_count(fs, g);
423 pctx.blk2 = free_array[g];
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000424
425 if (fix_problem(ctx, PR_5_FREE_BLOCK_COUNT_GROUP,
426 &pctx)) {
Theodore Ts'o3971bfe2013-12-02 23:21:31 -0500427 ext2fs_bg_free_blocks_count_set(fs, g, free_array[g]);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000428 ext2fs_mark_super_dirty(fs);
429 } else
430 ext2fs_unmark_valid(fs);
431 }
432 }
Theodore Ts'ofe75afb2011-06-16 01:38:43 -0400433 free_blocks = EXT2FS_C2B(fs, free_blocks);
Valerie Aurora Henson4efbac62009-09-07 20:46:34 -0400434 if (free_blocks != ext2fs_free_blocks_count(fs->super)) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000435 pctx.group = 0;
Valerie Aurora Henson4efbac62009-09-07 20:46:34 -0400436 pctx.blk = ext2fs_free_blocks_count(fs->super);
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000437 pctx.blk2 = free_blocks;
438
439 if (fix_problem(ctx, PR_5_FREE_BLOCK_COUNT, &pctx)) {
Valerie Aurora Henson4efbac62009-09-07 20:46:34 -0400440 ext2fs_free_blocks_count_set(fs->super, free_blocks);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000441 ext2fs_mark_super_dirty(fs);
Andreas Dilger2788cc82012-04-24 16:22:48 -0400442 }
Theodore Ts'o3839e651997-04-26 13:21:57 +0000443 }
Brian Behlendorf49e2df22007-03-28 12:07:41 -0400444errout:
Theodore Ts'oc4e3d3f2003-08-01 09:41:07 -0400445 ext2fs_free_mem(&free_array);
Theodore Ts'o53e31202012-11-24 19:17:44 -0500446 ext2fs_free_mem(&actual_buf);
447 ext2fs_free_mem(&bitmap_buf);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000448}
Brian Behlendorf49e2df22007-03-28 12:07:41 -0400449
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000450static void check_inode_bitmaps(e2fsck_t ctx)
Theodore Ts'o3839e651997-04-26 13:21:57 +0000451{
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000452 ext2_filsys fs = ctx->fs;
Theodore Ts'o86c627e2001-01-11 15:12:14 +0000453 ext2_ino_t i;
Theodore Ts'o54434922003-12-07 01:28:50 -0500454 unsigned int free_inodes = 0;
455 int group_free = 0;
456 int dirs_count = 0;
Theodore Ts'o3971bfe2013-12-02 23:21:31 -0500457 dgrp_t group = 0;
Theodore Ts'o54434922003-12-07 01:28:50 -0500458 unsigned int inodes = 0;
Theodore Ts'oe64e6762012-04-05 12:13:05 -0700459 ext2_ino_t *free_array;
460 ext2_ino_t *dir_array;
Theodore Ts'o54434922003-12-07 01:28:50 -0500461 int actual, bitmap;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000462 errcode_t retval;
463 struct problem_context pctx;
Theodore Ts'o3c7c6d72013-12-02 20:52:43 -0500464 problem_t problem, save_problem;
465 int fixit, had_problem;
Theodore Ts'o16b851c2008-04-20 23:33:34 -0400466 int csum_flag;
Theodore Ts'of5fa2002006-05-08 20:17:26 -0400467 int skip_group = 0;
Kazuya Mio479463a2009-07-09 13:46:59 -0400468 int redo_flag = 0;
Theodore Ts'oe64e6762012-04-05 12:13:05 -0700469 ext2_ino_t first_free = fs->super->s_inodes_per_group + 1;
Brian Behlendorf49e2df22007-03-28 12:07:41 -0400470
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000471 clear_problem_context(&pctx);
Theodore Ts'oe64e6762012-04-05 12:13:05 -0700472 free_array = (ext2_ino_t *) e2fsck_allocate_memory(ctx,
473 fs->group_desc_count * sizeof(ext2_ino_t), "free inode count array");
Brian Behlendorf49e2df22007-03-28 12:07:41 -0400474
Theodore Ts'oe64e6762012-04-05 12:13:05 -0700475 dir_array = (ext2_ino_t *) e2fsck_allocate_memory(ctx,
476 fs->group_desc_count * sizeof(ext2_ino_t), "directory count array");
Brian Behlendorf49e2df22007-03-28 12:07:41 -0400477
Valerie Aurora Hensonc5d2f502009-08-22 22:29:02 -0400478 if ((1 < ext2fs_get_inode_bitmap_start2(ctx->inode_used_map)) ||
Brian Behlendorf49e2df22007-03-28 12:07:41 -0400479 (fs->super->s_inodes_count >
Valerie Aurora Hensonc5d2f502009-08-22 22:29:02 -0400480 ext2fs_get_inode_bitmap_end2(ctx->inode_used_map))) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000481 pctx.num = 3;
482 pctx.blk = 1;
483 pctx.blk2 = fs->super->s_inodes_count;
Valerie Aurora Hensonc5d2f502009-08-22 22:29:02 -0400484 pctx.ino = ext2fs_get_inode_bitmap_start2(ctx->inode_used_map);
485 pctx.ino2 = ext2fs_get_inode_bitmap_end2(ctx->inode_used_map);
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000486 fix_problem(ctx, PR_5_BMAP_ENDPOINTS, &pctx);
Theodore Ts'o08b21301997-11-03 19:42:40 +0000487
488 ctx->flags |= E2F_FLAG_ABORT; /* fatal */
Brian Behlendorf49e2df22007-03-28 12:07:41 -0400489 goto errout;
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000490 }
Valerie Aurora Hensonc5d2f502009-08-22 22:29:02 -0400491 if ((1 < ext2fs_get_inode_bitmap_start2(fs->inode_map)) ||
Brian Behlendorf49e2df22007-03-28 12:07:41 -0400492 (fs->super->s_inodes_count >
Valerie Aurora Hensonc5d2f502009-08-22 22:29:02 -0400493 ext2fs_get_inode_bitmap_end2(fs->inode_map))) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000494 pctx.num = 4;
495 pctx.blk = 1;
496 pctx.blk2 = fs->super->s_inodes_count;
Valerie Aurora Hensonc5d2f502009-08-22 22:29:02 -0400497 pctx.ino = ext2fs_get_inode_bitmap_start2(fs->inode_map);
498 pctx.ino2 = ext2fs_get_inode_bitmap_end2(fs->inode_map);
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000499 fix_problem(ctx, PR_5_BMAP_ENDPOINTS, &pctx);
Theodore Ts'o08b21301997-11-03 19:42:40 +0000500
501 ctx->flags |= E2F_FLAG_ABORT; /* fatal */
Brian Behlendorf49e2df22007-03-28 12:07:41 -0400502 goto errout;
Theodore Ts'o50e1e101997-04-26 13:58:21 +0000503 }
504
Jose R. Santos49a73602007-10-21 21:04:03 -0500505 csum_flag = EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
506 EXT4_FEATURE_RO_COMPAT_GDT_CSUM);
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000507redo_counts:
Theodore Ts'o63c49691998-02-20 05:24:59 +0000508 had_problem = 0;
Theodore Ts'of1226322002-03-07 02:47:07 -0500509 save_problem = 0;
510 pctx.ino = pctx.ino2 = 0;
Theodore Ts'o16b851c2008-04-20 23:33:34 -0400511 if (csum_flag &&
Theodore Ts'ocd65a242009-10-25 21:42:12 -0400512 (ext2fs_bg_flags_test(fs, group, EXT2_BG_INODE_UNINIT)))
Theodore Ts'of5fa2002006-05-08 20:17:26 -0400513 skip_group++;
514
Eric Sandeen5830d6b2006-08-30 02:16:55 -0400515 /* Protect loop from wrap-around if inodes_count is maxed */
516 for (i = 1; i <= fs->super->s_inodes_count && i > 0; i++) {
Kazuya Mio479463a2009-07-09 13:46:59 -0400517 bitmap = 0;
518 if (skip_group &&
519 i % fs->super->s_inodes_per_group == 1) {
520 /*
521 * Current inode is the first inode
522 * in the current block group.
523 */
524 if (ext2fs_test_inode_bitmap_range(
525 ctx->inode_used_map, i,
526 fs->super->s_inodes_per_group)) {
527 /*
528 * When the compared inodes in inodes bitmap
529 * are 0, count the free inode,
530 * skip the current block group.
531 */
Lukas Czerner57581c12012-03-11 12:55:45 -0400532 first_free = 1;
Kazuya Mio479463a2009-07-09 13:46:59 -0400533 inodes = fs->super->s_inodes_per_group - 1;
534 group_free = inodes;
535 free_inodes += inodes;
536 i += inodes;
537 skip_group = 0;
538 goto do_counts;
539 }
540 }
541
Valerie Aurora Hensonc5d2f502009-08-22 22:29:02 -0400542 actual = ext2fs_fast_test_inode_bitmap2(ctx->inode_used_map, i);
Kazuya Mio479463a2009-07-09 13:46:59 -0400543 if (redo_flag)
544 bitmap = actual;
545 else if (!skip_group)
Valerie Aurora Hensonc5d2f502009-08-22 22:29:02 -0400546 bitmap = ext2fs_fast_test_inode_bitmap2(fs->inode_map, i);
Theodore Ts'oe35ff9b2011-12-17 11:56:35 -0500547 if (!actual == !bitmap)
Theodore Ts'o3839e651997-04-26 13:21:57 +0000548 goto do_counts;
Brian Behlendorf49e2df22007-03-28 12:07:41 -0400549
Theodore Ts'o3839e651997-04-26 13:21:57 +0000550 if (!actual && bitmap) {
551 /*
552 * Inode wasn't used, but marked in bitmap
553 */
Theodore Ts'of1226322002-03-07 02:47:07 -0500554 problem = PR_5_INODE_UNUSED;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000555 } else /* if (actual && !bitmap) */ {
Theodore Ts'o3839e651997-04-26 13:21:57 +0000556 /*
557 * Inode used, but not in bitmap
558 */
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000559 problem = PR_5_INODE_USED;
Jose R. Santos49a73602007-10-21 21:04:03 -0500560
561 /* We should never hit this, because it means that
562 * inodes were marked in use that weren't noticed
563 * in pass1 or pass 2. It is easier to fix the problem
564 * than to kill e2fsck and leave the user stuck. */
565 if (skip_group) {
566 struct problem_context pctx2;
567 pctx2.blk = i;
568 pctx2.group = group;
569 if (fix_problem(ctx, PR_5_INODE_UNINIT,&pctx2)){
Eric Sandeene633b582009-10-25 21:41:32 -0400570 ext2fs_bg_flags_clear(fs, group, EXT2_BG_INODE_UNINIT);
Jose R. Santos49a73602007-10-21 21:04:03 -0500571 skip_group = 0;
572 }
573 }
Theodore Ts'o3839e651997-04-26 13:21:57 +0000574 }
Theodore Ts'of1226322002-03-07 02:47:07 -0500575 if (pctx.ino == 0) {
576 pctx.ino = pctx.ino2 = i;
577 save_problem = problem;
578 } else {
579 if ((problem == save_problem) &&
580 (pctx.ino2 == i-1))
581 pctx.ino2++;
582 else {
583 print_bitmap_problem(ctx, save_problem, &pctx);
584 pctx.ino = pctx.ino2 = i;
585 save_problem = problem;
586 }
587 }
Theodore Ts'o5596def1999-07-19 15:27:37 +0000588 ctx->flags |= E2F_FLAG_PROG_SUPPRESS;
Theodore Ts'o63c49691998-02-20 05:24:59 +0000589 had_problem++;
Lukas Czernerefa1a352010-11-18 03:38:38 +0000590 /*
591 * If there a problem we should turn off the discard so we
592 * do not compromise the filesystem.
593 */
594 ctx->options &= ~E2F_OPT_DISCARD;
Brian Behlendorf49e2df22007-03-28 12:07:41 -0400595
Theodore Ts'o3839e651997-04-26 13:21:57 +0000596do_counts:
Lukas Czerner57581c12012-03-11 12:55:45 -0400597 inodes++;
Theodore Ts'of5fa2002006-05-08 20:17:26 -0400598 if (bitmap) {
Valerie Aurora Hensonc5d2f502009-08-22 22:29:02 -0400599 if (ext2fs_test_inode_bitmap2(ctx->inode_dir_map, i))
Theodore Ts'o3839e651997-04-26 13:21:57 +0000600 dirs_count++;
Lukas Czerner57581c12012-03-11 12:55:45 -0400601 if (inodes > first_free) {
602 e2fsck_discard_inodes(ctx, group, first_free,
603 inodes - first_free);
604 first_free = fs->super->s_inodes_per_group + 1;
605 }
Theodore Ts'od2c9c422012-03-11 14:15:19 -0400606 } else {
Theodore Ts'of5fa2002006-05-08 20:17:26 -0400607 group_free++;
608 free_inodes++;
Lukas Czerner57581c12012-03-11 12:55:45 -0400609 if (first_free > inodes)
610 first_free = inodes;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000611 }
Lukas Czernerefa1a352010-11-18 03:38:38 +0000612
Theodore Ts'o3839e651997-04-26 13:21:57 +0000613 if ((inodes == fs->super->s_inodes_per_group) ||
614 (i == fs->super->s_inodes_count)) {
Lukas Czerner57581c12012-03-11 12:55:45 -0400615 /*
616 * If the last inode is free, we can discard it as well.
617 */
618 if (!bitmap && inodes >= first_free)
619 e2fsck_discard_inodes(ctx, group, first_free,
620 inodes - first_free + 1);
Lukas Czernerefa1a352010-11-18 03:38:38 +0000621 /*
622 * If discard zeroes data and the group inode table
623 * was not zeroed yet, set itable as zeroed
624 */
625 if ((ctx->options & E2F_OPT_DISCARD) &&
Lukas Czerner57581c12012-03-11 12:55:45 -0400626 io_channel_discard_zeroes_data(fs->io) &&
Lukas Czernerefa1a352010-11-18 03:38:38 +0000627 !(ext2fs_bg_flags_test(fs, group,
Lukas Czerner57581c12012-03-11 12:55:45 -0400628 EXT2_BG_INODE_ZEROED))) {
Lukas Czernerefa1a352010-11-18 03:38:38 +0000629 ext2fs_bg_flags_set(fs, group,
630 EXT2_BG_INODE_ZEROED);
631 ext2fs_group_desc_csum_set(fs, group);
632 }
633
Lukas Czerner57581c12012-03-11 12:55:45 -0400634 first_free = fs->super->s_inodes_per_group + 1;
635 free_array[group] = group_free;
636 dir_array[group] = dirs_count;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000637 group ++;
638 inodes = 0;
Theodore Ts'of5fa2002006-05-08 20:17:26 -0400639 skip_group = 0;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000640 group_free = 0;
641 dirs_count = 0;
Theodore Ts'oefac9a11998-05-07 05:02:00 +0000642 if (ctx->progress)
643 if ((ctx->progress)(ctx, 5,
644 group + fs->group_desc_count,
645 fs->group_desc_count*2))
Brian Behlendorf49e2df22007-03-28 12:07:41 -0400646 goto errout;
Theodore Ts'o16b851c2008-04-20 23:33:34 -0400647 if (csum_flag &&
Theodore Ts'of5fa2002006-05-08 20:17:26 -0400648 (i != fs->super->s_inodes_count) &&
Theodore Ts'ocd65a242009-10-25 21:42:12 -0400649 (ext2fs_bg_flags_test(fs, group, EXT2_BG_INODE_UNINIT)
Theodore Ts'o732c8cd2009-09-07 21:15:12 -0400650 ))
Theodore Ts'of5fa2002006-05-08 20:17:26 -0400651 skip_group++;
Theodore Ts'o3839e651997-04-26 13:21:57 +0000652 }
653 }
Theodore Ts'of1226322002-03-07 02:47:07 -0500654 if (pctx.ino)
655 print_bitmap_problem(ctx, save_problem, &pctx);
Brian Behlendorf49e2df22007-03-28 12:07:41 -0400656
Theodore Ts'o63c49691998-02-20 05:24:59 +0000657 if (had_problem)
658 fixit = end_problem_latch(ctx, PR_LATCH_IBITMAP);
659 else
660 fixit = -1;
Theodore Ts'o5596def1999-07-19 15:27:37 +0000661 ctx->flags &= ~E2F_FLAG_PROG_SUPPRESS;
Brian Behlendorf49e2df22007-03-28 12:07:41 -0400662
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000663 if (fixit == 1) {
664 ext2fs_free_inode_bitmap(fs->inode_map);
665 retval = ext2fs_copy_bitmap(ctx->inode_used_map,
666 &fs->inode_map);
Theodore Ts'obbd47d72000-06-10 19:21:33 +0000667 if (retval) {
668 clear_problem_context(&pctx);
669 fix_problem(ctx, PR_5_COPY_IBITMAP_ERROR, &pctx);
670 ctx->flags |= E2F_FLAG_ABORT;
Brian Behlendorf49e2df22007-03-28 12:07:41 -0400671 goto errout;
Theodore Ts'obbd47d72000-06-10 19:21:33 +0000672 }
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000673 ext2fs_set_bitmap_padding(fs->inode_map);
674 ext2fs_mark_ib_dirty(fs);
675
676 /* redo counts */
677 inodes = 0; free_inodes = 0; group_free = 0;
678 dirs_count = 0; group = 0;
679 memset(free_array, 0, fs->group_desc_count * sizeof(int));
680 memset(dir_array, 0, fs->group_desc_count * sizeof(int));
Kazuya Mio479463a2009-07-09 13:46:59 -0400681 redo_flag++;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000682 goto redo_counts;
683 } else if (fixit == 0)
684 ext2fs_unmark_valid(fs);
Brian Behlendorf49e2df22007-03-28 12:07:41 -0400685
Theodore Ts'o3839e651997-04-26 13:21:57 +0000686 for (i = 0; i < fs->group_desc_count; i++) {
Valerie Aurora Hensond7cca6b2009-10-25 21:43:47 -0400687 if (free_array[i] != ext2fs_bg_free_inodes_count(fs, i)) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000688 pctx.group = i;
Valerie Aurora Hensond7cca6b2009-10-25 21:43:47 -0400689 pctx.ino = ext2fs_bg_free_inodes_count(fs, i);
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000690 pctx.ino2 = free_array[i];
691 if (fix_problem(ctx, PR_5_FREE_INODE_COUNT_GROUP,
692 &pctx)) {
Valerie Aurora Hensond7cca6b2009-10-25 21:43:47 -0400693 ext2fs_bg_free_inodes_count_set(fs, i, free_array[i]);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000694 ext2fs_mark_super_dirty(fs);
695 } else
696 ext2fs_unmark_valid(fs);
697 }
Valerie Aurora Hensond7cca6b2009-10-25 21:43:47 -0400698 if (dir_array[i] != ext2fs_bg_used_dirs_count(fs, i)) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000699 pctx.group = i;
Valerie Aurora Hensond7cca6b2009-10-25 21:43:47 -0400700 pctx.ino = ext2fs_bg_used_dirs_count(fs, i);
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000701 pctx.ino2 = dir_array[i];
702
703 if (fix_problem(ctx, PR_5_FREE_DIR_COUNT_GROUP,
704 &pctx)) {
Valerie Aurora Hensond7cca6b2009-10-25 21:43:47 -0400705 ext2fs_bg_used_dirs_count_set(fs, i, dir_array[i]);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000706 ext2fs_mark_super_dirty(fs);
707 } else
708 ext2fs_unmark_valid(fs);
709 }
710 }
711 if (free_inodes != fs->super->s_free_inodes_count) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000712 pctx.group = -1;
713 pctx.ino = fs->super->s_free_inodes_count;
714 pctx.ino2 = free_inodes;
715
716 if (fix_problem(ctx, PR_5_FREE_INODE_COUNT, &pctx)) {
Theodore Ts'o3839e651997-04-26 13:21:57 +0000717 fs->super->s_free_inodes_count = free_inodes;
718 ext2fs_mark_super_dirty(fs);
Andreas Dilger2788cc82012-04-24 16:22:48 -0400719 }
Theodore Ts'o3839e651997-04-26 13:21:57 +0000720 }
Brian Behlendorf49e2df22007-03-28 12:07:41 -0400721errout:
Theodore Ts'oc4e3d3f2003-08-01 09:41:07 -0400722 ext2fs_free_mem(&free_array);
723 ext2fs_free_mem(&dir_array);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000724}
725
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000726static void check_inode_end(e2fsck_t ctx)
Theodore Ts'o3839e651997-04-26 13:21:57 +0000727{
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000728 ext2_filsys fs = ctx->fs;
Theodore Ts'o86c627e2001-01-11 15:12:14 +0000729 ext2_ino_t end, save_inodes_count, i;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000730 struct problem_context pctx;
731
732 clear_problem_context(&pctx);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000733
734 end = EXT2_INODES_PER_GROUP(fs->super) * fs->group_desc_count;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000735 pctx.errcode = ext2fs_fudge_inode_bitmap_end(fs->inode_map, end,
736 &save_inodes_count);
737 if (pctx.errcode) {
738 pctx.num = 1;
739 fix_problem(ctx, PR_5_FUDGE_BITMAP_ERROR, &pctx);
Theodore Ts'o08b21301997-11-03 19:42:40 +0000740 ctx->flags |= E2F_FLAG_ABORT; /* fatal */
741 return;
Theodore Ts'of3db3561997-04-26 13:34:30 +0000742 }
Theodore Ts'o3839e651997-04-26 13:21:57 +0000743 if (save_inodes_count == end)
744 return;
Eric Sandeen5830d6b2006-08-30 02:16:55 -0400745
Theodore Ts'oefc6f622008-08-27 23:07:54 -0400746 /* protect loop from wrap-around if end is maxed */
Eric Sandeen5830d6b2006-08-30 02:16:55 -0400747 for (i = save_inodes_count + 1; i <= end && i > save_inodes_count; i++) {
Theodore Ts'of3db3561997-04-26 13:34:30 +0000748 if (!ext2fs_test_inode_bitmap(fs->inode_map, i)) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000749 if (fix_problem(ctx, PR_5_INODE_BMAP_PADDING, &pctx)) {
Kazuya Mio01ec1262009-07-06 17:15:24 +0900750 for (; i <= end; i++)
Theodore Ts'of3db3561997-04-26 13:34:30 +0000751 ext2fs_mark_inode_bitmap(fs->inode_map,
Theodore Ts'o3839e651997-04-26 13:21:57 +0000752 i);
753 ext2fs_mark_ib_dirty(fs);
754 } else
755 ext2fs_unmark_valid(fs);
756 break;
757 }
758 }
759
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000760 pctx.errcode = ext2fs_fudge_inode_bitmap_end(fs->inode_map,
761 save_inodes_count, 0);
762 if (pctx.errcode) {
763 pctx.num = 2;
764 fix_problem(ctx, PR_5_FUDGE_BITMAP_ERROR, &pctx);
Theodore Ts'o08b21301997-11-03 19:42:40 +0000765 ctx->flags |= E2F_FLAG_ABORT; /* fatal */
766 return;
Theodore Ts'of3db3561997-04-26 13:34:30 +0000767 }
Theodore Ts'o3839e651997-04-26 13:21:57 +0000768}
769
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000770static void check_block_end(e2fsck_t ctx)
Theodore Ts'o3839e651997-04-26 13:21:57 +0000771{
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000772 ext2_filsys fs = ctx->fs;
Valerie Aurora Hensonc5d2f502009-08-22 22:29:02 -0400773 blk64_t end, save_blocks_count, i;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000774 struct problem_context pctx;
775
776 clear_problem_context(&pctx);
Theodore Ts'o3839e651997-04-26 13:21:57 +0000777
Valerie Aurora Hensonc5d2f502009-08-22 22:29:02 -0400778 end = ext2fs_get_block_bitmap_start2(fs->block_map) +
Theodore Ts'o1e33a8b2014-07-26 07:40:36 -0400779 EXT2_GROUPS_TO_CLUSTERS(fs->super, fs->group_desc_count) - 1;
Valerie Aurora Hensonc5d2f502009-08-22 22:29:02 -0400780 pctx.errcode = ext2fs_fudge_block_bitmap_end2(fs->block_map, end,
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000781 &save_blocks_count);
782 if (pctx.errcode) {
783 pctx.num = 3;
784 fix_problem(ctx, PR_5_FUDGE_BITMAP_ERROR, &pctx);
Theodore Ts'o08b21301997-11-03 19:42:40 +0000785 ctx->flags |= E2F_FLAG_ABORT; /* fatal */
786 return;
Theodore Ts'of3db3561997-04-26 13:34:30 +0000787 }
Theodore Ts'o3839e651997-04-26 13:21:57 +0000788 if (save_blocks_count == end)
789 return;
Eric Sandeen5830d6b2006-08-30 02:16:55 -0400790
Theodore Ts'oefc6f622008-08-27 23:07:54 -0400791 /* Protect loop from wrap-around if end is maxed */
Eric Sandeen5830d6b2006-08-30 02:16:55 -0400792 for (i = save_blocks_count + 1; i <= end && i > save_blocks_count; i++) {
Theodore Ts'o44fe08f2011-06-10 18:58:16 -0400793 if (!ext2fs_test_block_bitmap2(fs->block_map,
794 EXT2FS_C2B(fs, i))) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000795 if (fix_problem(ctx, PR_5_BLOCK_BMAP_PADDING, &pctx)) {
Kazuya Mio01ec1262009-07-06 17:15:24 +0900796 for (; i <= end; i++)
Valerie Aurora Hensonc5d2f502009-08-22 22:29:02 -0400797 ext2fs_mark_block_bitmap2(fs->block_map,
Theodore Ts'o44fe08f2011-06-10 18:58:16 -0400798 EXT2FS_C2B(fs, i));
Theodore Ts'o3839e651997-04-26 13:21:57 +0000799 ext2fs_mark_bb_dirty(fs);
800 } else
801 ext2fs_unmark_valid(fs);
802 break;
803 }
804 }
805
Valerie Aurora Hensonc5d2f502009-08-22 22:29:02 -0400806 pctx.errcode = ext2fs_fudge_block_bitmap_end2(fs->block_map,
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000807 save_blocks_count, 0);
808 if (pctx.errcode) {
809 pctx.num = 4;
810 fix_problem(ctx, PR_5_FUDGE_BITMAP_ERROR, &pctx);
Theodore Ts'o08b21301997-11-03 19:42:40 +0000811 ctx->flags |= E2F_FLAG_ABORT; /* fatal */
812 return;
Theodore Ts'of3db3561997-04-26 13:34:30 +0000813 }
Theodore Ts'o3839e651997-04-26 13:21:57 +0000814}
815
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000816
817