Skip to content

Commit 0aa3657

Browse files
Dev Jainakpm00
authored andcommitted
mm: add batched versions of ptep_modify_prot_start/commit
Batch ptep_modify_prot_start/commit in preparation for optimizing mprotect, implementing them as a simple loop over the corresponding single pte helpers. Architecture may override these helpers. Link: https://lkml.kernel.org/r/20250718090244.21092-4-dev.jain@arm.com Signed-off-by: Dev Jain <dev.jain@arm.com> Reviewed-by: Lorenzo Stoakes <lorenzo.stoakes@oracle.com> Reviewed-by: Barry Song <baohua@kernel.org> Reviewed-by: Ryan Roberts <ryan.roberts@arm.com> Reviewed-by: Zi Yan <ziy@nvidia.com> Cc: Anshuman Khandual <anshuman.khandual@arm.com> Cc: Catalin Marinas <catalin.marinas@arm.com> Cc: Christophe Leroy <christophe.leroy@csgroup.eu> Cc: David Hildenbrand <david@redhat.com> Cc: Hugh Dickins <hughd@google.com> Cc: Jann Horn <jannh@google.com> Cc: Joey Gouly <joey.gouly@arm.com> Cc: Kevin Brodsky <kevin.brodsky@arm.com> Cc: Lance Yang <ioworker0@gmail.com> Cc: Liam Howlett <liam.howlett@oracle.com> Cc: Matthew Wilcox (Oracle) <willy@infradead.org> Cc: Peter Xu <peterx@redhat.com> Cc: Vlastimil Babka <vbabka@suse.cz> Cc: Will Deacon <will@kernel.org> Cc: Yang Shi <yang@os.amperecomputing.com> Cc: Yicong Yang <yangyicong@hisilicon.com> Cc: Zhenhua Huang <quic_zhenhuah@quicinc.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
1 parent 1d40f4e commit 0aa3657

File tree

2 files changed

+85
-3
lines changed

2 files changed

+85
-3
lines changed

include/linux/pgtable.h

