]>
Commit | Line | Data |
---|---|---|
9f934a63 GKH |
1 | From b7f50cfa3630b6e079929ffccfd442d65064ee1f Mon Sep 17 00:00:00 2001 |
2 | From: Mel Gorman <mel@csn.ul.ie> | |
3 | Date: Tue, 26 Oct 2010 14:21:11 -0700 | |
4 | Subject: mm, page-allocator: do not check the state of a non-existant buddy during free | |
5 | ||
6 | From: Mel Gorman <mel@csn.ul.ie> | |
7 | ||
8 | commit b7f50cfa3630b6e079929ffccfd442d65064ee1f upstream. | |
9 | ||
10 | There is a bug in commit 6dda9d55 ("page allocator: reduce fragmentation | |
11 | in buddy allocator by adding buddies that are merging to the tail of the | |
12 | free lists") that means a buddy at order MAX_ORDER is checked for merging. | |
13 | A page of this order never exists so at times, an effectively random | |
14 | piece of memory is being checked. | |
15 | ||
16 | Alan Curry has reported that this is causing memory corruption in | |
17 | userspace data on a PPC32 platform (http://lkml.org/lkml/2010/10/9/32). | |
18 | It is not clear why this is happening. It could be a cache coherency | |
19 | problem where pages mapped in both user and kernel space are getting | |
20 | different cache lines due to the bad read from kernel space | |
21 | (http://lkml.org/lkml/2010/10/13/179). It could also be that there are | |
22 | some special registers being io-remapped at the end of the memmap array | |
23 | and that a read has special meaning on them. Compiler bugs have been | |
24 | ruled out because the assembly before and after the patch looks relatively | |
25 | harmless. | |
26 | ||
27 | This patch fixes the problem by ensuring we are not reading a possibly | |
28 | invalid location of memory. It's not clear why the read causes corruption | |
29 | but one way or the other it is a buggy read. | |
30 | ||
31 | Signed-off-by: Mel Gorman <mel@csn.ul.ie> | |
32 | Cc: Corrado Zoccolo <czoccolo@gmail.com> | |
33 | Reported-by: Alan Curry <pacman@kosh.dhis.org> | |
34 | Cc: KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com> | |
35 | Cc: Christoph Lameter <cl@linux-foundation.org> | |
36 | Cc: Rik van Riel <riel@redhat.com> | |
37 | Signed-off-by: Andrew Morton <akpm@linux-foundation.org> | |
38 | Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> | |
39 | Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> | |
40 | ||
41 | --- | |
42 | mm/page_alloc.c | 2 +- | |
43 | 1 file changed, 1 insertion(+), 1 deletion(-) | |
44 | ||
45 | --- a/mm/page_alloc.c | |
46 | +++ b/mm/page_alloc.c | |
47 | @@ -530,7 +530,7 @@ static inline void __free_one_page(struc | |
48 | * so it's less likely to be used soon and more likely to be merged | |
49 | * as a higher order page | |
50 | */ | |
51 | - if ((order < MAX_ORDER-1) && pfn_valid_within(page_to_pfn(buddy))) { | |
52 | + if ((order < MAX_ORDER-2) && pfn_valid_within(page_to_pfn(buddy))) { | |
53 | struct page *higher_page, *higher_buddy; | |
54 | combined_idx = __find_combined_index(page_idx, order); | |
55 | higher_page = page + combined_idx - page_idx; |