Skip to contentSkip to conversation

Threaded e2fsck proof of concept

PATCH New Valerie Henson 1 participant 1 message Sep 26, 2007 VFS

lore
Share & tools
lore
#0 lore raw

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 *arg
 		case '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;