Whamcloud - gitweb
e2fsck: merge dirs_to_hash when threads finish
[tools/e2fsprogs.git] / e2fsck / pass1.c
index c5b3c09..922de3d 100644 (file)
@@ -88,7 +88,6 @@ static void alloc_imagic_map(e2fsck_t ctx);
 static void mark_inode_bad(e2fsck_t ctx, ino_t ino);
 static void add_casefolded_dir(e2fsck_t ctx, ino_t ino);
 static void handle_fs_bad_blocks(e2fsck_t ctx);
-static void process_inodes(e2fsck_t ctx, char *block_buf);
 static EXT2_QSORT_TYPE process_inode_cmp(const void *a, const void *b);
 static errcode_t scan_callback(ext2_filsys fs, ext2_inode_scan scan,
                                  dgrp_t group, void * priv_data);
@@ -123,15 +122,15 @@ struct process_inode_block {
 };
 
 struct scan_callback_struct {
-       e2fsck_t        ctx;
-       char            *block_buf;
+       e2fsck_t                         ctx;
+       char                            *block_buf;
+       struct process_inode_block      *inodes_to_process;
+       int                             *process_inode_count;
 };
 
-/*
- * For the inodes to process list.
- */
-static struct process_inode_block *inodes_to_process;
-static int process_inode_count;
+static void process_inodes(e2fsck_t ctx, char *block_buf,
+                          struct process_inode_block *inodes_to_process,
+                          int *process_inode_count);
 
 static __u64 ext2_max_sizes[EXT2_MAX_BLOCK_LOG_SIZE -
                            EXT2_MIN_BLOCK_LOG_SIZE + 1];
@@ -1170,7 +1169,6 @@ static int e2fsck_should_abort(e2fsck_t ctx)
 void e2fsck_pass1_run(e2fsck_t ctx)
 {
        int     i;
-       __u64   max_sizes;
        ext2_filsys fs = ctx->fs;
        ext2_ino_t      ino = 0;
        struct ext2_inode *inode = NULL;
@@ -1193,6 +1191,8 @@ void e2fsck_pass1_run(e2fsck_t ctx)
        ext2_ino_t      ino_threshold = 0;
        dgrp_t          ra_group = 0;
        struct ea_quota ea_ibody_quota;
+       struct process_inode_block *inodes_to_process;
+       int             process_inode_count;
 
        init_resource_track(&rtrack, ctx->fs->io);
        clear_problem_context(&pctx);
@@ -1217,17 +1217,6 @@ void e2fsck_pass1_run(e2fsck_t ctx)
        mtrace_print("Pass 1");
 #endif
 
-#define EXT2_BPP(bits) (1ULL << ((bits) - 2))
-
-       for (i = EXT2_MIN_BLOCK_LOG_SIZE; i <= EXT2_MAX_BLOCK_LOG_SIZE; i++) {
-               max_sizes = EXT2_NDIR_BLOCKS + EXT2_BPP(i);
-               max_sizes = max_sizes + EXT2_BPP(i) * EXT2_BPP(i);
-               max_sizes = max_sizes + EXT2_BPP(i) * EXT2_BPP(i) * EXT2_BPP(i);
-               max_sizes = (max_sizes * (1UL << i));
-               ext2_max_sizes[i - EXT2_MIN_BLOCK_LOG_SIZE] = max_sizes;
-       }
-#undef EXT2_BPP
-
        imagic_fs = ext2fs_has_feature_imagic_inodes(sb);
        extent_fs = ext2fs_has_feature_extents(sb);
        inlinedata_fs = ext2fs_has_feature_inline_data(sb);
@@ -1248,6 +1237,7 @@ void e2fsck_pass1_run(e2fsck_t ctx)
        }
        pctx.errcode = e2fsck_allocate_inode_bitmap(fs,
                        _("directory inode map"),
+                       ctx->global_ctx ? EXT2FS_BMAP64_RBTREE :
                        EXT2FS_BMAP64_AUTODIR,
                        "inode_dir_map", &ctx->inode_dir_map);
        if (pctx.errcode) {
@@ -1365,6 +1355,8 @@ void e2fsck_pass1_run(e2fsck_t ctx)
        ctx->stashed_inode = inode;
        scan_struct.ctx = ctx;
        scan_struct.block_buf = block_buf;
+       scan_struct.inodes_to_process = inodes_to_process;
+       scan_struct.process_inode_count = &process_inode_count;
        ext2fs_set_inode_callback(scan, scan_callback, &scan_struct);
        if (ctx->progress && ((ctx->progress)(ctx, 1, 0,
                                              ctx->fs->group_desc_count)))
@@ -2018,13 +2010,15 @@ void e2fsck_pass1_run(e2fsck_t ctx)
                        goto endit;
 
                if (process_inode_count >= ctx->process_inode_size) {
-                       process_inodes(ctx, block_buf);
+                       process_inodes(ctx, block_buf, inodes_to_process,
+                                      &process_inode_count);
 
                        if (e2fsck_should_abort(ctx))
                                goto endit;
                }
        }
