Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions Documentation/mm/process_addrs.rst
Original file line number Diff line number Diff line change
Expand Up @@ -537,6 +537,12 @@ We establish basic locking rules when interacting with page tables:
* When changing a page table entry the page table lock for that page table
**must** be held, except if you can safely assume nobody can access the page
tables concurrently (such as on invocation of :c:func:`!free_pgtables`).
* Page tables may be *walked* under RCU alone, as page tables are freed only
after an RCU grace period has elapsed. However, any entry found must be
revalidated after the page table lock is taken (such as the
:c:func:`!pmd_same` recheck performed by :c:func:`!pte_offset_map_lock`)
before it is acted upon. Changing an entry requires the page table
lock and one of the locks that excludes teardown (mmap or VMA lock).
* Reads from and writes to page table entries must be *appropriately*
atomic. See the section on atomicity below for details.
* Populating previously empty entries requires that the mmap or VMA locks are
Expand Down
8 changes: 0 additions & 8 deletions arch/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -526,13 +526,6 @@ config HAVE_ARCH_JUMP_LABEL
config HAVE_ARCH_JUMP_LABEL_RELATIVE
bool

config MMU_GATHER_TABLE_FREE
bool

config MMU_GATHER_RCU_TABLE_FREE
bool
select MMU_GATHER_TABLE_FREE

config MMU_GATHER_PAGE_SIZE
bool

Expand All @@ -548,7 +541,6 @@ config MMU_GATHER_MERGE_VMAS

config MMU_GATHER_NO_GATHER
bool
depends on MMU_GATHER_TABLE_FREE

config ARCH_WANT_IRQS_OFF_ACTIVATE_MM
bool
Expand Down
1 change: 0 additions & 1 deletion arch/alpha/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@ config ALPHA
select ARCH_STACKWALK
select CPU_NO_EFFICIENT_FFS if !ALPHA_EV67
select MMU_GATHER_NO_RANGE
select MMU_GATHER_RCU_TABLE_FREE
select SPARSEMEM_EXTREME if SPARSEMEM
select ZONE_DMA
select TRACE_IRQFLAGS_SUPPORT
Expand Down
6 changes: 3 additions & 3 deletions arch/arc/include/asm/pgalloc.h
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ static inline void p4d_populate(struct mm_struct *mm, p4d_t *p4dp, pud_t *pudp)
set_p4d(p4dp, __p4d((unsigned long)pudp));
}

#define __pud_free_tlb(tlb, pmd, addr) pud_free((tlb)->mm, pmd)
#define __pud_free_tlb(tlb, pmd, addr) tlb_remove_ptdesc((tlb), virt_to_ptdesc(pmd))

#endif

Expand All @@ -83,10 +83,10 @@ static inline void pud_populate(struct mm_struct *mm, pud_t *pudp, pmd_t *pmdp)
set_pud(pudp, __pud((unsigned long)pmdp));
}

#define __pmd_free_tlb(tlb, pmd, addr) pmd_free((tlb)->mm, pmd)
#define __pmd_free_tlb(tlb, pmd, addr) tlb_remove_ptdesc((tlb), virt_to_ptdesc(pmd))

#endif

#define __pte_free_tlb(tlb, pte, addr) pte_free((tlb)->mm, pte)
#define __pte_free_tlb(tlb, pte, addr) tlb_remove_ptdesc((tlb), page_ptdesc(pte))

