x86/mm: Straightforward TLB flush fixes/cleanups
Andy Lutomirski
maintainerPATCH v2 3/3 x86/mm: Fix flush_tlb_page() on Xen
In reply to Andy Lutomirskiflush_tlb_page() passes a bogus range to flush_tlb_others() and expects the latter to fix it up. native_flush_tlb_others() has the fixup but Xen's version doesn't. Move the fixup to flush_tlb_others().
AFAICS the only real effect is that, without this fix, Xen would flush everything instead of just the one page on remote vCPUs in when flush_tlb_page() was called.
--- arch/x86/mm/tlb.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-)
arch/x86/mm/tlb.c +1 -3
@@ -263,8 +263,6 @@ void native_flush_tlb_others(const struct cpumask *cpumask, {struct flush_tlb_info info; -if (end ==0 ) - end = start +PAGE_SIZE ; info.flush_mm = mm; info.flush_start = start; info.flush_end = end;
@@ -378,7 +376,7 @@ void flush_tlb_page(struct vm_area_struct *vma, unsigned long start) }if (cpumask_any_but (mm_cpumask (mm),smp_processor_id ()) < nr_cpu_ids) -flush_tlb_others (mm_cpumask (mm), mm, start,0UL ); +flush_tlb_others (mm_cpumask (mm), mm, start, start +PAGE_SIZE );preempt_enable (); }
Signature · 1 line
2.9.3
Andy Lutomirski
maintainerPATCH v2 2/3 x86/mm: Make flush_tlb_mm_range() more predictable
In reply to Andy LutomirskiI'm about to rewrite the function almost completely, but first I want to get a functional change out of the way. Currently, if flush_tlb_mm_range() does not flush the local TLB at all, it will never do individual page flushes on remote CPUs. This seems to be an accident, and preserving it will be awkward. Let's change it first so that any regressions in the rewrite will be easier to bisect and so that the rewrite can attempt to change no visible behavior at all.
The fix is simple: we can simply avoid short-circuiting the calculation of base_pages_to_flush.
As a side effect, this also eliminates a potential corner case: if tlb_single_page_flush_ceiling == TLB_FLUSH_ALL, flush_tlb_mm_range() could have ended up flushing the entire address space one page at a time.
--- arch/x86/mm/tlb.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-)
arch/x86/mm/tlb.c +7 -5
@@ -309,6 +309,12 @@ void flush_tlb_mm_range(struct mm_struct *mm, unsigned long start,unsigned long base_pages_to_flush =TLB_FLUSH_ALL ;preempt_disable (); + +if ((end !=TLB_FLUSH_ALL ) && !(vmflag &VM_HUGETLB )) + base_pages_to_flush = (end - start) >>PAGE_SHIFT ; +if (base_pages_to_flush > tlb_single_page_flush_ceiling) + base_pages_to_flush =TLB_FLUSH_ALL ; +if (current->active_mm != mm) {/* Synchronize with switch_mm. */ smp_mb ();
@@ -325,15 +331,11 @@ void flush_tlb_mm_range(struct mm_struct *mm, unsigned long start, goto out; } -if ((end !=TLB_FLUSH_ALL ) && !(vmflag &VM_HUGETLB )) - base_pages_to_flush = (end - start) >>PAGE_SHIFT ; -/* * Both branches below are implicit full barriers (MOV to CR or * INVLPG) that synchronize with switch_mm. */ -if (base_pages_to_flush > tlb_single_page_flush_ceiling) { - base_pages_to_flush =TLB_FLUSH_ALL ; +if (base_pages_to_flush ==TLB_FLUSH_ALL ) {count_vm_tlb_event (NR_TLB_LOCAL_FLUSH_ALL );local_flush_tlb (); }else {
Signature · 1 line
2.9.3
Andy Lutomirski
maintainerv2 cover x86/mm: Straightforward TLB flush fixes/cleanups
I have some less straightforward cleanups coming, but these three are easy and might even be okay for 4.12 assuming that someone feels like reviewing them.
Changes from v1:
- Fixed the Cc list on patch 3. No code changes at all.
Andy Lutomirski (3):
x86/mm: Remove flush_tlb() and flush_tlb_current_task() x86/mm: Make flush_tlb_mm_range() more predictable x86/mm: Fix flush_tlb_page() on Xen
arch/x86/include/asm/tlbflush.h | 3 --- arch/x86/mm/tlb.c | 33 ++++++++------------------------- 2 files changed, 8 insertions(+), 28 deletions(-)
Signature · 1 line
2.9.3
Andy Lutomirski
maintainerPATCH v2 1/3 x86/mm: Remove flush_tlb() and flush_tlb_current_task()
I was trying to figure out what how flush_tlb_current_task() would possibly work correctly if current->mm != current->active_mm, but I realized I could spare myself the effort: it has no callers except the unused flush_tlb() macro. In fact, it doesn't even exist on !SMP builds.
--- arch/x86/include/asm/tlbflush.h | 3 --- arch/x86/mm/tlb.c | 17 ----------------- 2 files changed, 20 deletions(-)
arch/x86/include/asm/tlbflush.h +0 -3
@@ -303,14 +303,11 @@ static inline void flush_tlb_kernel_range(unsigned long start, flush_tlb_mm_range(vma->vm_mm, start, end, vma->vm_flags)extern void flush_tlb_all (void ); -extern void flush_tlb_current_task (void );extern void flush_tlb_page (struct vm_area_struct *,unsigned long );extern void flush_tlb_mm_range (struct mm_struct *mm,unsigned long start,unsigned long end,unsigned long vmflag);extern void flush_tlb_kernel_range (unsigned long start,unsigned long end); -#define flush_tlb () flush_tlb_current_task() -void native_flush_tlb_others (const struct cpumask *cpumask,struct mm_struct *mm,unsigned long start,unsigned long end);
arch/x86/mm/tlb.c +0 -17
@@ -289,23 +289,6 @@ void native_flush_tlb_others(const struct cpumask *cpumask,smp_call_function_many (cpumask, flush_tlb_func, &info,1 ); } -void flush_tlb_current_task (void ) -{ -struct mm_struct *mm = current->mm; - -preempt_disable (); - -count_vm_tlb_event (NR_TLB_LOCAL_FLUSH_ALL ); - -/* This is an implicit full barrier that synchronizes with switch_mm. */ -local_flush_tlb (); - -trace_tlb_flush (TLB_LOCAL_SHOOTDOWN ,TLB_FLUSH_ALL ); -if (cpumask_any_but (mm_cpumask (mm),smp_processor_id ()) < nr_cpu_ids) -flush_tlb_others (mm_cpumask (mm), mm,0UL ,TLB_FLUSH_ALL ); -preempt_enable (); -} -/* * See Documentation/x86/tlb.txt for details. We choose 33 * because it is large enough to cover the vast majority (at
Signature · 1 line
2.9.3
Re: [PATCH v2 3/3] x86/mm: Fix flush_tlb_page() on Xen
In reply to Andy LutomirskiQuoted 20 lines · Andy Lutomirski
flush_tlb_page()passes a bogus range toflush_tlb_others()and expects the latter to fix it up.native_flush_tlb_others()has the fixup but Xen's version doesn't. Move the fixup toflush_tlb_others().AFAICS the only real effect is that, without this fix, Xen would flush everything instead of just the one page on remote vCPUs in when
flush_tlb_page()was called.Cc Rik van Riel <[email protected]>Cc Dave Hansen <[email protected]>Cc Nadav Amit <[email protected]>Cc Michal Hocko <[email protected]>Cc Sasha Levin <[email protected]>Cc Andrew Morton <[email protected]>Cc Boris Ostrovsky <[email protected]>Cc Juergen Gross <[email protected]>Cc Konrad Rzeszutek Wilk <[email protected]>Fixes e7b52ffd45a6 ("x86/flush_tlb: try flush_tlb_single one by one in flush_tlb_range")Signed-off-by Andy Lutomirski <[email protected]>
Quoted 3 lines
--- arch/x86/mm/tlb.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-)
Thanks, Andy.
Re: [PATCH v2 2/3] x86/mm: Make flush_tlb_mm_range() more predictable
In reply to Andy LutomirskiQuoted 11 lines · Andy Lutomirski
I'm about to rewrite the function almost completely, but first I want to get a functional change out of the way. Currently, if
flush_tlb_mm_range()does not flush the local TLB at all, it will never do individual page flushes on remote CPUs. This seems to be an accident, and preserving it will be awkward. Let's change it first so that any regressions in the rewrite will be easier to bisect and so that the rewrite can attempt to change no visible behavior at all.The fix is simple: we can simply avoid short-circuiting the calculation of
base_pages_to_flush.
This looks sane to me. I think it makes things more straightforward.
Re: [PATCH v2 1/3] x86/mm: Remove flush_tlb() and flush_tlb_current_task()
In reply to Andy LutomirskiQuoted 5 lines · Andy Lutomirski
I was trying to figure out what how
flush_tlb_current_task()would possibly work correctly ifcurrent->mm!=current->active_mm, but I realized I could spare myself the effort: it has no callers except the unusedflush_tlb()macro. In fact, it doesn't even exist on !SMP builds.
Please disregard this patch for now. It has issues.
---Andy