Whamcloud - gitweb
e2fsck: read-ahead metadata during passes 1, 2, and 4
[tools/e2fsprogs.git] / e2fsck / pass1.c
index 319d23b..b13be54 100644 (file)
@@ -898,6 +898,60 @@ out:
        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;
@@ -920,10 +974,19 @@ void e2fsck_pass1(e2fsck_t ctx)
        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);
 
@@ -1103,6 +1166,8 @@ void e2fsck_pass1(e2fsck_t ctx)
                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;
@@ -1196,12 +1261,12 @@ void e2fsck_pass1(e2fsck_t ctx)
 
                        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;
@@ -1251,6 +1316,8 @@ void e2fsck_pass1(e2fsck_t ctx)
                                                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;
@@ -2874,18 +2941,6 @@ static void check_blocks(e2fsck_t ctx, struct problem_context *pctx,
        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;
@@ -3159,28 +3214,6 @@ static int process_block(ext2_filsys fs,
        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 ".."
@@ -3209,7 +3242,7 @@ static int process_block(ext2_filsys fs,
         * 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 = '?';
@@ -3383,11 +3416,6 @@ static int process_bad_block(ext2_filsys fs,
        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;
 
@@ -3823,7 +3851,7 @@ static errcode_t e2fsck_get_alloc_block(ext2_filsys fs, blk64_t goal,
                                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;
        }