Commit e611939f authored by Christophe Leroy's avatar Christophe Leroy Committed by Michael Ellerman

powerpc/mm: Ensure change_page_attr() doesn't invalidate pinned TLBs

__change_page_attr() uses flush_tlb_page().
flush_tlb_page() uses tlbie instruction, which also invalidates
pinned TLBs, which is not what we expect.

This patch modifies the implementation to use flush_tlb_kernel_range()
instead. This will make use of tlbia which will preserve pinned TLBs.
Signed-off-by: default avatarChristophe Leroy <christophe.leroy@c-s.fr>
Signed-off-by: default avatarMichael Ellerman <mpe@ellerman.id.au>
parent 2ef973a9
...@@ -325,7 +325,7 @@ get_pteptr(struct mm_struct *mm, unsigned long addr, pte_t **ptep, pmd_t **pmdp) ...@@ -325,7 +325,7 @@ get_pteptr(struct mm_struct *mm, unsigned long addr, pte_t **ptep, pmd_t **pmdp)
#ifdef CONFIG_DEBUG_PAGEALLOC #ifdef CONFIG_DEBUG_PAGEALLOC
static int __change_page_attr(struct page *page, pgprot_t prot) static int __change_page_attr_noflush(struct page *page, pgprot_t prot)
{ {
pte_t *kpte; pte_t *kpte;
pmd_t *kpmd; pmd_t *kpmd;
...@@ -339,8 +339,6 @@ static int __change_page_attr(struct page *page, pgprot_t prot) ...@@ -339,8 +339,6 @@ static int __change_page_attr(struct page *page, pgprot_t prot)
if (!get_pteptr(&init_mm, address, &kpte, &kpmd)) if (!get_pteptr(&init_mm, address, &kpte, &kpmd))
return -EINVAL; return -EINVAL;
__set_pte_at(&init_mm, address, kpte, mk_pte(page, prot), 0); __set_pte_at(&init_mm, address, kpte, mk_pte(page, prot), 0);
wmb();
flush_tlb_page(NULL, address);
pte_unmap(kpte); pte_unmap(kpte);
return 0; return 0;
...@@ -355,13 +353,17 @@ static int change_page_attr(struct page *page, int numpages, pgprot_t prot) ...@@ -355,13 +353,17 @@ static int change_page_attr(struct page *page, int numpages, pgprot_t prot)
{ {
int i, err = 0; int i, err = 0;
unsigned long flags; unsigned long flags;
struct page *start = page;
local_irq_save(flags); local_irq_save(flags);
for (i = 0; i < numpages; i++, page++) { for (i = 0; i < numpages; i++, page++) {
err = __change_page_attr(page, prot); err = __change_page_attr_noflush(page, prot);
if (err) if (err)
break; break;
} }
wmb();
flush_tlb_kernel_range((unsigned long)page_address(start),
(unsigned long)page_address(page));
local_irq_restore(flags); local_irq_restore(flags);
return err; return err;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment