Skip to content

Commit d862613

Browse files
joergroedeltorvalds
authored andcommitted
mm: add functions to track page directory modifications
Patch series "mm: Get rid of vmalloc_sync_(un)mappings()", v3. After the recent issue with vmalloc and tracing code[1] on x86 and a long history of previous issues related to the vmalloc_sync_mappings() interface, I thought the time has come to remove it. Please see [2], [3], and [4] for some other issues in the past. The patches add tracking of page-table directory changes to the vmalloc and ioremap code. Depending on which page-table levels changes have been made, a new per-arch function is called: arch_sync_kernel_mappings(). On x86-64 with 4-level paging, this function will not be called more than 64 times in a systems runtime (because vmalloc-space takes 64 PGD entries which are only populated, but never cleared). As a side effect this also allows to get rid of vmalloc faults on x86, making it safe to touch vmalloc'ed memory in the page-fault handler. Note that this potentially includes per-cpu memory. This patch (of 7): Add page-table allocation functions which will keep track of changed directory entries. They are needed for new PGD, P4D, PUD, and PMD entries and will be used in vmalloc and ioremap code to decide whether any changes in the kernel mappings need to be synchronized between page-tables in the system. Signed-off-by: Joerg Roedel <[email protected]> Signed-off-by: Andrew Morton <[email protected]> Acked-by: Andy Lutomirski <[email protected]> Acked-by: Peter Zijlstra (Intel) <[email protected]> Cc: "H . Peter Anvin" <[email protected]> Cc: Dave Hansen <[email protected]> Cc: "Rafael J. Wysocki" <[email protected]> Cc: Arnd Bergmann <[email protected]> Cc: Steven Rostedt (VMware) <[email protected]> Cc: Vlastimil Babka <[email protected]> Cc: Michal Hocko <[email protected]> Cc: Matthew Wilcox (Oracle) <[email protected]> Cc: Ingo Molnar <[email protected]> Cc: Thomas Gleixner <[email protected]> Cc: Christoph Hellwig <[email protected]> Link: http://lkml.kernel.org/r/[email protected] Link: http://lkml.kernel.org/r/[email protected] Signed-off-by: Linus Torvalds <[email protected]>
1 parent b200f5b commit d862613

File tree

3 files changed

+72
-2
lines changed

3 files changed

+72
-2
lines changed

include/asm-generic/5level-fixup.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,9 @@
1717
((unlikely(pgd_none(*(p4d))) && __pud_alloc(mm, p4d, address)) ? \
1818
NULL : pud_offset(p4d, address))
1919

20-
#define p4d_alloc(mm, pgd, address) (pgd)
21-
#define p4d_offset(pgd, start) (pgd)
20+
#define p4d_alloc(mm, pgd, address) (pgd)
21+
#define p4d_alloc_track(mm, pgd, address, mask) (pgd)
22+
#define p4d_offset(pgd, start) (pgd)
2223

2324
#ifndef __ASSEMBLY__
2425
static inline int p4d_none(p4d_t p4d)

include/asm-generic/pgtable.h

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1213,6 +1213,29 @@ static inline bool arch_has_pfn_modify_check(void)
12131213
# define PAGE_KERNEL_EXEC PAGE_KERNEL
12141214
#endif
12151215

1216+
/*
1217+
* Page Table Modification bits for pgtbl_mod_mask.
1218+
*
1219+
* These are used by the p?d_alloc_track*() set of functions an in the generic
1220+
* vmalloc/ioremap code to track at which page-table levels entries have been
1221+
* modified. Based on that the code can better decide when vmalloc and ioremap
1222+
* mapping changes need to be synchronized to other page-tables in the system.
1223+
*/
1224+
#define __PGTBL_PGD_MODIFIED 0
1225+
#define __PGTBL_P4D_MODIFIED 1
1226+
#define __PGTBL_PUD_MODIFIED 2
1227+
#define __PGTBL_PMD_MODIFIED 3
1228+
#define __PGTBL_PTE_MODIFIED 4
1229+
1230+
#define PGTBL_PGD_MODIFIED BIT(__PGTBL_PGD_MODIFIED)
1231+
#define PGTBL_P4D_MODIFIED BIT(__PGTBL_P4D_MODIFIED)
1232+
#define PGTBL_PUD_MODIFIED BIT(__PGTBL_PUD_MODIFIED)
1233+
#define PGTBL_PMD_MODIFIED BIT(__PGTBL_PMD_MODIFIED)
1234+
#define PGTBL_PTE_MODIFIED BIT(__PGTBL_PTE_MODIFIED)
1235+
1236+
/* Page-Table Modification Mask */
1237+
typedef unsigned int pgtbl_mod_mask;
1238+
12161239
#endif /* !__ASSEMBLY__ */
12171240

