From: "Aneesh Kumar K.V" <aneesh.ku...@linux.vnet.ibm.com>

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.ku...@linux.vnet.ibm.com>
---
 arch/powerpc/mm/gup.c         | 8 ++++----
 arch/powerpc/mm/hugetlbpage.c | 2 +-
 2 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/arch/powerpc/mm/gup.c b/arch/powerpc/mm/gup.c
index 3d36fd7..4823e4d 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,
 
        ptep = pte_offset_kernel(&pmd, addr);
        do {
-               pte_t pte = *ptep;
+               pte_t pte = ACCESS_ONCE(*ptep);
                struct page *page;
 
                if ((pte_val(pte) & mask) != result)
@@ -63,7 +63,7 @@ static int gup_pmd_range(pud_t pud, unsigned long addr, 
unsigned long end,
 
        pmdp = pmd_offset(&pud, addr);
        do {
-               pmd_t pmd = *pmdp;
+               pmd_t pmd = ACCESS_ONCE(*pmdp);
 
                next = pmd_addr_end(addr, end);
                /*
@@ -102,7 +102,7 @@ static int gup_pud_range(pgd_t pgd, unsigned long addr, 
unsigned long end,
 
        pudp = pud_offset(&pgd, addr);
        do {
-               pud_t pud = *pudp;
+               pud_t pud = ACCESS_ONCE(*pudp);
 
                next = pud_addr_end(addr, end);
                if (pud_none(pud))
@@ -165,7 +165,7 @@ int get_user_pages_fast(unsigned long start, int nr_pages, 
int write,
 
        pgdp = pgd_offset(mm, addr);
        do {
-               pgd_t pgd = *pgdp;
+               pgd_t pgd = ACCESS_ONCE(*pgdp);
 
                pr_devel("  %016lx: normal pgd %p\n", addr,
                         (void *)pgd_val(pgd));
diff --git a/arch/powerpc/mm/hugetlbpage.c b/arch/powerpc/mm/hugetlbpage.c
index e9e6882..f2f01fd 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,
        if (pte_end < end)
                end = pte_end;
 
-       pte = *ptep;
+       pte = ACCESS_ONCE(*ptep);
        mask = _PAGE_PRESENT | _PAGE_USER;
        if (write)
                mask |= _PAGE_RW;
-- 
1.8.1.2

_______________________________________________
Linuxppc-dev mailing list
Linuxppc-dev@lists.ozlabs.org
https://lists.ozlabs.org/listinfo/linuxppc-dev

Reply via email to