ext4: don't use the orphan list when migrating an inode
authorTheodore Ts'o <tytso@mit.edu>
Thu, 6 Jan 2022 04:59:56 +0000 (23:59 -0500)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 27 Jan 2022 07:47:40 +0000 (08:47 +0100)
commit 6eeaf88fd586f05aaf1d48cb3a139d2a5c6eb055 upstream.

We probably want to remove the indirect block to extents migration
feature after a deprecation window, but until then, let's fix a
potential data loss problem caused by the fact that we put the
tmp_inode on the orphan list.  In the unlikely case where we crash and
do a journal recovery, the data blocks belonging to the inode being
migrated are also represented in the tmp_inode on the orphan list ---
and so its data blocks will get marked unallocated, and available for
reuse.

Instead, stop putting the tmp_inode on the oprhan list.  So in the
case where we crash while migrating the inode, we'll leak an inode,
which is not a disaster.  It will be easily fixed the next time we run
fsck, and it's better than potentially having blocks getting claimed
by two different files, and losing data as a result.

Signed-off-by: Theodore Ts'o <tytso@mit.edu>
Reviewed-by: Lukas Czerner <lczerner@redhat.com>
Cc: stable@kernel.org
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
fs/ext4/migrate.c

index f918accde5eca76084bb04b1c8c9b56f66b78777..6967ab3306e7d086d7e670f95dfbc5be16f09821 100644 (file)
@@ -462,12 +462,12 @@ int ext4_ext_migrate(struct inode *inode)
        percpu_down_write(&sbi->s_writepages_rwsem);
 
        /*
-        * Worst case we can touch the allocation bitmaps, a bgd
-        * block, and a block to link in the orphan list.  We do need
-        * need to worry about credits for modifying the quota inode.
+        * Worst case we can touch the allocation bitmaps and a block
+        * group descriptor block.  We do need need to worry about
+        * credits for modifying the quota inode.
         */
        handle = ext4_journal_start(inode, EXT4_HT_MIGRATE,
-               4 + EXT4_MAXQUOTAS_TRANS_BLOCKS(inode->i_sb));
+               3 + EXT4_MAXQUOTAS_TRANS_BLOCKS(inode->i_sb));
 
        if (IS_ERR(handle)) {
                retval = PTR_ERR(handle);
@@ -488,10 +488,6 @@ int ext4_ext_migrate(struct inode *inode)
         * Use the correct seed for checksum (i.e. the seed from 'inode').  This
         * is so that the metadata blocks will have the correct checksum after
         * the migration.
-        *
-        * Note however that, if a crash occurs during the migration process,
-        * the recovery process is broken because the tmp_inode checksums will
-        * be wrong and the orphans cleanup will fail.
         */
        ei = EXT4_I(inode);
        EXT4_I(tmp_inode)->i_csum_seed = ei->i_csum_seed;
@@ -503,7 +499,6 @@ int ext4_ext_migrate(struct inode *inode)
        clear_nlink(tmp_inode);
 
        ext4_ext_tree_init(handle, tmp_inode);
-       ext4_orphan_add(handle, tmp_inode);
        ext4_journal_stop(handle);
 
        /*
@@ -528,12 +523,6 @@ int ext4_ext_migrate(struct inode *inode)
 
        handle = ext4_journal_start(inode, EXT4_HT_MIGRATE, 1);
        if (IS_ERR(handle)) {
-               /*
-                * It is impossible to update on-disk structures without
-                * a handle, so just rollback in-core changes and live other
-                * work to orphan_list_cleanup()
-                */
-               ext4_orphan_del(NULL, tmp_inode);
                retval = PTR_ERR(handle);
                goto out_tmp_inode;
        }