12181241
#ifndef io_remap_pfn_range

include/linux/mm.h

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2091,13 +2091,54 @@ static inline pud_t *pud_alloc(struct mm_struct *mm, p4d_t *p4d,
20912091
return (unlikely(p4d_none(*p4d)) && __pud_alloc(mm, p4d, address)) ?
20922092
NULL : pud_offset(p4d, address);
20932093
}
2094+
2095+
static inline p4d_t *p4d_alloc_track(struct mm_struct *mm, pgd_t *pgd,
2096+
unsigned long address,
2097+
pgtbl_mod_mask *mod_mask)
2098+
2099+
{
2100+
if (unlikely(pgd_none(*pgd))) {
2101+
if (__p4d_alloc(mm, pgd, address))
2102+
return NULL;
2103+
*mod_mask |= PGTBL_PGD_MODIFIED;
2104+
}
2105+
2106+
return p4d_offset(pgd, address);
2107+
}
2108+
20942109
#endif /* !__ARCH_HAS_5LEVEL_HACK */
20952110

2111+
static inline pud_t *pud_alloc_track(struct mm_struct *mm, p4d_t *p4d,
2112+
unsigned long address,
2113+
pgtbl_mod_mask *mod_mask)
2114+
{
2115+
if (unlikely(p4d_none(*p4d))) {
2116+
if (__pud_alloc(mm, p4d, address))
2117+
return NULL;
2118+
*mod_mask |= PGTBL_P4D_MODIFIED;
2119+
}
2120+
2121+
return pud_offset(p4d, address);
2122+
}
2123+
20962124
static inline pmd_t *pmd_alloc(struct mm_struct *mm, pud_t *pud, unsigned long address)
20972125
{
20982126
return (unlikely(pud_none(*pud)) && __pmd_alloc(mm, pud, address))?
20992127
NULL: pmd_offset(pud, address);
21002128
}
2129+
2130+
static inline pmd_t *pmd_alloc_track(struct mm_struct *mm, pud_t *pud,
2131+
unsigned long address,
2132+
pgtbl_mod_mask *mod_mask)
2133+
{
2134+
if (unlikely(pud_none(*pud))) {
2135+
if (__pmd_alloc(mm, pud, address))
2136+
return NULL;
2137+
*mod_mask |= PGTBL_PUD_MODIFIED;
2138+
}
2139+
2140+
return pmd_offset(pud, address);
2141+
}
21012142
#endif /* CONFIG_MMU */
21022143

21032144
#if USE_SPLIT_PTE_PTLOCKS
@@ -2213,6 +2254,11 @@ static inline void pgtable_pte_page_dtor(struct page *page)
22132254
((unlikely(pmd_none(*(pmd))) && __pte_alloc_kernel(pmd))? \
22142255
NULL: pte_offset_kernel(pmd, address))
22152256

2257+
#define pte_alloc_kernel_track(pmd, address, mask) \
2258+
((unlikely(pmd_none(*(pmd))) && \
2259+
(__pte_alloc_kernel(pmd) || ({*(mask)|=PGTBL_PMD_MODIFIED;0;})))?\
2260+
NULL: pte_offset_kernel(pmd, address))
2261+
22162262
#if USE_SPLIT_PMD_PTLOCKS
22172263

22182264
static struct page *pmd_to_page(pmd_t *pmd)

0 commit comments

Comments
 (0)