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

[BUG]
Since e2fsprog 1.47, even with a newly created empty ext4 filesystem,
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>
Signed-off-by: David Sterba <dsterba@suse.com>
This commit is contained in:
Qu Wenruo 2023-03-23 10:33:59 +08:00 committed by David Sterba
parent 2f8fc64d50
commit f3353a5e85
1 changed files with 11 additions and 2 deletions

View File

@ -903,10 +903,19 @@ 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 +949,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,