Whamcloud - gitweb
e2fsck: check the checksum seed feature flag is set correctly
[tools/e2fsprogs.git] / e2fsck / pass2.c
index 94665c6..6a7215a 100644 (file)
@@ -47,7 +47,7 @@
 
 #include "e2fsck.h"
 #include "problem.h"
-#include "dict.h"
+#include "support/dict.h"
 
 #ifdef NO_INLINE_FUNCS
 #define _INLINE_
@@ -61,6 +61,9 @@
  * Keeps track of how many times an inode is referenced.
  */
 static void deallocate_inode(e2fsck_t ctx, ext2_ino_t ino, char* block_buf);
+static int check_dir_block2(ext2_filsys fs,
+                          struct ext2_db_entry2 *dir_blocks_info,
+                          void *priv_data);
 static int check_dir_block(ext2_filsys fs,
                           struct ext2_db_entry2 *dir_blocks_info,
                           void *priv_data);
@@ -77,6 +80,9 @@ struct check_dir_struct {
        struct problem_context  pctx;
        int     count, max;
        e2fsck_t ctx;
+       unsigned long long list_offset;
+       unsigned long long ra_entries;
+       unsigned long long next_ra_off;
 };
 
 void e2fsck_pass2(e2fsck_t ctx)
@@ -96,6 +102,9 @@ void e2fsck_pass2(e2fsck_t ctx)
        int                     i, depth;
        problem_t               code;
        int                     bad_dir;
+       int (*check_dir_func)(ext2_filsys fs,
+                             struct ext2_db_entry2 *dir_blocks_info,
+                             void *priv_data);
 
        init_resource_track(&rtrack, ctx->fs->io);
        clear_problem_context(&cd.pctx);
@@ -139,30 +148,33 @@ void e2fsck_pass2(e2fsck_t ctx)
        cd.ctx = ctx;
        cd.count = 1;
        cd.max = ext2fs_dblist_count2(fs->dblist);
+       cd.list_offset = 0;
+       cd.ra_entries = ctx->readahead_kb * 1024 / ctx->fs->blocksize;
+       cd.next_ra_off = 0;
 
        if (ctx->progress)
                (void) (ctx->progress)(ctx, 2, 0, cd.max);
 
-       if (fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_DIR_INDEX)
+       if (ext2fs_has_feature_dir_index(fs->super))
                ext2fs_dblist_sort2(fs->dblist, special_dir_block_cmp);
 
-       cd.pctx.errcode = ext2fs_dblist_iterate2(fs->dblist, check_dir_block,
+       check_dir_func = cd.ra_entries ? check_dir_block2 : check_dir_block;
+       cd.pctx.errcode = ext2fs_dblist_iterate2(fs->dblist, check_dir_func,
                                                 &cd);
-       if (ctx->flags & E2F_FLAG_SIGNAL_MASK || ctx->flags & E2F_FLAG_RESTART)
-               return;
-
        if (ctx->flags & E2F_FLAG_RESTART_LATER) {
                ctx->flags |= E2F_FLAG_RESTART;
-               return;
+               ctx->flags &= ~E2F_FLAG_RESTART_LATER;
        }
 
+       if (ctx->flags & E2F_FLAG_RUN_RETURN)
+               return;
+
        if (cd.pctx.errcode) {
                fix_problem(ctx, PR_2_DBLIST_ITERATE, &cd.pctx);
                ctx->flags |= E2F_FLAG_ABORT;
                return;
        }
 
-#ifdef ENABLE_HTREE
        for (i=0; (dx_dir = e2fsck_dx_dir_info_iter(ctx, &i)) != 0;) {
                if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
                        return;
@@ -251,7 +263,7 @@ void e2fsck_pass2(e2fsck_t ctx)
                }
        }
        e2fsck_free_dx_dir_info(ctx);
-#endif
+
        ext2fs_free_mem(&buf);
        ext2fs_free_dblist(fs->dblist);
 
