Skip to contentSkip to conversation

e2fsprogs: Parallel fsck support

RFC Applied Ritesh Harjani (IBM) 4 participants 104 messages Nov 7, 2022 – Jan 24, 2023 1 message not in the archive Page 2 of 2

lore
Share & tools
lore
#90 lore raw

RFC 61/72 tests: add pfsck test

In reply to Ritesh Harjani (IBM)

From: Wang Shilong <[email protected]>

pfsck run on a clean fs should not return any errors.

Generate an image with possible features enabled,
especially EA shared blocks etc.

---
 tests/f_multithread_ok/expect.1 |   7 +++++++
 tests/f_multithread_ok/image.gz | Bin 0 -> 796311 bytes
 tests/f_multithread_ok/name     |   1 +
 tests/f_multithread_ok/script   |  21 +++++++++++++++++++++
 4 files changed, 29 insertions(+)
 create mode 100644 tests/f_multithread_ok/expect.1
 create mode 100644 tests/f_multithread_ok/image.gz
 create mode 100644 tests/f_multithread_ok/name
 create mode 100644 tests/f_multithread_ok/script
tests/f_multithread_ok/expect.1 new file +7 -0
new file mode 100644
index 00000000..4742f408
@@ -0,0 +1,7 @@
+Pass 1: Checking inodes, blocks, and sizes
+Pass 2: Checking directory structure
+Pass 3: Checking directory connectivity
+Pass 4: Checking reference counts
+Pass 5: Checking group summary information
+test_filesys: 10251/32768 files (0.0% non-contiguous), 2218/131072 blocks
+Exit status is 0
tests/f_multithread_ok/image.gz new file binary +0 -0
new file mode 100644
index 0000000000000000000000000000000000000000..42622c3786a81f348f2935d4f9cc2812bcf539d4
GIT binary patch
tests/f_multithread_ok/name new file +1 -0
new file mode 100644
index 00000000..45dd561d
@@ -0,0 +1 @@
+multiple threads checking on clean fs
tests/f_multithread_ok/script new file +21 -0
new file mode 100644
index 00000000..7334cde6
@@ -0,0 +1,21 @@
+FSCK_OPT="-fym4"
+SKIP_VERIFY="true"
+ONE_PASS_ONLY="true"
+SKIP_CLEANUP="true"
+
+. $cmd_dir/run_e2fsck
+
+grep -v Thread $OUT1 > $OUT1.tmp
+cmp -s $EXP1 $OUT1.tmp
+status1=$?
+if [ "$status1" -eq 0 ]; then
+	echo "$test_name: $test_description: ok"
+	touch $test_name.ok
+else
+	echo "$test_name: $test_description: failed"
+	diff $DIFF_OPTS $EXP1 $OUT1.tmp > $test_name.failed
+fi
+
+unset IMAGE FSCK_OPT SECOND_FSCK_OPT OUT1 OUT2 EXP1 EXP2
+unset SKIP_VERIFY SKIP_CLEANUP SKIP_GUNZIP ONE_PASS_ONLY PREP_CMD
+unset DESCRIPTION SKIP_UNLINK AFTER_CMD PASS_ZERO
Signature · 1 line
2.37.3
#91 lore raw

RFC 62/72 e2fsck: fix memory leaks with pfsck enabled

In reply to Ritesh Harjani (IBM)

From: Wang Shilong <[email protected]>

valgrind detected two memory leaks:

1) quota context is not released after merging.
2) @refcount_orig should be released

---
 e2fsck/e2fsck.c | 4 ++++
 e2fsck/pass1.c  | 1 +
 2 files changed, 5 insertions(+)
e2fsck/e2fsck.c +4 -0
index 53af8905..db0a5059 100644
@@ -106,6 +106,10 @@ errcode_t e2fsck_reset_context(e2fsck_t ctx)
 		ea_refcount_free(ctx->refcount_extra);
 		ctx->refcount_extra = 0;
 	}
+	if (ctx->refcount_orig) {
+		ea_refcount_free(ctx->refcount_orig);
+		ctx->refcount_orig = 0;
+	}
 	if (ctx->ea_block_quota_blocks) {
 		ea_refcount_free(ctx->ea_block_quota_blocks);
 		ctx->ea_block_quota_blocks = 0;
e2fsck/pass1.c +1 -0
index ed4275c3..d745699d 100644
@@ -3039,6 +3039,7 @@ static int e2fsck_pass1_thread_join(e2fsck_t global_ctx, e2fsck_t thread_ctx)
 
 	retval = e2fsck_pass1_merge_context(global_ctx, thread_ctx);
 
+	quota_release_context(&thread_ctx->qctx);
 	/*
 	 * @block_metadata_map and @block_dup_map are
 	 * shared, so we don't free them.
Signature · 1 line
2.37.3
#92 lore raw

RFC 63/72 e2fsck: misc cleanups for pfsck

In reply to Ritesh Harjani (IBM)

From: Andreas Dilger <[email protected]>

Add -m option description to e2fsck.8 man page.

Rename e2fsck_struct fs_num_threads to pfs_num_threads to avoid confusion with the ext2_filsys fs_num_threads field, and move thread_info to be together with the other HAVE_PTHREAD fields.

Move ext2_filsys fs_num_threads to fit into the __u16 "pad" field to avoid consuming one of the few remaining __u32 reserved fields.

Fix a few print format warnings.

---
 e2fsck/e2fsck.8.in |  8 +++++++-
 e2fsck/e2fsck.h    | 13 +++++--------
 e2fsck/pass1.c     | 20 +++++++++++---------
 e2fsck/unix.c      |  4 ++--
 4 files changed, 25 insertions(+), 20 deletions(-)
e2fsck/e2fsck.8.in +7 -1
index dc6a5856..37dc8936 100644
@@ -8,7 +8,7 @@ e2fsck \- check a Linux ext2/ext3/ext4 file system
 .SH SYNOPSIS
 .B e2fsck
 [
-.B \-pacnyrdfkvtDFV
+.B \-pacnyrdfkmvtDFV
 ]
 [
 .B \-b
@@ -333,6 +333,12 @@ Set the bad blocks list to be the list of blocks specified by
 option, except the bad blocks list is cleared before the blocks listed
 in the file are added to the bad blocks list.)
 .TP
+.B \-m " threads"
+Run e2fsck with up to the specified number of
+.IR threads .
+The actual number of threads may be lower, if the filesystem does not
+have enough block groups to effectively parallelize the workload.
+.TP
 .B \-n
 Open the file system read-only, and assume an answer of `no' to all
 questions.  Allows
e2fsck/e2fsck.h +5 -8
index 2dd7ba27..33866316 100644
@@ -277,8 +277,8 @@ struct e2fsck_thread {
 	dgrp_t		et_group_next;
 	/* Scanned inode number */
 	ext2_ino_t	et_inode_number;
-	char		et_log_buf[2048];
 	char		et_log_length;
+	char		et_log_buf[2048];
 };
 #endif
 
