Viewing: ext4-fix-ext4_inode_attach_jinode.patch
commit 10fa969f87c2c4306a2da2087008f765f8cd0627
Author: Li Dongyang <dongyangli@ddn.com>
AuthorDate: Wed Mar 12 20:28:53 2025 +1100
LU-17950 ldiskfs: race in ext4_inode_attach_jinode
A race condition could happen when multiple threads
trying to attach jinode for the same inode:
Thread 1:
ext4_map_blocks
ext4_inode_attach_jinode
spin_lock(&inode->i_lock)
ei->jinode = jinode
-> jbd2_journal_init_jbd_inode(ei->jinode, inode)
Thread 2:
ext4_map_blocks
ext4_inode_attach_jinode
if (ei->jinode || !EXT4_SB(inode->i_sb)->s_journal)
return 0;
ext4_jbd2_inode_add_write
-> jbd2_journal_file_inode
The problem is in ext4_inode_attach_jinode() the initial check
of ei->jinode is not protected by inode->i_lock,
thread 2 could go ahead and use the not yet initialized jinode
in jbd2_journal_file_inode(), and thread 1 later will
use jbd2_journal_init_jbd_inode, corrupting the jinode.
Note this issue is specific to ldiskfs because of
ext4-attach-jinode-in-writepages.patch added
ext4_inode_attach_jinode() to make sure jinode is initialized
before calling ext4_jbd2_inode_add_write().
Signed-off-by: Li Dongyang <dongyangli@ddn.com>
Reviewed-by: Andreas Dilger <adilger@whamcloud.com>
Reviewed-by: Alex Zhuravlev <bzzz@whamcloud.com>
Reviewed-by: Yang Sheng <ys@whamcloud.com>
Reviewed-by: Oleg Drokin <green@whamcloud.com>
Change-Id: Iafd7aa9537505afbf4bc53fef40ea3aa0a94b7da
Reviewed-on: https://review.whamcloud.com/58381
Index: linux/fs/ext4/inode.c
===================================================================
--- linux.orig/fs/ext4/inode.c
+++ linux/fs/ext4/inode.c
@@ -4461,18 +4461,19 @@ int ext4_inode_attach_jinode(struct inod
struct ext4_inode_info *ei = EXT4_I(inode);
struct jbd2_inode *jinode;
- if (ei->jinode || !EXT4_SB(inode->i_sb)->s_journal)
+ if (READ_ONCE(ei->jinode) || !EXT4_SB(inode->i_sb)->s_journal)
return 0;
- jinode = jbd2_alloc_inode(GFP_KERNEL);
+ jinode = jbd2_alloc_inode(GFP_NOFS);
spin_lock(&inode->i_lock);
- if (!ei->jinode) {
+ if (!READ_ONCE(ei->jinode)) {
if (!jinode) {
spin_unlock(&inode->i_lock);
return -ENOMEM;
}
- ei->jinode = jinode;
- jbd2_journal_init_jbd_inode(ei->jinode, inode);
+ jbd2_journal_init_jbd_inode(jinode, inode);
+ smp_wmb();
+ WRITE_ONCE(ei->jinode, jinode);
jinode = NULL;
}
spin_unlock(&inode->i_lock);