#define FINISH_INODE_LOOP(ctx, ino, pctx, failed_csum) \
do { \
finish_processing_inode((ctx), (ino), (pctx), (failed_csum)); \
- if ((ctx)->flags & E2F_FLAG_ABORT) \
+ if ((ctx)->flags & E2F_FLAG_ABORT) { \
+ e2fsck_pass1_check_unlock(ctx); \
return; \
+ } \
} while (0)
static int could_be_block_map(ext2_filsys fs, struct ext2_inode *inode)
static void pass1_readahead(e2fsck_t ctx, dgrp_t *group, ext2_ino_t *next_ino)
{
ext2_ino_t inodes_in_group = 0, inodes_per_block, inodes_per_buffer;
- dgrp_t start = *group, grp;
+ dgrp_t start = *group, grp, grp_end = ctx->fs->group_desc_count;
blk64_t blocks_to_read = 0;
errcode_t err = EXT2_ET_INVALID_ARGUMENT;
+#ifdef HAVE_PTHREAD
+ if (ctx->fs->fs_num_threads > 1)
+ grp_end = ctx->thread_info.et_group_end;
+#endif
if (ctx->readahead_kb == 0)
goto out;
/* Keep iterating groups until we have enough to readahead */
inodes_per_block = EXT2_INODES_PER_BLOCK(ctx->fs->super);
- for (grp = start; grp < ctx->fs->group_desc_count; grp++) {
+ for (grp = start; grp < grp_end; grp++) {
if (ext2fs_bg_flags_test(ctx->fs, grp, EXT2_BG_INODE_UNINIT))
continue;
inodes_in_group = ctx->fs->super->s_inodes_per_group -
}
out:
ctx->fs_num_threads = num_threads;
+ ctx->fs->fs_num_threads = num_threads;
}
#endif
{
struct problem_context pctx;
ext2_filsys fs = ctx->fs;
+ unsigned long long readahead_kb;
init_ext2_max_sizes();
-#ifdef HAVE_PTHREAD
+#ifdef HAVE_PTHREAD
e2fsck_pass1_set_thread_num(ctx);
#endif
+ /* If we can do readahead, figure out how many groups to pull in. */
+ if (!e2fsck_can_readahead(ctx->fs))
+ ctx->readahead_kb = 0;
+ else if (ctx->readahead_kb == ~0ULL)
+ ctx->readahead_kb = e2fsck_guess_readahead(ctx->fs);
+#ifdef HAVE_PTHREAD
+ /* don't use more than 1/10 of memory for threads checking */
+ readahead_kb = get_memory_size() / (10 * ctx->fs_num_threads);
+ /* maybe better disable RA if this is too small? */
+ if (ctx->readahead_kb > readahead_kb)
+ ctx->readahead_kb = readahead_kb;
+#endif
clear_problem_context(&pctx);
if (!(ctx->options & E2F_OPT_PREEN))
fix_problem(ctx, PR_1_PASS_HEADER, &pctx);
ext2fs_mark_block_bitmap2(ctx->block_found_map,
fs->super->s_mmp_block);
#ifdef HAVE_PTHREAD
- pthread_mutex_init(&ctx->fs_fix_mutex, NULL);
+ pthread_rwlock_init(&ctx->fs_fix_rwlock, NULL);
pthread_rwlock_init(&ctx->fs_block_map_rwlock, NULL);
+ if (ctx->fs_num_threads > 1)
+ ctx->fs_need_locking = 1;
#endif
return 0;
{
struct problem_context pctx;
ext2_filsys fs = ctx->fs;
+ char *block_buf;
+
+ if (e2fsck_should_abort(ctx))
+ return;
- char *block_buf =
- (char *)e2fsck_allocate_memory(ctx, ctx->fs->blocksize * 3,
+ block_buf = (char *)e2fsck_allocate_memory(ctx, ctx->fs->blocksize * 3,
"block interate buffer");
reserve_block_for_root_repair(ctx);
reserve_block_for_lnf_repair(ctx);
ext2fs_free_mem(&block_buf);
ctx->flags &= ~E2F_FLAG_DUP_BLOCK;
}
+
+ ctx->flags |= E2F_FLAG_ALLOC_OK;
}
dgrp_t ra_group = 0;
struct ea_quota ea_ibody_quota;
struct process_inode_block *inodes_to_process;
- int process_inode_count;
+ int process_inode_count, check_mmp;
+ e2fsck_t global_ctx = ctx->global_ctx ? ctx->global_ctx : ctx;
init_resource_track(&rtrack, ctx->fs->io);
clear_problem_context(&pctx);
- /* If we can do readahead, figure out how many groups to pull in. */
- if (!e2fsck_can_readahead(ctx->fs))
- ctx->readahead_kb = 0;
- else if (ctx->readahead_kb == ~0ULL)
- ctx->readahead_kb = e2fsck_guess_readahead(ctx->fs);
pass1_readahead(ctx, &ra_group, &ino_threshold);
-
if (ext2fs_has_feature_dir_index(fs->super) &&
!(ctx->options & E2F_OPT_NO)) {
if (ext2fs_u32_list_create(&ctx->dirs_to_hash, 50))
#endif
while (1) {
- if (ino % (fs->super->s_inodes_per_group * 4) == 1) {
+ check_mmp = 0;
+ e2fsck_pass1_check_lock(ctx);
+#ifdef HAVE_PTHREAD
+ if (!global_ctx->mmp_update_thread) {
+ e2fsck_pass1_block_map_w_lock(ctx);
+ if (!global_ctx->mmp_update_thread) {
+ global_ctx->mmp_update_thread =
+ ctx->thread_info.et_thread_index + 1;
+ check_mmp = 1;
+ }
+ e2fsck_pass1_block_map_w_unlock(ctx);
+ }
+
+ /* only one active thread could update mmp block. */
+ e2fsck_pass1_block_map_r_lock(ctx);
+ if (global_ctx->mmp_update_thread ==
+ ctx->thread_info.et_thread_index + 1)
+ check_mmp = 1;
+ e2fsck_pass1_block_map_r_unlock(ctx);
+#else
+ check_mmp = 1;
+#endif
+
+ if (check_mmp && (ino % (fs->super->s_inodes_per_group * 4) == 1)) {
if (e2fsck_mmp_update(fs))
fatal_error(ctx, 0);
}
if (ino > ino_threshold)
pass1_readahead(ctx, &ra_group, &ino_threshold);
ehandler_operation(old_op);
- if (e2fsck_should_abort(ctx))
+ if (e2fsck_should_abort(ctx)) {
+ e2fsck_pass1_check_unlock(ctx);
goto endit;
+ }
if (pctx.errcode == EXT2_ET_BAD_BLOCK_IN_INODE_TABLE) {
/*
* If badblocks says badblocks is bad, offer to clear
fix_problem(ctx, PR_1_ISCAN_ERROR,
&pctx);
ctx->flags |= E2F_FLAG_ABORT;
+ e2fsck_pass1_check_unlock(ctx);
+ goto endit;
} else
ctx->flags |= E2F_FLAG_RESTART;
- goto endit;
+ err = ext2fs_inode_scan_goto_blockgroup(scan,
+ 0);
+ if (err) {
+ fix_problem(ctx, PR_1_ISCAN_ERROR,
+ &pctx);
+ ctx->flags |= E2F_FLAG_ABORT;
+ e2fsck_pass1_check_unlock(ctx);
+ goto endit;
+ }
+ e2fsck_pass1_check_unlock(ctx);
+ continue;
}
if (!ctx->inode_bb_map)
alloc_bb_map(ctx);
ext2fs_mark_inode_bitmap2(ctx->inode_bb_map, ino);
ext2fs_mark_inode_bitmap2(ctx->inode_used_map, ino);
+ e2fsck_pass1_check_unlock(ctx);
continue;
}
- if (pctx.errcode == EXT2_ET_SCAN_FINISHED)
+ if (pctx.errcode == EXT2_ET_SCAN_FINISHED) {
+ e2fsck_pass1_check_unlock(ctx);
break;
+ }
if (pctx.errcode &&
pctx.errcode != EXT2_ET_INODE_CSUM_INVALID &&
pctx.errcode != EXT2_ET_INODE_IS_GARBAGE) {
fix_problem(ctx, PR_1_ISCAN_ERROR, &pctx);
ctx->flags |= E2F_FLAG_ABORT;
+ e2fsck_pass1_check_unlock(ctx);
goto endit;
}
- if (!ino)
+ if (!ino) {
+ e2fsck_pass1_check_unlock(ctx);
break;
+ }
#ifdef HAVE_PTHREAD
if (ctx->global_ctx)
ctx->thread_info.et_inode_number++;
pctx.num = inode->i_links_count;
fix_problem(ctx, PR_1_ICOUNT_STORE, &pctx);
ctx->flags |= E2F_FLAG_ABORT;
+ e2fsck_pass1_check_unlock(ctx);
goto endit;
}
} else if ((ino >= EXT2_FIRST_INODE(fs->super)) &&
}
}
FINISH_INODE_LOOP(ctx, ino, &pctx, failed_csum);
+ e2fsck_pass1_check_unlock(ctx);
continue;
}
&pctx);
if (res < 0) {
/* skip FINISH_INODE_LOOP */
+ e2fsck_pass1_check_unlock(ctx);
continue;
}
}
} else if (fix_problem(ctx, PR_1_INLINE_DATA_SET, &pctx)) {
e2fsck_clear_inode(ctx, ino, inode, 0, "pass1");
/* skip FINISH_INODE_LOOP */
+ e2fsck_pass1_check_unlock(ctx);
continue;
}
}
if (err) {
pctx.errcode = err;
ctx->flags |= E2F_FLAG_ABORT;
+ e2fsck_pass1_check_unlock(ctx);
goto endit;
}
inode->i_flags &= ~EXT4_INLINE_DATA_FL;
/* Some other kind of non-xattr error? */
pctx.errcode = err;
ctx->flags |= E2F_FLAG_ABORT;
+ e2fsck_pass1_check_unlock(ctx);
goto endit;
}
}
ext2fs_mark_inode_bitmap2(ctx->inode_used_map,
ino);
/* skip FINISH_INODE_LOOP */
+ e2fsck_pass1_check_unlock(ctx);
continue;
}
}
pctx.num = 4;
fix_problem(ctx, PR_1_ALLOCATE_BBITMAP_ERROR, &pctx);
ctx->flags |= E2F_FLAG_ABORT;
+ e2fsck_pass1_check_unlock(ctx);
goto endit;
}
pb.ino = EXT2_BAD_INO;
if (pctx.errcode) {
fix_problem(ctx, PR_1_BLOCK_ITERATE, &pctx);
ctx->flags |= E2F_FLAG_ABORT;
+ e2fsck_pass1_check_unlock(ctx);
goto endit;
}
if (pb.bbcheck)
if (!fix_problem(ctx, PR_1_BBINODE_BAD_METABLOCK_PROMPT, &pctx)) {
ctx->flags |= E2F_FLAG_ABORT;
+ e2fsck_pass1_check_unlock(ctx);
goto endit;
}
ext2fs_mark_inode_bitmap2(ctx->inode_used_map, ino);
clear_problem_context(&pctx);
FINISH_INODE_LOOP(ctx, ino, &pctx, failed_csum);
+ e2fsck_pass1_check_unlock(ctx);
continue;
} else if (ino == EXT2_ROOT_INO) {
/*
}
check_blocks(ctx, &pctx, block_buf, NULL);
FINISH_INODE_LOOP(ctx, ino, &pctx, failed_csum);
+ e2fsck_pass1_check_unlock(ctx);
continue;
}
if ((inode->i_links_count ||
}
check_blocks(ctx, &pctx, block_buf, NULL);
FINISH_INODE_LOOP(ctx, ino, &pctx, failed_csum);
+ e2fsck_pass1_check_unlock(ctx);
continue;
}
if ((inode->i_links_count ||
}
check_blocks(ctx, &pctx, block_buf, NULL);
FINISH_INODE_LOOP(ctx, ino, &pctx, failed_csum);
+ e2fsck_pass1_check_unlock(ctx);
continue;
}
if (!inode->i_links_count) {
FINISH_INODE_LOOP(ctx, ino, &pctx, failed_csum);
+ e2fsck_pass1_check_unlock(ctx);
continue;
}
/*
ctx->fs_symlinks_count++;
if (inode->i_flags & EXT4_INLINE_DATA_FL) {
FINISH_INODE_LOOP(ctx, ino, &pctx, failed_csum);
+ e2fsck_pass1_check_unlock(ctx);
continue;
} else if (ext2fs_is_fast_symlink(inode)) {
ctx->fs_fast_symlinks_count++;
check_blocks(ctx, &pctx, block_buf,
&ea_ibody_quota);
FINISH_INODE_LOOP(ctx, ino, &pctx, failed_csum);
+ e2fsck_pass1_check_unlock(ctx);
continue;
}
}
FINISH_INODE_LOOP(ctx, ino, &pctx, failed_csum);
- if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
+ if (e2fsck_should_abort(ctx)) {
+ e2fsck_pass1_check_unlock(ctx);
goto endit;
+ }
if (process_inode_count >= ctx->process_inode_size) {
process_inodes(ctx, block_buf, inodes_to_process,
&process_inode_count);
- if (e2fsck_should_abort(ctx))
+ if (e2fsck_should_abort(ctx)) {
+ e2fsck_pass1_check_unlock(ctx);
goto endit;
+ }
}
+ e2fsck_pass1_check_unlock(ctx);
}
process_inodes(ctx, block_buf, inodes_to_process,
&process_inode_count);
}
ctx->flags |= E2F_FLAG_ALLOC_OK;
+ ext2fs_free_mem(&inodes_to_process);
endit:
e2fsck_use_inode_shortcuts(ctx, 0);
ext2fs_free_mem(&inodes_to_process);
print_resource_track(ctx, _("Pass 1"), &rtrack, ctx->fs->io);
else
ctx->invalid_bitmaps++;
+#ifdef HAVE_PTHREAD
+ /* reset update_thread after this thread exit */
+ e2fsck_pass1_block_map_w_lock(ctx);
+ if (check_mmp)
+ global_ctx->mmp_update_thread = 0;
+ e2fsck_pass1_block_map_w_unlock(ctx);
+#endif
}
#ifdef HAVE_PTHREAD
ext2_badblocks_list badblocks;
ext2_dblist dblist;
int flags;
+ e2fsck_t dest_ctx = dest->priv_data;
dest_io = dest->io;
dest_image_io = dest->image_io;
dest->block_map = block_map;
dest->badblocks = badblocks;
dest->dblist = dblist;
+ dest->priv_data = dest_ctx;
if (dest->dblist)
dest->dblist->fs = dest;
dest->flags = src->flags | flags;
}
static errcode_t e2fsck_pass1_thread_prepare(e2fsck_t global_ctx, e2fsck_t *thread_ctx,
- int thread_index, int num_threads)
+ int thread_index, int num_threads,
+ dgrp_t average_group)
{
errcode_t retval;
e2fsck_t thread_context;
ext2_filsys thread_fs;
ext2_filsys global_fs = global_ctx->fs;
struct e2fsck_thread *tinfo;
- dgrp_t average_group;
assert(global_ctx->inode_used_map == NULL);
assert(global_ctx->inode_dir_map == NULL);
}
memcpy(thread_context, global_ctx, sizeof(struct e2fsck_struct));
thread_context->block_dup_map = NULL;
+ thread_context->casefolded_dirs = NULL;
retval = e2fsck_allocate_block_bitmap(global_ctx->fs,
_("in-use block map"), EXT2FS_BMAP64_RBTREE,
thread_context->thread_info.et_thread_index = thread_index;
set_up_logging(thread_context);
- /*
- * Distribute work to multiple threads:
- * Each thread work on fs->group_desc_count / nthread groups.
- */
tinfo = &thread_context->thread_info;
- average_group = thread_fs->group_desc_count / num_threads;
- if (average_group == 0)
- average_group = 1;
tinfo->et_group_start = average_group * thread_index;
- if (thread_index == num_threads - 1)
+ if (thread_index == global_fs->fs_num_threads - 1)
tinfo->et_group_end = thread_fs->group_desc_count;
else
tinfo->et_group_end = average_group * (thread_index + 1);
return retval;
}
-static int e2fsck_pass1_thread_join_one(e2fsck_t global_ctx, e2fsck_t thread_ctx)
+static errcode_t e2fsck_pass1_merge_casefolded_dirs(e2fsck_t global_ctx,
+ e2fsck_t thread_ctx)
{
- errcode_t retval;
- int flags = global_ctx->flags;
- ext2_filsys thread_fs = thread_ctx->fs;
- 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 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;
- quota_ctx_t qctx = global_ctx->qctx;
- int *invalid_block_bitmap_flag = global_ctx->invalid_block_bitmap_flag;
- int *invalid_inode_bitmap_flag = global_ctx->invalid_inode_bitmap_flag;
- int *invalid_inode_table_flag = global_ctx->invalid_inode_table_flag;
- int invalid_bitmaps = global_ctx->invalid_bitmaps;
- ext2_refcount_t refcount = global_ctx->refcount;
- ext2_refcount_t refcount_extra = global_ctx->refcount_extra;
- ext2_refcount_t refcount_orig = global_ctx->refcount_orig;
- ext2_refcount_t ea_block_quota_blocks = global_ctx->ea_block_quota_blocks;
- ext2_refcount_t ea_block_quota_inodes = global_ctx->ea_block_quota_inodes;
- ext2fs_block_bitmap block_ea_map = global_ctx->block_ea_map;
- ext2_refcount_t ea_inode_refs = global_ctx->ea_inode_refs;
- ext2fs_block_bitmap block_found_map = global_ctx->block_found_map;
- ext2fs_block_bitmap block_dup_map = global_ctx->block_dup_map;
+ errcode_t retval = 0;
-#ifdef HAVE_SETJMP_H
- jmp_buf old_jmp;
+ if (!thread_ctx->casefolded_dirs)
+ return 0;
- memcpy(old_jmp, global_ctx->abort_loc, sizeof(jmp_buf));
-#endif
- memcpy(global_ctx, thread_ctx, sizeof(struct e2fsck_struct));
-#ifdef HAVE_SETJMP_H
- memcpy(global_ctx->abort_loc, old_jmp, sizeof(jmp_buf));
-#endif
+ if (!global_ctx->casefolded_dirs)
+ retval = ext2fs_badblocks_copy(thread_ctx->casefolded_dirs,
+ &global_ctx->casefolded_dirs);
+ else
+ retval = ext2fs_badblocks_merge(thread_ctx->casefolded_dirs,
+ global_ctx->casefolded_dirs);
+
+ return retval;
+}
+
+static errcode_t e2fsck_pass1_merge_context(e2fsck_t global_ctx,
+ e2fsck_t thread_ctx)
+{
+ ext2_filsys global_fs = global_ctx->fs;
+ errcode_t retval;
+ int i;
+
+ global_ctx->fs_directory_count += thread_ctx->fs_directory_count;
+ global_ctx->fs_regular_count += thread_ctx->fs_regular_count;
+ global_ctx->fs_blockdev_count += thread_ctx->fs_blockdev_count;
+ global_ctx->fs_chardev_count += thread_ctx->fs_chardev_count;
+ global_ctx->fs_links_count += thread_ctx->fs_links_count;
+ global_ctx->fs_symlinks_count += thread_ctx->fs_symlinks_count;
+ global_ctx->fs_fast_symlinks_count += thread_ctx->fs_fast_symlinks_count;
+ global_ctx->fs_fifo_count += thread_ctx->fs_fifo_count;
+ global_ctx->fs_total_count += thread_ctx->fs_total_count;
+ global_ctx->fs_badblocks_count += thread_ctx->fs_badblocks_count;
+ global_ctx->fs_sockets_count += thread_ctx->fs_sockets_count;
+ global_ctx->fs_ind_count += thread_ctx->fs_ind_count;
+ global_ctx->fs_dind_count += thread_ctx->fs_dind_count;
+ global_ctx->fs_tind_count += thread_ctx->fs_tind_count;
+ global_ctx->fs_fragmented += thread_ctx->fs_fragmented;
+ global_ctx->fs_fragmented_dir += thread_ctx->fs_fragmented_dir;
+ global_ctx->large_files += thread_ctx->large_files;
+ /* threads might enable E2F_OPT_YES */
+ global_ctx->options |= thread_ctx->options;
+ global_ctx->flags |= thread_ctx->flags;
+ /*
+ * The l+f inode may have been cleared, so zap it now and
+ * later passes will recalculate it if necessary
+ */
+ global_ctx->lost_and_found = 0;
+ /* merge extent depth count */
+ for (i = 0; i < MAX_EXTENT_DEPTH_COUNT; i++)
+ global_ctx->extent_depth_count[i] +=
+ thread_ctx->extent_depth_count[i];
- 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_dup_map = block_dup_map;
- global_ctx->block_found_map = block_found_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->refcount = refcount;
- global_ctx->refcount_extra = refcount_extra;
- global_ctx->refcount_orig = refcount_orig;
- global_ctx->ea_block_quota_blocks = ea_block_quota_blocks;
- global_ctx->ea_block_quota_inodes = ea_block_quota_inodes;
- global_ctx->block_ea_map = block_ea_map;
- global_ctx->ea_inode_refs = ea_inode_refs;
- 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;
-
- global_ctx->flags |= flags;
-
- retval = e2fsck_pass1_merge_fs(global_fs, thread_fs);
+
+ retval = e2fsck_pass1_merge_fs(global_ctx->fs, thread_ctx->fs);
if (retval) {
com_err(global_ctx->program_name, 0, _("while merging fs\n"));
return retval;
}
- global_fs->priv_data = global_ctx;
- global_ctx->fs = global_fs;
- 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,
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,
e2fsck_pass1_merge_ea_inode_refs(global_ctx, thread_ctx);
e2fsck_pass1_merge_ea_refcount(global_ctx, thread_ctx);
- global_ctx->qctx = qctx;
retval = quota_merge_and_update_usage(global_ctx->qctx,
thread_ctx->qctx);
if (retval)
return retval;
- global_ctx->invalid_block_bitmap_flag = invalid_block_bitmap_flag;
- global_ctx->invalid_inode_bitmap_flag = invalid_inode_bitmap_flag;
- global_ctx->invalid_inode_table_flag = invalid_inode_table_flag;
- global_ctx->invalid_bitmaps = invalid_bitmaps;
+
+ retval = e2fsck_pass1_merge_casefolded_dirs(global_ctx, thread_ctx);
+ if (retval) {
+ com_err(global_ctx->program_name, 0,
+ _("while merging casefolded dirs\n"));
+ return retval;
+ }
+
e2fsck_pass1_merge_invalid_bitmaps(global_ctx, thread_ctx);
retval = e2fsck_pass1_merge_bitmap(global_fs,
{
errcode_t retval;
- retval = e2fsck_pass1_thread_join_one(global_ctx, thread_ctx);
+ retval = e2fsck_pass1_merge_context(global_ctx, thread_ctx);
ext2fs_free_mem(&thread_ctx->fs);
if (thread_ctx->logf)
fclose(thread_ctx->logf);
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_ea_map);
- if (thread_ctx->refcount)
- ea_refcount_free(thread_ctx->refcount);
- if (thread_ctx->refcount_extra)
- ea_refcount_free(thread_ctx->refcount_extra);
- if (thread_ctx->ea_inode_refs)
- ea_refcount_free(thread_ctx->ea_inode_refs);
- if (thread_ctx->refcount_orig)
- ea_refcount_free(thread_ctx->refcount_orig);
- 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);
- quota_release_context(&thread_ctx->qctx);
- ext2fs_free_mem(&thread_ctx->invalid_block_bitmap_flag);
- ext2fs_free_mem(&thread_ctx->invalid_inode_bitmap_flag);
- ext2fs_free_mem(&thread_ctx->invalid_inode_table_flag);
+
+ /*
+ * @block_metadata_map and @block_dup_map are
+ * shared, so we don't free them.
+ */
+ thread_ctx->block_metadata_map = NULL;
+ thread_ctx->block_dup_map = NULL;
+ e2fsck_reset_context(thread_ctx);
ext2fs_free_mem(&thread_ctx);
return retval;
}
static int e2fsck_pass1_threads_join(struct e2fsck_thread_info *infos,
- int num_threads, e2fsck_t global_ctx)
+ e2fsck_t global_ctx)
{
errcode_t rc;
errcode_t ret = 0;
int i;
struct e2fsck_thread_info *pinfo;
+ int num_threads = global_ctx->fs_num_threads;
/* merge invalid bitmaps will recalculate it */
global_ctx->invalid_bitmaps = 0;
return NULL;
}
+static dgrp_t ext2fs_get_avg_group(ext2_filsys fs)
+{
+#ifdef HAVE_PTHREAD
+ dgrp_t average_group;
+ unsigned flexbg_size;
+
+ if (fs->fs_num_threads <= 1)
+ return fs->group_desc_count;
+
+ average_group = fs->group_desc_count / fs->fs_num_threads;
+ if (average_group <= 1)
+ return 1;
+
+ if (ext2fs_has_feature_flex_bg(fs->super)) {
+ int times = 1;
+
+ flexbg_size = 1 << fs->super->s_log_groups_per_flex;
+ if (average_group % flexbg_size) {
+ times = average_group / flexbg_size;
+ average_group = times * flexbg_size;
+ }
+ }
+
+ return average_group;
+#else
+ return fs->group_desc_count;
+#endif
+}
+
static int e2fsck_pass1_threads_start(struct e2fsck_thread_info **pinfo,
- int num_threads, e2fsck_t global_ctx)
+ e2fsck_t global_ctx)
{
struct e2fsck_thread_info *infos;
pthread_attr_t attr;
struct e2fsck_thread_info *tmp_pinfo;
int i;
e2fsck_t thread_ctx;
+ dgrp_t average_group;
+ int num_threads = global_ctx->fs_num_threads;
#ifdef DEBUG_THREADS
struct e2fsck_thread_debug thread_debug =
{PTHREAD_MUTEX_INITIALIZER, PTHREAD_COND_INITIALIZER, 0};
return retval;
}
+ average_group = ext2fs_get_avg_group(global_ctx->fs);
for (i = 0; i < num_threads; i++) {
tmp_pinfo = &infos[i];
tmp_pinfo->eti_thread_index = i;
tmp_pinfo->eti_debug = &thread_debug;
#endif
retval = e2fsck_pass1_thread_prepare(global_ctx, &thread_ctx,
- i, num_threads);
+ i, num_threads,
+ average_group);
if (retval) {
com_err(global_ctx->program_name, retval,
_("while preparing pass1 thread\n"));
}
if (retval) {
- e2fsck_pass1_threads_join(infos, num_threads, global_ctx);
+ e2fsck_pass1_threads_join(infos, global_ctx);
return retval;
}
*pinfo = infos;
static void e2fsck_pass1_multithread(e2fsck_t global_ctx)
{
struct e2fsck_thread_info *infos = NULL;
- int num_threads = global_ctx->fs_num_threads;
errcode_t retval;
- retval = e2fsck_pass1_threads_start(&infos, num_threads, global_ctx);
+ retval = e2fsck_pass1_threads_start(&infos, global_ctx);
if (retval) {
com_err(global_ctx->program_name, retval,
_("while starting pass1 threads\n"));
goto out_abort;
}
- retval = e2fsck_pass1_threads_join(infos, num_threads, global_ctx);
+ retval = e2fsck_pass1_threads_join(infos, global_ctx);
if (retval) {
com_err(global_ctx->program_name, retval,
_("while joining pass1 threads\n"));
need_single = 0;
e2fsck_pass1_multithread(ctx);
}
+ /* No lock is needed at this time */
+ ctx->fs_need_locking = 0;
#endif
if (need_single)
e2fsck_pass1_run(ctx);