aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLi Xi <lixi@ddn.com>2019-08-15 16:33:19 +0800
committerTheodore Ts'o <tytso@mit.edu>2021-01-25 15:16:46 -0500
commitb2a9a40831dfbb6dacf8bbc819acac2c25ab6980 (patch)
treefba18fabf1d36fbe3b1ad5516699d701585ed0d9
parent2643de7d00dc8da9f5be79fab768fca7a27f3745 (diff)
downloade2fsprogs-b2a9a40831dfbb6dacf8bbc819acac2c25ab6980.tar.gz
e2fsck: configure one pfsck thread
This patch creates only one thread to do pass1 check if pthreads are enabled. The same codes can be used to create multiple threads, but other functions need to be modified to get ready for that. Signed-off-by: Li Xi <lixi@ddn.com> Signed-off-by: Wang Shilong <wshilong@ddn.com> Reviewed-by: Andreas Dilger <adilger@whamcloud.com> Signed-off-by: Theodore Ts'o <tytso@mit.edu>
-rw-r--r--e2fsck/e2fsck.h13
-rw-r--r--e2fsck/logfile.c2
-rw-r--r--e2fsck/pass1.c153
-rw-r--r--e2fsck/unix.c10
-rw-r--r--tests/test_one.in8
5 files changed, 168 insertions, 18 deletions
diff --git a/e2fsck/e2fsck.h b/e2fsck/e2fsck.h
index 5ad0fe935..3bc79212c 100644
--- a/e2fsck/e2fsck.h
+++ b/e2fsck/e2fsck.h
@@ -426,6 +426,19 @@ struct e2fsck_struct {
char *undo_file;
};
+#ifdef HAVE_PTHREAD
+struct e2fsck_thread_info {
+ /* ID returned by pthread_create() */
+ pthread_t eti_thread_id;
+ /* Application-defined thread index */
+ int eti_thread_index;
+ /* Thread has been started */
+ int eti_started;
+ /* Context used for this thread */
+ e2fsck_t eti_thread_ctx;
+};
+#endif
+
/* Data structures to evaluate whether an extent tree needs rebuilding. */
struct extent_tree_level {
unsigned int num_extents;
diff --git a/e2fsck/logfile.c b/e2fsck/logfile.c
index c5505d279..9f9218550 100644
--- a/e2fsck/logfile.c
+++ b/e2fsck/logfile.c
@@ -310,11 +310,13 @@ static FILE *set_up_log_file(e2fsck_t ctx, const char *key, const char *fn)
goto out;
expand_logfn(ctx, log_fn, &s);
+#ifdef HAVE_PTHREAD
if (ctx->global_ctx) {
sprintf(string_index, "%d", ctx->thread_index);
append_string(&s, ".", 1);
append_string(&s, string_index, 0);
}
+#endif
if ((log_fn[0] == '/') || !log_dir || !log_dir[0])
s0 = s.s;
diff --git a/e2fsck/pass1.c b/e2fsck/pass1.c
index bae47a7f1..88099ac2b 100644
--- a/e2fsck/pass1.c
+++ b/e2fsck/pass1.c
@@ -47,6 +47,9 @@
#include <errno.h>
#endif
#include <assert.h>
+#ifdef HAVE_PTHREAD
+#include <pthread.h>
+#endif
#include "e2fsck.h"
#include <ext2fs/ext2_ext_attr.h>
@@ -1162,7 +1165,7 @@ static int e2fsck_should_abort(e2fsck_t ctx)
return 0;
}
-void e2fsck_pass1_thread(e2fsck_t ctx)
+void e2fsck_pass1_run(e2fsck_t ctx)
{
int i;
__u64 max_sizes;
@@ -2087,6 +2090,7 @@ endit:
ctx->invalid_bitmaps++;
}
+#ifdef HAVE_PTHREAD
static errcode_t e2fsck_pass1_copy_bitmap(ext2_filsys fs, ext2fs_generic_bitmap *src,
ext2fs_generic_bitmap *dest)
{
@@ -2392,18 +2396,38 @@ static int e2fsck_pass1_thread_join(e2fsck_t global_ctx, e2fsck_t thread_ctx)
return retval;
}
-void e2fsck_pass1_multithread(e2fsck_t ctx)
+static int e2fsck_pass1_threads_join(struct e2fsck_thread_info *infos,
+ int num_threads, e2fsck_t global_ctx)
{
- errcode_t retval;
- e2fsck_t thread_ctx;
+ errcode_t rc;
+ errcode_t ret = 0;
+ int i;
+ struct e2fsck_thread_info *pinfo;
- retval = e2fsck_pass1_thread_prepare(ctx, &thread_ctx);
- if (retval) {
- com_err(ctx->program_name, 0,
- _("while preparing pass1 thread\n"));
- ctx->flags |= E2F_FLAG_ABORT;
- return;
+ for (i = 0; i < num_threads; i++) {
+ pinfo = &infos[i];
+
+ if (!pinfo->eti_started)
+ continue;
+
+ rc = pthread_join(pinfo->eti_thread_id, NULL);
+ if (rc) {
+ com_err(global_ctx->program_name, rc,
+ _("while joining thread\n"));
+ if (ret == 0)
+ ret = rc;
+ }
+ e2fsck_pass1_thread_join(global_ctx, infos[i].eti_thread_ctx);
}
+ free(infos);
+
+ return ret;
+}
+
+static void *e2fsck_pass1_thread(void *arg)
+{
+ struct e2fsck_thread_info *info = arg;
+ e2fsck_t thread_ctx = info->eti_thread_ctx;
#ifdef HAVE_SETJMP_H
/*
@@ -2414,25 +2438,118 @@ void e2fsck_pass1_multithread(e2fsck_t ctx)
*/
if (setjmp(thread_ctx->abort_loc)) {
thread_ctx->flags &= ~E2F_FLAG_SETJMP_OK;
- e2fsck_pass1_thread_join(ctx, thread_ctx);
- return;
+ goto out;
}
thread_ctx->flags |= E2F_FLAG_SETJMP_OK;
#endif
- e2fsck_pass1_thread(thread_ctx);
- retval = e2fsck_pass1_thread_join(ctx, thread_ctx);
+ e2fsck_pass1_run(thread_ctx);
+
+out:
+ return NULL;
+}
+
+static int e2fsck_pass1_threads_start(struct e2fsck_thread_info **pinfo,
+ int num_threads, e2fsck_t global_ctx)
+{
+ struct e2fsck_thread_info *infos;
+ pthread_attr_t attr;
+ errcode_t retval;
+ errcode_t ret;
+ struct e2fsck_thread_info *tmp_pinfo;
+ int i;
+ e2fsck_t thread_ctx;
+
+ retval = pthread_attr_init(&attr);
if (retval) {
- com_err(ctx->program_name, 0,
- _("while joining pass1 thread\n"));
- ctx->flags |= E2F_FLAG_ABORT;
- return;
+ com_err(global_ctx->program_name, retval,
+ _("while setting pthread attribute\n"));
+ return retval;
}
+
+ infos = calloc(num_threads, sizeof(struct e2fsck_thread_info));
+ if (infos == NULL) {
+ retval = -ENOMEM;
+ com_err(global_ctx->program_name, retval,
+ _("while allocating memory for threads\n"));
+ pthread_attr_destroy(&attr);
+ return retval;
+ }
+
+ 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);
+ if (retval) {
+ com_err(global_ctx->program_name, retval,
+ _("while preparing pass1 thread\n"));
+ break;
+ }
+ tmp_pinfo->eti_thread_ctx = thread_ctx;
+
+ retval = pthread_create(&tmp_pinfo->eti_thread_id, &attr,
+ &e2fsck_pass1_thread, tmp_pinfo);
+ if (retval) {
+ com_err(global_ctx->program_name, retval,
+ _("while creating thread\n"));
+ e2fsck_pass1_thread_join(global_ctx, thread_ctx);
+ break;
+ }
+
+ tmp_pinfo->eti_started = 1;
+ }
+
+ /* destroy the thread attribute object, since it is no longer needed */
+ ret = pthread_attr_destroy(&attr);
+ if (ret) {
+ com_err(global_ctx->program_name, ret,
+ _("while destroying thread attribute\n"));
+ if (retval == 0)
+ retval = ret;
+ }
+
+ if (retval) {
+ e2fsck_pass1_threads_join(infos, num_threads, global_ctx);
+ return retval;
+ }
+ *pinfo = infos;
+ return 0;
+}
+
+static void e2fsck_pass1_multithread(e2fsck_t global_ctx)
+{
+ struct e2fsck_thread_info *infos = NULL;
+ int num_threads = 1;
+ errcode_t retval;
+
+ retval = e2fsck_pass1_threads_start(&infos, num_threads, 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);
+ if (retval) {
+ com_err(global_ctx->program_name, retval,
+ _("while joining pass1 threads\n"));
+ goto out_abort;
+ }
+ return;
+out_abort:
+ global_ctx->flags |= E2F_FLAG_ABORT;
+ return;
}
+#endif
void e2fsck_pass1(e2fsck_t ctx)
{
+
+#ifdef HAVE_PTHREAD
e2fsck_pass1_multithread(ctx);
+#else
+ e2fsck_pass1_run(ctx);
+#endif
}
#undef FINISH_INODE_LOOP
diff --git a/e2fsck/unix.c b/e2fsck/unix.c
index 1d68f3186..2a736859e 100644
--- a/e2fsck/unix.c
+++ b/e2fsck/unix.c
@@ -82,7 +82,9 @@ static void usage(e2fsck_t ctx)
fprintf(stderr, "%s", _("\nEmergency help:\n"
" -p Automatic repair (no questions)\n"
+#ifdef HAVE_PTHREAD
" -m multiple threads to speedup fsck\n"
+#endif
" -n Make no changes to the filesystem\n"
" -y Assume \"yes\" to all questions\n"
" -c Check for bad blocks and add them to the badblock list\n"
@@ -849,7 +851,11 @@ static errcode_t PRS(int argc, char *argv[], e2fsck_t *ret_ctx)
phys_mem_kb = get_memory_size() / 1024;
ctx->readahead_kb = ~0ULL;
+#ifdef HAVE_PTHREAD
while ((c = getopt(argc, argv, "pamnyrcC:B:dE:fvtFVM:b:I:j:P:l:L:N:SsDkz:")) != EOF)
+#else
+ while ((c = getopt(argc, argv, "panyrcC:B:dE:fvtFVM:b:I:j:P:l:L:N:SsDkz:")) != EOF)
+#endif
switch (c) {
case 'C':
ctx->progress = e2fsck_update_progress;
@@ -890,9 +896,11 @@ static errcode_t PRS(int argc, char *argv[], e2fsck_t *ret_ctx)
}
ctx->options |= E2F_OPT_PREEN;
break;
+#ifdef HAVE_PTHREAD
case 'm':
ctx->options |= E2F_OPT_MULTITHREAD;
break;
+#endif
case 'n':
if (ctx->options & (E2F_OPT_YES|E2F_OPT_PREEN))
goto conflict_opt;
@@ -1011,6 +1019,7 @@ static errcode_t PRS(int argc, char *argv[], e2fsck_t *ret_ctx)
_("The -n and -l/-L options are incompatible."));
fatal_error(ctx, 0);
}
+#ifdef HAVE_PTHREAD
if (ctx->options & E2F_OPT_MULTITHREAD) {
if ((ctx->options & (E2F_OPT_YES|E2F_OPT_NO|E2F_OPT_PREEN)) == 0) {
com_err(ctx->program_name, 0, "%s",
@@ -1023,6 +1032,7 @@ static errcode_t PRS(int argc, char *argv[], e2fsck_t *ret_ctx)
fatal_error(ctx, 0);
}
}
+#endif
if (ctx->options & E2F_OPT_NO)
ctx->options |= E2F_OPT_READONLY;
diff --git a/tests/test_one.in b/tests/test_one.in
index 5d7607ad8..c0a0b4fd6 100644
--- a/tests/test_one.in
+++ b/tests/test_one.in
@@ -27,6 +27,7 @@ esac
test_dir=$1
cmd_dir=$SRCDIR
+pfsck_enabled="no"
if test "$TEST_CONFIG"x = x; then
TEST_CONFIG=$SRCDIR/test_config
@@ -52,6 +53,13 @@ else
test_description=
fi
+$FSCK --help 2>&1 | grep -q -w -- -m && pfsck_enabled=yes
+if [ "$pfsck_enabled" != "yes" ] ; then
+ echo "$test_dir" | grep -q multithread &&
+ echo "$test_name: $test_description: skipped (pfsck disabled)" &&
+ exit 0
+fi
+
if [ -n "$SKIP_SLOW_TESTS" -a -f $test_dir/is_slow_test ]; then
echo "$test_name: $test_description: skipped (slow test)"
exit 0