* [PATCH AUTOSEL 5.4 081/109] btrfs: subpage: check if there are compressed extents inside one page
[not found] <20210909115507.147917-1-sashal@kernel.org>
@ 2021-09-09 11:54 ` Sasha Levin
2021-09-09 13:00 ` David Sterba
2021-09-09 11:54 ` [PATCH AUTOSEL 5.4 082/109] btrfs: subpage: fix race between prepare_pages() and btrfs_releasepage() Sasha Levin
2021-09-09 11:54 ` [PATCH AUTOSEL 5.4 083/109] btrfs: tree-log: check btrfs_lookup_data_extent return value Sasha Levin
2 siblings, 1 reply; 5+ messages in thread
From: Sasha Levin @ 2021-09-09 11:54 UTC (permalink / raw)
To: linux-kernel, stable; +Cc: Qu Wenruo, David Sterba, Sasha Levin, linux-btrfs
From: Qu Wenruo <wqu@suse.com>
[ Upstream commit 3670e6451bc9c39ab3a46f1da19360219e4319f3 ]
[BUG]
When testing experimental subpage compressed write support, it hits a
NULL pointer dereference inside read path:
Unable to handle kernel NULL pointer dereference at virtual address 0000000000000018
pc : __pi_memcmp+0x28/0x1ec
lr : check_data_csum+0xd0/0x274 [btrfs]
Call trace:
__pi_memcmp+0x28/0x1ec
btrfs_verify_data_csum+0xf4/0x244 [btrfs]
end_bio_extent_readpage+0x1d0/0x6b0 [btrfs]
bio_endio+0x15c/0x1dc
end_workqueue_fn+0x44/0x64 [btrfs]
btrfs_work_helper+0x74/0x250 [btrfs]
process_one_work+0x1d4/0x47c
worker_thread+0x180/0x400
kthread+0x11c/0x120
ret_from_fork+0x10/0x30
Code: 54000261 d100044c d343fd8c f8408403 (f8408424)
---[ end trace 9e2c59f33ea40866 ]---
[CAUSE]
When reading two compressed extents inside the same page, like the
following layout, we trigger above crash:
0 32K 64K
|-------|\\\\\\\|
| \- Compressed extent (A)
\--------- Compressed extent (B)
For compressed read, we don't need to populate its io_bio->csum, as we
rely on compressed_bio->csum to verify the compressed data, and then
copy the decompressed to inode pages.
Normally btrfs_verify_data_csum() skip such page by checking and
clearing its PageChecked flag
But since that flag is still for the full page, when endio for inode
page range [0, 32K) gets executed, it clears PageChecked flag for the
full page.
Then when endio for inode page range [32K, 64K) gets executed, since the
page no longer has PageChecked flag, it just continues checking, even
though io_bio->csum is NULL.
[FIX]
Thankfully there are only two users of PageChecked bit:
- Cow fixup
Since subpage has its own way to trace page dirty (dirty_bitmap) and
ordered bit (ordered_bitmap), it should never trigger cow fixup.
- Compressed read
We can distinguish such read by just checking io_bio->csum.
So just check io_bio->csum before doing the verification to avoid such
NULL pointer dereference.
Signed-off-by: Qu Wenruo <wqu@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/btrfs/inode.c | 14 ++++++++++++++
1 file changed, 14 insertions(+)
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index 29552d4f6845..b775af634403 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -3510,6 +3510,20 @@ static int btrfs_readpage_end_io_hook(struct btrfs_io_bio *io_bio,
return 0;
}
+ /*
+ * For subpage case, above PageChecked is not safe as it's not subpage
+ * compatible.
+ * But for now only cow fixup and compressed read utilize PageChecked
+ * flag, while in this context we can easily use io_bio->csum to
+ * determine if we really need to do csum verification.
+ *
+ * So for now, just exit if io_bio->csum is NULL, as it means it's
+ * compressed read, and its compressed data csum has already been
+ * verified.
+ */
+ if (io_bio->csum == NULL)
+ return 0;
+
if (BTRFS_I(inode)->flags & BTRFS_INODE_NODATASUM)
return 0;
--
2.30.2
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH AUTOSEL 5.4 082/109] btrfs: subpage: fix race between prepare_pages() and btrfs_releasepage()
[not found] <20210909115507.147917-1-sashal@kernel.org>
2021-09-09 11:54 ` [PATCH AUTOSEL 5.4 081/109] btrfs: subpage: check if there are compressed extents inside one page Sasha Levin
@ 2021-09-09 11:54 ` Sasha Levin
2021-09-09 13:00 ` David Sterba
2021-09-09 11:54 ` [PATCH AUTOSEL 5.4 083/109] btrfs: tree-log: check btrfs_lookup_data_extent return value Sasha Levin
2 siblings, 1 reply; 5+ messages in thread
From: Sasha Levin @ 2021-09-09 11:54 UTC (permalink / raw)
To: linux-kernel, stable
Cc: Qu Wenruo, Ritesh Harjani, Filipe Manana, David Sterba,
Sasha Levin, linux-btrfs
From: Qu Wenruo <wqu@suse.com>
[ Upstream commit e0467866198f7f536806f39e5d0d91ae8018de08 ]
[BUG]
When running generic/095, there is a high chance to crash with subpage
data RW support:
assertion failed: PagePrivate(page) && page->private
------------[ cut here ]------------
kernel BUG at fs/btrfs/ctree.h:3403!
Internal error: Oops - BUG: 0 [#1] SMP
CPU: 1 PID: 3567 Comm: fio Tainted: 5.12.0-rc7-custom+ #17
Hardware name: Khadas VIM3 (DT)
Call trace:
assertfail.constprop.0+0x28/0x2c [btrfs]
btrfs_subpage_assert+0x80/0xa0 [btrfs]
btrfs_subpage_set_uptodate+0x34/0xec [btrfs]
btrfs_page_clamp_set_uptodate+0x74/0xa4 [btrfs]
btrfs_dirty_pages+0x160/0x270 [btrfs]
btrfs_buffered_write+0x444/0x630 [btrfs]
btrfs_direct_write+0x1cc/0x2d0 [btrfs]
btrfs_file_write_iter+0xc0/0x160 [btrfs]
new_sync_write+0xe8/0x180
vfs_write+0x1b4/0x210
ksys_pwrite64+0x7c/0xc0
__arm64_sys_pwrite64+0x24/0x30
el0_svc_common.constprop.0+0x70/0x140
do_el0_svc+0x28/0x90
el0_svc+0x2c/0x54
el0_sync_handler+0x1a8/0x1ac
el0_sync+0x170/0x180
Code: f0000160 913be042 913c4000 955444bc (d4210000)
---[ end trace 3fdd39f4cccedd68 ]---
[CAUSE]
Although prepare_pages() calls find_or_create_page(), which returns the
page locked, but in later prepare_uptodate_page() calls, we may call
btrfs_readpage() which will unlock the page before it returns.
This leaves a window where btrfs_releasepage() can sneak in and release
the page, clearing page->private and causing above ASSERT().
[FIX]
In prepare_uptodate_page(), we should not only check page->mapping, but
also PagePrivate() to ensure we are still holding the correct page which
has proper fs context setup.
Reported-by: Ritesh Harjani <riteshh@linux.ibm.com>
Tested-by: Ritesh Harjani <riteshh@linux.ibm.com>
Reviewed-by: Filipe Manana <fdmanana@suse.com>
Signed-off-by: Qu Wenruo <wqu@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/btrfs/file.c | 13 ++++++++++++-
1 file changed, 12 insertions(+), 1 deletion(-)
diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c
index 1279359ed172..0af696ba5051 100644
--- a/fs/btrfs/file.c
+++ b/fs/btrfs/file.c
@@ -1407,7 +1407,18 @@ static int prepare_uptodate_page(struct inode *inode,
unlock_page(page);
return -EIO;
}
- if (page->mapping != inode->i_mapping) {
+
+ /*
+ * Since btrfs_readpage() will unlock the page before it
+ * returns, there is a window where btrfs_releasepage() can
+ * be called to release the page.
+ * Here we check both inode mapping and PagePrivate() to
+ * make sure the page was not released.
+ *
+ * The private flag check is essential for subpage as we need
+ * to store extra bitmap using page->private.
+ */
+ if (page->mapping != inode->i_mapping || !PagePrivate(page)) {
unlock_page(page);
return -EAGAIN;
}
--
2.30.2
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH AUTOSEL 5.4 083/109] btrfs: tree-log: check btrfs_lookup_data_extent return value
[not found] <20210909115507.147917-1-sashal@kernel.org>
2021-09-09 11:54 ` [PATCH AUTOSEL 5.4 081/109] btrfs: subpage: check if there are compressed extents inside one page Sasha Levin
2021-09-09 11:54 ` [PATCH AUTOSEL 5.4 082/109] btrfs: subpage: fix race between prepare_pages() and btrfs_releasepage() Sasha Levin
@ 2021-09-09 11:54 ` Sasha Levin
2 siblings, 0 replies; 5+ messages in thread
From: Sasha Levin @ 2021-09-09 11:54 UTC (permalink / raw)
To: linux-kernel, stable
Cc: Marcos Paulo de Souza, Filipe Manana, David Sterba, Sasha Levin,
linux-btrfs
From: Marcos Paulo de Souza <mpdesouza@suse.com>
[ Upstream commit 3736127a3aa805602b7a2ad60ec9cfce68065fbb ]
Function btrfs_lookup_data_extent calls btrfs_search_slot to verify if
the EXTENT_ITEM exists in the extent tree. btrfs_search_slot can return
values bellow zero if an error happened.
Function replay_one_extent currently checks if the search found
something (0 returned) and increments the reference, and if not, it
seems to evaluate as 'not found'.
Fix the condition by checking if the value was bellow zero and return
early.
Reviewed-by: Filipe Manana <fdmanana@suse.com>
Signed-off-by: Marcos Paulo de Souza <mpdesouza@suse.com>
Reviewed-by: David Sterba <dsterba@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/btrfs/tree-log.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c
index 5412361d0c27..8ea4b3da85d1 100644
--- a/fs/btrfs/tree-log.c
+++ b/fs/btrfs/tree-log.c
@@ -719,7 +719,9 @@ static noinline int replay_one_extent(struct btrfs_trans_handle *trans,
*/
ret = btrfs_lookup_data_extent(fs_info, ins.objectid,
ins.offset);
- if (ret == 0) {
+ if (ret < 0) {
+ goto out;
+ } else if (ret == 0) {
btrfs_init_generic_ref(&ref,
BTRFS_ADD_DELAYED_REF,
ins.objectid, ins.offset, 0);
--
2.30.2
^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [PATCH AUTOSEL 5.4 081/109] btrfs: subpage: check if there are compressed extents inside one page
2021-09-09 11:54 ` [PATCH AUTOSEL 5.4 081/109] btrfs: subpage: check if there are compressed extents inside one page Sasha Levin
@ 2021-09-09 13:00 ` David Sterba
0 siblings, 0 replies; 5+ messages in thread
From: David Sterba @ 2021-09-09 13:00 UTC (permalink / raw)
To: Sasha Levin; +Cc: linux-kernel, stable, Qu Wenruo, David Sterba, linux-btrfs
On Thu, Sep 09, 2021 at 07:54:38AM -0400, Sasha Levin wrote:
> From: Qu Wenruo <wqu@suse.com>
>
> [ Upstream commit 3670e6451bc9c39ab3a46f1da19360219e4319f3 ]
Please drop this patch from stable queue, thanks.
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH AUTOSEL 5.4 082/109] btrfs: subpage: fix race between prepare_pages() and btrfs_releasepage()
2021-09-09 11:54 ` [PATCH AUTOSEL 5.4 082/109] btrfs: subpage: fix race between prepare_pages() and btrfs_releasepage() Sasha Levin
@ 2021-09-09 13:00 ` David Sterba
0 siblings, 0 replies; 5+ messages in thread
From: David Sterba @ 2021-09-09 13:00 UTC (permalink / raw)
To: Sasha Levin
Cc: linux-kernel, stable, Qu Wenruo, Ritesh Harjani, Filipe Manana,
David Sterba, linux-btrfs
On Thu, Sep 09, 2021 at 07:54:39AM -0400, Sasha Levin wrote:
> From: Qu Wenruo <wqu@suse.com>
>
> [ Upstream commit e0467866198f7f536806f39e5d0d91ae8018de08 ]
Please drop this patch from stable queue, thanks.
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2021-09-09 13:12 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
[not found] <20210909115507.147917-1-sashal@kernel.org>
2021-09-09 11:54 ` [PATCH AUTOSEL 5.4 081/109] btrfs: subpage: check if there are compressed extents inside one page Sasha Levin
2021-09-09 13:00 ` David Sterba
2021-09-09 11:54 ` [PATCH AUTOSEL 5.4 082/109] btrfs: subpage: fix race between prepare_pages() and btrfs_releasepage() Sasha Levin
2021-09-09 13:00 ` David Sterba
2021-09-09 11:54 ` [PATCH AUTOSEL 5.4 083/109] btrfs: tree-log: check btrfs_lookup_data_extent return value Sasha Levin
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox