aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndrea Arcangeli <aarcange@redhat.com>2011-01-13 18:46:43 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2011-01-13 20:32:40 -0500
commit8ac1f8320a0073f28cf9e0491af4cd98f504f92a (patch)
tree4dad891c302587fdc7b099b18e05d7dbc5526c64
parent64cc6ae001d70bc59e5f854e6b5678f59110df16 (diff)
thp: pte alloc trans splitting
pte alloc routines must wait for split_huge_page if the pmd is not present and not null (i.e. pmd_trans_splitting). The additional branches are optimized away at compile time by pmd_trans_splitting if the config option is off. However we must pass the vma down in order to know the anon_vma lock to wait for. [akpm@linux-foundation.org: coding-style fixes] Signed-off-by: Andrea Arcangeli <aarcange@redhat.com> Acked-by: Rik van Riel <riel@redhat.com> Acked-by: Mel Gorman <mel@csn.ul.ie> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--arch/arm/mm/pgd.c2
-rw-r--r--arch/ia64/mm/hugetlbpage.c2
-rw-r--r--arch/sh/mm/hugetlbpage.c2
-rw-r--r--arch/sparc/mm/generic_32.c2
-rw-r--r--arch/sparc/mm/generic_64.c2
-rw-r--r--arch/sparc/mm/hugetlbpage.c2
-rw-r--r--arch/um/kernel/skas/mmu.c2
-rw-r--r--arch/x86/kernel/tboot.c2
-rw-r--r--include/linux/mm.h15
-rw-r--r--mm/memory.c19
-rw-r--r--mm/mremap.c8
11 files changed, 35 insertions, 23 deletions
diff --git a/arch/arm/mm/pgd.c b/arch/arm/mm/pgd.c
index 93292a18cf77..709244c66fa3 100644
--- a/arch/arm/mm/pgd.c
+++ b/arch/arm/mm/pgd.c
@@ -50,7 +50,7 @@ pgd_t *pgd_alloc(struct mm_struct *mm)
50 if (!new_pmd) 50 if (!new_pmd)
51 goto no_pmd; 51 goto no_pmd;
52 52
53 new_pte = pte_alloc_map(mm, new_pmd, 0); 53 new_pte = pte_alloc_map(mm, NULL, new_pmd, 0);
54 if (!new_pte) 54 if (!new_pte)
55 goto no_pte; 55 goto no_pte;
56 56
diff --git a/arch/ia64/mm/hugetlbpage.c b/arch/ia64/mm/hugetlbpage.c
index 1841ee7e65f9..5ca674b74737 100644
--- a/arch/ia64/mm/hugetlbpage.c
+++ b/arch/ia64/mm/hugetlbpage.c
@@ -38,7 +38,7 @@ huge_pte_alloc(struct mm_struct *mm, unsigned long addr, unsigned long sz)
38 if (pud) { 38 if (pud) {
39 pmd = pmd_alloc(mm, pud, taddr); 39 pmd = pmd_alloc(mm, pud, taddr);
40 if (pmd) 40 if (pmd)
41 pte = pte_alloc_map(mm, pmd, taddr); 41 pte = pte_alloc_map(mm, NULL, pmd, taddr);
42 } 42 }
43 return pte; 43 return pte;
44} 44}
diff --git a/arch/sh/mm/hugetlbpage.c b/arch/sh/mm/hugetlbpage.c
index 9163db3e8d15..d7762349ea48 100644
--- a/arch/sh/mm/hugetlbpage.c
+++ b/arch/sh/mm/hugetlbpage.c
@@ -35,7 +35,7 @@ pte_t *huge_pte_alloc(struct mm_struct *mm,
35 if (pud) { 35 if (pud) {
36 pmd = pmd_alloc(mm, pud, addr); 36 pmd = pmd_alloc(mm, pud, addr);
37 if (pmd) 37 if (pmd)
38 pte = pte_alloc_map(mm, pmd, addr); 38 pte = pte_alloc_map(mm, NULL, pmd, addr);
39 } 39 }
40 } 40 }
41 41
diff --git a/arch/sparc/mm/generic_32.c b/arch/sparc/mm/generic_32.c
index 5edcac184eaf..e6067b75f11c 100644
--- a/arch/sparc/mm/generic_32.c
+++ b/arch/sparc/mm/generic_32.c
@@ -50,7 +50,7 @@ static inline int io_remap_pmd_range(struct mm_struct *mm, pmd_t * pmd, unsigned
50 end = PGDIR_SIZE; 50 end = PGDIR_SIZE;
51 offset -= address; 51 offset -= address;
52 do { 52 do {
53 pte_t * pte = pte_alloc_map(mm, pmd, address); 53 pte_t *pte = pte_alloc_map(mm, NULL, pmd, address);
54 if (!pte) 54 if (!pte)
55 return -ENOMEM; 55 return -ENOMEM;
56 io_remap_pte_range(mm, pte, address, end - address, address + offset, prot, space); 56 io_remap_pte_range(mm, pte, address, end - address, address + offset, prot, space);
diff --git a/arch/sparc/mm/generic_64.c b/arch/sparc/mm/generic_64.c
index 04f2bf4cd571..3cb00dfd4bd6 100644
--- a/arch/sparc/mm/generic_64.c
+++ b/arch/sparc/mm/generic_64.c
@@ -92,7 +92,7 @@ static inline int io_remap_pmd_range(struct mm_struct *mm, pmd_t * pmd, unsigned
92 end = PGDIR_SIZE; 92 end = PGDIR_SIZE;
93 offset -= address; 93 offset -= address;
94 do { 94 do {
95 pte_t * pte = pte_alloc_map(mm, pmd, address); 95 pte_t *pte = pte_alloc_map(mm, NULL, pmd, address);
96 if (!pte) 96 if (!pte)
97 return -ENOMEM; 97 return -ENOMEM;
98 io_remap_pte_range(mm, pte, address, end - address, address + offset, prot, space); 98 io_remap_pte_range(mm, pte, address, end - address, address + offset, prot, space);
diff --git a/arch/sparc/mm/hugetlbpage.c b/arch/sparc/mm/hugetlbpage.c
index 5fdddf134caa..f4e97646ce23 100644
--- a/arch/sparc/mm/hugetlbpage.c
+++ b/arch/sparc/mm/hugetlbpage.c
@@ -214,7 +214,7 @@ pte_t *huge_pte_alloc(struct mm_struct *mm,
214 if (pud) { 214 if (pud) {
215 pmd = pmd_alloc(mm, pud, addr); 215 pmd = pmd_alloc(mm, pud, addr);
216 if (pmd) 216 if (pmd)
217 pte = pte_alloc_map(mm, pmd, addr); 217 pte = pte_alloc_map(mm, NULL, pmd, addr);
218 } 218 }
219 return pte; 219 return pte;
220} 220}
diff --git a/arch/um/kernel/skas/mmu.c b/arch/um/kernel/skas/mmu.c
index 3d099f974785..1aee587e9c5d 100644
--- a/arch/um/kernel/skas/mmu.c
+++ b/arch/um/kernel/skas/mmu.c
@@ -31,7 +31,7 @@ static int init_stub_pte(struct mm_struct *mm, unsigned long proc,
31 if (!pmd) 31 if (!pmd)
32 goto out_pmd; 32 goto out_pmd;
33 33
34 pte = pte_alloc_map(mm, pmd, proc); 34 pte = pte_alloc_map(mm, NULL, pmd, proc);
35 if (!pte) 35 if (!pte)
36 goto out_pte; 36 goto out_pte;
37 37
diff --git a/arch/x86/kernel/tboot.c b/arch/x86/kernel/tboot.c
index c2f1b26141e2..998e972f3b1a 100644
--- a/arch/x86/kernel/tboot.c
+++ b/arch/x86/kernel/tboot.c
@@ -133,7 +133,7 @@ static int map_tboot_page(unsigned long vaddr, unsigned long pfn,
133 pmd = pmd_alloc(&tboot_mm, pud, vaddr); 133 pmd = pmd_alloc(&tboot_mm, pud, vaddr);
134 if (!pmd) 134 if (!pmd)
135 return -1; 135 return -1;
136 pte = pte_alloc_map(&tboot_mm, pmd, vaddr); 136 pte = pte_alloc_map(&tboot_mm, NULL, pmd, vaddr);
137 if (!pte) 137 if (!pte)
138 return -1; 138 return -1;
139 set_pte_at(&tboot_mm, vaddr, pte, pfn_pte(pfn, prot)); 139 set_pte_at(&tboot_mm, vaddr, pte, pfn_pte(pfn, prot));
diff --git a/include/linux/mm.h b/include/linux/mm.h
index 6bef67d74adf..14ddd98b063f 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -1131,7 +1131,8 @@ static inline int __pmd_alloc(struct mm_struct *mm, pud_t *pud,
1131int __pmd_alloc(struct mm_struct *mm, pud_t *pud, unsigned long address); 1131int __pmd_alloc(struct mm_struct *mm, pud_t *pud, unsigned long address);
1132#endif 1132#endif
1133 1133
1134int __pte_alloc(struct mm_struct *mm, pmd_t *pmd, unsigned long address); 1134int __pte_alloc(struct mm_struct *mm, struct vm_area_struct *vma,
1135 pmd_t *pmd, unsigned long address);
1135int __pte_alloc_kernel(pmd_t *pmd, unsigned long address); 1136int __pte_alloc_kernel(pmd_t *pmd, unsigned long address);
1136 1137
1137/* 1138/*
@@ -1200,16 +1201,18 @@ static inline void pgtable_page_dtor(struct page *page)
1200 pte_unmap(pte); \ 1201 pte_unmap(pte); \
1201} while (0) 1202} while (0)
1202 1203
1203#define pte_alloc_map(mm, pmd, address) \ 1204#define pte_alloc_map(mm, vma, pmd, address) \
1204 ((unlikely(!pmd_present(*(pmd))) && __pte_alloc(mm, pmd, address))? \ 1205 ((unlikely(pmd_none(*(pmd))) && __pte_alloc(mm, vma, \
1205 NULL: pte_offset_map(pmd, address)) 1206 pmd, address))? \
1207 NULL: pte_offset_map(pmd, address))
1206 1208
1207#define pte_alloc_map_lock(mm, pmd, address, ptlp) \ 1209#define pte_alloc_map_lock(mm, pmd, address, ptlp) \
1208 ((unlikely(!pmd_present(*(pmd))) && __pte_alloc(mm, pmd, address))? \ 1210 ((unlikely(pmd_none(*(pmd))) && __pte_alloc(mm, NULL, \
1211 pmd, address))? \
1209 NULL: pte_offset_map_lock(mm, pmd, address, ptlp)) 1212 NULL: pte_offset_map_lock(mm, pmd, address, ptlp))
1210 1213
1211#define pte_alloc_kernel(pmd, address) \ 1214#define pte_alloc_kernel(pmd, address) \
1212 ((unlikely(!pmd_present(*(pmd))) && __pte_alloc_kernel(pmd, address))? \ 1215 ((unlikely(pmd_none(*(pmd))) && __pte_alloc_kernel(pmd, address))? \
1213 NULL: pte_offset_kernel(pmd, address)) 1216 NULL: pte_offset_kernel(pmd, address))
1214 1217
1215extern void free_area_init(unsigned long * zones_size); 1218extern void free_area_init(unsigned long * zones_size);
diff --git a/mm/memory.c b/mm/memory.c
index bdf19366b705..567bca80ea53 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -394,9 +394,11 @@ void free_pgtables(struct mmu_gather *tlb, struct vm_area_struct *vma,
394 } 394 }
395} 395}
396 396
397int __pte_alloc(struct mm_struct *mm, pmd_t *pmd, unsigned long address) 397int __pte_alloc(struct mm_struct *mm, struct vm_area_struct *vma,
398 pmd_t *pmd, unsigned long address)
398{ 399{
399 pgtable_t new = pte_alloc_one(mm, address); 400 pgtable_t new = pte_alloc_one(mm, address);
401 int wait_split_huge_page;
400 if (!new) 402 if (!new)
401 return -ENOMEM; 403 return -ENOMEM;
402 404
@@ -416,14 +418,18 @@ int __pte_alloc(struct mm_struct *mm, pmd_t *pmd, unsigned long address)
416 smp_wmb(); /* Could be smp_wmb__xxx(before|after)_spin_lock */ 418 smp_wmb(); /* Could be smp_wmb__xxx(before|after)_spin_lock */
417 419
418 spin_lock(&mm->page_table_lock); 420 spin_lock(&mm->page_table_lock);
419 if (!pmd_present(*pmd)) { /* Has another populated it ? */ 421 wait_split_huge_page = 0;
422 if (likely(pmd_none(*pmd))) { /* Has another populated it ? */
420 mm->nr_ptes++; 423 mm->nr_ptes++;
421 pmd_populate(mm, pmd, new); 424 pmd_populate(mm, pmd, new);
422 new = NULL; 425 new = NULL;
423 } 426 } else if (unlikely(pmd_trans_splitting(*pmd)))
427 wait_split_huge_page = 1;
424 spin_unlock(&mm->page_table_lock); 428 spin_unlock(&mm->page_table_lock);
425 if (new) 429 if (new)
426 pte_free(mm, new); 430 pte_free(mm, new);
431 if (wait_split_huge_page)
432 wait_split_huge_page(vma->anon_vma, pmd);
427 return 0; 433 return 0;
428} 434}
429 435
@@ -436,10 +442,11 @@ int __pte_alloc_kernel(pmd_t *pmd, unsigned long address)
436 smp_wmb(); /* See comment in __pte_alloc */ 442 smp_wmb(); /* See comment in __pte_alloc */
437 443
438 spin_lock(&init_mm.page_table_lock); 444 spin_lock(&init_mm.page_table_lock);
439 if (!pmd_present(*pmd)) { /* Has another populated it ? */ 445 if (likely(pmd_none(*pmd))) { /* Has another populated it ? */
440 pmd_populate_kernel(&init_mm, pmd, new); 446 pmd_populate_kernel(&init_mm, pmd, new);
441 new = NULL; 447 new = NULL;
442 } 448 } else
449 VM_BUG_ON(pmd_trans_splitting(*pmd));
443 spin_unlock(&init_mm.page_table_lock); 450 spin_unlock(&init_mm.page_table_lock);
444 if (new) 451 if (new)
445 pte_free_kernel(&init_mm, new); 452 pte_free_kernel(&init_mm, new);
@@ -3253,7 +3260,7 @@ int handle_mm_fault(struct mm_struct *mm, struct vm_area_struct *vma,
3253 pmd = pmd_alloc(mm, pud, address); 3260 pmd = pmd_alloc(mm, pud, address);
3254 if (!pmd) 3261 if (!pmd)
3255 return VM_FAULT_OOM; 3262 return VM_FAULT_OOM;
3256 pte = pte_alloc_map(mm, pmd, address); 3263 pte = pte_alloc_map(mm, vma, pmd, address);
3257 if (!pte) 3264 if (!pte)
3258 return VM_FAULT_OOM; 3265 return VM_FAULT_OOM;
3259 3266
diff --git a/mm/mremap.c b/mm/mremap.c
index 563fbdd6293a..b09eefaea0b8 100644
--- a/mm/mremap.c
+++ b/mm/mremap.c
@@ -47,7 +47,8 @@ static pmd_t *get_old_pmd(struct mm_struct *mm, unsigned long addr)
47 return pmd; 47 return pmd;
48} 48}
49 49
50static pmd_t *alloc_new_pmd(struct mm_struct *mm, unsigned long addr) 50static pmd_t *alloc_new_pmd(struct mm_struct *mm, struct vm_area_struct *vma,
51 unsigned long addr)
51{ 52{
52 pgd_t *pgd; 53 pgd_t *pgd;
53 pud_t *pud; 54 pud_t *pud;
@@ -62,7 +63,8 @@ static pmd_t *alloc_new_pmd(struct mm_struct *mm, unsigned long addr)
62 if (!pmd) 63 if (!pmd)
63 return NULL; 64 return NULL;
64 65
65 if (!pmd_present(*pmd) && __pte_alloc(mm, pmd, addr)) 66 VM_BUG_ON(pmd_trans_huge(*pmd));
67 if (pmd_none(*pmd) && __pte_alloc(mm, vma, pmd, addr))
66 return NULL; 68 return NULL;
67 69
68 return pmd; 70 return pmd;
@@ -147,7 +149,7 @@ unsigned long move_page_tables(struct vm_area_struct *vma,
147 old_pmd = get_old_pmd(vma->vm_mm, old_addr); 149 old_pmd = get_old_pmd(vma->vm_mm, old_addr);
148 if (!old_pmd) 150 if (!old_pmd)
149 continue; 151 continue;
150 new_pmd = alloc_new_pmd(vma->vm_mm, new_addr); 152 new_pmd = alloc_new_pmd(vma->vm_mm, vma, new_addr);
151 if (!new_pmd) 153 if (!new_pmd)
152 break; 154 break;
153 next = (new_addr + PMD_SIZE) & PMD_MASK; 155 next = (new_addr + PMD_SIZE) & PMD_MASK;