]> git.ipfire.org Git - thirdparty/e2fsprogs.git/commitdiff
Add support to e2fsck to reindex directories to use hash trees.
authorTheodore Ts'o <tytso@mit.edu>
Sat, 20 Jul 2002 04:28:07 +0000 (00:28 -0400)
committerTheodore Ts'o <tytso@mit.edu>
Sat, 20 Jul 2002 04:28:07 +0000 (00:28 -0400)
23 files changed:
e2fsck/ChangeLog
e2fsck/Makefile.in
e2fsck/e2fsck.c
e2fsck/e2fsck.h
e2fsck/pass1.c
e2fsck/pass2.c
e2fsck/pass3.c
e2fsck/problem.c
e2fsck/problem.h
e2fsck/problemP.h
e2fsck/rehash.c [new file with mode: 0644]
lib/ext2fs/ChangeLog
lib/ext2fs/badblocks.c
lib/ext2fs/ext2_fs.h
lib/ext2fs/ext2fs.h
lib/ext2fs/ext2fsP.h
lib/ext2fs/freefs.c
tests/ChangeLog
tests/f_expand/expect.1
tests/f_h_badnode/expect.1
tests/f_h_badnode/expect.2
tests/f_h_badroot/expect.1
tests/f_h_badroot/expect.2

index da1d2c9ebabd057b63618266035a825a8654a723..aaf776365e4e4b92bf1272c1be28208042fbb70c 100644 (file)
@@ -1,3 +1,39 @@
+2002-07-19  Theodore Ts'o  <tytso@mit.edu>
+
+       * rehash.c, Makefile.in: New file which rewrites directories using
+               the htree format.
+       
+       * problem.c (fix_problem), problemP.h (PR_PREEN_NOHDR): Add option
+               which suppresses the header printed when in preen mode.
+
+       * pass3.c (e2fsck_pass3): If there are entries on the dirs_to_hash
+               list, call e2fsck_rehash_directories to reindex those
+               directories.
+               (e2fsck_expand_directory): Generalize the old
+               expand_dirctory() function so it can expand a directory to
+               a guaranteed minimum size. 
+
+       * e2fsck.h (struct e2fsck_struct): Add the dirs_to_hash list.  Add
+               new function prototypes for rehash.c and for
+               e2fsck_expand_directory().
+       
+       * e2fsck.c (e2fsck_reset_context): Free the dirs_to_hash list.
+
+       * pass1.c (e2fsck_pass1): Initialize the dirs_to_hash list if the
+               htree feature is present in the filesystem.
+               (check_blocks): If a non-htree directory has more than 2
+               blocks, put it on the dirs_to_hash list.
+
+       * pass2.c (clear_htree): Add corrupt htree directories to the
+               dirs_to_hash list.
+
+       * problem.h, problem.c (PR_3A_PASS_HEADER, PR_3A_REHASH_ITER, 
+               PR_3A_REHASH_DIR_ERR, PR_3A_REHASH_DIR_HEADER,
+               PR_3A_REHASH_DIR, PR_3A_REHASH_DIR_END): Add new problem codes
+
+       * pass2.c (parse_int_node), problem.c (PR_2_HTREE_BADBLK): Fix
+               problem display.
+       
 2002-07-15  Theodore Ts'o  <tytso@mit.edu>
 
        * pass2.c (e2fsck_pass2): Use dx_dir->numblocks instead of
index 51c08212324dde2da63d296bbb85a98ef54507f6..44732803e472a922cdf7eb6b789bce0f5355a342 100644 (file)
@@ -57,7 +57,7 @@ PROFILED_DEPLIBS= $(PROFILED_LIBEXT2FS) $(PROFILED_LIBCOM_ERR) \
 OBJS= unix.o e2fsck.o super.o pass1.o pass1b.o pass2.o pass3.o pass4.o \
        pass5.o journal.o swapfs.o badblocks.o util.o dirinfo.o dx_dirinfo.o \
        ehandler.o problem.o message.o recovery.o region.o revoke.o \
-       ea_refcount.o $(MTRACE_OBJ)
+       ea_refcount.o rehash.o $(MTRACE_OBJ)
 
 PROFILED_OBJS= profiled/unix.o profiled/e2fsck.o profiled/super.o \
        profiled/pass1.o profiled/pass1b.o \
@@ -66,7 +66,7 @@ PROFILED_OBJS= profiled/unix.o profiled/e2fsck.o profiled/super.o \
        profiled/dirinfo.o profiled/dx_dirinfo.o profiled/ehandler.o \
        profiled/message.o profiled/problem.o profiled/swapfs.o \
        profiled/recovery.o profiled/region.o profiled/revoke.o \
-       profiled/ea_refcount.o
+       profiled/ea_refcount.o profiled/rehash.o
 
 SRCS= $(srcdir)/e2fsck.c \
        $(srcdir)/super.c \
@@ -89,6 +89,7 @@ SRCS= $(srcdir)/e2fsck.c \
        $(srcdir)/message.c \
        $(srcdir)/swapfs.c \
        $(srcdir)/ea_refcount.c \
+       $(srcdir)/rehash.c \
        $(srcdir)/region.c \
        $(MTRACE_SRC)
 
index 0abae190eab0cf33cf964526f258961efac154e4..7356f32697daf4711f2ca300b512d57fd755804f 100644 (file)
@@ -103,6 +103,10 @@ errcode_t e2fsck_reset_context(e2fsck_t ctx)
                ext2fs_free_inode_bitmap(ctx->inode_imagic_map);
                ctx->inode_imagic_map = 0;
        }
+       if (ctx->dirs_to_hash) {
+               ext2fs_u32_list_free(ctx->dirs_to_hash);
+               ctx->dirs_to_hash = 0;
+       }
 
        /*
         * Clear the array of invalid meta-data flags
index 49097fe65cc2872bfac529aa200e660f0283e07d..d68b79c156ab468c9576d9b3c2822209387ccc17 100644 (file)
@@ -248,6 +248,11 @@ struct e2fsck_struct {
        int             dx_dir_info_size;
        struct dx_dir_info *dx_dir_info;
 
+       /*
+        * Directories to hash
+        */
+       ext2_u32_list   dirs_to_hash;
+
        /*
         * Tuning parameters
         */
@@ -379,12 +384,19 @@ extern int e2fsck_process_bad_inode(e2fsck_t ctx, ext2_ino_t dir,
 
 /* pass3.c */
 extern int e2fsck_reconnect_file(e2fsck_t ctx, ext2_ino_t inode);
+extern errcode_t e2fsck_expand_directory(e2fsck_t ctx, ext2_ino_t dir,
+                                        int num, int gauranteed_size);
+
 
 /* region.c */
 extern region_t region_create(region_addr_t min, region_addr_t max);
 extern void region_free(region_t region);
 extern int region_allocate(region_t region, region_addr_t start, int n);
 
+/* rehash.c */
+errcode_t e2fsck_rehash_dir(e2fsck_t ctx, ext2_ino_t ino);
+void e2fsck_rehash_directories(e2fsck_t ctx);
+
 /* super.c */
 void check_super_block(e2fsck_t ctx);
 errcode_t e2fsck_get_device_size(e2fsck_t ctx);
index 8bc35a2cc30314bc4ba05ddc96cb507858329fda..bc4ac26a51982799e73f1ebc937d38a8da69e233 100644 (file)
@@ -277,6 +277,11 @@ void e2fsck_pass1(e2fsck_t ctx)
        if (!(ctx->options & E2F_OPT_PREEN))
                fix_problem(ctx, PR_1_PASS_HEADER, &pctx);
 
+       if (fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_DIR_INDEX) {
+               if (ext2fs_u32_list_create(&ctx->dirs_to_hash, 50))
+                       ctx->dirs_to_hash = 0;
+       }
+
 #ifdef MTRACE
        mtrace_print("Pass 1");
 #endif
@@ -1269,7 +1274,11 @@ static void check_blocks(e2fsck_t ctx, struct problem_context *pctx,
 #endif
                }
        }
