]>
Commit | Line | Data |
---|---|---|
b9e9b117 GKH |
1 | From 405e44f2e312dd5dd63e5a9f459bffcbcd4368ef Mon Sep 17 00:00:00 2001 |
2 | From: Andrea Arcangeli <aarcange@redhat.com> | |
3 | Date: Wed, 2 Nov 2011 13:37:08 -0700 | |
4 | Subject: powerpc: get_hugepte() don't put_page() the wrong page | |
5 | ||
6 | From: Andrea Arcangeli <aarcange@redhat.com> | |
7 | ||
8 | commit 405e44f2e312dd5dd63e5a9f459bffcbcd4368ef upstream. | |
9 | ||
10 | "page" may have changed to point to the next hugepage after the loop | |
11 | completed, The references have been taken on the head page, so the | |
12 | put_page must happen there too. | |
13 | ||
14 | This is a longstanding issue pre-thp inclusion. | |
15 | ||
16 | It's totally unclear how these page_cache_add_speculative and | |
17 | pte_val(pte) != pte_val(*ptep) checks are necessary across all the | |
18 | powerpc gup_fast code, when x86 doesn't need any of that: there's no way | |
19 | the page can be freed with irq disabled so we're guaranteed the | |
20 | atomic_inc will happen on a page with page_count > 0 (so not needing the | |
21 | speculative check). | |
22 | ||
23 | The pte check is also meaningless on x86: no need to rollback on x86 if | |
24 | the pte changed, because the pte can still change a CPU tick after the | |
25 | check succeeded and it won't be rolled back in that case. The important | |
26 | thing is we got a reference on a valid page that was mapped there a CPU | |
27 | tick ago. So not knowing the soft tlb refill code of ppc64 in great | |
28 | detail I'm not removing the "speculative" page_count increase and the | |
29 | pte checks across all the code, but unless there's a strong reason for | |
30 | it they should be later cleaned up too. | |
31 | ||
32 | If a pte can change from huge to non-huge (like it could happen with | |
33 | THP) passing a pte_t *ptep to gup_hugepte() would also require to repeat | |
34 | the is_hugepd in gup_hugepte(), but that shouldn't happen with hugetlbfs | |
35 | only so I'm not altering that. | |
36 | ||
37 | Signed-off-by: Andrea Arcangeli <aarcange@redhat.com> | |
38 | Cc: Peter Zijlstra <a.p.zijlstra@chello.nl> | |
39 | Cc: Hugh Dickins <hughd@google.com> | |
40 | Cc: Johannes Weiner <jweiner@redhat.com> | |
41 | Cc: Rik van Riel <riel@redhat.com> | |
42 | Cc: Mel Gorman <mgorman@suse.de> | |
43 | Cc: KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com> | |
44 | Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org> | |
45 | Acked-by: David Gibson <david@gibson.dropbear.id.au> | |
46 | Signed-off-by: Andrew Morton <akpm@linux-foundation.org> | |
47 | Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> | |
48 | Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> | |
49 | ||
50 | --- | |
51 | arch/powerpc/mm/hugetlbpage.c | 2 +- | |
52 | 1 file changed, 1 insertion(+), 1 deletion(-) | |
53 | ||
54 | --- a/arch/powerpc/mm/hugetlbpage.c | |
55 | +++ b/arch/powerpc/mm/hugetlbpage.c | |
56 | @@ -429,7 +429,7 @@ static noinline int gup_hugepte(pte_t *p | |
57 | if (unlikely(pte_val(pte) != pte_val(*ptep))) { | |
58 | /* Could be optimized better */ | |
59 | while (*nr) { | |
60 | - put_page(page); | |
61 | + put_page(head); | |
62 | (*nr)--; | |
63 | } | |
64 | } |