diff options
author | Vineet Gupta <vgupta@synopsys.com> | 2015-02-20 00:06:28 -0500 |
---|---|---|
committer | Vineet Gupta <vgupta@synopsys.com> | 2015-10-17 08:18:20 -0400 |
commit | 12ebc1581ad114543ae822aa3a12f76072e2f902 (patch) | |
tree | 2e80b72284497b1a45f29f0970ce13332f6896e2 /mm/pgtable-generic.c | |
parent | bd5e88ad72b26ebf7ecb231bc22ceecd6cbdb951 (diff) |
mm,thp: introduce flush_pmd_tlb_range
ARCHes with special requirements for evicting THP backing TLB entries
can implement this.
Otherwise also, it can help optimize TLB flush in THP regime.
stock flush_tlb_range() typically has optimization to nuke the entire
TLB if flush span is greater than a certain threshhold, which will
likely be true for a single huge page. Thus a single thp flush will
invalidate the entrire TLB which is not desirable.
e.g. see arch/arc: flush_pmd_tlb_range
Acked-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>
Link: http://lkml.kernel.org/r/20151009100816.GC7873@node
Signed-off-by: Vineet Gupta <vgupta@synopsys.com>
Diffstat (limited to 'mm/pgtable-generic.c')
-rw-r--r-- | mm/pgtable-generic.c | 26 |
1 files changed, 20 insertions, 6 deletions
diff --git a/mm/pgtable-generic.c b/mm/pgtable-generic.c index c9c59bb75a17..7d3db0247983 100644 --- a/mm/pgtable-generic.c +++ b/mm/pgtable-generic.c | |||
@@ -84,6 +84,20 @@ pte_t ptep_clear_flush(struct vm_area_struct *vma, unsigned long address, | |||
84 | 84 | ||
85 | #ifdef CONFIG_TRANSPARENT_HUGEPAGE | 85 | #ifdef CONFIG_TRANSPARENT_HUGEPAGE |
86 | 86 | ||
87 | #ifndef __HAVE_ARCH_FLUSH_PMD_TLB_RANGE | ||
88 | |||
89 | /* | ||
90 | * ARCHes with special requirements for evicting THP backing TLB entries can | ||
91 | * implement this. Otherwise also, it can help optimize normal TLB flush in | ||
92 | * THP regime. stock flush_tlb_range() typically has optimization to nuke the | ||
93 | * entire TLB TLB if flush span is greater than a threshhold, which will | ||
94 | * likely be true for a single huge page. Thus a single thp flush will | ||
95 | * invalidate the entire TLB which is not desitable. | ||
96 | * e.g. see arch/arc: flush_pmd_tlb_range | ||
97 | */ | ||
98 | #define flush_pmd_tlb_range(vma, addr, end) flush_tlb_range(vma, addr, end) | ||
99 | #endif | ||
100 | |||
87 | #ifndef __HAVE_ARCH_PMDP_SET_ACCESS_FLAGS | 101 | #ifndef __HAVE_ARCH_PMDP_SET_ACCESS_FLAGS |
88 | int pmdp_set_access_flags(struct vm_area_struct *vma, | 102 | int pmdp_set_access_flags(struct vm_area_struct *vma, |
89 | unsigned long address, pmd_t *pmdp, | 103 | unsigned long address, pmd_t *pmdp, |
@@ -93,7 +107,7 @@ int pmdp_set_access_flags(struct vm_area_struct *vma, | |||
93 | VM_BUG_ON(address & ~HPAGE_PMD_MASK); | 107 | VM_BUG_ON(address & ~HPAGE_PMD_MASK); |
94 | if (changed) { | 108 | if (changed) { |
95 | set_pmd_at(vma->vm_mm, address, pmdp, entry); | 109 | set_pmd_at(vma->vm_mm, address, pmdp, entry); |
96 | flush_tlb_range(vma, address, address + HPAGE_PMD_SIZE); | 110 | flush_pmd_tlb_range(vma, address, address + HPAGE_PMD_SIZE); |
97 | } | 111 | } |
98 | return changed; | 112 | return changed; |
99 | } | 113 | } |
@@ -107,7 +121,7 @@ int pmdp_clear_flush_young(struct vm_area_struct *vma, | |||
107 | VM_BUG_ON(address & ~HPAGE_PMD_MASK); | 121 | VM_BUG_ON(address & ~HPAGE_PMD_MASK); |
108 | young = pmdp_test_and_clear_young(vma, address, pmdp); | 122 | young = pmdp_test_and_clear_young(vma, address, pmdp); |
109 | if (young) | 123 | if (young) |
110 | flush_tlb_range(vma, address, address + HPAGE_PMD_SIZE); | 124 | flush_pmd_tlb_range(vma, address, address + HPAGE_PMD_SIZE); |
111 | return young; | 125 | return young; |
112 | } | 126 | } |
113 | #endif | 127 | #endif |
@@ -120,7 +134,7 @@ pmd_t pmdp_huge_clear_flush(struct vm_area_struct *vma, unsigned long address, | |||
120 | VM_BUG_ON(address & ~HPAGE_PMD_MASK); | 134 | VM_BUG_ON(address & ~HPAGE_PMD_MASK); |
121 | VM_BUG_ON(!pmd_trans_huge(*pmdp)); | 135 | VM_BUG_ON(!pmd_trans_huge(*pmdp)); |
122 | pmd = pmdp_huge_get_and_clear(vma->vm_mm, address, pmdp); | 136 | pmd = pmdp_huge_get_and_clear(vma->vm_mm, address, pmdp); |
123 | flush_tlb_range(vma, address, address + HPAGE_PMD_SIZE); | 137 | flush_pmd_tlb_range(vma, address, address + HPAGE_PMD_SIZE); |
124 | return pmd; | 138 | return pmd; |
125 | } | 139 | } |
126 | #endif | 140 | #endif |
@@ -133,7 +147,7 @@ void pmdp_splitting_flush(struct vm_area_struct *vma, unsigned long address, | |||
133 | VM_BUG_ON(address & ~HPAGE_PMD_MASK); | 147 | VM_BUG_ON(address & ~HPAGE_PMD_MASK); |
134 | set_pmd_at(vma->vm_mm, address, pmdp, pmd); | 148 | set_pmd_at(vma->vm_mm, address, pmdp, pmd); |
135 | /* tlb flush only to serialize against gup-fast */ | 149 | /* tlb flush only to serialize against gup-fast */ |
136 | flush_tlb_range(vma, address, address + HPAGE_PMD_SIZE); | 150 | flush_pmd_tlb_range(vma, address, address + HPAGE_PMD_SIZE); |
137 | } | 151 | } |
138 | #endif | 152 | #endif |
139 | 153 | ||
@@ -179,7 +193,7 @@ void pmdp_invalidate(struct vm_area_struct *vma, unsigned long address, | |||
179 | { | 193 | { |
180 | pmd_t entry = *pmdp; | 194 | pmd_t entry = *pmdp; |
181 | set_pmd_at(vma->vm_mm, address, pmdp, pmd_mknotpresent(entry)); | 195 | set_pmd_at(vma->vm_mm, address, pmdp, pmd_mknotpresent(entry)); |
182 | flush_tlb_range(vma, address, address + HPAGE_PMD_SIZE); | 196 | flush_pmd_tlb_range(vma, address, address + HPAGE_PMD_SIZE); |
183 | } | 197 | } |
184 | #endif | 198 | #endif |
185 | 199 | ||
@@ -196,7 +210,7 @@ pmd_t pmdp_collapse_flush(struct vm_area_struct *vma, unsigned long address, | |||
196 | VM_BUG_ON(address & ~HPAGE_PMD_MASK); | 210 | VM_BUG_ON(address & ~HPAGE_PMD_MASK); |
197 | VM_BUG_ON(pmd_trans_huge(*pmdp)); | 211 | VM_BUG_ON(pmd_trans_huge(*pmdp)); |
198 | pmd = pmdp_huge_get_and_clear(vma->vm_mm, address, pmdp); | 212 | pmd = pmdp_huge_get_and_clear(vma->vm_mm, address, pmdp); |
199 | flush_tlb_range(vma, address, address + HPAGE_PMD_SIZE); | 213 | flush_pmd_tlb_range(vma, address, address + HPAGE_PMD_SIZE); |
200 | return pmd; | 214 | return pmd; |
201 | } | 215 | } |
202 | #endif | 216 | #endif |