aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThomas Gleixner <tglx@linutronix.de>2008-02-09 17:24:09 -0500
committerThomas Gleixner <tglx@linutronix.de>2008-02-09 17:24:09 -0500
commitfac84939609a683503947f41eb93e1917d026263 (patch)
tree8bf2df694a2300a277cf097ba778f9b4b28f2122
parentb1d95f4e41d6a5969e3a847ceeae8379f30c84c3 (diff)
x86: cpa, strict range check in try_preserve_large_page()
Right now, we check only the first 4k page for static required protections. This does not take overlapping regions into account. So we might end up setting the wrong permissions/protections for other parts of this large page. This can be optimized further, but correctness is the important part. Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Signed-off-by: Ingo Molnar <mingo@elte.hu>
-rw-r--r--arch/x86/mm/pageattr.c17
1 files changed, 15 insertions, 2 deletions
diff --git a/arch/x86/mm/pageattr.c b/arch/x86/mm/pageattr.c
index e5d29a112d00..440210a2277d 100644
--- a/arch/x86/mm/pageattr.c
+++ b/arch/x86/mm/pageattr.c
@@ -253,10 +253,10 @@ static int
253try_preserve_large_page(pte_t *kpte, unsigned long address, 253try_preserve_large_page(pte_t *kpte, unsigned long address,
254 struct cpa_data *cpa) 254 struct cpa_data *cpa)
255{ 255{
256 unsigned long nextpage_addr, numpages, pmask, psize, flags; 256 unsigned long nextpage_addr, numpages, pmask, psize, flags, addr;
257 pte_t new_pte, old_pte, *tmp; 257 pte_t new_pte, old_pte, *tmp;
258 pgprot_t old_prot, new_prot; 258 pgprot_t old_prot, new_prot;
259 int do_split = 1; 259 int i, do_split = 1;
260 unsigned int level; 260 unsigned int level;
261 261
262 spin_lock_irqsave(&pgd_lock, flags); 262 spin_lock_irqsave(&pgd_lock, flags);
@@ -304,6 +304,19 @@ try_preserve_large_page(pte_t *kpte, unsigned long address,
304 new_prot = static_protections(new_prot, address); 304 new_prot = static_protections(new_prot, address);
305 305
306 /* 306 /*
307 * We need to check the full range, whether
308 * static_protection() requires a different pgprot for one of
309 * the pages in the range we try to preserve:
310 */
311 addr = address + PAGE_SIZE;
312 for (i = 1; i < cpa->numpages; i++, addr += PAGE_SIZE) {
313 pgprot_t chk_prot = static_protections(new_prot, addr);
314
315 if (pgprot_val(chk_prot) != pgprot_val(new_prot))
316 goto out_unlock;
317 }
318
319 /*
307 * If there are no changes, return. maxpages has been updated 320 * If there are no changes, return. maxpages has been updated
308 * above: 321 * above:
309 */ 322 */