Whamcloud - gitweb
Fix a bug which caused e2fsck to fail to correctly check filesystems
authorTheodore Ts'o <tytso@mit.edu>
Sat, 31 Aug 2002 06:32:41 +0000 (02:32 -0400)
committerTheodore Ts'o <tytso@mit.edu>
Sat, 31 Aug 2002 06:32:41 +0000 (02:32 -0400)
using a non-zero hash version (i.e., half MD4 or TEA hash).

The hash version wasn't getting copied into dx_dir->hashversion and
this caused the kernel to treat all directories if they were using the
legacy hash, which was Bad.

e2fsck/ChangeLog
e2fsck/pass2.c
e2fsck/problem.c
e2fsck/problem.h
lib/ext2fs/ChangeLog
lib/ext2fs/dblist.c
lib/ext2fs/ext2fs.h

index 6581282..14733dc 100644 (file)
@@ -1,3 +1,17 @@
+2002-08-31  Theodore Ts'o  <tytso@valinux.com>
+
+       * pass2.c (e2fsck_pass2): If this is a HTREE directory, sort the
+               dblist so that the first block of all of the directories
+               is handled first so we can read the hash version
+               information.
+               (check_dir_block): Examine the root node for correctness,
+               and offer to clear it if it is not correct.  Also copy the
+               hash version to the dx_dir structure, so that the proper
+               hash function can be used for other blocks in the
+               directory.
+
+       * problem.c, problem.h (PR_2_HTREE_BAD_ROOT): Add new problem code.
+
 2002-08-21  Theodore Ts'o  <tytso@mit.edu>
 
        * problem.c: Fix PR_1_RELOC_BLOCK_ALLOCATE message to explain that
index e61a6a2..329107b 100644 (file)
@@ -69,6 +69,7 @@ static int update_dir_block(ext2_filsys fs,
                            int         ref_offset, 
                            void        *priv_data);
 static void clear_htree(e2fsck_t ctx, ext2_ino_t ino);
+static EXT2_QSORT_TYPE special_dir_block_cmp(const void *a, const void *b);
 
 struct check_dir_struct {
        char *buf;
@@ -135,6 +136,9 @@ void e2fsck_pass2(e2fsck_t ctx)
 
        if (ctx->progress)
                (void) (ctx->progress)(ctx, 2, 0, cd.max);
+
+       if (fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_DIR_INDEX)
+               ext2fs_dblist_sort(fs->dblist, special_dir_block_cmp);
        
        cd.pctx.errcode = ext2fs_dblist_iterate(fs->dblist, check_dir_block,
                                                &cd);
@@ -279,6 +283,35 @@ void e2fsck_pass2(e2fsck_t ctx)
 }
 
 /*
+ * This is special sort function that makes sure that directory blocks
+ * with a dirblock of zero are sorted to the beginning of the list.
+ * This guarantees that the root node of the htree directories are
+ * processed first, so we know what hash version to use.
+ */
+static EXT2_QSORT_TYPE special_dir_block_cmp(const void *a, const void *b)
+{
+       const struct ext2_db_entry *db_a =
+               (const struct ext2_db_entry *) a;
+       const struct ext2_db_entry *db_b =
+               (const struct ext2_db_entry *) b;
+
+       if (db_a->blockcnt && !db_b->blockcnt)
+               return 1;
+
+       if (!db_a->blockcnt && db_b->blockcnt)
+               return -1;
+       
+       if (db_a->blk != db_b->blk)
+               return (int) (db_a->blk - db_b->blk);
+       
+       if (db_a->ino != db_b->ino)
+               return (int) (db_a->ino - db_b->ino);
+
+       return (int) (db_a->blockcnt - db_b->blockcnt);
+}
+
+
+/*
  * Make sure the first entry in the directory is '.', and that the
  * directory entry is sane.
  */
