mirror of
https://github.com/torvalds/linux.git
synced 2024-11-10 22:21:40 +00:00
mm: add pte_batch_hint() to reduce scanning in folio_pte_batch()
Some architectures (e.g. arm64) can tell from looking at a pte, if some follow-on ptes also map contiguous physical memory with the same pgprot. (for arm64, these are contpte mappings). Take advantage of this knowledge to optimize folio_pte_batch() so that it can skip these ptes when scanning to create a batch. By default, if an arch does not opt-in, folio_pte_batch() returns a compile-time 1, so the changes are optimized out and the behaviour is as before. arm64 will opt-in to providing this hint in the next patch, which will greatly reduce the cost of ptep_get() when scanning a range of contptes. Link: https://lkml.kernel.org/r/20240215103205.2607016-16-ryan.roberts@arm.com Signed-off-by: Ryan Roberts <ryan.roberts@arm.com> Acked-by: David Hildenbrand <david@redhat.com> Tested-by: John Hubbard <jhubbard@nvidia.com> Cc: Alistair Popple <apopple@nvidia.com> Cc: Andrey Ryabinin <ryabinin.a.a@gmail.com> Cc: Ard Biesheuvel <ardb@kernel.org> Cc: Barry Song <21cnbao@gmail.com> Cc: Borislav Petkov (AMD) <bp@alien8.de> Cc: Catalin Marinas <catalin.marinas@arm.com> Cc: Dave Hansen <dave.hansen@linux.intel.com> Cc: "H. Peter Anvin" <hpa@zytor.com> Cc: Ingo Molnar <mingo@redhat.com> Cc: James Morse <james.morse@arm.com> Cc: Kefeng Wang <wangkefeng.wang@huawei.com> Cc: Marc Zyngier <maz@kernel.org> Cc: Mark Rutland <mark.rutland@arm.com> Cc: Matthew Wilcox (Oracle) <willy@infradead.org> Cc: Thomas Gleixner <tglx@linutronix.de> Cc: Will Deacon <will@kernel.org> Cc: Yang Shi <shy828301@gmail.com> Cc: Zi Yan <ziy@nvidia.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
This commit is contained in:
parent
6b1e4efb6f
commit
c6ec76a2eb
@ -212,6 +212,27 @@ static inline int pmd_dirty(pmd_t pmd)
|
||||
#define arch_flush_lazy_mmu_mode() do {} while (0)
|
||||
#endif
|
||||
|
||||
#ifndef pte_batch_hint
|
||||
/**
|
||||
* pte_batch_hint - Number of pages that can be added to batch without scanning.
|
||||
* @ptep: Page table pointer for the entry.
|
||||
* @pte: Page table entry.
|
||||
*
|
||||
* Some architectures know that a set of contiguous ptes all map the same
|
||||
* contiguous memory with the same permissions. In this case, it can provide a
|
||||
* hint to aid pte batching without the core code needing to scan every pte.
|
||||
*
|
||||
* An architecture implementation may ignore the PTE accessed state. Further,
|
||||
* the dirty state must apply atomically to all the PTEs described by the hint.
|
||||
*
|
||||
* May be overridden by the architecture, else pte_batch_hint is always 1.
|
||||
*/
|
||||
static inline unsigned int pte_batch_hint(pte_t *ptep, pte_t pte)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef pte_advance_pfn
|
||||
static inline pte_t pte_advance_pfn(pte_t pte, unsigned long nr)
|
||||
{
|
||||
|
19
mm/memory.c
19
mm/memory.c
@ -988,16 +988,20 @@ static inline int folio_pte_batch(struct folio *folio, unsigned long addr,
|
||||
{
|
||||
unsigned long folio_end_pfn = folio_pfn(folio) + folio_nr_pages(folio);
|
||||
const pte_t *end_ptep = start_ptep + max_nr;
|
||||
pte_t expected_pte = __pte_batch_clear_ignored(pte_next_pfn(pte), flags);
|
||||
pte_t *ptep = start_ptep + 1;
|
||||
pte_t expected_pte, *ptep;
|
||||
bool writable;
|
||||
int nr;
|
||||
|
||||
if (any_writable)
|
||||
*any_writable = false;
|
||||
|
||||
VM_WARN_ON_FOLIO(!pte_present(pte), folio);
|
||||
|
||||
while (ptep != end_ptep) {
|
||||
nr = pte_batch_hint(start_ptep, pte);
|
||||
expected_pte = __pte_batch_clear_ignored(pte_advance_pfn(pte, nr), flags);
|
||||
ptep = start_ptep + nr;
|
||||
|
||||
while (ptep < end_ptep) {
|
||||
pte = ptep_get(ptep);
|
||||
if (any_writable)
|
||||
writable = !!pte_write(pte);
|
||||
@ -1011,17 +1015,18 @@ static inline int folio_pte_batch(struct folio *folio, unsigned long addr,
|
||||
* corner cases the next PFN might fall into a different
|
||||
* folio.
|
||||
*/
|
||||
if (pte_pfn(pte) == folio_end_pfn)
|
||||
if (pte_pfn(pte) >= folio_end_pfn)
|
||||
break;
|
||||
|
||||
if (any_writable)
|
||||
*any_writable |= writable;
|
||||
|
||||
expected_pte = pte_next_pfn(expected_pte);
|
||||
ptep++;
|
||||
nr = pte_batch_hint(ptep, pte);
|
||||
expected_pte = pte_advance_pfn(expected_pte, nr);
|
||||
ptep += nr;
|
||||
}
|
||||
|
||||
return ptep - start_ptep;
|
||||
return min(ptep - start_ptep, max_nr);
|
||||
}
|
||||
|
||||
/*
|
||||
|
Loading…
Reference in New Issue
Block a user