Skip to content

Commit 9cc9f17

Browse files
committed
x86/mm/cpa: Do the range check early
To avoid excessive 4k wise checks in the common case do a quick check first whether the requested new page protections conflict with a static protection area in the large page. If there is no conflict then the decision whether to preserve or to split the page can be made immediately. If the requested range covers the full large page, preserve it. Otherwise split it up. No point in doing a slow crawl in 4k steps. Before: 1G pages checked: 2 1G pages sameprot: 0 1G pages preserved: 0 2M pages checked: 538 2M pages sameprot: 466 2M pages preserved: 47 4K pages checked: 560642 4K pages set-checked: 7668 After: 1G pages checked: 2 1G pages sameprot: 0 1G pages preserved: 0 2M pages checked: 541 2M pages sameprot: 466 2M pages preserved: 47 4K pages checked: 514 4K pages set-checked: 7668 Signed-off-by: Thomas Gleixner <[email protected]> Reviewed-by: Dave Hansen <[email protected]> Cc: Peter Zijlstra <[email protected]> Cc: Bin Yang <[email protected]> Cc: Mark Gross <[email protected]> Link: https://lkml.kernel.org/r/[email protected]
1 parent 1c4b406 commit 9cc9f17

File tree

1 file changed

+23
-4
lines changed

1 file changed

+23
-4
lines changed

arch/x86/mm/pageattr.c

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -854,10 +854,28 @@ static int __should_split_large_page(pte_t *kpte, unsigned long address,
854854
}
855855

856856
/*
857-
* Make sure that the requested pgprot does not violate the static
858-
* protections. Check the full large page whether one of the pages
859-
* in it results in a different pgprot than the first one of the
860-
* requested range. If yes, then the page needs to be split.
857+
* Optimization: Check whether the requested pgprot is conflicting
858+
* with a static protection requirement in the large page. If not,
859+
* then checking whether the requested range is fully covering the
860+
* large page can be done right here.
861+
*/
862+
new_prot = static_protections(req_prot, lpaddr, old_pfn, numpages,
863+
CPA_DETECT);
864+
865+
if (pgprot_val(req_prot) == pgprot_val(new_prot)) {
866+
if (address != lpaddr || cpa->numpages != numpages)
867+
return 1;
868+
goto setlp;
869+
}
870+
871+
/*
872+
* Slow path. The full large page check above established that the
873+
* requested pgprot cannot be applied to the full large page due to
874+
* conflicting requirements of static protection regions. It might
875+
* turn out that the whole requested range is covered by the
876+
* modified protection of the first 4k segment at @address. This
877+
* might result in the ability to preserve the large page
878+
* nevertheless.
861879
*/
862880
new_prot = static_protections(req_prot, address, pfn, 1, CPA_DETECT);
863881
pfn = old_pfn;
@@ -882,6 +900,7 @@ static int __should_split_large_page(pte_t *kpte, unsigned long address,
882900
if (address != lpaddr || cpa->numpages != numpages)
883901
return 1;
884902

903+
setlp:
885904
/* All checks passed. Update the large page mapping. */
886905
new_pte = pfn_pte(old_pfn, new_prot);
887906
__set_pmd_pte(kpte, address, new_pte);

0 commit comments

Comments
 (0)