aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
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 */