#endif /* _ASM_ARC_PGALLOC_H */
1 change: 0 additions & 1 deletion arch/arm/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,6 @@ config ARM
select HAVE_PERF_REGS
select HAVE_PERF_USER_STACK_DUMP
select HAVE_POSIX_CPU_TIMERS_TASK_WORK
select MMU_GATHER_RCU_TABLE_FREE if SMP && ARM_LPAE
select HAVE_REGS_AND_STACK_ACCESS_API
select HAVE_RSEQ
select HAVE_RUST if CPU_LITTLE_ENDIAN && CPU_32v7 && !KASAN
Expand Down
1 change: 0 additions & 1 deletion arch/arm64/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,6 @@ config ARM64
select HAVE_RELIABLE_STACKTRACE
select HAVE_POSIX_CPU_TIMERS_TASK_WORK
select HAVE_FUNCTION_ARG_ACCESS_API
select MMU_GATHER_RCU_TABLE_FREE
select HAVE_RSEQ
select HAVE_RUST if RUSTC_SUPPORTS_ARM64
select HAVE_STACKPROTECTOR
Expand Down
1 change: 0 additions & 1 deletion arch/loongarch/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,6 @@ config LOONGARCH
select IRQ_LOONGARCH_CPU
select LOCK_MM_AND_FIND_VMA
select MMU_GATHER_MERGE_VMAS if MMU
select MMU_GATHER_RCU_TABLE_FREE
select MODULES_USE_ELF_RELA if MODULES
select NEED_PER_CPU_EMBED_FIRST_CHUNK
select NEED_PER_CPU_PAGE_FIRST_CHUNK
Expand Down
1 change: 1 addition & 0 deletions arch/m68k/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ config M68K
select HAVE_ARCH_LIBGCC_H
select HAVE_ARCH_SECCOMP
select HAVE_ARCH_SECCOMP_FILTER
select HAVE_ARCH_TLB_REMOVE_TABLE if MMU_MOTOROLA
select HAVE_ASM_MODVERSIONS
select HAVE_DEBUG_BUGVERBOSE
select HAVE_EFFICIENT_UNALIGNED_ACCESS if !CPU_HAS_NO_UNALIGNED
Expand Down
5 changes: 1 addition & 4 deletions arch/m68k/include/asm/mcf_pgalloc.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,7 @@ extern inline pmd_t *pmd_alloc_kernel(pgd_t *pgd, unsigned long address)
static inline void __pte_free_tlb(struct mmu_gather *tlb, pgtable_t pgtable,
unsigned long address)
{
struct ptdesc *ptdesc = virt_to_ptdesc(pgtable);

pagetable_dtor(ptdesc);
pagetable_free(ptdesc);
tlb_remove_ptdesc(tlb, virt_to_ptdesc(pgtable));
}

