]>
Commit | Line | Data |
---|---|---|
f85a50aa GKH |
1 | From 2a872fa4e9c8adc79c830e4009e1cc0c013a9d8a Mon Sep 17 00:00:00 2001 |
2 | From: "Steven Rostedt (VMware)" <rostedt@goodmis.org> | |
3 | Date: Mon, 2 Apr 2018 10:33:56 -0400 | |
4 | Subject: ring-buffer: Check if memory is available before allocation | |
5 | ||
6 | From: Steven Rostedt (VMware) <rostedt@goodmis.org> | |
7 | ||
8 | commit 2a872fa4e9c8adc79c830e4009e1cc0c013a9d8a upstream. | |
9 | ||
10 | The ring buffer is made up of a link list of pages. When making the ring | |
11 | buffer bigger, it will allocate all the pages it needs before adding to the | |
12 | ring buffer, and if it fails, it frees them and returns an error. This makes | |
13 | increasing the ring buffer size an all or nothing action. When this was | |
14 | first created, the pages were allocated with "NORETRY". This was to not | |
15 | cause any Out-Of-Memory (OOM) actions from allocating the ring buffer. But | |
16 | NORETRY was too strict, as the ring buffer would fail to expand even when | |
17 | there's memory available, but was taken up in the page cache. | |
18 | ||
19 | Commit 848618857d253 ("tracing/ring_buffer: Try harder to allocate") changed | |
20 | the allocating from NORETRY to RETRY_MAYFAIL. The RETRY_MAYFAIL would | |
21 | allocate from the page cache, but if there was no memory available, it would | |
22 | simple fail the allocation and not trigger an OOM. | |
23 | ||
24 | This worked fine, but had one problem. As the ring buffer would allocate one | |
25 | page at a time, it could take up all memory in the system before it failed | |
26 | to allocate and free that memory. If the allocation is happening and the | |
27 | ring buffer allocates all memory and then tries to take more than available, | |
28 | its allocation will not trigger an OOM, but if there's any allocation that | |
29 | happens someplace else, that could trigger an OOM, even though once the ring | |
30 | buffer's allocation fails, it would free up all the previous memory it tried | |
31 | to allocate, and allow other memory allocations to succeed. | |
32 | ||
33 | Commit d02bd27bd33dd ("mm/page_alloc.c: calculate 'available' memory in a | |
34 | separate function") separated out si_mem_availble() as a separate function | |
35 | that could be used to see how much memory is available in the system. Using | |
36 | this function to make sure that the ring buffer could be allocated before it | |
37 | tries to allocate pages we can avoid allocating all memory in the system and | |
38 | making it vulnerable to OOMs if other allocations are taking place. | |
39 | ||
40 | Link: http://lkml.kernel.org/r/1522320104-6573-1-git-send-email-zhaoyang.huang@spreadtrum.com | |
41 | ||
42 | CC: stable@vger.kernel.org | |
43 | Cc: linux-mm@kvack.org | |
44 | Fixes: 848618857d253 ("tracing/ring_buffer: Try harder to allocate") | |
45 | Requires: d02bd27bd33dd ("mm/page_alloc.c: calculate 'available' memory in a separate function") | |
46 | Reported-by: Zhaoyang Huang <huangzhaoyang@gmail.com> | |
47 | Tested-by: Joel Fernandes <joelaf@google.com> | |
48 | Signed-off-by: Steven Rostedt (VMware) <rostedt@goodmis.org> | |
49 | Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> | |
50 | ||
51 | --- | |
52 | kernel/trace/ring_buffer.c | 5 +++++ | |
53 | 1 file changed, 5 insertions(+) | |
54 | ||
55 | --- a/kernel/trace/ring_buffer.c | |
56 | +++ b/kernel/trace/ring_buffer.c | |
57 | @@ -1136,6 +1136,11 @@ static int __rb_allocate_pages(long nr_p | |
58 | struct buffer_page *bpage, *tmp; | |
59 | long i; | |
60 | ||
61 | + /* Check if the available memory is there first */ | |
62 | + i = si_mem_available(); | |
63 | + if (i < nr_pages) | |
64 | + return -ENOMEM; | |
65 | + | |
66 | for (i = 0; i < nr_pages; i++) { | |
67 | struct page *page; | |
68 | /* |