x86: Always flush pages in change_page_attr Fix a bug introduced with the CLFLUSH changes: we must always flush pages changed in cpa(), not just when they are reverted. Signed-off-by: Andi Kleen --- arch/i386/mm/pageattr.c | 7 +++++-- arch/x86_64/mm/pageattr.c | 7 ++++--- 2 files changed, 9 insertions(+), 5 deletions(-) Index: linux/arch/x86_64/mm/pageattr.c =================================================================== --- linux.orig/arch/x86_64/mm/pageattr.c +++ linux/arch/x86_64/mm/pageattr.c @@ -158,10 +158,9 @@ __change_page_attr(unsigned long address /* on x86-64 the direct mapping set at boot is not using 4k pages */ BUG_ON(PageReserved(kpte_page)); - if (page_private(kpte_page) == 0) { - save_page(kpte_page); + save_page(kpte_page); + if (page_private(kpte_page) == 0) revert_page(address, ref_prot); - } return 0; } @@ -233,6 +232,8 @@ void global_flush_tlb(void) flush_map(&l); list_for_each_entry_safe(pg, next, &l, lru) { + if (page_private(pg) != 0) + continue; ClearPagePrivate(pg); __free_page(pg); } Index: linux/arch/i386/mm/pageattr.c =================================================================== --- linux.orig/arch/i386/mm/pageattr.c +++ linux/arch/i386/mm/pageattr.c @@ -170,11 +170,11 @@ __change_page_attr(struct page *page, pg * time (not via split_large_page) and in turn we must not * replace it with a largepage. */ + + list_add(&kpte_page->lru, &df_list); if (!PageReserved(kpte_page)) { if (cpu_has_pse && (page_private(kpte_page) == 0)) { - ClearPagePrivate(kpte_page); paravirt_release_pt(page_to_pfn(kpte_page)); - list_add(&kpte_page->lru, &df_list); revert_page(kpte_page, address); } } @@ -230,6 +230,9 @@ void global_flush_tlb(void) list_for_each_entry_safe(pg, next, &l, lru) { if (cpu_has_clflush) flush_map(page_address(pg)); + if (page_private(pg) != 0) + continue; + ClearPagePrivate(pg); __free_page(pg); } }