static inline pgtable_t pte_alloc_one(struct mm_struct *mm)
Expand Down
9 changes: 5 additions & 4 deletions arch/m68k/include/asm/motorola_pgalloc.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ enum m68k_table_types {
extern void init_pointer_table(void *table, int type);
extern void *get_pointer_table(struct mm_struct *mm, int type);
extern int free_pointer_table(void *table, int type);
extern void __tlb_remove_table(void *table);

/*
* Allocate and free page tables. The xxx_kernel() versions are
Expand Down Expand Up @@ -47,7 +48,7 @@ static inline void pte_free(struct mm_struct *mm, pgtable_t pgtable)
static inline void __pte_free_tlb(struct mmu_gather *tlb, pgtable_t pgtable,
unsigned long address)
{
free_pointer_table(pgtable, TABLE_PTE);
tlb_remove_table(tlb, (void *)((unsigned long)pgtable | TABLE_PTE));
}


Expand All @@ -61,10 +62,10 @@ static inline int pmd_free(struct mm_struct *mm, pmd_t *pmd)
return free_pointer_table(pmd, TABLE_PMD);
}

static inline int __pmd_free_tlb(struct mmu_gather *tlb, pmd_t *pmd,
unsigned long address)
static inline void __pmd_free_tlb(struct mmu_gather *tlb, pmd_t *pmd,
unsigned long address)
{
return free_pointer_table(pmd, TABLE_PMD);
tlb_remove_table(tlb, (void *)((unsigned long)pmd | TABLE_PMD));
}


Expand Down
121 changes: 79 additions & 42 deletions arch/m68k/mm/motorola.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include <linux/init.h>
#include <linux/memblock.h>
#include <linux/gfp.h>
#include <linux/cleanup.h>

#include <asm/setup.h>
#include <linux/uaccess.h>
Expand Down Expand Up @@ -103,6 +104,8 @@ static struct list_head ptable_list[3] = {
LIST_HEAD_INIT(ptable_list[2]),
};

static DEFINE_SPINLOCK(ptable_lock);

#define PD_PTABLE(ptdesc) ((ptable_desc *)&(virt_to_ptdesc((void *)(ptdesc))->pt_list))
#define PD_PTDESC(ptable) (list_entry(ptable, struct ptdesc, pt_list))
#define PD_MARKBITS(dp) (*(unsigned int *)&PD_PTDESC(dp)->pt_index)
Expand Down Expand Up @@ -139,52 +142,66 @@ void __init init_pointer_table(void *table, int type)
return;
}

void *get_pointer_table(struct mm_struct *mm, int type)
/*
* For a pointer table for a user process address space, a
* table is taken from a ptdesc allocated for the purpose. Each
* ptdesc can hold 8 pointer tables. The ptdesc is remapped in
* virtual address space to be noncacheable.
*/
static void *add_pointer_table(struct mm_struct *mm, int type)
{
ptable_desc *dp = ptable_list[type].next;
unsigned int mask = list_empty(&ptable_list[type]) ? 0 : PD_MARKBITS(dp);
unsigned int tmp, off;
struct ptdesc *ptdesc;
ptable_desc *new;
void *pt_addr;

/*
* For a pointer table for a user process address space, a
* table is taken from a ptdesc allocated for the purpose. Each
* ptdesc can hold 8 pointer tables. The ptdesc is remapped in
* virtual address space to be noncacheable.
*/
if (mask == 0) {
struct ptdesc *ptdesc;
ptable_desc *new;
void *pt_addr;

ptdesc = pagetable_alloc(GFP_KERNEL | __GFP_ZERO, 0);
if (!ptdesc)
return NULL;

pt_addr = ptdesc_address(ptdesc);

switch (type) {
case TABLE_PTE:
/*
* m68k doesn't have SPLIT_PTE_PTLOCKS for not having
* SMP.
*/
pagetable_pte_ctor(mm, ptdesc);
break;
case TABLE_PMD:
pagetable_pmd_ctor(mm, ptdesc);
break;
case TABLE_PGD:
pagetable_pgd_ctor(ptdesc);
break;
}
ptdesc = pagetable_alloc(GFP_KERNEL | __GFP_ZERO, 0);
if (!ptdesc)
return NULL;

pt_addr = ptdesc_address(ptdesc);

switch (type) {
case TABLE_PTE:
/*
* m68k doesn't have SPLIT_PTE_PTLOCKS for not having
* SMP.
*/
pagetable_pte_ctor(mm, ptdesc);
break;
case TABLE_PMD:
pagetable_pmd_ctor(mm, ptdesc);
break;
case TABLE_PGD:
pagetable_pgd_ctor(ptdesc);
break;
}

mmu_page_ctor(pt_addr);

new = PD_PTABLE(pt_addr);

mmu_page_ctor(pt_addr);
PD_MARKBITS(new) = ptable_mask(type) - 1;
scoped_guard(spinlock_irqsave, &ptable_lock)
list_add(new, &ptable_list[type]);

new = PD_PTABLE(pt_addr);
PD_MARKBITS(new) = ptable_mask(type) - 1;
list_add_tail(new, dp);
return (pmd_t *)pt_addr;
}

void *get_pointer_table(struct mm_struct *mm, int type)
{
unsigned int tmp, off;
unsigned long mask;
unsigned long flags;
ptable_desc *dp;
void *ret;

return (pmd_t *)pt_addr;
spin_lock_irqsave(&ptable_lock, flags);
dp = ptable_list[type].next;
mask = list_empty(&ptable_list[type]) ? 0 : PD_MARKBITS(dp);

if (mask == 0) {
spin_unlock_irqrestore(&ptable_lock, flags);
return add_pointer_table(mm, type);
}

for (tmp = 1, off = 0; (mask & tmp) == 0; tmp <<= 1, off += ptable_size(type))
Expand All @@ -194,7 +211,10 @@ void *get_pointer_table(struct mm_struct *mm, int type)
/* move to end of list */
list_move_tail(dp, &ptable_list[type]);
}
return ptdesc_address(PD_PTDESC(dp)) + off;

ret = ptdesc_address(PD_PTDESC(dp)) + off;
spin_unlock_irqrestore(&ptable_lock, flags);
return ret;
}

int free_pointer_table(void *table, int type)
Expand All @@ -203,6 +223,9 @@ int free_pointer_table(void *table, int type)
unsigned long ptable = (unsigned long)table;
unsigned long pt_addr = ptable & PAGE_MASK;
unsigned int mask = 1U << ((ptable - pt_addr)/ptable_size(type));
unsigned long flags;

spin_lock_irqsave(&ptable_lock, flags);

dp = PD_PTABLE(pt_addr);
if (PD_MARKBITS (dp) & mask)
Expand All @@ -213,6 +236,8 @@ int free_pointer_table(void *table, int type)
if (PD_MARKBITS(dp) == ptable_mask(type)) {
/* all tables in ptdesc are free, free ptdesc */
list_del(dp);
spin_unlock_irqrestore(&ptable_lock, flags);

mmu_page_dtor((void *)pt_addr);
pagetable_dtor_free(virt_to_ptdesc((void *)pt_addr));
return 1;
Expand All @@ -223,9 +248,21 @@ int free_pointer_table(void *table, int type)
*/
list_move(dp, &ptable_list[type]);
}

spin_unlock_irqrestore(&ptable_lock, flags);
return 0;
}

