aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/mm
diff options
context:
space:
mode:
authorAneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>2013-06-20 05:00:23 -0400
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>2013-06-21 02:01:56 -0400
commit7888b4ddb44dccd68bc20d0dc4425707dff88c72 (patch)
tree7d9b5d74f6f51255fe06649511bf39d1a0516356 /arch/powerpc/mm
parent0ac52dd7666d5c0d0147d73a8e4b1d1ffd81cdf3 (diff)
powerpc: Prevent gcc to re-read the pagetables
GCC is very likely to read the pagetables just once and cache them in the local stack or in a register, but it is can also decide to re-read the pagetables. The problem is that the pagetable in those places can change from under gcc. With THP/hugetlbfs the pmd (and pgd for hugetlbfs giga pages) can change under gup_fast. The pages won't be freed untill we finish gup fast because we have irq disabled and we free these pages via rcu callback. Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com> Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Diffstat (limited to 'arch/powerpc/mm')
-rw-r--r--arch/powerpc/mm/gup.c8
-rw-r--r--arch/powerpc/mm/hugetlbpage.c2
2 files changed, 5 insertions, 5 deletions
diff --git a/arch/powerpc/mm/gup.c b/arch/powerpc/mm/gup.c
index 223a255545fc..49822d90ea96 100644
--- a/arch/powerpc/mm/gup.c
+++ b/arch/powerpc/mm/gup.c
@@ -34,7 +34,7 @@ static noinline int gup_pte_range(pmd_t pmd, unsigned long addr,
34 34
35 ptep = pte_offset_kernel(&pmd, addr); 35 ptep = pte_offset_kernel(&pmd, addr);
36 do { 36 do {
37 pte_t pte = *ptep; 37 pte_t pte = ACCESS_ONCE(*ptep);
38 struct page *page; 38 struct page *page;
39 39
40 if ((pte_val(pte) & mask) != result) 40 if ((pte_val(pte) & mask) != result)
@@ -63,7 +63,7 @@ static int gup_pmd_range(pud_t pud, unsigned long addr, unsigned long end,
63 63
64 pmdp = pmd_offset(&pud, addr); 64 pmdp = pmd_offset(&pud, addr);
65 do { 65 do {
66 pmd_t pmd = *pmdp; 66 pmd_t pmd = ACCESS_ONCE(*pmdp);
67 67
68 next = pmd_addr_end(addr, end); 68 next = pmd_addr_end(addr, end);
69 /* 69 /*
@@ -97,7 +97,7 @@ static int gup_pud_range(pgd_t pgd, unsigned long addr, unsigned long end,
97 97
98 pudp = pud_offset(&pgd, addr); 98 pudp = pud_offset(&pgd, addr);
99 do { 99 do {
100 pud_t pud = *pudp; 100 pud_t pud = ACCESS_ONCE(*pudp);
101 101
102 next = pud_addr_end(addr, end); 102 next = pud_addr_end(addr, end);
103 if (pud_none(pud)) 103 if (pud_none(pud))
@@ -160,7 +160,7 @@ int get_user_pages_fast(unsigned long start, int nr_pages, int write,
160 160
161 pgdp = pgd_offset(mm, addr); 161 pgdp = pgd_offset(mm, addr);
162 do { 162 do {
163 pgd_t pgd = *pgdp; 163 pgd_t pgd = ACCESS_ONCE(*pgdp);
164 164
165 pr_devel(" %016lx: normal pgd %p\n", addr, 165 pr_devel(" %016lx: normal pgd %p\n", addr,
166 (void *)pgd_val(pgd)); 166 (void *)pgd_val(pgd));
diff --git a/arch/powerpc/mm/hugetlbpage.c b/arch/powerpc/mm/hugetlbpage.c
index e9e6882231da..f2f01fd3ec68 100644
--- a/arch/powerpc/mm/hugetlbpage.c
+++ b/arch/powerpc/mm/hugetlbpage.c
@@ -1024,7 +1024,7 @@ int gup_hugepte(pte_t *ptep, unsigned long sz, unsigned long addr,
1024 if (pte_end < end) 1024 if (pte_end < end)
1025 end = pte_end; 1025 end = pte_end;
1026 1026
1027 pte = *ptep; 1027 pte = ACCESS_ONCE(*ptep);
1028 mask = _PAGE_PRESENT | _PAGE_USER; 1028 mask = _PAGE_PRESENT | _PAGE_USER;
1029 if (write) 1029 if (write)
1030 mask |= _PAGE_RW; 1030 mask |= _PAGE_RW;