diff options
author | Thomas Gleixner <tglx@linutronix.de> | 2008-02-04 16:48:07 +0100 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2008-02-04 16:48:07 +0100 |
commit | f4ae5da0e8e92caa168e7c2a7c4a6c4064b082c2 (patch) | |
tree | f4b3a98c7e9ea6d158bdc5bf5a479eaeb93c6957 | |
parent | 72e458dfa63b3db7a46f66b0eb19e9ff4e17fc0e (diff) |
x86: cpa, check if we changed anything and tlb flushing is necessary
Flush tlbs only when there was a real change.
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
-rw-r--r-- | arch/x86/mm/pageattr.c | 18 |
1 files changed, 17 insertions, 1 deletions
diff --git a/arch/x86/mm/pageattr.c b/arch/x86/mm/pageattr.c index d1c08308ecb..79a9f1b42dd 100644 --- a/arch/x86/mm/pageattr.c +++ b/arch/x86/mm/pageattr.c @@ -21,6 +21,7 @@ struct cpa_data { int numpages; pgprot_t mask_set; pgprot_t mask_clr; + int flushtlb; }; static inline int @@ -329,11 +330,19 @@ repeat: * not the memory it points to */ new_pte = pfn_pte(pte_pfn(old_pte), canon_pgprot(new_prot)); - set_pte_atomic(kpte, new_pte); + + /* + * Do we really change anything ? + */ + if (pte_val(old_pte) != pte_val(new_pte)) { + set_pte_atomic(kpte, new_pte); + cpa->flushtlb = 1; + } } else { err = split_large_page(kpte, address); if (!err) goto repeat; + cpa->flushtlb = 1; } return err; } @@ -438,10 +447,17 @@ static int change_page_attr_set_clr(unsigned long addr, int numpages, cpa.numpages = numpages; cpa.mask_set = mask_set; cpa.mask_clr = mask_clr; + cpa.flushtlb = 0; ret = __change_page_attr_set_clr(&cpa); /* + * Check whether we really changed something: + */ + if (!cpa.flushtlb) + return ret; + + /* * No need to flush, when we did not set any of the caching * attributes: */ |