MM: Make Page Tables Relocatable -- Conditional Flush
Subsystems (11)
PATCH 1/2 MM: Make Page Tables Relocatable -- Conditional Flush
These Patches make page tables relocatable for numa, memory defragmentation, and memory hotblug. The potential need to rewalk the page tables before making any changes causes a 1.6% peformance degredation in the lmbench page miss micro benchmark.
Page table relocation is critical for several projects.
1) Numa system process relcoation. Currently, when a process is migrated from one node to another the page tables are left behind. This means increased latency and inter-node traffic on all page faults. Migrating the page tables with the process will be a performance win.
2) Memory hotplug. Currently memory hotplug cannot move page tables out of the memory that is about to be removed. This code is a first step to being able to move page tables out of memory that is going to be unplugged.
3) Memory defragmentation. Currently page tables are the largest chunk of non-moveable memory (needs verification). By making page tables relocatable, we can decrease the number of memory fragments and allow for higher order allocations. This is important for supporting huge pages that can greatly improve performance in some circumstances.
There are two sets of entry points to the relocation code. The first is migrate_page_tables_mm which is used to relocate page tables from one node to another. It is the primary entry point for 1 and currently the easiest way to test the code.
The second set of entry points are the migrate_pXX_entry routines. They can be used to relocate a single page table to a new page. Before using these functions, enter_page_table_relocation_mode must be called. When the page tables have been relocated and the old ones have been freed, then leave_pagee_table_relocation_mode must be called. These routines can be used to support 2 and 3 above. Because of the use of the page_table_lock, these rouintes cannot be called at interrupt time.
See the comments in the code for the overall strategy to accomplish the relocation. In particular, look in mm/migrate.c right after the #ifdef CONFIG_RELOCATE_PAGE_TABLES.
Currently only x86_64 is fully supported, although x86_32 has a good chance to work. The key routines that must be written are a tlb_reload, pXX_alloc_node routines, pXX cleanup routines, and finally a routine to copy bits (Dirty and Accessed in particular) the CPU might update from an old page table entry to a new one.
------
These patches are still against 2.6.25-rc9. Final patches will have to wait until the x86 unification is complete, or nearly so.
arch/avr32/mm/tlb.c renamed from home/rossb/local/linux-2.6.25-rc9/arch/avr32/mm/tlb.c +2 -0
@@ -249,6 +249,8 @@ void flush_tlb_kernel_range(unsigned lonvoid flush_tlb_mm (struct mm_struct *mm) { +clear_bit (MMF_NEED_FLUSH , mm->flags); +/* Invalidate all TLB entries of this process by getting a new ASID */ if (mm->context !=NO_CONTEXT ) {unsigned long flags;
arch/cris/arch-v10/mm/tlb.c renamed from home/rossb/local/linux-2.6.25-rc9/arch/cris/arch-v10/mm/tlb.c +2 -0
@@ -69,6 +69,8 @@ flush_tlb_mm(struct mm_struct *mm)D (printk ("tlb: flush mm context %d (%p)\n" , page_id, mm)); +clear_bit (MMF_NEED_FLUSH , mm->flags); +if (page_id ==NO_CONTEXT )return ;
arch/cris/arch-v32/kernel/smp.c renamed from home/rossb/local/linux-2.6.25-rc9/arch/cris/arch-v32/kernel/smp.c +1 -0
@@ -252,6 +252,7 @@ void flush_tlb_all(void)void flush_tlb_mm (struct mm_struct *mm) { +clear_bit (MMF_NEED_FLUSH , mm->flags);__flush_tlb_mm (mm);flush_tlb_common (mm,FLUSH_ALL ,0 );/* No more mappings in other CPUs */
arch/ia64/kernel/smp.c renamed from home/rossb/local/linux-2.6.25-rc9/arch/ia64/kernel/smp.c +2 -0
@@ -325,6 +325,8 @@ smp_flush_tlb_all (void)void smp_flush_tlb_mm (struct mm_struct *mm) { +clear_bit (MMF_NEED_FLUSH , mm->flags); +preempt_disable ();/* this happens for the common case of a single-threaded fork(): */ if (likely (mm == current->active_mm &&atomic_read (&mm->mm_users) ==1 ))
arch/m32r/kernel/smp.c renamed from home/rossb/local/linux-2.6.25-rc9/arch/m32r/kernel/smp.c +2 -0
@@ -280,6 +280,8 @@ void smp_flush_tlb_mm(struct mm_struct *unsigned long *mmc;unsigned long flags; +clear_bit (MMF_NEED_FLUSH , mm->flags); +preempt_disable (); cpu_id =smp_processor_id (); mmc = &mm->context[cpu_id];
arch/mips/kernel/smp.c renamed from home/rossb/local/linux-2.6.25-rc9/arch/mips/kernel/smp.c +2 -0
@@ -408,6 +408,8 @@ static inline void smp_on_each_tlb(voidvoid flush_tlb_mm (struct mm_struct *mm) { +clear_bit (MMF_NEED_FLUSH , mm->flags); +preempt_disable ();if ((atomic_read (&mm->mm_users) !=1 ) || (current->mm != mm)) {
arch/powerpc/mm/tlb_32.c renamed from home/rossb/local/linux-2.6.25-rc9/arch/powerpc/mm/tlb_32.c +2 -0
@@ -144,6 +144,8 @@ void flush_tlb_mm(struct mm_struct *mm) {struct vm_area_struct *mp; +clear_bit (MMF_NEED_FLUSH , mm->flags); +if (Hash ==0 ) {_tlbia ();return ;
arch/ppc/mm/tlb.c renamed from home/rossb/local/linux-2.6.25-rc9/arch/ppc/mm/tlb.c +2 -0
@@ -144,6 +144,8 @@ void flush_tlb_mm(struct mm_struct *mm) {struct vm_area_struct *mp; +clear_bit (MMF_NEED_FLUSH , mm->flags); +if (Hash ==0 ) {_tlbia ();return ;
arch/sparc/kernel/smp.c renamed from home/rossb/local/linux-2.6.25-rc9/arch/sparc/kernel/smp.c +2 -0
@@ -163,6 +163,8 @@ void smp_flush_cache_mm(struct mm_structvoid smp_flush_tlb_mm (struct mm_struct *mm) { +clear_bit (MMF_NEED_FLUSH , mm->flags); +if (mm->context !=NO_CONTEXT ) {cpumask_t cpu_mask = mm->cpu_vm_mask;cpu_clear (smp_processor_id (), cpu_mask);
arch/sparc64/kernel/smp.c renamed from home/rossb/local/linux-2.6.25-rc9/arch/sparc64/kernel/smp.c +2 -0
@@ -1119,6 +1119,8 @@ void smp_flush_tlb_mm(struct mm_struct *u32 ctx =CTX_HWBITS (mm->context);int cpu =get_cpu (); +clear_bit (MMF_NEED_FLUSH , mm->flags); +if (atomic_read (&mm->mm_users) ==1 ) { mm->cpu_vm_mask =cpumask_of_cpu (cpu); goto local_flush_and_out;
arch/um/kernel/tlb.c renamed from home/rossb/local/linux-2.6.25-rc9/arch/um/kernel/tlb.c +2 -0
@@ -517,6 +517,8 @@ void flush_tlb_mm(struct mm_struct *mm) {struct vm_area_struct *vma = mm->mmap; +clear_bit (MMF_NEED_FLUSH , mm->flags); +while (vma !=NULL ) {fix_range (mm, vma->vm_start, vma->vm_end,0 ); vma = vma->vm_next;
arch/x86/kernel/smp_32.c renamed from home/rossb/local/linux-2.6.25-rc9/arch/x86/kernel/smp_32.c +27 -0
@@ -332,6 +332,8 @@ void smp_invalidate_interrupt(struct pt_if (per_cpu (cpu_tlbstate, cpu).state ==TLBSTATE_OK ) {if (flush_va ==TLB_FLUSH_ALL )local_flush_tlb (); +else if (flush_va ==TLB_RELOAD_ALL ) +local_reload_tlb_mm (flush_mm);else __flush_tlb_one (flush_va); }else
@@ -408,10 +410,35 @@ void flush_tlb_current_task(void)preempt_enable (); } +void reload_tlb_mm (struct mm_struct *mm) +{ +cpumask_t cpu_mask; + +clear_bit (MMF_NEED_RELOAD , &mm->flags); +clear_bit (MMF_NEED_FLUSH , &mm->flags); + +preempt_disable (); + cpu_mask = mm->cpu_vm_mask; +cpu_clear (smp_processor_id (), cpu_mask); + +if (current->active_mm == mm) { +if (current->mm) +local_reload_tlb_mm (mm); +else +leave_mm (smp_processor_id ()); + } +if (!cpus_empty (cpu_mask)) +flush_tlb_others (cpu_mask, mm,TLB_RELOAD_ALL ); + +preempt_enable (); + +} +void flush_tlb_mm (struct mm_struct * mm) {cpumask_t cpu_mask; +clear_bit (MMF_NEED_FLUSH , &mm->flags);preempt_disable (); cpu_mask = mm->cpu_vm_mask;cpu_clear (smp_processor_id (), cpu_mask);
arch/x86/kernel/smp_64.c renamed from home/rossb/local/linux-2.6.25-rc9/arch/x86/kernel/smp_64.c +28 -0
@@ -155,6 +155,8 @@ asmlinkage void smp_invalidate_interruptif (read_pda (mmu_state) ==TLBSTATE_OK ) {if (f->flush_va ==TLB_FLUSH_ALL )local_flush_tlb (); +else if (f->flush_va ==TLB_RELOAD_ALL ) +local_reload_tlb_mm (f->flush_mm);else __flush_tlb_one (f->flush_va); }else
@@ -228,10 +230,36 @@ void flush_tlb_current_task(void)preempt_enable (); } +void reload_tlb_mm (struct mm_struct *mm) +{ +cpumask_t cpu_mask; + +clear_bit (MMF_NEED_RELOAD , &mm->flags); +clear_bit (MMF_NEED_FLUSH , &mm->flags); + +preempt_disable (); + cpu_mask = mm->cpu_vm_mask; +cpu_clear (smp_processor_id (), cpu_mask); + +if (current->active_mm == mm) { +if (current->mm) +local_reload_tlb_mm (mm); +else +leave_mm (smp_processor_id ()); + } +if (!cpus_empty (cpu_mask)) +flush_tlb_others (cpu_mask, mm,TLB_RELOAD_ALL ); + +preempt_enable (); + +} +void flush_tlb_mm (struct mm_struct * mm) {cpumask_t cpu_mask; +clear_bit (MMF_NEED_FLUSH , &mm->flags); +preempt_disable (); cpu_mask = mm->cpu_vm_mask;cpu_clear (smp_processor_id (), cpu_mask);
arch/x86/mach-voyager/voyager_smp.c renamed from home/rossb/local/linux-2.6.25-rc9/arch/x86/mach-voyager/voyager_smp.c +2 -0
@@ -909,6 +909,8 @@ void flush_tlb_mm(struct mm_struct *mm) {unsigned long cpu_mask; +clear_bit (MMF_NEED_FLUSH , mm->flags); +preempt_disable (); cpu_mask =cpus_addr (mm->cpu_vm_mask)[0 ] & ~(1 <<smp_processor_id ());
arch/xtensa/mm/tlb.c renamed from home/rossb/local/linux-2.6.25-rc9/arch/xtensa/mm/tlb.c +2 -0
@@ -63,6 +63,8 @@ void flush_tlb_all (void)void flush_tlb_mm (struct mm_struct *mm) { +clear_bit (MMF_NEED_FLUSH , mm->flags); +if (mm == current->active_mm) {int flags;local_save_flags (flags);
arch/alpha/kernel/smp.c renamed from home/rossb/local/linux-2.6.25-rc9/arch/alpha/kernel/smp.c +2 -0
@@ -845,6 +845,8 @@ flush_tlb_mm(struct mm_struct *mm) {preempt_disable (); +clear_bit (MMF_NEED_FLUSH , mm->flags); +if (mm == current->active_mm) {flush_tlb_current (mm);if (atomic_read (&mm->mm_users) <=1 ) {
arch/arm/kernel/smp.c renamed from home/rossb/local/linux-2.6.25-rc9/arch/arm/kernel/smp.c +2 -0
@@ -738,6 +738,8 @@ void flush_tlb_mm(struct mm_struct *mm) {cpumask_t mask = mm->cpu_vm_mask; +clear_bit (MMF_NEED_FLUSH , mm->flags); +on_each_cpu_mask (ipi_flush_tlb_mm, mm,1 ,1 , mask); }
include/asm-alpha/tlbflush.h renamed from home/rossb/local/linux-2.6.25-rc9/include/asm-alpha/tlbflush.h +2 -0
@@ -148,4 +148,6 @@ static inline void flush_tlb_kernel_rang flush_tlb_all(); } +#include <asm-generic/tlbflush.h> +#endif /* _ALPHA_TLBFLUSH_H */
include/asm-arm/tlbflush.h renamed from home/rossb/local/linux-2.6.25-rc9/include/asm-arm/tlbflush.h +1 -0
@@ -466,5 +466,6 @@ extern void update_mmu_cache(struct vm_a#endif #endif /* CONFIG_MMU */ +#include <asm-generic/tlbflush.h> #endif
include/asm-avr32/tlbflush.h renamed from home/rossb/local/linux-2.6.25-rc9/include/asm-avr32/tlbflush.h +1 -0
@@ -29,5 +29,6 @@ extern void flush_tlb_page(struct vm_areextern void __flush_tlb_page (unsigned long asid,unsigned long page);extern void flush_tlb_kernel_range (unsigned long start,unsigned long end); +#include <asm-generic/tlbflush.h> #endif /* __ASM_AVR32_TLBFLUSH_H */
include/asm-blackfin/tlbflush.h renamed from home/rossb/local/linux-2.6.25-rc9/include/asm-blackfin/tlbflush.h +1 -0
@@ -53,4 +53,5 @@ static inline void flush_tlb_kernel_page BUG(); } +#include <asm-generic/tlbflush.h> #endif
include/asm-cris/tlbflush.h renamed from home/rossb/local/linux-2.6.25-rc9/include/asm-cris/tlbflush.h +1 -0
@@ -44,5 +44,6 @@ static inline void flush_tlb(void) }#define flush_tlb_kernel_range (start, end) flush_tlb_all() +#include <asm-generic/tlbflush.h> #endif /* _CRIS_TLBFLUSH_H */
include/asm-frv/tlbflush.h renamed from home/rossb/local/linux-2.6.25-rc9/include/asm-frv/tlbflush.h +1 -0
@@ -68,6 +68,7 @@ do { \#define flush_tlb_kernel_range (start, end) BUG()#endif +#include <asm-generic/tlbflush.h> #endif /* _ASM_TLBFLUSH_H */
include/asm-generic/tlbflush.h renamed from home/rossb/local/linux-2.6.25-rc9/include/asm-generic/tlbflush.h +74 -0
74 lines not on this page · raw message
include/asm-h8300/tlbflush.h renamed from home/rossb/local/linux-2.6.25-rc9/include/asm-h8300/tlbflush.h +2 -0
@@ -52,4 +52,6 @@ static inline void flush_tlb_kernel_page BUG(); } +#include <asm-generic/tlbflush.h> +#endif /* _H8300_TLBFLUSH_H */
include/asm-ia64/tlbflush.h renamed from home/rossb/local/linux-2.6.25-rc9/include/asm-ia64/tlbflush.h +2 -0
@@ -98,4 +98,6 @@ static inline void flush_tlb_kernel_rang flush_tlb_all(); /* XXX fix me */ } +#include <asm-generic/tlbflush.h> +#endif /* _ASM_IA64_TLBFLUSH_H */
include/asm-m32r/tlbflush.h renamed from home/rossb/local/linux-2.6.25-rc9/include/asm-m32r/tlbflush.h +1 -0
@@ -93,5 +93,6 @@ static __inline__ void __flush_tlb_all(v }extern void update_mmu_cache (struct vm_area_struct *,unsigned long ,pte_t ); +#include <asm-generic/tlbflush.h> #endif /* _ASM_M32R_TLBFLUSH_H */
include/asm-m68k/tlbflush.h renamed from home/rossb/local/linux-2.6.25-rc9/include/asm-m68k/tlbflush.h +1 -0
@@ -215,5 +215,6 @@ static inline void flush_tlb_kernel_page }#endif +#include <asm-generic/tlbflush.h> #endif /* _M68K_TLBFLUSH_H */
include/asm-m68knommu/tlbflush.h renamed from home/rossb/local/linux-2.6.25-rc9/include/asm-m68knommu/tlbflush.h +2 -0
@@ -52,4 +52,6 @@ static inline void flush_tlb_kernel_page BUG(); } +#include <asm-generic/tlbflush.h> +#endif /* _M68KNOMMU_TLBFLUSH_H */
include/asm-mips/tlbflush.h renamed from home/rossb/local/linux-2.6.25-rc9/include/asm-mips/tlbflush.h +2 -0
@@ -44,4 +44,6 @@ extern void flush_tlb_one(unsigned long#endif /* CONFIG_SMP */ +#include <asm-generic/tlbflush.h> +#endif /* __ASM_TLBFLUSH_H */
include/asm-parisc/tlbflush.h renamed from home/rossb/local/linux-2.6.25-rc9/include/asm-parisc/tlbflush.h +1 -0
@@ -76,5 +76,6 @@ void __flush_tlb_range(unsigned long sid#define flush_tlb_range (vma,start,end) __flush_tlb_range((vma)->vm_mm->context,start,end)#define flush_tlb_kernel_range (start, end) __flush_tlb_range(0,start,end) +#include <asm-generic/tlbflush.h> #endif
include/asm-powerpc/tlbflush.h renamed from home/rossb/local/linux-2.6.25-rc9/include/asm-powerpc/tlbflush.h +2 -0
@@ -173,5 +173,7 @@ extern void __flush_hash_table_range(str*/ extern void update_mmu_cache (struct vm_area_struct *,unsigned long ,pte_t ); +#include <asm-generic/tlbflush.h> +#endif /*__KERNEL__ */ #endif /* _ASM_POWERPC_TLBFLUSH_H */
include/asm-s390/tlbflush.h renamed from home/rossb/local/linux-2.6.25-rc9/include/asm-s390/tlbflush.h +2 -0
@@ -126,4 +126,6 @@ static inline void flush_tlb_kernel_rang __tlb_flush_mm(&init_mm); } +#include <asm-generic/tlbflush.h> +#endif /* _S390_TLBFLUSH_H */
include/asm-sh/tlbflush.h renamed from home/rossb/local/linux-2.6.25-rc9/include/asm-sh/tlbflush.h +2 -0
@@ -46,4 +46,6 @@ extern void flush_tlb_one(unsigned long#endif /* CONFIG_SMP */ +#include <asm-generic/tlbflush.h> +#endif /* __ASM_SH_TLBFLUSH_H */
include/asm-sparc/tlbflush.h renamed from home/rossb/local/linux-2.6.25-rc9/include/asm-sparc/tlbflush.h +2 -0
@@ -57,4 +57,6 @@ static inline void flush_tlb_kernel_rang flush_tlb_all(); } +#include <asm-generic/tlbflush.h> +#endif /* _SPARC_TLBFLUSH_H */
include/asm-sparc64/tlbflush.h renamed from home/rossb/local/linux-2.6.25-rc9/include/asm-sparc64/tlbflush.h +2 -0
@@ -41,4 +41,6 @@ do { flush_tsb_kernel_range(start,end);#endif /* ! CONFIG_SMP */ +#include <asm-generic/tlbflush.h> +#endif /* _SPARC64_TLBFLUSH_H */
include/asm-um/tlbflush.h renamed from home/rossb/local/linux-2.6.25-rc9/include/asm-um/tlbflush.h +2 -0
@@ -28,4 +28,6 @@ extern void flush_tlb_kernel_vm(void);extern void flush_tlb_kernel_range (unsigned long start,unsigned long end);extern void __flush_tlb_one (unsigned long addr); +#include <asm-generic/tlbflush.h> +#endif
include/asm-v850/tlbflush.h renamed from home/rossb/local/linux-2.6.25-rc9/include/asm-v850/tlbflush.h +2 -0
@@ -61,4 +61,6 @@ static inline void flush_tlb_kernel_page BUG (); } +#include <asm-generic/tlbflush.h> +#endif /* __V850_TLBFLUSH_H__ */
include/asm-x86/tlbflush.h renamed from home/rossb/local/linux-2.6.25-rc9/include/asm-x86/tlbflush.h +21 -0
@@ -35,6 +35,13 @@ static inline void __native_flush_tlb_si __asm__ __volatile__("invlpg (%0)" ::"r" (addr) :"memory" ); } +#define ARCH_HAS_RELOAD_TLB +static inline void load_cr3 (pgd_t *pgd); +static inline void __reload_tlb_mm (struct mm_struct *mm) +{ +load_cr3 (mm->pgd); +} +static inline void __flush_tlb_all (void ) {if (cpu_has_pge)
@@ -53,8 +60,10 @@ static inline void __flush_tlb_one(unsig#ifdef CONFIG_X86_32 # define TLB_FLUSH_ALL 0xffffffff +# define TLB_RELOAD_ALL 0xfffffffe#else # define TLB_FLUSH_ALL -1ULL +# define TLB_RELOAD_ALL -2ULL#endif /*
@@ -82,6 +91,12 @@ static inline void __flush_tlb_one(unsig#define flush_tlb_all () __flush_tlb_all()#define local_flush_tlb () __flush_tlb() +static inline void reload_tlb_mm (struct mm_struct *mm) +{ +if (mm == current->active_mm) +__reload_tlb_mm (mm); +} +static inline void flush_tlb_mm (struct mm_struct *mm) {if (mm == current->active_mm)
@@ -114,6 +129,10 @@ static inline void native_flush_tlb_othe#define local_flush_tlb () __flush_tlb() +#define local_reload_tlb_mm (mm) \ + __reload_tlb_mm(mm) + +extern void reload_tlb_mm (struct mm_struct *mm);extern void flush_tlb_all (void );extern void flush_tlb_current_task (void );extern void flush_tlb_mm (struct mm_struct *);
@@ -155,4 +174,6 @@ static inline void flush_tlb_kernel_rang flush_tlb_all(); } +#include <asm-generic/tlbflush.h> +#endif /* _ASM_X86_TLBFLUSH_H */
include/asm-xtensa/tlbflush.h renamed from home/rossb/local/linux-2.6.25-rc9/include/asm-xtensa/tlbflush.h +2 -0
@@ -186,6 +186,8 @@ static inline unsigned long read_itlb_trreturn tmp; } +#include <asm-generic/tlbflush.h> +#endif /* __ASSEMBLY__ */ #endif /* __KERNEL__ */ #endif /* _XTENSA_TLBFLUSH_H */
include/linux/sched.h renamed from home/rossb/local/linux-2.6.25-rc9/include/linux/sched.h +10 -0
@@ -408,6 +408,16 @@ extern int get_dumpable(struct mm_struct#define MMF_DUMP_FILTER_DEFAULT \ ((1 << MMF_DUMP_ANON_PRIVATE) | (1 << MMF_DUMP_ANON_SHARED)) +/* Misc MM flags. */ +#define MMF_NEED_FLUSH 7 +#define MMF_NEED_RELOAD 8/* Only meaningful on some archs. */ + +#ifdef CONFIG_RELOCATE_PAGE_TABLES +#define MMF_NEED_REWALK 9/* Must rewalk page tables with spin +* lock held. */ +#endif /* CONFIG_RELOCATE_PAGE_TABLES */ + +struct sighand_struct {atomic_t count;struct k_sigaction action[_NSIG];
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>