401 Star 1.4K Fork 1.3K

GVPopenEuler / kernel

 / 详情

ext4创建软链接时发生abort,日志提交流程中发生空指针解引用

已完成
缺陷
创建于  
2022-06-13 14:56

【标题描述】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

出现概率(是否必现,概率性错误): 构造后必现
【预期结果】
不发生空指针解引用
【实际结果】
发生空指针解引用
【附件信息】

评论 (4)

陈孝松 创建了缺陷

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

openeuler-ci-bot 添加了
 
sig/Kernel
标签

内核构造补丁

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

登录 后才可以发表评论

状态
负责人
项目
里程碑
Pull Requests
关联的 Pull Requests 被合并后可能会关闭此 issue
分支
开始日期   -   截止日期
-
置顶选项
优先级
预计工期 (小时)
参与者(2)
5329419 openeuler ci bot 1632792936
C
1
https://gitee.com/openeuler/kernel.git
git@gitee.com:openeuler/kernel.git
openeuler
kernel
kernel

搜索帮助