diff mbox series

btrfs-progs: convert: handle ext4 orphan file feature properly

Message ID c481f192c76a98d5d750aa42f2d268a9bc20be5f.1679538836.git.wqu@suse.com (mailing list archive)
State New, archived
Headers show
Series btrfs-progs: convert: handle ext4 orphan file feature properly | expand

Commit Message

Qu Wenruo March 23, 2023, 2:33 a.m. UTC
[BUG]
Since e2fsprog 1.47, even a newly created empty ext4, btrfs-convert
would result an fs that btrfs-check would complain:

 # mkfs.ext4 -F test.img
 # btrfs-convert test.img
 # btrfs-check test.img
 Opening filesystem to check...
 Checking filesystem on test.img
 UUID: e45da158-8967-4e4d-9c9f-66b0d127dbce
 [1/7] checking root items
 [2/7] checking extents
 [3/7] checking free space cache
 [4/7] checking fs roots
 root 5 inode 266 errors 2000, link count wrong
 ERROR: errors found in fs roots
 found 26333184 bytes used, error(s) found <<<
 total csum bytes: 25540
 total tree bytes: 180224
 total fs tree bytes: 49152
 total extent tree bytes: 16384
 btree space waste bytes: 145423
 file data blocks allocated: 33947648
  referenced 26284032

[CAUSE]
Ext4 has a new compat feature, COMPAT_ORPHAN_FILE, as a better way to
track all the orphan inodes.

This new feature would create a new special inode for this purpose, and
such orphan file inode would not be reachable from any other inode, but
only from super block.

Unfortunately btrfs-convert only skip ext2 known special inodes, not the
newer one.

[FIX]
According to the kernel document, we can locate the orphan file inode
using ext2 super block s_orphan_file_inum, and skip it for
btrfs-convert.

And such skip would only happen if we have the definition of
EXT4_FEATURE_COMPAT_ORPHAN_FILE, to be compatible with older e2fsprogs.

Signed-off-by: Qu Wenruo <wqu@suse.com>
---
 convert/source-ext2.c | 14 ++++++++++++--
 1 file changed, 12 insertions(+), 2 deletions(-)

Comments

David Sterba March 23, 2023, 6:57 p.m. UTC | #1
On Thu, Mar 23, 2023 at 10:33:59AM +0800, Qu Wenruo wrote:
> [BUG]
> Since e2fsprog 1.47, even a newly created empty ext4, btrfs-convert
> would result an fs that btrfs-check would complain:
> 
>  # mkfs.ext4 -F test.img
>  # btrfs-convert test.img
>  # btrfs-check test.img
>  Opening filesystem to check...
>  Checking filesystem on test.img
>  UUID: e45da158-8967-4e4d-9c9f-66b0d127dbce
>  [1/7] checking root items
>  [2/7] checking extents
>  [3/7] checking free space cache
>  [4/7] checking fs roots
>  root 5 inode 266 errors 2000, link count wrong
>  ERROR: errors found in fs roots
>  found 26333184 bytes used, error(s) found <<<
>  total csum bytes: 25540
>  total tree bytes: 180224
>  total fs tree bytes: 49152
>  total extent tree bytes: 16384
>  btree space waste bytes: 145423
>  file data blocks allocated: 33947648
>   referenced 26284032
> 
> [CAUSE]
> Ext4 has a new compat feature, COMPAT_ORPHAN_FILE, as a better way to
> track all the orphan inodes.
> 
> This new feature would create a new special inode for this purpose, and
> such orphan file inode would not be reachable from any other inode, but
> only from super block.
> 
> Unfortunately btrfs-convert only skip ext2 known special inodes, not the
> newer one.
> 
> [FIX]
> According to the kernel document, we can locate the orphan file inode
> using ext2 super block s_orphan_file_inum, and skip it for
> btrfs-convert.
> 
> And such skip would only happen if we have the definition of
> EXT4_FEATURE_COMPAT_ORPHAN_FILE, to be compatible with older e2fsprogs.
> 
> Signed-off-by: Qu Wenruo <wqu@suse.com>

Added to devel, thanks. I don't have e2fsprogs 1.47 on any testing host
yet, it's stuck in the QA because the change in defaults broke grub2,
but I could update the Tumbleweed CI image to pull packages from the
devel repos.
diff mbox series

Patch

diff --git a/convert/source-ext2.c b/convert/source-ext2.c
index b0b865b99b7b..c8c8930a79e9 100644
--- a/convert/source-ext2.c
+++ b/convert/source-ext2.c
@@ -903,10 +903,20 @@  static int ext2_copy_single_inode(struct btrfs_trans_handle *trans,
 	return btrfs_insert_inode(trans, root, objectid, &btrfs_inode);
 }
 
-static int ext2_is_special_inode(ext2_ino_t ino)
+static bool ext2_is_special_inode(ext2_filsys ext2_fs, ext2_ino_t ino)
 {
 	if (ino < EXT2_GOOD_OLD_FIRST_INO && ino != EXT2_ROOT_INO)
 		return 1;
+#ifdef	EXT4_FEATURE_COMPAT_ORPHAN_FILE
+	/*
+	 * If we have COMPAT_ORPHAN_FILE feature, we have a special inode
+	 * recording all the orphan files.
+	 * We need to skip such special inode.
+	 */
+	if (ext2_fs->super->s_feature_compat & EXT4_FEATURE_COMPAT_ORPHAN_FILE &&
+	    ino == ext2_fs->super->s_orphan_file_inum)
+		return 1;
+#endif
 	return 0;
 }
 
@@ -940,7 +950,7 @@  static int ext2_copy_inodes(struct btrfs_convert_context *cctx,
 		/* no more inodes */
 		if (ext2_ino == 0)
 			break;
-		if (ext2_is_special_inode(ext2_ino))
+		if (ext2_is_special_inode(ext2_fs, ext2_ino))
 			continue;
 		objectid = ext2_ino + INO_OFFSET;
 		ret = ext2_copy_single_inode(trans, root,