Lines changed: 83 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1331,7 +1331,9 @@ static inline pte_t ptep_modify_prot_start(struct vm_area_struct *vma,
13311331

13321332
/*
13331333
* Commit an update to a pte, leaving any hardware-controlled bits in
1334-
* the PTE unmodified.
1334+
* the PTE unmodified. The pte returned from ptep_modify_prot_start() may
1335+
* additionally have young and/or dirty bits set where previously they were not,
1336+
* so the updated pte may have these additional changes.
13351337
*/
13361338
static inline void ptep_modify_prot_commit(struct vm_area_struct *vma,
13371339
unsigned long addr,
@@ -1340,6 +1342,86 @@ static inline void ptep_modify_prot_commit(struct vm_area_struct *vma,
13401342
__ptep_modify_prot_commit(vma, addr, ptep, pte);
13411343
}
13421344
#endif /* __HAVE_ARCH_PTEP_MODIFY_PROT_TRANSACTION */
1345+
1346+
/**
1347+
* modify_prot_start_ptes - Start a pte protection read-modify-write transaction
1348+
* over a batch of ptes, which protects against asynchronous hardware
1349+
* modifications to the ptes. The intention is not to prevent the hardware from
1350+
* making pte updates, but to prevent any updates it may make from being lost.
1351+
* Please see the comment above ptep_modify_prot_start() for full description.
1352+
*
1353+
* @vma: The virtual memory area the pages are mapped into.
1354+
* @addr: Address the first page is mapped at.
1355+
* @ptep: Page table pointer for the first entry.
1356+
* @nr: Number of entries.
1357+
*
1358+
* May be overridden by the architecture; otherwise, implemented as a simple
1359+
* loop over ptep_modify_prot_start(), collecting the a/d bits from each pte
1360+
* in the batch.
1361+
*
1362+
* Note that PTE bits in the PTE batch besides the PFN can differ.
1363+
*
1364+
* Context: The caller holds the page table lock. The PTEs map consecutive
1365+
* pages that belong to the same folio. All other PTE bits must be identical for
1366+
* all PTEs in the batch except for young and dirty bits. The PTEs are all in
1367+
* the same PMD.
1368+
*/
1369+
#ifndef modify_prot_start_ptes
1370+
static inline pte_t modify_prot_start_ptes(struct vm_area_struct *vma,
1371+
unsigned long addr, pte_t *ptep, unsigned int nr)
1372+
{
1373+
pte_t pte, tmp_pte;
1374+
1375+
pte = ptep_modify_prot_start(vma, addr, ptep);
1376+
while (--nr) {
1377+
ptep++;
1378+
addr += PAGE_SIZE;
1379+
tmp_pte = ptep_modify_prot_start(vma, addr, ptep);
1380+
if (pte_dirty(tmp_pte))
1381+
pte = pte_mkdirty(pte);
1382+
if (pte_young(tmp_pte))
1383+
pte = pte_mkyoung(pte);
1384+
}
1385+
return pte;
1386+
}
1387+
#endif
1388+
1389+
/**
1390+
* modify_prot_commit_ptes - Commit an update to a batch of ptes, leaving any
1391+
* hardware-controlled bits in the PTE unmodified.
1392+
*
1393+
* @vma: The virtual memory area the pages are mapped into.
1394+
* @addr: Address the first page is mapped at.
1395+
* @ptep: Page table pointer for the first entry.
1396+
* @old_pte: Old page table entry (for the first entry) which is now cleared.
1397+
* @pte: New page table entry to be set.
1398+
* @nr: Number of entries.
1399+
*
1400+
* May be overridden by the architecture; otherwise, implemented as a simple
1401+
* loop over ptep_modify_prot_commit().
1402+
*
1403+
* Context: The caller holds the page table lock. The PTEs are all in the same
1404+
* PMD. On exit, the set ptes in the batch map the same folio. The ptes set by
1405+
* ptep_modify_prot_start() may additionally have young and/or dirty bits set
1406+
* where previously they were not, so the updated ptes may have these
1407+
* additional changes.
1408+
*/
1409+
#ifndef modify_prot_commit_ptes
1410+
static inline void modify_prot_commit_ptes(struct vm_area_struct *vma, unsigned long addr,
1411+
pte_t *ptep, pte_t old_pte, pte_t pte, unsigned int nr)
1412+
{
1413+
int i;
1414+
1415+
for (i = 0; i < nr; ++i, ++ptep, addr += PAGE_SIZE) {
1416+
ptep_modify_prot_commit(vma, addr, ptep, old_pte, pte);
1417+
1418+
/* Advance PFN only, set same prot */
1419+
old_pte = pte_next_pfn(old_pte);
1420+
pte = pte_next_pfn(pte);
1421+
}
1422+
}
1423+
#endif
1424+
13431425
#endif /* CONFIG_MMU */
13441426

13451427
/*

mm/mprotect.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,7 @@ static long change_pte_range(struct mmu_gather *tlb,
204204
}
205205
}
206206

207-
oldpte = ptep_modify_prot_start(vma, addr, pte);
207+
oldpte = modify_prot_start_ptes(vma, addr, pte, nr_ptes);
208208
ptent = pte_modify(oldpte, newprot);
209209

210210
if (uffd_wp)
@@ -230,7 +230,7 @@ static long change_pte_range(struct mmu_gather *tlb,
230230
can_change_pte_writable(vma, addr, ptent))
231231
ptent = pte_mkwrite(ptent, vma);
232232

233-
ptep_modify_prot_commit(vma, addr, pte, oldpte, ptent);
233+
modify_prot_commit_ptes(vma, addr, pte, oldpte, ptent, nr_ptes);
234234
if (pte_needs_flush(oldpte, ptent))
235235
tlb_flush_pte_range(tlb, addr, PAGE_SIZE);
236236
pages++;

0 commit comments

Comments
 (0)