aboutsummaryrefslogtreecommitdiffstats
path: root/mm
diff options
context:
space:
mode:
authorKirill A. Shutemov <kirill.shutemov@linux.intel.com>2012-12-12 16:51:05 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2012-12-12 20:38:31 -0500
commit78ca0e679203bbf74f8febd9725a1c8dd083d073 (patch)
tree6b2541d8cb1ee2697eb12a299447e5afc78f830c /mm
parent80371957f09814d25c38733d2d08de47f59a13c2 (diff)
thp: lazy huge zero page allocation
Instead of allocating huge zero page on hugepage_init() we can postpone it until first huge zero page map. It saves memory if THP is not in use. cmpxchg() is used to avoid race on huge_zero_pfn initialization. Signed-off-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com> Cc: Andrea Arcangeli <aarcange@redhat.com> Cc: Andi Kleen <ak@linux.intel.com> Cc: "H. Peter Anvin" <hpa@linux.intel.com> Cc: Mel Gorman <mel@csn.ul.ie> Cc: David Rientjes <rientjes@google.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'mm')
-rw-r--r--mm/huge_memory.c20
1 files changed, 10 insertions, 10 deletions
diff --git a/mm/huge_memory.c b/mm/huge_memory.c
index e1b6f4e13b91..9539d6654bb9 100644
--- a/mm/huge_memory.c
+++ b/mm/huge_memory.c
@@ -160,22 +160,24 @@ static int start_khugepaged(void)
160 return err; 160 return err;
161} 161}
162 162
163static int __init init_huge_zero_page(void) 163static int init_huge_zero_pfn(void)
164{ 164{
165 struct page *hpage; 165 struct page *hpage;
166 unsigned long pfn;
166 167
167 hpage = alloc_pages((GFP_TRANSHUGE | __GFP_ZERO) & ~__GFP_MOVABLE, 168 hpage = alloc_pages((GFP_TRANSHUGE | __GFP_ZERO) & ~__GFP_MOVABLE,
168 HPAGE_PMD_ORDER); 169 HPAGE_PMD_ORDER);
169 if (!hpage) 170 if (!hpage)
170 return -ENOMEM; 171 return -ENOMEM;
171 172 pfn = page_to_pfn(hpage);
172 huge_zero_pfn = page_to_pfn(hpage); 173 if (cmpxchg(&huge_zero_pfn, 0, pfn))
174 __free_page(hpage);
173 return 0; 175 return 0;
174} 176}
175 177
176static inline bool is_huge_zero_pfn(unsigned long pfn) 178static inline bool is_huge_zero_pfn(unsigned long pfn)
177{ 179{
178 return pfn == huge_zero_pfn; 180 return huge_zero_pfn && pfn == huge_zero_pfn;
179} 181}
180 182
181static inline bool is_huge_zero_pmd(pmd_t pmd) 183static inline bool is_huge_zero_pmd(pmd_t pmd)
@@ -564,10 +566,6 @@ static int __init hugepage_init(void)
564 if (err) 566 if (err)
565 return err; 567 return err;
566 568
567 err = init_huge_zero_page();
568 if (err)
569 goto out;
570
571 err = khugepaged_slab_init(); 569 err = khugepaged_slab_init();
572 if (err) 570 if (err)
573 goto out; 571 goto out;
@@ -590,8 +588,6 @@ static int __init hugepage_init(void)
590 588
591 return 0; 589 return 0;
592out: 590out:
593 if (huge_zero_pfn)
594 __free_page(pfn_to_page(huge_zero_pfn));
595 hugepage_exit_sysfs(hugepage_kobj); 591 hugepage_exit_sysfs(hugepage_kobj);
596 return err; 592 return err;
597} 593}
@@ -735,6 +731,10 @@ int do_huge_pmd_anonymous_page(struct mm_struct *mm, struct vm_area_struct *vma,
735 return VM_FAULT_OOM; 731 return VM_FAULT_OOM;
736 if (!(flags & FAULT_FLAG_WRITE)) { 732 if (!(flags & FAULT_FLAG_WRITE)) {
737 pgtable_t pgtable; 733 pgtable_t pgtable;
734 if (unlikely(!huge_zero_pfn && init_huge_zero_pfn())) {
735 count_vm_event(THP_FAULT_FALLBACK);
736 goto out;
737 }
738 pgtable = pte_alloc_one(mm, haddr); 738 pgtable = pte_alloc_one(mm, haddr);
739 if (unlikely(!pgtable)) 739 if (unlikely(!pgtable))
740 return VM_FAULT_OOM; 740 return VM_FAULT_OOM;