-       process_inodes(ctx, block_buf);
+       process_inodes(ctx, block_buf, inodes_to_process,
+                      &process_inode_count);
        ext2fs_close_inode_scan(scan);
        scan = NULL;
 
@@ -2147,6 +2141,27 @@ endit:
                ctx->invalid_bitmaps++;
 }
 
+static void init_ext2_max_sizes()
+{
+       int     i;
+       __u64   max_sizes;
+
+       /*
+        * Init ext2_max_sizes which will be immutable and shared between
+        * threads
+        */
+#define EXT2_BPP(bits) (1ULL << ((bits) - 2))
+
+       for (i = EXT2_MIN_BLOCK_LOG_SIZE; i <= EXT2_MAX_BLOCK_LOG_SIZE; i++) {
+               max_sizes = EXT2_NDIR_BLOCKS + EXT2_BPP(i);
+               max_sizes = max_sizes + EXT2_BPP(i) * EXT2_BPP(i);
+               max_sizes = max_sizes + EXT2_BPP(i) * EXT2_BPP(i) * EXT2_BPP(i);
+               max_sizes = (max_sizes * (1UL << i));
+               ext2_max_sizes[i - EXT2_MIN_BLOCK_LOG_SIZE] = max_sizes;
+       }
+#undef EXT2_BPP
+}
+
 #ifdef HAVE_PTHREAD
 static errcode_t e2fsck_pass1_copy_bitmap(ext2_filsys fs, ext2fs_generic_bitmap *src,
                                          ext2fs_generic_bitmap *dest)
@@ -2158,12 +2173,38 @@ static errcode_t e2fsck_pass1_copy_bitmap(ext2_filsys fs, ext2fs_generic_bitmap
                return ret;
 
        (*dest)->fs = fs;
-       ext2fs_free_generic_bmap(*src);
-       *src = NULL;
 
        return 0;
 }
 
+static void e2fsck_pass1_free_bitmap(ext2fs_generic_bitmap *bitmap)
+{
+       if (*bitmap) {
+               ext2fs_free_generic_bmap(*bitmap);
+               *bitmap = NULL;
+       }
+
+}
+
+static errcode_t e2fsck_pass1_merge_bitmap(ext2_filsys fs, ext2fs_generic_bitmap *src,
+                                         ext2fs_generic_bitmap *dest)
+{
+       errcode_t ret = 0;
+
+       if (*src) {
+               if (*dest == NULL) {
+                       *dest = *src;
+                       *src = NULL;
+               } else {
+                       ret = ext2fs_merge_bitmap(*src, *dest, NULL, NULL);
+                       if (ret)
+                               return ret;
+               }
+               (*dest)->fs = fs;
+       }
+
+       return 0;
+}
 
 static errcode_t e2fsck_pass1_copy_fs(ext2_filsys dest, e2fsck_t src_context,
                                      ext2_filsys src)
