|
Qu Wenruo |
e13003 |
From e0467866198f7f536806f39e5d0d91ae8018de08 Mon Sep 17 00:00:00 2001
|
|
Qu Wenruo |
e13003 |
From: Qu Wenruo <wqu@suse.com>
|
|
Qu Wenruo |
e13003 |
Date: Mon, 26 Jul 2021 14:35:02 +0800
|
|
Qu Wenruo |
e13003 |
Patch-mainline: v5.15-rc1
|
|
Qu Wenruo |
e13003 |
References: jsc#SLE-17681
|
|
Qu Wenruo |
e13003 |
Git-commit: e0467866198f7f536806f39e5d0d91ae8018de08
|
|
Qu Wenruo |
e13003 |
Subject: [PATCH 13/18] btrfs: subpage: fix race between prepare_pages() and
|
|
Qu Wenruo |
e13003 |
btrfs_releasepage()
|
|
Qu Wenruo |
e13003 |
|
|
Qu Wenruo |
e13003 |
[BUG]
|
|
Qu Wenruo |
e13003 |
When running generic/095, there is a high chance to crash with subpage
|
|
Qu Wenruo |
e13003 |
data RW support:
|
|
Qu Wenruo |
e13003 |
|
|
Qu Wenruo |
e13003 |
assertion failed: PagePrivate(page) && page->private
|
|
Qu Wenruo |
e13003 |
------------[ cut here ]------------
|
|
Qu Wenruo |
e13003 |
kernel BUG at fs/btrfs/ctree.h:3403!
|
|
Qu Wenruo |
e13003 |
Internal error: Oops - BUG: 0 [#1] SMP
|
|
Qu Wenruo |
e13003 |
CPU: 1 PID: 3567 Comm: fio Tainted: 5.12.0-rc7-custom+ #17
|
|
Qu Wenruo |
e13003 |
Hardware name: Khadas VIM3 (DT)
|
|
Qu Wenruo |
e13003 |
Call trace:
|
|
Qu Wenruo |
e13003 |
assertfail.constprop.0+0x28/0x2c [btrfs]
|
|
Qu Wenruo |
e13003 |
btrfs_subpage_assert+0x80/0xa0 [btrfs]
|
|
Qu Wenruo |
e13003 |
btrfs_subpage_set_uptodate+0x34/0xec [btrfs]
|
|
Qu Wenruo |
e13003 |
btrfs_page_clamp_set_uptodate+0x74/0xa4 [btrfs]
|
|
Qu Wenruo |
e13003 |
btrfs_dirty_pages+0x160/0x270 [btrfs]
|
|
Qu Wenruo |
e13003 |
btrfs_buffered_write+0x444/0x630 [btrfs]
|
|
Qu Wenruo |
e13003 |
btrfs_direct_write+0x1cc/0x2d0 [btrfs]
|
|
Qu Wenruo |
e13003 |
btrfs_file_write_iter+0xc0/0x160 [btrfs]
|
|
Qu Wenruo |
e13003 |
new_sync_write+0xe8/0x180
|
|
Qu Wenruo |
e13003 |
vfs_write+0x1b4/0x210
|
|
Qu Wenruo |
e13003 |
ksys_pwrite64+0x7c/0xc0
|
|
Qu Wenruo |
e13003 |
__arm64_sys_pwrite64+0x24/0x30
|
|
Qu Wenruo |
e13003 |
el0_svc_common.constprop.0+0x70/0x140
|
|
Qu Wenruo |
e13003 |
do_el0_svc+0x28/0x90
|
|
Qu Wenruo |
e13003 |
el0_svc+0x2c/0x54
|
|
Qu Wenruo |
e13003 |
el0_sync_handler+0x1a8/0x1ac
|
|
Qu Wenruo |
e13003 |
el0_sync+0x170/0x180
|
|
Qu Wenruo |
e13003 |
Code: f0000160 913be042 913c4000 955444bc (d4210000)
|
|
Qu Wenruo |
e13003 |
---[ end trace 3fdd39f4cccedd68 ]---
|
|
Qu Wenruo |
e13003 |
|
|
Qu Wenruo |
e13003 |
[CAUSE]
|
|
Qu Wenruo |
e13003 |
Although prepare_pages() calls find_or_create_page(), which returns the
|
|
Qu Wenruo |
e13003 |
page locked, but in later prepare_uptodate_page() calls, we may call
|
|
Qu Wenruo |
e13003 |
btrfs_readpage() which will unlock the page before it returns.
|
|
Qu Wenruo |
e13003 |
|
|
Qu Wenruo |
e13003 |
This leaves a window where btrfs_releasepage() can sneak in and release
|
|
Qu Wenruo |
e13003 |
the page, clearing page->private and causing above ASSERT().
|
|
Qu Wenruo |
e13003 |
|
|
Qu Wenruo |
e13003 |
[FIX]
|
|
Qu Wenruo |
e13003 |
In prepare_uptodate_page(), we should not only check page->mapping, but
|
|
Qu Wenruo |
e13003 |
also PagePrivate() to ensure we are still holding the correct page which
|
|
Qu Wenruo |
e13003 |
has proper fs context setup.
|
|
Qu Wenruo |
e13003 |
|
|
Qu Wenruo |
e13003 |
Reported-by: Ritesh Harjani <riteshh@linux.ibm.com>
|
|
Qu Wenruo |
e13003 |
Tested-by: Ritesh Harjani <riteshh@linux.ibm.com>
|
|
Qu Wenruo |
e13003 |
Reviewed-by: Filipe Manana <fdmanana@suse.com>
|
|
Qu Wenruo |
e13003 |
Signed-off-by: Qu Wenruo <wqu@suse.com>
|
|
Qu Wenruo |
e13003 |
Signed-off-by: David Sterba <dsterba@suse.com>
|
|
Qu Wenruo |
e13003 |
---
|
|
Qu Wenruo |
e13003 |
fs/btrfs/file.c | 13 ++++++++++++-
|
|
Qu Wenruo |
e13003 |
1 file changed, 12 insertions(+), 1 deletion(-)
|
|
Qu Wenruo |
e13003 |
|
|
Qu Wenruo |
e13003 |
diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c
|
|
Qu Wenruo |
e13003 |
index ee34497500e1..8c57af3702fa 100644
|
|
Qu Wenruo |
e13003 |
--- a/fs/btrfs/file.c
|
|
Qu Wenruo |
e13003 |
+++ b/fs/btrfs/file.c
|
|
Qu Wenruo |
e13003 |
@@ -1340,7 +1340,18 @@ static int prepare_uptodate_page(struct inode *inode,
|
|
Qu Wenruo |
e13003 |
unlock_page(page);
|
|
Qu Wenruo |
e13003 |
return -EIO;
|
|
Qu Wenruo |
e13003 |
}
|
|
Qu Wenruo |
e13003 |
- if (page->mapping != inode->i_mapping) {
|
|
Qu Wenruo |
e13003 |
+
|
|
Qu Wenruo |
e13003 |
+ /*
|
|
Qu Wenruo |
e13003 |
+ * Since btrfs_readpage() will unlock the page before it
|
|
Qu Wenruo |
e13003 |
+ * returns, there is a window where btrfs_releasepage() can
|
|
Qu Wenruo |
e13003 |
+ * be called to release the page.
|
|
Qu Wenruo |
e13003 |
+ * Here we check both inode mapping and PagePrivate() to
|
|
Qu Wenruo |
e13003 |
+ * make sure the page was not released.
|
|
Qu Wenruo |
e13003 |
+ *
|
|
Qu Wenruo |
e13003 |
+ * The private flag check is essential for subpage as we need
|
|
Qu Wenruo |
e13003 |
+ * to store extra bitmap using page->private.
|
|
Qu Wenruo |
e13003 |
+ */
|
|
Qu Wenruo |
e13003 |
+ if (page->mapping != inode->i_mapping || !PagePrivate(page)) {
|
|
Qu Wenruo |
e13003 |
unlock_page(page);
|
|
Qu Wenruo |
e13003 |
return -EAGAIN;
|
|
Qu Wenruo |
e13003 |
}
|
|
Qu Wenruo |
e13003 |
--
|
|
Qu Wenruo |
e13003 |
2.33.0
|
|
Qu Wenruo |
e13003 |
|