【标题描述】ext4创建软链接时发生abort,日志提交流程中发生空指针解引用
【环境信息】
硬件信息:qemu虚拟机
软件信息:涉及内核版本:OLK-5.10, openEuler-22.03-LTS
【问题复现步骤】
打上内核构造补丁
umount /mnt
mkfs.ext4 -F -b 4096 /dev/sda
mount /dev/sda /mnt
mkdir /mnt/123456789012345678901234567890/1234567890123456789012345678901234567890 -p
touch /mnt/123456789012345678901234567890/1234567890123456789012345678901234567890/file
ln -s /mnt/123456789012345678901234567890/1234567890123456789012345678901234567890/file /mnt/link &
sleep 0.5
mount -o remount,abort /mnt
出现概率(是否必现,概率性错误): 构造后必现
【预期结果】
不发生空指针解引用
【实际结果】
发生空指针解引用
【附件信息】
无
Hi chenxiaosonggitee, welcome to the openEuler Community.
I'm the Bot here serving you. You can find the instructions on how to interact with me at Here.
If you have any questions, please contact the SIG: Kernel, and any of the maintainers: @YangYingliang , @pi3orama , @成坚 (CHENG Jian) , @jiaoff , @zhengzengkai , @Qiuuuuu , @刘勇强 , @Xie XiuQi
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index 1ce13f69fbec..bb4b2fe8968d 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -49,6 +49,7 @@
#include "truncate.h"
#include <trace/events/ext4.h>
+#include <linux/delay.h>
static __u32 ext4_inode_csum(struct inode *inode, struct ext4_inode *raw,
struct ext4_inode_info *ei)
@@ -1261,6 +1262,9 @@ static int write_end_fn(handle_t *handle, struct inode *inode,
if (!buffer_mapped(bh) || buffer_freed(bh))
return 0;
set_buffer_uptodate(bh);
+ printk("%s:%d,jh:%px,bh:%px,begin sleep...\n", __func__, __LINE__, bh2jh(bh), bh);
+ mdelay(2000);
+ printk("%s:%d,jh:%px,bh:%px,end sleep...\n", __func__, __LINE__, bh2jh(bh), bh);
ret = ext4_handle_dirty_metadata(handle, NULL, bh);
clear_buffer_meta(bh);
clear_buffer_prio(bh);
@@ -4034,6 +4038,9 @@ int ext4_punch_hole(struct inode *inode, loff_t offset, loff_t length)
ret = ext4_update_disksize_before_punch(inode, offset, length);
if (ret)
goto out_dio;
+ printk("%s:%d,begin sleep...\n", __func__, __LINE__);
+ mdelay(3000);
+ printk("%s:%d,end sleep...\n", __func__, __LINE__);
truncate_pagecache_range(inode, first_block_offset,
last_block_offset);
}
diff --git a/fs/jbd2/commit.c b/fs/jbd2/commit.c
index 5b9408e3b370..f7a4db3835ee 100644
--- a/fs/jbd2/commit.c
+++ b/fs/jbd2/commit.c
@@ -25,6 +25,7 @@
#include <linux/blkdev.h>
#include <linux/bitops.h>
#include <trace/events/jbd2.h>
+#include <linux/delay.h>
/*
* IO end handler for temporary buffer_heads handling writes to the journal.
@@ -511,6 +512,9 @@ void jbd2_journal_commit_transaction(journal_t *journal)
*/
while (commit_transaction->t_reserved_list) {
jh = commit_transaction->t_reserved_list;
+ printk("%s:%d,jh:%px,bh:%px,begin sleep...\n", __func__, __LINE__, jh, jh2bh(jh));
+ mdelay(5000);
+ printk("%s:%d,jh:%px,bh:%px,end sleep...\n", __func__, __LINE__, jh, jh2bh(jh));
JBUFFER_TRACE(jh, "reserved, unused: refile");
/*
* A jbd2_journal_get_undo_access()+jbd2_journal_release_buffer() may
diff --git a/fs/jbd2/journal.c b/fs/jbd2/journal.c
index fcacafa4510d..9bad5d4b2a84 100644
--- a/fs/jbd2/journal.c
+++ b/fs/jbd2/journal.c
@@ -47,6 +47,7 @@
#include <linux/uaccess.h>
#include <asm/page.h>
+#include <linux/delay.h>
#ifdef CONFIG_JBD2_DEBUG
ushort jbd2_journal_enable_debug __read_mostly;
@@ -2993,6 +2994,11 @@ static void __journal_remove_journal_head(struct buffer_head *bh)
/* Unlink before dropping the lock */
bh->b_private = NULL;
jh->b_bh = NULL; /* debug, really */
+ if (strcmp(current->comm, "fallocate") == 0 || strcmp(current->comm, "ln") == 0) {
+ printk("%s:%d,jh:%px,bh:%px,begin sleep...\n", __func__, __LINE__, jh, bh);
+ mdelay(10000);
+ printk("%s:%d,jh:%px,bh:%px,end sleep...\n", __func__, __LINE__, jh, bh);
+ }
clear_buffer_jbd(bh);
}
--
2.25.1
// 创建软链接发生abort时的流程
symlinkat
do_symlinkat
vfs_symlink
ext4_symlink
__page_symlink
pagecache_write_end
ext4_journalled_write_end
ext4_walk_page_buffers
write_end_fn
ext4_handle_dirty_metadata
__ext4_handle_dirty_metadata
jbd2_journal_dirty_metadata
is_handle_aborted
is_journal_aborted
return journal->j_flags & JBD2_ABORT
return -EROFS
goto err_drop_inode
err_drop_inode:
iput
iput_final
evict
ext4_evict_inode
truncate_inode_pages_final
truncate_inode_pages
truncate_inode_pages_range
truncate_cleanup_folio
folio_invalidate
ext4_journalled_invalidate_folio
__ext4_journalled_invalidate_folio
jbd2_jouranl_invalidate_folio
journal_unmap_buffer
if (transaction == NULL) { // 条件不满足
} else if (transaction == journal->j_committing_transaction) { // 条件也不满足
} else {
may_free = __dispose_buffer
__jbd2_journal_unfile_buffer
__jbd2_journal_temp_unlink_buffer
case BJ_Reserved:
list = &transaction->t_reserved_list
__blist_del_buffer // 从 reserved 链表中删除
jbd2_journal_put_journal_head
if (!jh->b_jcount) // jh->b_jcount == 1
jbd_unlock_bh_journal_head
zap_buffer:
write_unlock(&journal->j_state_lock)
jbd2_journal_put_journal_head
__journal_remove_journal_head
jh->b_bh = NULL
clear_buffer_jbd
// 日志提交流程
kthread
// kthread_run(kjournald2, ...)
kjournald2
jbd2_journal_commit_transaction
while (commit_transaction->t_reserved_list)
// 这时 jh 已经从 reserved list 中删除
jh = commit_transaction->t_reserved_list
主线修复补丁为: 23e3d7f7061f jbd2: fix a potential race while discarding reserved buffers after an abort
登录 后才可以发表评论