blob: 227a02542857fcc5bbac5aec9e31dac23f48759a [file] [log] [blame]
Theodore Ts'o1b6bf171997-10-03 17:48:10 +00001/*
2 * e2fsck.c - superblock checks
3 *
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%
10 */
11
Theodore Ts'o1b6bf171997-10-03 17:48:10 +000012#ifdef HAVE_ERRNO_H
13#include <errno.h>
14#endif
Theodore Ts'o1b6bf171997-10-03 17:48:10 +000015
Theodore Ts'o54be2cc1998-02-01 12:58:48 +000016#ifndef EXT2_SKIP_UUID
Theodore Ts'o1b6bf171997-10-03 17:48:10 +000017#include "uuid/uuid.h"
Theodore Ts'o54be2cc1998-02-01 12:58:48 +000018#endif
Theodore Ts'o1b6bf171997-10-03 17:48:10 +000019#include "e2fsck.h"
20#include "problem.h"
Theodore Ts'o1b6bf171997-10-03 17:48:10 +000021
22#define MIN_CHECK 1
23#define MAX_CHECK 2
24
25static void check_super_value(e2fsck_t ctx, const char *descr,
26 unsigned long value, int flags,
Theodore Ts'o7f813ba1998-09-03 01:26:03 +000027 unsigned long min_val, unsigned long max_val)
Theodore Ts'o1b6bf171997-10-03 17:48:10 +000028{
29 struct problem_context pctx;
30
Theodore Ts'o7f813ba1998-09-03 01:26:03 +000031 if (((flags & MIN_CHECK) && (value < min_val)) ||
32 ((flags & MAX_CHECK) && (value > max_val))) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +000033 clear_problem_context(&pctx);
34 pctx.num = value;
35 pctx.str = descr;
36 fix_problem(ctx, PR_0_MISC_CORRUPT_SUPER, &pctx);
Theodore Ts'o08b21301997-11-03 19:42:40 +000037 ctx->flags |= E2F_FLAG_ABORT; /* never get here! */
Theodore Ts'o1b6bf171997-10-03 17:48:10 +000038 }
39}
40
Theodore Ts'o43139321998-02-16 22:34:46 +000041/*
42 * This routine may get stubbed out in special compilations of the
43 * e2fsck code..
44 */
45#ifndef EXT2_SPECIAL_DEVICE_SIZE
46errcode_t e2fsck_get_device_size(e2fsck_t ctx)
47{
48 return (ext2fs_get_device_size(ctx->filesystem_name,
49 EXT2_BLOCK_SIZE(ctx->fs->super),
50 &ctx->num_blocks));
51}
Theodore Ts'o43139321998-02-16 22:34:46 +000052#endif
53
Theodore Ts'o80bfaa32000-08-18 15:08:37 +000054/*
55 * helper function to release an inode
56 */
57struct process_block_struct {
Theodore Ts'o83949022000-10-25 01:38:50 +000058 e2fsck_t ctx;
59 char *buf;
Theodore Ts'o80bfaa32000-08-18 15:08:37 +000060 struct problem_context *pctx;
Theodore Ts'o83949022000-10-25 01:38:50 +000061 int truncating;
62 int truncate_offset;
63 blk_t truncate_block;
64 int truncated_blocks;
65 int abort;
66 errcode_t errcode;
Theodore Ts'o80bfaa32000-08-18 15:08:37 +000067};
68
69static int release_inode_block(ext2_filsys fs,
70 blk_t *block_nr,
71 int blockcnt,
72 void *priv_data)
73{
74 struct process_block_struct *pb;
Theodore Ts'o83949022000-10-25 01:38:50 +000075 e2fsck_t ctx;
76 struct problem_context *pctx;
77 blk_t blk = *block_nr;
78 int retval = 0;
Theodore Ts'o80bfaa32000-08-18 15:08:37 +000079
80 pb = (struct process_block_struct *) priv_data;
81 ctx = pb->ctx;
82 pctx = pb->pctx;
83
84 pctx->blk = blk;
85 pctx->blkcount = blockcnt;
86
87 if (HOLE_BLKADDR(blk))
88 return 0;
89
90 if ((blk < fs->super->s_first_data_block) ||
91 (blk >= fs->super->s_blocks_count)) {
92 fix_problem(ctx, PR_0_ORPHAN_ILLEGAL_BLOCK_NUM, pctx);
Theodore Ts'o53ef44c2001-01-06 05:55:58 +000093 return_abort:
Theodore Ts'o80bfaa32000-08-18 15:08:37 +000094 pb->abort = 1;
95 return BLOCK_ABORT;
96 }
97
98 if (!ext2fs_test_block_bitmap(fs->block_map, blk)) {
99 fix_problem(ctx, PR_0_ORPHAN_ALREADY_CLEARED_BLOCK, pctx);
Theodore Ts'o53ef44c2001-01-06 05:55:58 +0000100 goto return_abort;
Theodore Ts'o83949022000-10-25 01:38:50 +0000101 }
102
103 /*
104 * If we are deleting an orphan, then we leave the fields alone.
105 * If we are truncating an orphan, then update the inode fields
106 * and clean up any partial block data.
107 */
108 if (pb->truncating) {
109 /*
110 * We only remove indirect blocks if they are
111 * completely empty.
112 */
113 if (blockcnt < 0) {
114 int i, limit;
Theodore Ts'o53ef44c2001-01-06 05:55:58 +0000115 blk_t *bp;
Theodore Ts'o83949022000-10-25 01:38:50 +0000116
117 pb->errcode = io_channel_read_blk(fs->io, blk, 1,
118 pb->buf);
119 if (pb->errcode)
Theodore Ts'o53ef44c2001-01-06 05:55:58 +0000120 goto return_abort;
Theodore Ts'o83949022000-10-25 01:38:50 +0000121
122 limit = fs->blocksize >> 2;
Theodore Ts'o53ef44c2001-01-06 05:55:58 +0000123 for (i = 0, bp = (blk_t *) pb->buf;
124 i < limit; i++, bp++)
125 if (*bp)
Theodore Ts'o83949022000-10-25 01:38:50 +0000126 return 0;
127 }
128 /*
129 * We don't remove direct blocks until we've reached
130 * the truncation block.
131 */
132 if (blockcnt >= 0 && blockcnt < pb->truncate_block)
133 return 0;
134 /*
135 * If part of the last block needs truncating, we do
136 * it here.
137 */
138 if ((blockcnt == pb->truncate_block) && pb->truncate_offset) {
139 pb->errcode = io_channel_read_blk(fs->io, blk, 1,
140 pb->buf);
141 if (pb->errcode)
Theodore Ts'o53ef44c2001-01-06 05:55:58 +0000142 goto return_abort;
Theodore Ts'o83949022000-10-25 01:38:50 +0000143 memset(pb->buf + pb->truncate_offset, 0,
144 fs->blocksize - pb->truncate_offset);
145 pb->errcode = io_channel_write_blk(fs->io, blk, 1,
146 pb->buf);
147 if (pb->errcode)
Theodore Ts'o53ef44c2001-01-06 05:55:58 +0000148 goto return_abort;
Theodore Ts'o83949022000-10-25 01:38:50 +0000149 }
150 pb->truncated_blocks++;
151 *block_nr = 0;
152 retval |= BLOCK_CHANGED;
Theodore Ts'o80bfaa32000-08-18 15:08:37 +0000153 }
154
155 ext2fs_unmark_block_bitmap(fs->block_map, blk);
Theodore Ts'oecf1b772000-08-20 22:06:31 +0000156 fs->group_desc[ext2fs_group_of_blk(fs, blk)].bg_free_blocks_count++;
157 fs->super->s_free_blocks_count++;
Theodore Ts'o80bfaa32000-08-18 15:08:37 +0000158
Theodore Ts'o83949022000-10-25 01:38:50 +0000159 return retval;
Theodore Ts'o80bfaa32000-08-18 15:08:37 +0000160}
161
162/*
163 * This function releases an inode. Returns 1 if an inconsistency was
Theodore Ts'o83949022000-10-25 01:38:50 +0000164 * found. If the inode has a link count, then it is being truncated and
165 * not deleted.
Theodore Ts'o80bfaa32000-08-18 15:08:37 +0000166 */
Theodore Ts'o86c627e2001-01-11 15:12:14 +0000167static int release_inode_blocks(e2fsck_t ctx, ext2_ino_t ino,
Theodore Ts'o721edd02001-01-12 21:05:57 +0000168 struct ext2_inode *inode, char *block_buf,
Theodore Ts'o80bfaa32000-08-18 15:08:37 +0000169 struct problem_context *pctx)
170{
Theodore Ts'o83949022000-10-25 01:38:50 +0000171 ext2_filsys fs = ctx->fs;
Theodore Ts'o80bfaa32000-08-18 15:08:37 +0000172 errcode_t retval;
173 struct process_block_struct pb;
174
Theodore Ts'o42475e22001-06-22 20:35:38 -0400175 if (!ext2fs_inode_has_valid_blocks(inode))
176 return 0;
177
Theodore Ts'o83949022000-10-25 01:38:50 +0000178 pb.buf = block_buf + 3 * ctx->fs->blocksize;
Theodore Ts'o80bfaa32000-08-18 15:08:37 +0000179 pb.ctx = ctx;
180 pb.abort = 0;
Theodore Ts'o83949022000-10-25 01:38:50 +0000181 pb.errcode = 0;
Theodore Ts'o80bfaa32000-08-18 15:08:37 +0000182 pb.pctx = pctx;
Theodore Ts'o83949022000-10-25 01:38:50 +0000183 if (inode->i_links_count) {
184 pb.truncating = 1;
185 pb.truncate_block = (blk_t)
186 ((((long long)inode->i_size_high << 32) +
187 inode->i_size + fs->blocksize - 1) /
188 fs->blocksize);
189 pb.truncate_offset = inode->i_size % fs->blocksize;
190 } else {
191 pb.truncating = 0;
192 pb.truncate_block = 0;
193 pb.truncate_offset = 0;
194 }
195 pb.truncated_blocks = 0;
196 retval = ext2fs_block_iterate(fs, ino, BLOCK_FLAG_DEPTH_TRAVERSE,
197 block_buf, release_inode_block, &pb);
Theodore Ts'o80bfaa32000-08-18 15:08:37 +0000198 if (retval) {
Theodore Ts'o83949022000-10-25 01:38:50 +0000199 com_err("release_inode_blocks", retval,
Theodore Ts'o80bfaa32000-08-18 15:08:37 +0000200 _("while calling ext2fs_block_iterate for inode %d"),
201 ino);
202 return 1;
203 }
204 if (pb.abort)
205 return 1;
206
Theodore Ts'o83949022000-10-25 01:38:50 +0000207 /* Refresh the inode since ext2fs_block_iterate may have changed it */
208 e2fsck_read_inode(ctx, ino, inode, "release_inode_blocks");
209
210 if (pb.truncated_blocks)
211 inode->i_blocks -= pb.truncated_blocks *
212 (fs->blocksize / 512);
213
Theodore Ts'o80bfaa32000-08-18 15:08:37 +0000214 ext2fs_mark_bb_dirty(fs);
215 return 0;
216}
217
218/*
219 * This function releases all of the orphan inodes. It returns 1 if
220 * it hit some error, and 0 on success.
221 */
222static int release_orphan_inodes(e2fsck_t ctx)
223{
224 ext2_filsys fs = ctx->fs;
Theodore Ts'oecf1b772000-08-20 22:06:31 +0000225 int group;
Theodore Ts'o86c627e2001-01-11 15:12:14 +0000226 ext2_ino_t ino, next_ino;
Theodore Ts'o80bfaa32000-08-18 15:08:37 +0000227 struct ext2_inode inode;
228 struct problem_context pctx;
229 char *block_buf;
230
231 if ((ino = fs->super->s_last_orphan) == 0)
232 return 0;
233
Theodore Ts'o25c63ba2000-08-18 15:31:37 +0000234 /*
235 * Win or lose, we won't be using the head of the orphan inode
236 * list again.
237 */
238 fs->super->s_last_orphan = 0;
239 ext2fs_mark_super_dirty(fs);
Theodore Ts'oeb4ab512001-08-13 10:58:41 -0400240
241 /*
242 * If the filesystem contains errors, don't run the orphan
243 * list, since the orphan list can't be trusted; and we're
244 * going to be running a full e2fsck run anyway...
245 */
246 if (fs->super->s_state & EXT2_ERROR_FS)
247 return 0;
Theodore Ts'o25c63ba2000-08-18 15:31:37 +0000248
Theodore Ts'o80bfaa32000-08-18 15:08:37 +0000249 if ((ino < EXT2_FIRST_INODE(fs->super)) ||
250 (ino > fs->super->s_inodes_count)) {
251 clear_problem_context(&pctx);
Theodore Ts'o53ef44c2001-01-06 05:55:58 +0000252 pctx.ino = ino;
Theodore Ts'o80bfaa32000-08-18 15:08:37 +0000253 fix_problem(ctx, PR_0_ORPHAN_ILLEGAL_HEAD_INODE, &pctx);
254 return 1;
255 }
256
Theodore Ts'o83949022000-10-25 01:38:50 +0000257 block_buf = (char *) e2fsck_allocate_memory(ctx, fs->blocksize * 4,
Theodore Ts'o9b565752000-12-13 18:50:22 +0000258 "block iterate buffer");
Theodore Ts'o80bfaa32000-08-18 15:08:37 +0000259 e2fsck_read_bitmaps(ctx);
260
261 while (ino) {
Theodore Ts'o83949022000-10-25 01:38:50 +0000262 e2fsck_read_inode(ctx, ino, &inode, "release_orphan_inodes");
Theodore Ts'o80bfaa32000-08-18 15:08:37 +0000263 clear_problem_context(&pctx);
Theodore Ts'oecf1b772000-08-20 22:06:31 +0000264 pctx.ino = ino;
Theodore Ts'o80bfaa32000-08-18 15:08:37 +0000265 pctx.inode = &inode;
Theodore Ts'of0b8c872001-05-09 06:03:58 +0000266 pctx.str = inode.i_links_count ? _("Truncating") :
267 _("Clearing");
Theodore Ts'o80bfaa32000-08-18 15:08:37 +0000268
Theodore Ts'o83949022000-10-25 01:38:50 +0000269 fix_problem(ctx, PR_0_ORPHAN_CLEAR_INODE, &pctx);
Theodore Ts'oecf1b772000-08-20 22:06:31 +0000270
Theodore Ts'o80bfaa32000-08-18 15:08:37 +0000271 next_ino = inode.i_dtime;
272 if (next_ino &&
Theodore Ts'o99a2cc92000-08-22 21:41:52 +0000273 ((next_ino < EXT2_FIRST_INODE(fs->super)) ||
274 (next_ino > fs->super->s_inodes_count))) {
275 pctx.ino = next_ino;
Theodore Ts'o80bfaa32000-08-18 15:08:37 +0000276 fix_problem(ctx, PR_0_ORPHAN_ILLEGAL_INODE, &pctx);
Theodore Ts'o53ef44c2001-01-06 05:55:58 +0000277 goto return_abort;
Theodore Ts'o80bfaa32000-08-18 15:08:37 +0000278 }
279
Theodore Ts'o83949022000-10-25 01:38:50 +0000280 if (release_inode_blocks(ctx, ino, &inode, block_buf, &pctx))
Theodore Ts'o53ef44c2001-01-06 05:55:58 +0000281 goto return_abort;
Theodore Ts'oecf1b772000-08-20 22:06:31 +0000282
Theodore Ts'o83949022000-10-25 01:38:50 +0000283 if (!inode.i_links_count) {
284 ext2fs_unmark_inode_bitmap(fs->inode_map, ino);
285 ext2fs_mark_ib_dirty(fs);
286 group = ext2fs_group_of_ino(fs, ino);
287 fs->group_desc[group].bg_free_inodes_count++;
288 fs->super->s_free_inodes_count++;
289 if (LINUX_S_ISDIR(inode.i_mode))
290 fs->group_desc[group].bg_used_dirs_count--;
291
292 inode.i_dtime = time(0);
Stephen Tweedieeb16f862002-08-14 11:00:44 +0100293 } else {
294 inode.i_dtime = 0;
Theodore Ts'o83949022000-10-25 01:38:50 +0000295 }
296 e2fsck_write_inode(ctx, ino, &inode, "delete_file");
Theodore Ts'o80bfaa32000-08-18 15:08:37 +0000297 ino = next_ino;
298 }
Theodore Ts'od1a21822002-02-22 00:17:59 -0500299 ext2fs_free_mem((void **) &block_buf);
Theodore Ts'o80bfaa32000-08-18 15:08:37 +0000300 return 0;
Theodore Ts'o53ef44c2001-01-06 05:55:58 +0000301return_abort:
Theodore Ts'o80bfaa32000-08-18 15:08:37 +0000302 ext2fs_free_mem((void **) &block_buf);
303 return 1;
304}
305
306
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000307void check_super_block(e2fsck_t ctx)
308{
309 ext2_filsys fs = ctx->fs;
310 blk_t first_block, last_block;
Theodore Ts'o5dd8f962001-01-01 15:51:50 +0000311 struct ext2_super_block *sb = fs->super;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000312 blk_t blocks_per_group = fs->super->s_blocks_per_group;
Andreas Dilgerb21bf262002-06-10 11:05:56 -0600313 blk_t bpg_max;
Theodore Ts'o78cf0541999-10-20 18:29:18 +0000314 int inodes_per_block;
Andreas Dilgerb21bf262002-06-10 11:05:56 -0600315 int ipg_max;
Theodore Ts'o7f813ba1998-09-03 01:26:03 +0000316 dgrp_t i;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000317 blk_t should_be;
318 struct problem_context pctx;
Andreas Dilgerb21bf262002-06-10 11:05:56 -0600319
320 inodes_per_block = EXT2_INODES_PER_BLOCK(fs->super);
321 ipg_max = inodes_per_block * (blocks_per_group - 4);
322 if (ipg_max > EXT2_MAX_INODES_PER_GROUP(sb))
323 ipg_max = EXT2_MAX_INODES_PER_GROUP(sb);
324 bpg_max = 8 * EXT2_BLOCK_SIZE(sb);
325 if (bpg_max > EXT2_MAX_BLOCKS_PER_GROUP(sb))
326 bpg_max = EXT2_MAX_BLOCKS_PER_GROUP(sb);
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000327
Theodore Ts'o54dc7ca1998-01-19 14:50:49 +0000328 ctx->invalid_inode_bitmap_flag = (int *) e2fsck_allocate_memory(ctx,
Theodore Ts'of8188ff1997-11-14 05:23:04 +0000329 sizeof(int) * fs->group_desc_count, "invalid_inode_bitmap");
Theodore Ts'o54dc7ca1998-01-19 14:50:49 +0000330 ctx->invalid_block_bitmap_flag = (int *) e2fsck_allocate_memory(ctx,
Theodore Ts'of8188ff1997-11-14 05:23:04 +0000331 sizeof(int) * fs->group_desc_count, "invalid_block_bitmap");
Theodore Ts'o54dc7ca1998-01-19 14:50:49 +0000332 ctx->invalid_inode_table_flag = (int *) e2fsck_allocate_memory(ctx,
Theodore Ts'of8188ff1997-11-14 05:23:04 +0000333 sizeof(int) * fs->group_desc_count, "invalid_inode_table");
Andreas Dilgerb21bf262002-06-10 11:05:56 -0600334
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000335 clear_problem_context(&pctx);
336
337 /*
338 * Verify the super block constants...
339 */
Theodore Ts'o5dd8f962001-01-01 15:51:50 +0000340 check_super_value(ctx, "inodes_count", sb->s_inodes_count,
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000341 MIN_CHECK, 1, 0);
Theodore Ts'o5dd8f962001-01-01 15:51:50 +0000342 check_super_value(ctx, "blocks_count", sb->s_blocks_count,
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000343 MIN_CHECK, 1, 0);
Theodore Ts'o5dd8f962001-01-01 15:51:50 +0000344 check_super_value(ctx, "first_data_block", sb->s_first_data_block,
345 MAX_CHECK, 0, sb->s_blocks_count);
Theodore Ts'o5dd8f962001-01-01 15:51:50 +0000346 check_super_value(ctx, "log_block_size", sb->s_log_block_size,
Theodore Ts'o31e29a12002-05-17 10:53:07 -0400347 MIN_CHECK | MAX_CHECK, 0,
348 EXT2_MAX_BLOCK_LOG_SIZE - EXT2_MIN_BLOCK_LOG_SIZE);
Andreas Dilger932a4892002-05-16 03:20:07 -0600349 check_super_value(ctx, "log_frag_size", sb->s_log_frag_size,
350 MIN_CHECK | MAX_CHECK, 0, sb->s_log_block_size);
Theodore Ts'o5dd8f962001-01-01 15:51:50 +0000351 check_super_value(ctx, "frags_per_group", sb->s_frags_per_group,
Theodore Ts'oef059872001-04-17 00:40:02 +0000352 MIN_CHECK | MAX_CHECK, sb->s_blocks_per_group,
Andreas Dilgerb21bf262002-06-10 11:05:56 -0600353 bpg_max);
Theodore Ts'o5dd8f962001-01-01 15:51:50 +0000354 check_super_value(ctx, "blocks_per_group", sb->s_blocks_per_group,
Andreas Dilgerb21bf262002-06-10 11:05:56 -0600355 MIN_CHECK | MAX_CHECK, 8, bpg_max);
Theodore Ts'o5dd8f962001-01-01 15:51:50 +0000356 check_super_value(ctx, "inodes_per_group", sb->s_inodes_per_group,
Andreas Dilgerb21bf262002-06-10 11:05:56 -0600357 MIN_CHECK | MAX_CHECK, inodes_per_block, ipg_max);
Theodore Ts'o5dd8f962001-01-01 15:51:50 +0000358 check_super_value(ctx, "r_blocks_count", sb->s_r_blocks_count,
Theodore Ts'o424cd2b2001-05-14 04:06:56 +0000359 MAX_CHECK, 0, sb->s_blocks_count / 4);
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000360
Theodore Ts'of8188ff1997-11-14 05:23:04 +0000361 if (!ctx->num_blocks) {
Theodore Ts'o43139321998-02-16 22:34:46 +0000362 pctx.errcode = e2fsck_get_device_size(ctx);
Theodore Ts'of8188ff1997-11-14 05:23:04 +0000363 if (pctx.errcode && pctx.errcode != EXT2_ET_UNIMPLEMENTED) {
364 fix_problem(ctx, PR_0_GETSIZE_ERROR, &pctx);
Theodore Ts'o08b21301997-11-03 19:42:40 +0000365 ctx->flags |= E2F_FLAG_ABORT;
366 return;
367 }
Theodore Ts'of8188ff1997-11-14 05:23:04 +0000368 if ((pctx.errcode != EXT2_ET_UNIMPLEMENTED) &&
Theodore Ts'o5dd8f962001-01-01 15:51:50 +0000369 (ctx->num_blocks < sb->s_blocks_count)) {
370 pctx.blk = sb->s_blocks_count;
Theodore Ts'of8188ff1997-11-14 05:23:04 +0000371 pctx.blk2 = ctx->num_blocks;
372 if (fix_problem(ctx, PR_0_FS_SIZE_WRONG, &pctx)) {
373 ctx->flags |= E2F_FLAG_ABORT;
374 return;
375 }
376 }
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000377 }
378
Theodore Ts'o5dd8f962001-01-01 15:51:50 +0000379 if (sb->s_log_block_size != sb->s_log_frag_size) {
380 pctx.blk = EXT2_BLOCK_SIZE(sb);
381 pctx.blk2 = EXT2_FRAG_SIZE(sb);
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000382 fix_problem(ctx, PR_0_NO_FRAGMENTS, &pctx);
Theodore Ts'o08b21301997-11-03 19:42:40 +0000383 ctx->flags |= E2F_FLAG_ABORT;
384 return;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000385 }
386
Theodore Ts'o5dd8f962001-01-01 15:51:50 +0000387 should_be = sb->s_frags_per_group >>
388 (sb->s_log_block_size - sb->s_log_frag_size);
389 if (sb->s_blocks_per_group != should_be) {
390 pctx.blk = sb->s_blocks_per_group;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000391 pctx.blk2 = should_be;
392 fix_problem(ctx, PR_0_BLOCKS_PER_GROUP, &pctx);
Theodore Ts'o08b21301997-11-03 19:42:40 +0000393 ctx->flags |= E2F_FLAG_ABORT;
394 return;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000395 }
396
Theodore Ts'o5dd8f962001-01-01 15:51:50 +0000397 should_be = (sb->s_log_block_size == 0) ? 1 : 0;
398 if (sb->s_first_data_block != should_be) {
399 pctx.blk = sb->s_first_data_block;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000400 pctx.blk2 = should_be;
401 fix_problem(ctx, PR_0_FIRST_DATA_BLOCK, &pctx);
Theodore Ts'o08b21301997-11-03 19:42:40 +0000402 ctx->flags |= E2F_FLAG_ABORT;
403 return;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000404 }
405
Theodore Ts'o5dd8f962001-01-01 15:51:50 +0000406 should_be = sb->s_inodes_per_group * fs->group_desc_count;
407 if (sb->s_inodes_count != should_be) {
408 pctx.ino = sb->s_inodes_count;
Theodore Ts'od4b0ce01999-06-18 01:09:29 +0000409 pctx.ino2 = should_be;
410 if (fix_problem(ctx, PR_0_INODE_COUNT_WRONG, &pctx)) {
Theodore Ts'o5dd8f962001-01-01 15:51:50 +0000411 sb->s_inodes_count = should_be;
Theodore Ts'od4b0ce01999-06-18 01:09:29 +0000412 ext2fs_mark_super_dirty(fs);
413 }
414 }
415
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000416 /*
417 * Verify the group descriptors....
418 */
419 first_block = fs->super->s_first_data_block;
420 last_block = first_block + blocks_per_group;
421
422 for (i = 0; i < fs->group_desc_count; i++) {
423 pctx.group = i;
424
425 if (i == fs->group_desc_count - 1)
426 last_block = fs->super->s_blocks_count;
427 if ((fs->group_desc[i].bg_block_bitmap < first_block) ||
428 (fs->group_desc[i].bg_block_bitmap >= last_block)) {
429 pctx.blk = fs->group_desc[i].bg_block_bitmap;
Theodore Ts'o24bfb442001-11-26 15:51:14 -0500430 if (fix_problem(ctx, PR_0_BB_NOT_GROUP, &pctx))
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000431 fs->group_desc[i].bg_block_bitmap = 0;
Theodore Ts'o24bfb442001-11-26 15:51:14 -0500432 }
433 if (fs->group_desc[i].bg_block_bitmap == 0) {
434 ctx->invalid_block_bitmap_flag[i]++;
435 ctx->invalid_bitmaps++;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000436 }
437 if ((fs->group_desc[i].bg_inode_bitmap < first_block) ||
438 (fs->group_desc[i].bg_inode_bitmap >= last_block)) {
439 pctx.blk = fs->group_desc[i].bg_inode_bitmap;
Theodore Ts'o24bfb442001-11-26 15:51:14 -0500440 if (fix_problem(ctx, PR_0_IB_NOT_GROUP, &pctx))
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000441 fs->group_desc[i].bg_inode_bitmap = 0;
Theodore Ts'o24bfb442001-11-26 15:51:14 -0500442 }
443 if (fs->group_desc[i].bg_inode_bitmap == 0) {
444 ctx->invalid_inode_bitmap_flag[i]++;
445 ctx->invalid_bitmaps++;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000446 }
447 if ((fs->group_desc[i].bg_inode_table < first_block) ||
448 ((fs->group_desc[i].bg_inode_table +
449 fs->inode_blocks_per_group - 1) >= last_block)) {
450 pctx.blk = fs->group_desc[i].bg_inode_table;
Theodore Ts'o24bfb442001-11-26 15:51:14 -0500451 if (fix_problem(ctx, PR_0_ITABLE_NOT_GROUP, &pctx))
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000452 fs->group_desc[i].bg_inode_table = 0;
Theodore Ts'o24bfb442001-11-26 15:51:14 -0500453 }
454 if (fs->group_desc[i].bg_inode_table == 0) {
455 ctx->invalid_inode_table_flag[i]++;
456 ctx->invalid_bitmaps++;
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000457 }
458 first_block += fs->super->s_blocks_per_group;
459 last_block += fs->super->s_blocks_per_group;
460 }
461 /*
462 * If we have invalid bitmaps, set the error state of the
463 * filesystem.
464 */
465 if (ctx->invalid_bitmaps && !(ctx->options & E2F_OPT_READONLY)) {
466 fs->super->s_state &= ~EXT2_VALID_FS;
467 ext2fs_mark_super_dirty(fs);
468 }
469
Theodore Ts'o4ea0a112000-05-08 13:33:17 +0000470 clear_problem_context(&pctx);
471
Theodore Ts'o54be2cc1998-02-01 12:58:48 +0000472#ifndef EXT2_SKIP_UUID
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000473 /*
474 * If the UUID field isn't assigned, assign it.
475 */
Theodore Ts'o5dd8f962001-01-01 15:51:50 +0000476 if (!(ctx->options & E2F_OPT_READONLY) && uuid_is_null(sb->s_uuid)) {
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000477 if (fix_problem(ctx, PR_0_ADD_UUID, &pctx)) {
Theodore Ts'o5dd8f962001-01-01 15:51:50 +0000478 uuid_generate(sb->s_uuid);
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000479 ext2fs_mark_super_dirty(fs);
480 }
481 }
Theodore Ts'o54be2cc1998-02-01 12:58:48 +0000482#endif
Theodore Ts'o4ea0a112000-05-08 13:33:17 +0000483
484 /*
485 * For the Hurd, check to see if the filetype option is set,
486 * since it doesn't support it.
487 */
Theodore Ts'o80bfaa32000-08-18 15:08:37 +0000488 if (!(ctx->options & E2F_OPT_READONLY) &&
489 fs->super->s_creator_os == EXT2_OS_HURD &&
Theodore Ts'o4ea0a112000-05-08 13:33:17 +0000490 (fs->super->s_feature_incompat &
491 EXT2_FEATURE_INCOMPAT_FILETYPE)) {
492 if (fix_problem(ctx, PR_0_HURD_CLEAR_FILETYPE, &pctx)) {
493 fs->super->s_feature_incompat &=
494 ~EXT2_FEATURE_INCOMPAT_FILETYPE;
495 ext2fs_mark_super_dirty(fs);
496
497 }
498 }
Theodore Ts'o80bfaa32000-08-18 15:08:37 +0000499
500 /*
Theodore Ts'o7b59f1e2000-12-13 18:11:44 +0000501 * If we have any of the compatibility flags set, we need to have a
502 * revision 1 filesystem. Most kernels will not check the flags on
503 * a rev 0 filesystem and we may have corruption issues because of
504 * the incompatible changes to the filesystem.
505 */
506 if (!(ctx->options & E2F_OPT_READONLY) &&
507 fs->super->s_rev_level == EXT2_GOOD_OLD_REV &&
508 (fs->super->s_feature_compat ||
509 fs->super->s_feature_ro_compat ||
510 fs->super->s_feature_incompat) &&
511 fix_problem(ctx, PR_0_FS_REV_LEVEL, &pctx)) {
Theodore Ts'oa917d1c2000-12-13 18:36:23 +0000512 ext2fs_update_dynamic_rev(fs);
Theodore Ts'o7b59f1e2000-12-13 18:11:44 +0000513 ext2fs_mark_super_dirty(fs);
514 }
515
516 /*
Theodore Ts'o80bfaa32000-08-18 15:08:37 +0000517 * Clean up any orphan inodes, if present.
518 */
519 if (!(ctx->options & E2F_OPT_READONLY) && release_orphan_inodes(ctx)) {
520 fs->super->s_state &= ~EXT2_VALID_FS;
Theodore Ts'o7b59f1e2000-12-13 18:11:44 +0000521 ext2fs_mark_super_dirty(fs);
Theodore Ts'o80bfaa32000-08-18 15:08:37 +0000522 }
523
Theodore Ts'o773fd8a2001-10-06 21:26:27 -0400524 /*
525 * Move the ext3 journal file, if necessary.
526 */
527 e2fsck_move_ext3_journal(ctx);
Theodore Ts'o1b6bf171997-10-03 17:48:10 +0000528 return;
529}
Theodore Ts'o80bfaa32000-08-18 15:08:37 +0000530
531