Threaded e2fsck proof of concept
PATCH 1/1 Threaded e2fsck proof of concept
The below patch is a proof of concept that e2fsck can get a performance improvement on file systems with more than one disk underneath. On my test case, a 500GB file system with 150GB in use and 10+1 RAID underneath, elapsed time is reduced by 40-50%. I see no performance improvement in the single disk case. Only the reading of inode tables and indirect blocks in pass 1 is multi-threaded; most likely multithreading passes 2 and 5 will help too. The actual data processing is still all single-threaded, which is convenient.
Designing multithreaded readahead for the long term is another question. The Lustre folks are working on a sys_readahead() based patch. True aio() is the obvious solution, but won't work for older kernels. Pthreads works for all kernels but is clumsy. Coming up with a design for readahead that allows these different implementations is probably a good idea.
Finally, if you are planning on testing these patches:
* Use -n! You are crazy to let this write to your file system.
* Use about 2 * number_disks threads. (Doesn't work without -t <n> of some sort.)
* The striping logic is probably bogus. Try something like -A 100000.
Thanks to EMC for making this patch possible. Share and enjoy!
-VAL
e2fsck/Makefile.in +3 -3
@@ -119,16 +119,16 @@ e2fsck: e2fsck.@E2FSCK_TYPE@ e2fsck.static: $(OBJS) $(STATIC_DEPLIBS) @echo " LD $@" @$(LD) $(ALL_LDFLAGS) $(LDFLAG_STATIC) -o e2fsck.static $(OBJS) \ - $(STATIC_LIBS) + $(STATIC_LIBS) -lpthread e2fsck.shared: $(OBJS) $(DEPLIBS) @echo " LD $@" - @$(LD) $(ALL_LDFLAGS) -o e2fsck.shared $(OBJS) $(LIBS) + @$(LD) $(ALL_LDFLAGS) -o e2fsck.shared $(OBJS) $(LIBS) -lpthread e2fsck.profiled: $(PROFILED_OBJS) $(PROFILED_DEPLIBS) @echo " LD $@" @$(LD) $(ALL_LDFLAGS) -g -pg -o e2fsck.profiled $(PROFILED_OBJS) \ - $(PROFILED_LIBS) + $(PROFILED_LIBS) -lpthread tst_refcount: ea_refcount.c @echo " LD $@"
e2fsck/e2fsck.h +12 -0
@@ -25,6 +25,7 @@#ifdef HAVE_SETJMP_H #include <setjmp.h> #endif +#include <pthread.h> #if EXT2_FLAT_INCLUDES #include "ext2_fs.h"
@@ -334,6 +335,17 @@ struct e2fsck_struct {profile_t profile;/* +* Multithreaded readahead variables +*/ +unsigned int read_threads; +unsigned int stripe_size; +struct readahead_state *readahead; +/* Used to signal the main thread when a bg is ready */ +pthread_mutex_t mutex_ready; +pthread_cond_t buffer_ready; +/* Have to count groups left at the ctx level, not scan level */ +dgrp_t groups_left; +/* * For the use of callers of the e2fsck functions; not used by * e2fsck functions themselves. */
e2fsck/pass1.c +517 -30
630 lines not on this page · raw message
e2fsck/unix.c +8 -1
@@ -74,6 +74,7 @@ static void usage(e2fsck_t ctx)_ ("Usage: %s [-panyrcdfvstDFSV] [-b superblock] [-B blocksize]\n" "\t\t[-I inode_buffer_blocks] [-P process_inode_size]\n" "\t\t[-l|-L bad_blocks_file] [-C fd] [-j external_journal]\n" +"\t\t[-A readahead_streams] [-z stripe_size]\n" "\t\t[-E extended-options] device\n" ), ctx->program_name);
@@ -610,8 +611,11 @@ static errcode_t PRS(int argc, char *arg ctx->program_name = *argv; else ctx->program_name = "e2fsck"; -while ((c =getopt (argc, argv,"panyrcC:B:dE:fvtFVM:b:I:j:P:l:L:N:SsDk" )) !=EOF ) +while ((c =getopt (argc, argv,"paA:nyrcC:B:dE:fvtFVM:b:I:j:P:l:L:N:SsDkz:" )) !=EOF )switch (c) { +case 'A' : + ctx->read_threads =atoi (optarg); +break ;case 'C' : ctx->progress = e2fsck_update_progress; ctx->progress_fd =atoi (optarg);
@@ -734,6 +738,9 @@ static errcode_t PRS(int argc, char *argcase 'k' : keep_bad_blocks++;break ; +case 'z' : + ctx->stripe_size =atoi (optarg); +break ;default :usage (ctx); }
lib/ext2fs/ind_block.c +3 -0
@@ -30,6 +30,9 @@ errcode_t ext2fs_read_ind_block(ext2_fil (fs->io != fs->image_io)) memset(buf, 0, fs->blocksize); else { +#if 0 +printf ("Final read of ind blk %d\n" , blk); +#endif retval =io_channel_read_blk (fs->io, blk,1 , buf);if (retval)return retval;