generic: 5.15: replace ramips AR8033 fiber patch with 5.18 patches
[openwrt/openwrt.git] / target / linux / generic / backport-5.15 / 020-v6.1-18-mm-introduce-arch_has_hw_nonleaf_pmd_young.patch
1 From 46cbda7b65998a5af4493f745d94417af697bd68 Mon Sep 17 00:00:00 2001
2 From: Juergen Gross <jgross@suse.com>
3 Date: Wed, 23 Nov 2022 07:45:10 +0100
4 Subject: [PATCH 18/29] mm: introduce arch_has_hw_nonleaf_pmd_young()
5
6 When running as a Xen PV guests commit eed9a328aa1a ("mm: x86: add
7 CONFIG_ARCH_HAS_NONLEAF_PMD_YOUNG") can cause a protection violation in
8 pmdp_test_and_clear_young():
9
10 BUG: unable to handle page fault for address: ffff8880083374d0
11 #PF: supervisor write access in kernel mode
12 #PF: error_code(0x0003) - permissions violation
13 PGD 3026067 P4D 3026067 PUD 3027067 PMD 7fee5067 PTE 8010000008337065
14 Oops: 0003 [#1] PREEMPT SMP NOPTI
15 CPU: 7 PID: 158 Comm: kswapd0 Not tainted 6.1.0-rc5-20221118-doflr+ #1
16 RIP: e030:pmdp_test_and_clear_young+0x25/0x40
17
18 This happens because the Xen hypervisor can't emulate direct writes to
19 page table entries other than PTEs.
20
21 This can easily be fixed by introducing arch_has_hw_nonleaf_pmd_young()
22 similar to arch_has_hw_pte_young() and test that instead of
23 CONFIG_ARCH_HAS_NONLEAF_PMD_YOUNG.
24
25 Link: https://lkml.kernel.org/r/20221123064510.16225-1-jgross@suse.com
26 Fixes: eed9a328aa1a ("mm: x86: add CONFIG_ARCH_HAS_NONLEAF_PMD_YOUNG")
27 Signed-off-by: Juergen Gross <jgross@suse.com>
28 Reported-by: Sander Eikelenboom <linux@eikelenboom.it>
29 Acked-by: Yu Zhao <yuzhao@google.com>
30 Tested-by: Sander Eikelenboom <linux@eikelenboom.it>
31 Acked-by: David Hildenbrand <david@redhat.com> [core changes]
32 Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
33 ---
34 arch/x86/include/asm/pgtable.h | 8 ++++++++
35 include/linux/pgtable.h | 11 +++++++++++
36 mm/vmscan.c | 10 +++++-----
37 3 files changed, 24 insertions(+), 5 deletions(-)
38
39 --- a/arch/x86/include/asm/pgtable.h
40 +++ b/arch/x86/include/asm/pgtable.h
41 @@ -1405,6 +1405,14 @@ static inline bool arch_has_hw_pte_young
42 return true;
43 }
44
45 +#ifdef CONFIG_XEN_PV
46 +#define arch_has_hw_nonleaf_pmd_young arch_has_hw_nonleaf_pmd_young
47 +static inline bool arch_has_hw_nonleaf_pmd_young(void)
48 +{
49 + return !cpu_feature_enabled(X86_FEATURE_XENPV);
50 +}
51 +#endif
52 +
53 #endif /* __ASSEMBLY__ */
54
55 #endif /* _ASM_X86_PGTABLE_H */
56 --- a/include/linux/pgtable.h
57 +++ b/include/linux/pgtable.h
58 @@ -266,6 +266,17 @@ static inline int pmdp_clear_flush_young
59 #endif /* CONFIG_TRANSPARENT_HUGEPAGE */
60 #endif
61
62 +#ifndef arch_has_hw_nonleaf_pmd_young
63 +/*
64 + * Return whether the accessed bit in non-leaf PMD entries is supported on the
65 + * local CPU.
66 + */
67 +static inline bool arch_has_hw_nonleaf_pmd_young(void)
68 +{
69 + return IS_ENABLED(CONFIG_ARCH_HAS_NONLEAF_PMD_YOUNG);
70 +}
71 +#endif
72 +
73 #ifndef arch_has_hw_pte_young
74 /*
75 * Return whether the accessed bit is supported on the local CPU.
76 --- a/mm/vmscan.c
77 +++ b/mm/vmscan.c
78 @@ -3727,7 +3727,7 @@ static void walk_pmd_range_locked(pud_t
79 goto next;
80
81 if (!pmd_trans_huge(pmd[i])) {
82 - if (IS_ENABLED(CONFIG_ARCH_HAS_NONLEAF_PMD_YOUNG) &&
83 + if (arch_has_hw_nonleaf_pmd_young() &&
84 get_cap(LRU_GEN_NONLEAF_YOUNG))
85 pmdp_test_and_clear_young(vma, addr, pmd + i);
86 goto next;
87 @@ -3825,14 +3825,14 @@ restart:
88 #endif
89 walk->mm_stats[MM_NONLEAF_TOTAL]++;
90
91 -#ifdef CONFIG_ARCH_HAS_NONLEAF_PMD_YOUNG
92 - if (get_cap(LRU_GEN_NONLEAF_YOUNG)) {
93 + if (arch_has_hw_nonleaf_pmd_young() &&
94 + get_cap(LRU_GEN_NONLEAF_YOUNG)) {
95 if (!pmd_young(val))
96 continue;
97
98 walk_pmd_range_locked(pud, addr, vma, args, bitmap, &pos);
99 }
100 -#endif
101 +
102 if (!walk->force_scan && !test_bloom_filter(walk->lruvec, walk->max_seq, pmd + i))
103 continue;
104
105 @@ -5132,7 +5132,7 @@ static ssize_t show_enabled(struct kobje
106 if (arch_has_hw_pte_young() && get_cap(LRU_GEN_MM_WALK))
107 caps |= BIT(LRU_GEN_MM_WALK);
108
109 - if (IS_ENABLED(CONFIG_ARCH_HAS_NONLEAF_PMD_YOUNG) && get_cap(LRU_GEN_NONLEAF_YOUNG))
110 + if (arch_has_hw_nonleaf_pmd_young() && get_cap(LRU_GEN_NONLEAF_YOUNG))
111 caps |= BIT(LRU_GEN_NONLEAF_YOUNG);
112
113 return snprintf(buf, PAGE_SIZE, "0x%04x\n", caps);