@@ -270,11 +282,9 @@ void e2fsck_pass2(e2fsck_t ctx)
 
        clear_problem_context(&pctx);
        if (ctx->large_files) {
-               if (!(sb->s_feature_ro_compat &
-                     EXT2_FEATURE_RO_COMPAT_LARGE_FILE) &&
+               if (!ext2fs_has_feature_large_file(sb) &&
                    fix_problem(ctx, PR_2_FEATURE_LARGE_FILES, &pctx)) {
-                       sb->s_feature_ro_compat |=
-                               EXT2_FEATURE_RO_COMPAT_LARGE_FILE;
+                       ext2fs_set_feature_large_file(sb);
                        fs->flags &= ~EXT2_FLAG_MASTER_SB_ONLY;
                        ext2fs_mark_super_dirty(fs);
                }
@@ -463,7 +473,6 @@ static int check_dotdot(e2fsck_t ctx,
  */
 static int check_name(e2fsck_t ctx,
                      struct ext2_dir_entry *dirent,
-                     ext2_ino_t dir_ino,
                      struct problem_context *pctx)
 {
        int     i;
@@ -483,6 +492,20 @@ static int check_name(e2fsck_t ctx,
        return ret;
 }
 
+static int encrypted_check_name(e2fsck_t ctx,
+                               struct ext2_dir_entry *dirent,
+                               struct problem_context *pctx)
+{
+       if (ext2fs_dirent_name_len(dirent) < EXT4_CRYPTO_BLOCK_SIZE) {
+               if (fix_problem(ctx, PR_2_BAD_ENCRYPTED_NAME, pctx)) {
+                       dirent->inode = 0;
+                       return 1;
+               }
+               ext2fs_unmark_valid(ctx->fs);
+       }
+       return 0;
+}
+
 /*
  * Check the directory filetype (if present)
  */
@@ -495,8 +518,7 @@ static _INLINE_ int check_filetype(e2fsck_t ctx,
        int     should_be = EXT2_FT_UNKNOWN;
        struct ext2_inode       inode;
 
-       if (!(ctx->fs->super->s_feature_incompat &
-             EXT2_FEATURE_INCOMPAT_FILETYPE)) {
+       if (!ext2fs_has_feature_filetype(ctx->fs->super)) {
                if (filetype == 0 ||
                    !fix_problem(ctx, PR_2_CLEAR_FILETYPE, pctx))
                        return 0;
@@ -530,7 +552,6 @@ static _INLINE_ int check_filetype(e2fsck_t ctx,
        return 1;
 }
 
-#ifdef ENABLE_HTREE
 static void parse_int_node(ext2_filsys fs,
                           struct ext2_db_entry2 *db,
                           struct check_dir_struct *cd,
@@ -587,8 +608,7 @@ static void parse_int_node(ext2_filsys fs,
 #endif
 
        count = ext2fs_le16_to_cpu(limit->count);
-       if (EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
-                                      EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))
+       if (ext2fs_has_feature_metadata_csum(fs->super))
                csum_size = sizeof(struct ext2_dx_tail);
        expect_limit = (fs->blocksize -
                        (csum_size + ((char *) ent - block_buf))) /
@@ -660,7 +680,6 @@ clear_and_exit:
        dx_dir->numblocks = 0;
        e2fsck_rehash_dir_later(cd->ctx, cd->pctx.ino);
 }
-#endif /* ENABLE_HTREE */
 
 /*
  * Given a busted directory, try to salvage it somehow.
@@ -842,30 +861,27 @@ err:
        return retval;
 }
 
-int get_filename_hash(ext2_filsys fs, int encrypted, int version,
-                     const char *name, int len, ext2_dirhash_t *ret_hash,
-                     ext2_dirhash_t *ret_minor_hash)
+static int check_dir_block2(ext2_filsys fs,
+                          struct ext2_db_entry2 *db,
+                          void *priv_data)
 {
-       char    buf[2*EXT2FS_DIGEST_SIZE];
-       int     buf_len;
-
-       if (!encrypted)
-               return ext2fs_dirhash(version, name, len,
-                                     fs->super->s_hash_seed,
-                                     ret_hash, ret_minor_hash);
-
-       if (len <= EXT2FS_DIGEST_SIZE)
-               buf_len = ext2fs_digest_encode(name, len, buf);
-       else {
-               ext2fs_sha256(name, len, buf + EXT2FS_DIGEST_SIZE);
-               buf[0] = 'I';
-               buf_len = ext2fs_digest_encode(buf + EXT2FS_DIGEST_SIZE,
-                                              EXT2FS_DIGEST_SIZE, buf + 1);
-               buf_len++;
+       int err;
+       struct check_dir_struct *cd = priv_data;
+
+       if (cd->ra_entries && cd->list_offset >= cd->next_ra_off) {
+               err = e2fsck_readahead_dblist(fs,
+                                       E2FSCK_RA_DBLIST_IGNORE_BLOCKCNT,
+                                       fs->dblist,
+                                       cd->list_offset + cd->ra_entries / 8,
+                                       cd->ra_entries);
+               if (err)
+                       cd->ra_entries = 0;
+               cd->next_ra_off = cd->list_offset + (cd->ra_entries * 7 / 8);
        }
-       return ext2fs_dirhash(version, buf, buf_len,
-                             fs->super->s_hash_seed,
-                             ret_hash, ret_minor_hash);
+
+       err = check_dir_block(fs, db, priv_data);
+       cd->list_offset++;
+       return err;
 }
 
 static int check_dir_block(ext2_filsys fs,
@@ -873,9 +889,7 @@ static int check_dir_block(ext2_filsys fs,
                           void *priv_data)
 {
        struct dx_dir_info      *dx_dir;
-#ifdef ENABLE_HTREE
        struct dx_dirblock_info *dx_db = 0;
-#endif /* ENABLE_HTREE */
        struct ext2_dir_entry   *dirent, *prev, dot, dotdot;
        ext2_dirhash_t          hash;
        unsigned int            offset = 0;
@@ -908,20 +922,18 @@ static int check_dir_block(ext2_filsys fs,
        ibuf = buf = cd->buf;
        ctx = cd->ctx;
 
-       if (ctx->flags & E2F_FLAG_SIGNAL_MASK || ctx->flags & E2F_FLAG_RESTART)
+       if (ctx->flags & E2F_FLAG_RUN_RETURN)
                return DIRENT_ABORT;
 
        if (ctx->progress && (ctx->progress)(ctx, 2, cd->count++, cd->max))
                return DIRENT_ABORT;
 
-       if (EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
-                                      EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)) {
+       if (ext2fs_has_feature_metadata_csum(fs->super)) {
                dx_csum_size = sizeof(struct ext2_dx_tail);
                de_csum_size = sizeof(struct ext2_dir_entry_tail);
        }
 
-       if (EXT2_HAS_INCOMPAT_FEATURE(fs->super,
-                                     EXT2_FEATURE_INCOMPAT_FILETYPE))
+       if (ext2fs_has_feature_filetype(fs->super))
                filetype = EXT2_FT_DIR << 8;
 
        /*
@@ -938,8 +950,7 @@ static int check_dir_block(ext2_filsys fs,
        cd->pctx.dirent = 0;
        cd->pctx.num = 0;
 
-       if (EXT2_HAS_INCOMPAT_FEATURE(fs->super,
-                                     EXT4_FEATURE_INCOMPAT_INLINE_DATA)) {
+       if (ext2fs_has_feature_inline_data(fs->super)) {
                errcode_t ec;
 
                ec = ext2fs_inline_data_size(fs, ino, &inline_data_size);
@@ -1028,7 +1039,6 @@ inline_read_fail:
                memcpy(buf, buf2, fs->blocksize);
                ext2fs_free_mem(&buf2);
        }
-#ifdef ENABLE_HTREE
        dx_dir = e2fsck_get_dx_dir_info(ctx, ino);
        if (dx_dir && dx_dir->numblocks) {
                if (db->blockcnt >= dx_dir->numblocks) {
@@ -1075,10 +1085,9 @@ inline_read_fail:
                            ((fs->blocksize - (8 + dx_csum_size)) /
                             sizeof(struct ext2_dx_entry))))
                        dx_db->type = DX_DIRBLOCK_NODE;
-               is_leaf = 0;
+               is_leaf = (dx_db->type == DX_DIRBLOCK_LEAF);
        }
 out_htree:
-#endif /* ENABLE_HTREE */
 
        /* Leaf node with no space for csum?  Rebuild dirs in pass 3A. */
        if (is_leaf && !inline_data_size && failed_csum &&
@@ -1378,24 +1387,27 @@ skip_checksum:
                        }
                }
 
-               if (!encrypted && check_name(ctx, dirent, ino, &cd->pctx))
+               if (!encrypted && check_name(ctx, dirent, &cd->pctx))
                        dir_modified++;
 
+               if (encrypted && (dot_state) > 1 &&
+                   encrypted_check_name(ctx, dirent, &cd->pctx)) {
+                       dir_modified++;
+                       goto next;
+               }
+
                if (check_filetype(ctx, dirent, ino, &cd->pctx))
                        dir_modified++;
 
-#ifdef ENABLE_HTREE
                if (dx_db) {
-                       get_filename_hash(fs, encrypted, dx_dir->hashversion,
-                                         dirent->name,
-                                         ext2fs_dirent_name_len(dirent),
-                                         &hash, 0);
+                       ext2fs_dirhash(dx_dir->hashversion, dirent->name,
+                                      ext2fs_dirent_name_len(dirent),
+                                      fs->super->s_hash_seed, &hash, 0);
                        if (hash < dx_db->min_hash)
                                dx_db->min_hash = hash;
                        if (hash > dx_db->max_hash)
                                dx_db->max_hash = hash;
                }
-#endif
 
                /*
                 * If this is a directory, then mark its parent in its
@@ -1471,7 +1483,6 @@ skip_checksum:
 #if 0
        printf("\n");
 #endif
-#ifdef ENABLE_HTREE
        if (dx_db) {
 #ifdef DX_DEBUG
                printf("db_block %d, type %d, min_hash 0x%0x, max_hash 0x%0x\n",
@@ -1483,7 +1494,6 @@ skip_checksum:
                    (dx_db->type == DX_DIRBLOCK_NODE))
                        parse_int_node(fs, db, cd, dx_dir, buf, failed_csum);
        }
-#endif /* ENABLE_HTREE */
 
        if (offset != max_block_size) {
                cd->pctx.num = rec_len + offset - max_block_size;
@@ -1495,8 +1505,7 @@ skip_checksum:
        if (dir_modified) {
                int     flags, will_rehash;
                /* leaf block with no tail?  Rehash dirs later. */
-               if (EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
-                               EXT4_FEATURE_RO_COMPAT_METADATA_CSUM) &&
+               if (ext2fs_has_feature_metadata_csum(fs->super) &&
                    is_leaf &&
                    !inline_data_size &&
                    !ext2fs_dirent_has_tail(fs, (struct ext2_dir_entry *)buf)) {
@@ -1590,7 +1599,7 @@ static int deallocate_inode_block(ext2_filsys fs,
 {
        struct del_block *p = priv_data;
 
-       if (HOLE_BLKADDR(*block_nr))
+       if (*block_nr == 0)
                return 0;
        if ((*block_nr < fs->super->s_first_data_block) ||
            (*block_nr >= ext2fs_blocks_count(fs->super)))
@@ -1623,7 +1632,7 @@ static void deallocate_inode(e2fsck_t ctx, ext2_ino_t ino, char* block_buf)
        ext2fs_inode_alloc_stats2(fs, ino, -1, LINUX_S_ISDIR(inode.i_mode));
 
        if (ext2fs_file_acl_block(fs, &inode) &&
-           (fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_EXT_ATTR)) {
+           ext2fs_has_feature_xattr(fs->super)) {
                pctx.errcode = ext2fs_adjust_ea_refcount3(fs,
                                ext2fs_file_acl_block(fs, &inode),
                                block_buf, -1, &count, ino);
@@ -1705,7 +1714,7 @@ int e2fsck_process_bad_inode(e2fsck_t ctx, ext2_ino_t dir,
        pctx.inode = &inode;
 
        if (ext2fs_file_acl_block(fs, &inode) &&
-           !(fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_EXT_ATTR)) {
+           !ext2fs_has_feature_xattr(fs->super)) {
                if (fix_problem(ctx, PR_2_FILE_ACL_ZERO, &pctx)) {
                        ext2fs_file_acl_block_set(fs, &inode, 0);
                        inode_modified++;
@@ -1782,8 +1791,7 @@ int e2fsck_process_bad_inode(e2fsck_t ctx, ext2_ino_t dir,
        }
 
        if ((fs->super->s_creator_os == EXT2_OS_LINUX) &&
-           !(fs->super->s_feature_ro_compat &
-             EXT4_FEATURE_RO_COMPAT_HUGE_FILE) &&
+           !ext2fs_has_feature_huge_file(fs->super) &&
            (inode.osd2.linux2.l_i_blocks_hi != 0)) {
                pctx.num = inode.osd2.linux2.l_i_blocks_hi;
                if (fix_problem(ctx, PR_2_BLOCKS_HI_ZERO, &pctx)) {
@@ -1793,8 +1801,7 @@ int e2fsck_process_bad_inode(e2fsck_t ctx, ext2_ino_t dir,
        }
 
        if ((fs->super->s_creator_os == EXT2_OS_LINUX) &&
-           !(fs->super->s_feature_incompat &
-            EXT4_FEATURE_INCOMPAT_64BIT) &&
+           !ext2fs_has_feature_64bit(fs->super) &&
            inode.osd2.linux2.l_i_file_acl_high != 0) {
                pctx.num = inode.osd2.linux2.l_i_file_acl_high;
                if (fix_problem(ctx, PR_2_I_FILE_ACL_HI_ZERO, &pctx)) {