aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86
diff options
context:
space:
mode:
authorThomas Gleixner <tglx@linutronix.de>2008-02-23 14:43:21 -0500
committerIngo Molnar <mingo@elte.hu>2008-02-29 12:55:42 -0500
commit8be8f54bae3453588011cad06363813a5293af53 (patch)
tree073e86ac8d8b3e392b0b87269546d7aa0eb10386 /arch/x86
parent757265b8c57bb8fd91785d3d1a87fb483c86c9c2 (diff)
x86: CPA: avoid split of alias mappings
avoid over-eager large page splitup. When the target area needs to be split or is split already (ioremap) then the current code enforces the split of large mappings in the alias regions even if we could avoid it. Use a separate variable processed in the cpa_data structure to carry the number of pages which have been processed instead of reusing the numpages variable. This keeps numpages intact and gives the alias code a chance to keep large mappings intact. Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'arch/x86')
-rw-r--r--arch/x86/mm/pageattr.c21
1 files changed, 11 insertions, 10 deletions
diff --git a/arch/x86/mm/pageattr.c b/arch/x86/mm/pageattr.c
index 14e48b5a94ba..7049294fb469 100644
--- a/arch/x86/mm/pageattr.c
+++ b/arch/x86/mm/pageattr.c
@@ -26,6 +26,7 @@ struct cpa_data {
26 pgprot_t mask_set; 26 pgprot_t mask_set;
27 pgprot_t mask_clr; 27 pgprot_t mask_clr;
28 int numpages; 28 int numpages;
29 int processed;
29 int flushtlb; 30 int flushtlb;
30 unsigned long pfn; 31 unsigned long pfn;
31}; 32};
@@ -290,8 +291,8 @@ try_preserve_large_page(pte_t *kpte, unsigned long address,
290 */ 291 */
291 nextpage_addr = (address + psize) & pmask; 292 nextpage_addr = (address + psize) & pmask;
292 numpages = (nextpage_addr - address) >> PAGE_SHIFT; 293 numpages = (nextpage_addr - address) >> PAGE_SHIFT;
293 if (numpages < cpa->numpages) 294 if (numpages < cpa->processed)
294 cpa->numpages = numpages; 295 cpa->processed = numpages;
295 296
296 /* 297 /*
297 * We are safe now. Check whether the new pgprot is the same: 298 * We are safe now. Check whether the new pgprot is the same:
@@ -318,7 +319,7 @@ try_preserve_large_page(pte_t *kpte, unsigned long address,
318 */ 319 */
319 addr = address + PAGE_SIZE; 320 addr = address + PAGE_SIZE;
320 pfn++; 321 pfn++;
321 for (i = 1; i < cpa->numpages; i++, addr += PAGE_SIZE, pfn++) { 322 for (i = 1; i < cpa->processed; i++, addr += PAGE_SIZE, pfn++) {
322 pgprot_t chk_prot = static_protections(new_prot, addr, pfn); 323 pgprot_t chk_prot = static_protections(new_prot, addr, pfn);
323 324
324 if (pgprot_val(chk_prot) != pgprot_val(new_prot)) 325 if (pgprot_val(chk_prot) != pgprot_val(new_prot))
@@ -342,7 +343,7 @@ try_preserve_large_page(pte_t *kpte, unsigned long address,
342 * that we limited the number of possible pages already to 343 * that we limited the number of possible pages already to
343 * the number of pages in the large page. 344 * the number of pages in the large page.
344 */ 345 */
345 if (address == (nextpage_addr - psize) && cpa->numpages == numpages) { 346 if (address == (nextpage_addr - psize) && cpa->processed == numpages) {
346 /* 347 /*
347 * The address is aligned and the number of pages 348 * The address is aligned and the number of pages
348 * covers the full page. 349 * covers the full page.
@@ -572,7 +573,7 @@ repeat:
572 set_pte_atomic(kpte, new_pte); 573 set_pte_atomic(kpte, new_pte);
573 cpa->flushtlb = 1; 574 cpa->flushtlb = 1;
574 } 575 }
575 cpa->numpages = 1; 576 cpa->processed = 1;
576 return 0; 577 return 0;
577 } 578 }
578 579
@@ -583,7 +584,7 @@ repeat:
583 do_split = try_preserve_large_page(kpte, address, cpa); 584 do_split = try_preserve_large_page(kpte, address, cpa);
584 /* 585 /*
585 * When the range fits into the existing large page, 586 * When the range fits into the existing large page,
586 * return. cp->numpages and cpa->tlbflush have been updated in 587 * return. cp->processed and cpa->tlbflush have been updated in
587 * try_large_page: 588 * try_large_page:
588 */ 589 */
589 if (do_split <= 0) 590 if (do_split <= 0)
@@ -662,7 +663,7 @@ static int __change_page_attr_set_clr(struct cpa_data *cpa, int checkalias)
662 * Store the remaining nr of pages for the large page 663 * Store the remaining nr of pages for the large page
663 * preservation check. 664 * preservation check.
664 */ 665 */
665 cpa->numpages = numpages; 666 cpa->numpages = cpa->processed = numpages;
666 667
667 ret = __change_page_attr(cpa, checkalias); 668 ret = __change_page_attr(cpa, checkalias);
668 if (ret) 669 if (ret)
@@ -679,9 +680,9 @@ static int __change_page_attr_set_clr(struct cpa_data *cpa, int checkalias)
679 * CPA operation. Either a large page has been 680 * CPA operation. Either a large page has been
680 * preserved or a single page update happened. 681 * preserved or a single page update happened.
681 */ 682 */
682 BUG_ON(cpa->numpages > numpages); 683 BUG_ON(cpa->processed > numpages);
683 numpages -= cpa->numpages; 684 numpages -= cpa->processed;
684 cpa->vaddr += cpa->numpages * PAGE_SIZE; 685 cpa->vaddr += cpa->processed * PAGE_SIZE;
685 } 686 }
686 return 0; 687 return 0;
687} 688}