diff options
author | Rafael J. Wysocki <rjw@sisk.pl> | 2008-03-02 19:17:37 -0500 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2008-03-03 08:18:27 -0500 |
commit | 9b5cf48b06a52c04b85c88642c3b620db8e1d592 (patch) | |
tree | 1cb87d4778bbac056a4abdde770555ea5f3221a2 /arch/x86 | |
parent | 038f2f725503b55ab76cfd2645915a85594710fe (diff) |
x86: revert "x86: CPA: avoid split of alias mappings"
Revert:
commit 8be8f54bae3453588011cad06363813a5293af53
Author: Thomas Gleixner <tglx@linutronix.de>
Date: Sat Feb 23 20:43:21 2008 +0100
x86: CPA: avoid split of alias mappings
because it clearly mishandles the case when __change_page_attr(), called
from __change_page_attr_set_clr(), changes cpa->processed to 1 and
cpa_process_alias(cpa) is executed right after that.
This crashes my x86-64 test box early in the boot process
(ref. http://bugzilla.kernel.org/show_bug.cgi?id=10140#c4).
Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
Acked-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.c | 21 |
1 files changed, 10 insertions, 11 deletions
diff --git a/arch/x86/mm/pageattr.c b/arch/x86/mm/pageattr.c index 7049294fb469..14e48b5a94ba 100644 --- a/arch/x86/mm/pageattr.c +++ b/arch/x86/mm/pageattr.c | |||
@@ -26,7 +26,6 @@ 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; | ||
30 | int flushtlb; | 29 | int flushtlb; |
31 | unsigned long pfn; | 30 | unsigned long pfn; |
32 | }; | 31 | }; |
@@ -291,8 +290,8 @@ try_preserve_large_page(pte_t *kpte, unsigned long address, | |||
291 | */ | 290 | */ |
292 | nextpage_addr = (address + psize) & pmask; | 291 | nextpage_addr = (address + psize) & pmask; |
293 | numpages = (nextpage_addr - address) >> PAGE_SHIFT; | 292 | numpages = (nextpage_addr - address) >> PAGE_SHIFT; |
294 | if (numpages < cpa->processed) | 293 | if (numpages < cpa->numpages) |
295 | cpa->processed = numpages; | 294 | cpa->numpages = numpages; |
296 | 295 | ||
297 | /* | 296 | /* |
298 | * We are safe now. Check whether the new pgprot is the same: | 297 | * We are safe now. Check whether the new pgprot is the same: |
@@ -319,7 +318,7 @@ try_preserve_large_page(pte_t *kpte, unsigned long address, | |||
319 | */ | 318 | */ |
320 | addr = address + PAGE_SIZE; | 319 | addr = address + PAGE_SIZE; |
321 | pfn++; | 320 | pfn++; |
322 | for (i = 1; i < cpa->processed; i++, addr += PAGE_SIZE, pfn++) { | 321 | for (i = 1; i < cpa->numpages; i++, addr += PAGE_SIZE, pfn++) { |
323 | pgprot_t chk_prot = static_protections(new_prot, addr, pfn); | 322 | pgprot_t chk_prot = static_protections(new_prot, addr, pfn); |
324 | 323 | ||
325 | if (pgprot_val(chk_prot) != pgprot_val(new_prot)) | 324 | if (pgprot_val(chk_prot) != pgprot_val(new_prot)) |
@@ -343,7 +342,7 @@ try_preserve_large_page(pte_t *kpte, unsigned long address, | |||
343 | * that we limited the number of possible pages already to | 342 | * that we limited the number of possible pages already to |
344 | * the number of pages in the large page. | 343 | * the number of pages in the large page. |
345 | */ | 344 | */ |
346 | if (address == (nextpage_addr - psize) && cpa->processed == numpages) { | 345 | if (address == (nextpage_addr - psize) && cpa->numpages == numpages) { |
347 | /* | 346 | /* |
348 | * The address is aligned and the number of pages | 347 | * The address is aligned and the number of pages |
349 | * covers the full page. | 348 | * covers the full page. |
@@ -573,7 +572,7 @@ repeat: | |||
573 | set_pte_atomic(kpte, new_pte); | 572 | set_pte_atomic(kpte, new_pte); |
574 | cpa->flushtlb = 1; | 573 | cpa->flushtlb = 1; |
575 | } | 574 | } |
576 | cpa->processed = 1; | 575 | cpa->numpages = 1; |
577 | return 0; | 576 | return 0; |
578 | } | 577 | } |
579 | 578 | ||
@@ -584,7 +583,7 @@ repeat: | |||
584 | do_split = try_preserve_large_page(kpte, address, cpa); | 583 | do_split = try_preserve_large_page(kpte, address, cpa); |
585 | /* | 584 | /* |
586 | * When the range fits into the existing large page, | 585 | * When the range fits into the existing large page, |
587 | * return. cp->processed and cpa->tlbflush have been updated in | 586 | * return. cp->numpages and cpa->tlbflush have been updated in |
588 | * try_large_page: | 587 | * try_large_page: |
589 | */ | 588 | */ |
590 | if (do_split <= 0) | 589 | if (do_split <= 0) |
@@ -663,7 +662,7 @@ static int __change_page_attr_set_clr(struct cpa_data *cpa, int checkalias) | |||
663 | * Store the remaining nr of pages for the large page | 662 | * Store the remaining nr of pages for the large page |
664 | * preservation check. | 663 | * preservation check. |
665 | */ | 664 | */ |
666 | cpa->numpages = cpa->processed = numpages; | 665 | cpa->numpages = numpages; |
667 | 666 | ||
668 | ret = __change_page_attr(cpa, checkalias); | 667 | ret = __change_page_attr(cpa, checkalias); |
669 | if (ret) | 668 | if (ret) |
@@ -680,9 +679,9 @@ static int __change_page_attr_set_clr(struct cpa_data *cpa, int checkalias) | |||
680 | * CPA operation. Either a large page has been | 679 | * CPA operation. Either a large page has been |
681 | * preserved or a single page update happened. | 680 | * preserved or a single page update happened. |
682 | */ | 681 | */ |
683 | BUG_ON(cpa->processed > numpages); | 682 | BUG_ON(cpa->numpages > numpages); |
684 | numpages -= cpa->processed; | 683 | numpages -= cpa->numpages; |
685 | cpa->vaddr += cpa->processed * PAGE_SIZE; | 684 | cpa->vaddr += cpa->numpages * PAGE_SIZE; |
686 | } | 685 | } |
687 | return 0; | 686 | return 0; |
688 | } | 687 | } |