mm/thp: split out pmd collapse flush into separate functions
authorAneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
Wed, 24 Jun 2015 23:57:39 +0000 (16:57 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Thu, 25 Jun 2015 00:49:44 +0000 (17:49 -0700)
Architectures like ppc64 [1] need to do special things while clearing pmd
before a collapse.  For them this operation is largely different from a
normal hugepage pte clear.  Hence add a separate function to clear pmd
before collapse.  After this patch pmdp_* functions operate only on
hugepage pte, and not on regular pmd_t values pointing to page table.

[1] ppc64 needs to invalidate all the normal page pte mappings we already
have inserted in the hardware hash page table.  But before doing that we
need to make sure there are no parallel hash page table insert going on.
So we need to do a kick_all_cpus_sync() before flushing the older hash
table entries.  By moving this to a separate function we capture these
details and mention how it is different from a hugepage pte clear.

This patch is a cleanup and only does code movement for clarity.  There
should not be any change in functionality.

Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
Acked-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Michael Ellerman <mpe@ellerman.id.au>
Cc: Andrea Arcangeli <aarcange@redhat.com>
Cc: Martin Schwidefsky <schwidefsky@de.ibm.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
arch/powerpc/include/asm/pgtable-ppc64.h
arch/powerpc/mm/pgtable_64.c
include/asm-generic/pgtable.h
mm/huge_memory.c

index f890f7ce159323d8a3f35fca2f95a594ed0fa9e9..5f3a337842591d252e834f0273d9764897091177 100644 (file)
@@ -592,6 +592,10 @@ static inline void pmdp_set_wrprotect(struct mm_struct *mm, unsigned long addr,
 extern void pmdp_splitting_flush(struct vm_area_struct *vma,
                                 unsigned long address, pmd_t *pmdp);
 
+extern pmd_t pmdp_collapse_flush(struct vm_area_struct *vma,
+                                unsigned long address, pmd_t *pmdp);
+#define pmdp_collapse_flush pmdp_collapse_flush
+
 #define __HAVE_ARCH_PGTABLE_DEPOSIT
 extern void pgtable_trans_huge_deposit(struct mm_struct *mm, pmd_t *pmdp,
                                       pgtable_t pgtable);
index 6bfadf1aa5cbbfadbd7237e5f3da8ac8653a5651..049d961802aaf294dfb3185a70804f4ab2f25914 100644 (file)
@@ -560,41 +560,47 @@ pmd_t pmdp_clear_flush(struct vm_area_struct *vma, unsigned long address,
        pmd_t pmd;
 
        VM_BUG_ON(address & ~HPAGE_PMD_MASK);
-       if (pmd_trans_huge(*pmdp)) {
-               pmd = pmdp_get_and_clear(vma->vm_mm, address, pmdp);
-       } else {
-               /*
-                * khugepaged calls this for normal pmd
-                */
-               pmd = *pmdp;
-               pmd_clear(pmdp);
-               /*
-                * Wait for all pending hash_page to finish. This is needed
-                * in case of subpage collapse. When we collapse normal pages
-                * to hugepage, we first clear the pmd, then invalidate all
-                * the PTE entries. The assumption here is that any low level
-                * page fault will see a none pmd and take the slow path that
-                * will wait on mmap_sem. But we could very well be in a
-                * hash_page with local ptep pointer value. Such a hash page
-                * can result in adding new HPTE entries for normal subpages.
-                * That means we could be modifying the page content as we
-                * copy them to a huge page. So wait for parallel hash_page
-                * to finish before invalidating HPTE entries. We can do this
-                * by sending an IPI to all the cpus and executing a dummy
-                * function there.
-                */
-               kick_all_cpus_sync();
-               /*
-                * Now invalidate the hpte entries in the range
-                * covered by pmd. This make sure we take a
-                * fault and will find the pmd as none, which will
-                * result in a major fault which takes mmap_sem and
-                * hence wait for collapse to complete. Without this
-                * the __collapse_huge_page_copy can result in copying
-                * the old content.
-                */
-               flush_tlb_pmd_range(vma->vm_mm, &pmd, address);
-       }
+       VM_BUG_ON(!pmd_trans_huge(*pmdp));
+       pmd = pmdp_get_and_clear(vma->vm_mm, address, pmdp);
+       return pmd;
+}
+
+pmd_t pmdp_collapse_flush(struct vm_area_struct *vma, unsigned long address,
+                         pmd_t *pmdp)
+{
+       pmd_t pmd;
+
+       VM_BUG_ON(address & ~HPAGE_PMD_MASK);
+       VM_BUG_ON(pmd_trans_huge(*pmdp));
+
+       pmd = *pmdp;
+       pmd_clear(pmdp);
+       /*
+        * Wait for all pending hash_page to finish. This is needed
+        * in case of subpage collapse. When we collapse normal pages
+        * to hugepage, we first clear the pmd, then invalidate all
+        * the PTE entries. The assumption here is that any low level
+        * page fault will see a none pmd and take the slow path that
+        * will wait on mmap_sem. But we could very well be in a
+        * hash_page with local ptep pointer value. Such a hash page
+        * can result in adding new HPTE entries for normal subpages.
+        * That means we could be modifying the page content as we
+        * copy them to a huge page. So wait for parallel hash_page
+        * to finish before invalidating HPTE entries. We can do this
+        * by sending an IPI to all the cpus and executing a dummy
+        * function there.
+        */
+       kick_all_cpus_sync();
+       /*
+        * Now invalidate the hpte entries in the range
+        * covered by pmd. This make sure we take a
+        * fault and will find the pmd as none, which will
+        * result in a major fault which takes mmap_sem and
+        * hence wait for collapse to complete. Without this
+        * the __collapse_huge_page_copy can result in copying
+        * the old content.
+        */
+       flush_tlb_pmd_range(vma->vm_mm, &pmd, address);
        return pmd;
 }
 
index bd910ceaccfa2d5b66da77b1b5becc760c50a615..d2c2171d1c3266313088c41cd57317c25c1572e4 100644 (file)
@@ -189,6 +189,27 @@ extern void pmdp_splitting_flush(struct vm_area_struct *vma,
                                 unsigned long address, pmd_t *pmdp);
 #endif
 
+#ifndef pmdp_collapse_flush
+#ifdef CONFIG_TRANSPARENT_HUGEPAGE
+static inline pmd_t pmdp_collapse_flush(struct vm_area_struct *vma,
+                                       unsigned long address,
+                                       pmd_t *pmdp)
+{
+       return pmdp_clear_flush(vma, address, pmdp);
+}
+#define pmdp_collapse_flush pmdp_collapse_flush
+#else
+static inline pmd_t pmdp_collapse_flush(struct vm_area_struct *vma,
+                                       unsigned long address,
+                                       pmd_t *pmdp)
+{
+       BUILD_BUG();
+       return *pmdp;
+}
+#define pmdp_collapse_flush pmdp_collapse_flush
+#endif /* CONFIG_TRANSPARENT_HUGEPAGE */
+#endif
+
 #ifndef __HAVE_ARCH_PGTABLE_DEPOSIT
 extern void pgtable_trans_huge_deposit(struct mm_struct *mm, pmd_t *pmdp,
                                       pgtable_t pgtable);
index b3d8cd8d6968e752676598ade11cb996fc84d48e..65dd8d67287bb38df5a86682924aa5a30d3a30f4 100644 (file)
@@ -2499,7 +2499,7 @@ static void collapse_huge_page(struct mm_struct *mm,
         * huge and small TLB entries for the same virtual address
         * to avoid the risk of CPU bugs in that area.
         */
-       _pmd = pmdp_clear_flush(vma, address, pmd);
+       _pmd = pmdp_collapse_flush(vma, address, pmd);
        spin_unlock(pmd_ptl);
        mmu_notifier_invalidate_range_end(mm, mmun_start, mmun_end);