Skip to content

Commit 585948f

Browse files
committed
x86/mm/cpa: Avoid the 4k pages check completely
The extra loop which tries hard to preserve large pages in case of conflicts with static protection regions turns out to be not preserving anything, at least not in the experiments which have been conducted. There might be corner cases in which the code would be able to preserve a large page oaccsionally, but it's really not worth the extra code and the cycles wasted in the common case. Before: 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 After: 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 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 9cc9f17 commit 585948f

File tree

1 file changed

+16
-48
lines changed

1 file changed

+16
-48
lines changed

arch/x86/mm/pageattr.c

Lines changed: 16 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,6 @@ static unsigned long cpa_1g_preserved;
111111
static unsigned long cpa_2m_checked;
112112
static unsigned long cpa_2m_sameprot;
113113
static unsigned long cpa_2m_preserved;
114-
static unsigned long cpa_4k_checked;
115114
static unsigned long cpa_4k_install;
116115

117116
static inline void cpa_inc_1g_checked(void)
@@ -124,11 +123,6 @@ static inline void cpa_inc_2m_checked(void)
124123
cpa_2m_checked++;
125124
}
126125

127-
static inline void cpa_inc_4k_checked(void)
128-
{
129-
cpa_4k_checked++;
130-
}
131-
132126
static inline void cpa_inc_4k_install(void)
133127
{
134128
cpa_4k_install++;
@@ -158,7 +152,6 @@ static int cpastats_show(struct seq_file *m, void *p)
158152
seq_printf(m, "2M pages checked: %16lu\n", cpa_2m_checked);
159153
seq_printf(m, "2M pages sameprot: %16lu\n", cpa_2m_sameprot);
160154
seq_printf(m, "2M pages preserved: %16lu\n", cpa_2m_preserved);
161-
seq_printf(m, "4K pages checked: %16lu\n", cpa_4k_checked);
162155
seq_printf(m, "4K pages set-checked: %16lu\n", cpa_4k_install);
163156
return 0;
164157
}
@@ -185,7 +178,6 @@ late_initcall(cpa_stats_init);
185178
#else
186179
static inline void cpa_inc_1g_checked(void) { }
187180
static inline void cpa_inc_2m_checked(void) { }
188-
static inline void cpa_inc_4k_checked(void) { }
189181
static inline void cpa_inc_4k_install(void) { }
190182
static inline void cpa_inc_lp_sameprot(int level) { }
191183
static inline void cpa_inc_lp_preserved(int level) { }
@@ -745,11 +737,10 @@ static pgprot_t pgprot_clear_protnone_bits(pgprot_t prot)
745737
static int __should_split_large_page(pte_t *kpte, unsigned long address,
746738
struct cpa_data *cpa)
747739
{
748-
unsigned long numpages, pmask, psize, lpaddr, addr, pfn, old_pfn;
740+
unsigned long numpages, pmask, psize, lpaddr, pfn, old_pfn;
749741
pgprot_t old_prot, new_prot, req_prot, chk_prot;
750742
pte_t new_pte, old_pte, *tmp;
751743
enum pg_level level;
752-
int i;
753744

754745
/*
755746
* Check for races, another CPU might have split this page
@@ -854,53 +845,30 @@ static int __should_split_large_page(pte_t *kpte, unsigned long address,
854845
}
855846

856847
/*
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.
848+
* If the requested range does not cover the full page, split it up
861849
*/
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-
}
850+
if (address != lpaddr || cpa->numpages != numpages)
851+
return 1;
870852

871853
/*
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.
854+
* Check whether the requested pgprot is conflicting with a static
855+
* protection requirement in the large page.
879856
*/
880-
new_prot = static_protections(req_prot, address, pfn, 1, CPA_DETECT);
881-
pfn = old_pfn;
882-
for (i = 0, addr = lpaddr; i < numpages; i++, addr += PAGE_SIZE, pfn++) {
883-
chk_prot = static_protections(req_prot, addr, pfn, 1,
884-
CPA_DETECT);
885-
cpa_inc_4k_checked();
886-
if (pgprot_val(chk_prot) != pgprot_val(new_prot))
887-
return 1;
888-
}
889-
890-
/* If there are no changes, return. */
891-
if (pgprot_val(new_prot) == pgprot_val(old_prot)) {
892-
cpa_inc_lp_sameprot(level);
893-
return 0;
894-
}
857+
new_prot = static_protections(req_prot, lpaddr, old_pfn, numpages,
858+
CPA_DETECT);
895859

896860
/*
897-
* Verify that the address is aligned and the number of pages
898-
* covers the full page.
861+
* If there is a conflict, split the large page.
862+
*
863+
* There used to be a 4k wise evaluation trying really hard to
864+
* preserve the large pages, but experimentation has shown, that this
865+
* does not help at all. There might be corner cases which would
866+
* preserve one large page occasionally, but it's really not worth the
867+
* extra code and cycles for the common case.
899868
*/
900-
if (address != lpaddr || cpa->numpages != numpages)
869+
if (pgprot_val(req_prot) != pgprot_val(new_prot))
901870
return 1;
902871

903-
setlp:
904872
/* All checks passed. Update the large page mapping. */
905873
new_pte = pfn_pte(old_pfn, new_prot);
906874
__set_pmd_pte(kpte, address, new_pte);

0 commit comments

Comments
 (0)