[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#988830: [pre-approval] unblock e2fsprogs [Was: Bug#987641: e2fsprogs: FTBFS on armel/armhf with a 64-bit kernel]



Control: tags -1 -moreinfo
thanks

On Sun, Jun 06, 2021 at 06:18:27AM +0200, Paul Gevers wrote:
> On 03-06-2021 22:06, Paul Gevers wrote:
> > As I can't judge this myself, I'll take your word for it. If the upload
> > can happen in the next couple of days, let's have this in unstable and
> > if nothing is reported, have it in bullseye.
> 
> Please removed the moreinfo tag once the package is available.

I've just uploaded the package to unstable.

The debdiff is attached for your convenience.

    	       		      	       - Ted

diff -Nru e2fsprogs-1.46.2/debian/changelog e2fsprogs-1.46.2/debian/changelog
--- e2fsprogs-1.46.2/debian/changelog	2021-02-28 21:24:34.000000000 -0500
+++ e2fsprogs-1.46.2/debian/changelog	2021-06-07 07:27:15.000000000 -0400
@@ -1,3 +1,18 @@
+e2fsprogs (1.46.2-2) unstable; urgency=medium
+
+  * Fix FTBFS on arm32 when building on a system with an arm64 kernel.
+    This also fixes a portability problem when replaying a fast-commit
+    journal on an arm64 kernel when using an arm32 userspace.
+    (Closes: #987641)
+  * Fix additional fast-commit portability problems on non-x86 systems
+    which don't allow non-aligned pointer dereferences (for example, on a
+    sparc64 system).
+  * Fix a missing mutex unlock on an error path which can cause e2fsck
+    to hang on I/O errors.
+  * Clean up and improve the man page for e2image
+
+ -- Theodore Y. Ts'o <tytso@mit.edu>  Mon, 07 Jun 2021 07:27:15 -0400
+
 e2fsprogs (1.46.2-1) unstable; urgency=medium
 
   * New upstream release
diff -Nru e2fsprogs-1.46.2/debian/patches/0001-e2fsck-fix-portability-problems-caused-by-unaligned-.patch e2fsprogs-1.46.2/debian/patches/0001-e2fsck-fix-portability-problems-caused-by-unaligned-.patch
--- e2fsprogs-1.46.2/debian/patches/0001-e2fsck-fix-portability-problems-caused-by-unaligned-.patch	1969-12-31 19:00:00.000000000 -0500
+++ e2fsprogs-1.46.2/debian/patches/0001-e2fsck-fix-portability-problems-caused-by-unaligned-.patch	2021-06-07 07:27:15.000000000 -0400
@@ -0,0 +1,326 @@
+From 40960a7118171498448870b26d1c867f92fa430e Mon Sep 17 00:00:00 2001
+From: Theodore Ts'o <tytso@mit.edu>
+Date: Mon, 3 May 2021 15:37:33 -0400
+Subject: [PATCH 1/5] e2fsck: fix portability problems caused by unaligned
+ accesses
+
+The on-disk format for the ext4 journal can have unaigned 32-bit
+integers.  This can happen when replaying a journal using a obsolete
+checksum format (which was never popularly used, since the v3 format
+replaced v2 while the metadata checksum feature was being stablized),
+and in the fast commit feature (which landed in the 5.10 kernel,
+although it is not enabled by default).
+
+This commit fixes the following regression tests on some platforms
+(such as running 32-bit arm architectures on a 64-bit arm kernel):
+j_recover_csum2_32bit, j_recover_csum2_64bit, j_recover_fast_commit.
+
+https://github.com/tytso/e2fsprogs/issues/65
+
+Addresses-Debian-Bug: #987641
+Signed-off-by: Theodore Ts'o <tytso@mit.edu>
+---
+ e2fsck/journal.c                   | 83 ++++++++++++++++--------------
+ e2fsck/recovery.c                  | 22 ++++----
+ tests/j_recover_fast_commit/script |  1 -
+ 3 files changed, 56 insertions(+), 50 deletions(-)
+
+diff --git a/e2fsck/journal.c b/e2fsck/journal.c
+index a425bbd1..bd0e4f31 100644
+--- a/e2fsck/journal.c
++++ b/e2fsck/journal.c
+@@ -286,9 +286,9 @@ static int ext4_fc_replay_scan(journal_t *j, struct buffer_head *bh,
+ 	int ret = JBD2_FC_REPLAY_CONTINUE;
+ 	struct ext4_fc_add_range *ext;
+ 	struct ext4_fc_tl *tl;
+-	struct ext4_fc_tail *tail;
++	struct ext4_fc_tail tail;
+ 	__u8 *start, *end;
+-	struct ext4_fc_head *head;
++	struct ext4_fc_head head;
+ 	struct ext2fs_extent ext2fs_ex = {0};
+ 
+ 	state = &ctx->fc_replay_state;
+@@ -338,16 +338,15 @@ static int ext4_fc_replay_scan(journal_t *j, struct buffer_head *bh,
+ 			break;
+ 		case EXT4_FC_TAG_TAIL:
+ 			state->fc_cur_tag++;
+-			tail = (struct ext4_fc_tail *)ext4_fc_tag_val(tl);
++			memcpy(&tail, ext4_fc_tag_val(tl), sizeof(tail));
+ 			state->fc_crc = jbd2_chksum(j, state->fc_crc, tl,
+ 						sizeof(*tl) +
+ 						offsetof(struct ext4_fc_tail,
+ 						fc_crc));
+ 			jbd_debug(1, "tail tid %d, expected %d\n",
+-					le32_to_cpu(tail->fc_tid),
+-					expected_tid);
+-			if (le32_to_cpu(tail->fc_tid) == expected_tid &&
+-				le32_to_cpu(tail->fc_crc) == state->fc_crc) {
++				  le32_to_cpu(tail.fc_tid), expected_tid);
++			if (le32_to_cpu(tail.fc_tid) == expected_tid &&
++			    le32_to_cpu(tail.fc_crc) == state->fc_crc) {
+ 				state->fc_replay_num_tags = state->fc_cur_tag;
+ 			} else {
+ 				ret = state->fc_replay_num_tags ?
+@@ -356,13 +355,13 @@ static int ext4_fc_replay_scan(journal_t *j, struct buffer_head *bh,
+ 			state->fc_crc = 0;
+ 			break;
+ 		case EXT4_FC_TAG_HEAD:
+-			head = (struct ext4_fc_head *)ext4_fc_tag_val(tl);
+-			if (le32_to_cpu(head->fc_features) &
+-				~EXT4_FC_SUPPORTED_FEATURES) {
++			memcpy(&head, ext4_fc_tag_val(tl), sizeof(head));
++			if (le32_to_cpu(head.fc_features) &
++			    ~EXT4_FC_SUPPORTED_FEATURES) {
+ 				ret = -EOPNOTSUPP;
+ 				break;
+ 			}
+-			if (le32_to_cpu(head->fc_tid) != expected_tid) {
++			if (le32_to_cpu(head.fc_tid) != expected_tid) {
+ 				ret = -EINVAL;
+ 				break;
+ 			}
+@@ -612,27 +611,31 @@ struct dentry_info_args {
+ 	char *dname;
+ };
+ 
+-static inline void tl_to_darg(struct dentry_info_args *darg,
++static inline int tl_to_darg(struct dentry_info_args *darg,
+ 				struct  ext4_fc_tl *tl)
+ {
+-	struct ext4_fc_dentry_info *fcd;
++	struct ext4_fc_dentry_info fcd;
+ 	int tag = le16_to_cpu(tl->fc_tag);
+ 
+-	fcd = (struct ext4_fc_dentry_info *)ext4_fc_tag_val(tl);
++	memcpy(&fcd, ext4_fc_tag_val(tl), sizeof(fcd));
+ 
+-	darg->parent_ino = le32_to_cpu(fcd->fc_parent_ino);
+-	darg->ino = le32_to_cpu(fcd->fc_ino);
+-	darg->dname = (char *) fcd->fc_dname;
++	darg->parent_ino = le32_to_cpu(fcd.fc_parent_ino);
++	darg->ino = le32_to_cpu(fcd.fc_ino);
+ 	darg->dname_len = ext4_fc_tag_len(tl) -
+ 			sizeof(struct ext4_fc_dentry_info);
+ 	darg->dname = malloc(darg->dname_len + 1);
+-	memcpy(darg->dname, fcd->fc_dname, darg->dname_len);
++	if (!darg->dname)
++		return -ENOMEM;
++	memcpy(darg->dname,
++	       ext4_fc_tag_val(tl) + sizeof(struct ext4_fc_dentry_info),
++	       darg->dname_len);
+ 	darg->dname[darg->dname_len] = 0;
+ 	jbd_debug(1, "%s: %s, ino %d, parent %d\n",
+ 		tag == EXT4_FC_TAG_CREAT ? "create" :
+ 		(tag == EXT4_FC_TAG_LINK ? "link" :
+ 		(tag == EXT4_FC_TAG_UNLINK ? "unlink" : "error")),
+ 		darg->dname, darg->ino, darg->parent_ino);
++	return 0;
+ }
+ 
+ static int ext4_fc_handle_unlink(e2fsck_t ctx, struct ext4_fc_tl *tl)
+@@ -642,7 +645,9 @@ static int ext4_fc_handle_unlink(e2fsck_t ctx, struct ext4_fc_tl *tl)
+ 	ext2_filsys fs = ctx->fs;
+ 	int ret;
+ 
+-	tl_to_darg(&darg, tl);
++	ret = tl_to_darg(&darg, tl);
++	if (ret)
++		return ret;
+ 	ext4_fc_flush_extents(ctx, darg.ino);
+ 	ret = errcode_to_errno(
+ 		       ext2fs_unlink(ctx->fs, darg.parent_ino,
+@@ -659,7 +664,9 @@ static int ext4_fc_handle_link_and_create(e2fsck_t ctx, struct ext4_fc_tl *tl)
+ 	struct ext2_inode_large inode_large;
+ 	int ret, filetype, mode;
+ 
+-	tl_to_darg(&darg, tl);
++	ret = tl_to_darg(&darg, tl);
++	if (ret)
++		return ret;
+ 	ext4_fc_flush_extents(ctx, 0);
+ 	ret = errcode_to_errno(ext2fs_read_inode(fs, darg.ino,
+ 						 (struct ext2_inode *)&inode_large));
+@@ -730,17 +737,18 @@ static int ext4_fc_handle_inode(e2fsck_t ctx, struct ext4_fc_tl *tl)
+ 	struct e2fsck_fc_replay_state *state = &ctx->fc_replay_state;
+ 	int ino, inode_len = EXT2_GOOD_OLD_INODE_SIZE;
+ 	struct ext2_inode_large *inode = NULL, *fc_inode = NULL;
+-	struct ext4_fc_inode *fc_inode_val;
++	__le32 fc_ino;
++	__u8 *fc_raw_inode;
+ 	errcode_t err;
+ 	blk64_t blks;
+ 
+-	fc_inode_val = (struct ext4_fc_inode *)ext4_fc_tag_val(tl);
+-	ino = le32_to_cpu(fc_inode_val->fc_ino);
++	memcpy(&fc_ino, ext4_fc_tag_val(tl), sizeof(fc_ino));
++	fc_raw_inode = ext4_fc_tag_val(tl) + sizeof(fc_ino);
++	ino = le32_to_cpu(fc_ino);
+ 
+ 	if (EXT2_INODE_SIZE(ctx->fs->super) > EXT2_GOOD_OLD_INODE_SIZE)
+ 		inode_len += ext2fs_le16_to_cpu(
+-			((struct ext2_inode_large *)fc_inode_val->fc_raw_inode)
+-				->i_extra_isize);
++			((struct ext2_inode_large *)fc_raw_inode)->i_extra_isize);
+ 	err = ext2fs_get_mem(inode_len, &inode);
+ 	if (err)
+ 		goto out;
+@@ -755,10 +763,10 @@ static int ext4_fc_handle_inode(e2fsck_t ctx, struct ext4_fc_tl *tl)
+ 		goto out;
+ #ifdef WORDS_BIGENDIAN
+ 	ext2fs_swap_inode_full(ctx->fs, fc_inode,
+-			       (struct ext2_inode_large *)fc_inode_val->fc_raw_inode,
++			       (struct ext2_inode_large *)fc_raw_inode,
+ 			       0, sizeof(*inode));
+ #else
+-	memcpy(fc_inode, fc_inode_val->fc_raw_inode, inode_len);
++	memcpy(fc_inode, fc_raw_inode, inode_len);
+ #endif
+ 	memcpy(inode, fc_inode, offsetof(struct ext2_inode_large, i_block));
+ 	memcpy(&inode->i_generation, &fc_inode->i_generation,
+@@ -792,12 +800,11 @@ out:
+ static int ext4_fc_handle_add_extent(e2fsck_t ctx, struct ext4_fc_tl *tl)
+ {
+ 	struct ext2fs_extent extent;
+-	struct ext4_fc_add_range *add_range;
+-	struct ext4_fc_del_range *del_range;
++	struct ext4_fc_add_range add_range;
+ 	int ret = 0, ino;
+ 
+-	add_range = (struct ext4_fc_add_range *)ext4_fc_tag_val(tl);
+-	ino = le32_to_cpu(add_range->fc_ino);
++	memcpy(&add_range, ext4_fc_tag_val(tl), sizeof(add_range));
++	ino = le32_to_cpu(add_range.fc_ino);
+ 	ext4_fc_flush_extents(ctx, ino);
+ 
+ 	ret = ext4_fc_read_extents(ctx, ino);
+@@ -805,8 +812,8 @@ static int ext4_fc_handle_add_extent(e2fsck_t ctx, struct ext4_fc_tl *tl)
+ 		return ret;
+ 	memset(&extent, 0, sizeof(extent));
+ 	ret = errcode_to_errno(ext2fs_decode_extent(
+-			&extent, (void *)(add_range->fc_ex),
+-			sizeof(add_range->fc_ex)));
++			&extent, (void *)add_range.fc_ex,
++			sizeof(add_range.fc_ex)));
+ 	if (ret)
+ 		return ret;
+ 	return ext4_add_extent_to_list(ctx,
+@@ -819,16 +826,16 @@ static int ext4_fc_handle_add_extent(e2fsck_t ctx, struct ext4_fc_tl *tl)
+ static int ext4_fc_handle_del_range(e2fsck_t ctx, struct ext4_fc_tl *tl)
+ {
+ 	struct ext2fs_extent extent;
+-	struct ext4_fc_del_range *del_range;
++	struct ext4_fc_del_range del_range;
+ 	int ret, ino;
+ 
+-	del_range = (struct ext4_fc_del_range *)ext4_fc_tag_val(tl);
+-	ino = le32_to_cpu(del_range->fc_ino);
++	memcpy(&del_range, ext4_fc_tag_val(tl), sizeof(del_range));
++	ino = le32_to_cpu(del_range.fc_ino);
+ 	ext4_fc_flush_extents(ctx, ino);
+ 
+ 	memset(&extent, 0, sizeof(extent));
+-	extent.e_lblk = ext2fs_le32_to_cpu(del_range->fc_lblk);
+-	extent.e_len = ext2fs_le32_to_cpu(del_range->fc_len);
++	extent.e_lblk = le32_to_cpu(del_range.fc_lblk);
++	extent.e_len = le32_to_cpu(del_range.fc_len);
+ 	ret = ext4_fc_read_extents(ctx, ino);
+ 	if (ret)
+ 		return ret;
+diff --git a/e2fsck/recovery.c b/e2fsck/recovery.c
+index dc0694fc..02694d2c 100644
+--- a/e2fsck/recovery.c
++++ b/e2fsck/recovery.c
+@@ -196,7 +196,7 @@ static int jbd2_descriptor_block_csum_verify(journal_t *j, void *buf)
+ static int count_tags(journal_t *journal, struct buffer_head *bh)
+ {
+ 	char *			tagp;
+-	journal_block_tag_t *	tag;
++	journal_block_tag_t	tag;
+ 	int			nr = 0, size = journal->j_blocksize;
+ 	int			tag_bytes = journal_tag_bytes(journal);
+ 
+@@ -206,14 +206,14 @@ static int count_tags(journal_t *journal, struct buffer_head *bh)
+ 	tagp = &bh->b_data[sizeof(journal_header_t)];
+ 
+ 	while ((tagp - bh->b_data + tag_bytes) <= size) {
+-		tag = (journal_block_tag_t *) tagp;
++		memcpy(&tag, tagp, sizeof(tag));
+ 
+ 		nr++;
+ 		tagp += tag_bytes;
+-		if (!(tag->t_flags & cpu_to_be16(JBD2_FLAG_SAME_UUID)))
++		if (!(tag.t_flags & cpu_to_be16(JBD2_FLAG_SAME_UUID)))
+ 			tagp += 16;
+ 
+-		if (tag->t_flags & cpu_to_be16(JBD2_FLAG_LAST_TAG))
++		if (tag.t_flags & cpu_to_be16(JBD2_FLAG_LAST_TAG))
+ 			break;
+ 	}
+ 
+@@ -434,9 +434,9 @@ static int jbd2_commit_block_csum_verify(journal_t *j, void *buf)
+ }
+ 
+ static int jbd2_block_tag_csum_verify(journal_t *j, journal_block_tag_t *tag,
++				      journal_block_tag3_t *tag3,
+ 				      void *buf, __u32 sequence)
+ {
+-	journal_block_tag3_t *tag3 = (journal_block_tag3_t *)tag;
+ 	__u32 csum32;
+ 	__be32 seq;
+ 
+@@ -497,7 +497,7 @@ static int do_one_pass(journal_t *journal,
+ 	while (1) {
+ 		int			flags;
+ 		char *			tagp;
+-		journal_block_tag_t *	tag;
++		journal_block_tag_t	tag;
+ 		struct buffer_head *	obh;
+ 		struct buffer_head *	nbh;
+ 
+@@ -614,8 +614,8 @@ static int do_one_pass(journal_t *journal,
+ 			       <= journal->j_blocksize - descr_csum_size) {
+ 				unsigned long io_block;
+ 
+-				tag = (journal_block_tag_t *) tagp;
+-				flags = be16_to_cpu(tag->t_flags);
++				memcpy(&tag, tagp, sizeof(tag));
++				flags = be16_to_cpu(tag.t_flags);
+ 
+ 				io_block = next_log_block++;
+ 				wrap(journal, next_log_block);
+@@ -633,7 +633,7 @@ static int do_one_pass(journal_t *journal,
+ 
+ 					J_ASSERT(obh != NULL);
+ 					blocknr = read_tag_block(journal,
+-								 tag);
++								 &tag);
+ 
+ 					/* If the block has been
+ 					 * revoked, then we're all done
+@@ -648,8 +648,8 @@ static int do_one_pass(journal_t *journal,
+ 
+ 					/* Look for block corruption */
+ 					if (!jbd2_block_tag_csum_verify(
+-						journal, tag, obh->b_data,
+-						be32_to_cpu(tmp->h_sequence))) {
++			journal, &tag, (journal_block_tag3_t *)tagp,
++			obh->b_data, be32_to_cpu(tmp->h_sequence))) {
+ 						brelse(obh);
+ 						success = -EFSBADCRC;
+ 						printk(KERN_ERR "JBD2: Invalid "
+diff --git a/tests/j_recover_fast_commit/script b/tests/j_recover_fast_commit/script
+index 22ef6325..05c40cc5 100755
+--- a/tests/j_recover_fast_commit/script
++++ b/tests/j_recover_fast_commit/script
+@@ -10,7 +10,6 @@ gunzip < $IMAGE > $TMPFILE
+ EXP=$test_dir/expect
+ OUT=$test_name.log
+ 
+-cp $TMPFILE /tmp/debugthis
+ $FSCK $FSCK_OPT -E journal_only -N test_filesys $TMPFILE 2>/dev/null | head -n 1000 | tail -n +2 > $OUT
+ echo "Exit status is $?" >> $OUT
+ 
+-- 
+2.31.0
+
diff -Nru e2fsprogs-1.46.2/debian/patches/0002-e2fsck-fix-unaligned-accesses-to-ext4_fc_tl-struct.patch e2fsprogs-1.46.2/debian/patches/0002-e2fsck-fix-unaligned-accesses-to-ext4_fc_tl-struct.patch
--- e2fsprogs-1.46.2/debian/patches/0002-e2fsck-fix-unaligned-accesses-to-ext4_fc_tl-struct.patch	1969-12-31 19:00:00.000000000 -0500
+++ e2fsprogs-1.46.2/debian/patches/0002-e2fsck-fix-unaligned-accesses-to-ext4_fc_tl-struct.patch	2021-06-07 07:27:15.000000000 -0400
@@ -0,0 +1,389 @@
+From 440e465618f080b2742fccc3b6ae327e306aeab0 Mon Sep 17 00:00:00 2001
+From: Harshad Shirwadkar <harshadshirwadkar@gmail.com>
+Date: Thu, 6 May 2021 17:21:10 -0700
+Subject: [PATCH 2/5] e2fsck: fix unaligned accesses to ext4_fc_tl struct
+
+Fast commit related struct ext4_fc_tl can be unaligned on disk. So,
+while accessing that we should ensure that the pointers are
+aligned. This patch fixes unaligned accesses to ext4_fc_tl and also
+gets rid of macros fc_for_each_tl and ext4_fc_tag_val that may result
+in unaligned accesses to struct ext4_fc_tl.
+
+Signed-off-by: Harshad Shirwadkar <harshadshirwadkar@gmail.com>
+Signed-off-by: Theodore Ts'o <tytso@mit.edu>
+---
+ debugfs/logdump.c        | 42 ++++++++++----------
+ e2fsck/journal.c         | 82 +++++++++++++++++++++-------------------
+ lib/ext2fs/fast_commit.h | 13 -------
+ 3 files changed, 65 insertions(+), 72 deletions(-)
+
+diff --git a/debugfs/logdump.c b/debugfs/logdump.c
+index 27e2e72d..6aee1a12 100644
+--- a/debugfs/logdump.c
++++ b/debugfs/logdump.c
+@@ -551,24 +551,28 @@ static inline size_t journal_super_tag_bytes(journal_superblock_t *jsb)
+ static void dump_fc_block(FILE *out_file, char *buf, int blocksize,
+ 	int transaction, int *fc_done, int dump_old)
+ {
+-	struct ext4_fc_tl	*tl;
++	struct ext4_fc_tl	tl;
+ 	struct ext4_fc_head	*head;
+ 	struct ext4_fc_add_range	*add_range;
+ 	struct ext4_fc_del_range	*del_range;
+ 	struct ext4_fc_dentry_info	*dentry_info;
+ 	struct ext4_fc_tail		*tail;
+ 	struct ext3_extent	*ex;
++	__u8			*cur, *val;
+ 
+ 	*fc_done = 0;
+-	fc_for_each_tl(buf, buf + blocksize, tl) {
+-		switch (le16_to_cpu(tl->fc_tag)) {
++	for (cur = (__u8 *)buf; cur < (__u8 *)buf + blocksize;
++	     cur = cur + sizeof(tl) + le16_to_cpu(tl.fc_len)) {
++		memcpy(&tl, cur, sizeof(tl));
++		val = cur + sizeof(tl);
++
++		switch (le16_to_cpu(tl.fc_tag)) {
+ 		case EXT4_FC_TAG_ADD_RANGE:
+-			add_range =
+-				(struct ext4_fc_add_range *)ext4_fc_tag_val(tl);
++			add_range = (struct ext4_fc_add_range *)val;
+ 			ex = (struct ext3_extent *)add_range->fc_ex;
+ 			fprintf(out_file,
+ 				"tag %s, inode %d, lblk %u, pblk %llu, len %lu\n",
+-				tag2str(tl->fc_tag),
++				tag2str(tl.fc_tag),
+ 				le32_to_cpu(add_range->fc_ino),
+ 				le32_to_cpu(ex->ee_block),
+ 				le32_to_cpu(ex->ee_start) +
+@@ -578,10 +582,9 @@ static void dump_fc_block(FILE *out_file, char *buf, int blocksize,
+ 				le16_to_cpu(ex->ee_len));
+ 			break;
+ 		case EXT4_FC_TAG_DEL_RANGE:
+-			del_range =
+-				(struct ext4_fc_del_range *)ext4_fc_tag_val(tl);
++			del_range = (struct ext4_fc_del_range *)val;
+ 			fprintf(out_file, "tag %s, inode %d, lblk %d, len %d\n",
+-				tag2str(tl->fc_tag),
++				tag2str(tl.fc_tag),
+ 				le32_to_cpu(del_range->fc_ino),
+ 				le32_to_cpu(del_range->fc_lblk),
+ 				le32_to_cpu(del_range->fc_len));
+@@ -589,29 +592,26 @@ static void dump_fc_block(FILE *out_file, char *buf, int blocksize,
+ 		case EXT4_FC_TAG_LINK:
+ 		case EXT4_FC_TAG_UNLINK:
+ 		case EXT4_FC_TAG_CREAT:
+-			dentry_info =
+-				(struct ext4_fc_dentry_info *)
+-					ext4_fc_tag_val(tl);
++			dentry_info = (struct ext4_fc_dentry_info *)val;
+ 			fprintf(out_file,
+ 				"tag %s, parent %d, ino %d, name \"%s\"\n",
+-				tag2str(tl->fc_tag),
++				tag2str(tl.fc_tag),
+ 				le32_to_cpu(dentry_info->fc_parent_ino),
+ 				le32_to_cpu(dentry_info->fc_ino),
+ 				dentry_info->fc_dname);
+ 			break;
+ 		case EXT4_FC_TAG_INODE:
+ 			fprintf(out_file, "tag %s, inode %d\n",
+-				tag2str(tl->fc_tag),
+-				le32_to_cpu(((struct ext4_fc_inode *)
+-					ext4_fc_tag_val(tl))->fc_ino));
++				tag2str(tl.fc_tag),
++				le32_to_cpu(((struct ext4_fc_inode *)val)->fc_ino));
+ 			break;
+ 		case EXT4_FC_TAG_PAD:
+-			fprintf(out_file, "tag %s\n", tag2str(tl->fc_tag));
++			fprintf(out_file, "tag %s\n", tag2str(tl.fc_tag));
+ 			break;
+ 		case EXT4_FC_TAG_TAIL:
+-			tail = (struct ext4_fc_tail *)ext4_fc_tag_val(tl);
++			tail = (struct ext4_fc_tail *)val;
+ 			fprintf(out_file, "tag %s, tid %d\n",
+-				tag2str(tl->fc_tag),
++				tag2str(tl.fc_tag),
+ 				le32_to_cpu(tail->fc_tid));
+ 			if (!dump_old &&
+ 				le32_to_cpu(tail->fc_tid) < transaction) {
+@@ -621,9 +621,9 @@ static void dump_fc_block(FILE *out_file, char *buf, int blocksize,
+ 			break;
+ 		case EXT4_FC_TAG_HEAD:
+ 			fprintf(out_file, "\n*** Fast Commit Area ***\n");
+-			head = (struct ext4_fc_head *)ext4_fc_tag_val(tl);
++			head = (struct ext4_fc_head *)val;
+ 			fprintf(out_file, "tag %s, features 0x%x, tid %d\n",
+-				tag2str(tl->fc_tag),
++				tag2str(tl.fc_tag),
+ 				le32_to_cpu(head->fc_features),
+ 				le32_to_cpu(head->fc_tid));
+ 			if (!dump_old &&
+diff --git a/e2fsck/journal.c b/e2fsck/journal.c
+index bd0e4f31..ae3df800 100644
+--- a/e2fsck/journal.c
++++ b/e2fsck/journal.c
+@@ -285,9 +285,9 @@ static int ext4_fc_replay_scan(journal_t *j, struct buffer_head *bh,
+ 	struct e2fsck_fc_replay_state *state;
+ 	int ret = JBD2_FC_REPLAY_CONTINUE;
+ 	struct ext4_fc_add_range *ext;
+-	struct ext4_fc_tl *tl;
++	struct ext4_fc_tl tl;
+ 	struct ext4_fc_tail tail;
+-	__u8 *start, *end;
++	__u8 *start, *cur, *end, *val;
+ 	struct ext4_fc_head head;
+ 	struct ext2fs_extent ext2fs_ex = {0};
+ 
+@@ -313,12 +313,15 @@ static int ext4_fc_replay_scan(journal_t *j, struct buffer_head *bh,
+ 	}
+ 
+ 	state->fc_replay_expected_off++;
+-	fc_for_each_tl(start, end, tl) {
++	for (cur = start; cur < end; cur = cur + le16_to_cpu(tl.fc_len) + sizeof(tl)) {
++		memcpy(&tl, cur, sizeof(tl));
++		val = cur + sizeof(tl);
++
+ 		jbd_debug(3, "Scan phase, tag:%s, blk %lld\n",
+-			  tag2str(le16_to_cpu(tl->fc_tag)), bh->b_blocknr);
+-		switch (le16_to_cpu(tl->fc_tag)) {
++			  tag2str(le16_to_cpu(tl.fc_tag)), bh->b_blocknr);
++		switch (le16_to_cpu(tl.fc_tag)) {
+ 		case EXT4_FC_TAG_ADD_RANGE:
+-			ext = (struct ext4_fc_add_range *)ext4_fc_tag_val(tl);
++			ext = (struct ext4_fc_add_range *)val;
+ 			ret = ext2fs_decode_extent(&ext2fs_ex, (void *)&ext->fc_ex,
+ 						   sizeof(ext->fc_ex));
+ 			if (ret)
+@@ -333,14 +336,14 @@ static int ext4_fc_replay_scan(journal_t *j, struct buffer_head *bh,
+ 		case EXT4_FC_TAG_INODE:
+ 		case EXT4_FC_TAG_PAD:
+ 			state->fc_cur_tag++;
+-			state->fc_crc = jbd2_chksum(j, state->fc_crc, tl,
+-					sizeof(*tl) + ext4_fc_tag_len(tl));
++			state->fc_crc = jbd2_chksum(j, state->fc_crc, cur,
++					sizeof(tl) + ext4_fc_tag_len(&tl));
+ 			break;
+ 		case EXT4_FC_TAG_TAIL:
+ 			state->fc_cur_tag++;
+-			memcpy(&tail, ext4_fc_tag_val(tl), sizeof(tail));
+-			state->fc_crc = jbd2_chksum(j, state->fc_crc, tl,
+-						sizeof(*tl) +
++			memcpy(&tail, val, sizeof(tail));
++			state->fc_crc = jbd2_chksum(j, state->fc_crc, cur,
++						sizeof(tl) +
+ 						offsetof(struct ext4_fc_tail,
+ 						fc_crc));
+ 			jbd_debug(1, "tail tid %d, expected %d\n",
+@@ -355,7 +358,7 @@ static int ext4_fc_replay_scan(journal_t *j, struct buffer_head *bh,
+ 			state->fc_crc = 0;
+ 			break;
+ 		case EXT4_FC_TAG_HEAD:
+-			memcpy(&head, ext4_fc_tag_val(tl), sizeof(head));
++			memcpy(&head, val, sizeof(head));
+ 			if (le32_to_cpu(head.fc_features) &
+ 			    ~EXT4_FC_SUPPORTED_FEATURES) {
+ 				ret = -EOPNOTSUPP;
+@@ -366,8 +369,8 @@ static int ext4_fc_replay_scan(journal_t *j, struct buffer_head *bh,
+ 				break;
+ 			}
+ 			state->fc_cur_tag++;
+-			state->fc_crc = jbd2_chksum(j, state->fc_crc, tl,
+-					sizeof(*tl) + ext4_fc_tag_len(tl));
++			state->fc_crc = jbd2_chksum(j, state->fc_crc, cur,
++					sizeof(tl) + ext4_fc_tag_len(&tl));
+ 			break;
+ 		default:
+ 			ret = state->fc_replay_num_tags ?
+@@ -612,12 +615,12 @@ struct dentry_info_args {
+ };
+ 
+ static inline int tl_to_darg(struct dentry_info_args *darg,
+-				struct  ext4_fc_tl *tl)
++			     struct  ext4_fc_tl *tl, __u8 *val)
+ {
+ 	struct ext4_fc_dentry_info fcd;
+ 	int tag = le16_to_cpu(tl->fc_tag);
+ 
+-	memcpy(&fcd, ext4_fc_tag_val(tl), sizeof(fcd));
++	memcpy(&fcd, val, sizeof(fcd));
+ 
+ 	darg->parent_ino = le32_to_cpu(fcd.fc_parent_ino);
+ 	darg->ino = le32_to_cpu(fcd.fc_ino);
+@@ -627,7 +630,7 @@ static inline int tl_to_darg(struct dentry_info_args *darg,
+ 	if (!darg->dname)
+ 		return -ENOMEM;
+ 	memcpy(darg->dname,
+-	       ext4_fc_tag_val(tl) + sizeof(struct ext4_fc_dentry_info),
++	       val + sizeof(struct ext4_fc_dentry_info),
+ 	       darg->dname_len);
+ 	darg->dname[darg->dname_len] = 0;
+ 	jbd_debug(1, "%s: %s, ino %d, parent %d\n",
+@@ -638,14 +641,14 @@ static inline int tl_to_darg(struct dentry_info_args *darg,
+ 	return 0;
+ }
+ 
+-static int ext4_fc_handle_unlink(e2fsck_t ctx, struct ext4_fc_tl *tl)
++static int ext4_fc_handle_unlink(e2fsck_t ctx, struct ext4_fc_tl *tl, __u8 *val)
+ {
+ 	struct ext2_inode inode;
+ 	struct dentry_info_args darg;
+ 	ext2_filsys fs = ctx->fs;
+ 	int ret;
+ 
+-	ret = tl_to_darg(&darg, tl);
++	ret = tl_to_darg(&darg, tl, val);
+ 	if (ret)
+ 		return ret;
+ 	ext4_fc_flush_extents(ctx, darg.ino);
+@@ -657,14 +660,14 @@ static int ext4_fc_handle_unlink(e2fsck_t ctx, struct ext4_fc_tl *tl)
+ 	return ret;
+ }
+ 
+-static int ext4_fc_handle_link_and_create(e2fsck_t ctx, struct ext4_fc_tl *tl)
++static int ext4_fc_handle_link_and_create(e2fsck_t ctx, struct ext4_fc_tl *tl, __u8 *val)
+ {
+ 	struct dentry_info_args darg;
+ 	ext2_filsys fs = ctx->fs;
+ 	struct ext2_inode_large inode_large;
+ 	int ret, filetype, mode;
+ 
+-	ret = tl_to_darg(&darg, tl);
++	ret = tl_to_darg(&darg, tl, val);
+ 	if (ret)
+ 		return ret;
+ 	ext4_fc_flush_extents(ctx, 0);
+@@ -732,7 +735,7 @@ static void ext4_fc_replay_fixup_iblocks(struct ext2_inode_large *ondisk_inode,
+ 	}
+ }
+ 
+-static int ext4_fc_handle_inode(e2fsck_t ctx, struct ext4_fc_tl *tl)
++static int ext4_fc_handle_inode(e2fsck_t ctx, __u8 *val)
+ {
+ 	struct e2fsck_fc_replay_state *state = &ctx->fc_replay_state;
+ 	int ino, inode_len = EXT2_GOOD_OLD_INODE_SIZE;
+@@ -742,8 +745,8 @@ static int ext4_fc_handle_inode(e2fsck_t ctx, struct ext4_fc_tl *tl)
+ 	errcode_t err;
+ 	blk64_t blks;
+ 
+-	memcpy(&fc_ino, ext4_fc_tag_val(tl), sizeof(fc_ino));
+-	fc_raw_inode = ext4_fc_tag_val(tl) + sizeof(fc_ino);
++	memcpy(&fc_ino, val, sizeof(fc_ino));
++	fc_raw_inode = val + sizeof(fc_ino);
+ 	ino = le32_to_cpu(fc_ino);
+ 
+ 	if (EXT2_INODE_SIZE(ctx->fs->super) > EXT2_GOOD_OLD_INODE_SIZE)
+@@ -797,13 +800,13 @@ out:
+ /*
+  * Handle add extent replay tag.
+  */
+-static int ext4_fc_handle_add_extent(e2fsck_t ctx, struct ext4_fc_tl *tl)
++static int ext4_fc_handle_add_extent(e2fsck_t ctx, __u8 *val)
+ {
+ 	struct ext2fs_extent extent;
+ 	struct ext4_fc_add_range add_range;
+ 	int ret = 0, ino;
+ 
+-	memcpy(&add_range, ext4_fc_tag_val(tl), sizeof(add_range));
++	memcpy(&add_range, val, sizeof(add_range));
+ 	ino = le32_to_cpu(add_range.fc_ino);
+ 	ext4_fc_flush_extents(ctx, ino);
+ 
+@@ -823,13 +826,13 @@ static int ext4_fc_handle_add_extent(e2fsck_t ctx, struct ext4_fc_tl *tl)
+ /*
+  * Handle delete logical range replay tag.
+  */
+-static int ext4_fc_handle_del_range(e2fsck_t ctx, struct ext4_fc_tl *tl)
++static int ext4_fc_handle_del_range(e2fsck_t ctx, __u8 *val)
+ {
+ 	struct ext2fs_extent extent;
+ 	struct ext4_fc_del_range del_range;
+ 	int ret, ino;
+ 
+-	memcpy(&del_range, ext4_fc_tag_val(tl), sizeof(del_range));
++	memcpy(&del_range, val, sizeof(del_range));
+ 	ino = le32_to_cpu(del_range.fc_ino);
+ 	ext4_fc_flush_extents(ctx, ino);
+ 
+@@ -854,8 +857,8 @@ static int ext4_fc_replay(journal_t *journal, struct buffer_head *bh,
+ 	e2fsck_t ctx = journal->j_fs_dev->k_ctx;
+ 	struct e2fsck_fc_replay_state *state = &ctx->fc_replay_state;
+ 	int ret = JBD2_FC_REPLAY_CONTINUE;
+-	struct ext4_fc_tl *tl;
+-	__u8 *start, *end;
++	struct ext4_fc_tl tl;
++	__u8 *start, *end, *cur, *val;
+ 
+ 	if (pass == PASS_SCAN) {
+ 		state->fc_current_pass = PASS_SCAN;
+@@ -891,28 +894,31 @@ static int ext4_fc_replay(journal_t *journal, struct buffer_head *bh,
+ 	start = (__u8 *)bh->b_data;
+ 	end = (__u8 *)bh->b_data + journal->j_blocksize - 1;
+ 
+-	fc_for_each_tl(start, end, tl) {
++	for (cur = start; cur < end; cur = cur + le16_to_cpu(tl.fc_len) + sizeof(tl)) {
++		memcpy(&tl, cur, sizeof(tl));
++		val = cur + sizeof(tl);
++
+ 		if (state->fc_replay_num_tags == 0)
+ 			goto replay_done;
+ 		jbd_debug(3, "Replay phase processing %s tag\n",
+-				tag2str(le16_to_cpu(tl->fc_tag)));
++				tag2str(le16_to_cpu(tl.fc_tag)));
+ 		state->fc_replay_num_tags--;
+-		switch (le16_to_cpu(tl->fc_tag)) {
++		switch (le16_to_cpu(tl.fc_tag)) {
+ 		case EXT4_FC_TAG_CREAT:
+ 		case EXT4_FC_TAG_LINK:
+-			ret = ext4_fc_handle_link_and_create(ctx, tl);
++			ret = ext4_fc_handle_link_and_create(ctx, &tl, val);
+ 			break;
+ 		case EXT4_FC_TAG_UNLINK:
+-			ret = ext4_fc_handle_unlink(ctx, tl);
++			ret = ext4_fc_handle_unlink(ctx, &tl, val);
+ 			break;
+ 		case EXT4_FC_TAG_ADD_RANGE:
+-			ret = ext4_fc_handle_add_extent(ctx, tl);
++			ret = ext4_fc_handle_add_extent(ctx, val);
+ 			break;
+ 		case EXT4_FC_TAG_DEL_RANGE:
+-			ret = ext4_fc_handle_del_range(ctx, tl);
++			ret = ext4_fc_handle_del_range(ctx, val);
+ 			break;
+ 		case EXT4_FC_TAG_INODE:
+-			ret = ext4_fc_handle_inode(ctx, tl);
++			ret = ext4_fc_handle_inode(ctx, val);
+ 			break;
+ 		case EXT4_FC_TAG_TAIL:
+ 			ext4_fc_flush_extents(ctx, 0);
+diff --git a/lib/ext2fs/fast_commit.h b/lib/ext2fs/fast_commit.h
+index b83e1810..4ad38f12 100644
+--- a/lib/ext2fs/fast_commit.h
++++ b/lib/ext2fs/fast_commit.h
+@@ -155,13 +155,6 @@ struct ext4_fc_replay_state {
+ #define region_last(__region) (((__region)->lblk) + ((__region)->len) - 1)
+ #endif
+ 
+-#define fc_for_each_tl(__start, __end, __tl)				\
+-	for (tl = (struct ext4_fc_tl *)(__start);			\
+-	     (__u8 *)tl < (__u8 *)(__end);				\
+-		tl = (struct ext4_fc_tl *)((__u8 *)tl +			\
+-					sizeof(struct ext4_fc_tl) +	\
+-					+ le16_to_cpu(tl->fc_len)))
+-
+ static inline const char *tag2str(__u16 tag)
+ {
+ 	switch (tag) {
+@@ -194,10 +187,4 @@ static inline int ext4_fc_tag_len(struct ext4_fc_tl *tl)
+ 	return le16_to_cpu(tl->fc_len);
+ }
+ 
+-/* Get a pointer to "value" of a tlv */
+-static inline __u8 *ext4_fc_tag_val(struct ext4_fc_tl *tl)
+-{
+-	return (__u8 *)tl + sizeof(*tl);
+-}
+-
+ #endif /* __FAST_COMMIT_H__ */
+-- 
+2.31.0
+
diff -Nru e2fsprogs-1.46.2/debian/patches/0003-e2fsck-fix-unaligned-accesses-to-ext4_fc_add_range-a.patch e2fsprogs-1.46.2/debian/patches/0003-e2fsck-fix-unaligned-accesses-to-ext4_fc_add_range-a.patch
--- e2fsprogs-1.46.2/debian/patches/0003-e2fsck-fix-unaligned-accesses-to-ext4_fc_add_range-a.patch	1969-12-31 19:00:00.000000000 -0500
+++ e2fsprogs-1.46.2/debian/patches/0003-e2fsck-fix-unaligned-accesses-to-ext4_fc_add_range-a.patch	2021-06-07 07:27:15.000000000 -0400
@@ -0,0 +1,63 @@
+From 8188d943e51290e7edce0b6e462021504afdf3e6 Mon Sep 17 00:00:00 2001
+From: Theodore Ts'o <tytso@mit.edu>
+Date: Thu, 6 May 2021 22:40:57 -0400
+Subject: [PATCH 3/5] e2fsck: fix unaligned accesses to ext4_fc_add_range and
+ fc_raw_inode
+
+These fast commit related structures can be unaligned on disk.  So we
+need to avoid accessing these structures directly, and first copy
+them to memory which we know is appropriately aligned.
+
+This fixes an e2fsck crash while running the j_recovery_fast_commit
+regression test on a sparc64 system.
+
+Signed-off-by: Theodore Ts'o <tytso@mit.edu>
+---
+ e2fsck/journal.c | 16 +++++++---------
+ 1 file changed, 7 insertions(+), 9 deletions(-)
+
+diff --git a/e2fsck/journal.c b/e2fsck/journal.c
+index ae3df800..0128fbd3 100644
+--- a/e2fsck/journal.c
++++ b/e2fsck/journal.c
+@@ -284,7 +284,7 @@ static int ext4_fc_replay_scan(journal_t *j, struct buffer_head *bh,
+ 	e2fsck_t ctx = j->j_fs_dev->k_ctx;
+ 	struct e2fsck_fc_replay_state *state;
+ 	int ret = JBD2_FC_REPLAY_CONTINUE;
+-	struct ext4_fc_add_range *ext;
++	struct ext4_fc_add_range ext;
+ 	struct ext4_fc_tl tl;
+ 	struct ext4_fc_tail tail;
+ 	__u8 *start, *cur, *end, *val;
+@@ -321,9 +321,10 @@ static int ext4_fc_replay_scan(journal_t *j, struct buffer_head *bh,
+ 			  tag2str(le16_to_cpu(tl.fc_tag)), bh->b_blocknr);
+ 		switch (le16_to_cpu(tl.fc_tag)) {
+ 		case EXT4_FC_TAG_ADD_RANGE:
+-			ext = (struct ext4_fc_add_range *)val;
+-			ret = ext2fs_decode_extent(&ext2fs_ex, (void *)&ext->fc_ex,
+-						   sizeof(ext->fc_ex));
++			memcpy(&ext, val, sizeof(ext));
++			ret = ext2fs_decode_extent(&ext2fs_ex,
++						   (void *)&ext.fc_ex,
++						   sizeof(ext.fc_ex));
+ 			if (ret)
+ 				ret = JBD2_FC_REPLAY_STOP;
+ 			else
+@@ -764,12 +765,9 @@ static int ext4_fc_handle_inode(e2fsck_t ctx, __u8 *val)
+ 					inode_len);
+ 	if (err)
+ 		goto out;
+-#ifdef WORDS_BIGENDIAN
+-	ext2fs_swap_inode_full(ctx->fs, fc_inode,
+-			       (struct ext2_inode_large *)fc_raw_inode,
+-			       0, sizeof(*inode));
+-#else
+ 	memcpy(fc_inode, fc_raw_inode, inode_len);
++#ifdef WORDS_BIGENDIAN
++	ext2fs_swap_inode_full(ctx->fs, fc_inode, fc_inode, 0, inode_len);
+ #endif
+ 	memcpy(inode, fc_inode, offsetof(struct ext2_inode_large, i_block));
+ 	memcpy(&inode->i_generation, &fc_inode->i_generation,
+-- 
+2.31.0
+
diff -Nru e2fsprogs-1.46.2/debian/patches/0004-libext2fs-fix-missing-mutex-unlock-in-an-error-path-.patch e2fsprogs-1.46.2/debian/patches/0004-libext2fs-fix-missing-mutex-unlock-in-an-error-path-.patch
--- e2fsprogs-1.46.2/debian/patches/0004-libext2fs-fix-missing-mutex-unlock-in-an-error-path-.patch	1969-12-31 19:00:00.000000000 -0500
+++ e2fsprogs-1.46.2/debian/patches/0004-libext2fs-fix-missing-mutex-unlock-in-an-error-path-.patch	2021-06-07 07:27:15.000000000 -0400
@@ -0,0 +1,30 @@
+From c9b85b3453d54181cf0bb9beab4056ccff7d1733 Mon Sep 17 00:00:00 2001
+From: Alexander Kanavin <alex.kanavin@gmail.com>
+Date: Fri, 30 Apr 2021 23:45:56 +0200
+Subject: [PATCH 4/5] libext2fs: fix missing mutex unlock in an error path of
+ the Unix I/O manager
+
+Originally from https://github.com/tytso/e2fsprogs/pull/68
+
+Signed-off-by: Alexander Kanavin <alex.kanavin@gmail.com>
+Signed-off-by: Theodore Ts'o <tytso@mit.edu>
+---
+ lib/ext2fs/unix_io.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/lib/ext2fs/unix_io.c b/lib/ext2fs/unix_io.c
+index 64eee342..528c2fbc 100644
+--- a/lib/ext2fs/unix_io.c
++++ b/lib/ext2fs/unix_io.c
+@@ -398,7 +398,7 @@ static errcode_t raw_write_blk(io_channel channel,
+ 		mutex_lock(data, BOUNCE_MTX);
+ 		if (ext2fs_llseek(data->dev, location, SEEK_SET) < 0) {
+ 			retval = errno ? errno : EXT2_ET_LLSEEK_FAILED;
+-			goto error_out;
++			goto error_unlock;
+ 		}
+ 		actual = write(data->dev, buf, size);
+ 		mutex_unlock(data, BOUNCE_MTX);
+-- 
+2.31.0
+
diff -Nru e2fsprogs-1.46.2/debian/patches/0005-e2image-add-OPTIONS-section-to-man-page.patch e2fsprogs-1.46.2/debian/patches/0005-e2image-add-OPTIONS-section-to-man-page.patch
--- e2fsprogs-1.46.2/debian/patches/0005-e2image-add-OPTIONS-section-to-man-page.patch	1969-12-31 19:00:00.000000000 -0500
+++ e2fsprogs-1.46.2/debian/patches/0005-e2image-add-OPTIONS-section-to-man-page.patch	2021-06-07 07:27:15.000000000 -0400
@@ -0,0 +1,504 @@
+From 040cf161ae70c375218ca47ef7e4d3b37316df71 Mon Sep 17 00:00:00 2001
+From: Andreas Dilger <adilger@dilger.ca>
+Date: Tue, 9 Mar 2021 01:35:08 -0700
+Subject: [PATCH 5/5] e2image: add OPTIONS section to man page
+
+Reorganize the e2image.8 man page so that the command-line options
+are listed in a dedicated OPTIONS section, rather than being
+interspersed among the text in the DESCRIPTION section.  Otherwise,
+it is difficult to determine which options are available, and to
+find where each option is described.
+
+Signed-off-by: Andreas Dilger <adilger@dilger.ca>
+Signed-off-by: Theodore Ts'o <tytso@mit.edu>
+---
+ misc/e2image.8.in | 350 ++++++++++++++++++++++++----------------------
+ 1 file changed, 184 insertions(+), 166 deletions(-)
+
+diff --git a/misc/e2image.8.in b/misc/e2image.8.in
+index ef124867..cb176f5d 100644
+--- a/misc/e2image.8.in
++++ b/misc/e2image.8.in
+@@ -1,18 +1,14 @@
+ .\" -*- nroff -*-
+ .\" Copyright 2001 by Theodore Ts'o.  All Rights Reserved.
+ .\" This file may be copied under the terms of the GNU Public License.
+-.\" 
++.\"
+ .TH E2IMAGE 8 "@E2FSPROGS_MONTH@ @E2FSPROGS_YEAR@" "E2fsprogs version @E2FSPROGS_VERSION@"
+ .SH NAME
+ e2image \- Save critical ext2/ext3/ext4 filesystem metadata to a file
++
+ .SH SYNOPSIS
+ .B e2image
+-[
+-.B \-r|\-Q
+-]
+-[
+-.B \-f
+-]
++.RB [ \-r | \-Q " [" \-af ]]
+ [
+ .B \-b
+ .I superblock
+@@ -21,18 +17,8 @@ e2image \- Save critical ext2/ext3/ext4 filesystem metadata to a file
+ .B \-B
+ .I blocksize
+ ]
+-.I device
+-.I image-file
+-.br
+-.B e2image
+-.B \-I
+-.I device
+-.I image-file
+-.br
+-.B e2image
+-.B \-ra
+ [
+-.B \-cfnp
++.B \-cnps
+ ]
+ [
+ .B \-o
+@@ -42,10 +28,14 @@ e2image \- Save critical ext2/ext3/ext4 filesystem metadata to a file
+ .B \-O
+ .I dest_offset
+ ]
+-.I src_fs
+-[
+-.I dest_fs
+-]
++.I device
++.I image-file
++.br
++.B e2image
++.B \-I
++.I device
++.I image-file
++
+ .SH DESCRIPTION
+ The
+ .B e2image
+@@ -59,40 +49,11 @@ and
+ .BR  debugfs ,
+ by using the
+ .B \-i
+-option to those programs.  This can assist an expert in
+-recovering catastrophically corrupted filesystems.  In the future,
+-e2fsck will be enhanced to be able to use the image file to help
+-recover a badly damaged filesystem.
++option to those programs.  This can assist an expert in recovering
++catastrophically corrupted filesystems.
+ .PP
+-When saving an e2image for debugging purposes, using either the
+-.B \-r
+-or
+-.B \-Q
+-options, the filesystem must be unmounted or be mounted read/only, in order
+-for the image file to be in a consistent state.  This requirement can be
+-overridden using the
+-.B \-f
+-option, but the resulting image file is very likely not going to be useful.
+-.PP
+-If
+-.I image-file
+-is \-, then the output of
+-.B e2image
+-will be sent to standard output, so that the output can be piped to
+-another program, such as
+-.BR gzip (1).
+-(Note that this is currently only supported when
+-creating a raw image file using the
+-.B \-r
+-option, since the process of creating a normal image file, or QCOW2
+-image currently
+-requires random access to the file, which cannot be done using a
+-pipe.  This restriction will hopefully be lifted in a future version of
+-.BR e2image .)
+-.PP
+-It is a very good idea to create image files for all of
+-filesystems on a system and save the partition
+-layout (which can be generated using the
++It is a very good idea to create image files for all filesystems on a
++system and save the partition layout (which can be generated using the
+ .B fdisk \-l
+ command) at regular intervals --- at boot time, and/or every week or so.
+ The image file should be stored on some filesystem other than
+@@ -101,31 +62,95 @@ accessible in the case where the filesystem has been badly damaged.
+ .PP
+ To save disk space,
+ .B e2image
+-creates the image file as a sparse file, or in QCOW2 format.
+-Hence, if the sparse image file
+-needs to be copied to another location, it should
++creates the image file as a sparse file, or in QCOW2 format.  Hence, if
++the sparse image file needs to be copied to another location, it should
+ either be compressed first or copied using the
+ .B \-\-sparse=always
+ option to the GNU version of
+-.BR cp .
++.BR cp (1).
+ This does not apply to the QCOW2 image, which is not sparse.
+ .PP
+ The size of an ext2 image file depends primarily on the size of the
+-filesystems and how many inodes are in use.  For a typical 10 gigabyte
+-filesystem, with 200,000 inodes in use out of 1.2 million inodes, the
+-image file will be approximately 35 megabytes; a 4 gigabyte filesystem with
+-15,000 inodes in use out of 550,000 inodes will result in a 3 megabyte
+-image file.  Image files tend to be quite
+-compressible; an image file taking up 32 megabytes of space on
+-disk will generally compress down to 3 or 4 megabytes.
++filesystems and how many inodes are in use.  For a typical 10 Gigabyte
++filesystem, with 200,000 inodes in use out of 1.2 million inodes, the image
++file will be approximately 35 Megabytes; a 4 Gigabyte filesystem with 15,000
++inodes in use out of 550,000 inodes will result in a 3 Megabyte image file.
++Image files tend to be quite compressible; an image file taking up 32 Megabytes
++of space on disk will generally compress down to 3 or 4 Megabytes.
+ .PP
+-.SH RESTORING FILESYSTEM METADATA USING AN IMAGE FILE
+-.PP
+-The
++If
++.I image-file
++is
++.BR \- ,
++then the output of
++.B e2image
++will be sent to standard output, so that the output can be piped to
++another program, such as
++.BR gzip (1).
++(Note that this is currently only supported when
++creating a raw image file using the
++.B \-r
++option, since the process of creating a normal image file, or QCOW2
++image currently
++requires random access to the file, which cannot be done using a
++pipe.
++
++.SH OPTIONS
++.TP
++.B \-a
++Include file data in the image file.  Normally
++.B e2image
++only includes fs metadata, not regular file data.  This option will
++produce an image that is suitable to use to clone the entire FS or
++for backup purposes.  Note that this option only works with the
++raw
++.RI ( \-r )
++or QCOW2
++.RI ( \-Q )
++formats.  In conjunction with the
++.B \-r
++option it is possible to clone all and only the used blocks of one
++filesystem to another device/image file.
++.TP
++.BI \-b " superblock"
++Get image from partition with broken primary superblock by using
++the superblock located at filesystem block number
++.IR superblock .
++The partition is copied as-is including broken primary superblock.
++.TP
++.BI \-B " blocksize"
++Set the filesystem blocksize in bytes.  Normally,
++.B e2image
++will search for the superblock at various different block sizes in an
++attempt to find the appropriate blocksize. This search can be fooled in
++some cases.  This option forces e2fsck to only try locating the superblock
++with a particular blocksize. If the superblock is not found, e2image will
++terminate with a fatal error.
++.TP
++.BI \-c
++Compare each block to be copied from the source
++.I device
++to the corresponding block in the target
++.IR image-file .
++If both are already the same, the write will be skipped.  This is
++useful if the file system is being cloned to a flash-based storage device
++(where reads are very fast and where it is desirable to avoid unnecessary
++writes to reduce write wear on the device).
++.TP
++.B \-f
++Override the read-only requirement for the source filesystem when saving
++the image file using the
++.B \-r
++and
++.B \-Q
++options.  Normally, if the source filesystem is in use, the resulting image
++file is very likely not going to be useful. In some cases where the source
++filesystem is in constant use this may be better than no image at all.
++.TP
+ .B \-I
+-option will cause e2image to install the metadata stored in the image
+-file back to the device.  It can be used to restore the filesystem metadata
+-back to the device in emergency situations.
++install the metadata stored in the image file back to the device.
++It can be used to restore the filesystem metadata back to the device
++in emergency situations.
+ .PP
+ .B WARNING!!!!
+ The
+@@ -134,29 +159,76 @@ option should only be used as a desperation measure when other
+ alternatives have failed.  If the filesystem has changed since the image
+ file was created, data
+ .B will
+-be lost.  In general, you should make a full image
+-backup of the filesystem first, in case you wish to try other recovery
+-strategies afterwards.
+-.PP
++be lost.  In general, you should make another full image backup of the
++filesystem first, in case you wish to try other recovery strategies afterward.
++.TP
++.B \-n
++Cause all image writes to be skipped, and instead only print the block
++numbers that would have been written.
++.TP
++.BI \-o " src_offset"
++Specify offset of the image to be read from the start of the source
++.I device
++in bytes.  See
++.B OFFSETS
++for more details.
++.TP
++.BI \-O " tgt_offset"
++Specify offset of the image to be written from the start of the target
++.I image-file
++in bytes.  See
++.B OFFSETS
++for more details.
++.TP
++.B \-p
++Show progress of image-file creation.
++.TP
++.B \-Q
++Create a QCOW2-format image file instead of a normal image file, suitable
++for use by virtual machine images, and other tools that can use the
++.B .qcow
++image format. See
++.B QCOW2 IMAGE FILES
++below for details.
++.TP
++.B \-r
++Create a raw image file instead of a normal image file.  See
++.B RAW IMAGE FILES
++below for details.
++.TP
++.B \-s
++Scramble directory entries and zero out unused portions of the directory
++blocks in the written image file to avoid revealing information about
++the contents of the filesystem.  However, this will prevent analysis of
++problems related to hash-tree indexed directories.
++
+ .SH RAW IMAGE FILES
+ The
+ .B \-r
+-option will create a raw image file instead of a normal image file.
+-A raw image file differs
++option will create a raw image file, which differs
+ from a normal image file in two ways.  First, the filesystem metadata is
+-placed in the proper position so that e2fsck, dumpe2fs, debugfs,
+-etc.\& can be run directly on the raw image file.  In order to minimize
+-the amount of disk space consumed by a raw image file, the file is
++placed in the same relative offset within
++.I image-file
++as it is in the
++.I device
++so that
++.BR debugfs (8),
++.BR dumpe2fs (8),
++.BR e2fsck (8),
++.BR losetup (8),
++etc. and can be run directly on the raw image file.  In order to minimize
++the amount of disk space consumed by the raw image file, it is
+ created as a sparse file.  (Beware of copying or
+ compressing/decompressing this file with utilities that don't understand
+ how to create sparse files; the file will become as large as the
+ filesystem itself!)  Secondly, the raw image file also includes indirect
+-blocks and directory blocks, which the standard image file does not have,
+-although this may change in the future.
++blocks and directory blocks, which the standard image file does not have.
+ .PP
+ Raw image files are sometimes used when sending filesystems to the maintainer
+ as part of bug reports to e2fsprogs.  When used in this capacity, the
+-recommended command is as follows (replace hda1 with the appropriate device):
++recommended command is as follows (replace
++.B hda1
++with the appropriate device for your system):
+ .PP
+ .br
+ 	\fBe2image \-r /dev/hda1 \- | bzip2 > hda1.e2i.bz2\fR
+@@ -166,46 +238,27 @@ However, the filenames in the directory blocks can still reveal
+ information about the contents of the filesystem that the bug reporter
+ may wish to keep confidential.  To address this concern, the
+ .B \-s
+-option can be specified.  This will cause
+-.B e2image
+-to scramble directory entries and zero out any unused portions
+-of the directory blocks before writing the image file.  However,
+-the
+-.B \-s
+-option will prevent analysis of problems related to hash-tree indexed
+-directories.
++option can be specified to scramble the filenames in the image.
+ .PP
+-Option
+-.B \-b
+-.I superblock
+-can be used to get image from partition with broken primary superblock.
+-The partition is copied as-is including broken primary superblock.
+-.PP
+-Option
+-.B \-B
+-.I blocksize
+-can be used to set superblock block size. Normally, e2fsck will search
+-for the superblock at various different block sizes in an attempt to find
+-the appropriate blocksize. This search can be fooled in some cases.  This
+-option forces e2fsck to only try locating the superblock at a particular
+-blocksize. If the superblock is not found, e2fsck will terminate with a
+-fatal error.
+-.PP
+-Note that this will work even if you substitute "/dev/hda1" for another raw
++Note that this will work even if you substitute
++.B /dev/hda1
++for another raw
+ disk image, or QCOW2 image previously created by
+ .BR e2image .
+-.PP
++
+ .SH QCOW2 IMAGE FILES
+ The
+ .B \-Q
+ option will create a QCOW2 image file instead of a normal, or raw image file.
+ A QCOW2 image contains all the information the raw image does, however unlike
+-the raw image it is not sparse. The QCOW2 image minimize the amount of disk
+-space by storing data in special format with pack data closely together, hence
+-avoiding holes while still minimizing size.
++the raw image it is not sparse. The QCOW2 image minimize the amount of space
++used by the image by storing it in special format which packs data closely
++together, hence avoiding holes while still minimizing size.
+ .PP
+ In order to send filesystem to the maintainer as a part of bug report to
+-e2fsprogs, use following commands (replace hda1 with the appropriate device):
++e2fsprogs, use following commands (replace
++.B hda1
++with the appropriate device for your system):
+ .PP
+ .br
+ \	\fBe2image \-Q /dev/hda1 hda1.qcow2\fR
+@@ -213,66 +266,28 @@ e2fsprogs, use following commands (replace hda1 with the appropriate device):
+ \	\fBbzip2 -z hda1.qcow2\fR
+ .PP
+ This will only send the metadata information, without any data blocks.
+-However, the filenames in the directory blocks can still reveal
+-information about the contents of the filesystem that the bug reporter
+-may wish to keep confidential.  To address this concern, the
+-.B \-s
+-option can be specified.  This will cause
+-.B e2image
+-to scramble directory entries and zero out any unused portions
+-of the directory blocks before writing the image file.  However, the
++As described for
++.B RAW IMAGE FILES
++the
+ .B \-s
+-option will prevent analysis of problems related to hash-tree indexed
+-directories.
++option can be specified to scramble the filesystem names in the image.
+ .PP
+-Note that QCOW2 image created by
++Note that the QCOW2 image created by
+ .B e2image
+-is regular QCOW2 image and can be processed by tools aware of QCOW2 format
++is a regular QCOW2 image and can be processed by tools aware of QCOW2 format
+ such as for example
+ .BR qemu-img .
+ .PP
+-You can convert a qcow2 image into a raw image with:
++You can convert a .qcow2 image into a raw image with:
+ .PP
+ .br
+ \	\fBe2image \-r hda1.qcow2 hda1.raw\fR
+ .br
+ .PP
+-This can be useful to write a qcow2 image containing all data to a
++This can be useful to write a QCOW2 image containing all data to a
+ sparse image file where it can be loop mounted, or to a disk partition.
+-Note that this may not work with qcow2 images not generated by e2image.
+-.PP
+-Options
+-.B \-b
+-.I superblock
+-and
+-.B \-B
+-.I blocksize
+-can be used same way as for raw images.
+-.PP
+-.SH INCLUDING DATA
+-Normally
+-.B e2image
+-only includes fs metadata, not regular file data.  The
+-.B \-a
+-option can be specified to include all data.  This will
+-give an image that is suitable to use to clone the entire FS or
+-for backup purposes.  Note that this option only works with the
+-raw or QCOW2 formats.  The
+-.B \-p
+-switch may be given to show progress.  If the file system is being
+-cloned to a flash-based storage device (where reads are very fast and
+-where it is desirable to avoid unnecessary writes to reduce write wear
+-on the device), the
+-.B \-c
+-option which cause e2image to try reading a block from the destination
+-to see if it is identical to the block which
+-.B e2image
+-is about to copy.  If the block is already the same, the write can be
+-skipped.  The
+-.B \-n
+-option will cause all of the writes to be no-ops, and print the blocks
+-that would have been written.
+-.PP
++Note that this may not work with QCOW2 images not generated by e2image.
++
+ .SH OFFSETS
+ Normally a filesystem starts at the beginning of a partition, and
+ .B e2image
+@@ -288,14 +303,14 @@ before writing the filesystem.
+ For example, if you have a
+ .B dd
+ image of a whole hard drive that contains an ext2 fs in a partition
+-starting at 1 MiB, you can clone that fs with:
++starting at 1 MiB, you can clone that image to a block device with:
+ .PP
+ .br
+ \	\fBe2image \-aro 1048576 img /dev/sda1\fR
+ .br
+ .PP
+-Or you can clone a fs into an image file, leaving room in the first
+-MiB for a partition table with:
++Or you can clone a filesystem from a block device into an image file,
++leaving room in the first MiB for a partition table with:
+ .PP
+ .br
+ \	\fBe2image -arO 1048576 /dev/sda1 img\fR
+@@ -304,14 +319,17 @@ MiB for a partition table with:
+ If you specify at least one offset, and only one file, an in-place
+ move will be performed, allowing you to safely move the filesystem
+ from one offset to another.
++
+ .SH AUTHOR
+ .B e2image
+ was written by Theodore Ts'o (tytso@mit.edu).
++
+ .SH AVAILABILITY
+ .B e2image
+ is part of the e2fsprogs package and is available from
+ http://e2fsprogs.sourceforge.net.
++
+ .SH SEE ALSO
+ .BR dumpe2fs (8),
+ .BR debugfs (8)
+-
++.BR e2fsck (8)
+-- 
+2.31.0
+
diff -Nru e2fsprogs-1.46.2/debian/patches/series e2fsprogs-1.46.2/debian/patches/series
--- e2fsprogs-1.46.2/debian/patches/series	1969-12-31 19:00:00.000000000 -0500
+++ e2fsprogs-1.46.2/debian/patches/series	2021-06-07 07:27:15.000000000 -0400
@@ -0,0 +1,5 @@
+0001-e2fsck-fix-portability-problems-caused-by-unaligned-.patch
+0002-e2fsck-fix-unaligned-accesses-to-ext4_fc_tl-struct.patch
+0003-e2fsck-fix-unaligned-accesses-to-ext4_fc_add_range-a.patch
+0004-libext2fs-fix-missing-mutex-unlock-in-an-error-path-.patch
+0005-e2image-add-OPTIONS-section-to-man-page.patch

Reply to: