alternate 4-level page tables patches (take 2)
Subsystems (13)
cover alternate 4-level page tables patches (take 2)
OK, it turned out that the fallback header I sent out earlier seemed to do the right thing on both ia64 and x86_64 (3-level) without really any changes. So combined with i386 !PAE, that covers 2-level and 3-level implementations... so with any luck it will work on all arches.
So in the following series, there is:
a minor shuffling of hunks between patches
slight improvement to the clear_page_range patch
one off-by-one bug in clear_pud_range
dropped the inlining patch
inclusion of the fallback header.
Theoretically, all architectures should continue to work as before.
Comments? Any consensus as to which way we want to go? I don't want to inflame tempers by continuing this line of work, just provoke discussion.
Thanks,
Nick
--
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>
PATCH 1/11 parentheses to x86-64 macro
1/11
Not strictly a 4level patch, but a warning was spat at me at one stage during my travels.
Add parentheses to x86-64's pgd_index's arguments
---
linux-2.6-npiggin/include/asm-x86_64/pgtable.h | 2 +- 1 files changed, 1 insertion(+), 1 deletion(-)
include/asm-x86_64/pgtable.h renamed from include/asm-x86_64/pgtable.h~x86-64-fix-macro +1 -1
@@ -311,7 +311,7 @@ static inline int pmd_large(pmd_t pte) {/* PGD - Level3 access */ /* to find an entry in a page-table-directory. */ -#define pgd_index (address) ((address >> PGDIR_SHIFT) & (PTRS_PER_PGD-1)) +#define pgd_index (address) (((address) >> PGDIR_SHIFT) & (PTRS_PER_PGD-1))static inline pgd_t *__pgd_offset_k (pgd_t *pgd,unsigned long address) {return pgd +pgd_index (address);
_
PATCH 2/11 generic 3-level nopmd folding header
2/11
Generic headers to fold the 3-level pagetable into 2 levels.
---
linux-2.6-npiggin/include/asm-generic/pgtable-nopmd.h | 59 ++++++++++++++++++ 1 files changed, 59 insertions(+)
include/asm-generic/pgtable-nopmd.h new file +59 -0
@@ -0,0 +1,59 @@ +#ifndef _PGTABLE_NOPMD_H +#define _PGTABLE_NOPMD_H + +#ifndef __ASSEMBLY__ + +/* +* Having the pmd type consist of a pgd gets the size right, and allows +* us to conceptually access the pgd entry that this pmd is folded into +* without casting. +*/ +typedef struct {pgd_t pgd; }pmd_t ; + +#define PMD_SHIFT PGDIR_SHIFT +#define PTRS_PER_PMD 1 +#define PMD_SIZE (1UL << PMD_SHIFT) +#define PMD_MASK (~(PMD_SIZE-1)) + +/* +* The "pgd_xxx()" functions here are trivial for a folded two-level +* setup: the pmd is never bad, and a pmd always exists (as it's folded +* into the pgd entry) +*/ +static inline int pgd_none (pgd_t pgd) {return 0 ; } +static inline int pgd_bad (pgd_t pgd) {return 0 ; } +static inline int pgd_present (pgd_t pgd) {return 1 ; } +static inline void pgd_clear (pgd_t *pgd) { } +#define pmd_ERROR (pmd) (pgd_ERROR((pmd).pgd)) + +#define pgd_populate (mm, pmd, pte) do { } while (0) +#define pgd_populate_kernel (mm, pmd, pte) do { } while (0) + +/* +* (pmds are folded into pgds so this doesn't get actually called, +* but the define is needed for a generic inline function.) +*/ +#define set_pgd (pgdptr, pgdval) set_pmd((pmd_t *)(pgdptr), (pmd_t) { pgdval }) + +static inline pmd_t *pmd_offset (pgd_t * pgd,unsigned long address) +{ +return (pmd_t *)pgd; +} + +#define pmd_val (x) (pgd_val((x).pgd)) +#define __pmd (x) ((pmd_t) { __pgd(x) } ) + +#define pgd_page (pgd) (pmd_page((pmd_t){ pgd })) +#define pgd_page_kernel (pgd) (pmd_page_kernel((pmd_t){ pgd })) + +/* +* allocating and freeing a pmd is trivial: the 1-entry pmd is +* inside the pgd, so has no extra memory associated with it. +*/ +#define pmd_alloc_one (mm, address) NULL +#define pmd_free (x) do { } while (0) +#define __pmd_free_tlb (tlb, x) do { } while (0) + +#endif /* __ASSEMBLY__ */ + +#endif /* _PGTABLE_NOPMD_H */
_
PATCH 3/11 convert i386 to generic nopmd header
3/11
Adapt the i386 architecture to use the generic 2-level folding header. Just to show how it is done.
---
linux-2.6-npiggin/include/asm-i386/mmzone.h | 1 linux-2.6-npiggin/include/asm-i386/page.h | 6 -- linux-2.6-npiggin/include/asm-i386/pgalloc.h | 17 +++---- linux-2.6-npiggin/include/asm-i386/pgtable-2level-defs.h | 2 linux-2.6-npiggin/include/asm-i386/pgtable-2level.h | 33 +++------------ linux-2.6-npiggin/include/asm-i386/pgtable-3level.h | 11 +++++ linux-2.6-npiggin/include/asm-i386/pgtable.h | 13 +---- 7 files changed, 31 insertions(+), 52 deletions(-)
include/asm-i386/pgtable-2level.h renamed from include/asm-i386/pgtable-2level.h~3level-i386-cleanup +8 -25
@@ -1,44 +1,22 @@#ifndef _I386_PGTABLE_2LEVEL_H#define _I386_PGTABLE_2LEVEL_H +#include <asm-generic/pgtable-nopmd.h> +#define pte_ERROR (e) \ printk("%s:%d: bad pte %08lx.\n", __FILE__, __LINE__, (e).pte_low) -#define pmd_ERROR (e) \ - printk("%s:%d: bad pmd %08lx.\n", __FILE__, __LINE__, pmd_val(e))#define pgd_ERROR (e) \ printk("%s:%d: bad pgd %08lx.\n", __FILE__, __LINE__, pgd_val(e))/* -* The "pgd_xxx()" functions here are trivial for a folded two-level -* setup: the pgd is never bad, and a pmd always exists (as it's folded -* into the pgd entry) -*/ -static inline int pgd_none (pgd_t pgd) {return 0 ; } -static inline int pgd_bad (pgd_t pgd) {return 0 ; } -static inline int pgd_present (pgd_t pgd) {return 1 ; } -#define pgd_clear (xp) do { } while (0) - -/* * Certain architectures need to do special things when PTEs * within a page table are directly modified. Thus, the following * hook is made available. */ #define set_pte (pteptr, pteval) (*(pteptr) = pteval)#define set_pte_atomic (pteptr, pteval) set_pte(pteptr,pteval) -/* -* (pmds are folded into pgds so this doesn't get actually called, -* but the define is needed for a generic inline function.) -*/ -#define set_pmd (pmdptr, pmdval) (*(pmdptr) = pmdval) -#define set_pgd (pgdptr, pgdval) (*(pgdptr) = pgdval) +#define set_pmd (pmdptr, pmdval) (*(pmdptr) = (pmdval)) -#define pgd_page (pgd) \ -((unsigned long) __va(pgd_val(pgd) & PAGE_MASK)) - -static inline pmd_t *pmd_offset (pgd_t * dir,unsigned long address) -{ -return (pmd_t *) dir; -}#define ptep_get_and_clear (xp) __pte(xchg(&(xp)->pte_low, 0))#define pte_same (a, b) ((a).pte_low == (b).pte_low)#define pte_page (x) pfn_to_page(pte_pfn(x))
@@ -47,6 +25,11 @@ static inline pmd_t * pmd_offset(pgd_t *#define pfn_pte (pfn, prot) __pte(((pfn) << PAGE_SHIFT) | pgprot_val(prot))#define pfn_pmd (pfn, prot) __pmd(((pfn) << PAGE_SHIFT) | pgprot_val(prot)) +#define pmd_page (pmd) (pfn_to_page(pmd_val(pmd) >> PAGE_SHIFT)) + +#define pmd_page_kernel (pmd) \ +((unsigned long) __va(pmd_val(pmd) & PAGE_MASK)) +/* * All present user pages are user-executable: */
include/asm-i386/page.h renamed from include/asm-i386/page.h~3level-i386-cleanup +2 -4
@@ -46,11 +46,12 @@ typedef struct { unsigned long pte_low,typedef struct {unsigned long long pmd; }pmd_t ;typedef struct {unsigned long long pgd; }pgd_t ;typedef struct {unsigned long long pgprot; }pgprot_t ; +#define pmd_val (x) ((x).pmd)#define pte_val (x) ((x).pte_low | ((unsigned long long)(x).pte_high << 32)) +#define __pmd (x) ((pmd_t) { (x) } )#define HPAGE_SHIFT 21#else typedef struct {unsigned long pte_low; }pte_t ; -typedef struct {unsigned long pmd; }pmd_t ;typedef struct {unsigned long pgd; }pgd_t ;typedef struct {unsigned long pgprot; }pgprot_t ;#define boot_pte_t pte_t/* or would you rather have a typedef */
@@ -66,13 +67,10 @@ typedef struct { unsigned long pgprot; }#define HAVE_ARCH_HUGETLB_UNMAPPED_AREA #endif - -#define pmd_val (x) ((x).pmd)#define pgd_val (x) ((x).pgd)#define pgprot_val (x) ((x).pgprot)#define __pte (x) ((pte_t) { (x) } ) -#define __pmd (x) ((pmd_t) { (x) } )#define __pgd (x) ((pgd_t) { (x) } )#define __pgprot (x) ((pgprot_t) { (x) } )
include/asm-i386/pgtable-2level-defs.h renamed from include/asm-i386/pgtable-2level-defs.h~3level-i386-cleanup +0 -2
@@ -12,8 +12,6 @@* the i386 is two-level, so we don't really have any * PMD directory physically. */ -#define PMD_SHIFT 22 -#define PTRS_PER_PMD 1#define PTRS_PER_PTE 1024
include/asm-i386/pgtable-3level.h renamed from include/asm-i386/pgtable-3level.h~3level-i386-cleanup +11 -0
@@ -70,9 +70,18 @@ static inline void set_pte(pte_t *ptep,*/ static inline void pgd_clear (pgd_t * pgd) { } +#define pmd_page (pmd) (pfn_to_page(pmd_val(pmd) >> PAGE_SHIFT)) + +#define pmd_page_kernel (pmd) \ +((unsigned long) __va(pmd_val(pmd) & PAGE_MASK)) +#define pgd_page (pgd) \ +((struct page *) __va(pgd_val(pgd) & PAGE_MASK)) + +#define pgd_page_kernel (pgd) \ ((unsigned long) __va(pgd_val(pgd) & PAGE_MASK)) +/* Find an entry in the second-level page table.. */ #define pmd_offset (dir, address) ((pmd_t *) pgd_page(*(dir)) + \ pmd_index(address))
@@ -142,4 +151,6 @@ static inline pmd_t pfn_pmd(unsigned lon#define __pte_to_swp_entry (pte) ((swp_entry_t){ (pte).pte_high })#define __swp_entry_to_pte (x) ((pte_t){ 0, (x).val }) +#define __pmd_free_tlb (tlb, x) do { } while (0) +#endif /* _I386_PGTABLE_3LEVEL_H */
include/asm-i386/pgalloc.h renamed from include/asm-i386/pgalloc.h~3level-i386-cleanup +7 -10
@@ -10,12 +10,10 @@#define pmd_populate_kernel (mm, pmd, pte) \ set_pmd(pmd, __pmd(_PAGE_TABLE + __pa(pte))) -static inline void pmd_populate (struct mm_struct *mm,pmd_t *pmd,struct page *pte) -{ -set_pmd (pmd,__pmd (_PAGE_TABLE + - ((unsigned long long )page_to_pfn (pte) << - (unsigned long long )PAGE_SHIFT ))); -} +#define pmd_populate (mm, pmd, pte) \ + set_pmd(pmd, __pmd(_PAGE_TABLE + \ + ((unsigned long long)page_to_pfn(pte) << \ + (unsigned long long) PAGE_SHIFT)))/* * Allocate and free page tables. */
@@ -39,16 +37,15 @@ static inline void pte_free(struct page#define __pte_free_tlb (tlb,pte) tlb_remove_page((tlb),(pte)) +#ifdef CONFIG_X86_PAE /* -* allocating and freeing a pmd is trivial: the 1-entry pmd is -* inside the pgd, so has no extra memory associated with it. -* (In the PAE case we free the pmds as part of the pgd.) +* In the PAE case we free the pmds as part of the pgd. */ -#define pmd_alloc_one (mm, addr) ({ BUG(); ((pmd_t *)2); })#define pmd_free (x) do { } while (0)#define __pmd_free_tlb (tlb,x) do { } while (0)#define pgd_populate (mm, pmd, pte) BUG() +#endif #define check_pgt_cache () do { } while (0)
include/asm-i386/pgtable.h renamed from include/asm-i386/pgtable.h~3level-i386-cleanup +3 -10
@@ -50,12 +50,12 @@ void paging_init(void);*/ #ifdef CONFIG_X86_PAE # include <asm/pgtable-3level-defs.h> +# define PMD_SIZE (1UL << PMD_SHIFT) +# define PMD_MASK (~(PMD_SIZE-1))#else # include <asm/pgtable-2level-defs.h> #endif -#define PMD_SIZE (1UL << PMD_SHIFT) -#define PMD_MASK (~(PMD_SIZE-1))#define PGDIR_SIZE (1UL << PGDIR_SHIFT)#define PGDIR_MASK (~(PGDIR_SIZE-1))
@@ -293,15 +293,8 @@ static inline pte_t pte_modify(pte_t pte#define page_pte (page) page_pte_prot(page, __pgprot(0)) -#define pmd_page_kernel (pmd) \ -((unsigned long) __va(pmd_val(pmd) & PAGE_MASK)) - -#ifndef CONFIG_DISCONTIGMEM -#define pmd_page (pmd) (pfn_to_page(pmd_val(pmd) >> PAGE_SHIFT)) -#endif /* !CONFIG_DISCONTIGMEM */ -#define pmd_large (pmd) \ - ((pmd_val(pmd) & (_PAGE_PSE|_PAGE_PRESENT)) == (_PAGE_PSE|_PAGE_PRESENT)) +((pmd_val(pmd) & (_PAGE_PSE|_PAGE_PRESENT)) == (_PAGE_PSE|_PAGE_PRESENT))/* * the pgd page can be thought of an array like this: pgd_t[PTRS_PER_PGD]
include/asm-i386/mmzone.h renamed from include/asm-i386/mmzone.h~3level-i386-cleanup +0 -1
@@ -116,7 +116,6 @@ static inline struct pglist_data *pfn_to (unsigned long )(__page - __zone->zone_mem_map) \ + __zone->zone_start_pfn; \ }) -#define pmd_page (pmd) (pfn_to_page(pmd_val(pmd) >> PAGE_SHIFT))#ifdef CONFIG_X86_NUMAQ /* we have contiguous memory on NUMA-Q */ #define pfn_valid (pfn) ((pfn) < num_physpages)
_
PATCH 4/11 split copy_page_range
4/11
Split copy_page_range into the usual set of page table walking functions. Needed to handle the complexity when moving to 4 levels.
Split out from Andi Kleen's 4level patch.
---
linux-2.6-npiggin/mm/memory.c | 290 ++++++++++++++++++++++-------------------- 1 files changed, 152 insertions(+), 138 deletions(-)
mm/memory.c renamed from mm/memory.c~3level-split-copy_page_range +152 -138
@@ -204,165 +204,179 @@ pte_t fastcall * pte_alloc_kernel(struct out:return pte_offset_kernel (pmd, address); } -#define PTE_TABLE_MASK ((PTRS_PER_PTE-1) * sizeof(pte_t)) -#define PMD_TABLE_MASK ((PTRS_PER_PMD-1) * sizeof(pmd_t))/* * copy one vm_area from one task to the other. Assumes the page tables * already present in the new task to be cleared in the whole range * covered by this vma. * -* 08Jan98 Merged into one routine from several inline routines to reduce -* variable count and make things faster. -jj -* * dst->page_table_lock is held on entry and exit, -* but may be dropped within pmd_alloc() and pte_alloc_map(). +* but may be dropped within p[mg]d_alloc() and pte_alloc_map(). */ + +static inline void +copy_swap_pte (struct mm_struct *dst_mm,struct mm_struct *src_mm,pte_t pte) +{ +if (pte_file (pte)) +return ; +swap_duplicate (pte_to_swp_entry (pte)); +if (list_empty (&dst_mm->mmlist)) { +spin_lock (&mmlist_lock); +list_add (&dst_mm->mmlist, &src_mm->mmlist); +spin_unlock (&mmlist_lock); + } +} + +static inline void +copy_one_pte (struct mm_struct *dst_mm,struct mm_struct *src_mm, +pte_t *dst_pte,pte_t *src_pte,unsigned long vm_flags, +unsigned long addr) +{ +pte_t pte = *src_pte; +struct page *page; +unsigned long pfn; + +/* pte contains position in swap, so copy. */ +if (!pte_present (pte)) { +copy_swap_pte (dst_mm, src_mm, pte); +set_pte (dst_pte, pte); +return ; + } + pfn =pte_pfn (pte); +/* the pte points outside of valid memory, the +* mapping is assumed to be good, meaningful +* and not mapped via rmap - duplicate the +* mapping as is. +*/ + page =NULL ; +if (pfn_valid (pfn)) + page =pfn_to_page (pfn); + +if (!page ||PageReserved (page)) { +set_pte (dst_pte, pte); +return ; + } + +/* +* If it's a COW mapping, write protect it both +* in the parent and the child +*/ +if ((vm_flags & (VM_SHARED |VM_MAYWRITE )) ==VM_MAYWRITE ) { +ptep_set_wrprotect (src_pte); + pte = *src_pte; + } + +/* +* If it's a shared mapping, mark it clean in +* the child +*/ +if (vm_flags &VM_SHARED ) + pte =pte_mkclean (pte); + pte =pte_mkold (pte); +get_page (page); + dst_mm->rss++; +if (PageAnon (page)) + dst_mm->anon_rss++; +set_pte (dst_pte, pte); +page_dup_rmap (page); +} + +static int copy_pte_range (struct mm_struct *dst_mm,struct mm_struct *src_mm, +pmd_t *dst_pmd,pmd_t *src_pmd,struct vm_area_struct *vma, +unsigned long addr,unsigned long end) +{ +pte_t *src_pte, *dst_pte; +pte_t *s, *d; +unsigned long vm_flags = vma->vm_flags; + + d = dst_pte =pte_alloc_map (dst_mm, dst_pmd, addr); +if (!dst_pte) +return -ENOMEM ; + +spin_lock (&src_mm->page_table_lock); + s = src_pte =pte_offset_map_nested (src_pmd, addr); +for (; addr < end; addr +=PAGE_SIZE , s++, d++) { +if (pte_none (*s)) +continue ; +copy_one_pte (dst_mm, src_mm, d, s, vm_flags, addr); + } +pte_unmap_nested (src_pte); +pte_unmap (dst_pte); +spin_unlock (&src_mm->page_table_lock); +cond_resched_lock (&dst_mm->page_table_lock); +return 0 ; +} + +static int copy_pmd_range (struct mm_struct *dst_mm,struct mm_struct *src_mm, +pgd_t *dst_pgd,pgd_t *src_pgd,struct vm_area_struct *vma, +unsigned long addr,unsigned long end) +{ +pmd_t *src_pmd, *dst_pmd; +int err =0 ; +unsigned long next; + + src_pmd =pmd_offset (src_pgd, addr); + dst_pmd =pmd_alloc (dst_mm, dst_pgd, addr); +if (!dst_pmd) +return -ENOMEM ; + +for (; addr < end; addr = next, src_pmd++, dst_pmd++) { + next = (addr +PMD_SIZE ) &PMD_MASK ; +if (next > end) + next = end; +if (pmd_none (*src_pmd)) +continue ; +if (pmd_bad (*src_pmd)) { +pmd_ERROR (*src_pmd); +pmd_clear (src_pmd); +continue ; + } + err =copy_pte_range (dst_mm, src_mm, dst_pmd, src_pmd, + vma, addr, next); +if (err) +break ; + } +return err; +} +int copy_page_range (struct mm_struct *dst,struct mm_struct *src, -struct vm_area_struct *vma) +struct vm_area_struct *vma) { -pgd_t * src_pgd, * dst_pgd; -unsigned long address = vma->vm_start; -unsigned long end = vma->vm_end; -unsigned long cow; +pgd_t *src_pgd, *dst_pgd; +unsigned long addr, start, end, next; +int err =0 ;if (is_vm_hugetlb_page (vma))return copy_hugetlb_page_range (dst, src, vma); - cow = (vma->vm_flags & (VM_SHARED |VM_MAYWRITE )) ==VM_MAYWRITE ; - src_pgd =pgd_offset (src, address)-1 ; - dst_pgd =pgd_offset (dst, address)-1 ; - -for (;;) { -pmd_t * src_pmd, * dst_pmd; - - src_pgd++; dst_pgd++; - -/* copy_pmd_range */ - + start = vma->vm_start; + src_pgd =pgd_offset (src, start); + dst_pgd =pgd_offset (dst, start); + + end = vma->vm_end; + addr = start; +while (addr && (addr < end-1 )) { + next = (addr +PGDIR_SIZE ) &PGDIR_MASK ; +if (next > end || next <= addr) + next = end;if (pgd_none (*src_pgd)) - goto skip_copy_pmd_range; -if (unlikely (pgd_bad (*src_pgd))) { +continue ; +if (pgd_bad (*src_pgd)) {pgd_ERROR (*src_pgd);pgd_clear (src_pgd); -skip_copy_pmd_range: address = (address +PGDIR_SIZE ) &PGDIR_MASK ; -if (!address || (address >= end)) - goto out;continue ; } + err =copy_pmd_range (dst, src, dst_pgd, src_pgd, + vma, addr, next); +if (err) +break ; - src_pmd =pmd_offset (src_pgd, address); - dst_pmd =pmd_alloc (dst, dst_pgd, address); -if (!dst_pmd) - goto nomem; - -do { -pte_t * src_pte, * dst_pte; - -/* copy_pte_range */ - -if (pmd_none (*src_pmd)) - goto skip_copy_pte_range; -if (unlikely (pmd_bad (*src_pmd))) { -pmd_ERROR (*src_pmd); -pmd_clear (src_pmd); -skip_copy_pte_range: - address = (address +PMD_SIZE ) &PMD_MASK ; -if (address >= end) - goto out; - goto cont_copy_pmd_range; - } - - dst_pte =pte_alloc_map (dst, dst_pmd, address); -if (!dst_pte) - goto nomem; -spin_lock (&src->page_table_lock); - src_pte =pte_offset_map_nested (src_pmd, address); -do { -pte_t pte = *src_pte; -struct page *page; -unsigned long pfn; - -/* copy_one_pte */ - -if (pte_none (pte)) - goto cont_copy_pte_range_noset; -/* pte contains position in swap, so copy. */ -if (!pte_present (pte)) { -if (!pte_file (pte)) { -swap_duplicate (pte_to_swp_entry (pte)); -if (list_empty (&dst->mmlist)) { -spin_lock (&mmlist_lock); -list_add (&dst->mmlist, - &src->mmlist); -spin_unlock (&mmlist_lock); - } - } -set_pte (dst_pte, pte); - goto cont_copy_pte_range_noset; - } - pfn =pte_pfn (pte); -/* the pte points outside of valid memory, the -* mapping is assumed to be good, meaningful -* and not mapped via rmap - duplicate the -* mapping as is. -*/ - page =NULL ; -if (pfn_valid (pfn)) - page =pfn_to_page (pfn); - -if (!page ||PageReserved (page)) { -set_pte (dst_pte, pte); - goto cont_copy_pte_range_noset; - } - -/* -* If it's a COW mapping, write protect it both -* in the parent and the child -*/ -if (cow) { -ptep_set_wrprotect (src_pte); - pte = *src_pte; - } - -/* -* If it's a shared mapping, mark it clean in -* the child -*/ -if (vma->vm_flags &VM_SHARED ) - pte =pte_mkclean (pte); - pte =pte_mkold (pte); -get_page (page); - dst->rss++; -if (PageAnon (page)) - dst->anon_rss++; -set_pte (dst_pte, pte); -page_dup_rmap (page); -cont_copy_pte_range_noset: - address +=PAGE_SIZE ; -if (address >= end) { -pte_unmap_nested (src_pte); -pte_unmap (dst_pte); - goto out_unlock; - } - src_pte++; - dst_pte++; - }while ((unsigned long )src_pte &PTE_TABLE_MASK ); -pte_unmap_nested (src_pte-1 ); -pte_unmap (dst_pte-1 ); -spin_unlock (&src->page_table_lock); -cond_resched_lock (&dst->page_table_lock); -cont_copy_pmd_range: - src_pmd++; - dst_pmd++; - }while ((unsigned long )src_pmd &PMD_TABLE_MASK ); + src_pgd++; + dst_pgd++; + addr = next; } -out_unlock: -spin_unlock (&src->page_table_lock); -out: -return 0 ; -nomem: -return -ENOMEM ; + +return err; } static void zap_pte_range(struct mmu_gather *tlb,
_
PATCH 5/11 replace clear_page_tables with clear_page_range
5/11
Rename clear_page_tables to clear_page_range. clear_page_range takes byte ranges, and aggressively frees page table pages. Maybe useful to control page table memory consumption on 4-level architectures (and even 3 level ones).
Possible downsides are:
- flush_tlb_pgtables gets called more often (only a problem for sparc64 AFAIKS).
- the opportunistic "expand to fill PGDIR_SIZE hole" logic that ensures something actually gets done under the old system is still in place. This could sometimes make unmapping small regions more inefficient. There are some other solutions to look at if this is the case though.
---
linux-2.6-npiggin/arch/i386/mm/pgtable.c | 2 linux-2.6-npiggin/arch/ia64/mm/hugetlbpage.c | 15 ----- linux-2.6-npiggin/include/linux/mm.h | 2 linux-2.6-npiggin/mm/memory.c | 80 ++++++++++++++++----------- linux-2.6-npiggin/mm/mmap.c | 24 +++----- 5 files changed, 63 insertions(+), 60 deletions(-)
include/linux/mm.h renamed from include/linux/mm.h~3level-clear_page_range +1 -1
@@ -566,7 +566,7 @@ int unmap_vmas(struct mmu_gather **tlbp, struct vm_area_struct *start_vma, unsigned long start_addr, unsigned long end_addr, unsigned long *nr_accounted, struct zap_details *); -void clear_page_tables (struct mmu_gather *tlb,unsigned long first,int nr); +void clear_page_range (struct mmu_gather *tlb,unsigned long addr,unsigned long end);int copy_page_range (struct mm_struct *dst,struct mm_struct *src,struct vm_area_struct *vma); int zeromap_page_range(struct vm_area_struct *vma, unsigned long from,
mm/memory.c renamed from mm/memory.c~3level-clear_page_range +49 -31
107 lines not on this page · raw message
mm/mmap.c renamed from mm/mmap.c~3level-clear_page_range +10 -14
@@ -1474,7 +1474,6 @@ static void free_pgtables(struct mmu_gat {unsigned long first = start &PGDIR_MASK ;unsigned long last = end +PGDIR_SIZE -1 ; -unsigned long start_index, end_index;struct mm_struct *mm = tlb->mm;if (!prev) {
@@ -1499,23 +1498,18 @@ static void free_pgtables(struct mmu_gat last = next->vm_start; }if (prev->vm_end > first) - first = prev->vm_end +PGDIR_SIZE -1 ; + first = prev->vm_end;break ; } no_mmaps:if (last < first)/* for arches with discontiguous pgd indices */ return ; -/* -* If the PGD bits are not consecutive in the virtual address, the -* old method of shifting the VA >> by PGDIR_SHIFT doesn't work. -*/ - start_index =pgd_index (first); -if (start_index <FIRST_USER_PGD_NR ) - start_index =FIRST_USER_PGD_NR ; - end_index =pgd_index (last); -if (end_index > start_index) { -clear_page_tables (tlb, start_index, end_index - start_index); -flush_tlb_pgtables (mm, first &PGDIR_MASK , last &PGDIR_MASK ); +if (first <FIRST_USER_PGD_NR *PGDIR_SIZE ) + first =FIRST_USER_PGD_NR *PGDIR_SIZE ; +/* No point trying to free anything if we're in the same pte page */ +if ((first &PMD_MASK ) < (last &PMD_MASK )) { +clear_page_range (tlb, first, last); +flush_tlb_pgtables (mm, first, last); } }
@@ -1844,7 +1838,9 @@ void exit_mmap(struct mm_struct *mm) ~0UL, &nr_accounted, NULL);vm_unacct_memory (nr_accounted);BUG_ON (mm->map_count);/* This is just debugging */ -clear_page_tables (tlb,FIRST_USER_PGD_NR ,USER_PTRS_PER_PGD ); +clear_page_range (tlb,FIRST_USER_PGD_NR *PGDIR_SIZE , + (TASK_SIZE +PGDIR_SIZE -1 ) &PGDIR_MASK ); +tlb_finish_mmu (tlb,0 ,MM_VM_SIZE (mm)); vma = mm->mmap;
arch/i386/mm/pgtable.c renamed from arch/i386/mm/pgtable.c~3level-clear_page_range +1 -1
@@ -252,6 +252,6 @@ void pgd_free(pgd_t *pgd)if (PTRS_PER_PMD >1 )for (i =0 ; i <USER_PTRS_PER_PGD ; ++i)kmem_cache_free (pmd_cache, (void *)__va (pgd_val (pgd[i])-1 )); -/* in the non-PAE case, clear_page_tables() clears user pgd entries */ +/* in the non-PAE case, clear_page_range() clears user pgd entries */ kmem_cache_free (pgd_cache, pgd); }
arch/ia64/mm/hugetlbpage.c renamed from arch/ia64/mm/hugetlbpage.c~3level-clear_page_range +2 -13
@@ -187,7 +187,6 @@ void hugetlb_free_pgtables(struct mmu_ga {unsigned long first = start &HUGETLB_PGDIR_MASK ;unsigned long last = end +HUGETLB_PGDIR_SIZE -1 ; -unsigned long start_index, end_index;struct mm_struct *mm = tlb->mm;if (!prev) {
@@ -212,23 +211,13 @@ void hugetlb_free_pgtables(struct mmu_ga last = next->vm_start; }if (prev->vm_end > first) - first = prev->vm_end +HUGETLB_PGDIR_SIZE -1 ; + first = prev->vm_end;break ; } no_mmaps:if (last < first)/* for arches with discontiguous pgd indices */ return ; -/* -* If the PGD bits are not consecutive in the virtual address, the -* old method of shifting the VA >> by PGDIR_SHIFT doesn't work. -*/ - - start_index =pgd_index (htlbpage_to_page (first)); - end_index =pgd_index (htlbpage_to_page (last)); - -if (end_index > start_index) { -clear_page_tables (tlb, start_index, end_index - start_index); - } +clear_page_range (tlb, first, last); }void unmap_hugepage_range (struct vm_area_struct *vma,unsigned long start,unsigned long end)
_
PATCH 6/11 introduce 4-level nopud folding header
6/11
Generic headers to fold the 4-level pagetable into 3 levels.
---
linux-2.6-npiggin/include/asm-generic/pgtable-nopmd.h | 45 +++++++------- linux-2.6-npiggin/include/asm-generic/pgtable-nopud.h | 56 ++++++++++++++++++ linux-2.6-npiggin/include/asm-generic/tlb.h | 6 + 3 files changed, 85 insertions(+), 22 deletions(-)
include/asm-generic/pgtable-nopud.h new file +56 -0
@@ -0,0 +1,56 @@ +#ifndef _PGTABLE_NOPUD_H +#define _PGTABLE_NOPUD_H + +#ifndef __ASSEMBLY__ + +/* +* Having the pud type consist of a pgd gets the size right, and allows +* us to conceptually access the pgd entry that this pud is folded into +* without casting. +*/ +typedef struct {pgd_t pgd; }pud_t ; + +#define PUD_SHIFT PGDIR_SHIFT +#define PTRS_PER_PUD 1 +#define PUD_SIZE (1UL << PUD_SHIFT) +#define PUD_MASK (~(PUD_SIZE-1)) + +/* +* The "pgd_xxx()" functions here are trivial for a folded two-level +* setup: the pud is never bad, and a pud always exists (as it's folded +* into the pgd entry) +*/ +static inline int pgd_none (pgd_t pgd) {return 0 ; } +static inline int pgd_bad (pgd_t pgd) {return 0 ; } +static inline int pgd_present (pgd_t pgd) {return 1 ; } +static inline void pgd_clear (pgd_t *pgd) { } +#define pud_ERROR (pud) (pgd_ERROR((pud).pgd)) + +#define pgd_populate (mm, pgd, pud) do { } while (0) +/* +* (puds are folded into pgds so this doesn't get actually called, +* but the define is needed for a generic inline function.) +*/ +#define set_pgd (pgdptr, pgdval) set_pud((pud_t *)(pgdptr), (pud_t) { pgdval }) + +static inline pud_t *pud_offset (pgd_t * pgd,unsigned long address) +{ +return (pud_t *)pgd; +} + +#define pud_val (x) (pgd_val((x).pgd)) +#define __pud (x) ((pud_t) { __pgd(x) } ) + +#define pgd_page (pgd) (pud_page((pud_t){ pgd })) +#define pgd_page_kernel (pgd) (pud_page_kernel((pud_t){ pgd })) + +/* +* allocating and freeing a pud is trivial: the 1-entry pud is +* inside the pgd, so has no extra memory associated with it. +*/ +#define pud_alloc_one (mm, address) NULL +#define pud_free (x) do { } while (0) +#define __pud_free_tlb (tlb, x) do { } while (0) + +#endif /* __ASSEMBLY__ */ +#endif /* _PGTABLE_NOPUD_H */
include/asm-generic/pgtable-nopmd.h renamed from include/asm-generic/pgtable-nopmd.h~4level-compat +23 -22
75 lines not on this page · raw message
include/asm-generic/tlb.h renamed from include/asm-generic/tlb.h~4level-compat +6 -0
@@ -141,6 +141,12 @@ static inline void tlb_remove_page(struc__pte_free_tlb (tlb, ptep); \ } while (0) +#define pud_free_tlb (tlb, pudp) \ + do { \ + tlb->need_flush = 1; \ + __pud_free_tlb(tlb, pudp); \ + } while (0) +#define pmd_free_tlb (tlb, pmdp) \ do { \ tlb->need_flush = 1; \
_
PATCH 7/11 convert Linux to 4-level page tables
7/11
Extend the Linux MM to 4level page tables.
This is the core patch for mm/*, fs/*, include/linux/*
It breaks all architectures, which will be fixed in separate patches.
The conversion is quite straight forward. All the functions walking the page table hierarchy have been changed to deal with another level at the top. The additional level is called pml4.
mm/memory.c has changed a lot because it did most of the heavy lifting here. Most of the changes here are extensions of the previous code.
Converted to use the pud_t 'page upper' level between pgd and pmd instead of Andi's pml4 level above pgd.
---
linux-2.6-npiggin/drivers/char/drm/drm_memory.h | 3 linux-2.6-npiggin/fs/exec.c | 6 linux-2.6-npiggin/include/linux/init_task.h | 2 linux-2.6-npiggin/include/linux/mm.h | 20 - linux-2.6-npiggin/mm/fremap.c | 18 - linux-2.6-npiggin/mm/memory.c | 408 ++++++++++++++++++------ linux-2.6-npiggin/mm/mempolicy.c | 22 + linux-2.6-npiggin/mm/mprotect.c | 65 ++- linux-2.6-npiggin/mm/mremap.c | 29 + linux-2.6-npiggin/mm/msync.c | 55 ++- linux-2.6-npiggin/mm/rmap.c | 21 + linux-2.6-npiggin/mm/swapfile.c | 81 +++- linux-2.6-npiggin/mm/vmalloc.c | 113 ++++-- 13 files changed, 644 insertions(+), 199 deletions(-)
fs/exec.c renamed from fs/exec.c~4level-core-patch +5 -1
@@ -300,6 +300,7 @@ void install_arg_page(struct vm_area_str {struct mm_struct *mm = vma->vm_mm;pgd_t * pgd; +pud_t * pud;pmd_t * pmd;pte_t * pte;
@@ -310,7 +311,10 @@ void install_arg_page(struct vm_area_str pgd =pgd_offset (mm, address);spin_lock (&mm->page_table_lock); - pmd =pmd_alloc (mm, pgd, address); + pud =pud_alloc (mm, pgd, address); +if (!pud) + goto out; + pmd =pmd_alloc (mm, pud, address);if (!pmd) goto out; pte =pte_alloc_map (mm, pmd, address);
include/linux/init_task.h renamed from include/linux/init_task.h~4level-core-patch +1 -1
@@ -34,7 +34,7 @@#define INIT_MM (name) \ { \ .mm_rb = RB_ROOT, \ - .pgd = swapper_pg_dir, \ + .pgd = swapper_pg_dir, \ .mm_users = ATOMIC_INIT(2), \ .mm_count = ATOMIC_INIT(1), \ .mmap_sem = __RWSEM_INITIALIZER(name.mmap_sem), \
include/linux/mm.h renamed from include/linux/mm.h~4level-core-patch +14 -6
@@ -581,7 +581,8 @@ static inline void unmap_shared_mapping_ }extern int vmtruncate (struct inode * inode,loff_t offset); -extern pmd_t *FASTCALL (__pmd_alloc (struct mm_struct *mm,pgd_t *pgd,unsigned long address)); +extern pud_t *FASTCALL (__pud_alloc (struct mm_struct *mm,pgd_t *pgd,unsigned long address)); +extern pmd_t *FASTCALL (__pmd_alloc (struct mm_struct *mm,pud_t *pud,unsigned long address));extern pte_t *FASTCALL (pte_alloc_kernel (struct mm_struct *mm,pmd_t *pmd,unsigned long address));extern pte_t *FASTCALL (pte_alloc_map (struct mm_struct *mm,pmd_t *pmd,unsigned long address));extern int install_page (struct mm_struct *mm,struct vm_area_struct *vma,unsigned long addr,struct page *page,pgprot_t prot);
@@ -626,15 +627,22 @@ extern struct shrinker *set_shrinker(intextern void remove_shrinker (struct shrinker *shrinker);/* -* On a two-level page table, this ends up being trivial. Thus the -* inlining and the symmetry break with pte_alloc_map() that does all +* On a two-level or three-level page table, this ends up being trivial. Thus +* the inlining and the symmetry break with pte_alloc_map() that does all * of this out-of-line. */ -static inline pmd_t *pmd_alloc (struct mm_struct *mm,pgd_t *pgd,unsigned long address) +static inline pud_t *pud_alloc (struct mm_struct *mm,pgd_t *pgd,unsigned long address) {if (pgd_none (*pgd)) -return __pmd_alloc (mm, pgd, address); -return pmd_offset (pgd, address); +return __pud_alloc (mm, pgd, address); +return pud_offset (pgd, address); +} + +static inline pmd_t *pmd_alloc (struct mm_struct *mm,pud_t *pud,unsigned long address) +{ +if (pud_none (*pud)) +return __pmd_alloc (mm, pud, address); +return pmd_offset (pud, address); }extern void free_area_init (unsigned long * zones_size);
diff -puN include/linux/sched.h~4level-core-patch include/linux/sched.h diff -puN kernel/fork.c~4level-core-patch kernel/fork.c
mm/fremap.c renamed from mm/fremap.c~4level-core-patch +14 -4
@@ -60,14 +60,19 @@ int install_page(struct mm_struct *mm, spgoff_t size;int err = -ENOMEM ;pte_t *pte; -pgd_t *pgd;pmd_t *pmd; +pud_t *pud; +pgd_t *pgd;pte_t pte_val; pgd =pgd_offset (mm, addr);spin_lock (&mm->page_table_lock); + + pud =pud_alloc (mm, pgd, addr); +if (!pud) + goto err_unlock; - pmd =pmd_alloc (mm, pgd, addr); + pmd =pmd_alloc (mm, pud, addr);if (!pmd) goto err_unlock;
@@ -112,14 +117,19 @@ int install_file_pte(struct mm_struct *m {int err = -ENOMEM ;pte_t *pte; -pgd_t *pgd;pmd_t *pmd; +pud_t *pud; +pgd_t *pgd;pte_t pte_val; pgd =pgd_offset (mm, addr);spin_lock (&mm->page_table_lock); + + pud =pud_alloc (mm, pgd, addr); +if (!pud) + goto err_unlock; - pmd =pmd_alloc (mm, pgd, addr); + pmd =pmd_alloc (mm, pud, addr);if (!pmd) goto err_unlock;
mm/memory.c renamed from mm/memory.c~4level-core-patch +317 -91
662 lines not on this page · raw message
mm/mempolicy.c renamed from mm/mempolicy.c~4level-core-patch +17 -5
@@ -234,18 +234,29 @@ static struct mempolicy *mpol_new(int mo/* Ensure all existing pages follow the policy. */ static int -verify_pages (unsigned long addr,unsigned long end,unsigned long *nodes) +verify_pages (struct mm_struct *mm, +unsigned long addr,unsigned long end,unsigned long *nodes) {while (addr < end) {struct page *p;pte_t *pte;pmd_t *pmd; -pgd_t *pgd =pgd_offset_k (addr); +pud_t *pud; +pgd_t *pgd; + pgd =pgd_offset (mm, addr);if (pgd_none (*pgd)) { - addr = (addr +PGDIR_SIZE ) &PGDIR_MASK ; +unsigned long next = (addr +PGDIR_SIZE ) &PGDIR_MASK ; +if (next > addr) +break ; + addr = next; +continue ; + } + pud =pud_offset (pgd, addr); +if (pud_none (*pud)) { + addr = (addr +PUD_SIZE ) &PUD_MASK ;continue ; } - pmd =pmd_offset (pgd, addr); + pmd =pmd_offset (pud, addr);if (pmd_none (*pmd)) { addr = (addr +PMD_SIZE ) &PMD_MASK ;continue ;
@@ -283,7 +294,8 @@ check_range(struct mm_struct *mm, unsignif (prev && prev->vm_end < vma->vm_start)return ERR_PTR (-EFAULT );if ((flags &MPOL_MF_STRICT ) && !is_vm_hugetlb_page (vma)) { - err =verify_pages (vma->vm_start, vma->vm_end, nodes); + err =verify_pages (vma->vm_mm, + vma->vm_start, vma->vm_end, nodes);if (err) { first =ERR_PTR (err);break ;
diff -puN mm/mmap.c~4level-core-patch mm/mmap.c
mm/mprotect.c renamed from mm/mprotect.c~4level-core-patch +47 -18
96 lines not on this page · raw message
mm/mremap.c renamed from mm/mremap.c~4level-core-patch +23 -6
@@ -25,19 +25,24 @@static pte_t *get_one_pte_map_nested (struct mm_struct *mm,unsigned long addr) {pgd_t *pgd; +pud_t *pud;pmd_t *pmd;pte_t *pte =NULL ; pgd =pgd_offset (mm, addr);if (pgd_none (*pgd)) goto end; -if (pgd_bad (*pgd)) { -pgd_ERROR (*pgd); -pgd_clear (pgd); + + pud =pud_offset (pgd, addr); +if (pud_none (*pud)) + goto end; +if (pud_bad (*pud)) { +pud_ERROR (*pud); +pud_clear (pud); goto end; } - pmd =pmd_offset (pgd, addr); + pmd =pmd_offset (pud, addr);if (pmd_none (*pmd)) goto end;if (pmd_bad (*pmd)) {
@@ -58,12 +63,17 @@ end:static pte_t *get_one_pte_map (struct mm_struct *mm,unsigned long addr) {pgd_t *pgd; +pud_t *pud;pmd_t *pmd; pgd =pgd_offset (mm, addr);if (pgd_none (*pgd))return NULL ; - pmd =pmd_offset (pgd, addr); + + pud =pud_offset (pgd, addr); +if (pud_none (*pud)) +return NULL ; + pmd =pmd_offset (pud, addr);if (!pmd_present (*pmd))return NULL ;return pte_offset_map (pmd, addr);
@@ -71,10 +81,17 @@ static pte_t *get_one_pte_map(struct mm_static inline pte_t *alloc_one_pte_map (struct mm_struct *mm,unsigned long addr) { +pgd_t *pgd; +pud_t *pud;pmd_t *pmd;pte_t *pte =NULL ; - pmd =pmd_alloc (mm,pgd_offset (mm, addr), addr); + pgd =pgd_offset (mm, addr); + + pud =pud_alloc (mm, pgd, addr); +if (!pud) +return NULL ; + pmd =pmd_alloc (mm, pud, addr);if (pmd) pte =pte_alloc_map (mm, pmd, addr);return pte;
mm/msync.c renamed from mm/msync.c~4level-core-patch +43 -12
96 lines not on this page · raw message
mm/rmap.c renamed from mm/rmap.c~4level-core-patch +18 -3
@@ -259,6 +259,7 @@ static int page_referenced_one(struct pastruct mm_struct *mm = vma->vm_mm;unsigned long address;pgd_t *pgd; +pud_t *pud;pmd_t *pmd;pte_t *pte;int referenced =0 ;
@@ -275,7 +276,11 @@ static int page_referenced_one(struct paif (!pgd_present (*pgd)) goto out_unlock; - pmd =pmd_offset (pgd, address); + pud =pud_offset (pgd, address); +if (!pud_present (*pud)) + goto out_unlock; + + pmd =pmd_offset (pud, address);if (!pmd_present (*pmd)) goto out_unlock;
@@ -502,6 +507,7 @@ static int try_to_unmap_one(struct pagestruct mm_struct *mm = vma->vm_mm;unsigned long address;pgd_t *pgd; +pud_t *pud;pmd_t *pmd;pte_t *pte;pte_t pteval;
@@ -523,7 +529,11 @@ static int try_to_unmap_one(struct pageif (!pgd_present (*pgd)) goto out_unlock; - pmd =pmd_offset (pgd, address); + pud =pud_offset (pgd, address); +if (!pud_present (*pud)) + goto out_unlock; + + pmd =pmd_offset (pud, address);if (!pmd_present (*pmd)) goto out_unlock;
@@ -631,6 +641,7 @@ static void try_to_unmap_cluster(unsigne {struct mm_struct *mm = vma->vm_mm;pgd_t *pgd; +pud_t *pud;pmd_t *pmd;pte_t *pte;pte_t pteval;
@@ -656,7 +667,11 @@ static void try_to_unmap_cluster(unsigneif (!pgd_present (*pgd)) goto out_unlock; - pmd =pmd_offset (pgd, address); + pud =pud_offset (pgd, address); +if (!pud_present (*pud)) + goto out_unlock; + + pmd =pmd_offset (pud, address);if (!pmd_present (*pmd)) goto out_unlock;
mm/swapfile.c renamed from mm/swapfile.c~4level-core-patch +60 -21
114 lines not on this page · raw message
mm/vmalloc.c renamed from mm/vmalloc.c~4level-core-patch +83 -30
176 lines not on this page · raw message
drivers/char/drm/drm_memory.h renamed from drivers/char/drm/drm_memory.h~4level-core-patch +2 -1
@@ -125,7 +125,8 @@ static inline unsigned long drm_follow_page (void *vaddr) {pgd_t *pgd =pgd_offset_k ((unsigned long ) vaddr); -pmd_t *pmd =pmd_offset (pgd, (unsigned long ) vaddr); +pud_t *pud =pud_offset (pgd, (unsigned long ) vaddr); +pmd_t *pmd =pmd_offset (pud, (unsigned long ) vaddr);pte_t *ptep =pte_offset_kernel (pmd, (unsigned long ) vaddr);return pte_pfn (*ptep) <<PAGE_SHIFT ; }
_
PATCH 8/11 introduce fallback header
8/11
Add a temporary "fallback" header so architectures can run with the 4level patgetables patch without modification. All architectures should be converted to use the folding headers (include/asm-generic/pgtable-nop?d.h) as soon as possible, and the fallback header removed.
Make all architectures include the fallback header, except i386, because that architecture has earlier been converted to use pgtable-nopmd.h under the 3 level system, which is not compatible with the fallback header.
---
linux-2.6-npiggin/include/asm-alpha/pgtable.h | 2 + linux-2.6-npiggin/include/asm-arm/pgtable.h | 2 + linux-2.6-npiggin/include/asm-arm26/pgtable.h | 2 + linux-2.6-npiggin/include/asm-cris/pgtable.h | 2 + linux-2.6-npiggin/include/asm-generic/4level-fixup.h | 34 +++++++++++++++++++ linux-2.6-npiggin/include/asm-generic/tlb.h | 2 + linux-2.6-npiggin/include/asm-h8300/pgtable.h | 2 + linux-2.6-npiggin/include/asm-ia64/pgtable.h | 2 + linux-2.6-npiggin/include/asm-m32r/pgtable.h | 2 + linux-2.6-npiggin/include/asm-m68k/pgtable.h | 2 + linux-2.6-npiggin/include/asm-m68knommu/pgtable.h | 2 + linux-2.6-npiggin/include/asm-mips/pgtable.h | 2 + linux-2.6-npiggin/include/asm-parisc/pgtable.h | 2 + linux-2.6-npiggin/include/asm-ppc/pgtable.h | 2 + linux-2.6-npiggin/include/asm-ppc64/pgtable.h | 2 + linux-2.6-npiggin/include/asm-s390/pgtable.h | 2 + linux-2.6-npiggin/include/asm-sh/pgtable.h | 2 + linux-2.6-npiggin/include/asm-sh64/pgtable.h | 2 + linux-2.6-npiggin/include/asm-sparc/pgtable.h | 2 + linux-2.6-npiggin/include/asm-sparc64/pgtable.h | 2 + linux-2.6-npiggin/include/asm-um/pgtable.h | 2 + linux-2.6-npiggin/include/asm-v850/pgtable.h | 2 + linux-2.6-npiggin/include/asm-x86_64/pgtable.h | 2 + linux-2.6-npiggin/include/linux/mm.h | 6 +++ linux-2.6-npiggin/mm/memory.c | 25 +++++++++++++ 25 files changed, 109 insertions(+)
include/asm-generic/4level-fixup.h new file +34 -0
@@ -0,0 +1,34 @@ +#ifndef _4LEVEL_FIXUP_H +#define _4LEVEL_FIXUP_H + +#define __ARCH_HAS_4LEVEL_HACK + +#define PUD_SIZE PGDIR_SIZE +#define PUD_MASK PGDIR_MASK +#define PTRS_PER_PUD 1 + +#define pud_t pgd_t + +#define pmd_alloc (mm, pud, address) \ +({ pmd_t *ret; \ + if (pgd_none(*pud)) \ + ret = __pmd_alloc(mm, pud, address); \ + else \ + ret = pmd_offset(pud, address); \ + ret; \ +}) + +#define pud_alloc (mm, pgd, address) (pgd) +#define pud_offset (pgd, start) (pgd) +#define pud_none (pud) 0 +#define pud_bad (pud) 0 +#define pud_present (pud) 1 +#define pud_ERROR (pud) do { } while (0) +#define pud_clear (pud) do { } while (0) + +#undef pud_free_tlb +#define pud_free_tlb (tlb, x) do { } while (0) +#define pud_free (x) do { } while (0) +#define __pud_free_tlb (tlb, x) do { } while (0) + +#endif
include/linux/mm.h renamed from include/linux/mm.h~4level-fallback +6 -0
@@ -631,6 +631,11 @@ extern void remove_shrinker(struct shrin* the inlining and the symmetry break with pte_alloc_map() that does all * of this out-of-line. */ +/* +* The following ifdef needed to get the 4level-fixup.h header to work. +* Remove it when 4level-fixup.h has been removed. +*/ +#ifndef __ARCH_HAS_4LEVEL_HACKstatic inline pud_t *pud_alloc (struct mm_struct *mm,pgd_t *pgd,unsigned long address) {if (pgd_none (*pgd))
@@ -644,6 +649,7 @@ static inline pmd_t *pmd_alloc(struct mmreturn __pmd_alloc (mm, pud, address);return pmd_offset (pud, address); } +#endif extern void free_area_init (unsigned long * zones_size); extern void free_area_init_node(int nid, pg_data_t *pgdat,
mm/memory.c renamed from mm/memory.c~4level-fallback +25 -0
@@ -1940,6 +1940,7 @@ int handle_mm_fault(struct mm_struct *mmreturn VM_FAULT_OOM ; } +#ifndef __ARCH_HAS_4LEVEL_HACK#if (PTRS_PER_PGD >1 )/* * Allocate page upper directory.
@@ -2007,6 +2008,30 @@ out:return pmd_offset (pud, address); }#endif +#else +pmd_t fastcall *__pmd_alloc(struct mm_struct *mm, pud_t *pud, unsigned long address) +{ +pmd_t *new; + +spin_unlock (&mm->page_table_lock); + new =pmd_alloc_one (mm, address); +spin_lock (&mm->page_table_lock); +if (!new) +return NULL ; + +/* +* Because we dropped the lock, we should re-check the +* entry, as somebody else could have populated it.. +*/ +if (pgd_present (*pud)) { +pmd_free (new); + goto out; + } +pgd_populate (mm, pud, new); +out: +return pmd_offset (pud, address); +} +#endif int make_pages_present (unsigned long addr,unsigned long end) {
include/asm-alpha/pgtable.h renamed from include/asm-alpha/pgtable.h~4level-fallback +2 -0
@@ -1,6 +1,8 @@#ifndef _ALPHA_PGTABLE_H#define _ALPHA_PGTABLE_H +#include <asm-generic/4level-fixup.h> +/* * This file contains the functions and defines necessary to modify and use * the Alpha page table tree.
include/asm-arm/pgtable.h renamed from include/asm-arm/pgtable.h~4level-fallback +2 -0
@@ -10,6 +10,8 @@#ifndef _ASMARM_PGTABLE_H#define _ASMARM_PGTABLE_H +#include <asm-generic/4level-fixup.h> +#include <asm/memory.h> #include <asm/proc-fns.h> #include <asm/arch/vmalloc.h>
include/asm-arm26/pgtable.h renamed from include/asm-arm26/pgtable.h~4level-fallback +2 -0
@@ -11,6 +11,8 @@#ifndef _ASMARM_PGTABLE_H#define _ASMARM_PGTABLE_H +#include <asm-generic/4level-fixup.h> +#include <linux/config.h> #include <asm/memory.h>
include/asm-cris/pgtable.h renamed from include/asm-cris/pgtable.h~4level-fallback +2 -0
@@ -5,6 +5,8 @@#ifndef _CRIS_PGTABLE_H#define _CRIS_PGTABLE_H +#include <asm-generic/4level-fixup.h> +#ifndef __ASSEMBLY__#include <linux/config.h> #include <linux/sched.h>
diff -puN include/asm-generic/pgtable.h~4level-fallback include/asm-generic/pgtable.h
include/asm-h8300/pgtable.h renamed from include/asm-h8300/pgtable.h~4level-fallback +2 -0
@@ -1,6 +1,8 @@#ifndef _H8300_PGTABLE_H#define _H8300_PGTABLE_H +#include <asm-generic/4level-fixup.h> +#include <linux/config.h> #include <linux/slab.h> #include <asm/processor.h>
diff -puN include/asm-i386/pgtable.h~4level-fallback include/asm-i386/pgtable.h
include/asm-ia64/pgtable.h renamed from include/asm-ia64/pgtable.h~4level-fallback +2 -0
@@ -1,6 +1,8 @@#ifndef _ASM_IA64_PGTABLE_H#define _ASM_IA64_PGTABLE_H +#include <asm-generic/4level-fixup.h> +/* * This file contains the functions and defines necessary to modify and use * the IA-64 page table tree.
include/asm-m32r/pgtable.h renamed from include/asm-m32r/pgtable.h~4level-fallback +2 -0
@@ -1,6 +1,8 @@#ifndef _ASM_M32R_PGTABLE_H#define _ASM_M32R_PGTABLE_H +#include <asm-generic/4level-fixup.h> +/* $Id$ */ /*
include/asm-m68k/pgtable.h renamed from include/asm-m68k/pgtable.h~4level-fallback +2 -0
@@ -1,6 +1,8 @@#ifndef _M68K_PGTABLE_H#define _M68K_PGTABLE_H +#include <asm-generic/4level-fixup.h> +#include <linux/config.h> #include <asm/setup.h>
include/asm-m68knommu/pgtable.h renamed from include/asm-m68knommu/pgtable.h~4level-fallback +2 -0
@@ -1,6 +1,8 @@#ifndef _M68KNOMMU_PGTABLE_H#define _M68KNOMMU_PGTABLE_H +#include <asm-generic/4level-fixup.h> +/* * (C) Copyright 2000-2002, Greg Ungerer <[email protected]> */
include/asm-mips/pgtable.h renamed from include/asm-mips/pgtable.h~4level-fallback +2 -0
@@ -8,6 +8,8 @@#ifndef _ASM_PGTABLE_H#define _ASM_PGTABLE_H +#include <asm-generic/4level-fixup.h> +#include <linux/config.h> #ifdef CONFIG_MIPS32 #include <asm/pgtable-32.h>
include/asm-parisc/pgtable.h renamed from include/asm-parisc/pgtable.h~4level-fallback +2 -0
@@ -1,6 +1,8 @@#ifndef _PARISC_PGTABLE_H#define _PARISC_PGTABLE_H +#include <asm-generic/4level-fixup.h> +#include <linux/config.h> #include <asm/fixmap.h>
include/asm-ppc/pgtable.h renamed from include/asm-ppc/pgtable.h~4level-fallback +2 -0
@@ -2,6 +2,8 @@#ifndef _PPC_PGTABLE_H#define _PPC_PGTABLE_H +#include <asm-generic/4level-fixup.h> +#include <linux/config.h> #ifndef __ASSEMBLY__
include/asm-ppc64/pgtable.h renamed from include/asm-ppc64/pgtable.h~4level-fallback +2 -0
@@ -1,6 +1,8 @@#ifndef _PPC64_PGTABLE_H#define _PPC64_PGTABLE_H +#include <asm-generic/4level-fixup.h> +/* * This file contains the functions and defines necessary to modify and use * the ppc64 hashed page table.
include/asm-s390/pgtable.h renamed from include/asm-s390/pgtable.h~4level-fallback +2 -0
@@ -13,6 +13,8 @@#ifndef _ASM_S390_PGTABLE_H#define _ASM_S390_PGTABLE_H +#include <asm-generic/4level-fixup.h> +/* * The Linux memory management assumes a three-level page table setup. For * s390 31 bit we "fold" the mid level into the top-level page table, so
include/asm-sh/pgtable.h renamed from include/asm-sh/pgtable.h~4level-fallback +2 -0
@@ -1,6 +1,8 @@#ifndef __ASM_SH_PGTABLE_H#define __ASM_SH_PGTABLE_H +#include <asm-generic/4level-fixup.h> +/* * Copyright (C) 1999 Niibe Yutaka * Copyright (C) 2002, 2003, 2004 Paul Mundt
include/asm-sh64/pgtable.h renamed from include/asm-sh64/pgtable.h~4level-fallback +2 -0
@@ -1,6 +1,8 @@#ifndef __ASM_SH64_PGTABLE_H#define __ASM_SH64_PGTABLE_H +#include <asm-generic/4level-fixup.h> +/* * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive
include/asm-sparc/pgtable.h renamed from include/asm-sparc/pgtable.h~4level-fallback +2 -0
@@ -9,6 +9,8 @@* Copyright (C) 1998 Jakub Jelinek ([email protected]) */ +#include <asm-generic/4level-fixup.h> +#include <linux/config.h> #include <linux/spinlock.h> #include <linux/swap.h>
include/asm-sparc64/pgtable.h renamed from include/asm-sparc64/pgtable.h~4level-fallback +2 -0
@@ -12,6 +12,8 @@* the SpitFire page tables. */ +#include <asm-generic/4level-fixup.h> +#include <linux/config.h> #include <asm/spitfire.h> #include <asm/asi.h>
include/asm-um/pgtable.h renamed from include/asm-um/pgtable.h~4level-fallback +2 -0
@@ -7,6 +7,8 @@#ifndef __UM_PGTABLE_H#define __UM_PGTABLE_H +#include <asm-generic/4level-fixup.h> +#include "linux/sched.h" #include "asm/processor.h" #include "asm/page.h"
include/asm-v850/pgtable.h renamed from include/asm-v850/pgtable.h~4level-fallback +2 -0
@@ -1,6 +1,8 @@#ifndef __V850_PGTABLE_H__#define __V850_PGTABLE_H__ +#include <asm-generic/4level-fixup.h> +#include <linux/config.h> #include <asm/page.h>
include/asm-x86_64/pgtable.h renamed from include/asm-x86_64/pgtable.h~4level-fallback +2 -0
@@ -1,6 +1,8 @@#ifndef _X86_64_PGTABLE_H#define _X86_64_PGTABLE_H +#include <asm-generic/4level-fixup.h> +/* * This file contains the functions and defines necessary to modify and use * the x86-64 page table tree.
include/asm-generic/tlb.h renamed from include/asm-generic/tlb.h~4level-fallback +2 -0
@@ -141,11 +141,13 @@ static inline void tlb_remove_page(struc__pte_free_tlb (tlb, ptep); \ } while (0) +#ifndef __ARCH_HAS_4LEVEL_HACK#define pud_free_tlb (tlb, pudp) \ do { \ tlb->need_flush = 1; \ __pud_free_tlb(tlb, pudp); \ } while (0) +#endif #define pmd_free_tlb (tlb, pmdp) \ do { \
_
PATCH 9/11 convert i386 to generic nopud header
9/11
i386 works with 2 and 3 levels
Converted to use pud_t by Nick Piggin
---
---
linux-2.6-npiggin/arch/i386/kernel/acpi/sleep.c | 3 +- linux-2.6-npiggin/arch/i386/kernel/vm86.c | 11 ++++++++- linux-2.6-npiggin/arch/i386/mm/fault.c | 13 ++++++++-- linux-2.6-npiggin/arch/i386/mm/hugetlbpage.c | 8 +++++- linux-2.6-npiggin/arch/i386/mm/init.c | 18 ++++++++++----- linux-2.6-npiggin/arch/i386/mm/ioremap.c | 7 +++++ linux-2.6-npiggin/arch/i386/mm/pageattr.c | 14 ++++++++--- linux-2.6-npiggin/arch/i386/mm/pgtable.c | 12 ++++++++-- linux-2.6-npiggin/include/asm-i386/pgalloc.h | 3 -- linux-2.6-npiggin/include/asm-i386/pgtable-3level.h | 24 ++++++++++---------- linux-2.6-npiggin/include/asm-i386/pgtable.h | 1 11 files changed, 81 insertions(+), 33 deletions(-)
arch/i386/kernel/acpi/sleep.c renamed from arch/i386/kernel/acpi/sleep.c~4level-architecture-changes-for-i386 +2 -1
@@ -7,6 +7,7 @@#include <linux/acpi.h> #include <linux/bootmem.h> +#include <asm/current.h> /* XXX remove me */ #include <asm/smp.h>
@@ -24,7 +25,7 @@ static void init_low_mapping(pgd_t *pgd,int pgd_ofs =0 ;while ((pgd_ofs < pgd_limit) && (pgd_ofs +USER_PTRS_PER_PGD <PTRS_PER_PGD )) { -set_pgd (pgd, *(pgd+USER_PTRS_PER_PGD )); +set_pgd (pgd, (*(pgd+USER_PTRS_PER_PGD ))); pgd_ofs++, pgd++; } }
arch/i386/kernel/vm86.c renamed from arch/i386/kernel/vm86.c~4level-architecture-changes-for-i386 +10 -1
@@ -137,6 +137,7 @@ struct pt_regs * fastcall save_v86_statestatic void mark_screen_rdonly (struct task_struct * tsk) {pgd_t *pgd; +pud_t *pud;pmd_t *pmd;pte_t *pte, *mapped;int i;
@@ -151,7 +152,15 @@ static void mark_screen_rdonly(struct tapgd_clear (pgd); goto out; } - pmd =pmd_offset (pgd,0xA0000 ); + pud =pud_offset (pgd,0xA0000 ); +if (pud_none (*pud)) + goto out; +if (pud_bad (*pud)) { +pud_ERROR (*pud); +pud_clear (pud); + goto out; + } + pmd =pmd_offset (pud,0xA0000 );if (pmd_none (*pmd)) goto out;if (pmd_bad (*pmd)) {
arch/i386/mm/fault.c renamed from arch/i386/mm/fault.c~4level-architecture-changes-for-i386 +10 -3
@@ -518,6 +518,7 @@ vmalloc_fault:int index =pgd_index (address);unsigned long pgd_paddr;pgd_t *pgd, *pgd_k; +pud_t *pud, *pud_k;pmd_t *pmd, *pmd_k;pte_t *pte_k;
@@ -530,11 +531,17 @@ vmalloc_fault:/* * set_pgd(pgd, *pgd_k); here would be useless on PAE -* and redundant with the set_pmd() on non-PAE. +* and redundant with the set_pmd() on non-PAE. As would +* set_pud. */ - pmd =pmd_offset (pgd, address); - pmd_k =pmd_offset (pgd_k, address); + pud =pud_offset (pgd, address); + pud_k =pud_offset (pgd_k, address); +if (!pud_present (*pud_k)) + goto no_context; + + pmd =pmd_offset (pud, address); + pmd_k =pmd_offset (pud_k, address);if (!pmd_present (*pmd_k)) goto no_context;set_pmd (pmd, *pmd_k);
arch/i386/mm/hugetlbpage.c renamed from arch/i386/mm/hugetlbpage.c~4level-architecture-changes-for-i386 +6 -2
@@ -21,20 +21,24 @@static pte_t *huge_pte_alloc (struct mm_struct *mm,unsigned long addr) {pgd_t *pgd; +pud_t *pud;pmd_t *pmd =NULL ; pgd =pgd_offset (mm, addr); - pmd =pmd_alloc (mm, pgd, addr); + pud =pud_alloc (mm, pgd, addr); + pmd =pmd_alloc (mm, pud, addr);return (pte_t *) pmd; }static pte_t *huge_pte_offset (struct mm_struct *mm,unsigned long addr) {pgd_t *pgd; +pud_t *pud;pmd_t *pmd =NULL ; pgd =pgd_offset (mm, addr); - pmd =pmd_offset (pgd, addr); + pud =pud_offset (pgd, addr); + pmd =pmd_offset (pud, addr);return (pte_t *) pmd; }
arch/i386/mm/init.c renamed from arch/i386/mm/init.c~4level-architecture-changes-for-i386 +12 -6
@@ -54,15 +54,18 @@ static int noinline do_test_wp_bit(void)*/ static pmd_t *__init one_md_table_init (pgd_t *pgd) { +pud_t *pud;pmd_t *pmd_table;#ifdef CONFIG_X86_PAE pmd_table = (pmd_t *)alloc_bootmem_low_pages (PAGE_SIZE );set_pgd (pgd,__pgd (__pa (pmd_table) | _PAGE_PRESENT)); -if (pmd_table !=pmd_offset (pgd,0 )) + pud =pud_offset (pgd,0 ); +if (pmd_table !=pmd_offset (pud,0 ))BUG ();#else - pmd_table =pmd_offset (pgd,0 ); + pud =pud_offset (pgd,0 ); + pmd_table =pmd_offset (pud,0 );#endif return pmd_table;
@@ -100,6 +103,7 @@ static pte_t * __init one_page_table_inistatic void __init page_table_range_init (unsigned long start,unsigned long end,pgd_t *pgd_base) {pgd_t *pgd; +pud_t *pud;pmd_t *pmd;int pgd_idx, pmd_idx;unsigned long vaddr;
@@ -112,8 +116,8 @@ static void __init page_table_range_initfor ( ; (pgd_idx <PTRS_PER_PGD ) && (vaddr != end); pgd++, pgd_idx++) {if (pgd_none (*pgd))one_md_table_init (pgd); - - pmd =pmd_offset (pgd, vaddr); + pud =pud_offset (pgd, vaddr); + pmd =pmd_offset (pud, vaddr);for (; (pmd_idx <PTRS_PER_PMD ) && (vaddr != end); pmd++, pmd_idx++) {if (pmd_none (*pmd))one_page_table_init (pmd);
@@ -233,7 +237,7 @@ EXPORT_SYMBOL(kmap_prot);EXPORT_SYMBOL (kmap_pte);#define kmap_get_fixmap_pte (vaddr) \ - pte_offset_kernel(pmd_offset(pgd_offset_k(vaddr), (vaddr)), (vaddr)) + pte_offset_kernel(pmd_offset(pud_offset(pgd_offset_k(vaddr), vaddr), (vaddr)), (vaddr))void __init kmap_init (void ) {
@@ -249,6 +253,7 @@ void __init kmap_init(void)void __init permanent_kmaps_init (pgd_t *pgd_base) {pgd_t *pgd; +pud_t *pud;pmd_t *pmd;pte_t *pte;unsigned long vaddr;
@@ -257,7 +262,8 @@ void __init permanent_kmaps_init(pgd_t *page_table_range_init (vaddr, vaddr +PAGE_SIZE *LAST_PKMAP , pgd_base); pgd = swapper_pg_dir +pgd_index (vaddr); - pmd =pmd_offset (pgd, vaddr); + pud =pud_offset (pgd, vaddr); + pmd =pmd_offset (pud, vaddr); pte =pte_offset_kernel (pmd, vaddr); pkmap_page_table = pte; }
arch/i386/mm/ioremap.c renamed from arch/i386/mm/ioremap.c~4level-architecture-changes-for-i386 +6 -1
@@ -80,9 +80,14 @@ static int remap_area_pages(unsigned lonBUG ();spin_lock (&init_mm.page_table_lock); do { + pud_t *pud; pmd_t *pmd; - pmd = pmd_alloc(&init_mm, dir, address); + error = -ENOMEM; + pud = pud_alloc(&init_mm, dir, address); + if (!pud) + break; + pmd = pmd_alloc(&init_mm, pud, address); if (!pmd) break; if (remap_area_pmd(pmd, address, end - address,
arch/i386/mm/pageattr.c renamed from arch/i386/mm/pageattr.c~4level-architecture-changes-for-i386 +10 -4
@@ -19,11 +19,15 @@ static struct list_head df_list = LIST_Hpte_t *lookup_address (unsigned long address) { -pgd_t *pgd =pgd_offset_k (address); +pgd_t *pgd =pgd_offset_k (address); +pud_t *pud;pmd_t *pmd;if (pgd_none (*pgd))return NULL ; - pmd =pmd_offset (pgd, address); + pud =pud_offset (pgd, address); +if (pud_none (*pud)) +return NULL ; + pmd =pmd_offset (pud, address);if (pmd_none (*pmd))return NULL ;if (pmd_large (*pmd))
@@ -77,9 +81,11 @@ static void set_pmd_pte(pte_t *kpte, unsspin_lock_irqsave (&pgd_lock, flags);for (page = pgd_list; page; page = (struct page *)page->index) {pgd_t *pgd; +pud_t *pud;pmd_t *pmd; pgd = (pgd_t *)page_address (page) +pgd_index (address); - pmd =pmd_offset (pgd, address); + pud =pud_offset (pgd, address); + pmd =pmd_offset (pud, address);set_pte_atomic ((pte_t *)pmd, pte); }spin_unlock_irqrestore (&pgd_lock, flags);
@@ -92,7 +98,7 @@ static void set_pmd_pte(pte_t *kpte, unsstatic inline void revert_page (struct page *kpte_page,unsigned long address) {pte_t *linear = (pte_t *) -pmd_offset (pgd_offset (&init_mm, address), address); +pmd_offset (pud_offset (pgd_offset_k (address), address), address);set_pmd_pte (linear, address,pfn_pte ((__pa (address) &LARGE_PAGE_MASK ) >>PAGE_SHIFT ,PAGE_KERNEL_LARGE ));
arch/i386/mm/pgtable.c renamed from arch/i386/mm/pgtable.c~4level-architecture-changes-for-i386 +10 -2
@@ -62,6 +62,7 @@ void show_mem(void)static void set_pte_pfn (unsigned long vaddr,unsigned long pfn,pgprot_t flags) {pgd_t *pgd; +pud_t *pud;pmd_t *pmd;pte_t *pte;
@@ -70,7 +71,12 @@ static void set_pte_pfn(unsigned long vaBUG ();return ; } - pmd =pmd_offset (pgd, vaddr); + pud =pud_offset (pgd, vaddr); +if (pud_none (*pud)) { +BUG (); +return ; + } + pmd =pmd_offset (pud, vaddr);if (pmd_none (*pmd)) {BUG ();return ;
@@ -95,6 +101,7 @@ static void set_pte_pfn(unsigned long vavoid set_pmd_pfn (unsigned long vaddr,unsigned long pfn,pgprot_t flags) {pgd_t *pgd; +pud_t *pud;pmd_t *pmd;if (vaddr & (PMD_SIZE -1 )) {/* vaddr is misaligned */
@@ -110,7 +117,8 @@ void set_pmd_pfn(unsigned long vaddr, unprintk ("set_pmd_pfn: pgd_none\n" );return ;/* BUG(); */ } - pmd =pmd_offset (pgd, vaddr); + pud =pud_offset (pgd, vaddr); + pmd =pmd_offset (pud, vaddr);set_pmd (pmd,pfn_pmd (pfn, flags));/* * It's enough to flush this one mapping.
diff -puN include/asm-i386/mmu_context.h~4level-architecture-changes-for-i386 include/asm-i386/mmu_context.h diff -puN include/asm-i386/page.h~4level-architecture-changes-for-i386 include/asm-i386/page.h
include/asm-i386/pgalloc.h renamed from include/asm-i386/pgalloc.h~4level-architecture-changes-for-i386 +1 -2
@@ -17,7 +17,6 @@/* * Allocate and free page tables. */ -extern pgd_t *pgd_alloc (struct mm_struct *);extern void pgd_free (pgd_t *pgd);
@@ -44,7 +43,7 @@ static inline void pte_free(struct page#define pmd_alloc_one (mm, addr) ({ BUG(); ((pmd_t *)2); })#define pmd_free (x) do { } while (0)#define __pmd_free_tlb (tlb,x) do { } while (0) -#define pgd_populate (mm, pmd, pte) BUG() +#define pud_populate (mm, pmd, pte) BUG()#endif #define check_pgt_cache () do { } while (0)
include/asm-i386/pgtable.h renamed from include/asm-i386/pgtable.h~4level-architecture-changes-for-i386 +1 -0
@@ -303,6 +303,7 @@ static inline pte_t pte_modify(pte_t pte* control the given virtual address */ #define pgd_index (address) (((address) >> PGDIR_SHIFT) & (PTRS_PER_PGD-1)) +#define pgd_index_k (addr) pgd_index(addr)/* * pgd_offset() returns a (pgd_t *)
diff -puN include/asm-i386/pgtable-2level.h~4level-architecture-changes-for-i386 include/asm-i386/pgtable-2level.h
include/asm-i386/pgtable-3level.h renamed from include/asm-i386/pgtable-3level.h~4level-architecture-changes-for-i386 +13 -11
@@ -1,6 +1,8 @@#ifndef _I386_PGTABLE_3LEVEL_H#define _I386_PGTABLE_3LEVEL_H +#include <asm-generic/pgtable-nopud.h> +/* * Intel Physical Address Extension (PAE) Mode - three-level page * tables on PPro+ CPUs.
@@ -15,9 +17,9 @@#define pgd_ERROR (e) \ printk("%s:%d: bad pgd %p(%016Lx).\n", __FILE__, __LINE__, &(e), pgd_val(e)) -static inline int pgd_none (pgd_t pgd) {return 0 ; } -static inline int pgd_bad (pgd_t pgd) {return 0 ; } -static inline int pgd_present (pgd_t pgd) {return 1 ; } +#define pud_none (pud) 0 +#define pud_bad (pud) 0 +#define pud_present (pud) 1/* * Is the pte executable?
@@ -59,8 +61,8 @@ static inline void set_pte(pte_t *ptep, set_64bit((unsigned long long *)(pteptr),pte_val(pteval))#define set_pmd (pmdptr,pmdval) \ set_64bit((unsigned long long *)(pmdptr),pmd_val(pmdval)) -#define set_pgd (pgdptr,pgdval) \ - set_64bit((unsigned long long *)(pgdptr),pgd_val(pgdval)) +#define set_pud (pudptr,pudval) \ + set_64bit((unsigned long long *)(pudptr),pud_val(pudval))/* * Pentium-II erratum A13: in PAE mode we explicitly have to flush
@@ -68,22 +70,22 @@ static inline void set_pte(pte_t *ptep,* We do not let the generic code free and clear pgd entries due to * this erratum. */ -static inline void pgd_clear (pgd_t * pgd) { } +static inline void pud_clear (pud_t * pud) { }#define pmd_page (pmd) (pfn_to_page(pmd_val(pmd) >> PAGE_SHIFT))#define pmd_page_kernel (pmd) \ ((unsigned long) __va(pmd_val(pmd) & PAGE_MASK)) -#define pgd_page (pgd) \ -((struct page *) __va(pgd_val(pgd) & PAGE_MASK)) +#define pud_page (pud) \ +((struct page *) __va(pud_val(pud) & PAGE_MASK)) -#define pgd_page_kernel (pgd) \ -((unsigned long) __va(pgd_val(pgd) & PAGE_MASK)) +#define pud_page_kernel (pud) \ +((unsigned long) __va(pud_val(pud) & PAGE_MASK))/* Find an entry in the second-level page table.. */ -#define pmd_offset (dir, address) ((pmd_t *) pgd_page(*(dir)) + \ +#define pmd_offset (pud, address) ((pmd_t *) pud_page(*(pud)) + \ pmd_index(address))static inline pte_t ptep_get_and_clear (pte_t *ptep)
_
PATCH 10/11 convert ia64 to generic nopud header
10/11
Convert ia64 architecture over to handle 4 level pagetables.
---
linux-2.6-npiggin/arch/ia64/mm/fault.c | 7 ++++++- linux-2.6-npiggin/arch/ia64/mm/hugetlbpage.c | 20 ++++++++++++++------ linux-2.6-npiggin/arch/ia64/mm/init.c | 14 ++++++++++++-- linux-2.6-npiggin/include/asm-ia64/pgalloc.h | 5 ++--- linux-2.6-npiggin/include/asm-ia64/pgtable.h | 16 ++++++++-------- linux-2.6-npiggin/include/asm-ia64/tlb.h | 6 ++++++ 6 files changed, 48 insertions(+), 20 deletions(-)
include/asm-ia64/pgtable.h renamed from include/asm-ia64/pgtable.h~4level-ia64 +8 -8
@@ -1,8 +1,6 @@#ifndef _ASM_IA64_PGTABLE_H#define _ASM_IA64_PGTABLE_H -#include <asm-generic/4level-fixup.h> -/* * This file contains the functions and defines necessary to modify and use * the IA-64 page table tree.
@@ -256,11 +254,12 @@ ia64_phys_addr_valid (unsigned long addr#define pmd_page_kernel (pmd) ((unsigned long) __va(pmd_val(pmd) & _PFN_MASK))#define pmd_page (pmd) virt_to_page((pmd_val(pmd) + PAGE_OFFSET)) -#define pgd_none (pgd) (!pgd_val(pgd)) -#define pgd_bad (pgd) (!ia64_phys_addr_valid(pgd_val(pgd))) -#define pgd_present (pgd) (pgd_val(pgd) != 0UL) -#define pgd_clear (pgdp) (pgd_val(*(pgdp)) = 0UL) -#define pgd_page (pgd) ((unsigned long) __va(pgd_val(pgd) & _PFN_MASK)) +#define pud_none (pud) (!pud_val(pud)) +#define pud_bad (pud) (!ia64_phys_addr_valid(pud_val(pud))) +#define pud_present (pud) (pud_val(pud) != 0UL) +#define pud_clear (pudp) (pud_val(*(pudp)) = 0UL) + +#define pud_page (pud) ((unsigned long) __va(pud_val(pud) & _PFN_MASK))/* * The following have defined behavior only work if pte_present() is true.
@@ -330,7 +329,7 @@ pgd_offset (struct mm_struct *mm, unsign/* Find an entry in the second-level page table.. */ #define pmd_offset (dir,addr) \ - ((pmd_t *) pgd_page(*(dir)) + (((addr) >> PMD_SHIFT) & (PTRS_PER_PMD - 1))) + ((pmd_t *) pud_page(*(dir)) + (((addr) >> PMD_SHIFT) & (PTRS_PER_PMD - 1)))/* * Find an entry in the third-level page table. This looks more complicated than it
@@ -563,5 +562,6 @@ do { \#define __HAVE_ARCH_PTE_SAME#define __HAVE_ARCH_PGD_OFFSET_GATE#include <asm-generic/pgtable.h> +#include <asm-generic/pgtable-nopud.h> #endif /* _ASM_IA64_PGTABLE_H */
arch/ia64/mm/fault.c renamed from arch/ia64/mm/fault.c~4level-ia64 +6 -1
@@ -51,6 +51,7 @@ static int mapped_kernel_page_is_present (unsigned long address) {pgd_t *pgd; +pud_t *pud;pmd_t *pmd;pte_t *ptep, pte;
@@ -58,7 +59,11 @@ mapped_kernel_page_is_present (unsignedif (pgd_none (*pgd) ||pgd_bad (*pgd))return 0 ; - pmd =pmd_offset (pgd, address); + pud =pud_offset (pgd, address); +if (pud_none (*pud) ||pud_bad (*pud)) +return 0 ; + + pmd =pmd_offset (pud, address);if (pmd_none (*pmd) ||pmd_bad (*pmd))return 0 ;
arch/ia64/mm/hugetlbpage.c renamed from arch/ia64/mm/hugetlbpage.c~4level-ia64 +14 -6
@@ -29,13 +29,17 @@ huge_pte_alloc (struct mm_struct *mm, un {unsigned long taddr =htlbpage_to_page (addr);pgd_t *pgd; +pud_t *pud;pmd_t *pmd;pte_t *pte =NULL ; pgd =pgd_offset (mm, taddr); - pmd =pmd_alloc (mm, pgd, taddr); -if (pmd) - pte =pte_alloc_map (mm, pmd, taddr); + pud =pud_alloc (mm, pgd, taddr); +if (pud) { + pmd =pmd_alloc (mm, pud, taddr); +if (pmd) + pte =pte_alloc_map (mm, pmd, taddr); + }return pte; }
@@ -44,14 +48,18 @@ huge_pte_offset (struct mm_struct *mm, u {unsigned long taddr =htlbpage_to_page (addr);pgd_t *pgd; +pud_t *pud;pmd_t *pmd;pte_t *pte =NULL ; pgd =pgd_offset (mm, taddr);if (pgd_present (*pgd)) { - pmd =pmd_offset (pgd, taddr); -if (pmd_present (*pmd)) - pte =pte_offset_map (pmd, taddr); + pud =pud_offset (pgd, taddr); +if (pud_present (*pud)) { + pmd =pmd_offset (pud, taddr); +if (pmd_present (*pmd)) + pte =pte_offset_map (pmd, taddr); + } }return pte;
arch/ia64/mm/init.c renamed from arch/ia64/mm/init.c~4level-ia64 +12 -2
@@ -237,6 +237,7 @@ struct page * put_kernel_page (struct page *page, unsigned long address, pgprot_t pgprot) { pgd_t *pgd; +pud_t *pud;pmd_t *pmd;pte_t *pte;
@@ -248,7 +249,11 @@ put_kernel_page (struct page *page, unsispin_lock (&init_mm.page_table_lock); { - pmd =pmd_alloc (&init_mm, pgd, address); + pud =pud_alloc (&init_mm, pgd, address); +if (!pud) + goto out; + + pmd =pmd_alloc (&init_mm, pud, address);if (!pmd) goto out; pte =pte_alloc_map (&init_mm, pmd, address);
@@ -381,6 +386,7 @@ create_mem_map_page_table (u64 start, u6struct page *map_start, *map_end;int node;pgd_t *pgd; +pud_t *pud;pmd_t *pmd;pte_t *pte;
@@ -395,7 +401,11 @@ create_mem_map_page_table (u64 start, u6 pgd =pgd_offset_k (address);if (pgd_none (*pgd))pgd_populate (&init_mm, pgd,alloc_bootmem_pages_node (NODE_DATA (node),PAGE_SIZE )); - pmd =pmd_offset (pgd, address); + pud =pud_offset (pgd, address); + +if (pud_none (*pud)) +pud_populate (&init_mm, pud,alloc_bootmem_pages_node (NODE_DATA (node),PAGE_SIZE )); + pmd =pmd_offset (pud, address);if (pmd_none (*pmd))pmd_populate_kernel (&init_mm, pmd,alloc_bootmem_pages_node (NODE_DATA (node),PAGE_SIZE ));
include/asm-ia64/pgalloc.h renamed from include/asm-ia64/pgalloc.h~4level-ia64 +2 -3
@@ -79,12 +79,11 @@ pgd_free (pgd_t *pgd) }static inline void -pgd_populate (struct mm_struct *mm,pgd_t *pgd_entry,pmd_t *pmd) +pud_populate (struct mm_struct *mm,pud_t *pud_entry,pmd_t *pmd) { -pgd_val (*pgd_entry) =__pa (pmd); +pud_val (*pud_entry) =__pa (pmd); } -static inline pmd_t *pmd_alloc_one_fast (struct mm_struct *mm,unsigned long addr) {
include/asm-ia64/tlb.h renamed from include/asm-ia64/tlb.h~4level-ia64 +6 -0
@@ -236,4 +236,10 @@ do { \__pmd_free_tlb (tlb, ptep); \ } while (0) +#define pud_free_tlb (tlb, pudp) \ +do { \ + tlb->need_flush = 1; \ + __pud_free_tlb(tlb, pudp); \ +} while (0) +#endif /* _ASM_IA64_TLB_H */
_
PATCH 11/11 convert x86_64 to 4 level page tables
11/11
From: Andi Kleen <[email protected]>
Converted to true 4levels. The address space per process is expanded to 47bits now, the supported physical address space is 46bits.
Lmbench fork/exit numbers are down a few percent because it has to walk much more pagetables, but some planned future optimizations will hopefully recover it.
See Documentation/x86_64/mm.txt for more details on the memory map.
Converted to pud_t by Nick Piggin.
---
linux-2.6-npiggin/Documentation/x86_64/mm.txt | 168 ++------------------- linux-2.6-npiggin/arch/x86_64/ia32/syscall32.c | 31 ++- linux-2.6-npiggin/arch/x86_64/kernel/acpi/sleep.c | 8 - linux-2.6-npiggin/arch/x86_64/kernel/head.S | 1 linux-2.6-npiggin/arch/x86_64/kernel/init_task.c | 2 linux-2.6-npiggin/arch/x86_64/kernel/reboot.c | 2 linux-2.6-npiggin/arch/x86_64/kernel/setup64.c | 13 - linux-2.6-npiggin/arch/x86_64/mm/fault.c | 111 ++++++++----- linux-2.6-npiggin/arch/x86_64/mm/init.c | 101 +++++------- linux-2.6-npiggin/arch/x86_64/mm/ioremap.c | 43 ++++- linux-2.6-npiggin/arch/x86_64/mm/pageattr.c | 34 ++-- linux-2.6-npiggin/include/asm-x86_64/e820.h | 3 linux-2.6-npiggin/include/asm-x86_64/mmu_context.h | 5 linux-2.6-npiggin/include/asm-x86_64/page.h | 12 - linux-2.6-npiggin/include/asm-x86_64/pda.h | 1 linux-2.6-npiggin/include/asm-x86_64/pgalloc.h | 38 ++++ linux-2.6-npiggin/include/asm-x86_64/pgtable.h | 140 +++++++---------- linux-2.6-npiggin/include/asm-x86_64/processor.h | 4 18 files changed, 314 insertions(+), 403 deletions(-)
Documentation/x86_64/mm.txt renamed from Documentation/x86_64/mm.txt~4level-x86-64 +22 -146
@@ -1,148 +1,24 @@ -The paging design used on the x86-64 linux kernel port in 2.4.x provides: -o per process virtual address space limit of 512 Gigabytes -o top of userspace stack located at address 0x0000007fffffffff -o PAGE_OFFSET = 0xffff800000000000 -o start of the kernel = 0xffffffff800000000 -o global RAM per system 2^64-PAGE_OFFSET-sizeof(kernel) = 128 Terabytes - 2 Gigabytes -o no need of any common code change -o no need to use highmem to handle the 128 Terabytes of RAM - -Description: - - Userspace is able to modify and it sees only the 3rd/2nd/1st level - pagetables (pgd_offset() implicitly walks the 1st slot of the 4th - level pagetable and it returns an entry into the 3rd level pagetable). - This is where the per-process 512 Gigabytes limit cames from. - - The common code pgd is the PDPE, the pmd is the PDE, the - pte is the PTE. The PML4E remains invisible to the common - code. - - The kernel uses all the first 47 bits of the negative half - of the virtual address space to build the direct mapping using - 2 Mbytes page size. The kernel virtual addresses have bit number - 47 always set to 1 (and in turn also bits 48-63 are set to 1 too, - due the sign extension). This is where the 128 Terabytes - 2 Gigabytes global - limit of RAM cames from. - - Since the per-process limit is 512 Gigabytes (due to kernel common - code 3 level pagetable limitation), the higher virtual address mapped - into userspace is 0x7fffffffff and it makes sense to use it - as the top of the userspace stack to allow the stack to grow as - much as possible. - - Setting the PAGE_OFFSET to 2^39 (after the last userspace - virtual address) wouldn't make much difference compared to - setting PAGE_OFFSET to 0xffff800000000000 because we have an - hole into the virtual address space. The last byte mapped by the - 255th slot in the 4th level pagetable is at virtual address - 0x00007fffffffffff and the first byte mapped by the 256th slot in the - 4th level pagetable is at address 0xffff800000000000. Due to this - hole we can't trivially build a direct mapping across all the - 512 slots of the 4th level pagetable, so we simply use only the - second (negative) half of the 4th level pagetable for that purpose - (that provides us 128 Terabytes of contigous virtual addresses). - Strictly speaking we could build a direct mapping also across the hole - using some DISCONTIGMEM trick, but we don't need such a large - direct mapping right now. - -Future: - - During 2.5.x we can break the 512 Gigabytes per-process limit - possibly by removing from the common code any knowledge about the - architectural dependent physical layout of the virtual to physical - mapping. - - Once the 512 Gigabytes limit will be removed the kernel stack will - be moved (most probably to virtual address 0x00007fffffffffff). - Nothing will break in userspace due that move, as nothing breaks - in IA32 compiling the kernel with CONFIG_2G. - -Linus agreed on not breaking common code and to live with the 512 Gigabytes -per-process limitation for the 2.4.x timeframe and he has given me and Andi -some very useful hints... (thanks! :) - -Thanks also to H. Peter Anvin for his interesting and useful suggestions on -the x86-64-discuss lists! - -Other memory management related issues follows: - -PAGE_SIZE: - - If somebody is wondering why these days we still have a so small - 4k pagesize (16 or 32 kbytes would be much better for performance - of course), the PAGE_SIZE have to remain 4k for 32bit apps to - provide 100% backwards compatible IA32 API (we can't allow silent - fs corruption or as best a loss of coherency with the page cache - by allocating MAP_SHARED areas in MAP_ANONYMOUS memory with a - do_mmap_fake). I think it could be possible to have a dynamic page - size between 32bit and 64bit apps but it would need extremely - intrusive changes in the common code as first for page cache and - we sure don't want to depend on them right now even if the - hardware would support that. - -PAGETABLE SIZE: - - In turn we can't afford to have pagetables larger than 4k because - we could not be able to allocate them due physical memory - fragmentation, and failing to allocate the kernel stack is a minor - issue compared to failing the allocation of a pagetable. If we - fail the allocation of a pagetable the only thing we can do is to - sched_yield polling the freelist (deadlock prone) or to segfault - the task (not even the sighandler would be sure to run). - -KERNEL STACK: - - 1st stage: - - The kernel stack will be at first allocated with an order 2 allocation - (16k) (the utilization of the stack for a 64bit platform really - isn't exactly the double of a 32bit platform because the local - variables may not be all 64bit wide, but not much less). This will - make things even worse than they are right now on IA32 with - respect of failing fork/clone due memory fragmentation. - - 2nd stage: - - We'll benchmark if reserving one register as task_struct - pointer will improve performance of the kernel (instead of - recalculating the task_struct pointer starting from the stack - pointer each time). My guess is that recalculating will be faster - but it worth a try. - - If reserving one register for the task_struct pointer - will be faster we can as well split task_struct and kernel - stack. task_struct can be a slab allocation or a - PAGE_SIZEd allocation, and the kernel stack can then be - allocated in a order 1 allocation. Really this is risky, - since 8k on a 64bit platform is going to be less than 7k - on a 32bit platform but we could try it out. This would - reduce the fragmentation problem of an order of magnitude - making it equal to the current IA32. - - We must also consider the x86-64 seems to provide in hardware a - per-irq stack that could allow us to remove the irq handler - footprint from the regular per-process-stack, so it could allow - us to live with a smaller kernel stack compared to the other - linux architectures. - - 3rd stage: - - Before going into production if we still have the order 2 - allocation we can add a sysctl that allows the kernel stack to be - allocated with vmalloc during memory fragmentation. This have to - remain turned off during benchmarks :) but it should be ok in real - life. - -Order of PAGE_CACHE_SIZE and other allocations: - - On the long run we can increase the PAGE_CACHE_SIZE to be - an order 2 allocations and also the slab/buffercache etc.ec.. - could be all done with order 2 allocations. To make the above - to work we should change lots of common code thus it can be done - only once the basic port will be in a production state. Having - a working PAGE_CACHE_SIZE would be a benefit also for - IA32 and other architectures of course. +<previous description obsolete, deleted> -Andrea <[email protected]> SuSE +Virtual memory map with 4 level page tables: + +0000000000000000 - 00007fffffffffff (=47bits) user space, different per mm +hole caused by [48:63] sign extension +ffff800000000000 - ffff80ffffffffff (=40bits) guard hole +ffff810000000000 - ffffc0ffffffffff (=46bits) direct mapping of phys. memory +ffffc10000000000 - ffffc1ffffffffff (=40bits) hole +ffffc20000000000 - ffffe1ffffffffff (=45bits) vmalloc/ioremap space +... unused hole ... +ffffffff80000000 - ffffffff82800000 (=40MB) kernel text mapping, from phys 0 +... unused hole ... +ffffffff88000000 - fffffffffff00000 (=1919MB) module mapping space + +vmalloc space is lazily synchronized into the different PML4 pages of +the processes using the page fault handler, with init_level4_pgt as +reference. + +Current X86-64 implementations only support 40 bit of address space, +but we support upto 46bits. This expands into MBZ space in the page tables. + +-Andi Kleen, Jul 2004
arch/x86_64/ia32/syscall32.c renamed from arch/x86_64/ia32/syscall32.c~4level-x86-64 +19 -12
@@ -40,23 +40,30 @@ static int use_sysenter = -1;*/ int __map_syscall32 (struct mm_struct *mm,unsigned long address) { +pgd_t *pgd; +pgd_t *pud;pte_t *pte;pmd_t *pmd; -int err =0 ; +int err = -ENOMEM ;spin_lock (&mm->page_table_lock); - pmd =pmd_alloc (mm,pgd_offset (mm, address), address); -if (pmd && (pte =pte_alloc_map (mm, pmd, address)) !=NULL ) { -if (pte_none (*pte)) { -set_pte (pte, -mk_pte (virt_to_page (syscall32_page), -PAGE_KERNEL_VSYSCALL )); + pgd =pgd_offset (mm, address); + pud =pud_alloc (mm, pgd, address); +if (pud) { + pmd =pmd_alloc (mm, pud, address); +if (pmd && (pte =pte_alloc_map (mm, pmd, address)) !=NULL ) { +if (pte_none (*pte)) { +set_pte (pte, +mk_pte (virt_to_page (syscall32_page), +PAGE_KERNEL_VSYSCALL )); + } +/* Flush only the local CPU. Other CPUs taking a fault +will just end up here again +This probably not needed and just paranoia. */ +__flush_tlb_one (address); + err =0 ; } -/* Flush only the local CPU. Other CPUs taking a fault -will just end up here again */ -__flush_tlb_one (address); - }else - err = -ENOMEM ; + }spin_unlock (&mm->page_table_lock);return err; }
arch/x86_64/kernel/acpi/sleep.c renamed from arch/x86_64/kernel/acpi/sleep.c~4level-x86-64 +6 -2
@@ -61,9 +61,13 @@ extern char wakeup_start, wakeup_end;extern unsigned long FASTCALL (acpi_copy_wakeup_routine (unsigned long )); +static pgd_t low_ptr; +static void init_low_mapping (void ) { - cpu_pda[0 ].level4_pgt[0 ] = cpu_pda[0 ].level4_pgt[pml4_index (PAGE_OFFSET )]; +pgd_t *slot0 =pgd_offset (current->mm,0UL ); + low_ptr = *slot0; +set_pgd (slot0, *pgd_offset (current->mm,PAGE_OFFSET ));flush_tlb_all (); }
@@ -97,7 +101,7 @@ int acpi_save_state_disk (void)*/ void acpi_restore_state_mem (void ) { - cpu_pda[0 ].level4_pgt[0 ] =0 ; +set_pgd (pgd_offset (current->mm,0UL ), low_ptr);flush_tlb_all (); }
arch/x86_64/kernel/head.S renamed from arch/x86_64/kernel/head.S~4level-x86-64 +0 -1
@@ -225,7 +225,6 @@ ENTRY(init_level4_pgt) .quad 0x0000000000103007 /* -> level3_kernel_pgt */ .org 0x2000 -/* Kernel does not "know" about 4-th level of page tables. */ ENTRY(level3_ident_pgt) .quad 0x0000000000104007 .fill 511,8,0
arch/x86_64/kernel/init_task.c renamed from arch/x86_64/kernel/init_task.c~4level-x86-64 +0 -2
@@ -47,5 +47,3 @@ EXPORT_SYMBOL(init_task); DEFINE_PER_CPU(struct tss_struct, init_tss) ____cacheline_maxaligned_in_smp;#define ALIGN_TO_4K __attribute__((section(".data.init_task"))) - -pgd_t boot_vmalloc_pgt[512] ALIGN_TO_4K;
arch/x86_64/kernel/setup64.c renamed from arch/x86_64/kernel/setup64.c~4level-x86-64 +2 -11
@@ -66,7 +66,7 @@ __setup("noexec=", nonx_setup);/* * Great future plan: -* Declare PDA itself and support (irqstack,tss,pml4) as per cpu data. +* Declare PDA itself and support (irqstack,tss,pgd) as per cpu data. * Always point %gs to its beginning */ void __init setup_per_cpu_areas (void )
@@ -100,7 +100,6 @@ void __init setup_per_cpu_areas(void)void pda_init (int cpu) { -pml4_t *level4;struct x8664_pda *pda = &cpu_pda[cpu];/* Setup up data that may be needed in __get_free_pages early */
@@ -119,22 +118,14 @@ void pda_init(int cpu)/* others are initialized in smpboot.c */ pda->pcurrent = &init_task; pda->irqstackptr = boot_cpu_stack; - level4 = init_level4_pgt; }else { - level4 = (pml4_t *)__get_free_pages (GFP_ATOMIC ,0 ); -if (!level4) -panic ("Cannot allocate top level page for cpu %d" , cpu); pda->irqstackptr = (char *)__get_free_pages (GFP_ATOMIC ,IRQSTACK_ORDER );if (!pda->irqstackptr)panic ("cannot allocate irqstack for cpu %d" , cpu); } - pda->level4_pgt = (unsigned long *)level4; -if (level4 != init_level4_pgt) -memcpy (level4, &init_level4_pgt,PAGE_SIZE ); -set_pml4 (level4 +510 ,mk_kernel_pml4 (__pa_symbol (boot_vmalloc_pgt))); - asmvolatile ("movq %0,%%cr3" ::"r" (__pa (level4))); + asmvolatile ("movq %0,%%cr3" ::"r" (__pa_symbol (&init_level4_pgt))); pda->irqstackptr +=IRQSTACKSIZE -64 ; }
arch/x86_64/mm/fault.c renamed from arch/x86_64/mm/fault.c~4level-x86-64 +65 -46
146 lines not on this page · raw message
arch/x86_64/mm/init.c renamed from arch/x86_64/mm/init.c~4level-x86-64 +46 -55
198 lines not on this page · raw message
arch/x86_64/mm/ioremap.c renamed from arch/x86_64/mm/ioremap.c~4level-x86-64 +33 -10
74 lines not on this page · raw message
arch/x86_64/mm/pageattr.c renamed from arch/x86_64/mm/pageattr.c~4level-x86-64 +21 -13
@@ -16,12 +16,16 @@static inline pte_t *lookup_address (unsigned long address) { -pgd_t *pgd =pgd_offset_k (address); +pgd_t *pgd =pgd_offset_k (address); +pud_t *pud;pmd_t *pmd;pte_t *pte; -if (!pgd || !pgd_present (*pgd)) +if (pgd_none (*pgd)) +return NULL ; + pud =pud_offset (pgd, address); +if (!pud_present (*pud))return NULL ; - pmd =pmd_offset (pgd, address); + pmd =pmd_offset (pud, address);if (!pmd_present (*pmd))return NULL ;if (pmd_large (*pmd))
@@ -98,16 +102,20 @@ static inline void save_page(unsigned lo*/ static void revert_page (unsigned long address,pgprot_t ref_prot) { -pgd_t *pgd; -pmd_t *pmd; -pte_t large_pte; - - pgd =pgd_offset_k (address); - pmd =pmd_offset (pgd, address); -BUG_ON (pmd_val (*pmd) & _PAGE_PSE); -pgprot_val (ref_prot) |= _PAGE_PSE; - large_pte =mk_pte_phys (__pa (address) &LARGE_PAGE_MASK , ref_prot); -set_pte ((pte_t *)pmd, large_pte); +pgd_t *pgd; +pud_t *pud; +pmd_t *pmd; +pte_t large_pte; + + pgd =pgd_offset_k (address); +BUG_ON (pgd_none (*pgd)); + pud =pud_offset (pgd,address); +BUG_ON (pud_none (*pud)); + pmd =pmd_offset (pud, address); +BUG_ON (pmd_val (*pmd) & _PAGE_PSE); +pgprot_val (ref_prot) |= _PAGE_PSE; + large_pte =mk_pte_phys (__pa (address) &LARGE_PAGE_MASK , ref_prot); +set_pte ((pte_t *)pmd, large_pte); } static int
include/asm-x86_64/e820.h renamed from include/asm-x86_64/e820.h~4level-x86-64 +0 -3
@@ -26,9 +26,6 @@#define LOWMEMSIZE () (0x9f000) -#define MAXMEM (120UL * 1024 * 1024 * 1024 * 1024)/* 120TB */ - - #ifndef __ASSEMBLY__ struct e820entry { u64 addr; /* start of memory segment */
include/asm-x86_64/mmu_context.h renamed from include/asm-x86_64/mmu_context.h~4level-x86-64 +1 -4
@@ -40,10 +40,7 @@ static inline void switch_mm(struct mm_swrite_pda (active_mm, next);#endif set_bit (cpu, &next->cpu_vm_mask); -/* Re-load page tables */ - *read_pda (level4_pgt) =__pa (next->pgd) | _PAGE_TABLE; -__flush_tlb (); - + asmvolatile ("movq %0,%%cr3" ::"r" (__pa (next->pgd)) :"memory" );if (unlikely (next->context.ldt != prev->context.ldt))load_LDT_nolock (&next->context, cpu); }
include/asm-x86_64/page.h renamed from include/asm-x86_64/page.h~4level-x86-64 +6 -6
@@ -43,22 +43,22 @@ void copy_page(void *, void *);*/ typedef struct {unsigned long pte; }pte_t ;typedef struct {unsigned long pmd; }pmd_t ; +typedef struct {unsigned long pud; }pud_t ;typedef struct {unsigned long pgd; }pgd_t ; -typedef struct {unsigned long pml4; }pml4_t ;#define PTE_MASK PHYSICAL_PAGE_MASKtypedef struct {unsigned long pgprot; }pgprot_t ;#define pte_val (x) ((x).pte)#define pmd_val (x) ((x).pmd) +#define pud_val (x) ((x).pud)#define pgd_val (x) ((x).pgd) -#define pml4_val (x) ((x).pml4)#define pgprot_val (x) ((x).pgprot)#define __pte (x) ((pte_t) { (x) } )#define __pmd (x) ((pmd_t) { (x) } ) +#define __pud (x) ((pud_t) { (x) } )#define __pgd (x) ((pgd_t) { (x) } ) -#define __pml4 (x) ((pml4_t) { (x) } )#define __pgprot (x) ((pgprot_t) { (x) } )extern unsigned long vm_stack_flags, vm_stack_flags32;
@@ -67,19 +67,19 @@ extern unsigned long vm_force_exec32;#define __START_KERNEL 0xffffffff80100000UL#define __START_KERNEL_map 0xffffffff80000000UL -#define __PAGE_OFFSET 0x0000010000000000UL/* 1 << 40 */ +#define __PAGE_OFFSET 0xffff810000000000UL#else #define __START_KERNEL 0xffffffff80100000#define __START_KERNEL_map 0xffffffff80000000 -#define __PAGE_OFFSET 0x0000010000000000/* 1 << 40 */ +#define __PAGE_OFFSET 0xffff810000000000#endif /* !__ASSEMBLY__ */ /* to align the pointer to the (next) page boundary */ #define PAGE_ALIGN (addr) (((addr)+PAGE_SIZE-1)&PAGE_MASK)/* See Documentation/x86_64/mm.txt for a description of the memory map. */ -#define __PHYSICAL_MASK_SHIFT 40 +#define __PHYSICAL_MASK_SHIFT 46#define __PHYSICAL_MASK ((1UL << __PHYSICAL_MASK_SHIFT) - 1)#define __VIRTUAL_MASK_SHIFT 48#define __VIRTUAL_MASK ((1UL << __VIRTUAL_MASK_SHIFT) - 1)
include/asm-x86_64/pda.h renamed from include/asm-x86_64/pda.h~4level-x86-64 +0 -1
@@ -17,7 +17,6 @@ struct x8664_pda {int irqcount;/* Irq nesting counter. Starts with -1 */ int cpunumber;/* Logical CPU number */ char *irqstackptr;/* top of irqstack */ -unsigned long volatile *level4_pgt;/* Per CPU top level page table */ unsigned int __softirq_pending;unsigned int __nmi_count;/* number of NMI on this CPUs */ struct mm_struct *active_mm;
include/asm-x86_64/pgalloc.h renamed from include/asm-x86_64/pgalloc.h~4level-x86-64 +33 -5
@@ -9,8 +9,10 @@#define pmd_populate_kernel (mm, pmd, pte) \ set_pmd(pmd, __pmd(_PAGE_TABLE | __pa(pte))) -#define pgd_populate (mm, pgd, pmd) \ - set_pgd(pgd, __pgd(_PAGE_TABLE | __pa(pmd))) +#define pud_populate (mm, pud, pmd) \ + set_pud(pud, __pud(_PAGE_TABLE | __pa(pmd))) +#define pgd_populate (mm, pgd, pud) \ + set_pgd(pgd, __pgd(_PAGE_TABLE | __pa(pud)))static inline void pmd_populate (struct mm_struct *mm,pmd_t *pmd,struct page *pte) {
@@ -33,12 +35,37 @@ static inline pmd_t *pmd_alloc_one (strureturn (pmd_t *)get_zeroed_page (GFP_KERNEL |__GFP_REPEAT); } -static inline pgd_t *pgd_alloc (struct mm_struct *mm) +static inline pud_t *pud_alloc_one (struct mm_struct *mm,unsigned long addr) { -return (pgd_t *)get_zeroed_page (GFP_KERNEL |__GFP_REPEAT); +return (pud_t *)get_zeroed_page (GFP_KERNEL |__GFP_REPEAT); } -static inline void pgd_free (pgd_t *pgd) +static inline void pud_free (pud_t *pud) +{ +BUG_ON ((unsigned long )pud & (PAGE_SIZE -1 )); +free_page ((unsigned long )pud); +} + +static inline pgd_t *pgd_alloc (struct mm_struct *mm) +{ +unsigned boundary; +pgd_t *pgd = (pgd_t *)__get_free_page (GFP_KERNEL |__GFP_REPEAT); +if (!pgd) +return NULL ; +/* +* Copy kernel pointers in from init. +* Could keep a freelist or slab cache of those because the kernel +* part never changes. +*/ + boundary =pgd_index (__PAGE_OFFSET); +memset (pgd,0 , boundary *sizeof (pgd_t)); +memcpy (pgd + boundary, + init_level4_pgt + boundary, + (PTRS_PER_PGD - boundary) *sizeof (pgd_t)); +return pgd; +} + +static inline void pgd_free (pgd_t *pgd) {BUG_ON ((unsigned long )pgd & (PAGE_SIZE -1 ));free_page ((unsigned long )pgd);
@@ -73,5 +100,6 @@ extern inline void pte_free(struct page#define __pte_free_tlb (tlb,pte) tlb_remove_page((tlb),(pte))#define __pmd_free_tlb (tlb,x) pmd_free(x) +#define __pud_free_tlb (tlb,x) pud_free(x)#endif /* _X86_64_PGALLOC_H */
include/asm-x86_64/pgtable.h renamed from include/asm-x86_64/pgtable.h~4level-x86-64 +57 -83
230 lines not on this page · raw message
include/asm-x86_64/processor.h renamed from include/asm-x86_64/processor.h~4level-x86-64 +2 -2
@@ -165,9 +165,9 @@ static inline void clear_in_cr4 (unsigne/* -* User space process size: 512GB - 1GB (default). +* User space process size. 47bits. */ -#define TASK_SIZE (0x0000007fc0000000UL) +#define TASK_SIZE (0x800000000000)/* This decides where the kernel will search for a free chunk of vm * space during mmap's.
arch/x86_64/kernel/reboot.c renamed from arch/x86_64/kernel/reboot.c~4level-x86-64 +1 -1
@@ -74,7 +74,7 @@ static void reboot_warm(void)local_irq_disable ();/* restore identity mapping */ - init_level4_pgt[0 ] =__pml4 (__pa (level3_ident_pgt) |7 ); + init_level4_pgt[0 ] =__pgd (__pa (level3_ident_pgt) |7 );__flush_tlb_all ();/* Move the trampoline to low memory */
_
Quoted 2 lines
Comments? Any consensus as to which way we want to go? I don't want to inflame tempers by continuing this line of work, just provoke discussion.
Personally I think it's still better to just convert the architectures over like I did. It has to be done anyways, since you can't leave the warnings in.
When that is done it doesn't matter much which level you hcange.
I offer my tested patchkit for that :) Main advantage is that since it's already been tested for quite some time it would be possible to merge it much faster. And Nick would save some work someone else already did ;-)
If it helps I can do a global s/pml4_t/p<whatevernamelinusprefers>_t/ too.
-Andi
--
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>