Skip to content

Commit 3425cec

Browse files
Ryan Robertsctmarinas
authored andcommitted
arm64/mm: Hoist synchronization out of set_ptes() loop
set_ptes() sets a physically contiguous block of memory (which all belongs to the same folio) to a contiguous block of ptes. The arm64 implementation of this previously just looped, operating on each individual pte. But the __sync_icache_dcache() and mte_sync_tags() operations can both be hoisted out of the loop so that they are performed once for the contiguous set of pages (which may be less than the whole folio). This should result in minor performance gains. __sync_icache_dcache() already acts on the whole folio, and sets a flag in the folio so that it skips duplicate calls. But by hoisting the call, all the pte testing is done only once. mte_sync_tags() operates on each individual page with its own loop. But by passing the number of pages explicitly, we can rely solely on its loop and do the checks only once. This approach also makes it robust for the future, rather than assuming if a head page of a compound page is being mapped, then the whole compound page is being mapped, instead we explicitly know how many pages are being mapped. The old assumption may not continue to hold once the "anonymous large folios" feature is merged. Signed-off-by: Ryan Roberts <[email protected]> Reviewed-by: Steven Price <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Catalin Marinas <[email protected]>
1 parent 6503357 commit 3425cec

File tree

3 files changed

+21
-14
lines changed

3 files changed

+21
-14
lines changed

arch/arm64/include/asm/mte.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ static inline bool try_page_mte_tagging(struct page *page)
9090
}
9191

9292
void mte_zero_clear_page_tags(void *addr);
93-
void mte_sync_tags(pte_t pte);
93+
void mte_sync_tags(pte_t pte, unsigned int nr_pages);
9494
void mte_copy_page_tags(void *kto, const void *kfrom);
9595
void mte_thread_init_user(void);
9696
void mte_thread_switch(struct task_struct *next);
@@ -122,7 +122,7 @@ static inline bool try_page_mte_tagging(struct page *page)
122122
static inline void mte_zero_clear_page_tags(void *addr)
123123
{
124124
}
125-
static inline void mte_sync_tags(pte_t pte)
125+
static inline void mte_sync_tags(pte_t pte, unsigned int nr_pages)
126126
{
127127
}
128128
static inline void mte_copy_page_tags(void *kto, const void *kfrom)

arch/arm64/include/asm/pgtable.h

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -325,8 +325,7 @@ static inline void __check_safe_pte_update(struct mm_struct *mm, pte_t *ptep,
325325
__func__, pte_val(old_pte), pte_val(pte));
326326
}
327327

328-
static inline void __set_pte_at(struct mm_struct *mm, unsigned long addr,
329-
pte_t *ptep, pte_t pte)
328+
static inline void __sync_cache_and_tags(pte_t pte, unsigned int nr_pages)
330329
{
331330
if (pte_present(pte) && pte_user_exec(pte) && !pte_special(pte))
332331
__sync_icache_dcache(pte);
@@ -339,20 +338,18 @@ static inline void __set_pte_at(struct mm_struct *mm, unsigned long addr,
339338
*/
340339
if (system_supports_mte() && pte_access_permitted(pte, false) &&
341340
!pte_special(pte) && pte_tagged(pte))
342-
mte_sync_tags(pte);
343-
344-
__check_safe_pte_update(mm, ptep, pte);
345-
346-
set_pte(ptep, pte);
341+
mte_sync_tags(pte, nr_pages);
347342
}
348343

349344
static inline void set_ptes(struct mm_struct *mm, unsigned long addr,
350345
pte_t *ptep, pte_t pte, unsigned int nr)
351346
{
352347
page_table_check_ptes_set(mm, ptep, pte, nr);
348+
__sync_cache_and_tags(pte, nr);
353349

354350
for (;;) {
355-
__set_pte_at(mm, addr, ptep, pte);
351+
__check_safe_pte_update(mm, ptep, pte);
352+
set_pte(ptep, pte);
356353
if (--nr == 0)
357354
break;
358355
ptep++;
@@ -531,18 +528,28 @@ static inline pmd_t pmd_mkdevmap(pmd_t pmd)
531528
#define pud_pfn(pud) ((__pud_to_phys(pud) & PUD_MASK) >> PAGE_SHIFT)
532529
#define pfn_pud(pfn,prot) __pud(__phys_to_pud_val((phys_addr_t)(pfn) << PAGE_SHIFT) | pgprot_val(prot))
533530

531+
static inline void __set_pte_at(struct mm_struct *mm, unsigned long addr,
532+
pte_t *ptep, pte_t pte, unsigned int nr)
533+
{
534+
__sync_cache_and_tags(pte, nr);
535+
__check_safe_pte_update(mm, ptep, pte);
536+
set_pte(ptep, pte);
537+
}
538+
534539
static inline void set_pmd_at(struct mm_struct *mm, unsigned long addr,
535540
pmd_t *pmdp, pmd_t pmd)
536541
{
537542
page_table_check_pmd_set(mm, pmdp, pmd);
538-
return __set_pte_at(mm, addr, (pte_t *)pmdp, pmd_pte(pmd));
543+
return __set_pte_at(mm, addr, (pte_t *)pmdp, pmd_pte(pmd),
544+
PMD_SIZE >> PAGE_SHIFT);
539545
}
540546

541547
static inline void set_pud_at(struct mm_struct *mm, unsigned long addr,
542548
pud_t *pudp, pud_t pud)
543549
{
544550
page_table_check_pud_set(mm, pudp, pud);
545-
return __set_pte_at(mm, addr, (pte_t *)pudp, pud_pte(pud));
551+
return __set_pte_at(mm, addr, (pte_t *)pudp, pud_pte(pud),
552+
PUD_SIZE >> PAGE_SHIFT);
546553
}
547554

548555
#define __p4d_to_phys(p4d) __pte_to_phys(p4d_pte(p4d))

arch/arm64/kernel/mte.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,10 +35,10 @@ DEFINE_STATIC_KEY_FALSE(mte_async_or_asymm_mode);
3535
EXPORT_SYMBOL_GPL(mte_async_or_asymm_mode);
3636
#endif
3737

38-
void mte_sync_tags(pte_t pte)
38+
void mte_sync_tags(pte_t pte, unsigned int nr_pages)
3939
{
4040
struct page *page = pte_page(pte);
41-
long i, nr_pages = compound_nr(page);
41+
unsigned int i;
4242

4343
/* if PG_mte_tagged is set, tags have already been initialised */
4444
for (i = 0; i < nr_pages; i++, page++) {

0 commit comments

Comments
 (0)