ext4: don't use the orphan list when migrating an inode
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>
This commit is contained in:

committed by
Greg Kroah-Hartman

parent
679fb06532
commit
0ca7ec6db2
@@ -437,12 +437,12 @@ int ext4_ext_migrate(struct inode *inode)
|
|||||||
percpu_down_write(&sbi->s_writepages_rwsem);
|
percpu_down_write(&sbi->s_writepages_rwsem);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Worst case we can touch the allocation bitmaps, a bgd
|
* Worst case we can touch the allocation bitmaps and a block
|
||||||
* block, and a block to link in the orphan list. We do need
|
* group descriptor block. We do need need to worry about
|
||||||
* need to worry about credits for modifying the quota inode.
|
* credits for modifying the quota inode.
|
||||||
*/
|
*/
|
||||||
handle = ext4_journal_start(inode, EXT4_HT_MIGRATE,
|
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)) {
|
if (IS_ERR(handle)) {
|
||||||
retval = PTR_ERR(handle);
|
retval = PTR_ERR(handle);
|
||||||
@@ -463,10 +463,6 @@ int ext4_ext_migrate(struct inode *inode)
|
|||||||
* Use the correct seed for checksum (i.e. the seed from 'inode'). This
|
* 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
|
* is so that the metadata blocks will have the correct checksum after
|
||||||
* the migration.
|
* 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);
|
ei = EXT4_I(inode);
|
||||||
EXT4_I(tmp_inode)->i_csum_seed = ei->i_csum_seed;
|
EXT4_I(tmp_inode)->i_csum_seed = ei->i_csum_seed;
|
||||||
@@ -478,7 +474,6 @@ int ext4_ext_migrate(struct inode *inode)
|
|||||||
clear_nlink(tmp_inode);
|
clear_nlink(tmp_inode);
|
||||||
|
|
||||||
ext4_ext_tree_init(handle, tmp_inode);
|
ext4_ext_tree_init(handle, tmp_inode);
|
||||||
ext4_orphan_add(handle, tmp_inode);
|
|
||||||
ext4_journal_stop(handle);
|
ext4_journal_stop(handle);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -503,12 +498,6 @@ int ext4_ext_migrate(struct inode *inode)
|
|||||||
|
|
||||||
handle = ext4_journal_start(inode, EXT4_HT_MIGRATE, 1);
|
handle = ext4_journal_start(inode, EXT4_HT_MIGRATE, 1);
|
||||||
if (IS_ERR(handle)) {
|
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);
|
retval = PTR_ERR(handle);
|
||||||
goto out_tmp_inode;
|
goto out_tmp_inode;
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user