Skip to content

Commit 4574815

Browse files
committed
LoongArch: Use accessors to page table entries instead of direct dereference
As very well explained in commit 20a004e ("arm64: mm: Use READ_ONCE/WRITE_ONCE when accessing page tables"), an architecture whose page table walker can modify the PTE in parallel must use READ_ONCE()/ WRITE_ONCE() macro to avoid any compiler transformation. So apply that to LoongArch which is such an architecture, in order to avoid potential problems. Similar to commit edf9556 ("riscv: Use accessors to page table entries instead of direct dereference"). Signed-off-by: Huacai Chen <[email protected]>
1 parent e688c22 commit 4574815

File tree

8 files changed

+52
-42
lines changed

8 files changed

+52
-42
lines changed

arch/loongarch/include/asm/hugetlb.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ static inline pte_t huge_ptep_get_and_clear(struct mm_struct *mm,
3434
unsigned long addr, pte_t *ptep)
3535
{
3636
pte_t clear;
37-
pte_t pte = *ptep;
37+
pte_t pte = ptep_get(ptep);
3838

3939
pte_val(clear) = (unsigned long)invalid_pte_table;
4040
set_pte_at(mm, addr, ptep, clear);
@@ -65,7 +65,7 @@ static inline int huge_ptep_set_access_flags(struct vm_area_struct *vma,
6565
pte_t *ptep, pte_t pte,
6666
int dirty)
6767
{
68-
int changed = !pte_same(*ptep, pte);
68+
int changed = !pte_same(ptep_get(ptep), pte);
6969

7070
if (changed) {
7171
set_pte_at(vma->vm_mm, addr, ptep, pte);

arch/loongarch/include/asm/kfence.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -53,13 +53,13 @@ static inline bool kfence_protect_page(unsigned long addr, bool protect)
5353
{
5454
pte_t *pte = virt_to_kpte(addr);
5555

56-
if (WARN_ON(!pte) || pte_none(*pte))
56+
if (WARN_ON(!pte) || pte_none(ptep_get(pte)))
5757
return false;
5858

5959
if (protect)
60-
set_pte(pte, __pte(pte_val(*pte) & ~(_PAGE_VALID | _PAGE_PRESENT)));
60+
set_pte(pte, __pte(pte_val(ptep_get(pte)) & ~(_PAGE_VALID | _PAGE_PRESENT)));
6161
else
62-
set_pte(pte, __pte(pte_val(*pte) | (_PAGE_VALID | _PAGE_PRESENT)));
62+
set_pte(pte, __pte(pte_val(ptep_get(pte)) | (_PAGE_VALID | _PAGE_PRESENT)));
6363

6464
preempt_disable();
6565
local_flush_tlb_one(addr);

arch/loongarch/include/asm/pgtable.h

Lines changed: 29 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,9 @@ extern unsigned long empty_zero_page[PAGE_SIZE / sizeof(unsigned long)];
106106
#define KFENCE_AREA_START (VMEMMAP_END + 1)
107107
#define KFENCE_AREA_END (KFENCE_AREA_START + KFENCE_AREA_SIZE - 1)
108108

109+
#define ptep_get(ptep) READ_ONCE(*(ptep))
110+
#define pmdp_get(pmdp) READ_ONCE(*(pmdp))
111+
109112
#define pte_ERROR(e) \
110113
pr_err("%s:%d: bad pte %016lx.\n", __FILE__, __LINE__, pte_val(e))
111114
#ifndef __PAGETABLE_PMD_FOLDED
@@ -147,19 +150,19 @@ static inline int p4d_present(p4d_t p4d)
147150
return p4d_val(p4d) != (unsigned long)invalid_pud_table;
148151
}
149152

150-
static inline void p4d_clear(p4d_t *p4dp)
151-
{
152-
p4d_val(*p4dp) = (unsigned long)invalid_pud_table;
153-
}
154-
155153
static inline pud_t *p4d_pgtable(p4d_t p4d)
156154
{
157155
return (pud_t *)p4d_val(p4d);
158156
}
159157

160158
static inline void set_p4d(p4d_t *p4d, p4d_t p4dval)
161159
{
162-
*p4d = p4dval;
160+
WRITE_ONCE(*p4d, p4dval);
161+
}
162+
163+
static inline void p4d_clear(p4d_t *p4dp)
164+
{
165+
set_p4d(p4dp, __p4d((unsigned long)invalid_pud_table));
163166
}
164167

165168
#define p4d_phys(p4d) PHYSADDR(p4d_val(p4d))
@@ -193,17 +196,20 @@ static inline int pud_present(pud_t pud)
193196
return pud_val(pud) != (unsigned long)invalid_pmd_table;
194197
}
195198

196-
static inline void pud_clear(pud_t *pudp)
199+
static inline pmd_t *pud_pgtable(pud_t pud)
197200
{
198-
pud_val(*pudp) = ((unsigned long)invalid_pmd_table);
201+
return (pmd_t *)pud_val(pud);
199202
}
200203

201-
static inline pmd_t *pud_pgtable(pud_t pud)
204+
static inline void set_pud(pud_t *pud, pud_t pudval)
202205
{
203-
return (pmd_t *)pud_val(pud);
206+
WRITE_ONCE(*pud, pudval);
204207
}
205208

206-
#define set_pud(pudptr, pudval) do { *(pudptr) = (pudval); } while (0)
209+
static inline void pud_clear(pud_t *pudp)
210+
{
211+
set_pud(pudp, __pud((unsigned long)invalid_pmd_table));
212+
}
207213

208214
#define pud_phys(pud) PHYSADDR(pud_val(pud))
209215
#define pud_page(pud) (pfn_to_page(pud_phys(pud) >> PAGE_SHIFT))
@@ -231,12 +237,15 @@ static inline int pmd_present(pmd_t pmd)
231237
return pmd_val(pmd) != (unsigned long)invalid_pte_table;
232238
}
233239

234-
static inline void pmd_clear(pmd_t *pmdp)
240+
static inline void set_pmd(pmd_t *pmd, pmd_t pmdval)
235241
{
236-
pmd_val(*pmdp) = ((unsigned long)invalid_pte_table);
242+
WRITE_ONCE(*pmd, pmdval);
237243
}
238244

239-
#define set_pmd(pmdptr, pmdval) do { *(pmdptr) = (pmdval); } while (0)
245+
static inline void pmd_clear(pmd_t *pmdp)
246+
{
247+
set_pmd(pmdp, __pmd((unsigned long)invalid_pte_table));
248+
}
240249

241250
#define pmd_phys(pmd) PHYSADDR(pmd_val(pmd))
242251

@@ -314,7 +323,8 @@ extern void paging_init(void);
314323

315324
static inline void set_pte(pte_t *ptep, pte_t pteval)
316325
{
317-
*ptep = pteval;
326+
WRITE_ONCE(*ptep, pteval);
327+
318328
if (pte_val(pteval) & _PAGE_GLOBAL) {
319329
pte_t *buddy = ptep_buddy(ptep);
320330
/*
@@ -341,16 +351,16 @@ static inline void set_pte(pte_t *ptep, pte_t pteval)
341351
: [buddy] "+m" (buddy->pte), [tmp] "=&r" (tmp)
342352
: [global] "r" (page_global));
343353
#else /* !CONFIG_SMP */
344-
if (pte_none(*buddy))
345-
pte_val(*buddy) = pte_val(*buddy) | _PAGE_GLOBAL;
354+
if (pte_none(ptep_get(buddy)))
355+
WRITE_ONCE(*buddy, __pte(pte_val(ptep_get(buddy)) | _PAGE_GLOBAL));
346356
#endif /* CONFIG_SMP */
347357
}
348358
}
349359

350360
static inline void pte_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep)
351361
{
352362
/* Preserve global status for the pair */
353-
if (pte_val(*ptep_buddy(ptep)) & _PAGE_GLOBAL)
363+
if (pte_val(ptep_get(ptep_buddy(ptep))) & _PAGE_GLOBAL)
354364
set_pte(ptep, __pte(_PAGE_GLOBAL));
355365
else
356366
set_pte(ptep, __pte(0));
@@ -603,7 +613,7 @@ static inline pmd_t pmd_mkinvalid(pmd_t pmd)
603613
static inline pmd_t pmdp_huge_get_and_clear(struct mm_struct *mm,
604614
unsigned long address, pmd_t *pmdp)
605615
{
606-
pmd_t old = *pmdp;
616+
pmd_t old = pmdp_get(pmdp);
607617

608618
pmd_clear(pmdp);
609619

arch/loongarch/kvm/mmu.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -714,19 +714,19 @@ static int host_pfn_mapping_level(struct kvm *kvm, gfn_t gfn,
714714
* value) and then p*d_offset() walks into the target huge page instead
715715
* of the old page table (sees the new value).
716716
*/
717-
pgd = READ_ONCE(*pgd_offset(kvm->mm, hva));
717+
pgd = pgdp_get(pgd_offset(kvm->mm, hva));
718718
if (pgd_none(pgd))
719719
goto out;
720720

721-
p4d = READ_ONCE(*p4d_offset(&pgd, hva));
721+
p4d = p4dp_get(p4d_offset(&pgd, hva));
722722
if (p4d_none(p4d) || !p4d_present(p4d))
723723
goto out;
724724

725-
pud = READ_ONCE(*pud_offset(&p4d, hva));
725+
pud = pudp_get(pud_offset(&p4d, hva));
726726
if (pud_none(pud) || !pud_present(pud))
727727
goto out;
728728

729-
pmd = READ_ONCE(*pmd_offset(&pud, hva));
729+
pmd = pmdp_get(pmd_offset(&pud, hva));
730730
if (pmd_none(pmd) || !pmd_present(pmd))
731731
goto out;
732732

arch/loongarch/mm/hugetlbpage.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,11 +39,11 @@ pte_t *huge_pte_offset(struct mm_struct *mm, unsigned long addr,
3939
pmd_t *pmd = NULL;
4040

4141
pgd = pgd_offset(mm, addr);
42-
if (pgd_present(*pgd)) {
42+
if (pgd_present(pgdp_get(pgd))) {
4343
p4d = p4d_offset(pgd, addr);
44-
if (p4d_present(*p4d)) {
44+
if (p4d_present(p4dp_get(p4d))) {
4545
pud = pud_offset(p4d, addr);
46-
if (pud_present(*pud))
46+
if (pud_present(pudp_get(pud)))
4747
pmd = pmd_offset(pud, addr);
4848
}
4949
}

arch/loongarch/mm/init.c

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,7 @@ void __meminit vmemmap_set_pmd(pmd_t *pmd, void *p, int node,
141141
int __meminit vmemmap_check_pmd(pmd_t *pmd, int node,
142142
unsigned long addr, unsigned long next)
143143
{
144-
int huge = pmd_val(*pmd) & _PAGE_HUGE;
144+
int huge = pmd_val(pmdp_get(pmd)) & _PAGE_HUGE;
145145

146146
if (huge)
147147
vmemmap_verify((pte_t *)pmd, node, addr, next);
@@ -173,7 +173,7 @@ pte_t * __init populate_kernel_pte(unsigned long addr)
173173
pud_t *pud;
174174
pmd_t *pmd;
175175

176-
if (p4d_none(*p4d)) {
176+
if (p4d_none(p4dp_get(p4d))) {
177177
pud = memblock_alloc(PAGE_SIZE, PAGE_SIZE);
178178
if (!pud)
179179
panic("%s: Failed to allocate memory\n", __func__);
@@ -184,7 +184,7 @@ pte_t * __init populate_kernel_pte(unsigned long addr)
184184
}
185185

186186
pud = pud_offset(p4d, addr);
187-
if (pud_none(*pud)) {
187+
if (pud_none(pudp_get(pud))) {
188188
pmd = memblock_alloc(PAGE_SIZE, PAGE_SIZE);
189189
if (!pmd)
190190
panic("%s: Failed to allocate memory\n", __func__);
@@ -195,7 +195,7 @@ pte_t * __init populate_kernel_pte(unsigned long addr)
195195
}
196196

197197
pmd = pmd_offset(pud, addr);
198-
if (!pmd_present(*pmd)) {
198+
if (!pmd_present(pmdp_get(pmd))) {
199199
pte_t *pte;
200200

201201
pte = memblock_alloc(PAGE_SIZE, PAGE_SIZE);
@@ -216,7 +216,7 @@ void __init __set_fixmap(enum fixed_addresses idx,
216216
BUG_ON(idx <= FIX_HOLE || idx >= __end_of_fixed_addresses);
217217

218218
ptep = populate_kernel_pte(addr);
219-
if (!pte_none(*ptep)) {
219+
if (!pte_none(ptep_get(ptep))) {
220220
pte_ERROR(*ptep);
221221
return;
222222
}

arch/loongarch/mm/kasan_init.c

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ static phys_addr_t __init kasan_alloc_zeroed_page(int node)
105105

106106
static pte_t *__init kasan_pte_offset(pmd_t *pmdp, unsigned long addr, int node, bool early)
107107
{
108-
if (__pmd_none(early, READ_ONCE(*pmdp))) {
108+
if (__pmd_none(early, pmdp_get(pmdp))) {
109109
phys_addr_t pte_phys = early ?
110110
__pa_symbol(kasan_early_shadow_pte) : kasan_alloc_zeroed_page(node);
111111
if (!early)
@@ -118,7 +118,7 @@ static pte_t *__init kasan_pte_offset(pmd_t *pmdp, unsigned long addr, int node,
118118

119119
static pmd_t *__init kasan_pmd_offset(pud_t *pudp, unsigned long addr, int node, bool early)
120120
{
121-
if (__pud_none(early, READ_ONCE(*pudp))) {
121+
if (__pud_none(early, pudp_get(pudp))) {
122122
phys_addr_t pmd_phys = early ?
123123
__pa_symbol(kasan_early_shadow_pmd) : kasan_alloc_zeroed_page(node);
124124
if (!early)
@@ -131,7 +131,7 @@ static pmd_t *__init kasan_pmd_offset(pud_t *pudp, unsigned long addr, int node,
131131

132132
static pud_t *__init kasan_pud_offset(p4d_t *p4dp, unsigned long addr, int node, bool early)
133133
{
134-
if (__p4d_none(early, READ_ONCE(*p4dp))) {
134+
if (__p4d_none(early, p4dp_get(p4dp))) {
135135
phys_addr_t pud_phys = early ?
136136
__pa_symbol(kasan_early_shadow_pud) : kasan_alloc_zeroed_page(node);
137137
if (!early)
@@ -154,7 +154,7 @@ static void __init kasan_pte_populate(pmd_t *pmdp, unsigned long addr,
154154
: kasan_alloc_zeroed_page(node);
155155
next = addr + PAGE_SIZE;
156156
set_pte(ptep, pfn_pte(__phys_to_pfn(page_phys), PAGE_KERNEL));
157-
} while (ptep++, addr = next, addr != end && __pte_none(early, READ_ONCE(*ptep)));
157+
} while (ptep++, addr = next, addr != end && __pte_none(early, ptep_get(ptep)));
158158
}
159159

160160
static void __init kasan_pmd_populate(pud_t *pudp, unsigned long addr,
@@ -166,7 +166,7 @@ static void __init kasan_pmd_populate(pud_t *pudp, unsigned long addr,
166166
do {
167167
next = pmd_addr_end(addr, end);
168168
kasan_pte_populate(pmdp, addr, next, node, early);
169-
} while (pmdp++, addr = next, addr != end && __pmd_none(early, READ_ONCE(*pmdp)));
169+
} while (pmdp++, addr = next, addr != end && __pmd_none(early, pmdp_get(pmdp)));
170170
}
171171

172172
static void __init kasan_pud_populate(p4d_t *p4dp, unsigned long addr,

arch/loongarch/mm/pgtable.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ pmd_t mk_pmd(struct page *page, pgprot_t prot)
128128
void set_pmd_at(struct mm_struct *mm, unsigned long addr,
129129
pmd_t *pmdp, pmd_t pmd)
130130
{
131-
*pmdp = pmd;
131+
WRITE_ONCE(*pmdp, pmd);
132132
flush_tlb_all();
133133
}
134134

0 commit comments

Comments
 (0)