@@ -367,11 +367,6 @@ struct e2fsck_struct {
 	ext2_ino_t		stashed_ino;
 	struct ext2_inode	*stashed_inode;
 
-	/* 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
 	 */
@@ -487,7 +482,9 @@ struct e2fsck_struct {
 	char *undo_file;
 
 #ifdef HAVE_PTHREAD
-	__u32			 fs_num_threads;
+	/* if @global_ctx is null, this field is unused */
+	struct e2fsck_thread	 thread_info;
+	__u32			 pfs_num_threads;
 	__u32			 mmp_update_thread;
 	int			 fs_need_locking;
 	/* serialize fix operation for multiple threads */
@@ -732,7 +729,7 @@ void check_resize_inode(e2fsck_t ctx);
 int check_init_orphan_file(e2fsck_t ctx);
 
 /* util.c */
-#define E2FSCK_MAX_THREADS	(65536)
+#define E2FSCK_MAX_THREADS	(65535)
 extern void *e2fsck_allocate_memory(e2fsck_t ctx, unsigned long size,
 				    const char *description);
 extern int ask(e2fsck_t ctx, const char * string, int def);
e2fsck/pass1.c +11 -9
index d745699d..8a6cdd8f 100644
@@ -1265,7 +1265,7 @@ static void e2fsck_pass1_set_thread_num(e2fsck_t ctx)
 {
 	unsigned flexbg_size = 1;
 	ext2_filsys fs = ctx->fs;
-	int num_threads = ctx->fs_num_threads;
+	int num_threads = ctx->pfs_num_threads;
 	int max_threads;
 
 	if (num_threads < 1) {
@@ -1285,6 +1285,8 @@ static void e2fsck_pass1_set_thread_num(e2fsck_t ctx)
 	max_threads = fs->group_desc_count / flexbg_size;
 	if (max_threads == 0)
 		max_threads = 1;
+	if (max_threads > E2FSCK_MAX_THREADS)
+		max_threads = E2FSCK_MAX_THREADS;
 
 	if (num_threads > max_threads) {
 		fprintf(stderr, "Use max possible thread num: %d instead\n",
@@ -1292,7 +1294,7 @@ static void e2fsck_pass1_set_thread_num(e2fsck_t ctx)
 		num_threads = max_threads;
 	}
 out:
-	ctx->fs_num_threads = num_threads;
+	ctx->pfs_num_threads = num_threads;
 	ctx->fs->fs_num_threads = num_threads;
 }
 #endif
@@ -1320,7 +1322,7 @@ static errcode_t e2fsck_pass1_prepare(e2fsck_t ctx)
 
 #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);
+	readahead_kb = get_memory_size() / (10 * ctx->pfs_num_threads);
 	/* maybe better disable RA if this is too small? */
 	if (ctx->readahead_kb > readahead_kb)
 		ctx->readahead_kb = readahead_kb;
@@ -1378,7 +1380,7 @@ static errcode_t e2fsck_pass1_prepare(e2fsck_t ctx)
 #ifdef	HAVE_PTHREAD
 	pthread_rwlock_init(&ctx->fs_fix_rwlock, NULL);
 	pthread_rwlock_init(&ctx->fs_block_map_rwlock, NULL);
-	if (ctx->fs_num_threads > 1)
+	if (ctx->pfs_num_threads > 1)
 		ctx->fs_need_locking = 1;
 	else
 		ctx->fs_need_locking = 0;
@@ -1659,7 +1661,7 @@ void e2fsck_pass1_run(e2fsck_t ctx)
 	if (ctx->global_ctx) {
 		if (ctx->options & E2F_OPT_DEBUG &&
 		    ctx->options & E2F_OPT_MULTITHREAD)
-			fprintf(stderr, "thread %d jumping to group %d\n",
+			fprintf(stderr, "thread %d jumping to group %u\n",
 					ctx->thread_info.et_thread_index,
 					ctx->thread_info.et_group_start);
 		pctx.errcode = ext2fs_inode_scan_goto_blockgroup(scan,
@@ -3064,7 +3066,7 @@ static int e2fsck_pass1_threads_join(struct e2fsck_thread_info *infos,
 	errcode_t ret = 0;
 	int i;
 	struct e2fsck_thread_info *pinfo;
-	int num_threads = global_ctx->fs_num_threads;
+	int num_threads = global_ctx->pfs_num_threads;
 
 	/* merge invalid bitmaps will recalculate it */
 	global_ctx->invalid_bitmaps = 0;
@@ -3130,7 +3132,7 @@ static void *e2fsck_pass1_thread(void *arg)
 out:
 	if (thread_ctx->options & E2F_OPT_MULTITHREAD)
 		log_out(thread_ctx,
-			_("Scanned group range [%lu, %lu), inodes %lu\n"),
+			_("Scanned group range [%u, %u), inodes %u\n"),
 			thread_ctx->thread_info.et_group_start,
 			thread_ctx->thread_info.et_group_end,
 			thread_ctx->thread_info.et_inode_number);
@@ -3156,7 +3158,7 @@ static int e2fsck_pass1_threads_start(struct e2fsck_thread_info **pinfo,
 	int i;
 	e2fsck_t thread_ctx;
 	dgrp_t average_group;
-	int num_threads = global_ctx->fs_num_threads;
+	int num_threads = global_ctx->pfs_num_threads;
 #ifdef DEBUG_THREADS
 	struct e2fsck_thread_debug thread_debug =
 		{PTHREAD_MUTEX_INITIALIZER, PTHREAD_COND_INITIALIZER, 0};
@@ -3259,7 +3261,7 @@ void e2fsck_pass1(e2fsck_t ctx)
 	if (retval)
 		return;
 #ifdef HAVE_PTHREAD
-	if (ctx->options & E2F_OPT_MULTITHREAD || ctx->fs_num_threads > 1)
+	if (ctx->options & E2F_OPT_MULTITHREAD || ctx->pfs_num_threads > 1)
 		e2fsck_pass1_multithread(ctx);
 	else
 #endif
e2fsck/unix.c +2 -2
index dfa3f897..461ab8cb 100644
@@ -915,12 +915,12 @@ static errcode_t PRS(int argc, char *argv[], e2fsck_t *ret_ctx)
 					_("Invalid multiple thread num.\n"));
 			if (thread_num > E2FSCK_MAX_THREADS) {
 				fprintf(stderr,
-					_("threads %lu too large (max %lu)\n"),
+					_("threads %lu too large (max %u)\n"),
 					thread_num, E2FSCK_MAX_THREADS);
 				fatal_error(ctx, 0);
 			}
 			ctx->options |= E2F_OPT_MULTITHREAD;
-			ctx->fs_num_threads = thread_num;
+			ctx->pfs_num_threads = thread_num;
 			break;
 #endif
 		case 'n':
Signature · 1 line
2.37.3
#93 lore raw

RFC 64/72 e2fsck: propagate number of threads

In reply to Ritesh Harjani (IBM)

From: Saranya Muruganandam <[email protected]>

Sometimes, such as in orphan_inode case, e2fsck_pass1 is called after reading the block bitmaps. This results in reading the block bitmap sequentially and multithreading only gets kicked in later. Fix the thread count earlier while setting up the file system.

---
 e2fsck/unix.c | 3 +++
 1 file changed, 3 insertions(+)
e2fsck/unix.c +3 -0
index 461ab8cb..fb0df85a 100644
@@ -1745,6 +1745,9 @@ failure:
 
 	ctx->fs = fs;
 	fs->now = ctx->now;
+#ifdef HAVE_PTHREAD
+	fs->fs_num_threads = ctx->pfs_num_threads;
+#endif
 	sb = fs->super;
 
 	if (sb->s_rev_level > E2FSCK_CURRENT_REV) {
Signature · 1 line
2.37.3
#94 lore raw

RFC 65/72 e2fsck: Annotating fields in e2fsck_struct

In reply to Ritesh Harjani (IBM)

From: Saranya Muruganandam <[email protected]>

Adding information on fields in e2fsck_struct
on how they are used when running parallel fsck.

---
 e2fsck/e2fsck.h | 20 ++++++++++++++------
 1 file changed, 14 insertions(+), 6 deletions(-)
e2fsck/e2fsck.h +14 -6
index 33866316..1e82b048 100644
@@ -285,7 +285,7 @@ struct e2fsck_thread {
 struct e2fsck_struct {
 	/* Global context to get the cancel flag */
 	e2fsck_t global_ctx;
-	ext2_filsys fs;
+	ext2_filsys fs; /* [fs_fix_rwlock] */
 	const char *program_name;
 	char *filesystem_name;
 	char *device_name;
@@ -294,7 +294,9 @@ struct e2fsck_struct {
 	char	*log_fn;
 	FILE	*problem_logf;
 	char	*problem_log_fn;
-	int	flags;		/* E2fsck internal flags */
+	/* E2fsck internal flags.
+	 * shared by different threads for pass1 [fs_fix_rwlock] */
+	int	flags;
 	int	options;
 	unsigned blocksize;	/* blocksize */
 	blk64_t	use_superblock;	/* sb requested by user */
@@ -314,6 +316,7 @@ struct e2fsck_struct {
 	int (*progress)(e2fsck_t ctx, int pass, unsigned long cur,
 			unsigned long max);
 
+	/* The following inode bitmaps are separately used in thread_ctx Pass1*/
 	ext2fs_inode_bitmap inode_used_map; /* Inodes which are in use */
 	ext2fs_inode_bitmap inode_bad_map; /* Inodes which are bad somehow */
 	ext2fs_inode_bitmap inode_dir_map; /* Inodes which are directories */
@@ -322,12 +325,14 @@ struct e2fsck_struct {
 	ext2fs_inode_bitmap inode_reg_map; /* Inodes which are regular files*/
 	ext2fs_inode_bitmap inode_casefold_map; /* Inodes which are casefolded */
 
+	/* Following 3 protected by [fs_block_map_rwlock] */
 	ext2fs_block_bitmap block_found_map; /* Blocks which are in use */
 	ext2fs_block_bitmap block_dup_map; /* Blks referenced more than once */
 	ext2fs_block_bitmap block_ea_map; /* Blocks which are used by EA's */
 
 	/*
-	 * Inode count arrays
+	 * Inode count arrays.
+	 * Separately used in thread_ctx, pass1
 	 */
 	ext2_icount_t	inode_count;
 	ext2_icount_t inode_link_info;
@@ -349,7 +354,8 @@ struct e2fsck_struct {
 
 	/*
 	 * Array of flags indicating whether an inode bitmap, block
-	 * bitmap, or inode table is invalid
+	 * bitmap, or inode table is invalid.
+	 * Separately used in thread_ctx, pass1
 	 */
 	int *invalid_inode_bitmap_flag;
 	int *invalid_block_bitmap_flag;
@@ -362,7 +368,8 @@ struct e2fsck_struct {
 	char *block_buf;
 
 	/*
-	 * For pass1_check_directory and pass1_get_blocks
+	 * For pass1_check_directory and pass1_get_blocks.
+	 * Separately used in thread_ctx in pass1
 	 */
 	ext2_ino_t		stashed_ino;
 	struct ext2_inode	*stashed_inode;
@@ -421,6 +428,7 @@ struct e2fsck_struct {
 
 	/*
 	 * How we display the progress update (for unix)
+	 * shared by different threads for pass1 [fs_fix_rwlock]
 	 */
 	int progress_fd;
 	int progress_pos;
@@ -429,7 +437,7 @@ struct e2fsck_struct {
 	int interactive;	/* Are we connected directly to a tty? */
 	char start_meta[2], stop_meta[2];
 
-	/* File counts */
+	/* File counts. Separately used in thread_ctx, pass1 */
 	__u32 fs_directory_count;
 	__u32 fs_regular_count;
 	__u32 fs_blockdev_count;
Signature · 1 line
2.37.3
#95 lore raw

RFC 66/72 e2fsck: merge casefolded dir lists after thread finish

In reply to Ritesh Harjani (IBM)

From: Wang Shilong <[email protected]>

This is missed and should be done after threads finish.

Original commit:
18538b27 ("LU-8465 e2fsck: merge encrypted dir lists after thread finish") Upstream is now using e2fsck_struct->casefolded_dirs instead of encrypted_dirs.

Only for the correctness of pfsck, we won't use casefolded feature on ldiskfs.

---
 e2fsck/pass1.c | 26 ++++++++++++++++++++++++++
 1 file changed, 26 insertions(+)
e2fsck/pass1.c +26 -0
index 8a6cdd8f..7345c96d 100644
@@ -2614,6 +2614,7 @@ static errcode_t e2fsck_pass1_thread_prepare(e2fsck_t global_ctx, e2fsck_t *thre
 	}
 	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,
@@ -2905,6 +2906,24 @@ static errcode_t e2fsck_pass1_merge_ea_refcount(e2fsck_t global_ctx,
 	return retval;
 }
 
+static errcode_t e2fsck_pass1_merge_casefolded_dirs(e2fsck_t global_ctx,
+						   e2fsck_t thread_ctx)
+{
+	errcode_t retval = 0;
+
+	if (!thread_ctx->casefolded_dirs)
+		return 0;
+
+	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)
 {
@@ -2971,6 +2990,13 @@ static errcode_t e2fsck_pass1_merge_context(e2fsck_t global_ctx,
 	if (retval)
 		return retval;
 
+	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,
Signature · 1 line
2.37.3
#96 lore raw

RFC 67/72 sec: support encrypted files handling in pfsck mode

In reply to Ritesh Harjani (IBM)

From: Sebastien Buisson <[email protected]>

e2fsck needs to be improved in order to support encrypted files handling in parallel fsck mode. The e2fsck_merge_encrypted_info() function is added to merge encrypted inodes info collected from different threads in pass1, so that it can be used in pass2.

---
 e2fsck/e2fsck.h          |   2 +
 e2fsck/encrypted_files.c | 139 +++++++++++++++++++++++++++++++++++++++
 e2fsck/pass1.c           |  26 +++++++-
 3 files changed, 164 insertions(+), 3 deletions(-)
e2fsck/e2fsck.h +2 -0
index 1e82b048..e4fb782a 100644
@@ -642,6 +642,8 @@ __u32 find_encryption_policy(e2fsck_t ctx, ext2_ino_t ino);
 
 void destroy_encryption_policy_map(e2fsck_t ctx);
 void destroy_encrypted_file_info(e2fsck_t ctx);
+int e2fsck_merge_encrypted_info(e2fsck_t ctx, struct encrypted_file_info *src,
+				struct encrypted_file_info *dest);
 
 /* extents.c */
 errcode_t e2fsck_rebuild_extents_later(e2fsck_t ctx, ext2_ino_t ino);
e2fsck/encrypted_files.c +139 -0

142 lines not on this page · raw message

e2fsck/pass1.c +23 -3
index 7345c96d..e7dc017c 100644
@@ -2411,9 +2411,6 @@ void e2fsck_pass1_run(e2fsck_t ctx)
 		ctx->ea_block_quota_inodes = 0;
 	}
 
-	/* We don't need the encryption policy => ID map any more */
-	destroy_encryption_policy_map(ctx);
-
 	if (ctx->flags & E2F_FLAG_RESTART) {
 		/*
 		 * Only the master copy of the superblock and block
@@ -2703,6 +2700,23 @@ static void e2fsck_pass1_merge_dx_dir(e2fsck_t global_ctx, e2fsck_t thread_ctx)
 	e2fsck_merge_dx_dir(global_ctx, thread_ctx);
 }
 
+static int e2fsck_pass1_merge_encrypted_info(e2fsck_t global_ctx,
+					      e2fsck_t thread_ctx)
+{
+	if (thread_ctx->encrypted_files == NULL)
+		return 0;
+
+	if (global_ctx->encrypted_files == NULL) {
+		global_ctx->encrypted_files = thread_ctx->encrypted_files;
+		thread_ctx->encrypted_files = NULL;
+		return 0;
+	}
+
+	return e2fsck_merge_encrypted_info(global_ctx,
+					   thread_ctx->encrypted_files,
+					   global_ctx->encrypted_files);
+}
+
 static inline errcode_t
 e2fsck_pass1_merge_icount(ext2_icount_t *dest_icount,
 			  ext2_icount_t *src_icount)
@@ -2963,6 +2977,12 @@ static errcode_t e2fsck_pass1_merge_context(e2fsck_t global_ctx,
 
 	e2fsck_pass1_merge_dir_info(global_ctx, thread_ctx);
 	e2fsck_pass1_merge_dx_dir(global_ctx, thread_ctx);
+	retval = e2fsck_pass1_merge_encrypted_info(global_ctx, thread_ctx);
+	if (retval) {
+		com_err(global_ctx->program_name, 0,
+			_("while merging encrypted info\n"));
+		return retval;
+	}
 
 	retval = ext2fs_merge_fs(&(thread_ctx->fs));
 	if (retval) {
Signature · 1 line
2.37.3
#97 lore raw

Re: [RFCv1 67/72] sec: support encrypted files handling in pfsck mode

Quoted 2 lines · Ritesh Harjani (IBM)

sec: support encrypted files handling in pfsck mode

"sec:" => "e2fsck:".

Quoted 22 lines
e2fsck/encrypted_files.c +22 -0
+/**
+ * Search policy matching @policy in @info->policies
+ * @ctx: e2fsck context
+ * @info: encrypted_file_info to look into
+ * @policy: the policy we are looking for
+ * @parent: (out) last known parent, useful to insert a new leaf
+ *	    in @info->policies
+ *
+ * Return: id of found policy on success, -1 if no matching policy found.
+ */
+static inline int search_policy(e2fsck_t ctx, struct encrypted_file_info *info,
+				union fscrypt_policy policy,
+				struct rb_node **parent)
+{
+	struct rb_node *n = info->policies.rb_node;
+	struct policy_map_entry *entry;
+
+	while (n) {
+		int res;
+
+		*parent = n;
+		entry = ext2fs_rb_entry(n, struct policy_map_entry, node);

e2fsck/encrypted_files.c void destroy_encrypted_file_info(e2fsck_t ctx) · line 491

Quoted 10 lines
e2fsck/encrypted_files.c +10 -0
+		res = cmp_fscrypt_policies(ctx, &policy, &entry->policy);
+		if (res < 0)
+			n = n->rb_left;
+		else if (res > 0)
+			n = n->rb_right;
+		else
+			return entry->policy_id;
+	}
+	return -1;
+}

Can this rbtree search code be reused by get_encryption_policy_id()?

Also, please use the existing constant NO_ENCRYPTION_POLICY instead of -1.

e2fsck/encrypted_files.c void destroy_encrypted_file_info(e2fsck_t ctx) · line 504

Quoted 12 lines
e2fsck/encrypted_files.c +12 -0
+/*
+ * Merge @src encrypted info into @dest
+ */
+int e2fsck_merge_encrypted_info(e2fsck_t ctx, struct encrypted_file_info *src,
+				 struct encrypted_file_info *dest)
+{
+	struct rb_root *src_policies = &src->policies;
+	__u32 *policy_trans;
+	int i, rc = 0;
+
+	if (dest->file_ranges[src->file_ranges_count - 1].last_ino >
+	    src->file_ranges[0].first_ino) {

There is an off-by-one error here. How about writing it like the following so that it looks like the check in append_ino_and_policy_id():

        if (src->file_ranges[0].first_ino <=
            dest->file_ranges[src->file_ranges_count - 1].last_ino) {

e2fsck/encrypted_files.c void destroy_encrypted_file_info(e2fsck_t ctx) · line 514

Quoted 1 line
e2fsck/encrypted_files.c +1 -0
+	/* First, deal with the encryption policy => ID map.

My understanding is that e2fsprogs follows the kernel coding style, where block comments are formatted like the following:

	/*
	 * text
	 */

e2fsck/encrypted_files.c void destroy_encrypted_file_info(e2fsck_t ctx) · line 516

Quoted 2 lines
e2fsck/encrypted_files.c +2 -0
+	 * Compare encryption policies in src with policies already recorded
+	 * in dest. It can be similar policies, but recorded with a different

"similar" => "the same"

e2fsck/encrypted_files.c void destroy_encrypted_file_info(e2fsck_t ctx) · line 531

Quoted 10 lines
e2fsck/encrypted_files.c +10 -0
+	while (!ext2fs_rb_empty_root(src_policies)) {
+		struct policy_map_entry *entry, *newentry;
+		struct rb_node *new, *parent = NULL;
+		int existing_polid;
+
+		entry = ext2fs_rb_entry(src_policies->rb_node,
+					struct policy_map_entry, node);
+		existing_polid = search_policy(ctx, dest,
+					       entry->policy, &parent);
+		if (existing_polid >= 0) {

existing_polid != NO_ENCRYPTION_POLICY

e2fsck/encrypted_files.c void destroy_encrypted_file_info(e2fsck_t ctx) · line 543

Quoted 12 lines
e2fsck/encrypted_files.c +12 -0
+			/* The policy in src is already recorded in dest,
+			 * so just update its id.
+			 */
+			policy_trans[entry->policy_id] = existing_polid;
+		} else {
+			/* The policy in src is new to dest, so insert it
+			 * with the next available id (its original id could
+			 * be already used in dest).
+			 */
+			rc = ext2fs_get_mem(sizeof(*newentry), &newentry);
+			if (rc)
+				goto out_merge;

Use handle_nomem() for memory allocation failures?

e2fsck/encrypted_files.c void destroy_encrypted_file_info(e2fsck_t ctx) · line 549

Quoted 6 lines
e2fsck/encrypted_files.c +6 -0
+                     newentry->policy_id = dest->next_policy_id++;
+                     newentry->policy = entry->policy;
+                     ext2fs_rb_link_node(&newentry->node, parent, &new);
+                     ext2fs_rb_insert_color(&newentry->node,
+                                            &dest->policies);
+                     policy_trans[entry->policy_id] = newentry->policy_id;

This code also appears in get_encryption_policy_id(). Should it be refactored into a helper function?

Quoted 20 lines
e2fsck/encrypted_files.c +20 -0
+	/* Second, deal with the inode number => encryption policy ID map. */
+	if (dest->file_ranges_capacity <
+	    dest->file_ranges_count + src->file_ranges_count) {
+		/* dest->file_ranges is too short, increase its capacity. */
+		size_t new_capacity = dest->file_ranges_count +
+			src->file_ranges_count;
+
+		/* Make sure we at least double the capacity. */
+		if (new_capacity < (dest->file_ranges_capacity * 2))
+			new_capacity = dest->file_ranges_capacity * 2;
+
+		/* We won't need more than the filesystem's inode count. */
+		if (new_capacity > ctx->fs->super->s_inodes_count)
+			new_capacity = ctx->fs->super->s_inodes_count;
+
+		rc = ext2fs_resize_mem(dest->file_ranges_capacity *
+				       sizeof(struct encrypted_file_range),
+				       new_capacity *
+				       sizeof(struct encrypted_file_range),
+				       &dest->file_ranges);

e2fsck/encrypted_files.c void destroy_encrypted_file_info(e2fsck_t ctx) · line 584

Quoted 10 lines
e2fsck/encrypted_files.c +10 -0
+		if (rc) {
+			fix_problem(ctx, PR_1_ALLOCATE_ENCRYPTED_INODE_LIST,
+				    NULL);
+			/* Should never get here */
+			ctx->flags |= E2F_FLAG_ABORT;
+			goto out_merge;
+		}
+
+		dest->file_ranges_capacity = new_capacity;
+	}

The exact allocation size that is needed is 'dest->file_ranges_count + src->file_ranges_count', so much of the above logic is unnecessary. Just reallocate that exact amount.

Also, handle_nomem() should be used.

e2fsck/encrypted_files.c void destroy_encrypted_file_info(e2fsck_t ctx) · line 592

Quoted 8 lines
e2fsck/encrypted_files.c +8 -0
+	/* Copy file ranges from src to dest. */
+	for (i = 0; i < src->file_ranges_count; i++) {
+		/* Make sure to convert policy ids in src. */
+		src->file_ranges[i].policy_id =
+			policy_trans[src->file_ranges[i].policy_id];
+		dest->file_ranges[dest->file_ranges_count++] =
+			src->file_ranges[i];
+	}

This needs to handle UNRECOGNIZED_ENCRYPTION_POLICY as a special case.

Also, shouldn't src->file_ranges be freed after this?

Review

Quoted 2 lines
(quoted diff) +2 -0
+
+out_merge:

I guess the "_merge" in "out_merge:" comes from the name of the containing function? It's a bit confusing. Maybe just use "out:".

e2fsck/pass1.c void e2fsck_pass1_run(e2fsck_t ctx) · line 2415

Quoted 10 lines
e2fsck/pass1.c +0 -2
index 7345c96d..e7dc017c 100644
@@ -2411,9 +2411,6 @@ void e2fsck_pass1_run(e2fsck_t ctx)
 		ctx->ea_block_quota_inodes = 0;
 	}
 
-	/* We don't need the encryption policy => ID map any more */
-	destroy_encryption_policy_map(ctx);

With this change, there are no callers of destroy_encryption_policy_map() outside encrypted_files.c. So absent any other changes, destroy_encryption_policy_map() should be made into a static function and the 'if (info)' check inside it removed.

But, isn't there still some point where pass 1 is fully done and the encryption policy ID map can be destroyed? Maybe e2fsck_pass1_merge_encrypted_info() should be calling destroy_encryption_policy_map() on the global_ctx after doing the merge?

- Eric

#98 lore raw

RFC 68/72 e2fsck: Fix io->align assert check

In reply to Ritesh Harjani (IBM)

dest->io->align might still get set later in case of non-aligned read done by any thread in raw_read_blk(). Hence remove this assert check.

---
 e2fsck/pass1.c | 1 -
 1 file changed, 1 deletion(-)
e2fsck/pass1.c +0 -1
index e7dc017c..c934b021 100644
@@ -2514,7 +2514,6 @@ static errcode_t e2fsck_open_channel_fs(ext2_filsys dest, e2fsck_t dest_context,
 	assert(dest->io->flags == src->io->flags);
 	assert(dest->io->app_data == dest);
 	assert(src->io->app_data == src);
-	assert(dest->io->align == src->io->align);
 
 	dest->priv_data = dest_context;
 	dest_context->fs = dest;
Signature · 1 line
2.37.3
#99 lore raw

RFC 69/72 e2fsck: Fix double free of inodes_to_process

In reply to Ritesh Harjani (IBM)

Found during code review, this fixes the double free of inodes_to_process in e2fsck_pass1_run.

---
 e2fsck/pass1.c | 1 -
 1 file changed, 1 deletion(-)
e2fsck/pass1.c +0 -1
index c934b021..4168a45d 100644
@@ -2436,7 +2436,6 @@ void e2fsck_pass1_run(e2fsck_t ctx)
 	}
 
 	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);
Signature · 1 line
2.37.3
#100 lore raw

RFC 70/72 e2fsck: Fix and simplify update_mmp in case of pfsck

In reply to Ritesh Harjani (IBM)

This adds pass1_update_mmp_enter() & pass1_update_mmp_exit() routines to update mmp block. This also fixes a data race reported by threadsan because of reading and writing to mmp_update_thread variable.

---
 e2fsck/pass1.c | 97 ++++++++++++++++++++++++++++++++------------------
 1 file changed, 63 insertions(+), 34 deletions(-)
e2fsck/pass1.c +63 -34
index 4168a45d..2ff83fcb 100644
@@ -1097,6 +1097,66 @@ out:
 	return 0;
 }
 
+static void pass1_update_mmp_enter(e2fsck_t ctx, ext2_ino_t	ino)
+{
+	ext2_filsys fs = ctx->fs;
+	e2fsck_t global_ctx = ctx->global_ctx ? ctx->global_ctx : ctx;
+	int check_mmp = 0;
+	int set_mmp = 0;
+
+#ifdef HAVE_PTHREAD
+	/* only one active thread could update mmp block. */
+	e2fsck_pass1_block_map_r_lock(ctx);
+	if (!global_ctx->mmp_update_thread)
+		set_mmp = 1;
+	if (global_ctx->mmp_update_thread == ctx->thread_info.et_thread_index + 1)
+		check_mmp = 1;
+	e2fsck_pass1_block_map_r_unlock(ctx);
+
+	if (!check_mmp && !set_mmp)
+		return;
+
+	if (set_mmp) {
+		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);
+	}
+#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);
+	}
+}
+
+static void pass1_update_mmp_exit(e2fsck_t ctx)
+{
+	ext2_filsys fs = ctx->fs;
+	e2fsck_t global_ctx = ctx->global_ctx ? ctx->global_ctx : ctx;
+	int set_mmp = 0;
+
+#ifdef HAVE_PTHREAD
+	e2fsck_pass1_block_map_r_lock(ctx);
+	if (global_ctx->mmp_update_thread == ctx->thread_info.et_thread_index + 1)
+		set_mmp = 1;
+	e2fsck_pass1_block_map_r_unlock(ctx);
+
+	if (!set_mmp)
+		return;
+
+	/* reset update_thread after this thread exit */
+	e2fsck_pass1_block_map_w_lock(ctx);
+	global_ctx->mmp_update_thread = 0;
+	e2fsck_pass1_block_map_w_unlock(ctx);
+#endif
+}
+
 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;
@@ -1511,7 +1571,7 @@ void e2fsck_pass1_run(e2fsck_t ctx)
 	dgrp_t		ra_group = 0;
 	struct ea_quota	ea_ibody_quota;
 	struct process_inode_block *inodes_to_process;
-	int process_inode_count, check_mmp;
+	int process_inode_count;
 	e2fsck_t global_ctx = ctx->global_ctx ? ctx->global_ctx : ctx;
 
 	init_resource_track(&rtrack, ctx->fs->io);
@@ -1675,33 +1735,8 @@ void e2fsck_pass1_run(e2fsck_t ctx)
 #endif
 
 	while (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);
-		}
+		pass1_update_mmp_enter(ctx, ino);
 		old_op = ehandler_operation(eop_next_inode);
 		pctx.errcode = ext2fs_get_next_inode_full(scan, &ino,
 							  inode, inode_size);
@@ -2458,13 +2493,7 @@ endit:
 		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
+	pass1_update_mmp_exit(ctx);
 }
 
 #ifdef HAVE_PTHREAD
Signature · 1 line
2.37.3
#101 lore raw

RFC 71/72 e2fsck: Make threads call log_out after pthread_join

In reply to Ritesh Harjani (IBM)

All fsck threads will call for log_out prints after the pass1 their respective pass1 scanning is completed. This patch moves the log_out print from to after the pthread_join operation.
This makes the threads always print the info in order.

---
 e2fsck/pass1.c | 13 ++++++-------
 1 file changed, 6 insertions(+), 7 deletions(-)
e2fsck/pass1.c +6 -7
index 2ff83fcb..90adc419 100644
@@ -3112,6 +3112,12 @@ static int e2fsck_pass1_thread_join(e2fsck_t global_ctx, e2fsck_t thread_ctx)
 {
 	errcode_t retval;
 
+	log_out(thread_ctx,
+			_("Scanned group range [%u, %u), inodes %u\n"),
+			thread_ctx->thread_info.et_group_start,
+			thread_ctx->thread_info.et_group_end,
+			thread_ctx->thread_info.et_inode_number);
+
 	retval = e2fsck_pass1_merge_context(global_ctx, thread_ctx);
 
 	quota_release_context(&thread_ctx->qctx);
@@ -3203,13 +3209,6 @@ static void *e2fsck_pass1_thread(void *arg)
 	e2fsck_pass1_run(thread_ctx);
 
 out:
-	if (thread_ctx->options & E2F_OPT_MULTITHREAD)
-		log_out(thread_ctx,
-			_("Scanned group range [%u, %u), inodes %u\n"),
-			thread_ctx->thread_info.et_group_start,
-			thread_ctx->thread_info.et_group_end,
-			thread_ctx->thread_info.et_inode_number);
-
 #ifdef DEBUG_THREADS
 	pthread_mutex_lock(&thread_debug->etd_mutex);
 	thread_debug->etd_finished_threads++;
Signature · 1 line
2.37.3
#102 lore raw

RFC 72/72 tests/f_multithread: Fix f_multithread related tests

In reply to Ritesh Harjani (IBM)

With log_out() function now changed to print the message after the pthread join operation, it is safe to also add "Scan group range" related messages in expect files to compare against the pfsck output.

---
 tests/f_multithread_ok/expect.1 |  8 ++++++++
 tests/f_multithread_ok/script   | 17 -----------------
 2 files changed, 8 insertions(+), 17 deletions(-)
tests/f_multithread_ok/expect.1 +8 -0
index 4742f408..cecc11db 100644
@@ -1,4 +1,12 @@
 Pass 1: Checking inodes, blocks, and sizes
+[Thread 0] Scan group range [0, 1)
+[Thread 1] Scan group range [1, 2)
+[Thread 2] Scan group range [2, 3)
+[Thread 3] Scan group range [3, 4)
+[Thread 0] Scanned group range [0, 1), inodes 8192
+[Thread 1] Scanned group range [1, 2), inodes 8192
+[Thread 2] Scanned group range [2, 3), inodes 8192
+[Thread 3] Scanned group range [3, 4), inodes 8192
 Pass 2: Checking directory structure
 Pass 3: Checking directory connectivity
 Pass 4: Checking reference counts
tests/f_multithread_ok/script +0 -17
index 7334cde6..f14034cf 100644
@@ -1,21 +1,4 @@
 FSCK_OPT="-fym4"
-SKIP_VERIFY="true"
 ONE_PASS_ONLY="true"
-SKIP_CLEANUP="true"
 
 . $cmd_dir/run_e2fsck
-
-grep -v Thread $OUT1 > $OUT1.tmp
-cmp -s $EXP1 $OUT1.tmp
-status1=$?
-if [ "$status1" -eq 0 ]; then
-	echo "$test_name: $test_description: ok"
-	touch $test_name.ok
-else
-	echo "$test_name: $test_description: failed"
-	diff $DIFF_OPTS $EXP1 $OUT1.tmp > $test_name.failed
-fi
-
-unset IMAGE FSCK_OPT SECOND_FSCK_OPT OUT1 OUT2 EXP1 EXP2
-unset SKIP_VERIFY SKIP_CLEANUP SKIP_GUNZIP ONE_PASS_ONLY PREP_CMD
-unset DESCRIPTION SKIP_UNLINK AFTER_CMD PASS_ZERO
Signature · 1 line
2.37.3

A message that is not in the archive (sent off-list or not yet received): [email protected]

#104 lore raw
Quoted 39 lines · Andreas Dilger

On Nov 7, 2022, at 06:22, Ritesh Harjani (IBM) <[email protected]> wrote:

Hello,

This is a RFC patch series which has the list of all pfsck related changes which should also address the problem statements mentioned by Ted and Harshad here [1]

Below points will provide more details on how this patch series is laid out:-

1. This series is rebased on the latest e2fsprogs master branch.

2. Patch series is broken down into logical patches for easier review. The series contains libext2fs changes first, followed by e2fsck changes which utilizes libext2fs apis to add pfsck support to pass1.

3. Changes [0005] to [0012] addresses the problem statement laid out by Ted and Harshad [1] i.e. we now have a libext2fs API for clone and merge of ext2_filsys struct. (ext2fs_clone_fs() & ext2fs_merge_fs())

4. These two changes [0016] & [0026] uses above clone/merge api for test and for use in e2fsck.

5. For a lot of libext2fs changes (for e.g. bitmap merging logic or clone/merge apis), there are some unit tests added for it's functionality verification.

Performance results:
=====================
1. On nvme with 22M 0-byte inodes: 7sec v/s 19sec
2. On nvme with 22M 4KB-32KB inodes: 17sec v/s 30sec
3. On nvme with 11M 32KB inodes: 9sec v/s 15sec
4. On RAID HDD setups: (will get back with perf results for this. Although, I had shared some numbers earlier, but I wanted to run pfsck with different FS layout and collect the numbers once again)

Quoted 2 lines

Ritesh,
Thanks for your work to update this patch series. I've been meaning to look at it, but

Thanks Andreas, I see you have already started reviewing. This is super helpful :)

Quoted 4 lines

have been traveling the past couple of weeks.

Have you done any performance comparisons against the original pfsck patch series?

Yes, I did, for the existing tests that I just mentioned above and found the perf numbers to be
similar. I am also planning to take a RAID device setup from an internal team and collect
some performance numbers there.

Quoted 5 lines

I did make a patch against our original series to improve the workload balance between threads, so that they are assigned a roughly equal number of inodes, instead of an equal number of block groups, since my testing showed the processing time of the threads
was proportional to the inode count. This avoids uneven thread completion and reduces overall processing time.

Yes, based on my testing so far. I too agree that to improve the workload balance one should assign an equal
number of inodes to different threads.

Quoted 5 lines

That patch is available in our Gerrit, and I can push it once this series lands, or it could be merged into the original patch that adds the e2fsck_pass1_thread_prepare() code.

https://review.whamcloud.com/48806

Sure, I will keep a note of this patch too in my performance runs.

So, now given the number of patches are quite large, I am hoping that we could review all libext2fs changes
for getting it in shape for merge. Then while we are at e2fsck change, we can definitely look at the above patch
too.

Thanks again!!
-ritesh

Quoted 224 lines

Cheers, Andreas.

For review: Since these are large number of changes. So if the overall series looks good, then we can start reviewing changes in batches. For e.g. if we could review initial changes in libext2fs (from [001] - [0020]), that would be a good start.

Patch-0073 adds support to all tests/* with "-m 2" mode to test pfsck as well. If pthread support is present, make check then test with "-m 2" fsck mode option as well (for tests which utilizes run_e2fsck script).
This was mainly done for verifying that all existing tests passes with pfsck. In this only few tests are kept disabled by passing SKIP_MT=true (Note: Last min. I have decided to drop this patch from sending. Although this can still be found in the github branch [2] for any testing)

On Threadsan: I had tested this patch series against threadsan as well. It does lists few race conditions when running multi-threading (these doesn't looks to be any major problem). I have fixed a few [0070] and rest might either need some minor fixing or marking it false positive.

Here is the github link with all these commits (pfsck-RFCv1 branch) [2].

[1]: https://lore.kernel.org/linux-ext4/YMN10sXgoTR%[email protected]/
[2]: https://github.com/riteshharjani/e2fsprogs/commits/pfsck-RFCv1

Andreas Dilger (2):
libext2fs: Misc fixes for struct_ext2_filsys
e2fsck: misc cleanups for pfsck

Li Xi (16):
dblist: add dblist merge logic
libext2fs: Add flush cleanup API
libext2fs: merge icounts after thread finishes
e2fsck: add -m option for multithread
e2fsck: copy context when using multi-thread fsck
e2fsck: create logs for multi-threads
e2fsck: configure one pfsck thread
e2fsck: Add asserts in open_channel_fs
e2fsck: add start/end group for thread
e2fsck: split groups to different threads
e2fsck: print thread log properly
e2fsck: do not change global variables
e2fsck: optimize the inserting of dir_info_db
e2fsck: merge dir_info after thread finishes
e2fsck: merge icounts after thread finishes
e2fsck: add debug codes for multiple threads

Ritesh Harjani (IBM) (15):
e2fsck: Fix unbalanced mutex unlock for BOUNCE_MTX
gen_bitmaps: Fix ext2fs_compare_generic_bmap/bitmap logic
blkmap64_ba: Add common helper for bits size calculation
badblocks: Remove unused badblocks_flags
tst_badblocks: Add unit test to verify badblocks list merge api
tst_bitmaps_standalone: Add copy and merge bitmaps test
tst_bitmaps_pthread: Add merge bitmaps test using pthreads
tst_libext2fs_pthread: Add libext2fs merge/clone unit tests
e2fsck: Add e2fsck_pass1_thread_join return value
e2fsck: Use merge/clone apis of libext2fs
e2fsck: Fix io->align assert check
e2fsck: Fix double free of inodes_to_process
e2fsck: Fix and simplify update_mmp in case of pfsck
e2fsck: Make threads call log_out after pthread_join tests/f_multithread: Fix f_multithread related tests

Saranya Muruganandam (3):
libext2fs: dupfs: Add fs clone & merge api
e2fsck: propagate number of threads
e2fsck: Annotating fields in e2fsck_struct

Sebastien Buisson (1):
sec: support encrypted files handling in pfsck mode

Wang Shilong (35):
badblocks: Add badblocks merge logic
libext2fs: Add rbtree bitmap merge logic
libext2fs: Add bitmaps merge ops
libext2fs: merge quota context after threads finish
libext2fs: Add support for ext2fs_test_block_bitmap_range2_valid()
libext2fs: Add support to get average group count
libext2fs: avoid too much memory allocation in case fs_num_threads
e2fsck: Add e2fsck_pass1_merge_bitmap() api
e2fsck: rbtree bitmap for dir
e2fsck: merge counts after threads finish
e2fsck: merge dx_dir_info after threads finish
e2fsck: merge dirs_to_hash when threads finish
e2fsck: merge context flags properly
e2fsck: merge quota context after threads finish
e2fsck: serialize fix operations
e2fsck: move some fixes out of parallel pthreads
e2fsck: split and merge invalid bitmaps
e2fsck: merge EA blocks properly
e2fsck: kickoff mutex lock for block found map
e2fsck: allow admin specify number of threads
e2fsck: adjust number of threads
e2fsck: fix readahead for pfsck of pass1
e2fsck: merge options after threads finish
e2fsck: reset lost_and_found after threads finish
e2fsck: merge extent depth count after threads finish
e2fsck: simplify e2fsck context merging codes
e2fsck: set E2F_FLAG_ALLOC_OK after threads
e2fsck: wait fix thread finish before checking
e2fsck: cleanup e2fsck_pass1_thread_join()
e2fsck: make default smallest RA size to 1M
e2fsck: update mmp block in one thread
e2fsck: reset @inodes_to_rebuild if restart
tests: add pfsck test
e2fsck: fix memory leaks with pfsck enabled
e2fsck: merge casefolded dir lists after thread finish

e2fsck/dirinfo.c                        |  238 ++-
e2fsck/dx_dirinfo.c                     |   64 +
e2fsck/e2fsck.8.in                      |    8 +-
e2fsck/e2fsck.c                         |   11 +
e2fsck/e2fsck.h                         |  103 +-
e2fsck/encrypted_files.c                |  139 ++
e2fsck/logfile.c                        |   13 +-
e2fsck/pass1.c                          | 1894 +++++++++++++++++++----
e2fsck/problem.c                        |   11 +
e2fsck/problem.h                        |    3 +
e2fsck/readahead.c                      |    4 +
e2fsck/unix.c                           |   58 +-
e2fsck/util.c                           |  193 ++-
lib/ext2fs/Makefile.in                  |   53 +-
lib/ext2fs/badblocks.c                  |   81 +-
lib/ext2fs/bitmaps.c                    |   10 +
lib/ext2fs/bitops.h                     |    2 +
lib/ext2fs/blkmap64_ba.c                |   20 +-
lib/ext2fs/blkmap64_rb.c                |   65 +
lib/ext2fs/bmap64.h                     |    4 +
lib/ext2fs/dblist.c                     |   38 +
lib/ext2fs/dupfs.c                      |  183 +++
lib/ext2fs/ext2_err.et.in               |    3 +
lib/ext2fs/ext2_io.h                    |    2 +
lib/ext2fs/ext2fs.h                     |   66 +-
lib/ext2fs/ext2fsP.h                    |    1 -
lib/ext2fs/gen_bitmap.c                 |    9 +-
lib/ext2fs/gen_bitmap64.c               |   72 +-
lib/ext2fs/icount.c                     |  107 ++
lib/ext2fs/tst_badblocks.c              |   61 +-
lib/ext2fs/tst_bitmaps_pthread.c        |  247 +++
lib/ext2fs/tst_bitmaps_standalone.c     |  170 ++
lib/ext2fs/tst_libext2fs_pthread.c      |  315 ++++
lib/ext2fs/undo_io.c                    |   19 +
lib/ext2fs/unix_io.c                    |   25 +-
lib/support/mkquota.c                   |   39 +
lib/support/quotaio.h                   |    3 +
tests/f_itable_collision/expect.1       |    3 -
tests/f_multithread/expect.1            |   25 +
tests/f_multithread/expect.2            |    7 +
tests/f_multithread/image.gz            |    1 +
tests/f_multithread/name                |    1 +
tests/f_multithread/script              |    4 +
tests/f_multithread_completion/expect.1 |    2 +
tests/f_multithread_completion/expect.2 |   23 +
tests/f_multithread_completion/image.gz |    1 +
tests/f_multithread_completion/name     |    1 +
tests/f_multithread_completion/script   |    4 +
tests/f_multithread_logfile/expect.1    |   25 +
tests/f_multithread_logfile/image.gz    |    1 +
tests/f_multithread_logfile/name        |    1 +
tests/f_multithread_logfile/script      |   32 +
tests/f_multithread_no/expect.1         |   26 +
tests/f_multithread_no/expect.2         |   23 +
tests/f_multithread_no/image.gz         |    1 +
tests/f_multithread_no/name             |    1 +
tests/f_multithread_no/script           |    4 +
tests/f_multithread_ok/expect.1         |   15 +
tests/f_multithread_ok/image.gz         |  Bin 0 -> 796311 bytes
tests/f_multithread_ok/name             |    1 +
tests/f_multithread_ok/script           |    4 +
tests/f_multithread_preen/expect.1      |   11 +
tests/f_multithread_preen/expect.2      |   23 +
tests/f_multithread_preen/image.gz      |    1 +
tests/f_multithread_preen/name          |    1 +
tests/f_multithread_preen/script        |    4 +
tests/f_multithread_yes/expect.1        |    2 +
tests/f_multithread_yes/expect.2        |   23 +
tests/f_multithread_yes/image.gz        |    1 +
tests/f_multithread_yes/name            |    1 +
tests/f_multithread_yes/script          |    4 +
tests/test_one.in                       |    8 +
72 files changed, 4186 insertions(+), 433 deletions(-)

create mode 100644 lib/ext2fs/tst_bitmaps_pthread.c create mode 100644 lib/ext2fs/tst_bitmaps_standalone.c create mode 100644 lib/ext2fs/tst_libext2fs_pthread.c create mode 100644 tests/f_multithread/expect.1 create mode 100644 tests/f_multithread/expect.2 create mode 120000 tests/f_multithread/image.gz create mode 100644 tests/f_multithread/name create mode 100644 tests/f_multithread/script create mode 100644 tests/f_multithread_completion/expect.1 create mode 100644 tests/f_multithread_completion/expect.2 create mode 120000 tests/f_multithread_completion/image.gz create mode 100644 tests/f_multithread_completion/name create mode 100644 tests/f_multithread_completion/script create mode 100644 tests/f_multithread_logfile/expect.1 create mode 120000 tests/f_multithread_logfile/image.gz create mode 100644 tests/f_multithread_logfile/name create mode 100644 tests/f_multithread_logfile/script create mode 100644 tests/f_multithread_no/expect.1 create mode 100644 tests/f_multithread_no/expect.2 create mode 120000 tests/f_multithread_no/image.gz create mode 100644 tests/f_multithread_no/name create mode 100644 tests/f_multithread_no/script create mode 100644 tests/f_multithread_ok/expect.1 create mode 100644 tests/f_multithread_ok/image.gz create mode 100644 tests/f_multithread_ok/name create mode 100644 tests/f_multithread_ok/script create mode 100644 tests/f_multithread_preen/expect.1 create mode 100644 tests/f_multithread_preen/expect.2 create mode 120000 tests/f_multithread_preen/image.gz create mode 100644 tests/f_multithread_preen/name create mode 100644 tests/f_multithread_preen/script create mode 100644 tests/f_multithread_yes/expect.1 create mode 100644 tests/f_multithread_yes/expect.2 create mode 120000 tests/f_multithread_yes/image.gz create mode 100644 tests/f_multithread_yes/name create mode 100644 tests/f_multithread_yes/script

--
2.37.3