@@ -562,6 +595,7 @@ static int check_dir_block(ext2_filsys fs,
        char                    *buf;
        e2fsck_t                ctx;
        int                     problem;
+       struct ext2_dx_root_info *root;
 
        cd = (struct check_dir_struct *) priv_data;
        buf = cd->buf;
@@ -627,13 +661,19 @@ static int check_dir_block(ext2_filsys fs,
                dx_db->max_hash = 0;
                        
                dirent = (struct ext2_dir_entry *) buf;
-               /*
-                * XXX we need to check to make sure the root
-                * directory block  is actually valid!
-                */
                if (db->blockcnt == 0) {
+                       root = (struct ext2_dx_root_info *) (buf + 24);
                        dx_db->type = DX_DIRBLOCK_ROOT;
                        dx_db->flags |= DX_FLAG_FIRST | DX_FLAG_LAST;
+                       if ((root->reserved_zero ||
+                            root->info_length < 8 ||
+                            root->indirect_levels > 1) &&
+                           fix_problem(ctx, PR_2_HTREE_BAD_ROOT, &cd->pctx)) {
+                               clear_htree(ctx, ino);
+                               dx_dir->numblocks = 0;
+                               dx_db = 0;
+                       } 
+                       dx_dir->hashversion = root->hash_version;
                } else if ((dirent->inode == 0) &&
                         (dirent->rec_len == fs->blocksize))
                        dx_db->type = DX_DIRBLOCK_NODE;
index d56ec2d..7571ae7 100644 (file)
@@ -1062,6 +1062,11 @@ static const struct e2fsck_problem problem_table[] = {
          N_("Error addjusting refcount for @a @b %b (@i %i): %m\n"),
          PROMPT_NONE, PR_FATAL },
 
+       /* Invalid HTREE root node */
+       { PR_2_HTREE_BAD_ROOT,
+         N_("@p @h %d: root node is invalid\n"),
+         PROMPT_CLEAR_HTREE, 0 },
+
        /* Pass 3 errors */
 
        /* Pass 3: Checking directory connectivity */
index 2196a33..cc7a01b 100644 (file)
@@ -630,6 +630,9 @@ struct problem_context {
 /* Error adjusting EA refcount */
 #define PR_2_ADJ_EA_REFCOUNT   0x02003B
 
+/* Invalid HTREE root node */
+#define PR_2_HTREE_BAD_ROOT    0x02003C
+
 /*
  * Pass 3 errors
  */
index 7337c53..ecabd3d 100644 (file)
@@ -1,3 +1,8 @@
+2002-08-31  Theodore Ts'o  <tytso@valinux.com>
+
+       * dblist.c (ext2fs_dblist_sort): New function which allows the
+               caller to pass in a special sort comparison function.
+
 2002-08-20  Theodore Ts'o  <tytso@mit.edu>
 
        * valid_blk.c (ext2fs_inode_has_valid_blocks): Fix bug which
index a195b5b..a3f99eb 100644 (file)
@@ -204,6 +204,17 @@ errcode_t ext2fs_set_dir_block(ext2_dblist dblist, ext2_ino_t ino, blk_t blk,
        return EXT2_ET_DB_NOT_FOUND;
 }
 
+void ext2fs_dblist_sort(ext2_dblist dblist,
+                       EXT2_QSORT_TYPE (*sortfunc)(const void *,
+                                                   const void *))
+{
+       if (!sortfunc)
+               sortfunc = dir_block_cmp;
+       qsort(dblist->list, (size_t) dblist->count,
+             sizeof(struct ext2_db_entry), sortfunc);
+       dblist->sorted = 1;
+}
+
 /*
  * This function iterates over the directory block list
  */
@@ -218,11 +229,8 @@ errcode_t ext2fs_dblist_iterate(ext2_dblist dblist,
        
        EXT2_CHECK_MAGIC(dblist, EXT2_ET_MAGIC_DBLIST);
 
-       if (!dblist->sorted) {
-               qsort(dblist->list, (size_t) dblist->count,
-                     sizeof(struct ext2_db_entry), dir_block_cmp);
-               dblist->sorted = 1;
-       }
+       if (!dblist->sorted)
+               ext2fs_dblist_sort(dblist, 0);
        for (i=0; i < dblist->count; i++) {
                ret = (*func)(dblist->fs, &dblist->list[(int)i], priv_data);
                if (ret & DBLIST_ABORT)
@@ -231,7 +239,6 @@ errcode_t ext2fs_dblist_iterate(ext2_dblist dblist,
        return 0;
 }
 
-
 static EXT2_QSORT_TYPE dir_block_cmp(const void *a, const void *b)
 {
        const struct ext2_db_entry *db_a =
index e871f58..fa3eb63 100644 (file)
@@ -589,6 +589,9 @@ extern errcode_t ext2fs_get_num_dirs(ext2_filsys fs, ext2_ino_t *ret_num_dirs);
 extern errcode_t ext2fs_init_dblist(ext2_filsys fs, ext2_dblist *ret_dblist);
 extern errcode_t ext2fs_add_dir_block(ext2_dblist dblist, ext2_ino_t ino,
                                      blk_t blk, int blockcnt);
+extern void ext2fs_dblist_sort(ext2_dblist dblist,
+                              EXT2_QSORT_TYPE (*sortfunc)(const void *,
+                                                          const void *));
 extern errcode_t ext2fs_dblist_iterate(ext2_dblist dblist,
        int (*func)(ext2_filsys fs, struct ext2_db_entry *db_info,
                    void        *priv_data),