@@ -261,6 +261,22 @@ struct e2fsck_fc_replay_state {
__u16 fc_super_state;
};
+#ifdef HAVE_PTHREAD
+/*
+ * Fields that used for multi-thread
+ */
+struct e2fsck_thread {
+ /* Thread index */
+ int et_thread_index;
+ /* The start group number for this thread */
+ dgrp_t et_group_start;
+ /* The end (not included) group number for this thread*/
+ dgrp_t et_group_end;
+ /* The next group number to check */
+ dgrp_t et_group_next;
+};
+#endif
+
struct e2fsck_struct {
/* Global context to get the cancel flag */
e2fsck_t global_ctx;
@@ -344,8 +360,11 @@ struct e2fsck_struct {
*/
ext2_ino_t stashed_ino;
struct ext2_inode *stashed_inode;
- /* Thread index, if global_ctx is null, this field is unused */
- int thread_index;
+
+ /* if @global_ctx is null, this field is unused */
+#ifdef HAVE_PTHREAD
+ struct e2fsck_thread thread_info;
+#endif
/*
* Location of the lost and found directory
@@ -315,7 +315,8 @@ static FILE *set_up_log_file(e2fsck_t ctx, const char *key, const char *fn)
expand_logfn(ctx, log_fn, &s);
#ifdef HAVE_PTHREAD
if (ctx->global_ctx) {
- sprintf(string_index, "%d", ctx->thread_index);
+ sprintf(string_index, "%d",
+ ctx->thread_info.et_thread_index);
append_string(&s, ".", 1);
append_string(&s, string_index, 0);
}
@@ -1389,6 +1389,23 @@ void e2fsck_pass1_run(e2fsck_t ctx)
/* Set up ctx->lost_and_found if possible */
(void) e2fsck_get_lost_and_found(ctx, 0);
+#ifdef HAVE_PTHREAD
+ if (ctx->global_ctx) {
+ if (ctx->options & E2F_OPT_DEBUG &&
+ ctx->options & E2F_OPT_MULTITHREAD)
+ fprintf(stderr, "thread %d jumping to group %d\n",
+ ctx->thread_info.et_thread_index,
+ ctx->thread_info.et_group_start);
+ pctx.errcode = ext2fs_inode_scan_goto_blockgroup(scan,
+ ctx->thread_info.et_group_start);
+ if (pctx.errcode) {
+ fix_problem(ctx, PR_1_PASS_HEADER, &pctx);
+ ctx->flags |= E2F_FLAG_ABORT;
+ goto endit;
+ }
+ }
+#endif
+
while (1) {
if (ino % (fs->super->s_inodes_per_group * 4) == 1) {
if (e2fsck_mmp_update(fs))
@@ -1432,6 +1449,8 @@ void e2fsck_pass1_run(e2fsck_t ctx)
ext2fs_mark_inode_bitmap2(ctx->inode_used_map, ino);
continue;
}
+ if (pctx.errcode == EXT2_ET_SCAN_FINISHED)
+ break;
if (pctx.errcode &&
pctx.errcode != EXT2_ET_INODE_CSUM_INVALID &&
pctx.errcode != EXT2_ET_INODE_IS_GARBAGE) {
@@ -2211,12 +2230,14 @@ static errcode_t e2fsck_open_channel_fs(ext2_filsys dest, e2fsck_t dest_context,
return 0;
}
-static errcode_t e2fsck_pass1_thread_prepare(e2fsck_t global_ctx, e2fsck_t *thread_ctx)
+static errcode_t e2fsck_pass1_thread_prepare(e2fsck_t global_ctx, e2fsck_t *thread_ctx,
+ int thread_index)
{
errcode_t retval;
e2fsck_t thread_context;
ext2_filsys thread_fs;
ext2_filsys global_fs = global_ctx->fs;
+ struct e2fsck_thread *tinfo;
assert(global_ctx->inode_used_map == NULL);
assert(global_ctx->inode_dir_map == NULL);
@@ -2252,8 +2273,15 @@ static errcode_t e2fsck_pass1_thread_prepare(e2fsck_t global_ctx, e2fsck_t *thre
goto out_fs;
}
- thread_context->thread_index = 0;
+ thread_context->thread_info.et_thread_index = thread_index;
set_up_logging(thread_context);
+
+ assert(thread_index == 0);
+ tinfo = &thread_context->thread_info;
+ tinfo->et_group_start = 0;
+ tinfo->et_group_next = 0;
+ tinfo->et_group_end = thread_fs->group_desc_count;
+
*thread_ctx = thread_context;
return 0;
out_fs:
@@ -2495,7 +2523,7 @@ 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;
- retval = e2fsck_pass1_thread_prepare(global_ctx, &thread_ctx);
+ retval = e2fsck_pass1_thread_prepare(global_ctx, &thread_ctx, i);
if (retval) {
com_err(global_ctx->program_name, retval,
_("while preparing pass1 thread\n"));
@@ -2580,6 +2608,7 @@ static errcode_t scan_callback(ext2_filsys fs,
{
struct scan_callback_struct *scan_struct;
e2fsck_t ctx;
+ struct e2fsck_thread *tinfo;
scan_struct = (struct scan_callback_struct *) priv_data;
ctx = scan_struct->ctx;
@@ -2591,6 +2620,15 @@ static errcode_t scan_callback(ext2_filsys fs,
ctx->fs->group_desc_count))
return EXT2_ET_CANCEL_REQUESTED;
+#ifdef HAVE_PTHREAD
+ if (ctx->global_ctx) {
+ tinfo = &ctx->thread_info;
+ tinfo->et_group_next++;
+ if (tinfo->et_group_next >= tinfo->et_group_end)
+ return EXT2_ET_SCAN_FINISHED;
+ }
+#endif
+
return 0;
}
@@ -1309,6 +1309,11 @@ static struct e2fsck_problem problem_table[] = {
N_("Orphan file @i %i is not in use, but contains data. "),
PROMPT_CLEAR, PR_PREEN_OK },
+ /* Failed to goto block group */
+ { PR_1_SCAN_GOTO,
+ N_("failed to goto block group"),
+ PROMPT_NONE, PR_FATAL, 0, 0, 0 },
+
/* Pass 1b errors */
/* Pass 1B: Rescan for duplicate/bad blocks */
@@ -734,6 +734,9 @@ struct problem_context {
/* Orphan file inode is not in use, but contains data */
#define PR_1_ORPHAN_FILE_NOT_CLEAR 0x010090
+/* Failed to goto block group */
+#define PR_1_SCAN_GOTO 0x0100A0
+
/*
* Pass 1b errors
*/
@@ -557,4 +557,7 @@ ec EXT2_ET_EXTENT_CYCLE,
ec EXT2_ET_EXTERNAL_JOURNAL_NOSUPP,
"Operation not supported on an external journal"
+ec EXT2_ET_SCAN_FINISHED,
+ "Scanning finished"
+
end