diff options
author | Thomas Gleixner <tglx@linutronix.de> | 2008-02-23 14:43:21 -0500 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2008-02-29 12:55:42 -0500 |
commit | 8be8f54bae3453588011cad06363813a5293af53 (patch) | |
tree | 073e86ac8d8b3e392b0b87269546d7aa0eb10386 /arch/x86/mm | |
parent | 757265b8c57bb8fd91785d3d1a87fb483c86c9c2 (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/mm')
-rw-r--r-- | arch/x86/mm/pageattr.c | 21 |
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 | } |