]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/blame - releases/5.0.18/btrfs-correctly-free-extent-buffer-in-case-btree_read_extent_buffer_pages-fails.patch
Linux 5.0.18
[thirdparty/kernel/stable-queue.git] / releases / 5.0.18 / btrfs-correctly-free-extent-buffer-in-case-btree_read_extent_buffer_pages-fails.patch
CommitLineData
21f93658
GKH
1From 537f38f019fa0b762dbb4c0fc95d7fcce9db8e2d Mon Sep 17 00:00:00 2001
2From: Nikolay Borisov <nborisov@suse.com>
3Date: Thu, 14 Mar 2019 09:52:35 +0200
4Subject: btrfs: Correctly free extent buffer in case btree_read_extent_buffer_pages fails
5
6From: Nikolay Borisov <nborisov@suse.com>
7
8commit 537f38f019fa0b762dbb4c0fc95d7fcce9db8e2d upstream.
9
10If a an eb fails to be read for whatever reason - it's corrupted on disk
11and parent transid/key validations fail or IO for eb pages fail then
12this buffer must be removed from the buffer cache. Currently the code
13calls free_extent_buffer if an error occurs. Unfortunately this doesn't
14achieve the desired behavior since btrfs_find_create_tree_block returns
15with eb->refs == 2.
16
17On the other hand free_extent_buffer will only decrement the refs once
18leaving it added to the buffer cache radix tree. This enables later
19code to look up the buffer from the cache and utilize it potentially
20leading to a crash.
21
22The correct way to free the buffer is call free_extent_buffer_stale.
23This function will correctly call atomic_dec explicitly for the buffer
24and subsequently call release_extent_buffer which will decrement the
25final reference thus correctly remove the invalid buffer from buffer
26cache. This change affects only newly allocated buffers since they have
27eb->refs == 2.
28
29Link: https://bugzilla.kernel.org/show_bug.cgi?id=202755
30Reported-by: Jungyeon <jungyeon@gatech.edu>
31CC: stable@vger.kernel.org # 4.4+
32Signed-off-by: Nikolay Borisov <nborisov@suse.com>
33Reviewed-by: David Sterba <dsterba@suse.com>
34Signed-off-by: David Sterba <dsterba@suse.com>
35Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
36
37---
38 fs/btrfs/disk-io.c | 17 +++++++++++------
39 1 file changed, 11 insertions(+), 6 deletions(-)
40
41--- a/fs/btrfs/disk-io.c
42+++ b/fs/btrfs/disk-io.c
43@@ -1017,13 +1017,18 @@ void readahead_tree_block(struct btrfs_f
44 {
45 struct extent_buffer *buf = NULL;
46 struct inode *btree_inode = fs_info->btree_inode;
47+ int ret;
48
49 buf = btrfs_find_create_tree_block(fs_info, bytenr);
50 if (IS_ERR(buf))
51 return;
52- read_extent_buffer_pages(&BTRFS_I(btree_inode)->io_tree,
53- buf, WAIT_NONE, 0);
54- free_extent_buffer(buf);
55+
56+ ret = read_extent_buffer_pages(&BTRFS_I(btree_inode)->io_tree, buf,
57+ WAIT_NONE, 0);
58+ if (ret < 0)
59+ free_extent_buffer_stale(buf);
60+ else
61+ free_extent_buffer(buf);
62 }
63
64 int reada_tree_block_flagged(struct btrfs_fs_info *fs_info, u64 bytenr,
65@@ -1043,12 +1048,12 @@ int reada_tree_block_flagged(struct btrf
66 ret = read_extent_buffer_pages(io_tree, buf, WAIT_PAGE_LOCK,
67 mirror_num);
68 if (ret) {
69- free_extent_buffer(buf);
70+ free_extent_buffer_stale(buf);
71 return ret;
72 }
73
74 if (test_bit(EXTENT_BUFFER_CORRUPT, &buf->bflags)) {
75- free_extent_buffer(buf);
76+ free_extent_buffer_stale(buf);
77 return -EIO;
78 } else if (extent_buffer_uptodate(buf)) {
79 *eb = buf;
80@@ -1102,7 +1107,7 @@ struct extent_buffer *read_tree_block(st
81 ret = btree_read_extent_buffer_pages(fs_info, buf, parent_transid,
82 level, first_key);
83 if (ret) {
84- free_extent_buffer(buf);
85+ free_extent_buffer_stale(buf);
86 return ERR_PTR(ret);
87 }
88 return buf;