x86, pat: avoid highmem cache attribute aliasing
authorNick Piggin <npiggin@suse.de>
Fri, 1 Aug 2008 01:15:21 +0000 (03:15 +0200)
committerIngo Molnar <mingo@elte.hu>
Fri, 15 Aug 2008 15:22:57 +0000 (17:22 +0200)
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>
arch/x86/mm/pageattr.c
mm/highmem.c

index 2c5c18c2464da2dac2869542ff5efea0ab5bb9a5..4adb33628dec5608c8167c28181441a942ce3a00 100644 (file)
@@ -777,6 +777,9 @@ static int do_change_page_attr_set_clr(unsigned long addr, int numpages,
                WARN_ON_ONCE(1);
        }
 
+       /* Must avoid aliasing mappings in the highmem code */
+       kmap_flush_unused();
+
        cpa.vaddr = addr;
        cpa.numpages = numpages;
        cpa.mask_set = mask_set;
index e16e1523b688680572513b16ef0e49d5ac0314f0..b36b83b920ffe862f0d7060e29687c9bb998a0d8 100644 (file)
@@ -70,6 +70,7 @@ static DECLARE_WAIT_QUEUE_HEAD(pkmap_map_wait);
 static void flush_all_zero_pkmaps(void)
 {
        int i;
+       int need_flush = 0;
 
        flush_cache_kmaps();
 
@@ -101,8 +102,10 @@ static void flush_all_zero_pkmaps(void)
                          &pkmap_page_table[i]);
 
                set_page_address(page, NULL);
+               need_flush = 1;
        }
-       flush_tlb_kernel_range(PKMAP_ADDR(0), PKMAP_ADDR(LAST_PKMAP));
+       if (need_flush)
+               flush_tlb_kernel_range(PKMAP_ADDR(0), PKMAP_ADDR(LAST_PKMAP));
 }
 
 /**