aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKirill A. Shutemov <kirill.shutemov@linux.intel.com>2016-07-26 18:26:35 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2016-07-26 19:19:19 -0400
commite496cf3d782135c1cca0d154d4b924517ff58de0 (patch)
tree884ae0082c0b344dd9200b28ca087a3cc0973fed
parentf3f0e1d2150b2b99da2cbdfaad000089efe9bf30 (diff)
thp: introduce CONFIG_TRANSPARENT_HUGE_PAGECACHE
For file mappings, we don't deposit page tables on THP allocation because it's not strictly required to implement split_huge_pmd(): we can just clear pmd and let following page faults to reconstruct the page table. But Power makes use of deposited page table to address MMU quirk. Let's hide THP page cache, including huge tmpfs, under separate config option, so it can be forbidden on Power. We can revert the patch later once solution for Power found. Link: http://lkml.kernel.org/r/1466021202-61880-36-git-send-email-kirill.shutemov@linux.intel.com Signed-off-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com> Cc: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--include/linux/shmem_fs.h10
-rw-r--r--mm/Kconfig8
-rw-r--r--mm/huge_memory.c2
-rw-r--r--mm/khugepaged.c11
-rw-r--r--mm/memory.c5
-rw-r--r--mm/shmem.c26
6 files changed, 41 insertions, 21 deletions
diff --git a/include/linux/shmem_fs.h b/include/linux/shmem_fs.h
index 0890f700a546..54fa28dfbd89 100644
--- a/include/linux/shmem_fs.h
+++ b/include/linux/shmem_fs.h
@@ -54,7 +54,6 @@ extern unsigned long shmem_get_unmapped_area(struct file *, unsigned long addr,
54 unsigned long len, unsigned long pgoff, unsigned long flags); 54 unsigned long len, unsigned long pgoff, unsigned long flags);
55extern int shmem_lock(struct file *file, int lock, struct user_struct *user); 55extern int shmem_lock(struct file *file, int lock, struct user_struct *user);
56extern bool shmem_mapping(struct address_space *mapping); 56extern bool shmem_mapping(struct address_space *mapping);
57extern bool shmem_huge_enabled(struct vm_area_struct *vma);
58extern void shmem_unlock_mapping(struct address_space *mapping); 57extern void shmem_unlock_mapping(struct address_space *mapping);
59extern struct page *shmem_read_mapping_page_gfp(struct address_space *mapping, 58extern struct page *shmem_read_mapping_page_gfp(struct address_space *mapping,
60 pgoff_t index, gfp_t gfp_mask); 59 pgoff_t index, gfp_t gfp_mask);
@@ -112,4 +111,13 @@ static inline long shmem_fcntl(struct file *f, unsigned int c, unsigned long a)
112 111
113#endif 112#endif
114 113
114#ifdef CONFIG_TRANSPARENT_HUGE_PAGECACHE
115extern bool shmem_huge_enabled(struct vm_area_struct *vma);
116#else
117static inline bool shmem_huge_enabled(struct vm_area_struct *vma)
118{
119 return false;
120}
121#endif
122
115#endif 123#endif
diff --git a/mm/Kconfig b/mm/Kconfig
index 3e2daef3c946..3c81803b00a3 100644
--- a/mm/Kconfig
+++ b/mm/Kconfig
@@ -440,6 +440,14 @@ choice
440endchoice 440endchoice
441 441
442# 442#
443# We don't deposit page tables on file THP mapping,
444# but Power makes use of them to address MMU quirk.
445#
446config TRANSPARENT_HUGE_PAGECACHE
447 def_bool y
448 depends on TRANSPARENT_HUGEPAGE && !PPC
449
450#
443# UP and nommu archs use km based percpu allocator 451# UP and nommu archs use km based percpu allocator
444# 452#
445config NEED_PER_CPU_KM 453config NEED_PER_CPU_KM
diff --git a/mm/huge_memory.c b/mm/huge_memory.c
index 2706182787d8..d3abbf249fa0 100644
--- a/mm/huge_memory.c
+++ b/mm/huge_memory.c
@@ -287,7 +287,7 @@ static struct attribute *hugepage_attr[] = {
287 &enabled_attr.attr, 287 &enabled_attr.attr,
288 &defrag_attr.attr, 288 &defrag_attr.attr,
289 &use_zero_page_attr.attr, 289 &use_zero_page_attr.attr,
290#ifdef CONFIG_SHMEM 290#if defined(CONFIG_SHMEM) && defined(CONFIG_TRANSPARENT_HUGE_PAGECACHE)
291 &shmem_enabled_attr.attr, 291 &shmem_enabled_attr.attr,
292#endif 292#endif
293#ifdef CONFIG_DEBUG_VM 293#ifdef CONFIG_DEBUG_VM
diff --git a/mm/khugepaged.c b/mm/khugepaged.c
index 573e4366d3b9..93d5f87c00d5 100644
--- a/mm/khugepaged.c
+++ b/mm/khugepaged.c
@@ -819,6 +819,8 @@ static bool hugepage_vma_check(struct vm_area_struct *vma)
819 (vma->vm_flags & VM_NOHUGEPAGE)) 819 (vma->vm_flags & VM_NOHUGEPAGE))
820 return false; 820 return false;
821 if (shmem_file(vma->vm_file)) { 821 if (shmem_file(vma->vm_file)) {
822 if (!IS_ENABLED(CONFIG_TRANSPARENT_HUGE_PAGECACHE))
823 return false;
822 return IS_ALIGNED((vma->vm_start >> PAGE_SHIFT) - vma->vm_pgoff, 824 return IS_ALIGNED((vma->vm_start >> PAGE_SHIFT) - vma->vm_pgoff,
823 HPAGE_PMD_NR); 825 HPAGE_PMD_NR);
824 } 826 }
@@ -1222,7 +1224,7 @@ static void collect_mm_slot(struct mm_slot *mm_slot)
1222 } 1224 }
1223} 1225}
1224 1226
1225#ifdef CONFIG_SHMEM 1227#if defined(CONFIG_SHMEM) && defined(CONFIG_TRANSPARENT_HUGE_PAGECACHE)
1226static void retract_page_tables(struct address_space *mapping, pgoff_t pgoff) 1228static void retract_page_tables(struct address_space *mapping, pgoff_t pgoff)
1227{ 1229{
1228 struct vm_area_struct *vma; 1230 struct vm_area_struct *vma;
@@ -1681,8 +1683,6 @@ skip:
1681 if (khugepaged_scan.address < hstart) 1683 if (khugepaged_scan.address < hstart)
1682 khugepaged_scan.address = hstart; 1684 khugepaged_scan.address = hstart;
1683 VM_BUG_ON(khugepaged_scan.address & ~HPAGE_PMD_MASK); 1685 VM_BUG_ON(khugepaged_scan.address & ~HPAGE_PMD_MASK);
1684 if (shmem_file(vma->vm_file) && !shmem_huge_enabled(vma))
1685 goto skip;
1686 1686
1687 while (khugepaged_scan.address < hend) { 1687 while (khugepaged_scan.address < hend) {
1688 int ret; 1688 int ret;
@@ -1694,9 +1694,12 @@ skip:
1694 khugepaged_scan.address + HPAGE_PMD_SIZE > 1694 khugepaged_scan.address + HPAGE_PMD_SIZE >
1695 hend); 1695 hend);
1696 if (shmem_file(vma->vm_file)) { 1696 if (shmem_file(vma->vm_file)) {
1697 struct file *file = get_file(vma->vm_file); 1697 struct file *file;
1698 pgoff_t pgoff = linear_page_index(vma, 1698 pgoff_t pgoff = linear_page_index(vma,
1699 khugepaged_scan.address); 1699 khugepaged_scan.address);
1700 if (!shmem_huge_enabled(vma))
1701 goto skip;
1702 file = get_file(vma->vm_file);
1700 up_read(&mm->mmap_sem); 1703 up_read(&mm->mmap_sem);
1701 ret = 1; 1704 ret = 1;
1702 khugepaged_scan_shmem(mm, file->f_mapping, 1705 khugepaged_scan_shmem(mm, file->f_mapping,
diff --git a/mm/memory.c b/mm/memory.c
index 712790e95f08..4425b6059339 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -2920,7 +2920,7 @@ map_pte:
2920 return 0; 2920 return 0;
2921} 2921}
2922 2922
2923#ifdef CONFIG_TRANSPARENT_HUGEPAGE 2923#ifdef CONFIG_TRANSPARENT_HUGE_PAGECACHE
2924 2924
2925#define HPAGE_CACHE_INDEX_MASK (HPAGE_PMD_NR - 1) 2925#define HPAGE_CACHE_INDEX_MASK (HPAGE_PMD_NR - 1)
2926static inline bool transhuge_vma_suitable(struct vm_area_struct *vma, 2926static inline bool transhuge_vma_suitable(struct vm_area_struct *vma,
@@ -3002,7 +3002,8 @@ int alloc_set_pte(struct fault_env *fe, struct mem_cgroup *memcg,
3002 pte_t entry; 3002 pte_t entry;
3003 int ret; 3003 int ret;
3004 3004
3005 if (pmd_none(*fe->pmd) && PageTransCompound(page)) { 3005 if (pmd_none(*fe->pmd) && PageTransCompound(page) &&
3006 IS_ENABLED(CONFIG_TRANSPARENT_HUGE_PAGECACHE)) {
3006 /* THP on COW? */ 3007 /* THP on COW? */
3007 VM_BUG_ON_PAGE(memcg, page); 3008 VM_BUG_ON_PAGE(memcg, page);
3008 3009
diff --git a/mm/shmem.c b/mm/shmem.c
index 905c0e1cf5af..25f55a3a93b3 100644
--- a/mm/shmem.c
+++ b/mm/shmem.c
@@ -363,7 +363,7 @@ static bool shmem_confirm_swap(struct address_space *mapping,
363#define SHMEM_HUGE_DENY (-1) 363#define SHMEM_HUGE_DENY (-1)
364#define SHMEM_HUGE_FORCE (-2) 364#define SHMEM_HUGE_FORCE (-2)
365 365
366#ifdef CONFIG_TRANSPARENT_HUGEPAGE 366#ifdef CONFIG_TRANSPARENT_HUGE_PAGECACHE
367/* ifdef here to avoid bloating shmem.o when not necessary */ 367/* ifdef here to avoid bloating shmem.o when not necessary */
368 368
369int shmem_huge __read_mostly; 369int shmem_huge __read_mostly;
@@ -406,11 +406,11 @@ static const char *shmem_format_huge(int huge)
406 } 406 }
407} 407}
408 408
409#else /* !CONFIG_TRANSPARENT_HUGEPAGE */ 409#else /* !CONFIG_TRANSPARENT_HUGE_PAGECACHE */
410 410
411#define shmem_huge SHMEM_HUGE_DENY 411#define shmem_huge SHMEM_HUGE_DENY
412 412
413#endif /* CONFIG_TRANSPARENT_HUGEPAGE */ 413#endif /* CONFIG_TRANSPARENT_HUGE_PAGECACHE */
414 414
415/* 415/*
416 * Like add_to_page_cache_locked, but error if expected item has gone. 416 * Like add_to_page_cache_locked, but error if expected item has gone.
@@ -1229,7 +1229,7 @@ static struct page *shmem_alloc_hugepage(gfp_t gfp,
1229 void __rcu **results; 1229 void __rcu **results;
1230 struct page *page; 1230 struct page *page;
1231 1231
1232 if (!IS_ENABLED(CONFIG_TRANSPARENT_HUGEPAGE)) 1232 if (!IS_ENABLED(CONFIG_TRANSPARENT_HUGE_PAGECACHE))
1233 return NULL; 1233 return NULL;
1234 1234
1235 rcu_read_lock(); 1235 rcu_read_lock();
@@ -1270,7 +1270,7 @@ static struct page *shmem_alloc_and_acct_page(gfp_t gfp,
1270 int nr; 1270 int nr;
1271 int err = -ENOSPC; 1271 int err = -ENOSPC;
1272 1272
1273 if (!IS_ENABLED(CONFIG_TRANSPARENT_HUGEPAGE)) 1273 if (!IS_ENABLED(CONFIG_TRANSPARENT_HUGE_PAGECACHE))
1274 huge = false; 1274 huge = false;
1275 nr = huge ? HPAGE_PMD_NR : 1; 1275 nr = huge ? HPAGE_PMD_NR : 1;
1276 1276
@@ -1773,7 +1773,7 @@ unsigned long shmem_get_unmapped_area(struct file *file,
1773 get_area = current->mm->get_unmapped_area; 1773 get_area = current->mm->get_unmapped_area;
1774 addr = get_area(file, uaddr, len, pgoff, flags); 1774 addr = get_area(file, uaddr, len, pgoff, flags);
1775 1775
1776 if (!IS_ENABLED(CONFIG_TRANSPARENT_HUGEPAGE)) 1776 if (!IS_ENABLED(CONFIG_TRANSPARENT_HUGE_PAGECACHE))
1777 return addr; 1777 return addr;
1778 if (IS_ERR_VALUE(addr)) 1778 if (IS_ERR_VALUE(addr))
1779 return addr; 1779 return addr;
@@ -1890,7 +1890,7 @@ static int shmem_mmap(struct file *file, struct vm_area_struct *vma)
1890{ 1890{
1891 file_accessed(file); 1891 file_accessed(file);
1892 vma->vm_ops = &shmem_vm_ops; 1892 vma->vm_ops = &shmem_vm_ops;
1893 if (IS_ENABLED(CONFIG_TRANSPARENT_HUGEPAGE) && 1893 if (IS_ENABLED(CONFIG_TRANSPARENT_HUGE_PAGECACHE) &&
1894 ((vma->vm_start + ~HPAGE_PMD_MASK) & HPAGE_PMD_MASK) < 1894 ((vma->vm_start + ~HPAGE_PMD_MASK) & HPAGE_PMD_MASK) <
1895 (vma->vm_end & HPAGE_PMD_MASK)) { 1895 (vma->vm_end & HPAGE_PMD_MASK)) {
1896 khugepaged_enter(vma, vma->vm_flags); 1896 khugepaged_enter(vma, vma->vm_flags);
@@ -3287,7 +3287,7 @@ static int shmem_parse_options(char *options, struct shmem_sb_info *sbinfo,
3287 sbinfo->gid = make_kgid(current_user_ns(), gid); 3287 sbinfo->gid = make_kgid(current_user_ns(), gid);
3288 if (!gid_valid(sbinfo->gid)) 3288 if (!gid_valid(sbinfo->gid))
3289 goto bad_val; 3289 goto bad_val;
3290#ifdef CONFIG_TRANSPARENT_HUGEPAGE 3290#ifdef CONFIG_TRANSPARENT_HUGE_PAGECACHE
3291 } else if (!strcmp(this_char, "huge")) { 3291 } else if (!strcmp(this_char, "huge")) {
3292 int huge; 3292 int huge;
3293 huge = shmem_parse_huge(value); 3293 huge = shmem_parse_huge(value);
@@ -3384,7 +3384,7 @@ static int shmem_show_options(struct seq_file *seq, struct dentry *root)
3384 if (!gid_eq(sbinfo->gid, GLOBAL_ROOT_GID)) 3384 if (!gid_eq(sbinfo->gid, GLOBAL_ROOT_GID))
3385 seq_printf(seq, ",gid=%u", 3385 seq_printf(seq, ",gid=%u",
3386 from_kgid_munged(&init_user_ns, sbinfo->gid)); 3386 from_kgid_munged(&init_user_ns, sbinfo->gid));
3387#ifdef CONFIG_TRANSPARENT_HUGEPAGE 3387#ifdef CONFIG_TRANSPARENT_HUGE_PAGECACHE
3388 /* Rightly or wrongly, show huge mount option unmasked by shmem_huge */ 3388 /* Rightly or wrongly, show huge mount option unmasked by shmem_huge */
3389 if (sbinfo->huge) 3389 if (sbinfo->huge)
3390 seq_printf(seq, ",huge=%s", shmem_format_huge(sbinfo->huge)); 3390 seq_printf(seq, ",huge=%s", shmem_format_huge(sbinfo->huge));
@@ -3730,7 +3730,7 @@ int __init shmem_init(void)
3730 goto out1; 3730 goto out1;
3731 } 3731 }
3732 3732
3733#ifdef CONFIG_TRANSPARENT_HUGEPAGE 3733#ifdef CONFIG_TRANSPARENT_HUGE_PAGECACHE
3734 if (has_transparent_hugepage() && shmem_huge < SHMEM_HUGE_DENY) 3734 if (has_transparent_hugepage() && shmem_huge < SHMEM_HUGE_DENY)
3735 SHMEM_SB(shm_mnt->mnt_sb)->huge = shmem_huge; 3735 SHMEM_SB(shm_mnt->mnt_sb)->huge = shmem_huge;
3736 else 3736 else
@@ -3747,7 +3747,7 @@ out3:
3747 return error; 3747 return error;
3748} 3748}
3749 3749
3750#if defined(CONFIG_TRANSPARENT_HUGEPAGE) && defined(CONFIG_SYSFS) 3750#if defined(CONFIG_TRANSPARENT_HUGE_PAGECACHE) && defined(CONFIG_SYSFS)
3751static ssize_t shmem_enabled_show(struct kobject *kobj, 3751static ssize_t shmem_enabled_show(struct kobject *kobj,
3752 struct kobj_attribute *attr, char *buf) 3752 struct kobj_attribute *attr, char *buf)
3753{ 3753{
@@ -3830,7 +3830,7 @@ bool shmem_huge_enabled(struct vm_area_struct *vma)
3830 return false; 3830 return false;
3831 } 3831 }
3832} 3832}
3833#endif /* CONFIG_TRANSPARENT_HUGEPAGE && CONFIG_SYSFS */ 3833#endif /* CONFIG_TRANSPARENT_HUGE_PAGECACHE && CONFIG_SYSFS */
3834 3834
3835#else /* !CONFIG_SHMEM */ 3835#else /* !CONFIG_SHMEM */
3836 3836
@@ -4010,7 +4010,7 @@ int shmem_zero_setup(struct vm_area_struct *vma)
4010 vma->vm_file = file; 4010 vma->vm_file = file;
4011 vma->vm_ops = &shmem_vm_ops; 4011 vma->vm_ops = &shmem_vm_ops;
4012 4012
4013 if (IS_ENABLED(CONFIG_TRANSPARENT_HUGEPAGE) && 4013 if (IS_ENABLED(CONFIG_TRANSPARENT_HUGE_PAGECACHE) &&
4014 ((vma->vm_start + ~HPAGE_PMD_MASK) & HPAGE_PMD_MASK) < 4014 ((vma->vm_start + ~HPAGE_PMD_MASK) & HPAGE_PMD_MASK) <
4015 (vma->vm_end & HPAGE_PMD_MASK)) { 4015 (vma->vm_end & HPAGE_PMD_MASK)) {
4016 khugepaged_enter(vma, vma->vm_flags); 4016 khugepaged_enter(vma, vma->vm_flags);