aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNick Piggin <npiggin@suse.de>2008-07-31 21:15:21 -0400
committerIngo Molnar <mingo@elte.hu>2008-08-15 11:22:57 -0400
commit5843d9a4d0ba89719916c8f07fc9c57b7126be6d (patch)
tree3c55d6f17ce32ec3f53a324ce8fc90e291b44d79
parent466ae837424dcc538b1af2a0eaf53be32edcdbe7 (diff)
x86, pat: avoid highmem cache attribute aliasing
Highmem code can leave ptes and tlb entries around for a given page even after kunmap, and after it has been freed. >From what I can gather, the PAT code may change the cache attributes of arbitrary physical addresses (ie. including highmem pages), which would result in aliases in the case that it operates on one of these lazy tlb highmem pages. Flushing kmaps should solve the problem. I've also just added code for conditional flushing if we haven't got any dangling highmem aliases -- this should help performance if we change page attributes frequently or systems that aren't using much highmem pages (eg. if < 4G RAM). Should be turned into 2 patches, but just for RFC... Signed-off-by: Ingo Molnar <mingo@elte.hu>
-rw-r--r--arch/x86/mm/pageattr.c3
-rw-r--r--mm/highmem.c5
2 files changed, 7 insertions, 1 deletions
diff --git a/arch/x86/mm/pageattr.c b/arch/x86/mm/pageattr.c
index 2c5c18c2464d..4adb33628dec 100644
--- a/arch/x86/mm/pageattr.c
+++ b/arch/x86/mm/pageattr.c
@@ -777,6 +777,9 @@ static int do_change_page_attr_set_clr(unsigned long addr, int numpages,
777 WARN_ON_ONCE(1); 777 WARN_ON_ONCE(1);
778 } 778 }
779 779
780 /* Must avoid aliasing mappings in the highmem code */
781 kmap_flush_unused();
782
780 cpa.vaddr = addr; 783 cpa.vaddr = addr;
781 cpa.numpages = numpages; 784 cpa.numpages = numpages;
782 cpa.mask_set = mask_set; 785 cpa.mask_set = mask_set;
diff --git a/mm/highmem.c b/mm/highmem.c
index e16e1523b688..b36b83b920ff 100644
--- a/mm/highmem.c
+++ b/mm/highmem.c
@@ -70,6 +70,7 @@ static DECLARE_WAIT_QUEUE_HEAD(pkmap_map_wait);
70static void flush_all_zero_pkmaps(void) 70static void flush_all_zero_pkmaps(void)
71{ 71{
72 int i; 72 int i;
73 int need_flush = 0;
73 74
74 flush_cache_kmaps(); 75 flush_cache_kmaps();
75 76
@@ -101,8 +102,10 @@ static void flush_all_zero_pkmaps(void)
101 &pkmap_page_table[i]); 102 &pkmap_page_table[i]);
102 103
103 set_page_address(page, NULL); 104 set_page_address(page, NULL);
105 need_flush = 1;
104 } 106 }
105 flush_tlb_kernel_range(PKMAP_ADDR(0), PKMAP_ADDR(LAST_PKMAP)); 107 if (need_flush)
108 flush_tlb_kernel_range(PKMAP_ADDR(0), PKMAP_ADDR(LAST_PKMAP));
106} 109}
107 110
108/** 111/**