Skip to content

Commit 4aaf269

Browse files
jgross1akpm00
authored andcommitted
mm: introduce arch_has_hw_nonleaf_pmd_young()
When running as a Xen PV guests commit eed9a32 ("mm: x86: add CONFIG_ARCH_HAS_NONLEAF_PMD_YOUNG") can cause a protection violation in pmdp_test_and_clear_young(): BUG: unable to handle page fault for address: ffff8880083374d0 #PF: supervisor write access in kernel mode #PF: error_code(0x0003) - permissions violation PGD 3026067 P4D 3026067 PUD 3027067 PMD 7fee5067 PTE 8010000008337065 Oops: 0003 [#1] PREEMPT SMP NOPTI CPU: 7 PID: 158 Comm: kswapd0 Not tainted 6.1.0-rc5-20221118-doflr+ #1 RIP: e030:pmdp_test_and_clear_young+0x25/0x40 This happens because the Xen hypervisor can't emulate direct writes to page table entries other than PTEs. This can easily be fixed by introducing arch_has_hw_nonleaf_pmd_young() similar to arch_has_hw_pte_young() and test that instead of CONFIG_ARCH_HAS_NONLEAF_PMD_YOUNG. Link: https://lkml.kernel.org/r/[email protected] Fixes: eed9a32 ("mm: x86: add CONFIG_ARCH_HAS_NONLEAF_PMD_YOUNG") Signed-off-by: Juergen Gross <[email protected]> Reported-by: Sander Eikelenboom <[email protected]> Acked-by: Yu Zhao <[email protected]> Tested-by: Sander Eikelenboom <[email protected]> Acked-by: David Hildenbrand <[email protected]> [core changes] Signed-off-by: Andrew Morton <[email protected]>
1 parent 6617da8 commit 4aaf269

File tree

3 files changed

+24
-5
lines changed

3 files changed

+24
-5
lines changed

arch/x86/include/asm/pgtable.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1439,6 +1439,14 @@ static inline bool arch_has_hw_pte_young(void)
14391439
return true;
14401440
}
14411441

1442+
#ifdef CONFIG_XEN_PV
1443+
#define arch_has_hw_nonleaf_pmd_young arch_has_hw_nonleaf_pmd_young
1444+
static inline bool arch_has_hw_nonleaf_pmd_young(void)
1445+
{
1446+
return !cpu_feature_enabled(X86_FEATURE_XENPV);
1447+
}
1448+
#endif
1449+
14421450
#ifdef CONFIG_PAGE_TABLE_CHECK
14431451
static inline bool pte_user_accessible_page(pte_t pte)
14441452
{

include/linux/pgtable.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -267,6 +267,17 @@ static inline int pmdp_clear_flush_young(struct vm_area_struct *vma,
267267
#endif /* CONFIG_TRANSPARENT_HUGEPAGE */
268268
#endif
269269

270+
#ifndef arch_has_hw_nonleaf_pmd_young
271+
/*
272+
* Return whether the accessed bit in non-leaf PMD entries is supported on the
273+
* local CPU.
274+
*/
275+
static inline bool arch_has_hw_nonleaf_pmd_young(void)
276+
{
277+
return IS_ENABLED(CONFIG_ARCH_HAS_NONLEAF_PMD_YOUNG);
278+
}
279+
#endif
280+
270281
#ifndef arch_has_hw_pte_young
271282
/*
272283
* Return whether the accessed bit is supported on the local CPU.

mm/vmscan.c

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3987,7 +3987,7 @@ static void walk_pmd_range_locked(pud_t *pud, unsigned long next, struct vm_area
39873987
goto next;
39883988

39893989
if (!pmd_trans_huge(pmd[i])) {
3990-
if (IS_ENABLED(CONFIG_ARCH_HAS_NONLEAF_PMD_YOUNG) &&
3990+
if (arch_has_hw_nonleaf_pmd_young() &&
39913991
get_cap(LRU_GEN_NONLEAF_YOUNG))
39923992
pmdp_test_and_clear_young(vma, addr, pmd + i);
39933993
goto next;
@@ -4085,14 +4085,14 @@ static void walk_pmd_range(pud_t *pud, unsigned long start, unsigned long end,
40854085
#endif
40864086
walk->mm_stats[MM_NONLEAF_TOTAL]++;
40874087

4088-
#ifdef CONFIG_ARCH_HAS_NONLEAF_PMD_YOUNG
4089-
if (get_cap(LRU_GEN_NONLEAF_YOUNG)) {
4088+
if (arch_has_hw_nonleaf_pmd_young() &&
4089+
get_cap(LRU_GEN_NONLEAF_YOUNG)) {
40904090
if (!pmd_young(val))
40914091
continue;
40924092

40934093
walk_pmd_range_locked(pud, addr, vma, args, bitmap, &pos);
40944094
}
4095-
#endif
4095+
40964096
if (!walk->force_scan && !test_bloom_filter(walk->lruvec, walk->max_seq, pmd + i))
40974097
continue;
40984098

@@ -5392,7 +5392,7 @@ static ssize_t show_enabled(struct kobject *kobj, struct kobj_attribute *attr, c
53925392
if (arch_has_hw_pte_young() && get_cap(LRU_GEN_MM_WALK))
53935393
caps |= BIT(LRU_GEN_MM_WALK);
53945394

5395-
if (IS_ENABLED(CONFIG_ARCH_HAS_NONLEAF_PMD_YOUNG) && get_cap(LRU_GEN_NONLEAF_YOUNG))
5395+
if (arch_has_hw_nonleaf_pmd_young() && get_cap(LRU_GEN_NONLEAF_YOUNG))
53965396
caps |= BIT(LRU_GEN_NONLEAF_YOUNG);
53975397

53985398
return snprintf(buf, PAGE_SIZE, "0x%04x\n", caps);

0 commit comments

Comments
 (0)