void __tlb_remove_table(void *table)
{
/* The bottom 2 bits are used to encode page table type. */
const unsigned long encoded = (unsigned long)table;
void *addr = (void *)(encoded & ~3UL);
const int type = encoded & 3;

free_pointer_table(addr, type);
}

/* size of memory already mapped in head.S */
extern __initdata unsigned long m68k_init_mapped_size;

Expand Down
2 changes: 1 addition & 1 deletion arch/microblaze/include/asm/pgalloc.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ extern void __bad_pte(pmd_t *pmd);

extern pte_t *pte_alloc_one_kernel(struct mm_struct *mm);

#define __pte_free_tlb(tlb, pte, addr) pte_free((tlb)->mm, (pte))
#define __pte_free_tlb(tlb, pte, addr) tlb_remove_ptdesc((tlb), page_ptdesc(pte))

#define pmd_populate(mm, pmd, pte) \
(pmd_val(*(pmd)) = (unsigned long)page_address(pte))
Expand Down
1 change: 0 additions & 1 deletion arch/mips/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,6 @@ config MIPS
select IRQ_FORCED_THREADING
select ISA if EISA
select LOCK_MM_AND_FIND_VMA
select MMU_GATHER_RCU_TABLE_FREE
select MODULES_USE_ELF_REL if MODULES
select MODULES_USE_ELF_RELA if MODULES && 64BIT
select PERF_USE_VMALLOC
Expand Down
1 change: 0 additions & 1 deletion arch/parisc/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,6 @@ config PARISC
select GENERIC_CLOCKEVENTS
select CPU_NO_EFFICIENT_FFS
select THREAD_INFO_IN_TASK
select MMU_GATHER_RCU_TABLE_FREE
select NEED_DMA_MAP_STATE
select NEED_SG_DMA_LENGTH
select HAVE_ARCH_KGDB
Expand Down
1 change: 0 additions & 1 deletion arch/powerpc/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -307,7 +307,6 @@ config PPC
select KASAN_VMALLOC if KASAN && EXECMEM
select LOCK_MM_AND_FIND_VMA
select MMU_GATHER_PAGE_SIZE
select MMU_GATHER_RCU_TABLE_FREE
select HAVE_ARCH_TLB_REMOVE_TABLE
select MMU_GATHER_MERGE_VMAS
select MMU_LAZY_TLB_SHOOTDOWN if PPC_BOOK3S_64
Expand Down
1 change: 0 additions & 1 deletion arch/riscv/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,6 @@ config RISCV
select IRQ_FORCED_THREADING
select KASAN_VMALLOC if KASAN
select LOCK_MM_AND_FIND_VMA
select MMU_GATHER_RCU_TABLE_FREE if SMP && MMU
select MODULES_USE_ELF_RELA if MODULES
select OF
select OF_EARLY_FLATTREE
Expand Down
1 change: 0 additions & 1 deletion arch/s390/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -268,7 +268,6 @@ config S390
select LOCK_MM_AND_FIND_VMA
select MMU_GATHER_MERGE_VMAS
select MMU_GATHER_NO_GATHER
select MMU_GATHER_RCU_TABLE_FREE
select MODULES_USE_ELF_RELA
select NEED_DMA_MAP_STATE if PCI
select NEED_PER_CPU_EMBED_FIRST_CHUNK
Expand Down
1 change: 1 addition & 0 deletions arch/sh/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ config SUPERH
select HAVE_ARCH_AUDITSYSCALL
select HAVE_ARCH_KGDB
select HAVE_ARCH_SECCOMP_FILTER
select HAVE_ARCH_TLB_REMOVE_TABLE if X2TLB
select HAVE_ARCH_TRACEHOOK
select HAVE_DEBUG_BUGVERBOSE
select HAVE_DEBUG_KMEMLEAK
Expand Down
6 changes: 5 additions & 1 deletion arch/sh/include/asm/pgalloc.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,11 @@ extern void pgd_free(struct mm_struct *mm, pgd_t *pgd);
extern void pud_populate(struct mm_struct *mm, pud_t *pudp, pmd_t *pmd);
extern pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long address);
extern void pmd_free(struct mm_struct *mm, pmd_t *pmd);
#define __pmd_free_tlb(tlb, pmdp, addr) pmd_free((tlb)->mm, (pmdp))
extern void __tlb_remove_table(void *table);

/* PMDs are slab-allocated, tag so they are freed correctly. */
#define __pmd_free_tlb(tlb, pmdp, addr) \
tlb_remove_table((tlb), (void *)((unsigned long)(pmdp) | 1))
#endif

static inline void pmd_populate_kernel(struct mm_struct *mm, pmd_t *pmd,
Expand Down
Loading
Loading