@@ -2171,6 +2212,9 @@ static errcode_t e2fsck_pass1_copy_fs(ext2_filsys dest, e2fsck_t src_context,
        errcode_t       retval;
 
        memcpy(dest, src, sizeof(struct struct_ext2_filsys));
+       dest->inode_map = NULL;
+       dest->block_map = NULL;
+       dest->badblocks = NULL;
        if (dest->dblist)
                dest->dblist->fs = dest;
        if (src->block_map) {
@@ -2187,7 +2231,8 @@ static errcode_t e2fsck_pass1_copy_fs(ext2_filsys dest, e2fsck_t src_context,
        }
 
        if (src->badblocks) {
-               retval = ext2fs_badblocks_copy(src->badblocks, &dest->badblocks);
+               retval = ext2fs_badblocks_copy(src->badblocks,
+                                              &dest->badblocks);
                if (retval)
                        return retval;
        }
@@ -2230,42 +2275,81 @@ static int e2fsck_pass1_merge_fs(ext2_filsys dest, ext2_filsys src)
        errcode_t retval = 0;
        io_channel dest_io;
        io_channel dest_image_io;
+       ext2fs_inode_bitmap inode_map;
+       ext2fs_block_bitmap block_map;
+       ext2_badblocks_list badblocks;
+       ext2_dblist dblist;
+       int flags;
 
        dest_io = dest->io;
        dest_image_io = dest->image_io;
+       inode_map = dest->inode_map;
+       block_map = dest->block_map;
+       badblocks = dest->badblocks;
+       dblist = dest->dblist;
+       flags = dest->flags;
 
        memcpy(dest, src, sizeof(struct struct_ext2_filsys));
        dest->io = dest_io;
        dest->image_io = dest_image_io;
        dest->icache = icache;
+       dest->inode_map = inode_map;
+       dest->block_map = block_map;
+       dest->badblocks = badblocks;
+       dest->dblist = dblist;
        if (dest->dblist)
                dest->dblist->fs = dest;
-       if (src->inode_map) {
-               retval = e2fsck_pass1_copy_bitmap(dest, &src->inode_map,
-                                                 &dest->inode_map);
-               if (retval)
-                       return retval;
-       }
-       if (src->block_map) {
-               retval = e2fsck_pass1_copy_bitmap(dest, &src->block_map,
-                                                 &dest->block_map);
-               if (retval)
-                       return retval;
-       }
+       dest->flags = src->flags | flags;
+       if (!(src->flags & EXT2_FLAG_VALID) || !(flags & EXT2_FLAG_VALID))
+               ext2fs_unmark_valid(dest);
 
        if (src->icache) {
                ext2fs_free_inode_cache(src->icache);
                src->icache = NULL;
        }
 
-       if (src->badblocks) {
-               retval = ext2fs_badblocks_copy(src->badblocks, &dest->badblocks);
+       retval = e2fsck_pass1_merge_bitmap(dest, &src->inode_map,
+                                          &dest->inode_map);
+       if (retval)
+               goto out;
 
-               ext2fs_badblocks_list_free(src->badblocks);
-               src->badblocks = NULL;
+       retval = e2fsck_pass1_merge_bitmap(dest, &src->block_map,
+                                         &dest->block_map);
+       if (retval)
+               goto out;
+
+       if (src->dblist) {
+               if (dest->dblist) {
+                       retval = ext2fs_merge_dblist(src->dblist,
+                                                    dest->dblist);
+                       if (retval)
+                               goto out;
+               } else {
+                       dest->dblist = src->dblist;
+                       dest->dblist->fs = dest;
+                       src->dblist = NULL;
+               }
        }
 
+       if (src->badblocks) {
+               if (dest->badblocks == NULL)
+                       retval = ext2fs_badblocks_copy(src->badblocks,
+                                                      &dest->badblocks);
+               else
+                       retval = ext2fs_badblocks_merge(src->badblocks,
+                                                       dest->badblocks);
+       }
+out:
        io_channel_close(src->io);
+       if (src->inode_map)
+               ext2fs_free_generic_bmap(src->inode_map);
+       if (src->block_map)
+               ext2fs_free_generic_bmap(src->block_map);
+       if (src->badblocks)
+               ext2fs_badblocks_list_free(src->badblocks);
+       if (src->dblist)
+               ext2fs_free_dblist(src->dblist);
+
        return retval;
 }
 
@@ -2347,6 +2431,91 @@ out_context:
        return retval;
 }
 
+static void e2fsck_pass1_merge_dir_info(e2fsck_t global_ctx, e2fsck_t thread_ctx)
+{
+       if (thread_ctx->dir_info == NULL)
+               return;
+
+       if (global_ctx->dir_info == NULL) {
+               global_ctx->dir_info = thread_ctx->dir_info;
+               thread_ctx->dir_info = NULL;
+               return;
+       }
+
+       e2fsck_merge_dir_info(global_ctx, thread_ctx->dir_info,
+                             global_ctx->dir_info);
+}
+
+static void e2fsck_pass1_merge_dx_dir(e2fsck_t global_ctx, e2fsck_t thread_ctx)
+{
+       if (thread_ctx->dx_dir_info == NULL)
+               return;
+
+       if (global_ctx->dx_dir_info == NULL) {
+               global_ctx->dx_dir_info = thread_ctx->dx_dir_info;
+               global_ctx->dx_dir_info_size = thread_ctx->dx_dir_info_size;
+               global_ctx->dx_dir_info_count = thread_ctx->dx_dir_info_count;
+               thread_ctx->dx_dir_info = NULL;
+               return;
+       }
+
+       e2fsck_merge_dx_dir(global_ctx, thread_ctx);
+}
+
+static inline errcode_t
+e2fsck_pass1_merge_icount(ext2_icount_t *dest_icount,
+                         ext2_icount_t *src_icount)
+{
+       if (*src_icount) {
+               if (*dest_icount == NULL) {
+                       *dest_icount = *src_icount;
+                       *src_icount = NULL;
+               } else {
+                       errcode_t ret;
+
+                       ret = ext2fs_icount_merge(*src_icount,
+                                                 *dest_icount);
+                       if (ret)
+                               return ret;
+               }
+       }
+
+       return 0;
+}
+
+static errcode_t e2fsck_pass1_merge_icounts(e2fsck_t global_ctx, e2fsck_t thread_ctx)
+{
+       errcode_t ret;
+
+       ret = e2fsck_pass1_merge_icount(&global_ctx->inode_count,
+                                       &thread_ctx->inode_count);
+       if (ret)
+               return ret;
+       ret = e2fsck_pass1_merge_icount(&global_ctx->inode_link_info,
+                                       &thread_ctx->inode_link_info);
+
+       return ret;
+}
+
+static errcode_t e2fsck_pass1_merge_dirs_to_hash(e2fsck_t global_ctx,
+                                                e2fsck_t thread_ctx)
+{
+       errcode_t retval = 0;
+
+       if (!thread_ctx->dirs_to_hash)
+               return 0;
+
+       if (!global_ctx->dirs_to_hash)
+               retval = ext2fs_badblocks_copy(thread_ctx->dirs_to_hash,
+                                              &global_ctx->dirs_to_hash);
+       else
+               retval = ext2fs_badblocks_merge(thread_ctx->dirs_to_hash,
+                                               global_ctx->dirs_to_hash);
+
+       return retval;
+}
+
+
 static int e2fsck_pass1_thread_join_one(e2fsck_t global_ctx, e2fsck_t thread_ctx)
 {
        errcode_t        retval;
@@ -2355,6 +2524,42 @@ static int e2fsck_pass1_thread_join_one(e2fsck_t global_ctx, e2fsck_t thread_ctx
        ext2_filsys      global_fs = global_ctx->fs;
        FILE            *global_logf = global_ctx->logf;
        FILE            *global_problem_logf = global_ctx->problem_logf;
+       ext2fs_inode_bitmap inode_bad_map = global_ctx->inode_bad_map;
+       struct dir_info_db *dir_info = global_ctx->dir_info;
+       struct dx_dir_info *dx_dir_info = global_ctx->dx_dir_info;
+       ext2fs_inode_bitmap inode_used_map = global_ctx->inode_used_map;
+       ext2fs_inode_bitmap inode_dir_map = global_ctx->inode_dir_map;
+       ext2fs_inode_bitmap inode_bb_map = global_ctx->inode_bb_map;
+       ext2fs_inode_bitmap inode_imagic_map = global_ctx->inode_imagic_map;
+       ext2fs_inode_bitmap inode_reg_map = global_ctx->inode_reg_map;
+       ext2fs_block_bitmap block_found_map = global_ctx->block_found_map;
+       ext2fs_block_bitmap block_dup_map = global_ctx->block_dup_map;
+       ext2fs_block_bitmap block_ea_map = global_ctx->block_ea_map;
+       ext2fs_block_bitmap block_metadata_map = global_ctx->block_metadata_map;
+       ext2fs_block_bitmap inodes_to_rebuild = global_ctx->inodes_to_rebuild;
+       ext2_icount_t inode_count = global_ctx->inode_count;
+       ext2_icount_t inode_link_info = global_ctx->inode_link_info;
+       __u32 fs_directory_count = global_ctx->fs_directory_count;
+       __u32 fs_regular_count = global_ctx->fs_regular_count;
+       __u32 fs_blockdev_count = global_ctx->fs_blockdev_count;
+       __u32 fs_chardev_count = global_ctx->fs_chardev_count;
+       __u32 fs_links_count = global_ctx->fs_links_count;
+       __u32 fs_symlinks_count = global_ctx->fs_symlinks_count;
+       __u32 fs_fast_symlinks_count = global_ctx->fs_fast_symlinks_count;
+       __u32 fs_fifo_count = global_ctx->fs_fifo_count;
+       __u32 fs_total_count = global_ctx->fs_total_count;
+       __u32 fs_badblocks_count = global_ctx->fs_badblocks_count;
+       __u32 fs_sockets_count = global_ctx->fs_sockets_count;
+       __u32 fs_ind_count = global_ctx->fs_ind_count;
+       __u32 fs_dind_count = global_ctx->fs_dind_count;
+       __u32 fs_tind_count = global_ctx->fs_tind_count;
+       __u32 fs_fragmented = global_ctx->fs_fragmented;
+       __u32 fs_fragmented_dir = global_ctx->fs_fragmented_dir;
+       __u32 large_files = global_ctx->large_files;
+       ext2_ino_t dx_dir_info_size = global_ctx->dx_dir_info_size;
+       ext2_ino_t dx_dir_info_count = global_ctx->dx_dir_info_count;
+       ext2_u32_list dirs_to_hash = global_ctx->dirs_to_hash;
+
 #ifdef HAVE_SETJMP_H
        jmp_buf          old_jmp;
 
@@ -2364,6 +2569,44 @@ static int e2fsck_pass1_thread_join_one(e2fsck_t global_ctx, e2fsck_t thread_ctx
 #ifdef HAVE_SETJMP_H
        memcpy(global_ctx->abort_loc, old_jmp, sizeof(jmp_buf));
 #endif
+
+       global_ctx->inode_used_map = inode_used_map;
+       global_ctx->inode_bad_map = inode_bad_map;
+       global_ctx->inode_dir_map = inode_dir_map;
+       global_ctx->inode_bb_map = inode_bb_map;
+       global_ctx->inode_imagic_map = inode_imagic_map;
+       global_ctx->inodes_to_rebuild = inodes_to_rebuild;
+       global_ctx->inode_reg_map = inode_reg_map;
+       global_ctx->block_found_map = block_found_map;
+       global_ctx->block_dup_map = block_dup_map;
+       global_ctx->block_ea_map = block_ea_map;
+       global_ctx->block_metadata_map = block_metadata_map;
+       global_ctx->dir_info = dir_info;
+       e2fsck_pass1_merge_dir_info(global_ctx, thread_ctx);
+       global_ctx->dx_dir_info = dx_dir_info;
+       global_ctx->dx_dir_info_count = dx_dir_info_count;
+       global_ctx->dx_dir_info_size = dx_dir_info_size;
+       e2fsck_pass1_merge_dx_dir(global_ctx, thread_ctx);
+       global_ctx->inode_count = inode_count;
+       global_ctx->inode_link_info = inode_link_info;
+       global_ctx->fs_directory_count += fs_directory_count;
+       global_ctx->fs_regular_count += fs_regular_count;
+       global_ctx->fs_blockdev_count += fs_blockdev_count;
+       global_ctx->fs_chardev_count += fs_chardev_count;
+       global_ctx->fs_links_count += fs_links_count;
+       global_ctx->fs_symlinks_count += fs_symlinks_count;
+       global_ctx->fs_fast_symlinks_count += fs_fast_symlinks_count;
+       global_ctx->fs_fifo_count += fs_fifo_count;
+       global_ctx->fs_total_count += fs_total_count;
+       global_ctx->fs_badblocks_count += fs_badblocks_count;
+       global_ctx->fs_sockets_count += fs_sockets_count;
+       global_ctx->fs_ind_count += fs_ind_count;
+       global_ctx->fs_dind_count += fs_dind_count;
+       global_ctx->fs_tind_count += fs_tind_count;
+       global_ctx->fs_fragmented += fs_fragmented;
+       global_ctx->fs_fragmented_dir += fs_fragmented_dir;
+       global_ctx->large_files += large_files;
+
        /* Keep the global singal flags*/
        global_ctx->flags |= (flags & E2F_FLAG_SIGNAL_MASK) |
                             (global_ctx->flags & E2F_FLAG_SIGNAL_MASK);
@@ -2378,84 +2621,77 @@ static int e2fsck_pass1_thread_join_one(e2fsck_t global_ctx, e2fsck_t thread_ctx
        global_ctx->logf = global_logf;
        global_ctx->problem_logf = global_problem_logf;
        global_ctx->global_ctx = NULL;
-
-       if (thread_ctx->inode_used_map) {
-               retval = e2fsck_pass1_copy_bitmap(global_fs,
-                                       &thread_ctx->inode_used_map,
-                                       &global_ctx->inode_used_map);
-               if (retval)
-                       return retval;
+       retval = e2fsck_pass1_merge_icounts(global_ctx, thread_ctx);
+       if (retval) {
+               com_err(global_ctx->program_name, 0,
+                       _("while merging icounts\n"));
+               return retval;
        }
-       if (thread_ctx->inode_bad_map) {
-               retval = e2fsck_pass1_copy_bitmap(global_fs,
-                                       &thread_ctx->inode_bad_map,
-                                       &global_ctx->inode_bad_map);
-               if (retval)
-                       return retval;
+
+       global_ctx->dirs_to_hash = dirs_to_hash;
+       retval = e2fsck_pass1_merge_dirs_to_hash(global_ctx, thread_ctx);
+       if (retval) {
+               com_err(global_ctx->program_name, 0,
+                       _("while merging dirs to hash\n"));
+               return retval;
        }
-       if (thread_ctx->inode_dir_map) {
-               retval = e2fsck_pass1_copy_bitmap(global_fs,
+
+       retval = e2fsck_pass1_merge_bitmap(global_fs,
+                               &thread_ctx->inode_used_map,
+                               &global_ctx->inode_used_map);
+       if (retval)
+               return retval;
+
+       retval = e2fsck_pass1_merge_bitmap(global_fs,
+                               &thread_ctx->inode_bad_map,
+                               &global_ctx->inode_bad_map);
+       if (retval)
+               return retval;
+       retval = e2fsck_pass1_merge_bitmap(global_fs,
                                        &thread_ctx->inode_dir_map,
                                        &global_ctx->inode_dir_map);
-               if (retval)
-                       return retval;
-       }
-       if (thread_ctx->inode_bb_map) {
-               retval = e2fsck_pass1_copy_bitmap(global_fs,
-                                       &thread_ctx->inode_bb_map,
-                                       &global_ctx->inode_bb_map);
-               if (retval)
-                       return retval;
-       }
-       if (thread_ctx->inode_imagic_map) {
-               retval = e2fsck_pass1_copy_bitmap(global_fs,
-                                       &thread_ctx->inode_imagic_map,
-                                       &global_ctx->inode_imagic_map);
-               if (retval)
-                       return retval;
-       }
-       if (thread_ctx->inode_reg_map) {
-               retval = e2fsck_pass1_copy_bitmap(global_fs,
-                                       &thread_ctx->inode_reg_map,
-                                       &global_ctx->inode_reg_map);
-               if (retval)
-                       return retval;
-       }
-       if (thread_ctx->inodes_to_rebuild) {
-               retval = e2fsck_pass1_copy_bitmap(global_fs,
-                                       &thread_ctx->inodes_to_rebuild,
-                                       &global_ctx->inodes_to_rebuild);
-               if (retval)
-                       return retval;
-       }
-       if (thread_ctx->block_found_map) {
-               retval = e2fsck_pass1_copy_bitmap(global_fs,
-                                       &thread_ctx->block_found_map,
-                                       &global_ctx->block_found_map);
-               if (retval)
-                       return retval;
-       }
-       if (thread_ctx->block_dup_map) {
-               retval = e2fsck_pass1_copy_bitmap(global_fs,
-                                       &thread_ctx->block_dup_map,
-                                       &global_ctx->block_dup_map);
-               if (retval)
-                       return retval;
-       }
-       if (thread_ctx->block_ea_map) {
-               retval = e2fsck_pass1_copy_bitmap(global_fs,
-                                       &thread_ctx->block_ea_map,
-                                       &global_ctx->block_ea_map);
-               if (retval)
-                       return retval;
-       }
-       if (thread_ctx->block_metadata_map) {
-               retval = e2fsck_pass1_copy_bitmap(global_fs,
-                                       &thread_ctx->block_metadata_map,
-                                       &global_ctx->block_metadata_map);
-               if (retval)
-                       return retval;
-       }
+       if (retval)
+               return retval;
+       retval = e2fsck_pass1_merge_bitmap(global_fs,
+                               &thread_ctx->inode_bb_map,
+                               &global_ctx->inode_bb_map);
+       if (retval)
+               return retval;
+       retval = e2fsck_pass1_merge_bitmap(global_fs,
+                               &thread_ctx->inode_imagic_map,
+                               &global_ctx->inode_imagic_map);
+       if (retval)
+               return retval;
+       retval = e2fsck_pass1_merge_bitmap(global_fs,
+                               &thread_ctx->inode_reg_map,
+                               &global_ctx->inode_reg_map);
+       if (retval)
+               return retval;
+       retval = e2fsck_pass1_merge_bitmap(global_fs,
+                               &thread_ctx->inodes_to_rebuild,
+                               &global_ctx->inodes_to_rebuild);
+       if (retval)
+               return retval;
+       retval = e2fsck_pass1_merge_bitmap(global_fs,
+                               &thread_ctx->block_found_map,
+                               &global_ctx->block_found_map);
+       if (retval)
+               return retval;
+       retval = e2fsck_pass1_merge_bitmap(global_fs,
+                               &thread_ctx->block_dup_map,
+                               &global_ctx->block_dup_map);
+       if (retval)
+               return retval;
+       retval = e2fsck_pass1_merge_bitmap(global_fs,
+                               &thread_ctx->block_ea_map,
+                               &global_ctx->block_ea_map);
+       if (retval)
+               return retval;
+       retval = e2fsck_pass1_merge_bitmap(global_fs,
+                               &thread_ctx->block_metadata_map,
+                               &global_ctx->block_metadata_map);
+       if (retval)
+               return retval;
 
        return 0;
 }
@@ -2472,6 +2708,22 @@ static int e2fsck_pass1_thread_join(e2fsck_t global_ctx, e2fsck_t thread_ctx)
                fputs("</problem_log>\n", thread_ctx->problem_logf);
                fclose(thread_ctx->problem_logf);
        }
+       e2fsck_pass1_free_bitmap(&thread_ctx->inode_used_map);
+       e2fsck_pass1_free_bitmap(&thread_ctx->inode_bad_map);
+       e2fsck_pass1_free_bitmap(&thread_ctx->inode_dir_map);
+       e2fsck_pass1_free_bitmap(&thread_ctx->inode_bb_map);
+       e2fsck_pass1_free_bitmap(&thread_ctx->inode_imagic_map);
+       e2fsck_pass1_free_bitmap(&thread_ctx->inode_reg_map);
+       e2fsck_pass1_free_bitmap(&thread_ctx->inodes_to_rebuild);
+       e2fsck_pass1_free_bitmap(&thread_ctx->block_found_map);
+       e2fsck_pass1_free_bitmap(&thread_ctx->block_dup_map);
+       e2fsck_pass1_free_bitmap(&thread_ctx->block_ea_map);
+       e2fsck_pass1_free_bitmap(&thread_ctx->block_metadata_map);
+       e2fsck_free_dir_info(thread_ctx);
+       ext2fs_free_icount(thread_ctx->inode_count);
+       ext2fs_free_icount(thread_ctx->inode_link_info);
+       if (thread_ctx->dirs_to_hash)
+               ext2fs_badblocks_list_free(thread_ctx->dirs_to_hash);
        ext2fs_free_mem(&thread_ctx);
 
        return retval;
@@ -2498,7 +2750,13 @@ static int e2fsck_pass1_threads_join(struct e2fsck_thread_info *infos,
                        if (ret == 0)
                                ret = rc;
                }
-               e2fsck_pass1_thread_join(global_ctx, infos[i].eti_thread_ctx);
+               rc = e2fsck_pass1_thread_join(global_ctx, infos[i].eti_thread_ctx);
+               if (rc) {
+                       com_err(global_ctx->program_name, rc,
+                               _("while joining pass1 thread\n"));
+                       if (ret == 0)
+                               ret = rc;
+               }
        }
        free(infos);
 
@@ -2509,6 +2767,18 @@ static void *e2fsck_pass1_thread(void *arg)
 {
        struct e2fsck_thread_info       *info = arg;
        e2fsck_t                         thread_ctx = info->eti_thread_ctx;
+#ifdef DEBUG_THREADS
+       struct e2fsck_thread_debug      *thread_debug = info->eti_debug;
+#endif
+
+#ifdef DEBUG_THREADS
+       pthread_mutex_lock(&thread_debug->etd_mutex);
+       while (info->eti_thread_index > thread_debug->etd_finished_threads) {
+               pthread_cond_wait(&thread_debug->etd_cond,
+                                 &thread_debug->etd_mutex);
+       }
+       pthread_mutex_unlock(&thread_debug->etd_mutex);
+#endif
 
 #ifdef HAVE_SETJMP_H
        /*
@@ -2533,6 +2803,14 @@ out:
                        thread_ctx->thread_info.et_group_start,
                        thread_ctx->thread_info.et_group_end,
                        thread_ctx->thread_info.et_inode_number);
+
+#ifdef DEBUG_THREADS
+       pthread_mutex_lock(&thread_debug->etd_mutex);
+       thread_debug->etd_finished_threads++;
+       pthread_cond_broadcast(&thread_debug->etd_cond);
+       pthread_mutex_unlock(&thread_debug->etd_mutex);
+#endif
+
        return NULL;
 }
 
@@ -2546,6 +2824,12 @@ static int e2fsck_pass1_threads_start(struct e2fsck_thread_info **pinfo,
        struct e2fsck_thread_info       *tmp_pinfo;
        int                              i;
        e2fsck_t                         thread_ctx;
+#ifdef DEBUG_THREADS
+       struct e2fsck_thread_debug       thread_debug =
+               {PTHREAD_MUTEX_INITIALIZER, PTHREAD_COND_INITIALIZER, 0};
+
+       thread_debug.etd_finished_threads = 0;
+#endif
 
        retval = pthread_attr_init(&attr);
        if (retval) {
@@ -2566,6 +2850,9 @@ static int e2fsck_pass1_threads_start(struct e2fsck_thread_info **pinfo,
        for (i = 0; i < num_threads; i++) {
                tmp_pinfo = &infos[i];
                tmp_pinfo->eti_thread_index = i;
+#ifdef DEBUG_THREADS
+               tmp_pinfo->eti_debug = &thread_debug;
+#endif
                retval = e2fsck_pass1_thread_prepare(global_ctx, &thread_ctx,
                                                     i, num_threads);
                if (retval) {
@@ -2630,14 +2917,48 @@ out_abort:
 }
 #endif
 
+/* TODO: tdb needs to be handled properly for multiple threads*/
+static int multiple_threads_supported(e2fsck_t ctx)
+{
+#ifdef CONFIG_TDB
+       unsigned int            threshold;
+       ext2_ino_t              num_dirs;
+       errcode_t               retval;
+       char                    *tdb_dir;
+       int                     enable;
+
+       profile_get_string(ctx->profile, "scratch_files", "directory", 0, 0,
+                          &tdb_dir);
+       profile_get_uint(ctx->profile, "scratch_files",
+                        "numdirs_threshold", 0, 0, &threshold);
+       profile_get_boolean(ctx->profile, "scratch_files",
+                           "icount", 0, 1, &enable);
+
+       retval = ext2fs_get_num_dirs(ctx->fs, &num_dirs);
+       if (retval)
+               num_dirs = 1024;        /* Guess */
+
+       /* tdb is unsupported now */
+       if (enable && tdb_dir && !access(tdb_dir, W_OK) &&
+           (!threshold || num_dirs > threshold))
+               return 0;
+ #endif
+       return 1;
+}
+
 void e2fsck_pass1(e2fsck_t ctx)
 {
 
+       init_ext2_max_sizes();
 #ifdef HAVE_PTHREAD
-       e2fsck_pass1_multithread(ctx);
-#else
-       e2fsck_pass1_run(ctx);
+       if (multiple_threads_supported(ctx)) {
+               e2fsck_pass1_multithread(ctx);
+               return;
+       }
+       fprintf(stderr, "Fall through single thread for pass1 "
+                       "because tdb could not handle properly\n");
 #endif
+       e2fsck_pass1_run(ctx);
 }
 
 #undef FINISH_INODE_LOOP
@@ -2657,7 +2978,9 @@ static errcode_t scan_callback(ext2_filsys fs,
        scan_struct = (struct scan_callback_struct *) priv_data;
        ctx = scan_struct->ctx;
 
-       process_inodes((e2fsck_t) fs->priv_data, scan_struct->block_buf);
+       process_inodes((e2fsck_t) fs->priv_data, scan_struct->block_buf,
+                      scan_struct->inodes_to_process,
+                      scan_struct->process_inode_count);
 
        if (ctx->progress)
                if ((ctx->progress)(ctx, 1, group+1,
@@ -2683,7 +3006,9 @@ static errcode_t scan_callback(ext2_filsys fs,
 /*
  * Process the inodes in the "inodes to process" list.
  */
-static void process_inodes(e2fsck_t ctx, char *block_buf)
+static void process_inodes(e2fsck_t ctx, char *block_buf,
+                          struct process_inode_block *inodes_to_process,
+                          int *process_inode_count)
 {
        int                     i;
        struct ext2_inode       *old_stashed_inode;
@@ -2695,15 +3020,15 @@ static void process_inodes(e2fsck_t ctx, char *block_buf)
 #if 0
        printf("begin process_inodes: ");
 #endif
-       if (process_inode_count == 0)
+       if (*process_inode_count == 0)
                return;
        old_operation = ehandler_operation(0);
        old_stashed_inode = ctx->stashed_inode;
        old_stashed_ino = ctx->stashed_ino;
-       qsort(inodes_to_process, process_inode_count,
+       qsort(inodes_to_process, *process_inode_count,
                      sizeof(struct process_inode_block), process_inode_cmp);
        clear_problem_context(&pctx);
-       for (i=0; i < process_inode_count; i++) {
+       for (i=0; i < *process_inode_count; i++) {
                pctx.inode = ctx->stashed_inode =
                        (struct ext2_inode *) &inodes_to_process[i].inode;
                pctx.ino = ctx->stashed_ino = inodes_to_process[i].ino;
@@ -2721,7 +3046,7 @@ static void process_inodes(e2fsck_t ctx, char *block_buf)
        }
        ctx->stashed_inode = old_stashed_inode;
        ctx->stashed_ino = old_stashed_ino;
-       process_inode_count = 0;
+       *process_inode_count = 0;
 #if 0
        printf("end process inodes\n");
 #endif