diff options
Diffstat (limited to 'recipes-kernel/linux/linux-ti33x-psp-3.2/3.2.10/0035-mm-thp-fix-BUG-on-mm-nr_ptes.patch')
-rw-r--r-- | recipes-kernel/linux/linux-ti33x-psp-3.2/3.2.10/0035-mm-thp-fix-BUG-on-mm-nr_ptes.patch | 99 |
1 files changed, 99 insertions, 0 deletions
diff --git a/recipes-kernel/linux/linux-ti33x-psp-3.2/3.2.10/0035-mm-thp-fix-BUG-on-mm-nr_ptes.patch b/recipes-kernel/linux/linux-ti33x-psp-3.2/3.2.10/0035-mm-thp-fix-BUG-on-mm-nr_ptes.patch new file mode 100644 index 00000000..3a5ca20e --- /dev/null +++ b/recipes-kernel/linux/linux-ti33x-psp-3.2/3.2.10/0035-mm-thp-fix-BUG-on-mm-nr_ptes.patch | |||
@@ -0,0 +1,99 @@ | |||
1 | From 826878fadc80bdcaec6d80e4ec0a2761c46e2c00 Mon Sep 17 00:00:00 2001 | ||
2 | From: Andrea Arcangeli <aarcange@redhat.com> | ||
3 | Date: Mon, 5 Mar 2012 14:59:20 -0800 | ||
4 | Subject: [PATCH 35/95] mm: thp: fix BUG on mm->nr_ptes | ||
5 | |||
6 | commit 1c641e84719429bbfe62a95ed3545ee7fe24408f upstream. | ||
7 | |||
8 | Dave Jones reports a few Fedora users hitting the BUG_ON(mm->nr_ptes...) | ||
9 | in exit_mmap() recently. | ||
10 | |||
11 | Quoting Hugh's discovery and explanation of the SMP race condition: | ||
12 | |||
13 | "mm->nr_ptes had unusual locking: down_read mmap_sem plus | ||
14 | page_table_lock when incrementing, down_write mmap_sem (or mm_users | ||
15 | 0) when decrementing; whereas THP is careful to increment and | ||
16 | decrement it under page_table_lock. | ||
17 | |||
18 | Now most of those paths in THP also hold mmap_sem for read or write | ||
19 | (with appropriate checks on mm_users), but two do not: when | ||
20 | split_huge_page() is called by hwpoison_user_mappings(), and when | ||
21 | called by add_to_swap(). | ||
22 | |||
23 | It's conceivable that the latter case is responsible for the | ||
24 | exit_mmap() BUG_ON mm->nr_ptes that has been reported on Fedora." | ||
25 | |||
26 | The simplest way to fix it without having to alter the locking is to make | ||
27 | split_huge_page() a noop in nr_ptes terms, so by counting the preallocated | ||
28 | pagetables that exists for every mapped hugepage. It was an arbitrary | ||
29 | choice not to count them and either way is not wrong or right, because | ||
30 | they are not used but they're still allocated. | ||
31 | |||
32 | Reported-by: Dave Jones <davej@redhat.com> | ||
33 | Reported-by: Hugh Dickins <hughd@google.com> | ||
34 | Signed-off-by: Andrea Arcangeli <aarcange@redhat.com> | ||
35 | Acked-by: Hugh Dickins <hughd@google.com> | ||
36 | Cc: David Rientjes <rientjes@google.com> | ||
37 | Cc: Josh Boyer <jwboyer@redhat.com> | ||
38 | Signed-off-by: Andrew Morton <akpm@linux-foundation.org> | ||
39 | Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> | ||
40 | Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> | ||
41 | --- | ||
42 | mm/huge_memory.c | 6 +++--- | ||
43 | 1 file changed, 3 insertions(+), 3 deletions(-) | ||
44 | |||
45 | diff --git a/mm/huge_memory.c b/mm/huge_memory.c | ||
46 | index 33141f5..8f005e9 100644 | ||
47 | --- a/mm/huge_memory.c | ||
48 | +++ b/mm/huge_memory.c | ||
49 | @@ -642,6 +642,7 @@ static int __do_huge_pmd_anonymous_page(struct mm_struct *mm, | ||
50 | set_pmd_at(mm, haddr, pmd, entry); | ||
51 | prepare_pmd_huge_pte(pgtable, mm); | ||
52 | add_mm_counter(mm, MM_ANONPAGES, HPAGE_PMD_NR); | ||
53 | + mm->nr_ptes++; | ||
54 | spin_unlock(&mm->page_table_lock); | ||
55 | } | ||
56 | |||
57 | @@ -760,6 +761,7 @@ int copy_huge_pmd(struct mm_struct *dst_mm, struct mm_struct *src_mm, | ||
58 | pmd = pmd_mkold(pmd_wrprotect(pmd)); | ||
59 | set_pmd_at(dst_mm, addr, dst_pmd, pmd); | ||
60 | prepare_pmd_huge_pte(pgtable, dst_mm); | ||
61 | + dst_mm->nr_ptes++; | ||
62 | |||
63 | ret = 0; | ||
64 | out_unlock: | ||
65 | @@ -858,7 +860,6 @@ static int do_huge_pmd_wp_page_fallback(struct mm_struct *mm, | ||
66 | } | ||
67 | kfree(pages); | ||
68 | |||
69 | - mm->nr_ptes++; | ||
70 | smp_wmb(); /* make pte visible before pmd */ | ||
71 | pmd_populate(mm, pmd, pgtable); | ||
72 | page_remove_rmap(page); | ||
73 | @@ -1017,6 +1018,7 @@ int zap_huge_pmd(struct mmu_gather *tlb, struct vm_area_struct *vma, | ||
74 | VM_BUG_ON(page_mapcount(page) < 0); | ||
75 | add_mm_counter(tlb->mm, MM_ANONPAGES, -HPAGE_PMD_NR); | ||
76 | VM_BUG_ON(!PageHead(page)); | ||
77 | + tlb->mm->nr_ptes--; | ||
78 | spin_unlock(&tlb->mm->page_table_lock); | ||
79 | tlb_remove_page(tlb, page); | ||
80 | pte_free(tlb->mm, pgtable); | ||
81 | @@ -1356,7 +1358,6 @@ static int __split_huge_page_map(struct page *page, | ||
82 | pte_unmap(pte); | ||
83 | } | ||
84 | |||
85 | - mm->nr_ptes++; | ||
86 | smp_wmb(); /* make pte visible before pmd */ | ||
87 | /* | ||
88 | * Up to this point the pmd is present and huge and | ||
89 | @@ -1969,7 +1970,6 @@ static void collapse_huge_page(struct mm_struct *mm, | ||
90 | set_pmd_at(mm, address, pmd, _pmd); | ||
91 | update_mmu_cache(vma, address, _pmd); | ||
92 | prepare_pmd_huge_pte(pgtable, mm); | ||
93 | - mm->nr_ptes--; | ||
94 | spin_unlock(&mm->page_table_lock); | ||
95 | |||
96 | #ifndef CONFIG_NUMA | ||
97 | -- | ||
98 | 1.7.9.4 | ||
99 | |||