diff options
author | Kirill A. Shutemov <kirill.shutemov@linux.intel.com> | 2012-12-12 16:51:05 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-12-12 20:38:31 -0500 |
commit | 78ca0e679203bbf74f8febd9725a1c8dd083d073 (patch) | |
tree | 6b2541d8cb1ee2697eb12a299447e5afc78f830c /mm | |
parent | 80371957f09814d25c38733d2d08de47f59a13c2 (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.c | 20 |
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 | ||
163 | static int __init init_huge_zero_page(void) | 163 | static 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 | ||
176 | static inline bool is_huge_zero_pfn(unsigned long pfn) | 178 | static 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 | ||
181 | static inline bool is_huge_zero_pmd(pmd_t pmd) | 183 | static 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; |
592 | out: | 590 | out: |
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; |