aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorGerald Schaefer <gerald.schaefer@de.ibm.com>2012-10-08 19:30:15 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2012-10-09 03:22:30 -0400
commit75077afbec1ac89178c1542b23a70d0f960b0aaf (patch)
tree843b8a7175de7a9a2dca37d877cd742121f4b627 /arch
parent8e72033f2a489b6c98c4e3c7cc281b1afd6cb85c (diff)
thp, s390: thp splitting backend for s390
This patch is part of the architecture backend for thp on s390. It provides the functions related to thp splitting, including serialization against gup. Unlike other archs, pmdp_splitting_flush() cannot use a tlb flushing operation to serialize against gup on s390, because that wouldn't be stopped by the disabled IRQs. So instead, smp_call_function() is called with an empty function, which will have the expected effect. Signed-off-by: Gerald Schaefer <gerald.schaefer@de.ibm.com> Cc: Andrea Arcangeli <aarcange@redhat.com> Cc: Andi Kleen <ak@linux.intel.com> Cc: Hugh Dickins <hughd@google.com> Cc: Hillf Danton <dhillf@gmail.com> Cc: Martin Schwidefsky <schwidefsky@de.ibm.com> Cc: Heiko Carstens <heiko.carstens@de.ibm.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'arch')
-rw-r--r--arch/s390/include/asm/pgtable.h13
-rw-r--r--arch/s390/mm/gup.c11
-rw-r--r--arch/s390/mm/pgtable.c18
3 files changed, 41 insertions, 1 deletions
diff --git a/arch/s390/include/asm/pgtable.h b/arch/s390/include/asm/pgtable.h
index 6bd7d7483017..c3f0775e71f1 100644
--- a/arch/s390/include/asm/pgtable.h
+++ b/arch/s390/include/asm/pgtable.h
@@ -347,6 +347,8 @@ extern struct page *vmemmap;
347 347
348#define _SEGMENT_ENTRY_LARGE 0x400 /* STE-format control, large page */ 348#define _SEGMENT_ENTRY_LARGE 0x400 /* STE-format control, large page */
349#define _SEGMENT_ENTRY_CO 0x100 /* change-recording override */ 349#define _SEGMENT_ENTRY_CO 0x100 /* change-recording override */
350#define _SEGMENT_ENTRY_SPLIT_BIT 0 /* THP splitting bit number */
351#define _SEGMENT_ENTRY_SPLIT (1UL << _SEGMENT_ENTRY_SPLIT_BIT)
350 352
351/* Page status table bits for virtualization */ 353/* Page status table bits for virtualization */
352#define RCP_ACC_BITS 0xf000000000000000UL 354#define RCP_ACC_BITS 0xf000000000000000UL
@@ -506,6 +508,10 @@ static inline int pmd_bad(pmd_t pmd)
506 return (pmd_val(pmd) & mask) != _SEGMENT_ENTRY; 508 return (pmd_val(pmd) & mask) != _SEGMENT_ENTRY;
507} 509}
508 510
511#define __HAVE_ARCH_PMDP_SPLITTING_FLUSH
512extern void pmdp_splitting_flush(struct vm_area_struct *vma,
513 unsigned long addr, pmd_t *pmdp);
514
509static inline int pte_none(pte_t pte) 515static inline int pte_none(pte_t pte)
510{ 516{
511 return (pte_val(pte) & _PAGE_INVALID) && !(pte_val(pte) & _PAGE_SWT); 517 return (pte_val(pte) & _PAGE_INVALID) && !(pte_val(pte) & _PAGE_SWT);
@@ -1159,6 +1165,13 @@ static inline pmd_t *pmd_offset(pud_t *pud, unsigned long address)
1159#define pte_offset_map(pmd, address) pte_offset_kernel(pmd, address) 1165#define pte_offset_map(pmd, address) pte_offset_kernel(pmd, address)
1160#define pte_unmap(pte) do { } while (0) 1166#define pte_unmap(pte) do { } while (0)
1161 1167
1168#ifdef CONFIG_TRANSPARENT_HUGEPAGE
1169static inline int pmd_trans_splitting(pmd_t pmd)
1170{
1171 return pmd_val(pmd) & _SEGMENT_ENTRY_SPLIT;
1172}
1173#endif /* CONFIG_TRANSPARENT_HUGEPAGE */
1174
1162/* 1175/*
1163 * 31 bit swap entry format: 1176 * 31 bit swap entry format:
1164 * A page-table entry has some bits we have to treat in a special way. 1177 * A page-table entry has some bits we have to treat in a special way.
diff --git a/arch/s390/mm/gup.c b/arch/s390/mm/gup.c
index eeaf8023851f..60acb93a4680 100644
--- a/arch/s390/mm/gup.c
+++ b/arch/s390/mm/gup.c
@@ -115,7 +115,16 @@ static inline int gup_pmd_range(pud_t *pudp, pud_t pud, unsigned long addr,
115 pmd = *pmdp; 115 pmd = *pmdp;
116 barrier(); 116 barrier();
117 next = pmd_addr_end(addr, end); 117 next = pmd_addr_end(addr, end);
118 if (pmd_none(pmd)) 118 /*
119 * The pmd_trans_splitting() check below explains why
120 * pmdp_splitting_flush() has to serialize with
121 * smp_call_function() against our disabled IRQs, to stop
122 * this gup-fast code from running while we set the
123 * splitting bit in the pmd. Returning zero will take
124 * the slow path that will call wait_split_huge_page()
125 * if the pmd is still in splitting state.
126 */
127 if (pmd_none(pmd) || pmd_trans_splitting(pmd))
119 return 0; 128 return 0;
120 if (unlikely(pmd_huge(pmd))) { 129 if (unlikely(pmd_huge(pmd))) {
121 if (!gup_huge_pmd(pmdp, pmd, addr, next, 130 if (!gup_huge_pmd(pmdp, pmd, addr, next,
diff --git a/arch/s390/mm/pgtable.c b/arch/s390/mm/pgtable.c
index b402991e43d7..a6131d1fe6c0 100644
--- a/arch/s390/mm/pgtable.c
+++ b/arch/s390/mm/pgtable.c
@@ -866,3 +866,21 @@ bool kernel_page_present(struct page *page)
866 return cc == 0; 866 return cc == 0;
867} 867}
868#endif /* CONFIG_HIBERNATION && CONFIG_DEBUG_PAGEALLOC */ 868#endif /* CONFIG_HIBERNATION && CONFIG_DEBUG_PAGEALLOC */
869
870#ifdef CONFIG_TRANSPARENT_HUGEPAGE
871static void pmdp_splitting_flush_sync(void *arg)
872{
873 /* Simply deliver the interrupt */
874}
875
876void pmdp_splitting_flush(struct vm_area_struct *vma, unsigned long address,
877 pmd_t *pmdp)
878{
879 VM_BUG_ON(address & ~HPAGE_PMD_MASK);
880 if (!test_and_set_bit(_SEGMENT_ENTRY_SPLIT_BIT,
881 (unsigned long *) pmdp)) {
882 /* need to serialize against gup-fast (IRQ disabled) */
883 smp_call_function(pmdp_splitting_flush_sync, NULL, 1);
884 }
885}
886#endif /* CONFIG_TRANSPARENT_HUGEPAGE */