mm: Make page tables relocatable
Subsystems (9)
PATCH 2/2 mm: Make page tables relocatable
---
Part 2 contains the actual relocation code.
arch/i386/mm/hugetlbpage.c +1 -0
@@ -87,6 +87,7 @@ static void huge_pmd_share(struct mm_str goto out;spin_lock (&mm->page_table_lock); +delimbo_pud (&pud, mm, addr);if (pud_none (*pud))pud_populate (mm, pud, (unsigned long ) spte &PAGE_MASK );else
arch/powerpc/mm/fault.c +2 -0
@@ -301,6 +301,8 @@ good_area:if (get_pteptr (mm, address, &ptep, &pmdp)) {spinlock_t *ptl =pte_lockptr (mm, pmdp);spin_lock (ptl); +delimbo_pte (&ptep, &ptl, &pmdp, mm, address); +if (pte_present (*ptep)) {struct page *page =pte_page (*ptep);
arch/powerpc/mm/hugetlbpage.c +1 -0
@@ -77,6 +77,7 @@ static int __hugepte_alloc(struct mm_strreturn -ENOMEM ;spin_lock (&mm->page_table_lock); +delimbo_hpd (&hpdp, mm, address);if (!hugepd_none (*hpdp))kmem_cache_free (huge_pgtable_cache, new);else
arch/ppc/mm/fault.c +1 -0
@@ -219,6 +219,7 @@ good_area:if (get_pteptr (mm, address, &ptep, &pmdp)) {spinlock_t *ptl =pte_lockptr (mm, pmdp);spin_lock (ptl); +delimbo_pte (&ptep, &ptl, &pmdp, mm, address);if (pte_present (*ptep)) {struct page *page =pte_page (*ptep);
arch/x86_64/kernel/smp.c +29 -0
@@ -56,6 +56,7 @@ union smp_flush_state {struct mm_struct *flush_mm;unsigned long flush_va;#define FLUSH_ALL -1ULL +#define RELOAD_ALL -2ULLspinlock_t tlbstate_lock; };char pad[SMP_CACHE_BYTES ];
@@ -155,6 +156,8 @@ asmlinkage void smp_invalidate_interruptif (read_pda (mmu_state) ==TLBSTATE_OK ) {if (f->flush_va ==FLUSH_ALL )local_flush_tlb (); +else if (f->flush_va ==RELOAD_ALL ) +local_reload_tlb_mm (f->flush_mm);else __flush_tlb_one (f->flush_va); }else
@@ -225,10 +228,36 @@ void flush_tlb_current_task(void) }EXPORT_SYMBOL (flush_tlb_current_task); +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,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);
include/asm-generic/pgtable.h +45 -0
57 lines not on this page · raw message
include/asm-x86_64/tlbflush.h +19 -0
@@ -6,6 +6,13 @@#include <asm/processor.h> #include <asm/system.h> +#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 (void ) {write_cr3 (read_cr3 ());
@@ -44,6 +50,12 @@ static inline void __flush_tlb_all(void)#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)
@@ -71,6 +83,10 @@ static inline void flush_tlb_range(struc#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 *);
@@ -106,4 +122,6 @@ static inline void flush_tlb_pgtables(st by the normal TLB flushing algorithms. */ } +#include <asm-generic/tlbflush.h> +#endif /* _X8664_TLBFLUSH_H */
include/linux/mm.h +58 -0
76 lines not on this page · raw message
include/linux/mm_types.h +10 -0
@@ -5,6 +5,7 @@#include <linux/threads.h> #include <linux/list.h> #include <linux/spinlock.h> +#include <linux/rcupdate.h> struct address_space ;
@@ -61,9 +62,18 @@ struct page {pgoff_t index;/* Our offset within mapping. */ void *freelist;/* SLUB: freelist req. slab lock */ }; + +union {struct list_head lru;/* Pageout list, eg. active_list * protected by zone->lru_lock ! */ +struct rcu_head rcu;/* Used by page table relocation code +* to remember page for later freeing, +* after we are sure anyone +* poking at the page tables is no +* longer looking at this page. +*/ + };/* * On machines where all RAM is mapped into kernel address space, * we can simply calculate the virtual address. On machines with
mm/hugetlb.c +4 -0
@@ -379,6 +379,8 @@ int copy_hugetlb_page_range(struct mm_st goto nomem;spin_lock (&dst->page_table_lock);spin_lock (&src->page_table_lock); +delimbo_huge_pte (&src_pte, src, addr); +delimbo_huge_pte (&dst_pte, dst, addr);if (!pte_none (*src_pte)) {if (cow)ptep_set_wrprotect (src, addr, src_pte);
@@ -551,6 +553,7 @@ retry: }spin_lock (&mm->page_table_lock); +delimbo_huge_pte (&ptep, mm, address); size =i_size_read (mapping->host) >>HPAGE_SHIFT ;if (idx >= size) goto backout;
@@ -609,6 +612,7 @@ int hugetlb_fault(struct mm_struct *mm, ret =0 ;spin_lock (&mm->page_table_lock); +delimbo_huge_pte (&ptep, mm, address);/* Check for a racing update before calling hugetlb_cow */ if (likely (pte_same (entry, *ptep)))if (write_access && !pte_write (entry))
mm/memory.c +31 -3
@@ -306,6 +306,7 @@ int __pte_alloc(struct mm_struct *mm, pmpte_lock_init (new);spin_lock (&mm->page_table_lock); +delimbo_pmd (&pmd, mm, address);if (pmd_present (*pmd)) {/* Another has populated it */ pte_lock_deinit (new);pte_free (new);
@@ -325,6 +326,7 @@ int __pte_alloc_kernel(pmd_t *pmd, unsigreturn -ENOMEM ;spin_lock (&init_mm.page_table_lock); +delimbo_pmd (&pmd, &init_mm, address);if (pmd_present (*pmd))/* Another has populated it */ pte_free_kernel (new);else
@@ -504,6 +506,8 @@ again: src_pte =pte_offset_map_nested (src_pmd, addr); src_ptl =pte_lockptr (src_mm, src_pmd);spin_lock_nested (src_ptl,SINGLE_DEPTH_NESTING ); + +delimbo_pte (&src_pte, &src_ptl, &src_pmd, src_mm, addr);arch_enter_lazy_mmu_mode (); do {
@@ -1558,13 +1562,15 @@ EXPORT_SYMBOL_GPL(apply_to_page_range);* and do_anonymous_page and do_no_page can safely check later on). */ static inline int pte_unmap_same (struct mm_struct *mm,pmd_t *pmd, -pte_t *page_table,pte_t orig_pte) +pte_t *page_table,pte_t orig_pte, +unsigned long address) {int same =1 ;#if defined(CONFIG_SMP ) || defined(CONFIG_PREEMPT )if (sizeof (pte_t) >sizeof (unsigned long )) {spinlock_t *ptl =pte_lockptr (mm, pmd);spin_lock (ptl); +delimbo_pte (&page_table, &ptl, &pmd, mm, address); same =pte_same (*page_table, orig_pte);spin_unlock (ptl); }
@@ -2153,7 +2159,7 @@ static int do_swap_page(struct mm_structpte_t pte;int ret =0 ; -if (!pte_unmap_same (mm, pmd, page_table, orig_pte)) +if (!pte_unmap_same (mm, pmd, page_table, orig_pte, address)) goto out; entry =pte_to_swp_entry (orig_pte);
@@ -2227,6 +2233,10 @@ static int do_swap_page(struct mm_struct }/* No need to invalidate - it was non-present before */ +/* Unless of course the cpu might be looking at an old +copy of the pte. */ +maybe_reload_tlb_mm (mm); +update_mmu_cache (vma, address, pte); unlock:pte_unmap_unlock (page_table, ptl);
@@ -2279,6 +2289,7 @@ static int do_anonymous_page(struct mm_s ptl =pte_lockptr (mm, pmd);spin_lock (ptl); +delimbo_pte (&page_table, &ptl, &pmd, mm, address);if (!pte_none (*page_table)) goto release;inc_mm_counter (mm, file_rss);
@@ -2288,6 +2299,10 @@ static int do_anonymous_page(struct mm_sset_pte_at (mm, address, page_table, entry);/* No need to invalidate - it was non-present before */ +/* Unless of course the cpu might be looking at an old +copy of the pte. */ +maybe_reload_tlb_mm (mm); +update_mmu_cache (vma, address, entry);lazy_mmu_prot_update (entry); unlock:
@@ -2441,6 +2456,10 @@ static int __do_fault(struct mm_struct * }/* no need to invalidate: a not-present page won't be cached */ +/* Unless of course the cpu could be looking at an old page +table entry. */ +maybe_reload_tlb_mm (mm); +update_mmu_cache (vma, address, entry);lazy_mmu_prot_update (entry); }else {
@@ -2544,7 +2563,7 @@ static int do_nonlinear_fault(struct mm_ (write_access ?FAULT_FLAG_WRITE :0 );pgoff_t pgoff; -if (!pte_unmap_same (mm, pmd, page_table, orig_pte)) +if (!pte_unmap_same (mm, pmd, page_table, orig_pte, address))return 0 ; if (unlikely(!(vma->vm_flags & VM_NONLINEAR) ||
@@ -2603,6 +2622,7 @@ static inline int handle_pte_fault(struc ptl =pte_lockptr (mm, pmd);spin_lock (ptl); +delimbo_pte (&pte, &ptl, &pmd, mm, address);if (unlikely (!pte_same (*pte, entry))) goto unlock;if (write_access) {
@@ -2625,6 +2645,12 @@ static inline int handle_pte_fault(strucif (write_access)flush_tlb_page (vma, address); } + +/* if the cpu could be looking at an old page table, we need to +flush out everything. */ +maybe_reload_tlb_mm (mm); + + unlock:pte_unmap_unlock (pte, ptl);return 0 ;
@@ -2674,6 +2700,7 @@ int __pud_alloc(struct mm_struct *mm, pgreturn -ENOMEM ;spin_lock (&mm->page_table_lock); +delimbo_pgd (&pgd, mm, address);if (pgd_present (*pgd))/* Another has populated it */ pud_free (new);else
@@ -2695,6 +2722,7 @@ int __pmd_alloc(struct mm_struct *mm, pureturn -ENOMEM ;spin_lock (&mm->page_table_lock); +delimbo_pud (&pud, mm, address);#ifndef __ARCH_HAS_4LEVEL_HACKif (pud_present (*pud))/* Another has populated it */ pmd_free (new);
mm/mempolicy.c +14 -0
@@ -101,6 +101,11 @@static struct kmem_cache *policy_cache;static struct kmem_cache *sn_cache; + +int migrate_page_tables_mm (struct mm_struct *mm,int source, +new_page_t get_new_page,unsigned long private); + +/* Highest zone. An specific allocation for a zone below that is not policied. */ enum zone_type policy_zone =0 ;
@@ -597,6 +602,11 @@ static struct page *new_node_page(structreturn alloc_pages_node (node,GFP_HIGHUSER_MOVABLE ,0 ); } +static struct page *new_node_page_page_tables (struct page *page, +unsigned long node,int **x) { +return alloc_pages_node (node,GFP_KERNEL ,0 ); +} +/* * Migrate pages from one node to a target node. * Returns error or the number of pages not migrated.
@@ -616,6 +626,10 @@ int migrate_to_node(struct mm_struct *mmif (!list_empty (&pagelist)) err =migrate_pages (&pagelist, new_node_page, dest); +if (!err) + err =migrate_page_tables_mm (mm, source, + new_node_page_page_tables, dest); +return err; }
mm/migrate.c +319 -2
346 lines not on this page · raw message
mm/mremap.c +1 -0
@@ -98,6 +98,7 @@ static void move_ptes(struct vm_area_str new_ptl =pte_lockptr (mm, new_pmd);if (new_ptl != old_ptl)spin_lock_nested (new_ptl,SINGLE_DEPTH_NESTING ); +delimbo_pte (&new_pte, &new_ptl, &new_pmd, mm, new_addr);arch_enter_lazy_mmu_mode (); for (; old_addr < old_end; old_pte++, old_addr += PAGE_SIZE,
mm/rmap.c +1 -0
@@ -254,6 +254,7 @@ pte_t *page_check_address(struct page *p ptl =pte_lockptr (mm, pmd);spin_lock (ptl); +delimbo_pte (&pte, &ptl, &pmd, mm, address);if (pte_present (*pte) &&page_to_pfn (page) ==pte_pfn (*pte)) { *ptlp = ptl;return pte;
--
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>