-       
+       if (ctx->dirs_to_hash && pb.is_dir &&
+           !(inode->i_flags & EXT2_INDEX_FL) &&
+           ((inode->i_size / fs->blocksize) >= 3))
+               ext2fs_u32_list_add(ctx->dirs_to_hash, ino);
+               
        if (inode->i_file_acl && check_ext_attr(ctx, pctx, block_buf))
                pb.num_blocks++;
 
index d730765bb6c05327d5f4f96c5a5fe828aa048136..db23c88e7a35217d17fd263320b1f7978cc58293 100644 (file)
@@ -500,6 +500,7 @@ static void parse_int_node(ext2_filsys fs,
                blk = ent[i].block & 0x0ffffff;
                /* Check to make sure the block is valid */
                if (blk > dx_dir->numblocks) {
+                       cd->pctx.blk = blk;
                        if (fix_problem(cd->ctx, PR_2_HTREE_BADBLK,
                                        &cd->pctx)) {
                                clear_htree(cd->ctx, cd->pctx.ino);
@@ -838,6 +839,7 @@ static int check_dir_block(ext2_filsys fs,
                       db->blockcnt, dx_db->type,
                       dx_db->min_hash, dx_db->max_hash);
 #endif
+               cd->pctx.dir = cd->pctx.ino;
                if ((dx_db->type == DX_DIRBLOCK_ROOT) ||
                    (dx_db->type == DX_DIRBLOCK_NODE))
                        parse_int_node(fs, db, cd, dx_dir, buf);
@@ -946,6 +948,8 @@ static void clear_htree(e2fsck_t ctx, ext2_ino_t ino)
        e2fsck_read_inode(ctx, ino, &inode, "clear_htree");
        inode.i_flags = inode.i_flags & ~EXT2_INDEX_FL;
        e2fsck_write_inode(ctx, ino, &inode, "clear_htree");
+       if (ctx->dirs_to_hash)
+               ext2fs_u32_list_add(ctx->dirs_to_hash, ino);
 }
 
 
index bebd67f278cd419d68336bcd79edff50f3b5ea8b..7fdd814627bdaae37aacc4cfb8d85f9c924683af 100644 (file)
@@ -47,7 +47,6 @@ static int check_directory(e2fsck_t ctx, struct dir_info *dir,
 static ext2_ino_t get_lost_and_found(e2fsck_t ctx);
 static void fix_dotdot(e2fsck_t ctx, struct dir_info *dir, ext2_ino_t parent);
 static errcode_t adjust_inode_count(e2fsck_t ctx, ext2_ino_t ino, int adj);
-static errcode_t expand_directory(e2fsck_t ctx, ext2_ino_t dir);
 
 static ext2_ino_t lost_and_found = 0;
 static int bad_lost_and_found = 0;
@@ -135,6 +134,11 @@ abort_exit:
                ext2fs_free_inode_bitmap(inode_done_map);
                inode_done_map = 0;
        }
+
+       /* If there are any directories that need to be indexed, do it here. */
+       if (ctx->dirs_to_hash)
+               e2fsck_rehash_directories(ctx);
+       
 #ifdef RESOURCE_TRACK
        if (ctx->options & E2F_OPT_TIME2) {
                e2fsck_clear_progbar(ctx);
@@ -353,7 +357,7 @@ static int check_directory(e2fsck_t ctx, struct dir_info *dir,
                        fix_dotdot(ctx, dir, dir->parent);
        }
        return 0;
-}      
+}
 
 /*
  * This routine gets the lost_and_found inode, making it a directory
@@ -528,7 +532,7 @@ int e2fsck_reconnect_file(e2fsck_t ctx, ext2_ino_t ino)
        if (retval == EXT2_ET_DIR_NO_SPACE) {
                if (!fix_problem(ctx, PR_3_EXPAND_LF_DIR, &pctx))
                        return 1;
-               retval = expand_directory(ctx, lost_and_found);
+               retval = e2fsck_expand_directory(ctx, lost_and_found, 1, 0);
                if (retval) {
                        pctx.errcode = retval;
                        fix_problem(ctx, PR_3_CANT_EXPAND_LPF, &pctx);
@@ -672,8 +676,10 @@ static void fix_dotdot(e2fsck_t ctx, struct dir_info *dir, ext2_ino_t parent)
  */
 
 struct expand_dir_struct {
-       int                     done;
+       int                     num;
+       int                     guaranteed_size;
        int                     newblocks;
+       int                     last_block;
        errcode_t               err;
        e2fsck_t                ctx;
 };
@@ -694,6 +700,11 @@ static int expand_dir_proc(ext2_filsys fs,
 
        ctx = es->ctx;
        
+       if (es->guaranteed_size && blockcnt >= es->guaranteed_size)
+               return BLOCK_ABORT;
+
+       if (blockcnt > 0)
+               es->last_block = blockcnt;
        if (*blocknr) {
                last_blk = *blocknr;
                return 0;
@@ -710,7 +721,7 @@ static int expand_dir_proc(ext2_filsys fs,
                        es->err = retval;
                        return BLOCK_ABORT;
                }
-               es->done = 1;
+               es->num--;
                retval = ext2fs_write_dir_block(fs, new_blk, block);
        } else {
                retval = ext2fs_get_mem(fs->blocksize, (void **) &block);
@@ -728,17 +739,17 @@ static int expand_dir_proc(ext2_filsys fs,
        ext2fs_free_mem((void **) &block);
        *blocknr = new_blk;
        ext2fs_mark_block_bitmap(ctx->block_found_map, new_blk);
-       ext2fs_mark_block_bitmap(fs->block_map, new_blk);
-       ext2fs_mark_bb_dirty(fs);
+       ext2fs_block_alloc_stats(fs, new_blk, +1);
        es->newblocks++;
        
-       if (es->done)
+       if (es->num == 0)
                return (BLOCK_CHANGED | BLOCK_ABORT);
        else
                return BLOCK_CHANGED;
 }
 
-static errcode_t expand_directory(e2fsck_t ctx, ext2_ino_t dir)
+errcode_t e2fsck_expand_directory(e2fsck_t ctx, ext2_ino_t dir,
+                                 int num, int guaranteed_size)
 {
        ext2_filsys fs = ctx->fs;
        errcode_t       retval;
@@ -758,7 +769,9 @@ static errcode_t expand_directory(e2fsck_t ctx, ext2_ino_t dir)
        if (retval)
                return retval;
        
-       es.done = 0;
+       es.num = num;
+       es.guaranteed_size = guaranteed_size;
+       es.last_block = 0;
        es.err = 0;
        es.newblocks = 0;
        es.ctx = ctx;
@@ -768,8 +781,6 @@ static errcode_t expand_directory(e2fsck_t ctx, ext2_ino_t dir)
 
        if (es.err)
                return es.err;
-       if (!es.done)
-               return EXT2_ET_EXPAND_DIR_ERR;
 
        /*
         * Update the size and block count fields in the inode.
@@ -778,10 +789,11 @@ static errcode_t expand_directory(e2fsck_t ctx, ext2_ino_t dir)
        if (retval)
                return retval;
        
-       inode.i_size += fs->blocksize;
+       inode.i_size = (es.last_block + 1) * fs->blocksize;
        inode.i_blocks += (fs->blocksize / 512) * es.newblocks;
 
        e2fsck_write_inode(ctx, dir, &inode, "expand_directory");
 
        return 0;
 }
+
index 7f019a766bbc23f6fabefabd7e30b5edf6abea91..ff9714e5f2befcf90dd96f2043022793016325bf 100644 (file)
@@ -1048,7 +1048,7 @@ static const struct e2fsck_problem problem_table[] = {
 
        /* Bad block in htree interior node */
        { PR_2_HTREE_BADBLK,
-         N_("@p @h %d (%q): bad @b number %B.\n"),
+         N_("@p @h %d (%q): bad @b number %b.\n"),
          PROMPT_CLEAR_HTREE, 0 },
 
        /* Pass 3 errors */
@@ -1171,7 +1171,39 @@ static const struct e2fsck_problem problem_table[] = {
        /* Lost+found not a directory */
        { PR_3_LPF_NOTDIR,
          N_("/@l is not a @d (ino=%i)\n"),
-         PROMPT_UNLINK, 0 }, 
+         PROMPT_UNLINK, 0 },
+
+       /* Pass 3a (rehashing directory) errors */
+
+       /* Pass 3a: Reindexing directories */
+       { PR_3A_PASS_HEADER,
+         N_("Pass 3a: Reindexing directories\n"),
+         PROMPT_NONE, PR_PREEN_NOMSG },
+
+       /* Error iterating over directories */
+       { PR_3A_REHASH_ITER,
+         N_("Failed to create dirs_to_hash iterator: %m"),
+         PROMPT_NONE, 0 },
+
+       /* Error rehash directory */
+       { PR_3A_REHASH_DIR_ERR,
+         N_("Failed to rehash directory %q (%d): %m"),
+         PROMPT_NONE, 0 },
+
+       /* Rehashing dir header */
+       { PR_3A_REHASH_DIR_HEADER,
+         N_("Rehashing directories: "),
+         PROMPT_NONE, PR_MSG_ONLY },
+
+       /* Rehashing directory %d */
+       { PR_3A_REHASH_DIR,
+         " %d",
+         PROMPT_NONE, PR_LATCH_REHASH_DIR | PR_PREEN_NOHDR},
+                 
+       /* Rehashing dir end */   
+       { PR_3A_REHASH_DIR_END,
+         "\n",
+         PROMPT_NONE, PR_PREEN_NOHDR },
 
        /* Pass 4 errors */
        
@@ -1343,6 +1375,7 @@ static struct latch_descr pr_latch_info[] = {
        { PR_LATCH_DBLOCK, PR_1B_DUP_BLOCK_HEADER, PR_1B_DUP_BLOCK_END },
        { PR_LATCH_LOW_DTIME, PR_1_ORPHAN_LIST_REFUGEES, 0 },
        { PR_LATCH_TOOBIG, PR_1_INODE_TOOBIG, 0 },
+       { PR_LATCH_REHASH_DIR, PR_3A_REHASH_DIR_HEADER, PR_3A_REHASH_DIR_END },
        { -1, 0, 0 },
 };
 
@@ -1459,13 +1492,10 @@ int fix_problem(e2fsck_t ctx, problem_t code, struct problem_context *pctx)
                suppress++;
        if (!suppress) {
                message = ptr->e2p_description;
-               if (ctx->options & E2F_OPT_PREEN) {
+               if ((ctx->options & E2F_OPT_PREEN) &&
+                   !(ptr->flags & PR_PREEN_NOHDR)) {
                        printf("%s: ", ctx->device_name ?
                               ctx->device_name : ctx->filesystem_name);
-#if 0
-                       if (ptr->e2p_preen_msg)
-                               message = ptr->e2p_preen_msg;
-#endif
                }
                print_e2fsck_message(ctx, _(message), pctx, 1);
        }
index 91c0bd0ccf5e033bc0f0afa7b653a4c60062cf9d..693ecb762376f93fa5ba9607176ac16ec0f97058 100644 (file)
@@ -37,6 +37,7 @@ struct problem_context {
 #define PR_LATCH_DBLOCK        0x0060  /* Latch for pass 1b dup block headers */
 #define PR_LATCH_LOW_DTIME 0x0070 /* Latch for pass1 orphaned list refugees */
 #define PR_LATCH_TOOBIG        0x0080  /* Latch for file to big errors */
+#define PR_LATCH_REHASH_DIR 0x0090 /* Latch for rehashing directories */
 
 #define PR_LATCH(x)    ((((x) & PR_LATCH_MASK) >> 4) - 1)
 
@@ -699,6 +700,27 @@ struct problem_context {
 /* Lost+found is not a directory */
 #define PR_3_LPF_NOTDIR                        0x030017
 
+/*
+ * Pass 3a --- rehashing diretories
+ */
+/* Pass 3a: Reindexing directories */
+#define PR_3A_PASS_HEADER              0x031000
+
+/* Error iterating over directories */
+#define PR_3A_REHASH_ITER              0x031001
+
+/* Error rehash directory */
+#define PR_3A_REHASH_DIR_ERR           0x031002                
+
+/* Rehashing dir header */
+#define PR_3A_REHASH_DIR_HEADER                0x031003
+
+/* Rehashing directory %d */
+#define PR_3A_REHASH_DIR               0x031004
+                 
+/* Rehashing dir end */          
+#define PR_3A_REHASH_DIR_END           0x031005
+       
 /*
  * Pass 4 errors
  */
index cce5511a2a0df162ee74068c85873213edc57b2b..329056b959b6cf3eb82142cdf377cea494f95dd7 100644 (file)
@@ -38,4 +38,5 @@ struct latch_descr {
 #define PR_NOCOLLATE   0x008000 /* Don't collate answers for this latch */
 #define PR_NO_NOMSG    0x010000 /* Don't print a message if e2fsck -n */
 #define PR_PREEN_NO    0x020000 /* Use No as an answer if preening */
+#define PR_PREEN_NOHDR 0x040000 /* Don't print the preen header */
 
diff --git a/e2fsck/rehash.c b/e2fsck/rehash.c
new file mode 100644 (file)
index 0000000..95bb678
--- /dev/null
@@ -0,0 +1,578 @@
+/*
+ * rehash.c --- rebuild hash tree directories
+ * 
+ * Copyright (C) 2002 Theodore Ts'o
+ *
+ * %Begin-Header%
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ * %End-Header%
+ * 
+ * This algorithm is designed for simplicity of implementation and to
+ * pack the directory as much as possible.  It however requires twice
+ * as much memory as the size of the directory.  The maximum size
+ * directory supported using a 4k blocksize is roughly a gigabyte, and
+ * so there may very well be problems with machines that don't have
+ * virtual memory, and obscenely large directories.
+ *
+ * An alternate algorithm which is much more disk intensive could be
+ * written, and probably will need to be written in the future.  The
+ * design goals of such an algorithm are: (a) use (roughly) constant
+ * amounts of memory, no matter how large the directory, (b) the
+ * directory must be safe at all times, even if e2fsck is interrupted
+ * in the middle, (c) we must use minimal amounts of extra disk
+ * blocks.  This pretty much requires an incremental approach, where
+ * we are reading from one part of the directory, and inserting into
+ * the front half.  So the algorithm will have to keep track of a
+ * moving block boundary between the new tree and the old tree, and
+ * files will need to be moved from the old directory and inserted
+ * into the new tree.  If the new directory requires space which isn't
+ * yet available, blocks from the beginning part of the old directory
+ * may need to be moved to the end of the directory to make room for
+ * the new tree:
+ *
+ *    --------------------------------------------------------
+ *    |  new tree   |        | old tree                      |
+ *    --------------------------------------------------------
+ *                  ^ ptr    ^ptr
+ *                tail new   head old
+ * 
+ * This is going to be a pain in the tuckus to implement, and will
+ * require a lot more disk accesses.  So I'm going to skip it for now;
+ * it's only really going to be an issue for really, really big
+ * filesystems (when we reach the level of tens of millions of files
+ * in a single directory).  It will probably be easier to simply
+ * require that e2fsck use VM first.
+ */
+
+#include <errno.h>
+#include "e2fsck.h"
+#include "problem.h"
+
+struct fill_dir_struct {
+       char *buf;
+       struct ext2_inode *inode;
+       int err;
+       e2fsck_t ctx;
+       struct hash_entry *harray;
+       int max_array, num_array;
+       int dir_size;
+       ino_t parent;
+};
+
+struct hash_entry {
+       ext2_dirhash_t  hash;
+       ext2_dirhash_t  minor_hash;
+       struct ext2_dir_entry   *dir;
+};
+
+struct out_dir {
+       int             num;
+       int             max;
+       char            *buf;
+       ext2_dirhash_t  *hashes;
+};
+
+static int fill_dir_block(ext2_filsys fs,
+                         blk_t *block_nr,
+                         e2_blkcnt_t blockcnt,
+                         blk_t ref_block,
+                         int ref_offset, 
+                         void *priv_data)
+{
+       struct fill_dir_struct  *fd = (struct fill_dir_struct *) priv_data;
+       struct hash_entry       *new_array, *ent;
+       struct ext2_dir_entry   *dirent;
+       char                    *dir;
+       int                     offset, dir_offset;
+       
+       if (blockcnt < 0)
+               return 0;
+
+       offset = blockcnt * fs->blocksize;
+       if (offset + fs->blocksize > fd->inode->i_size) {
+               fd->err = EXT2_ET_DIR_CORRUPTED;
+               return BLOCK_ABORT;
+       }
+       dir = (fd->buf+offset);
+       if (HOLE_BLKADDR(*block_nr)) {
+               memset(dir, 0, fs->blocksize);
+               dirent = (struct ext2_dir_entry *) dir;
+               dirent->rec_len = fs->blocksize;
+       } else {
+               fd->err = ext2fs_read_dir_block(fs, *block_nr, dir);
+               if (fd->err)
+                       return BLOCK_ABORT;
+       }
+       /* While the directory block is "hot", index it. */
+       dir_offset = 0;
+       while (dir_offset < fs->blocksize) {
+               dirent = (struct ext2_dir_entry *) (dir + dir_offset);
+               if (((dir_offset + dirent->rec_len) > fs->blocksize) ||
+                   (dirent->rec_len < 8) ||
+                   ((dirent->rec_len % 4) != 0) ||
+                   (((dirent->name_len & 0xFF)+8) > dirent->rec_len)) {
+                       fd->err = EXT2_ET_DIR_CORRUPTED;
+                       return BLOCK_ABORT;
+               }
+               if (dirent->inode == 0)
+                       goto next;
+               if (((dirent->name_len&0xFF) == 1) && (dirent->name[0] == '.'))
+                       goto next;
+               if (((dirent->name_len&0xFF) == 2) &&
+                   (dirent->name[0] == '.') && (dirent->name[1] == '.')) {
+                       fd->parent = dirent->inode;
+                       goto next;
+               }
+               if (fd->num_array >= fd->max_array) {
+                       new_array = realloc(fd->harray,
+                           sizeof(struct hash_entry) * (fd->max_array+500));
+                       if (!new_array) {
+                               fd->err = ENOMEM;
+                               return BLOCK_ABORT;
+                       }
+                       fd->harray = new_array;
+                       fd->max_array += 500;
+               }
+               ent = fd->harray + fd->num_array;
+               ent->dir = dirent;
+               fd->err = ext2fs_dirhash(fs->super->s_def_hash_version,
+                                        dirent->name,
+                                        dirent->name_len & 0xFF,
+                                        fs->super->s_hash_seed,
+                                        &ent->hash, &ent->minor_hash);
+               if (fd->err)
+                       return BLOCK_ABORT;
+               fd->num_array++;
+               fd->dir_size += EXT2_DIR_REC_LEN(dirent->name_len & 0xFF);
+       next:
+               dir_offset += dirent->rec_len;
+       }
+       
+       return 0;
+}
+
+/* Used for sorting the hash entry */
+static EXT2_QSORT_TYPE hash_cmp(const void *a, const void *b)
+{
+       const struct hash_entry *he_a = (const struct hash_entry *) a;
+       const struct hash_entry *he_b = (const struct hash_entry *) b;
+       int     ret;
+       
+       if (he_a->hash > he_b->hash)
+               ret = 1;
+       else if (he_a->hash < he_b->hash)
+               ret = -1;
+       else {
+               if (he_a->minor_hash > he_b->minor_hash)
+                       ret = 1;
+               else if (he_a->minor_hash < he_b->minor_hash)
+                       ret = -1;
+               else
+                       ret = 0;
+       }
+       return ret;
+}
+
+static errcode_t alloc_size_dir(ext2_filsys fs, struct out_dir *outdir, 
+                               int blocks)
+{
+       void                    *new_mem;
+
+       if (outdir->max) {
+               new_mem = realloc(outdir->buf, blocks * fs->blocksize);
+               if (!new_mem)
+                       return ENOMEM;
+               outdir->buf = new_mem;
+               new_mem = realloc(outdir->hashes,
+                                 blocks * sizeof(ext2_dirhash_t));
+               if (!new_mem)
+                       return ENOMEM;
+               outdir->hashes = new_mem;
+       } else {
+               outdir->buf = malloc(blocks * fs->blocksize);
+               outdir->hashes = malloc(blocks * sizeof(ext2_dirhash_t));
+               outdir->num = 0;
+       }
+       outdir->max = blocks;
+       return 0;
+}
+
+static void free_out_dir(struct out_dir *outdir)
+{
+       free(outdir->buf);
+       free(outdir->hashes);
+       outdir->max = 0;
+       outdir->num =0;
+}
+
+errcode_t get_next_block(ext2_filsys fs, struct out_dir *outdir,
+                        char ** ret)
+{
+       errcode_t       retval;
+
+       if (outdir->num >= outdir->max) {
+               retval = alloc_size_dir(fs, outdir, outdir->max + 50);
+               if (retval)
+                       return retval;
+       }
+       *ret = outdir->buf + (outdir->num++ * fs->blocksize);
+       return 0;
+}
+
+
+struct ext2_dx_root_info *set_root_node(ext2_filsys fs, char *buf,
+                                   ext2_ino_t ino, ext2_ino_t parent)
+{
+       struct ext2_dir_entry           *dir;
+       struct ext2_dx_root_info        *root;
+       struct ext2_dx_countlimit       *limits;
+       int                             filetype;
+
+       if (fs->super->s_feature_incompat & EXT2_FEATURE_INCOMPAT_FILETYPE)
+               filetype = EXT2_FT_DIR << 8;
+       
+       memset(buf, 0, fs->blocksize);
+       dir = (struct ext2_dir_entry *) buf;
+       dir->inode = ino;
+       dir->name[0] = '.';
+       dir->name_len = 1 | filetype;
+       dir->rec_len = 12;
+       dir = (struct ext2_dir_entry *) (buf + 12);
+       dir->inode = parent;
+       dir->name[0] = '.';
+       dir->name[1] = '.';
+       dir->name_len = 2 | filetype;
+       dir->rec_len = fs->blocksize - 12;
+       
+       root = (struct ext2_dx_root_info *) (buf+24);
+       root->reserved_zero = 0;
+       root->hash_version = fs->super->s_def_hash_version;
+       root->info_length = 8;
+       root->indirect_levels = 0;
+       root->unused_flags = 0;
+
+       limits = (struct ext2_dx_countlimit *) (buf+32);
+       limits->limit = (fs->blocksize - 32) / sizeof(struct ext2_dx_entry);
+       limits->count = 0;
+
+       return root;
+}
+
+
+struct ext2_dx_entry *set_int_node(ext2_filsys fs, char *buf)
+{
+       struct ext2_dir_entry           *dir;
+       struct ext2_dx_countlimit       *limits;
+
+       memset(buf, 0, fs->blocksize);
+       dir = (struct ext2_dir_entry *) buf;
+       dir->inode = 0;
+       dir->rec_len = fs->blocksize;
+       
+       limits = (struct ext2_dx_countlimit *) (buf+8);
+       limits->limit = (fs->blocksize - 8) / sizeof(struct ext2_dx_entry);
+       limits->count = 0;
+
+       return (struct ext2_dx_entry *) limits;
+}
+
+
+struct write_dir_struct {
+       struct out_dir *outdir;
+       errcode_t       err;
+       e2fsck_t        ctx;
+       int             cleared;
+};
+
+/*
+ * This makes sure we have enough space to write out the modified
+ * directory.
+ */
+static int write_dir_block(ext2_filsys fs,
+                          blk_t        *block_nr,
+                          e2_blkcnt_t blockcnt,
+                          blk_t ref_block,
+                          int ref_offset, 
+                          void *priv_data)
+{
+       struct write_dir_struct *wd = (struct write_dir_struct *) priv_data;
+       blk_t   new_blk, blk;
+       char    *dir;
+       errcode_t       retval;
+
+       if (*block_nr == 0)
+               return 0;
+       if (blockcnt >= wd->outdir->num) {
+               e2fsck_read_bitmaps(wd->ctx);
+               blk = *block_nr;
+               ext2fs_unmark_block_bitmap(wd->ctx->block_found_map, blk);
+               ext2fs_block_alloc_stats(fs, blk, -1);
+               *block_nr = 0;
+               wd->cleared++;
+               return BLOCK_CHANGED;
+       }
+       if (blockcnt < 0)
+               return 0;
+
+       dir = wd->outdir->buf + (blockcnt * fs->blocksize);
+       wd->err = ext2fs_write_dir_block(fs, *block_nr, dir);
+       if (wd->err)
+               return BLOCK_ABORT;
+       return 0;
+}
+
+
+static errcode_t write_directory(e2fsck_t ctx, ext2_filsys fs,
+                                struct out_dir *outdir, ext2_ino_t ino)
+{
+       struct write_dir_struct wd;
+       errcode_t       retval;
+       struct ext2_inode       inode;
+
+       retval = e2fsck_expand_directory(ctx, ino, -1, outdir->num);
+       if (retval)
+               return retval;
+
+       wd.outdir = outdir;
+       wd.err = 0;
+       wd.ctx = ctx;
+       wd.cleared = 0;
+
+       retval = ext2fs_block_iterate2(fs, ino, 0, 0,
+                                      write_dir_block, &wd);
+       if (retval)
+               return retval;
+       if (wd.err)
+               return wd.err;
+
+       e2fsck_read_inode(ctx, ino, &inode, "rehash_dir");
+       inode.i_flags |= EXT2_INDEX_FL;
+       inode.i_size = outdir->num * fs->blocksize;
+       inode.i_blocks -= (fs->blocksize / 512) * wd.cleared;
+       e2fsck_write_inode(ctx, ino, &inode, "rehash_dir");
+
+       return 0;
+}
+
+errcode_t e2fsck_rehash_dir(e2fsck_t ctx, ext2_ino_t ino)
+{
+       ext2_filsys             fs = ctx->fs;
+       errcode_t               retval;
+       struct ext2_inode       inode;
+       char                    *dir_buf = 0, *block_start;
+       struct hash_entry       *ent;
+       struct ext2_dir_entry   *dirent;
+       struct fill_dir_struct  fd;
+       int                     i, rec_len, left, c1, c2, nblks;
+       ext2_dirhash_t          prev_hash;
+       int                     offset;
+       void                    *new_mem;
+       struct out_dir          outdir;
+       struct ext2_dx_root_info        *root_info;
+       struct ext2_dx_entry    *root, *dx_ent;
+       struct ext2_dx_countlimit       *root_limit, *limit;
+       
+       e2fsck_read_inode(ctx, ino, &inode, "rehash_dir");
+       if ((inode.i_size / fs->blocksize) < 3)
+               return 0;
+
+       retval = ENOMEM;
+       fd.harray = 0;
+       dir_buf = malloc(inode.i_size);
+       if (!dir_buf)
+               goto errout;
+
+       fd.max_array = inode.i_size / 32;
+       fd.num_array = 0;
+       fd.harray = malloc(fd.max_array * sizeof(struct hash_entry));
+       if (!fd.harray)
+               goto errout;
+
+       fd.ctx = ctx;
+       fd.buf = dir_buf;
+       fd.inode = &inode;
+       fd.err = 0;
+       fd.dir_size = 0;
+       fd.parent = 0;
+
+       /* Read in the entire directory into memory */
+       retval = ext2fs_block_iterate2(fs, ino, 0, 0,
+                                      fill_dir_block, &fd);
+       if (fd.err) {
+               retval = fd.err;
+               goto errout;
+       }
+
+#if 0
+       printf("%d entries (%d bytes) found in inode %d\n",
+              fd.num_array, fd.dir_size, ino);
+#endif
+
+       /* Sort the list into hash order */
+       qsort(fd.harray, fd.num_array, sizeof(struct hash_entry), hash_cmp);
+
+       outdir.max = 0;
+       retval = alloc_size_dir(fs, &outdir,
+                               (fd.dir_size / fs->blocksize) + 2);
+       if (retval)
+               goto errout;
+       outdir.num = 1; offset = 0;
+       outdir.hashes[0] = 0;
+       prev_hash = 1;
+       if ((retval = get_next_block(fs, &outdir, &block_start)))
+               goto errout;
+       for (i=0; i < fd.num_array; i++) {
+               ent = fd.harray + i;
+               rec_len = EXT2_DIR_REC_LEN(ent->dir->name_len & 0xFF);
+               dirent = (struct ext2_dir_entry *) (block_start + offset);
+               left = fs->blocksize - offset;
+               if (rec_len > left) {
+                       if (left) {
+                               dirent->rec_len = left;
+                               dirent->inode = 0;
+                               dirent->name_len = 0;
+                               offset += left;
+                               left = 0;
+                       }
+                       if ((retval =  get_next_block(fs, &outdir,
+                                                     &block_start)))
+                               goto errout;
+                       offset = 0; left = fs->blocksize;
+                       dirent = (struct ext2_dir_entry *) block_start;
+               }
+               if (offset == 0) {
+                       if (ent->hash == prev_hash)
+                               outdir.hashes[outdir.num-1] = ent->hash | 1;
+                       else
+                               outdir.hashes[outdir.num-1] = ent->hash;
+               }
+               dirent->inode = ent->dir->inode;
+               dirent->name_len = ent->dir->name_len;
+               dirent->rec_len = rec_len;
+               memcpy(dirent->name, ent->dir->name, dirent->name_len & 0xFF);
+               offset += rec_len;
+               left -= rec_len;
+               if (left < 12) {
+                       dirent->rec_len += left;
+                       offset += left;
+               }
+               prev_hash = ent->hash;
+       }
+       if (left)
+               dirent->rec_len += left;
+       free(dir_buf); dir_buf = 0;
+
+       root_info = set_root_node(fs, outdir.buf, ino, fd.parent);
+       root_limit = (struct ext2_dx_countlimit *)
+               ((char *)root_info + root_info->info_length);
+       root = (struct ext2_dx_entry *) root_limit;
+       c1 = root_limit->limit;
+       nblks = outdir.num;
+
+       /* Write out the pointer blocks */
+       if (nblks-1 <= c1) {
+               /* Just write out the root block, and we're done */
+               for (i=1; i < nblks; i++) {
+                       root->block = ext2fs_cpu_to_le32(i);
+                       if (i != 1)
+                               root->hash =
+                                       ext2fs_cpu_to_le32(outdir.hashes[i]);
+                       root++;
+                       c1--;
+               }
+       } else {
+               c2 = 0;
+               limit = 0;
+               root_info->indirect_levels = 1;
+               for (i=1; i < nblks; i++) {
+                       if (c1 == 0) {
+                               retval = ENOSPC;
+                               goto errout;
+                       }
+                       if (c2 == 0) {
+                               if (limit)
+                                       limit->limit = limit->count = 
+               ext2fs_cpu_to_le16(limit->limit);
+                               root->block = ext2fs_cpu_to_le32(outdir.num);
+                               if (i != 1)
+                                       root->hash =
+                       ext2fs_cpu_to_le32(outdir.hashes[i]);
+                               if ((retval =  get_next_block(fs, &outdir,
+                                                             &block_start)))
+                                       goto errout;
+                               dx_ent = set_int_node(fs, block_start);
+                               limit = (struct ext2_dx_countlimit *) dx_ent;
+                               c2 = limit->limit;
+                               root++;
+                               c1--;
+                       }
+                       dx_ent->block = ext2fs_cpu_to_le32(i);
+                       if (c2 != limit->limit)
+                               dx_ent->hash =
+                                       ext2fs_cpu_to_le32(outdir.hashes[i]);
+                       dx_ent++;
+                       c2--;
+               }
+               limit->count = ext2fs_cpu_to_le16(limit->limit - c2);
+               limit->limit = ext2fs_cpu_to_le16(limit->limit);
+       }
+       root_limit->count = ext2fs_cpu_to_le16(root_limit->limit - c1);
+       root_limit->limit = ext2fs_cpu_to_le16(root_limit->limit);
+
+       retval = write_directory(ctx, fs, &outdir, ino);
+       if (retval)
+               goto errout;
+
+errout:
+       if (dir_buf)
+               free(dir_buf);
+       free_out_dir(&outdir);
+       return retval;
+}
+
+void e2fsck_rehash_directories(e2fsck_t ctx)
+{
+       errcode_t       retval;
+       struct problem_context  pctx;
+       ext2_u32_iterate iter;
+       ext2_ino_t      ino,lpf;
+       static const char name[] = "lost+found";
+       int     first = 1;
+
+       if (!ctx->dirs_to_hash)
+               return;
+
+       retval = ext2fs_lookup(ctx->fs, EXT2_ROOT_INO, name,
+                              sizeof(name)-1, 0, &lpf);
+       if (retval)
+               lpf = 0;
+               
+       clear_problem_context(&pctx);
+       retval = ext2fs_u32_list_iterate_begin(ctx->dirs_to_hash, &iter);
+       if (retval) {
+               pctx.errcode = retval;
+               fix_problem(ctx, PR_3A_REHASH_ITER, &pctx);
+               return;
+       }
+       while (ext2fs_u32_list_iterate(iter, &ino)) {
+               if (ino == lpf)
+                       continue;
+               pctx.dir = ino;
+               if (first) {
+                       fix_problem(ctx, PR_3A_PASS_HEADER, &pctx);
+                       first = 0;
+               }
+               fix_problem(ctx, PR_3A_REHASH_DIR, &pctx);
+               pctx.errcode = e2fsck_rehash_dir(ctx, ino);
+               if (pctx.errcode) {
+                       end_problem_latch(ctx, PR_LATCH_REHASH_DIR);
+                       fix_problem(ctx, PR_3A_REHASH_DIR_ERR, &pctx);
+               }
+       }
+       end_problem_latch(ctx, PR_LATCH_REHASH_DIR);
+       ext2fs_u32_list_iterate_end(iter);
+       
+       ext2fs_u32_list_free(ctx->dirs_to_hash);
+       ctx->dirs_to_hash = 0;
+}
index 711daa96d08e8b750a7cf9de898cd7b56e936db4..4bbbca229b1d8dd1ab45ed24850f8f73e3e5e62f 100644 (file)
@@ -1,5 +1,11 @@
 2002-07-19  Theodore Ts'o  <tytso@mit.edu>
 
+       * ext2_fs.h: Add s_hash_seed and s_def_hash_version to the
+               superblock definition.
+
+       * badblocks.c, freefs.c, ext2fs.h: Use the badblocks functions to
+               create a set of u32_list functions.
+
        * dirhash.c (halfMD4Transform): Shift the hash by one bit,
                since that's required by the directory indexing code.
 
index 4e94e8c87643533f0356696d5ee74acb73862777..6f9ef95b0ea963541c45e700c31d7fd714fddfb7 100644 (file)
 /*
  * Helper function for making a badblocks list
  */
-static errcode_t make_badblocks_list(int size, int num, blk_t *list,
-                                    ext2_badblocks_list *ret)
+static errcode_t make_u32_list(int size, int num, __u32 *list,
+                              ext2_u32_list *ret)
 {
-       ext2_badblocks_list     bb;
-       errcode_t               retval;
+       ext2_u32_list   bb;
+       errcode_t       retval;
        
-       retval = ext2fs_get_mem(sizeof(struct ext2_struct_badblocks_list),
+       retval = ext2fs_get_mem(sizeof(struct ext2_struct_u32_list),
                                (void **) &bb);
        if (retval)
                return retval;
-       memset(bb, 0, sizeof(struct ext2_struct_badblocks_list));
+       memset(bb, 0, sizeof(struct ext2_struct_u32_list));
        bb->magic = EXT2_ET_MAGIC_BADBLOCKS_LIST;
        bb->size = size ? size : 10;
        bb->num = num;
@@ -57,30 +57,43 @@ static errcode_t make_badblocks_list(int size, int num, blk_t *list,
 }
        
 
+/*
+ * This procedure creates an empty u32 list.
+ */
+errcode_t ext2fs_u32_list_create(ext2_u32_list *ret, int size)
+{
+       return make_u32_list(size, 0, 0, ret);
+}
+
 /*
  * This procedure creates an empty badblocks list.
  */
 errcode_t ext2fs_badblocks_list_create(ext2_badblocks_list *ret, int size)
 {
-       return make_badblocks_list(size, 0, 0, ret);
+       return make_u32_list(size, 0, 0, (ext2_badblocks_list *) ret);
 }
 
+
 /*
  * This procedure copies a badblocks list
  */
-errcode_t ext2fs_badblocks_copy(ext2_badblocks_list src,
-                               ext2_badblocks_list *dest)
+errcode_t ext2fs_u32_copy(ext2_u32_list src, ext2_u32_list *dest)
 {
        errcode_t       retval;
        
-       retval = make_badblocks_list(src->size, src->num, src->list,
-                                    dest);
+       retval = make_u32_list(src->size, src->num, src->list, dest);
        if (retval)
                return retval;
        (*dest)->badblocks_flags = src->badblocks_flags;
        return 0;
 }
 
+errcode_t ext2fs_badblocks_copy(ext2_badblocks_list src,
+                               ext2_badblocks_list *dest)
+{
+       return ext2fs_u32_copy((ext2_u32_list) src,
+                              (ext2_u32_list *) dest);
+}
 
 /*
  * This procedure frees a badblocks list.
@@ -92,7 +105,7 @@ errcode_t ext2fs_badblocks_copy(ext2_badblocks_list src,
 /*
  * This procedure adds a block to a badblocks list.
  */
-errcode_t ext2fs_badblocks_list_add(ext2_badblocks_list bb, blk_t blk)
+errcode_t ext2fs_u32_list_add(ext2_u32_list bb, __u32 blk)
 {
        errcode_t       retval;
        int             i, j;
@@ -101,9 +114,9 @@ errcode_t ext2fs_badblocks_list_add(ext2_badblocks_list bb, blk_t blk)
        EXT2_CHECK_MAGIC(bb, EXT2_ET_MAGIC_BADBLOCKS_LIST);
 
        if (bb->num >= bb->size) {
-               old_size = bb->size * sizeof(blk_t);
+               old_size = bb->size * sizeof(__u32);
                bb->size += 100;
-               retval = ext2fs_resize_mem(old_size, bb->size * sizeof(blk_t),
+               retval = ext2fs_resize_mem(old_size, bb->size * sizeof(__u32),
                                           (void **) &bb->list);
                if (retval) {
                        bb->size -= 100;
@@ -138,11 +151,18 @@ errcode_t ext2fs_badblocks_list_add(ext2_badblocks_list bb, blk_t blk)
        return 0;
 }
 
+errcode_t ext2fs_badblocks_list_add(ext2_badblocks_list bb, blk_t blk)
+{
+       return ext2fs_u32_list_add((ext2_u32_list) bb, (__u32) blk);
+}
+
+
+
 /*
  * This procedure tests to see if a particular block is on a badblocks
  * list.
  */
-int ext2fs_badblocks_list_test(ext2_badblocks_list bb, blk_t blk)
+int ext2fs_u32_list_test(ext2_u32_list bb, __u32 blk)
 {
        int     low, high, mid;
 
@@ -173,15 +193,21 @@ int ext2fs_badblocks_list_test(ext2_badblocks_list bb, blk_t blk)
        return 0;
 }
 
-errcode_t ext2fs_badblocks_list_iterate_begin(ext2_badblocks_list bb,
-                                             ext2_badblocks_iterate *ret)
+int ext2fs_badblocks_list_test(ext2_badblocks_list bb, blk_t blk)
+{
+       return ext2fs_u32_list_test((ext2_u32_list) bb, (__u32) blk);
+}
+
+
+errcode_t ext2fs_u32_list_iterate_begin(ext2_u32_list bb,
+                                       ext2_u32_iterate *ret)
 {
-       ext2_badblocks_iterate iter;
+       ext2_u32_iterate iter;
        errcode_t               retval;
 
        EXT2_CHECK_MAGIC(bb, EXT2_ET_MAGIC_BADBLOCKS_LIST);
 
-       retval = ext2fs_get_mem(sizeof(struct ext2_struct_badblocks_iterate),
+       retval = ext2fs_get_mem(sizeof(struct ext2_struct_u32_iterate),
                              (void **) &iter);
        if (retval)
                return retval;
@@ -193,9 +219,17 @@ errcode_t ext2fs_badblocks_list_iterate_begin(ext2_badblocks_list bb,
        return 0;
 }
 
-int ext2fs_badblocks_list_iterate(ext2_badblocks_iterate iter, blk_t *blk)
+errcode_t ext2fs_badblocks_list_iterate_begin(ext2_badblocks_list bb,
+                                             ext2_badblocks_iterate *ret)
 {
-       ext2_badblocks_list     bb;
+       return ext2fs_u32_list_iterate_begin((ext2_u32_list) bb,
+                                             (ext2_u32_iterate *) ret);
+}
+
+
+int ext2fs_u32_list_iterate(ext2_u32_iterate iter, __u32 *blk)
+{
+       ext2_u32_list   bb;
 
        if (iter->magic != EXT2_ET_MAGIC_BADBLOCKS_ITERATE)
                return 0;
@@ -213,7 +247,14 @@ int ext2fs_badblocks_list_iterate(ext2_badblocks_iterate iter, blk_t *blk)
        return 0;
 }
 
-void ext2fs_badblocks_list_iterate_end(ext2_badblocks_iterate iter)
+int ext2fs_badblocks_list_iterate(ext2_badblocks_iterate iter, blk_t *blk)
+{
+       return ext2fs_u32_list_iterate((ext2_u32_iterate) iter,
+                                      (__u32 *) blk);
+}
+
+
+void ext2fs_u32_list_iterate_end(ext2_u32_iterate iter)
 {
        if (!iter || (iter->magic != EXT2_ET_MAGIC_BADBLOCKS_ITERATE))
                return;
@@ -222,7 +263,13 @@ void ext2fs_badblocks_list_iterate_end(ext2_badblocks_iterate iter)
        ext2fs_free_mem((void **) &iter);
 }
 
-int ext2fs_badblocks_equal(ext2_badblocks_list bb1, ext2_badblocks_list bb2)
+void ext2fs_badblocks_list_iterate_end(ext2_badblocks_iterate iter)
+{
+       ext2fs_u32_list_iterate_end((ext2_u32_iterate) iter);
+}
+
+
+int ext2fs_u32_list_equal(ext2_u32_list bb1, ext2_u32_list bb2)
 {
        EXT2_CHECK_MAGIC(bb1, EXT2_ET_MAGIC_BADBLOCKS_LIST);
        EXT2_CHECK_MAGIC(bb2, EXT2_ET_MAGIC_BADBLOCKS_LIST);
@@ -234,3 +281,9 @@ int ext2fs_badblocks_equal(ext2_badblocks_list bb1, ext2_badblocks_list bb2)
                return 0;
        return 1;
 }
+
+int ext2fs_badblocks_equal(ext2_badblocks_list bb1, ext2_badblocks_list bb2)
+{
+       return ext2fs_u32_list_equal((ext2_u32_list) bb1,
+                                    (ext2_u32_list) bb2);
+}
index 677805acd1ce3216a0f495dc43de7ff6082551ed..c53b13c726cf8d331ea70c493906619c410e1d35 100644 (file)
@@ -435,8 +435,11 @@ struct ext2_super_block {
        __u32   s_journal_inum;         /* inode number of journal file */
        __u32   s_journal_dev;          /* device number of journal file */
        __u32   s_last_orphan;          /* start of list of inodes to delete */
-       __u32   s_hash_seed[4];         /* HTREE hash */
-       __u32   s_reserved[193];        /* Padding to the end of the block */
+       __u32   s_hash_seed[4];         /* HTREE hash seed */
+       __u8    s_def_hash_version;     /* Default hash version to use */
+       __u8    s_reserved_char_pad;
+       __u16   s_reserved_word_pad;
+       __u32   s_reserved[192];        /* Padding to the end of the block */
 };
 
 /*
index b7f5ff2167ac36d42ea43ba007bf8d386f6ef6d0..6002193081db30281b5d72b27fd0e89aa78f1d53 100644 (file)
@@ -118,12 +118,15 @@ typedef struct ext2fs_struct_generic_bitmap *ext2fs_block_bitmap;
  * badblocks list definitions
  */
 
-typedef struct ext2_struct_badblocks_list *ext2_badblocks_list;
-typedef struct ext2_struct_badblocks_iterate *ext2_badblocks_iterate;
+typedef struct ext2_struct_u32_list *ext2_badblocks_list;
+typedef struct ext2_struct_u32_iterate *ext2_badblocks_iterate;
+
+typedef struct ext2_struct_u32_list *ext2_u32_list;
+typedef struct ext2_struct_u32_iterate *ext2_u32_iterate;
 
 /* old */
-typedef struct ext2_struct_badblocks_list *badblocks_list;
-typedef struct ext2_struct_badblocks_iterate *badblocks_iterate;
+typedef struct ext2_struct_u32_list *badblocks_list;
+typedef struct ext2_struct_u32_iterate *badblocks_iterate;
 
 #define BADBLOCKS_FLAG_DIRTY   1
 
@@ -210,7 +213,7 @@ struct struct_ext2_filsys {
                                struct ext2_inode *inode);
        errcode_t (*write_inode)(ext2_filsys fs, ext2_ino_t ino,
                                struct ext2_inode *inode);
-       badblocks_list                  badblocks;
+       ext2_badblocks_list             badblocks;
        ext2_dblist                     dblist;
        __u32                           stride; /* for mke2fs */
        struct ext2_super_block *       orig_super;
@@ -462,6 +465,16 @@ extern errcode_t ext2fs_allocate_group_table(ext2_filsys fs, dgrp_t group,
                                             ext2fs_block_bitmap bmap);
 
 /* badblocks.c */
+extern errcode_t ext2fs_u32_list_create(ext2_u32_list *ret, int size);
+extern errcode_t ext2fs_u32_list_add(ext2_u32_list bb, __u32 blk);
+extern int ext2fs_u32_list_test(ext2_u32_list bb, blk_t blk);
+extern errcode_t ext2fs_u32_list_iterate_begin(ext2_u32_list bb,
+                                              ext2_u32_iterate *ret);
+extern int ext2fs_u32_list_iterate(ext2_u32_iterate iter, blk_t *blk);
+extern void ext2fs_u32_list_iterate_end(ext2_u32_iterate iter);
+extern errcode_t ext2fs_u32_copy(ext2_u32_list src, ext2_u32_list *dest);
+extern int ext2fs_u32_list_equal(ext2_u32_list bb1, ext2_u32_list bb2);
+
 extern errcode_t ext2fs_badblocks_list_create(ext2_badblocks_list *ret,
                                            int size);
 extern errcode_t ext2fs_badblocks_list_add(ext2_badblocks_list bb,
@@ -678,7 +691,8 @@ extern void ext2fs_free_generic_bitmap(ext2fs_inode_bitmap bitmap);
 extern void ext2fs_free_block_bitmap(ext2fs_block_bitmap bitmap);
 extern void ext2fs_free_inode_bitmap(ext2fs_inode_bitmap bitmap);
 extern void ext2fs_free_dblist(ext2_dblist dblist);
-extern void ext2fs_badblocks_list_free(badblocks_list bb);
+extern void ext2fs_badblocks_list_free(ext2_badblocks_list bb);
+extern void ext2fs_u32_list_free(ext2_u32_list bb);
 
 /* getsize.c */
 extern errcode_t ext2fs_get_device_size(const char *file, int blocksize,
index 57833546e6c4d8e43fba07ad6078c8f0871d572a..eea32d632b092d40e8cdead89da429365e932ca6 100644 (file)
 /*
  * Badblocks list
  */
-struct ext2_struct_badblocks_list {
+struct ext2_struct_u32_list {
        int     magic;
        int     num;
        int     size;
-       blk_t   *list;
+       __u32   *list;
        int     badblocks_flags;
 };
 
-struct ext2_struct_badblocks_iterate {
-       int             magic;
-       badblocks_list  bb;
-       int             ptr;
+struct ext2_struct_u32_iterate {
+       int                     magic;
+       ext2_u32_list           bb;
+       int                     ptr;
 };
 
 
index 5cb3cf8b703dd0acd29e7443ba17d1aef63edc78..37de8692e8164d6924fafad49f4a37061aa205ed 100644 (file)
@@ -107,7 +107,7 @@ static void ext2fs_free_inode_cache(struct ext2_inode_cache *icache)
 /*
  * This procedure frees a badblocks list.
  */
-void ext2fs_badblocks_list_free(ext2_badblocks_list bb)
+void ext2fs_u32_list_free(ext2_u32_list bb)
 {
        if (bb->magic != EXT2_ET_MAGIC_BADBLOCKS_LIST)
                return;
@@ -118,6 +118,12 @@ void ext2fs_badblocks_list_free(ext2_badblocks_list bb)
        ext2fs_free_mem((void **) &bb);
 }
 
+void ext2fs_badblocks_list_free(ext2_badblocks_list bb)
+{
+       ext2fs_u32_list_free((ext2_u32_list) bb);
+}
+
+
 /*
  * Free a directory block list
  */
index c960c76c38f341af35f21f25beb5e26fb0320829..7d35940719d92619576762ed7e5ae6a997350a15 100644 (file)
@@ -1,3 +1,8 @@
+2002-07-19  Theodore Ts'o  <tytso@mit.edu>
+
+       * f_expand, f_h_badnode, f_h_badroot: Modify the expect scripts to
+               reflect the rebuild hash index directories.
+
 2002-06-26  Theodore Ts'o  <tytso@mit.edu>
 
        * f_h_badroot: New test cases to test bogus HTREE node values
index 7a92fb179c6aad0db0eb41ccf04db9fec0a60b21..c14287d0340191e8c8c980ea50f6a520ca812c8a 100644 (file)
@@ -11461,10 +11461,10 @@ Pass 5: Checking group summary information
 Block bitmap differences:  -(776--786)
 Fix? yes
 
-Free blocks count wrong for group #0 (86, counted=97).
+Free blocks count wrong for group #0 (62, counted=97).
 Fix? yes
 
-Free blocks count wrong (86, counted=97).
+Free blocks count wrong (62, counted=97).
 Fix? yes
 
 Directories count wrong for group #0 (6, counted=5).
index 6d45eab54aca9eadbecafa82aa46fc16c0de3d46..a0a13f0979375f9125d1212db2ae356f3c83b10d 100644 (file)
@@ -8,9 +8,11 @@ Problem in HTREE directory inode 12929: node (1062) not referenced
 Invalid HTREE directory inode 12929 (/test2).  Clear? yes
 
 Pass 3: Checking directory connectivity
+Pass 3a: Reindexing directories
+Rehashing directories:  12929
 Pass 4: Checking reference counts
 Pass 5: Checking group summary information
 
 test_filesys: ***** FILE SYSTEM WAS MODIFIED *****
-test_filesys: 47730/100192 files (0.0% non-contiguous), 13689/31745 blocks
+test_filesys: 47730/100192 files (0.0% non-contiguous), 13377/31745 blocks
 Exit status is 1
index 4f8c0ac218ee1c293bcce511488e0b8e468c0474..8a219978b5115abde33e0fd1bfa7704c0e84a6d1 100644 (file)
@@ -3,5 +3,5 @@ Pass 2: Checking directory structure
 Pass 3: Checking directory connectivity
 Pass 4: Checking reference counts
 Pass 5: Checking group summary information
-test_filesys: 47730/100192 files (0.0% non-contiguous), 13689/31745 blocks
+test_filesys: 47730/100192 files (0.0% non-contiguous), 13377/31745 blocks
 Exit status is 0
index d901967a82b4c4db9b1d971fa446415f4652a82b..73b5b1b298c3be5d7d11dad25ac4c9c6ca638677 100644 (file)
@@ -25,9 +25,11 @@ Problem in HTREE directory inode 80065: node (21) has bad max hash
 Invalid HTREE directory inode 80065 (/test7).  Clear? yes
 
 Pass 3: Checking directory connectivity
+Pass 3a: Reindexing directories
+Rehashing directories:  13345 26689 40033 53377 66721 73393 80065
 Pass 4: Checking reference counts
 Pass 5: Checking group summary information
 
 test_filesys: ***** FILE SYSTEM WAS MODIFIED *****
-test_filesys: 1719/100080 files (0.0% non-contiguous), 12611/15361 blocks
+test_filesys: 1719/100080 files (0.0% non-contiguous), 12605/15361 blocks
 Exit status is 1
index 82d72088b31d58edbdaa61879cbcaf9cd754a890..65d457e9d8c9ac2b0ddf5e58c93ec31b0581269d 100644 (file)
@@ -3,5 +3,5 @@ Pass 2: Checking directory structure
 Pass 3: Checking directory connectivity
 Pass 4: Checking reference counts
 Pass 5: Checking group summary information
-test_filesys: 1719/100080 files (0.0% non-contiguous), 12611/15361 blocks
+test_filesys: 1719/100080 files (0.0% non-contiguous), 12605/15361 blocks
 Exit status is 0