[Devel] [PATCH RHEL7 COMMIT] ms/ext4: Avoid freeing inodes on dirty list

Vasily Averin vvs at virtuozzo.com
Fri Feb 5 14:30:31 MSK 2021


The commit is pushed to "branch-rh7-3.10.0-1160.11.1.vz7.172.x-ovz" and will appear at https://src.openvz.org/scm/ovz/vzkernel.git
after rh7-3.10.0-1160.11.1.vz7.172.12
------>
commit 93afd120dc94c83dd12fca7310ef464c223ac36b
Author: Jan Kara <jack at suse.cz>
Date:   Fri Feb 5 14:30:31 2021 +0300

    ms/ext4: Avoid freeing inodes on dirty list
    
    When we are evicting inode with journalled data, we may race with
    transaction commit in the following way:
    
    CPU0					CPU1
    jbd2_journal_commit_transaction()	evict(inode)
    					  inode_io_list_del()
    					  inode_wait_for_writeback()
      process BJ_Forget list
        __jbd2_journal_insert_checkpoint()
        __jbd2_journal_refile_buffer()
          __jbd2_journal_unfile_buffer()
            if (test_clear_buffer_jbddirty(bh))
              mark_buffer_dirty(bh)
    	    __mark_inode_dirty(inode)
    					  ext4_evict_inode(inode)
    					    frees the inode
    
    This results in use-after-free issues in the writeback code (or
    the assertion added in the previous commit triggering).
    
    Fix the problem by removing inode from writeback lists once all the page
    cache is evicted and so inode cannot be added to writeback lists again.
    
    Signed-off-by: Jan Kara <jack at suse.cz>
    Link: https://lore.kernel.org/r/20200421085445.5731-4-jack@suse.cz
    Signed-off-by: Theodore Ts'o <tytso at mit.edu>
    
    (cherry picked from commit ceff86fddae8748fe00d4f2d249cb02cae62ad84)
    Signed-off-by: Konstantin Khorenko <khorenko at virtuozzo.com>
---
 fs/ext4/inode.c | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index f89fdb9..1c8e0cb 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -233,6 +233,16 @@ void ext4_evict_inode(struct inode *inode)
 	truncate_inode_pages_final(&inode->i_data);
 
 	/*
+	 * For inodes with journalled data, transaction commit could have
+	 * dirtied the inode. Flush worker is ignoring it because of I_FREEING
+	 * flag but we still need to remove the inode from the writeback lists.
+	 */
+	if (!list_empty_careful(&inode->i_io_list)) {
+		WARN_ON_ONCE(!ext4_should_journal_data(inode));
+		inode_io_list_del(inode);
+	}
+
+	/*
 	 * Protect us against freezing - iput() caller didn't have to have any
 	 * protection against it
 	 */


More information about the Devel mailing list