* - A bitmap of which inodes are in use. (inode_used_map)
* - A bitmap of which inodes are directories. (inode_dir_map)
* - A bitmap of which inodes are regular files. (inode_reg_map)
- * - A bitmap of which inodes have bad fields. (inode_bad_map)
+ * - An icount mechanism is used to keep track of
+ * inodes with bad fields and its badness (ctx->inode_badness)
* - A bitmap of which inodes are in bad blocks. (inode_bb_map)
* - A bitmap of which inodes are imagic inodes. (inode_imagic_map)
* - A bitmap of which inodes need to be expanded (expand_eisize_map)
static void mark_table_blocks(e2fsck_t ctx);
static void alloc_bb_map(e2fsck_t ctx);
static void alloc_imagic_map(e2fsck_t ctx);
-static void mark_inode_bad(e2fsck_t ctx, ino_t ino);
static void handle_fs_bad_blocks(e2fsck_t ctx);
static void process_inodes(e2fsck_t ctx, char *block_buf);
static EXT2_QSORT_TYPE process_inode_cmp(const void *a, const void *b);
if (!(pctx->inode->i_flags & BAD_SPECIAL_FLAGS))
return;
+ e2fsck_mark_inode_bad(ctx, pctx->ino, BADNESS_NORMAL);
if (!fix_problem(ctx, PR_1_SET_IMMUTABLE, pctx))
return;
if ((inode->i_size == 0) && (inode->i_size_high == 0))
return;
+ e2fsck_mark_inode_bad(ctx, pctx->ino, BADNESS_NORMAL);
if (!fix_problem(ctx, PR_1_SET_NONZSIZE, pctx))
return;
*/
if (inode->i_extra_isize &&
(inode->i_extra_isize < min || inode->i_extra_isize > max)) {
+ e2fsck_mark_inode_bad(ctx, pctx->ino, BADNESS_NORMAL);
if (!fix_problem(ctx, PR_1_EXTRA_ISIZE, pctx))
return;
inode->i_extra_isize = ctx->want_extra_isize;
(dirent->rec_len % 4))
return;
+ e2fsck_mark_inode_bad(ctx, pctx->ino, BADNESS_NORMAL);
if (fix_problem(ctx, PR_1_TREAT_AS_DIRECTORY, pctx)) {
inode->i_mode = (inode->i_mode & 07777) | LINUX_S_IFDIR;
e2fsck_write_inode_full(ctx, pctx->ino, inode,
ext2_filsys fs = ctx->fs;
ext2_ino_t ino;
struct ext2_inode *inode;
+ struct ext2_inode_large *inode_large;
ext2_inode_scan scan;
char *block_buf;
#ifdef RESOURCE_TRACK
ino, 0);
e2fsck_write_inode(ctx, ino, inode,
"pass1");
+ } else {
+ e2fsck_mark_inode_bad(ctx, ino,
+ BADNESS_NORMAL);
}
-
}
/*
* If dtime is set, offer to clear it. mke2fs
e2fsck_write_inode(ctx, ino, inode,
"pass1");
}
+ e2fsck_mark_inode_bad(ctx, ino, BADNESS_NORMAL);
}
} else if (ino == EXT2_JOURNAL_INO) {
ext2fs_mark_inode_bitmap(ctx->inode_used_map, ino);
inode->i_dtime = 0;
e2fsck_write_inode(ctx, ino, inode, "pass1");
}
+ e2fsck_mark_inode_bad(ctx, ino, BADNESS_NORMAL);
}
ext2fs_mark_inode_bitmap(ctx->inode_used_map, ino);
frag = fsize = 0;
}
+ /* Fixed in pass2, e2fsck_process_bad_inode(). */
if (inode->i_faddr || frag || fsize ||
(LINUX_S_ISDIR(inode->i_mode) && inode->i_dir_acl))
- mark_inode_bad(ctx, ino);
+ e2fsck_mark_inode_bad(ctx, ino, BADNESS_NORMAL);
+ /* Fixed in pass2, e2fsck_process_bad_inode(). */
if ((fs->super->s_creator_os == EXT2_OS_LINUX) &&
!(fs->super->s_feature_ro_compat &
EXT4_FEATURE_RO_COMPAT_HUGE_FILE) &&
(inode->osd2.linux2.l_i_blocks_hi != 0))
- mark_inode_bad(ctx, ino);
+ e2fsck_mark_inode_bad(ctx, ino, BADNESS_NORMAL);
if (inode->i_flags & EXT2_IMAGIC_FL) {
if (imagic_fs) {
if (!ctx->inode_imagic_map)
e2fsck_write_inode(ctx, ino,
inode, "pass1");
}
+ e2fsck_mark_inode_bad(ctx, ino, BADNESS_NORMAL);
}
}
check_immutable(ctx, &pctx);
check_size(ctx, &pctx);
ctx->fs_sockets_count++;
- } else
- mark_inode_bad(ctx, ino);
+ } else {
+ e2fsck_mark_inode_bad(ctx, ino, BADNESS_NORMAL);
+ }
+
+ if (inode->i_atime > ctx->now + ctx->now_tolerance_val ||
+ inode->i_mtime > ctx->now + ctx->now_tolerance_val)
+ e2fsck_mark_inode_bad(ctx, ino, BADNESS_NORMAL);
+
+ if (inode->i_ctime < sb->s_mkfs_time ||
+ inode->i_ctime > ctx->now + ctx->now_tolerance_val)
+ e2fsck_mark_inode_bad(ctx, ino, BADNESS_HIGH);
+
+ if (EXT4_FITS_IN_INODE(inode_large,
+ (struct ext2_inode_large *)inode, i_crtime)) {
+ if (((struct ext2_inode_large *)inode)->i_crtime <
+ sb->s_mkfs_time ||
+ ((struct ext2_inode_large *)inode)->i_crtime >
+ ctx->now + ctx->now_tolerance_val) {
+ e2fsck_mark_inode_bad(ctx, ino, BADNESS_HIGH);
+ }
+ }
+
+ /* Is it a regular file */
+ if ((LINUX_S_ISREG(inode->i_mode)) &&
+ /* File size > 2TB */
+ ((((long long)inode->i_size_high << 32) +
+ inode->i_size) > BADNESS_LARGE_FILE) &&
+ /* fs does not have huge file feature */
+ ((fs->super->s_creator_os == EXT2_OS_LINUX) &&
+ !(fs->super->s_feature_ro_compat &
+ EXT4_FEATURE_RO_COMPAT_HUGE_FILE) &&
+ /* inode does not have enough blocks for size */
+ (inode->osd2.linux2.l_i_blocks_hi != 0))) {
+ e2fsck_mark_inode_bad(ctx, ino, BADNESS_NORMAL);
+ }
eh = (struct ext3_extent_header *)inode->i_block;
if ((inode->i_flags & EXT4_EXTENTS_FL)) {
ext2fs_mark_super_dirty(fs);
extent_fs = 1;
}
- } else if (fix_problem(ctx, PR_1_SET_EXTENT_FL, &pctx)){
- inode->i_flags &= ~EXT4_EXTENTS_FL;
- e2fsck_write_inode(ctx, ino, inode, "pass1");
- goto check_ind_inode;
+ } else {
+ e2fsck_mark_inode_bad(ctx, ino, BADNESS_NORMAL);
+ if (fix_problem(ctx, PR_1_SET_EXTENT_FL,
+ &pctx)) {
+ inode->i_flags &= ~EXT4_EXTENTS_FL;
+ e2fsck_write_inode(ctx, ino,
+ inode,"pass1");
+ goto check_ind_inode;
+ }
}
} else if (extent_fs &&
(LINUX_S_ISREG(inode->i_mode) ||
LINUX_S_ISDIR(inode->i_mode)) &&
ext2fs_extent_header_verify(eh, EXT2_N_BLOCKS *
- sizeof(__u32)) == 0 &&
- fix_problem(ctx, PR_1_UNSET_EXTENT_FL, &pctx)) {
- inode->i_flags |= EXT4_EXTENTS_FL;
- e2fsck_write_inode(ctx, ino, inode, "pass1");
+ sizeof(__u32)) == 0) {
+ if (fix_problem(ctx, PR_1_UNSET_EXTENT_FL,
+ &pctx)) {
+ inode->i_flags |= EXT4_EXTENTS_FL;
+ e2fsck_write_inode(ctx, ino, inode,
+ "pass1");
+ }
+ e2fsck_mark_inode_bad(ctx, ino, BADNESS_NORMAL);
}
if (extent_fs && inode->i_flags & EXT4_EXTENTS_FL) {
ctx->extent_files++;
}
/*
- * Mark an inode as being bad in some what
+ * Mark an inode as being bad and increment its badness counter.
*/
-static void mark_inode_bad(e2fsck_t ctx, ino_t ino)
+void e2fsck_mark_inode_bad(e2fsck_t ctx, ino_t ino, int count)
{
- struct problem_context pctx;
-
- if (!ctx->inode_bad_map) {
- clear_problem_context(&pctx);
+ struct problem_context pctx;
+ __u16 result;
- pctx.errcode = ext2fs_allocate_inode_bitmap(ctx->fs,
- _("bad inode map"), &ctx->inode_bad_map);
+ if (!ctx->inode_badness) {
+ clear_problem_context(&pctx);
+ pctx.errcode = ext2fs_create_icount2(ctx->fs, 0, 0, NULL,
+ &ctx->inode_badness);
if (pctx.errcode) {
- pctx.num = 3;
- fix_problem(ctx, PR_1_ALLOCATE_IBITMAP_ERROR, &pctx);
- /* Should never get here */
+ fix_problem(ctx, PR_1_ALLOCATE_ICOUNT, &pctx);
ctx->flags |= E2F_FLAG_ABORT;
return;
}
}
- ext2fs_mark_inode_bitmap(ctx->inode_bad_map, ino);
+ ext2fs_icount_fetch(ctx->inode_badness, ino, &result);
+ ext2fs_icount_store(ctx->inode_badness, ino, count + result);
}
-
/*
* This procedure will allocate the inode "bb" (badblock) map table
*/
if (!(fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_EXT_ATTR) ||
(blk < fs->super->s_first_data_block) ||
(blk >= fs->super->s_blocks_count)) {
- mark_inode_bad(ctx, ino);
+ /* Fixed in pass2, e2fsck_process_bad_inode(). */
+ e2fsck_mark_inode_bad(ctx, ino, BADNESS_NORMAL);
return 0;
}
if ((!LINUX_S_ISDIR(inode->i_mode) &&
fix_problem(ctx, PR_1_HTREE_NODIR, pctx)) ||
- (!(fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_DIR_INDEX) &&
- fix_problem(ctx, PR_1_HTREE_SET, pctx)))
- return 1;
+ (!(fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_DIR_INDEX))) {
+ e2fsck_mark_inode_bad(ctx, ino, BADNESS_NORMAL);
+ if (fix_problem(ctx, PR_1_HTREE_SET, pctx))
+ return 1;
+ }
ext2fs_block_iterate2(fs, ino, BLOCK_FLAG_DATA_ONLY | BLOCK_FLAG_HOLE,
block_buf, htree_blk_iter_cb, &blk);
if (((blk == 0) ||
(blk < fs->super->s_first_data_block) ||
- (blk >= fs->super->s_blocks_count)) &&
- fix_problem(ctx, PR_1_HTREE_BADROOT, pctx))
- return 1;
+ (blk >= fs->super->s_blocks_count))) {
+ e2fsck_mark_inode_bad(ctx, ino, BADNESS_NORMAL);
+ if (fix_problem(ctx, PR_1_HTREE_BADROOT, pctx))
+ return 1;
+ }
retval = io_channel_read_blk(fs->io, blk, 1, block_buf);
- if (retval && fix_problem(ctx, PR_1_HTREE_BADROOT, pctx))
- return 1;
+ if (retval) {
+ e2fsck_mark_inode_bad(ctx, ino, BADNESS_NORMAL);
+ if (fix_problem(ctx, PR_1_HTREE_BADROOT, pctx))
+ return 1;
+ }
/* XXX should check that beginning matches a directory */
root = (struct ext2_dx_root_info *) (block_buf + 24);
bad++;
}
+ if (num_indir <= EXT2_N_BLOCKS)
+ e2fsck_mark_inode_bad(p->ctx, p->ino, bad);
+
if ((num_indir <= EXT2_N_BLOCKS && bad > 4) || bad > 8)
return PR_1_INDIRECT_BAD;
pctx->blkcount = ex->ee_start;
pctx->num = ex->ee_len;
pctx->blk = ex->ee_block;
+ /* To ensure that extent is in inode */
+ if (eh->eh_max == 4)
+ e2fsck_mark_inode_bad(p->ctx, p->ino,
+ BADNESS_HIGH);
if (fix_problem(ctx, PR_1_EXTENT_BAD, pctx)) {
ext2fs_extent_remove(eh, ex);
i--; ex--; /* check next (moved) item */
pctx->blkcount = ix->ei_leaf;;
pctx->num = i;
pctx->blk = ix->ei_block;
+ /* To ensure that extent_idx is in inode */
+ if (eh->eh_max == 4)
+ e2fsck_mark_inode_bad(p->ctx, p->ino,
+ BADNESS_HIGH);
if (fix_problem(ctx, PR_1_EXTENT_IDX_BAD,pctx)){
ext2fs_extent_index_remove(eh, ix);
i--; ix--; /* check next (moved) item */
continue;
}
}
-
ix_prev = ix;
}
}
inode->i_flags &= ~EXT2_COMPRBLK_FL;
dirty_inode++;
}
+ e2fsck_mark_inode_bad(ctx, ino, BADNESS_NORMAL);
}
}
ext2fs_icount_store(ctx->inode_link_info, ino, 0);
inode->i_dtime = ctx->now;
dirty_inode++;
+ ext2fs_icount_store(ctx->inode_badness, ino, 0);
ext2fs_unmark_inode_bitmap(ctx->inode_dir_map, ino);
ext2fs_unmark_inode_bitmap(ctx->inode_reg_map, ino);
ext2fs_unmark_inode_bitmap(ctx->inode_used_map, ino);
ctx->fs_directory_count--;
goto out;
}
+ /*
+ * The mode might be in-correct. Increasing the badness by
+ * small amount won't hurt much.
+ */
+ e2fsck_mark_inode_bad(ctx, ino, BADNESS_NORMAL);
}
pb.num_blocks *= (fs->blocksize / 512);
inode->i_size_high = pctx->num >> 32;
dirty_inode++;
}
+ e2fsck_mark_inode_bad(ctx, ino, BADNESS_NORMAL);
pctx->num = 0;
}
if (LINUX_S_ISREG(inode->i_mode) &&
inode->i_blocks = pb.num_blocks;
dirty_inode++;
}
+ e2fsck_mark_inode_bad(ctx, ino, BADNESS_NORMAL);
pctx->num = 0;
}
out:
ext2fs_free_mem(&buf);
ext2fs_free_dblist(fs->dblist);
- if (ctx->inode_bad_map) {
- ext2fs_free_inode_bitmap(ctx->inode_bad_map);
- ctx->inode_bad_map = 0;
- }
if (ctx->inode_reg_map) {
ext2fs_free_inode_bitmap(ctx->inode_reg_map);
ctx->inode_reg_map = 0;
{
int filetype = dirent->name_len >> 8;
int should_be = EXT2_FT_UNKNOWN;
+ __u32 result;
struct ext2_inode inode;
if (!(ctx->fs->super->s_feature_incompat &
return 1;
}
+ if (ctx->inode_badness)
+ ext2fs_icount_fetch32(ctx->inode_badness, dirent->inode,
+ &result);
+
if (ext2fs_test_inode_bitmap(ctx->inode_dir_map, dirent->inode)) {
should_be = EXT2_FT_DIR;
} else if (ext2fs_test_inode_bitmap(ctx->inode_reg_map,
dirent->inode)) {
should_be = EXT2_FT_REG_FILE;
- } else if (ctx->inode_bad_map &&
- ext2fs_test_inode_bitmap(ctx->inode_bad_map,
- dirent->inode))
+ } else if (ctx->inode_badness && result >= BADNESS_BAD_MODE) {
should_be = 0;
- else {
+ } else {
e2fsck_read_inode(ctx, dirent->inode, &inode,
"check_filetype");
should_be = ext2_file_type(inode.i_mode);
* (We wait until now so that we can display the
* pathname to the user.)
*/
- if (ctx->inode_bad_map &&
- ext2fs_test_inode_bitmap(ctx->inode_bad_map,
- dirent->inode)) {
- if (e2fsck_process_bad_inode(ctx, ino,
- dirent->inode,
- buf + fs->blocksize)) {
+ if ((ctx->inode_badness) &&
+ ext2fs_icount_is_set(ctx->inode_badness, dirent->inode)) {
+ if (e2fsck_process_bad_inode(ctx, ino, dirent->inode,
+ buf + fs->blocksize)) {
dirent->inode = 0;
dir_modified++;
goto next;
e2fsck_read_bitmaps(ctx);
ext2fs_unmark_inode_bitmap(ctx->inode_used_map, ino);
ext2fs_unmark_inode_bitmap(ctx->inode_dir_map, ino);
- if (ctx->inode_bad_map)
- ext2fs_unmark_inode_bitmap(ctx->inode_bad_map, ino);
+ if (ctx->inode_badness)
+ ext2fs_icount_store(ctx->inode_badness, ino, 0);
ext2fs_inode_alloc_stats2(fs, ino, -1, LINUX_S_ISDIR(inode.i_mode));
if (inode.i_file_acl &&
int not_fixed = 0;
unsigned char *frag, *fsize;
struct problem_context pctx;
- int problem = 0;
+ int problem = 0;
+ __u16 badness;
+ ext2fs_icount_fetch(ctx->inode_badness, ino, &badness);
e2fsck_read_inode(ctx, ino, &inode, "process_bad_inode");
clear_problem_context(&pctx);
inode_modified++;
} else
not_fixed++;
+ badness += BADNESS_NORMAL;
}
if (!LINUX_S_ISDIR(inode.i_mode) && !LINUX_S_ISREG(inode.i_mode) &&
} else
not_fixed++;
problem = 0;
+ /*
+ * A high value is associated with bad mode in order to detect
+ * that mode was corrupt in check_filetype()
+ */
+ badness += BADNESS_BAD_MODE;
}
if (inode.i_faddr) {
inode_modified++;
} else
not_fixed++;
+ badness += BADNESS_NORMAL;
}
switch (fs->super->s_creator_os) {
inode_modified++;
} else
not_fixed++;
+ badness += BADNESS_NORMAL;
pctx.num = 0;
}
if (fsize && *fsize) {
inode_modified++;
} else
not_fixed++;
+ badness += BADNESS_NORMAL;
pctx.num = 0;
}
+ /* In pass1 these conditions were used to mark inode bad so that
+ * it calls e2fsck_process_bad_inode and make an extensive check
+ * plus prompt for action to be taken. To compensate for badness
+ * incremented in pass1 by this condition, decrease it.
+ */
+ if ((inode.i_faddr || frag || fsize ||
+ (LINUX_S_ISDIR(inode.i_mode) && inode.i_dir_acl)) ||
+ (inode.i_file_acl &&
+ (!(fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_EXT_ATTR) ||
+ (inode.i_file_acl < fs->super->s_first_data_block) ||
+ (inode.i_file_acl >= fs->super->s_blocks_count)))) {
+ /* badness can be 0 if called from pass4. */
+ if (badness)
+ badness -= BADNESS_NORMAL;
+ }
+
if ((fs->super->s_creator_os == EXT2_OS_LINUX) &&
- !(fs->super->s_feature_ro_compat &
+ !(fs->super->s_feature_ro_compat &
EXT4_FEATURE_RO_COMPAT_HUGE_FILE) &&
(inode.osd2.linux2.l_i_blocks_hi != 0)) {
pctx.num = inode.osd2.linux2.l_i_blocks_hi;
inode.osd2.linux2.l_i_blocks_hi = 0;
inode_modified++;
}
+ /* Badness was increased in pass1 for this condition */
+ /* badness += BADNESS_NORMAL; */
}
if (inode.i_file_acl &&
inode_modified++;
} else
not_fixed++;
+ badness += BADNESS_NORMAL;
}
if (inode.i_dir_acl &&
LINUX_S_ISDIR(inode.i_mode)) {
inode_modified++;
} else
not_fixed++;
+ badness += BADNESS_NORMAL;
+ }
+
+ /*
+ * The high value due to BADNESS_BAD_MODE should not delete the inode.
+ */
+ if ((badness - ((badness >= BADNESS_BAD_MODE) ? BADNESS_BAD_MODE : 0))>=
+ ctx->inode_badness_threshold) {
+ pctx.num = badness;
+ if (fix_problem(ctx, PR_2_INODE_TOOBAD, &pctx)) {
+ deallocate_inode(ctx, ino, 0);
+ if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
+ return 0;
+ return 1;
+ }
+ not_fixed++;
}
if (inode_modified)
e2fsck_write_inode(ctx, ino, &inode, "process_bad_inode");
- if (!not_fixed && ctx->inode_bad_map)
- ext2fs_unmark_inode_bitmap(ctx->inode_bad_map, ino);
+ if (ctx->inode_badness)
+ ext2fs_icount_store(ctx->inode_badness, ino, 0);
return 0;
}