Whamcloud - gitweb
e2fsck: merge dirs_to_hash when threads finish
[tools/e2fsprogs.git] / e2fsck / pass1.c
index 94b0a96..922de3d 100644 (file)
@@ -2278,12 +2278,16 @@ static int e2fsck_pass1_merge_fs(ext2_filsys dest, ext2_filsys src)
        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;
@@ -2292,8 +2296,12 @@ static int e2fsck_pass1_merge_fs(ext2_filsys dest, ext2_filsys src)
        dest->inode_map = inode_map;
        dest->block_map = block_map;
        dest->badblocks = badblocks;
+       dest->dblist = dblist;
        if (dest->dblist)
                dest->dblist->fs = dest;
+       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);
@@ -2310,6 +2318,19 @@ static int e2fsck_pass1_merge_fs(ext2_filsys dest, ext2_filsys src)
        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,
@@ -2326,6 +2347,9 @@ out:
                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;
 }
 
@@ -2422,6 +2446,76 @@ static void e2fsck_pass1_merge_dir_info(e2fsck_t global_ctx, e2fsck_t thread_ctx
                              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;
@@ -2432,6 +2526,7 @@ static int e2fsck_pass1_thread_join_one(e2fsck_t global_ctx, e2fsck_t thread_ctx
        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;
@@ -2442,6 +2537,28 @@ static int e2fsck_pass1_thread_join_one(e2fsck_t global_ctx, e2fsck_t thread_ctx
        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;
@@ -2466,6 +2583,29 @@ static int e2fsck_pass1_thread_join_one(e2fsck_t global_ctx, e2fsck_t thread_ctx
        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) |
@@ -2481,6 +2621,20 @@ 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;
+       retval = e2fsck_pass1_merge_icounts(global_ctx, thread_ctx);
+       if (retval) {
+               com_err(global_ctx->program_name, 0,
+                       _("while merging icounts\n"));
+               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;
+       }
 
        retval = e2fsck_pass1_merge_bitmap(global_fs,
                                &thread_ctx->inode_used_map,
@@ -2566,6 +2720,10 @@ static int e2fsck_pass1_thread_join(e2fsck_t global_ctx, e2fsck_t thread_ctx)
        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;
@@ -2609,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
        /*
@@ -2633,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;
 }
 
@@ -2646,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) {
@@ -2666,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) {