ext2_extent_handle_t handle;
struct ext2_extent_info info;
struct ext2fs_extent extent;
+ int encrypted = 0;
if ((inode->i_size_high || inode->i_size == 0) ||
(inode->i_flags & EXT2_INDEX_FL))
if (io_channel_read_blk64(fs->io, inode->i_block[0], 1, buf))
return 0;
- len = strnlen(buf, fs->blocksize);
+ if (inode->i_flags & EXT4_ENCRYPT_FL) {
+ len = ext2fs_le32_to_cpu(*((__u32 *)buf)) + 4;
+ } else {
+ len = strnlen(buf, fs->blocksize);
+ }
if (len == fs->blocksize)
return 0;
} else if (inode->i_flags & EXT4_INLINE_DATA_FL) {
return 0;
}
if (len != inode->i_size)
- return 0;
+ if ((inode->i_flags & EXT4_ENCRYPT_FL) == 0)
+ return 0;
return 1;
}
return 0;
}
+static void pass1_readahead(e2fsck_t ctx, dgrp_t *group, ext2_ino_t *next_ino)
+{
+ ext2_ino_t inodes_in_group = 0, inodes_per_block, inodes_per_buffer;
+ dgrp_t start = *group, grp;
+ blk64_t blocks_to_read = 0;
+ errcode_t err = EXT2_ET_INVALID_ARGUMENT;
+
+ if (ctx->readahead_kb == 0)
+ goto out;
+
+ /* Keep iterating groups until we have enough to readahead */
+ inodes_per_block = EXT2_INODES_PER_BLOCK(ctx->fs->super);
+ for (grp = start; grp < ctx->fs->group_desc_count; grp++) {
+ if (ext2fs_bg_flags_test(ctx->fs, grp, EXT2_BG_INODE_UNINIT))
+ continue;
+ inodes_in_group = ctx->fs->super->s_inodes_per_group -
+ ext2fs_bg_itable_unused(ctx->fs, grp);
+ blocks_to_read += (inodes_in_group + inodes_per_block - 1) /
+ inodes_per_block;
+ if (blocks_to_read * ctx->fs->blocksize >
+ ctx->readahead_kb * 1024)
+ break;
+ }
+
+ err = e2fsck_readahead(ctx->fs, E2FSCK_READA_ITABLE, start,
+ grp - start + 1);
+ if (err == EAGAIN) {
+ ctx->readahead_kb /= 2;
+ err = 0;
+ }
+
+out:
+ if (err) {
+ /* Error; disable itable readahead */
+ *group = ctx->fs->group_desc_count;
+ *next_ino = ctx->fs->super->s_inodes_count;
+ } else {
+ /*
+ * Don't do more readahead until we've reached the first inode
+ * of the last inode scan buffer block for the last group.
+ */
+ *group = grp + 1;
+ inodes_per_buffer = (ctx->inode_buffer_blocks ?
+ ctx->inode_buffer_blocks :
+ EXT2_INODE_SCAN_DEFAULT_BUFFER_BLOCKS) *
+ ctx->fs->blocksize /
+ EXT2_INODE_SIZE(ctx->fs->super);
+ inodes_in_group--;
+ *next_ino = inodes_in_group -
+ (inodes_in_group % inodes_per_buffer) + 1 +
+ (grp * ctx->fs->super->s_inodes_per_group);
+ }
+}
+
void e2fsck_pass1(e2fsck_t ctx)
{
int i;
int low_dtime_check = 1;
int inode_size;
int failed_csum = 0;
+ ext2_ino_t ino_threshold = 0;
+ dgrp_t ra_group = 0;
init_resource_track(&rtrack, ctx->fs->io);
clear_problem_context(&pctx);
+ /* If we can do readahead, figure out how many groups to pull in. */
+ if (!e2fsck_can_readahead(ctx->fs))
+ ctx->readahead_kb = 0;
+ else if (ctx->readahead_kb == ~0ULL)
+ ctx->readahead_kb = e2fsck_guess_readahead(ctx->fs);
+ pass1_readahead(ctx, &ra_group, &ino_threshold);
+
if (!(ctx->options & E2F_OPT_PREEN))
fix_problem(ctx, PR_1_PASS_HEADER, &pctx);
old_op = ehandler_operation(_("getting next inode from scan"));
pctx.errcode = ext2fs_get_next_inode_full(scan, &ino,
inode, inode_size);
+ if (ino > ino_threshold)
+ pass1_readahead(ctx, &ra_group, &ino_threshold);
ehandler_operation(old_op);
if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
return;
pctx.errcode = ext2fs_inline_data_size(fs, ino, &size);
if (!pctx.errcode && size &&
- !fix_problem(ctx, PR_1_INLINE_DATA_FEATURE, &pctx)) {
+ fix_problem(ctx, PR_1_INLINE_DATA_FEATURE, &pctx)) {
sb->s_feature_incompat |=
EXT4_FEATURE_INCOMPAT_INLINE_DATA;
ext2fs_mark_super_dirty(fs);
inlinedata_fs = 1;
- } else if (!fix_problem(ctx, PR_1_INLINE_DATA_SET, &pctx)) {
+ } else if (fix_problem(ctx, PR_1_INLINE_DATA_SET, &pctx)) {
e2fsck_clear_inode(ctx, ino, inode, 0, "pass1");
/* skip FINISH_INODE_LOOP */
continue;
ctx->flags |= E2F_FLAG_ABORT;
goto endit;
}
+ if (LINUX_S_ISLNK(inode->i_mode))
+ inode->i_flags &= ~EXT4_INLINE_DATA_FL;
e2fsck_write_inode(ctx, ino, inode,
"pass1");
failed_csum = 0;
inlinedata_fs = (ctx->fs->super->s_feature_incompat &
EXT4_FEATURE_INCOMPAT_INLINE_DATA);
- if (inode->i_flags & EXT2_COMPRBLK_FL) {
- if (fs->super->s_feature_incompat &
- EXT2_FEATURE_INCOMPAT_COMPRESSION)
- pb.compressed = 1;
- else {
- if (fix_problem(ctx, PR_1_COMPR_SET, pctx)) {
- inode->i_flags &= ~EXT2_COMPRBLK_FL;
- dirty_inode++;
- }
- }
- }
-
if (check_ext_attr(ctx, pctx, block_buf)) {
if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
goto out;
pctx = p->pctx;
ctx = p->ctx;
- if (p->compressed && (blk == EXT2FS_COMPRESSED_BLKADDR)) {
- /* todo: Check that the comprblk_fl is high, that the
- blkaddr pattern looks right (all non-holes up to
- first EXT2FS_COMPRESSED_BLKADDR, then all
- EXT2FS_COMPRESSED_BLKADDR up to end of cluster),
- that the feature_incompat bit is high, and that the
- inode is a regular file. If we're doing a "full
- check" (a concept introduced to e2fsck by e2compr,
- meaning that we look at data blocks as well as
- metadata) then call some library routine that
- checks the compressed data. I'll have to think
- about this, because one particularly important
- problem to be able to fix is to recalculate the
- cluster size if necessary. I think that perhaps
- we'd better do most/all e2compr-specific checks
- separately, after the non-e2compr checks. If not
- doing a full check, it may be useful to test that
- the personality is linux; e.g. if it isn't then
- perhaps this really is just an illegal block. */
- return 0;
- }
-
/*
* For a directory, add logical block zero for processing even if it's
* not mapped or we'll be perennially stuck with broken "." and ".."
* file be contiguous. (Which can never be true for really
* big files that are greater than a block group.)
*/
- if (!HOLE_BLKADDR(p->previous_block) && p->ino != EXT2_RESIZE_INO) {
+ if (p->previous_block && p->ino != EXT2_RESIZE_INO) {
if (p->previous_block+1 != blk) {
if (ctx->options & E2F_OPT_FRAGCHECK) {
char type = '?';
struct problem_context *pctx;
e2fsck_t ctx;
- /*
- * Note: This function processes blocks for the bad blocks
- * inode, which is never compressed. So we don't use HOLE_BLKADDR().
- */
-
if (!blk)
return 0;
return retval;
}
- retval = ext2fs_new_block2(fs, goal, 0, &new_block);
+ retval = ext2fs_new_block2(fs, goal, fs->block_map, &new_block);
if (retval)
return retval;
}