diff options
| author | David Gibson <david@gibson.dropbear.id.au> | 2005-06-21 20:14:44 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-06-21 21:46:15 -0400 |
| commit | 63551ae0feaaa23807ebea60de1901564bbef32e (patch) | |
| tree | f6f97f60f83c3e9813bdfcc6039c499997b1ea10 | |
| parent | 1e7e5a9048b30c57ba1ddaa6cdf59b21b65cde99 (diff) | |
[PATCH] Hugepage consolidation
A lot of the code in arch/*/mm/hugetlbpage.c is quite similar. This patch
attempts to consolidate a lot of the code across the arch's, putting the
combined version in mm/hugetlb.c. There are a couple of uglyish hacks in
order to covert all the hugepage archs, but the result is a very large
reduction in the total amount of code. It also means things like hugepage
lazy allocation could be implemented in one place, instead of six.
Tested, at least a little, on ppc64, i386 and x86_64.
Notes:
- this patch changes the meaning of set_huge_pte() to be more
analagous to set_pte()
- does SH4 need s special huge_ptep_get_and_clear()??
Acked-by: William Lee Irwin <wli@holomorphy.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
| -rw-r--r-- | arch/i386/mm/hugetlbpage.c | 170 | ||||
| -rw-r--r-- | arch/ia64/mm/hugetlbpage.c | 158 | ||||
| -rw-r--r-- | arch/ppc64/mm/hugetlbpage.c | 180 | ||||
| -rw-r--r-- | arch/sh/mm/hugetlbpage.c | 196 | ||||
| -rw-r--r-- | arch/sh64/mm/hugetlbpage.c | 18 | ||||
| -rw-r--r-- | arch/sparc64/mm/hugetlbpage.c | 195 | ||||
| -rw-r--r-- | include/asm-i386/page.h | 1 | ||||
| -rw-r--r-- | include/asm-i386/pgtable.h | 2 | ||||
| -rw-r--r-- | include/asm-ia64/pgtable.h | 1 | ||||
| -rw-r--r-- | include/asm-sh/page.h | 1 | ||||
| -rw-r--r-- | include/asm-sh/pgtable.h | 1 | ||||
| -rw-r--r-- | include/asm-sh64/page.h | 1 | ||||
| -rw-r--r-- | include/asm-sh64/pgtable.h | 2 | ||||
| -rw-r--r-- | include/asm-sparc64/page.h | 2 | ||||
| -rw-r--r-- | include/asm-sparc64/pgtable.h | 1 | ||||
| -rw-r--r-- | include/asm-x86_64/page.h | 1 | ||||
| -rw-r--r-- | include/asm-x86_64/pgtable.h | 3 | ||||
| -rw-r--r-- | include/linux/hugetlb.h | 40 | ||||
| -rw-r--r-- | mm/hugetlb.c | 177 |
19 files changed, 300 insertions, 850 deletions
diff --git a/arch/i386/mm/hugetlbpage.c b/arch/i386/mm/hugetlbpage.c index 171fc925e1e4..5aa06001a4bd 100644 --- a/arch/i386/mm/hugetlbpage.c +++ b/arch/i386/mm/hugetlbpage.c | |||
| @@ -18,7 +18,7 @@ | |||
| 18 | #include <asm/tlb.h> | 18 | #include <asm/tlb.h> |
| 19 | #include <asm/tlbflush.h> | 19 | #include <asm/tlbflush.h> |
| 20 | 20 | ||
| 21 | static pte_t *huge_pte_alloc(struct mm_struct *mm, unsigned long addr) | 21 | pte_t *huge_pte_alloc(struct mm_struct *mm, unsigned long addr) |
| 22 | { | 22 | { |
| 23 | pgd_t *pgd; | 23 | pgd_t *pgd; |
| 24 | pud_t *pud; | 24 | pud_t *pud; |
| @@ -30,7 +30,7 @@ static pte_t *huge_pte_alloc(struct mm_struct *mm, unsigned long addr) | |||
| 30 | return (pte_t *) pmd; | 30 | return (pte_t *) pmd; |
| 31 | } | 31 | } |
| 32 | 32 | ||
| 33 | static pte_t *huge_pte_offset(struct mm_struct *mm, unsigned long addr) | 33 | pte_t *huge_pte_offset(struct mm_struct *mm, unsigned long addr) |
| 34 | { | 34 | { |
| 35 | pgd_t *pgd; | 35 | pgd_t *pgd; |
| 36 | pud_t *pud; | 36 | pud_t *pud; |
| @@ -42,21 +42,6 @@ static pte_t *huge_pte_offset(struct mm_struct *mm, unsigned long addr) | |||
| 42 | return (pte_t *) pmd; | 42 | return (pte_t *) pmd; |
| 43 | } | 43 | } |
| 44 | 44 | ||
| 45 | static void set_huge_pte(struct mm_struct *mm, struct vm_area_struct *vma, struct page *page, pte_t * page_table, int write_access) | ||
| 46 | { | ||
| 47 | pte_t entry; | ||
| 48 | |||
| 49 | add_mm_counter(mm, rss, HPAGE_SIZE / PAGE_SIZE); | ||
| 50 | if (write_access) { | ||
| 51 | entry = | ||
| 52 | pte_mkwrite(pte_mkdirty(mk_pte(page, vma->vm_page_prot))); | ||
| 53 | } else | ||
| 54 | entry = pte_wrprotect(mk_pte(page, vma->vm_page_prot)); | ||
| 55 | entry = pte_mkyoung(entry); | ||
| 56 | mk_pte_huge(entry); | ||
| 57 | set_pte(page_table, entry); | ||
| 58 | } | ||
| 59 | |||
| 60 | /* | 45 | /* |
| 61 | * This function checks for proper alignment of input addr and len parameters. | 46 | * This function checks for proper alignment of input addr and len parameters. |
| 62 | */ | 47 | */ |
| @@ -69,77 +54,6 @@ int is_aligned_hugepage_range(unsigned long addr, unsigned long len) | |||
| 69 | return 0; | 54 | return 0; |
| 70 | } | 55 | } |
| 71 | 56 | ||
| 72 | int copy_hugetlb_page_range(struct mm_struct *dst, struct mm_struct *src, | ||
| 73 | struct vm_area_struct *vma) | ||
| 74 | { | ||
| 75 | pte_t *src_pte, *dst_pte, entry; | ||
| 76 | struct page *ptepage; | ||
| 77 | unsigned long addr = vma->vm_start; | ||
| 78 | unsigned long end = vma->vm_end; | ||
| 79 | |||
| 80 | while (addr < end) { | ||
| 81 | dst_pte = huge_pte_alloc(dst, addr); | ||
| 82 | if (!dst_pte) | ||
| 83 | goto nomem; | ||
| 84 | src_pte = huge_pte_offset(src, addr); | ||
| 85 | entry = *src_pte; | ||
| 86 | ptepage = pte_page(entry); | ||
| 87 | get_page(ptepage); | ||
| 88 | set_pte(dst_pte, entry); | ||
| 89 | add_mm_counter(dst, rss, HPAGE_SIZE / PAGE_SIZE); | ||
| 90 | addr += HPAGE_SIZE; | ||
| 91 | } | ||
| 92 | return 0; | ||
| 93 | |||
| 94 | nomem: | ||
| 95 | return -ENOMEM; | ||
| 96 | } | ||
| 97 | |||
| 98 | int | ||
| 99 | follow_hugetlb_page(struct mm_struct *mm, struct vm_area_struct *vma, | ||
| 100 | struct page **pages, struct vm_area_struct **vmas, | ||
| 101 | unsigned long *position, int *length, int i) | ||
| 102 | { | ||
| 103 | unsigned long vpfn, vaddr = *position; | ||
| 104 | int remainder = *length; | ||
| 105 | |||
| 106 | WARN_ON(!is_vm_hugetlb_page(vma)); | ||
| 107 | |||
| 108 | vpfn = vaddr/PAGE_SIZE; | ||
| 109 | while (vaddr < vma->vm_end && remainder) { | ||
| 110 | |||
| 111 | if (pages) { | ||
| 112 | pte_t *pte; | ||
| 113 | struct page *page; | ||
| 114 | |||
| 115 | pte = huge_pte_offset(mm, vaddr); | ||
| 116 | |||
| 117 | /* hugetlb should be locked, and hence, prefaulted */ | ||
| 118 | WARN_ON(!pte || pte_none(*pte)); | ||
| 119 | |||
| 120 | page = &pte_page(*pte)[vpfn % (HPAGE_SIZE/PAGE_SIZE)]; | ||
| 121 | |||
| 122 | WARN_ON(!PageCompound(page)); | ||
| 123 | |||
| 124 | get_page(page); | ||
| 125 | pages[i] = page; | ||
| 126 | } | ||
| 127 | |||
| 128 | if (vmas) | ||
| 129 | vmas[i] = vma; | ||
| 130 | |||
| 131 | vaddr += PAGE_SIZE; | ||
| 132 | ++vpfn; | ||
| 133 | --remainder; | ||
| 134 | ++i; | ||
| 135 | } | ||
| 136 | |||
| 137 | *length = remainder; | ||
| 138 | *position = vaddr; | ||
| 139 | |||
| 140 | return i; | ||
| 141 | } | ||
| 142 | |||
| 143 | #if 0 /* This is just for testing */ | 57 | #if 0 /* This is just for testing */ |
| 144 | struct page * | 58 | struct page * |
| 145 | follow_huge_addr(struct mm_struct *mm, unsigned long address, int write) | 59 | follow_huge_addr(struct mm_struct *mm, unsigned long address, int write) |
| @@ -204,83 +118,15 @@ follow_huge_pmd(struct mm_struct *mm, unsigned long address, | |||
| 204 | } | 118 | } |
| 205 | #endif | 119 | #endif |
| 206 | 120 | ||
| 207 | void unmap_hugepage_range(struct vm_area_struct *vma, | 121 | void hugetlb_clean_stale_pgtable(pte_t *pte) |
| 208 | unsigned long start, unsigned long end) | ||
| 209 | { | 122 | { |
| 210 | struct mm_struct *mm = vma->vm_mm; | 123 | pmd_t *pmd = (pmd_t *) pte; |
| 211 | unsigned long address; | ||
| 212 | pte_t pte, *ptep; | ||
| 213 | struct page *page; | 124 | struct page *page; |
| 214 | 125 | ||
| 215 | BUG_ON(start & (HPAGE_SIZE - 1)); | 126 | page = pmd_page(*pmd); |
| 216 | BUG_ON(end & (HPAGE_SIZE - 1)); | 127 | pmd_clear(pmd); |
| 217 | 128 | dec_page_state(nr_page_table_pages); | |
| 218 | for (address = start; address < end; address += HPAGE_SIZE) { | 129 | page_cache_release(page); |
| 219 | ptep = huge_pte_offset(mm, address); | ||
| 220 | if (!ptep) | ||
| 221 | continue; | ||
| 222 | pte = ptep_get_and_clear(mm, address, ptep); | ||
| 223 | if (pte_none(pte)) | ||
| 224 | continue; | ||
| 225 | page = pte_page(pte); | ||
| 226 | put_page(page); | ||
| 227 | } | ||
| 228 | add_mm_counter(mm ,rss, -((end - start) >> PAGE_SHIFT)); | ||
| 229 | flush_tlb_range(vma, start, end); | ||
| 230 | } | ||
| 231 | |||
| 232 | int hugetlb_prefault(struct address_space *mapping, struct vm_area_struct *vma) | ||
| 233 | { | ||
| 234 | struct mm_struct *mm = current->mm; | ||
| 235 | unsigned long addr; | ||
| 236 | int ret = 0; | ||
| 237 | |||
