TLB and PTE coherency during munmap
Subsystems (7)
Hello arch and mm people.
Is it intentional that threads of a process that invoked munmap syscall can see TLB entries pointing to already freed pages, or it is a bug?
I'm talking about zap_pmd_range and zap_pte_range:
zap_pmd_range
zap_pte_range
arch_enter_lazy_mmu_mode
ptep_get_and_clear_full
tlb_remove_tlb_entry
__tlb_remove_page
arch_leave_lazy_mmu_mode
cond_resched
With the default arch_{enter,leave}_lazy_mmu_mode, tlb_remove_tlb_entry and __tlb_remove_page there is a loop in the zap_pte_range that clears PTEs and frees corresponding pages, but doesn't flush TLB, and surrounding loop in the zap_pmd_range that calls cond_resched. If a thread of the same process gets scheduled then it is able to see TLB entries pointing to already freed physical pages.
I've noticed that with xtensa arch when I added a test before returning to userspace checking that TLB contents agrees with page tables of the current mm. This check reliably fires with the LTP test mtest05 that maps, unmaps and accesses memory from multiple threads.
Is there anything wrong in my description, maybe something specific to my arch, or this issue really exists?
I've also noticed that there are a lot of arches with default implementations of the involved functions, does that mean that any/all of them have this issue too?
Signature · 2 lines
Thanks. -- Max
Hello arch and mm people.
Is it intentional that threads of a process that invoked munmap syscall can see TLB entries pointing to already freed pages, or it is a bug?
I'm talking about zap_pmd_range and zap_pte_range:
zap_pmd_range
zap_pte_range
arch_enter_lazy_mmu_mode
ptep_get_and_clear_full
tlb_remove_tlb_entry
__tlb_remove_page
arch_leave_lazy_mmu_mode
cond_resched
With the default arch_{enter,leave}_lazy_mmu_mode, tlb_remove_tlb_entry and __tlb_remove_page there is a loop in the zap_pte_range that clears PTEs and frees corresponding pages, but doesn't flush TLB, and surrounding loop in the zap_pmd_range that calls cond_resched. If a thread of the same process gets scheduled then it is able to see TLB entries pointing to already freed physical pages.
I've noticed that with xtensa arch when I added a test before returning to userspace checking that TLB contents agrees with page tables of the current mm. This check reliably fires with the LTP test mtest05 that maps, unmaps and accesses memory from multiple threads.
Is there anything wrong in my description, maybe something specific to my arch, or this issue really exists?
I've also noticed that there are a lot of arches with default implementations of the involved functions, does that mean that any/all of them have this issue too?
Signature · 2 lines
Thanks. -- Max
Quoted 23 lines · Max Filippov
Hello arch and mm people.
Is it intentional that threads of a process that invoked munmap syscall can see TLB entries pointing to already freed pages, or it is a bug?
I'm talking about
zap_pmd_rangeandzap_pte_range:
zap_pmd_range
zap_pte_range
arch_enter_lazy_mmu_mode
ptep_get_and_clear_full
tlb_remove_tlb_entry
__tlb_remove_page
arch_leave_lazy_mmu_mode
cond_reschedWith the default arch_{enter,leave}_lazy_mmu_mode,
tlb_remove_tlb_entryand__tlb_remove_pagethere is a loop in thezap_pte_rangethat clears PTEs and frees corresponding pages, but doesn't flush TLB, and surrounding loop in thezap_pmd_rangethat callscond_resched. If a thread of the same process gets scheduled then it is able to see TLB entries pointing to already freed physical pages.
Quoted 7 lines
I've noticed that with xtensa arch when I added a test before returning to userspace checking that TLB contents agrees with page tables of the current mm. This check reliably fires with the LTP test mtest05 that maps, unmaps and accesses memory from multiple threads.
Is there anything wrong in my description, maybe something specific to my arch, or this issue really exists?
Hi,
I've made similar checking function for MIPS (because qemu is my only choice and it simulates MIPS TLB) and ran my tests on mips-malta machine in qemu. With MIPS I can also see this issue. I hope I did it right, the patch at the bottom is for the reference. The test I run and the diagnostic output are as follows:
# ./runltp -p -q -T 100 -s mtest05 ... mmstress 0 TINFO : test2: Test case tests the race condition between simultaneous write faults in the same address space. [ 439.010000] 14: 70d68000: 03178000/00000000 mmstress 2 TPASS : TEST 2 Passed ... mmstress 0 TINFO : test2: Test case tests the race condition between simultaneous write faults in the same address space. [ 947.390000] 10: 6f9d2000: 03639000/00000000 [ 947.390000] 10: 6f9d3000: 03638000/00000000 mmstress 2 TPASS : TEST 2 Passed ... mmstress 0 TINFO : test1: Test case tests the race condition between simultaneous read faults in the same address space. [ 1922.680000] 10: 68e12000: 03b59000/00000000 [ 1922.680000] 10: 68e13000: 03b58000/00000000 mmstress 1 TPASS : TEST 1 Passed ...
To me it looks like the cond_resched in the zap_pmd_range is the root cause of this issue (let alone SMP case for now). It was introduced in the commit
commit 97a894136f29802da19a15541de3c019e1ca147e
Author: Peter Zijlstra <[email protected]> Date: Tue May 24 17:12:04 2011 -0700
mm: Remove i_mmap_lock lockbreak
Peter, Kamezawa, other reviewers of that commit, could you please comment?
------8<------
From 29324d01c0c95b11fbfe509d9b0eae42cab6d380 Mon Sep 17 00:00:00 2001
From: Max Filippov <[email protected]>
Date: Tue, 28 May 2013 08:06:03 +0400
Subject: [PATCH] mips: check TLB sanity on return to userspace
--- arch/mips/kernel/entry.S | 1 + arch/mips/lib/dump_tlb.c | 81 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 82 insertions(+), 0 deletions(-)
arch/mips/kernel/entry.S +1 -0
@@ -49,6 +49,7 @@ resume_userspace: local_irq_disable # make sure we dont miss an # interrupt setting need_resched # between sampling and return + jal check_tlb_all LONG_L a2, TI_FLAGS($28) # current->work andi t0, a2, _TIF_WORK_MASK # (ignoring syscall_trace) bnez t0, work_pending
arch/mips/lib/dump_tlb.c +81 -0
90 lines not on this page · raw message
Signature · 6 lines
1.7.7.6 -- Thanks. -- Max
Peter Zijlstra
maintainerQuoted 43 lines · Max Filippov
Quoted 23 lines · Max Filippov
Hello arch and mm people.
Is it intentional that threads of a process that invoked munmap syscall can see TLB entries pointing to already freed pages, or it is a bug?
I'm talking about
zap_pmd_rangeandzap_pte_range:
zap_pmd_range
zap_pte_range
arch_enter_lazy_mmu_mode
ptep_get_and_clear_full
tlb_remove_tlb_entry
__tlb_remove_page
arch_leave_lazy_mmu_mode
cond_reschedWith the default arch_{enter,leave}_lazy_mmu_mode,
tlb_remove_tlb_entryand__tlb_remove_pagethere is a loop in thezap_pte_rangethat clears PTEs and frees corresponding pages, but doesn't flush TLB, and surrounding loop in thezap_pmd_rangethat callscond_resched. If a thread of the same process gets scheduled then it is able to see TLB entries pointing to already freed physical pages.Quoted 7 lines
I've noticed that with xtensa arch when I added a test before returning to userspace checking that TLB contents agrees with page tables of the current mm. This check reliably fires with the LTP test mtest05 that maps, unmaps and accesses memory from multiple threads.
Is there anything wrong in my description, maybe something specific to my arch, or this issue really exists?
Hi,
I've made similar checking function for MIPS (because qemu is my only choice and it simulates MIPS TLB) and ran my tests on mips-malta machine in qemu. With MIPS I can also see this issue. I hope I did it right, the patch at the bottom is for the reference. The test I run and the diagnostic output are as follows:
To me it looks like the
cond_reschedin thezap_pmd_rangeis the root cause of this issue (let alone SMP case for now). It was introduced in the commit
Quoted 7 lines
commit
97a894136f29802da19a15541de3c019e1ca147eAuthor: Peter Zijlstra <[email protected]> Date: Tue May 24 17:12:04 2011 -0700mm: Remove
i_mmap_locklockbreakPeter, Kamezawa, other reviewers of that commit, could you please comment?
Are you all running UP systems? I suppose the preemptible muck invalidated the assumption that UP systems are 'easy'.
If you make tlb_fast_mode() return an unconditional false, does it all work again?
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Quoted 50 lines · Peter Zijlstra
Quoted 49 lines · Max Filippov
Quoted 23 lines · Max Filippov
Hello arch and mm people.
Is it intentional that threads of a process that invoked munmap syscall can see TLB entries pointing to already freed pages, or it is a bug?
I'm talking about
zap_pmd_rangeandzap_pte_range:
zap_pmd_range
zap_pte_range
arch_enter_lazy_mmu_mode
ptep_get_and_clear_full
tlb_remove_tlb_entry
__tlb_remove_page
arch_leave_lazy_mmu_mode
cond_reschedWith the default arch_{enter,leave}_lazy_mmu_mode,
tlb_remove_tlb_entryand__tlb_remove_pagethere is a loop in thezap_pte_rangethat clears PTEs and frees corresponding pages, but doesn't flush TLB, and surrounding loop in thezap_pmd_rangethat callscond_resched. If a thread of the same process gets scheduled then it is able to see TLB entries pointing to already freed physical pages.Quoted 7 lines
I've noticed that with xtensa arch when I added a test before returning to userspace checking that TLB contents agrees with page tables of the current mm. This check reliably fires with the LTP test mtest05 that maps, unmaps and accesses memory from multiple threads.
Is there anything wrong in my description, maybe something specific to my arch, or this issue really exists?
Hi,
I've made similar checking function for MIPS (because qemu is my only choice and it simulates MIPS TLB) and ran my tests on mips-malta machine in qemu. With MIPS I can also see this issue. I hope I did it right, the patch at the bottom is for the reference. The test I run and the diagnostic output are as follows:
To me it looks like the
cond_reschedin thezap_pmd_rangeis the root cause of this issue (let alone SMP case for now). It was introduced in the commitcommit
97a894136f29802da19a15541de3c019e1ca147eAuthor: Peter Zijlstra <[email protected]> Date: Tue May 24 17:12:04 2011 -0700mm: Remove
i_mmap_locklockbreak
Quoted 8 lines
Quoted 1 line
Peter, Kamezawa, other reviewers of that commit, could you please comment?
Are you all running UP systems? I suppose the preemptible muck invalidated the assumption that UP systems are 'easy'.
If you make
tlb_fast_mode()return an unconditional false, does it all work again?
It seems tlb_fast_mode() only affects the page free batching and won't affect the TLB flush themselves unless ofcourse the batching runs out of space.
FWIW, prior to your commit d16dfc550f5326 "mm: mmu_gather rework" tlb_finish_mmu() right before the need_resced() which would have handled the current situation. My proposal - please see my earlier email in thread is to reuse the force_flush logic in zap_pte_range() to do this.
-Vineet
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Peter Zijlstra
maintainerQuoted 2 lines · Vineet Gupta
It seems
tlb_fast_mode()only affects the page free batching and won't affect the TLB flush themselves unless ofcourse the batching runs out of space.
It does, it will keep the pages around until after a flush. So you'll no longer free pages before having done a TLB flush.
Quoted 4 lines
FWIW, prior to your commit
d16dfc550f5326"mm:mmu_gatherrework"tlb_finish_mmu()right before theneed_resced()which would have handled the current situation. My proposal - please see my earlier email in thread is to reuse theforce_flushlogic inzap_pte_range()to do this.
I don't have earlier emails as my lkml folder is somewhat broken atm :/
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Peter Zijlstra
maintainerWhat about something like this?
--- include/asm-generic/tlb.h | 11 ++++++++++- mm/memory.c | 17 ++++++++++++++++- 2 files changed, 26 insertions(+), 2 deletions(-)
include/asm-generic/tlb.h +10 -1
@@ -116,6 +116,7 @@ struct mmu_gather {static inline int tlb_fast_mode (struct mmu_gather *tlb) { +#ifndef CONFIG_PREEMPT #ifdef CONFIG_SMP return tlb->fast_mode;#else
@@ -124,7 +125,15 @@ static inline int tlb_fast_mode(struct mmu_gather *tlb)* and page free order so much.. */ return 1 ; -#endif +#endif /* CONFIG_SMP */ +#else /* CONFIG_PREEMPT */ +/* +* Since mmu_gather is preemptible, preemptible kernels are like SMP +* kernels, we must batch to make sure we invalidate TLBs before we +* free the pages. +*/ +return 0 ; +#endif /* CONFIG_PREEMPT */ }void tlb_gather_mmu (struct mmu_gather *tlb,struct mm_struct *mm,bool fullmm);
mm/memory.c +16 -1
@@ -384,6 +384,21 @@ void tlb_remove_table(struct mmu_gather *tlb, void *table)#endif /* CONFIG_HAVE_RCU_TABLE_FREE */ +static inline void cond_resched_tlb (struct mmu_gather *tlb) +{ +#ifndef CONFIG_PREEMPT +/* +* For full preempt kernels we must do regular batching like +* SMP, see tlb_fast_mode(). For !PREEMPT we can 'cheat' and +* do a flush before our voluntary 'yield'. +*/ +if (need_resched ()) { +tlb_flush_mmu (tlb); +cond_resched (); + } +#endif +} +/* * If a p?d_bad entry is found while walking page tables, report * the error, before resetting entry to p?d_none. Usually (but
@@ -1264,7 +1279,7 @@ static inline unsigned long zap_pmd_range(struct mmu_gather *tlb, goto next; next =zap_pte_range (tlb, vma, pmd, addr, next, details); next: -cond_resched (); +cond_resched_tlb (tlb); }while (pmd++, addr = next, addr != end);return addr;
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Quoted 10 lines · Peter Zijlstra
mm/memory.c +4
-0@@ -384,6 +384,21 @@ void tlb_remove_table(struct mmu_gather *tlb, void *table)#endif /* CONFIG_HAVE_RCU_TABLE_FREE */ +static inline void cond_resched_tlb (struct mmu_gather *tlb) +{ +#ifndef CONFIG_PREEMPT +/*
mm/memory.c void tlb_remove_table(struct mmu_gather *tlb, void *table) · line 400
Quoted 10 lines
mm/memory.c +10
-0+* For full preempt kernels we must do regular batching like +* SMP, see tlb_fast_mode(). For !PREEMPT we can 'cheat' and +* do a flush before our voluntary 'yield'. +*/ +if (need_resched ()) { +tlb_flush_mmu (tlb); +cond_resched (); + } +#endif +}
Does it matter that in the CONFIG_PREEMPT case, you no longer call cond_resched()? I guess we can just rely on the kernel full preemption to reschedule as needed.
--
Catalin
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Peter Zijlstra
maintainerQuoted 17 lines · Catalin Marinas
Quoted 16 lines · Peter Zijlstra
mm/memory.c +10
-0@@ -384,6 +384,21 @@ void tlb_remove_table(struct mmu_gather *tlb, void *table)#endif /* CONFIG_HAVE_RCU_TABLE_FREE */ +static inline void cond_resched_tlb (struct mmu_gather *tlb) +{ +#ifndef CONFIG_PREEMPT +/* +* For full preempt kernels we must do regular batching like +* SMP, see tlb_fast_mode(). For !PREEMPT we can 'cheat' and +* do a flush before our voluntary 'yield'. +*/ +if (need_resched ()) { +tlb_flush_mmu (tlb);
Quoted 8 lines
mm/memory.c void tlb_remove_table(struct mmu_gather *tlb, void *table) · line 400
Quoted 4 lines
mm/memory.c +4
-0+ cond_resched(); + } +#endif +}Does it matter that in the
CONFIG_PREEMPTcase, you no longer callcond_resched()? I guess we can just rely on the kernel full preemption to reschedule as needed.
Exactly, the preempt_enable from the spin_unlock in pte_unmap_unlock() will most likely immediately trigger a preemption.
And since we do full batching for PREEMPT doing extra flushes would be detrimental for performance -- however unlikely it is we'll still see the need_resched() there.
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Quoted 24 lines · Peter Zijlstra
What about something like this?
--- include/asm-generic/tlb.h | 11 ++++++++++- mm/memory.c | 17 ++++++++++++++++- 2 files changed, 26 insertions(+), 2 deletions(-)include/asm-generic/tlb.h +1
-1@@ -116,6 +116,7 @@ struct mmu_gather {static inline int tlb_fast_mode (struct mmu_gather *tlb) { +#ifndef CONFIG_PREEMPT #ifdef CONFIG_SMP return tlb->fast_mode;#else @@ -124,7 +125,15 @@ static inline int tlb_fast_mode(struct mmu_gather *tlb)* and page free order so much.. */ return 1 ; -#endif
include/asm-generic/tlb.h static inline int tlb_fast_mode(struct mmu_gather *tlb) · line 137
Quoted 10 lines
include/asm-generic/tlb.h +9
-0+#endif /* CONFIG_SMP */ +#else /* CONFIG_PREEMPT */ +/* +* Since mmu_gather is preemptible, preemptible kernels are like SMP +* kernels, we must batch to make sure we invalidate TLBs before we +* free the pages. +*/ +return 0 ; +#endif /* CONFIG_PREEMPT */ }
So this adds the page batching logic to small/simpler UP systems - but it's necessary evil :-(
Quoted 8 lines
include/asm-generic/tlb.h +0
-0void tlb_gather_mmu (struct mmu_gather *tlb,struct mm_struct *mm,bool fullmm);mm/memory.c +0
-0@@ -384,6 +384,21 @@ void tlb_remove_table(struct mmu_gather *tlb, void *table)#endif /* CONFIG_HAVE_RCU_TABLE_FREE */
mm/memory.c void tlb_remove_table(struct mmu_gather *tlb, void *table) · line 395
Quoted 10 lines
mm/memory.c +9
-0+static inline void cond_resched_tlb (struct mmu_gather *tlb) +{ +#ifndef CONFIG_PREEMPT +/* +* For full preempt kernels we must do regular batching like +* SMP, see tlb_fast_mode(). For !PREEMPT we can 'cheat' and +* do a flush before our voluntary 'yield'. +*/ +if (need_resched ()) {
This is really neat: w/o this check, a @fullmm flush (exit/execve) would have suffered multiple full TLB flushes in the loop, now you do that only if a scheduling was needed - meaning only in the case when we have the potential race condition which Max was seeing. Cool !
Quoted 10 lines
mm/memory.c +6
-0+tlb_flush_mmu (tlb); + cond_resched(); + } +#endif +} +/* * If a p?d_bad entry is found while walking page tables, report * the error, before resetting entry to p?d_none. Usually (but
mm/memory.c static inline unsigned long zap_pmd_range(struct mmu_gather *tlb, · line 1285
Quoted 8 lines
mm/memory.c +1
-1@@ -1264,7 +1279,7 @@ static inline unsigned long zap_pmd_range(struct mmu_gather *tlb, goto next; next =zap_pte_range (tlb, vma, pmd, addr, next, details); next: -cond_resched (); +cond_resched_tlb (tlb); }while (pmd++, addr = next, addr != end);return addr;
BTW, since we are on the topic, it seems that we are missing tlb_fast_mode() in one spot - unless it is tied to rcu table free stuff.
-------------->
From: Vineet Gupta <[email protected]>
Date: Thu, 30 May 2013 10:25:30 +0530
Subject: [PATCH] mm: tlb_fast_mode check missing in tlb_finish_mmu()
--- mm/memory.c | 3 +++ 1 file changed, 3 insertions(+)
mm/memory.c +0 -0
@@ -269,6 +269,9 @@ void tlb_finish_mmu(struct mmu_gather *tlb, unsigned long
start, unsigned long e
/* keep the page table cache within bounds */
check_pgt_cache();+ if (tlb_fast_mode(tlb))
+ return;
+
for (batch = tlb->local.next; batch; batch = next) {
next = batch->next;
free_pages((unsigned long)batch, 0);Signature · 1 line
1.7.10.4
Peter Zijlstra
maintainerQuoted 30 lines · Vineet Gupta
Quoted 29 lines · Peter Zijlstra
What about something like this?
--- include/asm-generic/tlb.h | 11 ++++++++++- mm/memory.c | 17 ++++++++++++++++- 2 files changed, 26 insertions(+), 2 deletions(-)include/asm-generic/tlb.h +6
-1@@ -116,6 +116,7 @@ struct mmu_gather {static inline int tlb_fast_mode (struct mmu_gather *tlb) { +#ifndef CONFIG_PREEMPT #ifdef CONFIG_SMP return tlb->fast_mode;#else @@ -124,7 +125,15 @@ static inline int tlb_fast_mode(struct mmu_gather *tlb)* and page free order so much.. */ return 1 ; -#endif +#endif /* CONFIG_SMP */ +#else /* CONFIG_PREEMPT */ +/* +* Since mmu_gather is preemptible, preemptible kernels are like SMP +* kernels, we must batch to make sure we invalidate TLBs before we
Quoted 8 lines
include/asm-generic/tlb.h static inline int tlb_fast_mode(struct mmu_gather *tlb) · line 137
Quoted 5 lines
include/asm-generic/tlb.h +4
-0+* free the pages. +*/ +return 0 ; +#endif /* CONFIG_PREEMPT */ }So this adds the page batching logic to small/simpler UP systems - but it's necessary evil :-(
Well, only if you have CONFIG_PREEMPT=y, at which point UP isn't really _that_ simply anymore really.
Quoted 9 lines
Quoted 9 lines
include/asm-generic/tlb.h +0
-0void tlb_gather_mmu (struct mmu_gather *tlb,struct mm_struct *mm,bool fullmm);mm/memory.c +0
-0@@ -384,6 +384,21 @@ void tlb_remove_table(struct mmu_gather *tlb, void *table)#endif /* CONFIG_HAVE_RCU_TABLE_FREE */
Quoted 14 lines
mm/memory.c void tlb_remove_table(struct mmu_gather *tlb, void *table) · line 395
Quoted 9 lines
mm/memory.c +9
-0+static inline void cond_resched_tlb (struct mmu_gather *tlb) +{ +#ifndef CONFIG_PREEMPT +/* +* For full preempt kernels we must do regular batching like +* SMP, see tlb_fast_mode(). For !PREEMPT we can 'cheat' and +* do a flush before our voluntary 'yield'. +*/ +if (need_resched ()) {This is really neat: w/o this check, a @fullmm flush (exit/execve) would have suffered multiple full TLB flushes in the loop, now you do that only if a scheduling was needed - meaning only in the case when we have the potential race condition which Max was seeing. Cool !
Glad you like it ;-)
Quoted 41 lines
Quoted 10 lines
mm/memory.c +6
-0+tlb_flush_mmu (tlb); + cond_resched(); + } +#endif +} +/* * If a p?d_bad entry is found while walking page tables, report * the error, before resetting entry to p?d_none. Usually (but mm/memory.c static inline unsigned long zap_pmd_range(struct mmu_gather *tlb, · line 1285
Quoted 8 lines
mm/memory.c +1
-1@@ -1264,7 +1279,7 @@ static inline unsigned long zap_pmd_range(struct mmu_gather *tlb, goto next; next =zap_pte_range (tlb, vma, pmd, addr, next, details); next: -cond_resched (); +cond_resched_tlb (tlb); }while (pmd++, addr = next, addr != end);return addr;BTW, since we are on the topic, it seems that we are missing
tlb_fast_mode()in one spot - unless it is tied to rcu table free stuff.-------------->
From: Vineet Gupta <[email protected]>
Date: Thu, 30 May 2013 10:25:30 +0530
Subject: [PATCH] mm:tlb_fast_modecheck missing intlb_finish_mmu()Signed-off-by Vineet Gupta <[email protected]>--- mm/memory.c | 3 +++ 1 file changed, 3 insertions(+)mm/memory.c +0
-0@@ -269,6 +269,9 @@ void tlb_finish_mmu(struct mmu_gather *tlb, unsigned longstart, unsigned long e
/* keep the page table cache within bounds */ check_pgt_cache();
mm/memory.c
Quoted 6 lines
mm/memory.c +3
-0+if (tlb_fast_mode (tlb)) +return ; +for (batch = tlb->local.next; batch; batch = next) { next = batch->next;free_pages ((unsigned long )batch,0 );
Yes I think that is possible. It would shrink the code a little when fast_mode was unconditionally 1 -- ie. simple UP ;-).
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Quoted 25 lines · Peter Zijlstra
Quoted 24 lines · Vineet Gupta
On 05/29/2013 11:21 PM, Peter Zijlstra wrote:
BTW, since we are on the topic, it seems that we are missing
tlb_fast_mode()in one spot - unless it is tied to rcu table free stuff.-------------->
From: Vineet Gupta <[email protected]>
Date: Thu, 30 May 2013 10:25:30 +0530
Subject: [PATCH] mm:tlb_fast_modecheck missing intlb_finish_mmu()Signed-off-by Vineet Gupta <[email protected]>--- mm/memory.c | 3 +++ 1 file changed, 3 insertions(+)mm/memory.c +0
-0@@ -269,6 +269,9 @@ void tlb_finish_mmu(struct mmu_gather *tlb, unsigned longstart, unsigned long e
/* keep the page table cache within bounds */ check_pgt_cache();
Quoted 8 lines
mm/memory.c
Quoted 6 lines
mm/memory.c +3
-0+if (tlb_fast_mode (tlb)) +return ; +for (batch = tlb->local.next; batch; batch = next) { next = batch->next;free_pages ((unsigned long )batch,0 );Yes I think that is possible. It would shrink the code a little when
fast_modewas unconditionally 1 -- ie. simple UP ;-).
Exactly ! Can you please revert with a Reviewed-by/Acked-by so I can formally send it over to linux-mm list.
Thx,
-Vineet
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Quoted 35 lines · Vineet Gupta
Quoted 25 lines · Peter Zijlstra
Quoted 24 lines · Vineet Gupta
On 05/29/2013 11:21 PM, Peter Zijlstra wrote:
BTW, since we are on the topic, it seems that we are missing
tlb_fast_mode()in one spot - unless it is tied to rcu table free stuff.-------------->
From: Vineet Gupta <[email protected]>
Date: Thu, 30 May 2013 10:25:30 +0530
Subject: [PATCH] mm:tlb_fast_modecheck missing intlb_finish_mmu()Signed-off-by Vineet Gupta <[email protected]>--- mm/memory.c | 3 +++ 1 file changed, 3 insertions(+)mm/memory.c +0
-0@@ -269,6 +269,9 @@ void tlb_finish_mmu(struct mmu_gather *tlb, unsigned longstart, unsigned long e
/* keep the page table cache within bounds */ check_pgt_cache();Quoted 8 lines
mm/memory.c
Quoted 6 lines
mm/memory.c +3
-0+if (tlb_fast_mode (tlb)) +return ; +for (batch = tlb->local.next; batch; batch = next) { next = batch->next;free_pages ((unsigned long )batch,0 );Yes I think that is possible. It would shrink the code a little when
fast_modewas unconditionally 1 -- ie. simple UP ;-).
Quoted 2 lines
Exactly ! Can you please revert with a Reviewed-by/Acked-by so I can formally send it over to linux-mm list.
s/revert/reply/?
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Hi Peter,
Quoted 1 line · Peter Zijlstra
What about something like this?
With that patch I still get mtest05 firing my TLB/PTE incoherency check in the UP PREEMPT_VOLUNTARY configuration. This happens after zap_pte_range completion in the end of unmap_region because of rescheduling called in the following call chain:
unmap_region
free_pgtables
unlink_anon_vmas
lock_anon_vma_root
down_write
might_sleep
might_resched
_cond_resched
Quoted 72 lines
--- include/asm-generic/tlb.h | 11 ++++++++++- mm/memory.c | 17 ++++++++++++++++- 2 files changed, 26 insertions(+), 2 deletions(-)include/asm-generic/tlb.h +10
-1@@ -116,6 +116,7 @@ struct mmu_gather {static inline int tlb_fast_mode (struct mmu_gather *tlb) { +#ifndef CONFIG_PREEMPT #ifdef CONFIG_SMP return tlb->fast_mode;#else @@ -124,7 +125,15 @@ static inline int tlb_fast_mode(struct mmu_gather *tlb)* and page free order so much.. */ return 1 ; -#endif +#endif /* CONFIG_SMP */ +#else /* CONFIG_PREEMPT */ +/* +* Since mmu_gather is preemptible, preemptible kernels are like SMP +* kernels, we must batch to make sure we invalidate TLBs before we +* free the pages. +*/ +return 0 ; +#endif /* CONFIG_PREEMPT */ }void tlb_gather_mmu (struct mmu_gather *tlb,struct mm_struct *mm,bool fullmm);mm/memory.c +16
-1@@ -384,6 +384,21 @@ void tlb_remove_table(struct mmu_gather *tlb, void *table)#endif /* CONFIG_HAVE_RCU_TABLE_FREE */ +static inline void cond_resched_tlb (struct mmu_gather *tlb) +{ +#ifndef CONFIG_PREEMPT +/* +* For full preempt kernels we must do regular batching like +* SMP, see tlb_fast_mode(). For !PREEMPT we can 'cheat' and +* do a flush before our voluntary 'yield'. +*/ +if (need_resched ()) { +tlb_flush_mmu (tlb); +cond_resched (); + } +#endif +} +/* * If a p?d_bad entry is found while walking page tables, report * the error, before resetting entry to p?d_none. Usually (but @@ -1264,7 +1279,7 @@ static inline unsigned long zap_pmd_range(struct mmu_gather *tlb, goto next; next =zap_pte_range (tlb, vma, pmd, addr, next, details); next: -cond_resched (); +cond_resched_tlb (tlb); }while (pmd++, addr = next, addr != end);return addr;
Signature · 2 lines
Thanks. -- Max
Peter Zijlstra
maintainerQuoted 10 lines · Max Filippov
Hi Peter,
Quoted 1 line · Peter Zijlstra
What about something like this?
With that patch I still get mtest05 firing my TLB/PTE incoherency check in the UP
PREEMPT_VOLUNTARYconfiguration. This happens afterzap_pte_rangecompletion in the end ofunmap_regionbecause of rescheduling called in the following call chain:
Quoted 9 lines
unmap_region
free_pgtables
unlink_anon_vmas
lock_anon_vma_root
down_write
might_sleep
might_resched
_cond_resched
Hurm, yeah. Catching all regular blocking primitives and making it maintainable is going to be a problem :/
I suppose the easiest thing is simply killing fast_mode for now/
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Peter Zijlstra
maintainerQuoted 9 lines · Max Filippov
Hi Peter,
Quoted 1 line · Peter Zijlstra
What about something like this?
With that patch I still get mtest05 firing my TLB/PTE incoherency check in the UP
PREEMPT_VOLUNTARYconfiguration. This happens afterzap_pte_rangecompletion in the end ofunmap_regionbecause of rescheduling called in the following call chain:
OK, so there two options; completely kill off fast-mode or something like the below where we add magic to the scheduler :/
I'm aware people might object to something like the below -- but since its a possibility I thought we ought to at least mention it.
For those new to the thread; the problem is that since the introduction of preemptible mmu_gather the traditional UP fast-mode is broken. Fast-mode is where we free the pages first and flush TLBs later. This is not a problem if there's no concurrency, but obviously if you can preempt there now is.
I think I prefer completely killing off fast-mode esp. since UP seems to go the way of the Dodo and it does away with an exception in the mmu_gather code.
Anyway; opinions? Linus, Thomas, Ingo?
---nclude/asm-generic/tlb.h | 19 +++++++++++++++----
include/linux/sched.h | 1 + kernel/sched/core.c | 9 +++++++++ mm/memory.c | 3 +++ 4 files changed, 28 insertions(+), 4 deletions(-)
include/asm-generic/tlb.h +15 -4
@@ -116,15 +116,26 @@ struct mmu_gather {static inline int tlb_fast_mode (struct mmu_gather *tlb) { +#ifdef CONFIG_PREEMPT +/* +* We don't want to add to the schedule fast path for preemptible +* kernels; disable fast mode unconditionally. +*/ +return 0 ; +#endif +#ifdef CONFIG_SMP +/* +* We can only use fast mode if there's a single CPU online; +* otherwise SMP might trip over stale TLB entries. +*/ return tlb->fast_mode; -#else +#endif +/* -* For UP we don't need to worry about TLB flush -* and page free order so much.. +* Non-preempt UP can do fast mode unconditionally. */ return 1 ; -#endif }void tlb_gather_mmu (struct mmu_gather *tlb,struct mm_struct *mm,bool fullmm);
include/linux/sched.h +1 -0
@@ -1416,6 +1416,7 @@ struct task_struct {unsigned int sequential_io;unsigned int sequential_io_avg;#endif +struct mmu_gather *tlb; };/* Future-safe accessor for struct task_struct's cpus_allowed. */
kernel/sched/core.c +9 -0
@@ -2374,6 +2374,15 @@ static void __sched __schedule(void)struct rq *rq;int cpu; +#ifndef CONFIG_PREEMPT +/* +* We always force batched mmu_gather for preemptible kernels in order +* to minimize scheduling delays. See tlb_fast_mode(). +*/ +if (current->tlb &&tlb_fast_mode (current->tlb)) +tlb_flush_mmu (current->tlb); +#endif + need_resched:preempt_disable (); cpu =smp_processor_id ();
mm/memory.c +3 -0
@@ -230,6 +230,7 @@ void tlb_gather_mmu(struct mmu_gather *tlb, struct mm_struct *mm, bool fullmm)#ifdef CONFIG_HAVE_RCU_TABLE_FREE tlb->batch =NULL ;#endif + current->tlb = tlb; }void tlb_flush_mmu (struct mmu_gather *tlb)
@@ -274,6 +275,8 @@ void tlb_finish_mmu(struct mmu_gather *tlb, unsigned long start, unsigned long efree_pages ((unsigned long )batch,0 ); } tlb->local.next =NULL ; + + current->tlb =NULL ; }/* __tlb_remove_page
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Quoted 23 lines · Peter Zijlstra
Quoted 9 lines · Max Filippov
Hi Peter,
Quoted 1 line · Peter Zijlstra
What about something like this?
With that patch I still get mtest05 firing my TLB/PTE incoherency check in the UP
PREEMPT_VOLUNTARYconfiguration. This happens afterzap_pte_rangecompletion in the end ofunmap_regionbecause of rescheduling called in the following call chain:OK, so there two options; completely kill off fast-mode or something like the below where we add magic to the scheduler :/
I'm aware people might object to something like the below -- but since its a possibility I thought we ought to at least mention it.
For those new to the thread; the problem is that since the introduction of preemptible
mmu_gatherthe traditional UP fast-mode is broken. Fast-mode is where we free the pages first and flush TLBs later. This is not a problem if there's no concurrency, but obviously if you can preempt there now is.
Quoted 5 lines
I think I prefer completely killing off fast-mode esp. since UP seems to go the way of the Dodo and it does away with an exception in the
mmu_gathercode.Anyway; opinions? Linus, Thomas, Ingo?
Since UP kernels have not been packaged up by major distros for years, and since the live-patching of SMP kernels (the SMP alternative-instructions patching machinery) does away with a big chunk of the SMP cost, I guess UP kernels are slowly becoming like TINY_RCU: interesting but not really a primary design goal?
( Another reason for reducing SMP vs. UP complexity in this area would be
the fact that we had a few bad regressions lately - the TLB code is not getting simpler, and bugs are getting discovered and fixed slower. )
At least that's the x86 perspective. ARM might still see it differently?
Thanks,
Ingo
Quoted 38 lines · Ingo Molnar
Quoted 23 lines · Peter Zijlstra
Quoted 9 lines · Max Filippov
Hi Peter,
Quoted 1 line · Peter Zijlstra
What about something like this?
With that patch I still get mtest05 firing my TLB/PTE incoherency check in the UP
PREEMPT_VOLUNTARYconfiguration. This happens afterzap_pte_rangecompletion in the end ofunmap_regionbecause of rescheduling called in the following call chain:OK, so there two options; completely kill off fast-mode or something like the below where we add magic to the scheduler :/
I'm aware people might object to something like the below -- but since its a possibility I thought we ought to at least mention it.
For those new to the thread; the problem is that since the introduction of preemptible
mmu_gatherthe traditional UP fast-mode is broken. Fast-mode is where we free the pages first and flush TLBs later. This is not a problem if there's no concurrency, but obviously if you can preempt there now is.Quoted 5 lines
I think I prefer completely killing off fast-mode esp. since UP seems to go the way of the Dodo and it does away with an exception in the
mmu_gathercode.Anyway; opinions? Linus, Thomas, Ingo?
Since UP kernels have not been packaged up by major distros for years, and since the live-patching of SMP kernels (the SMP alternative-instructions patching machinery) does away with a big chunk of the SMP cost, I guess UP kernels are slowly becoming like
TINY_RCU: interesting but not really a primary design goal?
Quoted 5 lines
( Another reason for reducing SMP vs. UP complexity in this area would be
the fact that we had a few bad regressions lately - the TLB code is not getting simpler, and bugs are getting discovered and fixed slower. )At least that's the x86 perspective. ARM might still see it differently?
On ARM there is a lot of ongoing work on single zImage for multiple SoCs and this implies SMP kernels. There is an SMP_ON_UP feature which does run-time code patching to optimise the UP case in a few places.
Regarding tlb_fast_mode(), the ARM-specific implementation is always 0 on ARMv7 even if UP because of speculative TLB loads (the MMU could pretty much act as a separate processor).
Catalin
Peter Zijlstra
maintainerQuoted 7 lines · Catalin Marinas
On ARM there is a lot of ongoing work on single zImage for multiple SoCs and this implies SMP kernels. There is an
SMP_ON_UPfeature which does run-time code patching to optimise the UP case in a few places.Regarding
tlb_fast_mode(), the ARM-specific implementation is always 0 on ARMv7 even if UP because of speculative TLB loads (the MMU could pretty much act as a separate processor).
Oh right.. I should really refresh the mmu_gather unification patches so all archs are using the generic code.
/me ups on todo list.
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Quoted 11 lines · Peter Zijlstra
Quoted 7 lines · Catalin Marinas
On ARM there is a lot of ongoing work on single zImage for multiple SoCs and this implies SMP kernels. There is an
SMP_ON_UPfeature which does run-time code patching to optimise the UP case in a few places.Regarding
tlb_fast_mode(), the ARM-specific implementation is always 0 on ARMv7 even if UP because of speculative TLB loads (the MMU could pretty much act as a separate processor).Oh right.. I should really refresh the
mmu_gatherunification patches so all archs are using the generic code.
That would be great! I'll help with testing/review (or if it needs anything else) from an arm/arm64 perspective.
Thanks.
Signature · 1 line
Catalin
Peter Zijlstra
maintainerQuoted 22 lines · Peter Zijlstra
Quoted 9 lines · Max Filippov
Hi Peter,
Quoted 1 line · Peter Zijlstra
What about something like this?
With that patch I still get mtest05 firing my TLB/PTE incoherency check in the UP
PREEMPT_VOLUNTARYconfiguration. This happens afterzap_pte_rangecompletion in the end ofunmap_regionbecause of rescheduling called in the following call chain:OK, so there two options; completely kill off fast-mode or something like the below where we add magic to the scheduler :/
I'm aware people might object to something like the below -- but since its a possibility I thought we ought to at least mention it.
For those new to the thread; the problem is that since the introduction of preemptible
mmu_gatherthe traditional UP fast-mode is broken. Fast-mode is where we free the pages first and flush TLBs later. This is not a problem if there's no concurrency, but obviously if you can preempt there now is.
Quoted 4 lines
I think I prefer completely killing off fast-mode esp. since UP seems to go the way of the Dodo and it does away with an exception in the
mmu_gathercode.Anyway; opinions? Linus, Thomas, Ingo?
And here's the patch that makes fast mode go *poof*..
--- arch/arm/include/asm/tlb.h | 27 ++++----------------------- arch/ia64/include/asm/tlb.h | 41 ++++++++--------------------------------- include/asm-generic/tlb.h | 17 +---------------- mm/memory.c | 9 --------- 4 files changed, 13 insertions(+), 81 deletions(-)
arch/arm/include/asm/tlb.h +4 -23
@@ -33,18 +33,6 @@#include <asm/pgalloc.h> #include <asm/tlbflush.h> -/* -* We need to delay page freeing for SMP as other CPUs can access pages -* which have been removed but not yet had their TLB entries invalidated. -* Also, as ARMv7 speculative prefetch can drag new entries into the TLB, -* we need to apply this same delaying tactic to ensure correct operation. -*/ -#if defined(CONFIG_SMP ) || defined(CONFIG_CPU_32v7) -#define tlb_fast_mode (tlb) 0 -#else -#define tlb_fast_mode (tlb) 1 -#endif -#define MMU_GATHER_BUNDLE 8/*
@@ -112,12 +100,10 @@ static inline void __tlb_alloc_page(struct mmu_gather *tlb)static inline void tlb_flush_mmu (struct mmu_gather *tlb) {tlb_flush (tlb); -if (!tlb_fast_mode (tlb)) { -free_pages_and_swap_cache (tlb->pages, tlb->nr); - tlb->nr =0 ; -if (tlb->pages == tlb->local) -__tlb_alloc_page (tlb); - } +free_pages_and_swap_cache (tlb->pages, tlb->nr); + tlb->nr =0 ; +if (tlb->pages == tlb->local) +__tlb_alloc_page (tlb); } static inline void
@@ -178,11 +164,6 @@ tlb_end_vma(struct mmu_gather *tlb, struct vm_area_struct *vma)static inline int __tlb_remove_page (struct mmu_gather *tlb,struct page *page) { -if (tlb_fast_mode (tlb)) { -free_page_and_swap_cache (page); -return 1 ;/* avoid calling tlb_flush_mmu */ - } - tlb->pages[tlb->nr++] = page;VM_BUG_ON (tlb->nr > tlb->max);return tlb->max - tlb->nr;
arch/ia64/include/asm/tlb.h +8 -33
77 lines not on this page · raw message
include/asm-generic/tlb.h +1 -16
@@ -97,11 +97,9 @@ struct mmu_gather {unsigned long start;unsigned long end; unsigned int need_flush : 1, /* Did free PTEs */ - fast_mode : 1; /* No batching */ -/* we are in the middle of an operation to clear * a full mm and can make some optimizations */ - unsigned int fullmm : 1, + fullmm : 1,/* we have performed an operation which * requires a complete flush of the tlb */ need_flush_all : 1;
@@ -114,19 +112,6 @@ struct mmu_gather {#define HAVE_GENERIC_MMU_GATHER -static inline int tlb_fast_mode (struct mmu_gather *tlb) -{ -#ifdef CONFIG_SMP -return tlb->fast_mode; -#else -/* -* For UP we don't need to worry about TLB flush -* and page free order so much.. -*/ -return 1 ; -#endif -} -void tlb_gather_mmu (struct mmu_gather *tlb,struct mm_struct *mm,bool fullmm);void tlb_flush_mmu (struct mmu_gather *tlb); void tlb_finish_mmu(struct mmu_gather *tlb, unsigned long start,
mm/memory.c +0 -9
@@ -220,7 +220,6 @@ void tlb_gather_mmu(struct mmu_gather *tlb, struct mm_struct *mm, bool fullmm) tlb->start =-1UL ; tlb->end =0 ; tlb->need_flush =0 ; - tlb->fast_mode = (num_possible_cpus () ==1 ); tlb->local.next =NULL ; tlb->local.nr =0 ; tlb->local.max =ARRAY_SIZE (tlb->__pages);
@@ -244,9 +243,6 @@ void tlb_flush_mmu(struct mmu_gather *tlb)tlb_table_flush (tlb);#endif -if (tlb_fast_mode (tlb)) -return ; -for (batch = &tlb->local; batch; batch = batch->next) {free_pages_and_swap_cache (batch->pages, batch->nr); batch->nr =0 ;
@@ -288,11 +284,6 @@ int __tlb_remove_page(struct mmu_gather *tlb, struct page *page)VM_BUG_ON (!tlb->need_flush); -if (tlb_fast_mode (tlb)) { -free_page_and_swap_cache (page); -return 1 ;/* avoid calling tlb_flush_mmu() */ - } - batch = tlb->active; batch->pages[batch->nr++] = page;if (batch->nr == batch->max) {
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Quoted 2 lines · Peter Zijlstra
And here's the patch that makes fast mode go *poof*..
Let's just do this. Mind sending a patch with proper changelog and sign-off?
Linus
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Peter Zijlstra
maintainerPATCH 1/1 arch, mm: Remove tlb_fast_mode()
Quoted 8 lines · Linus Torvalds
Quoted 2 lines · Peter Zijlstra
And here's the patch that makes fast mode go *poof*..
Let's just do this. Mind sending a patch with proper changelog and sign-off?
Sure, as an extra I even compile tested it! ;-) (including arm and ia64).
---
Subject: arch, mm: Remove tlb_fast_mode()
From: Peter Zijlstra <[email protected]>
Since the introduction of preemptible mmu_gather TLB fast mode has been broken. TLB fast mode relies on there being absolutely no concurrency; it frees pages first and invalidates TLBs later.
However now we can get concurrency and stuff goes *bang*.
This patch removes all tlb_fast_mode() code; it was found the better option vs trying to patch the hole by entangling tlb invalidation with the scheduler.
--- arch/arm/include/asm/tlb.h | 27 ++++----------------------- arch/ia64/include/asm/tlb.h | 41 ++++++++--------------------------------- include/asm-generic/tlb.h | 17 +---------------- mm/memory.c | 9 --------- 4 files changed, 13 insertions(+), 81 deletions(-)
arch/arm/include/asm/tlb.h +4 -23
@@ -33,18 +33,6 @@#include <asm/pgalloc.h> #include <asm/tlbflush.h> -/* -* We need to delay page freeing for SMP as other CPUs can access pages -* which have been removed but not yet had their TLB entries invalidated. -* Also, as ARMv7 speculative prefetch can drag new entries into the TLB, -* we need to apply this same delaying tactic to ensure correct operation. -*/ -#if defined(CONFIG_SMP ) || defined(CONFIG_CPU_32v7) -#define tlb_fast_mode (tlb) 0 -#else -#define tlb_fast_mode (tlb) 1 -#endif -#define MMU_GATHER_BUNDLE 8/*
@@ -112,12 +100,10 @@ static inline void __tlb_alloc_page(strustatic inline void tlb_flush_mmu (struct mmu_gather *tlb) {tlb_flush (tlb); -if (!tlb_fast_mode (tlb)) { -free_pages_and_swap_cache (tlb->pages, tlb->nr); - tlb->nr =0 ; -if (tlb->pages == tlb->local) -__tlb_alloc_page (tlb); - } +free_pages_and_swap_cache (tlb->pages, tlb->nr); + tlb->nr =0 ; +if (tlb->pages == tlb->local) +__tlb_alloc_page (tlb); } static inline void
@@ -178,11 +164,6 @@ tlb_end_vma(struct mmu_gather *tlb, strustatic inline int __tlb_remove_page (struct mmu_gather *tlb,struct page *page) { -if (tlb_fast_mode (tlb)) { -free_page_and_swap_cache (page); -return 1 ;/* avoid calling tlb_flush_mmu */ - } - tlb->pages[tlb->nr++] = page;VM_BUG_ON (tlb->nr > tlb->max);return tlb->max - tlb->nr;
arch/ia64/include/asm/tlb.h +8 -33
77 lines not on this page · raw message
include/asm-generic/tlb.h +1 -16
@@ -97,11 +97,9 @@ struct mmu_gather {unsigned long start;unsigned long end; unsigned int need_flush : 1, /* Did free PTEs */ - fast_mode : 1; /* No batching */ -/* we are in the middle of an operation to clear * a full mm and can make some optimizations */ - unsigned int fullmm : 1, + fullmm : 1,/* we have performed an operation which * requires a complete flush of the tlb */ need_flush_all : 1;
@@ -114,19 +112,6 @@ struct mmu_gather {#define HAVE_GENERIC_MMU_GATHER -static inline int tlb_fast_mode (struct mmu_gather *tlb) -{ -#ifdef CONFIG_SMP -return tlb->fast_mode; -#else -/* -* For UP we don't need to worry about TLB flush -* and page free order so much.. -*/ -return 1 ; -#endif -} -void tlb_gather_mmu (struct mmu_gather *tlb,struct mm_struct *mm,bool fullmm);void tlb_flush_mmu (struct mmu_gather *tlb); void tlb_finish_mmu(struct mmu_gather *tlb, unsigned long start,
mm/memory.c +0 -9
@@ -220,7 +220,6 @@ void tlb_gather_mmu(struct mmu_gather *t tlb->start =-1UL ; tlb->end =0 ; tlb->need_flush =0 ; - tlb->fast_mode = (num_possible_cpus () ==1 ); tlb->local.next =NULL ; tlb->local.nr =0 ; tlb->local.max =ARRAY_SIZE (tlb->__pages);
@@ -244,9 +243,6 @@ void tlb_flush_mmu(struct mmu_gather *tltlb_table_flush (tlb);#endif -if (tlb_fast_mode (tlb)) -return ; -for (batch = &tlb->local; batch; batch = batch->next) {free_pages_and_swap_cache (batch->pages, batch->nr); batch->nr =0 ;
@@ -288,11 +284,6 @@ int __tlb_remove_page(struct mmu_gatherVM_BUG_ON (!tlb->need_flush); -if (tlb_fast_mode (tlb)) { -free_page_and_swap_cache (page); -return 1 ;/* avoid calling tlb_flush_mmu() */ - } - batch = tlb->active; batch->pages[batch->nr++] = page;if (batch->nr == batch->max) {
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Quoted 48 lines · Peter Zijlstra
Quoted 47 lines · Max Filippov
Quoted 23 lines · Max Filippov
Hello arch and mm people.
Is it intentional that threads of a process that invoked munmap syscall can see TLB entries pointing to already freed pages, or it is a bug?
I'm talking about
zap_pmd_rangeandzap_pte_range:
zap_pmd_range
zap_pte_range
arch_enter_lazy_mmu_mode
ptep_get_and_clear_full
tlb_remove_tlb_entry
__tlb_remove_page
arch_leave_lazy_mmu_mode
cond_reschedWith the default arch_{enter,leave}_lazy_mmu_mode,
tlb_remove_tlb_entryand__tlb_remove_pagethere is a loop in thezap_pte_rangethat clears PTEs and frees corresponding pages, but doesn't flush TLB, and surrounding loop in thezap_pmd_rangethat callscond_resched. If a thread of the same process gets scheduled then it is able to see TLB entries pointing to already freed physical pages.Quoted 7 lines
I've noticed that with xtensa arch when I added a test before returning to userspace checking that TLB contents agrees with page tables of the current mm. This check reliably fires with the LTP test mtest05 that maps, unmaps and accesses memory from multiple threads.
Is there anything wrong in my description, maybe something specific to my arch, or this issue really exists?
Hi,
I've made similar checking function for MIPS (because qemu is my only choice and it simulates MIPS TLB) and ran my tests on mips-malta machine in qemu. With MIPS I can also see this issue. I hope I did it right, the patch at the bottom is for the reference. The test I run and the diagnostic output are as follows:
To me it looks like the
cond_reschedin thezap_pmd_rangeis the root cause of this issue (let alone SMP case for now). It was introduced in the commitcommit
97a894136f29802da19a15541de3c019e1ca147eAuthor: Peter Zijlstra <[email protected]> Date: Tue May 24 17:12:04 2011 -0700
Quoted 5 lines
Quoted 3 lines
mm: Remove
i_mmap_locklockbreakPeter, Kamezawa, other reviewers of that commit, could you please comment?
Are you all running UP systems? I suppose the preemptible muck
Yes, xtensa SMP support is in the middle of forward porting/cleanup process.
Quoted 4 lines
invalidated the assumption that UP systems are 'easy'.
If you make
tlb_fast_mode()return an unconditional false, does it all work again?
Actually the only thing that was visibly broken is the test for TLB/PTE coherency,
but that incoherency appears to be intentional (and the test is too simple for that).
Unconditionally returning false from tlb_fast_mode() doesn't fix that test, but AFAICS it fixes underlying page freeing.
Signature · 8 lines
Thanks. -- Max -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Quoted 16 lines · Max Filippov
Hello arch and mm people.
Is it intentional that threads of a process that invoked munmap syscall can see TLB entries pointing to already freed pages, or it is a bug?
I'm talking about
zap_pmd_rangeandzap_pte_range:
zap_pmd_range
zap_pte_range
arch_enter_lazy_mmu_mode
ptep_get_and_clear_full
tlb_remove_tlb_entry
__tlb_remove_page
arch_leave_lazy_mmu_mode
cond_resched
Quoted 6 lines
With the default arch_{enter,leave}_lazy_mmu_mode,
tlb_remove_tlb_entryand__tlb_remove_pagethere is a loop in thezap_pte_rangethat clears PTEs and frees corresponding pages, but doesn't flush TLB, and surrounding loop in thezap_pmd_rangethat callscond_resched. If a thread of the same process gets scheduled then it is able to see TLB entries pointing to already freed physical pages.
The idea behind the lazy MMU subsystem is that it does not need to flush the TLB all the time and allow one to do PTE manipulations in a "batch mode". Meaning there are stray entries - and one has to be diligient about not using them.
Here is the relvant comment from the Linux header:
/*
* A facility to provide lazy MMU batching. This allows PTE updates and
* page invalidations to be delayed until a call to leave lazy MMU mode
* is issued. Some architectures may benefit from doing this, and it is
* beneficial for both shadow and direct mode hypervisors, which may batch
* the PTE updates which happen during this window. Note that using this
* interface requires that read hazards be removed from the code. A read
* hazard could result in the direct mode hypervisor case, since the actual
* write to the page tables may not yet have taken place, so reads though
* a raw PTE pointer after it has been modified are not guaranteed to be
* up to date. This mode can only be entered and left under the protection of
* the page table locks for all page tables which may be modified. In the UP
* case, this is required so that preemption is disabled, and in the SMP case,
* it must synchronize the delayed page table writes properly on other CPUs. */
This means that eventually when arch_leave_lazy_mmu_mode or arch_flush_lazy_mmu_mode is called, the PTE updates _should_ be flushed (aka, TLB flush if needed on the altered PTE entries).
Quoted 6 lines
I've noticed that with xtensa arch when I added a test before returning to userspace checking that TLB contents agrees with page tables of the current mm. This check reliably fires with the LTP test mtest05 that maps, unmaps and accesses memory from multiple threads.
Quoted 17 lines
Is there anything wrong in my description, maybe something specific to my arch, or this issue really exists?
I've also noticed that there are a lot of arches with default implementations of the involved functions, does that mean that any/all of them have this issue too?
Signature · 8 lines
Thanks. -- Max -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Quoted 24 lines · Konrad Rzeszutek Wilk
Quoted 16 lines · Max Filippov
Hello arch and mm people.
Is it intentional that threads of a process that invoked munmap syscall can see TLB entries pointing to already freed pages, or it is a bug?
I'm talking about
zap_pmd_rangeandzap_pte_range:
zap_pmd_range
zap_pte_range
arch_enter_lazy_mmu_mode
ptep_get_and_clear_full
tlb_remove_tlb_entry
__tlb_remove_page
arch_leave_lazy_mmu_mode
cond_reschedQuoted 6 lines
With the default arch_{enter,leave}_lazy_mmu_mode,
tlb_remove_tlb_entryand__tlb_remove_pagethere is a loop in thezap_pte_rangethat clears PTEs and frees corresponding pages, but doesn't flush TLB, and surrounding loop in thezap_pmd_rangethat callscond_resched. If a thread of the same process gets scheduled then it is able to see TLB entries pointing to already freed physical pages.
Quoted 3 lines
The idea behind the lazy MMU subsystem is that it does not need to flush the TLB all the time and allow one to do PTE manipulations in a "batch mode". Meaning there are stray entries - and one has to be diligient about not using them.
Yes, I got it, IOW TLB entries must either be flushed before userspace can see them, or the underlying pages must not be freed.
Quoted 18 lines
Here is the relvant comment from the Linux header:
/*
* A facility to provide lazy MMU batching. This allows PTE updates and
* page invalidations to be delayed until a call to leave lazy MMU mode
* is issued. Some architectures may benefit from doing this, and it is
* beneficial for both shadow and direct mode hypervisors, which may batch
* the PTE updates which happen during this window. Note that using this
* interface requires that read hazards be removed from the code. A read
* hazard could result in the direct mode hypervisor case, since the actual
* write to the page tables may not yet have taken place, so reads though
* a raw PTE pointer after it has been modified are not guaranteed to be
* up to date. This mode can only be entered and left under the protection of
* the page table locks for all page tables which may be modified. In the UP
* case, this is required so that preemption is disabled, and in the SMP case,
* it must synchronize the delayed page table writes properly on other CPUs. */
Quoted 3 lines
This means that eventually when
arch_leave_lazy_mmu_modeorarch_flush_lazy_mmu_modeis called, the PTE updates _should_ be flushed (aka, TLB flush if needed on the altered PTE entries).
Should (: But I only see powerpc, sparc and x86 defining __HAVE_ARCH_ENTER_LAZY_MMU_MODE, so this does not apply to all remaining arches.
Signature · 2 lines
Thanks. -- Max
Quoted 16 lines · Max Filippov
Hello arch and mm people.
Is it intentional that threads of a process that invoked munmap syscall can see TLB entries pointing to already freed pages, or it is a bug?
I'm talking about
zap_pmd_rangeandzap_pte_range:
zap_pmd_range
zap_pte_range
arch_enter_lazy_mmu_mode
ptep_get_and_clear_full
tlb_remove_tlb_entry
__tlb_remove_page
arch_leave_lazy_mmu_mode
cond_resched
Quoted 3 lines
With the default arch_{enter,leave}_lazy_mmu_mode,
tlb_remove_tlb_entryand__tlb_remove_pagethere is a loop in thezap_pte_rangethat clears PTEs and frees corresponding pages,
The page is not freed at that time (at least not for the generic mmu_gather implementation). It is stored into mmu_gather and then freed along with the tlb flush in tlb_flush_mmu.
[...]
Signature · 8 lines
Michal Hocko SUSE Labs -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Quoted 15 lines · Michal Hocko
Quoted 14 lines · Max Filippov
Is it intentional that threads of a process that invoked munmap syscall can see TLB entries pointing to already freed pages, or it is a bug?
I'm talking about
zap_pmd_rangeandzap_pte_range:
zap_pmd_range
zap_pte_range
arch_enter_lazy_mmu_mode
ptep_get_and_clear_full
tlb_remove_tlb_entry
__tlb_remove_page
arch_leave_lazy_mmu_mode
cond_resched
Quoted 7 lines
Quoted 3 lines
With the default arch_{enter,leave}_lazy_mmu_mode,
tlb_remove_tlb_entryand__tlb_remove_pagethere is a loop in thezap_pte_rangethat clears PTEs and frees corresponding pages,The page is not freed at that time (at least not for the generic
mmu_gatherimplementation). It is stored intommu_gatherand then freed along with the tlb flush intlb_flush_mmu.
Actually for the UP case, the page gets freed in __tlb_remove_page() since tlb_fast_mode() is 1.
--
Catalin
Max,
Quoted 4 lines · Max Filippov
Hello arch and mm people.
Is it intentional that threads of a process that invoked munmap syscall can see TLB entries pointing to already freed pages, or it is a bug?
If it happens, this would be a bug. It means that a process can access a physical page that has been allocated to something else, possibly kernel data.
Quoted 11 lines
I'm talking about
zap_pmd_rangeandzap_pte_range:
zap_pmd_range
zap_pte_range
arch_enter_lazy_mmu_mode
ptep_get_and_clear_full
tlb_remove_tlb_entry
__tlb_remove_page
arch_leave_lazy_mmu_mode
cond_resched
Quoted 6 lines
With the default arch_{enter,leave}_lazy_mmu_mode,
tlb_remove_tlb_entryand__tlb_remove_pagethere is a loop in thezap_pte_rangethat clears PTEs and frees corresponding pages, but doesn't flush TLB, and surrounding loop in thezap_pmd_rangethat callscond_resched. If a thread of the same process gets scheduled then it is able to see TLB entries pointing to already freed physical pages.
It looks to me like cond_resched() here introduces a possible bug but it depends on the actual arch code, especially the __tlb_remove_tlb_entry() function. On ARM we record the range in tlb_remove_tlb_entry() and queue the pages to be removed in __tlb_remove_page(). It pretty much acts like tlb_fast_mode() == 0 even for the UP case (which is also needed for hardware speculative TLB loads). The tlb_finish_mmu() takes care of whatever pages are left to be freed.
With a dummy __tlb_remove_tlb_entry() and tlb_fast_mode() == 1, cond_resched() in zap_pmd_range() would cause problems.
I think possible workarounds:
1. tlb_fast_mode() always returning 0.
2. add a tlb_flush_mmu(tlb) before cond_resched() in zap_pmd_range().
3. implement __tlb_remove_tlb_entry() on xtensa to always flush the tlb (which is probably costly).
4. drop the cond_resched() (not sure about preemptible kernels though).
I would vote for 1 but let's see what the mm people say.
--
Catalin
Hi Catalin,
Quoted 39 lines · Catalin Marinas
Max,
Quoted 4 lines · Max Filippov
Hello arch and mm people.
Is it intentional that threads of a process that invoked munmap syscall can see TLB entries pointing to already freed pages, or it is a bug?
If it happens, this would be a bug. It means that a process can access a physical page that has been allocated to something else, possibly kernel data.
Quoted 11 lines
I'm talking about
zap_pmd_rangeandzap_pte_range:
zap_pmd_range
zap_pte_range
arch_enter_lazy_mmu_mode
ptep_get_and_clear_full
tlb_remove_tlb_entry
__tlb_remove_page
arch_leave_lazy_mmu_mode
cond_reschedQuoted 6 lines
With the default arch_{enter,leave}_lazy_mmu_mode,
tlb_remove_tlb_entryand__tlb_remove_pagethere is a loop in thezap_pte_rangethat clears PTEs and frees corresponding pages, but doesn't flush TLB, and surrounding loop in thezap_pmd_rangethat callscond_resched. If a thread of the same process gets scheduled then it is able to see TLB entries pointing to already freed physical pages.It looks to me like
cond_resched()here introduces a possible bug but it depends on the actual arch code, especially the__tlb_remove_tlb_entry()function. On ARM we record the range intlb_remove_tlb_entry()and queue the pages to be removed in__tlb_remove_page(). It pretty much acts liketlb_fast_mode()== 0 even for the UP case (which is also needed for hardware speculative TLB loads). Thetlb_finish_mmu()takes care of whatever pages are left to be freed.
Quoted 2 lines
With a dummy
__tlb_remove_tlb_entry()andtlb_fast_mode()== 1,cond_resched()inzap_pmd_range()would cause problems.
So, looks like most architectures in the UP configuration should have this issue (unless they flush TLB in the switch_mm, even when switching to the same mm):
tlb_remove_tlb_entry __tlb_remove_tlb_entry __tlb_remove_page __HAVE_ARCH_ENTER_LAZY_MMU_MODE
non-default non-trivial non-default defined
alpha
arc
arm yes yes
arm64 yes yes
avr32
blackfin
c6x
cris
frv
h8300
hexagon
ia64 yes yes yesKconfig
m32r
m68k
metag
microblaze
mips
mn10300
openrisc
parisc
powerpc yes yes
s390 yes yes (a)
score
sh yes yes (a)
sparc yes
tile
um yes yes yes
unicore32
x86 yes
xtensa
(a) __tlb_remove_page == free_page_and_swap_cache
Quoted 9 lines
I think possible workarounds:
1.
tlb_fast_mode()always returning 0.
2. add atlb_flush_mmu(tlb)beforecond_resched()inzap_pmd_range().
3. implement__tlb_remove_tlb_entry()on xtensa to always flush the tlb (which is probably costly).
4. drop thecond_resched()(not sure about preemptible kernels though).I would vote for 1 but let's see what the mm people say.
Signature · 2 lines
Thanks. -- Max
Quoted 36 lines · Max Filippov
Quoted 35 lines · Catalin Marinas
Quoted 2 lines · Max Filippov
Is it intentional that threads of a process that invoked munmap syscall can see TLB entries pointing to already freed pages, or it is a bug?
If it happens, this would be a bug. It means that a process can access a physical page that has been allocated to something else, possibly kernel data.
Quoted 11 lines
I'm talking about
zap_pmd_rangeandzap_pte_range:
zap_pmd_range
zap_pte_range
arch_enter_lazy_mmu_mode
ptep_get_and_clear_full
tlb_remove_tlb_entry
__tlb_remove_page
arch_leave_lazy_mmu_mode
cond_reschedQuoted 6 lines
With the default arch_{enter,leave}_lazy_mmu_mode,
tlb_remove_tlb_entryand__tlb_remove_pagethere is a loop in thezap_pte_rangethat clears PTEs and frees corresponding pages, but doesn't flush TLB, and surrounding loop in thezap_pmd_rangethat callscond_resched. If a thread of the same process gets scheduled then it is able to see TLB entries pointing to already freed physical pages.It looks to me like
cond_resched()here introduces a possible bug but it depends on the actual arch code, especially the__tlb_remove_tlb_entry()function. On ARM we record the range intlb_remove_tlb_entry()and queue the pages to be removed in__tlb_remove_page(). It pretty much acts liketlb_fast_mode()== 0 even for the UP case (which is also needed for hardware speculative TLB loads). Thetlb_finish_mmu()takes care of whatever pages are left to be freed.
Quoted 6 lines
Quoted 2 lines
With a dummy
__tlb_remove_tlb_entry()andtlb_fast_mode()== 1,cond_resched()inzap_pmd_range()would cause problems.So, looks like most architectures in the UP configuration should have this issue (unless they flush TLB in the
switch_mm, even when switching to the same mm):
switch_mm() wouldn't be called if switching to the same mm. You could do it in switch_to() but it's not efficient (or before returning to user space on the same processor).
Do you happen to have a user-space test for this? Something like one thread does an mmap(), writes some poison value, munmap(). The other thread keeps checking the poison value while trapping and ignoring any SIGSEGV. If it's working correctly, the second thread should either get a SIGSEGV or read the poison value.
Signature · 7 lines
Catalin -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Quoted 37 lines · Catalin Marinas
Quoted 36 lines · Max Filippov
Quoted 35 lines · Catalin Marinas
Quoted 2 lines · Max Filippov
Is it intentional that threads of a process that invoked munmap syscall can see TLB entries pointing to already freed pages, or it is a bug?
If it happens, this would be a bug. It means that a process can access a physical page that has been allocated to something else, possibly kernel data.
Quoted 11 lines
I'm talking about
zap_pmd_rangeandzap_pte_range:
zap_pmd_range
zap_pte_range
arch_enter_lazy_mmu_mode
ptep_get_and_clear_full
tlb_remove_tlb_entry
__tlb_remove_page
arch_leave_lazy_mmu_mode
cond_reschedQuoted 6 lines
With the default arch_{enter,leave}_lazy_mmu_mode,
tlb_remove_tlb_entryand__tlb_remove_pagethere is a loop in thezap_pte_rangethat clears PTEs and frees corresponding pages, but doesn't flush TLB, and surrounding loop in thezap_pmd_rangethat callscond_resched. If a thread of the same process gets scheduled then it is able to see TLB entries pointing to already freed physical pages.It looks to me like
cond_resched()here introduces a possible bug but it depends on the actual arch code, especially the__tlb_remove_tlb_entry()function. On ARM we record the range intlb_remove_tlb_entry()and queue the pages to be removed in__tlb_remove_page(). It pretty much acts liketlb_fast_mode()== 0 even for the UP case (which is also needed for hardware speculative TLB loads). Thetlb_finish_mmu()takes care of whatever pages are left to be freed.
Quoted 8 lines
Quoted 6 lines
Quoted 2 lines
With a dummy
__tlb_remove_tlb_entry()andtlb_fast_mode()== 1,cond_resched()inzap_pmd_range()would cause problems.So, looks like most architectures in the UP configuration should have this issue (unless they flush TLB in the
switch_mm, even when switching to the same mm):
switch_mm()wouldn't be called if switching to the same mm. You could do
Hmm... Strange, but as far as I can tell from the context_switch it would.
Quoted 4 lines
it in
switch_to()but it's not efficient (or before returning to user space on the same processor).Do you happen to have a user-space test for this? Something like one
I only had mtest05 from LTP that triggered TLB/PTE inconsistency, but not anything that would really try to peek at the freed page. I can make such test though.
Quoted 4 lines
thread does an
mmap(), writes some poison value,munmap(). The other thread keeps checking the poison value while trapping and ignoring any SIGSEGV. If it's working correctly, the second thread should either get a SIGSEGV or read the poison value.
Signature · 8 lines
Thanks. -- Max -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Quoted 42 lines · Max Filippov
Quoted 40 lines · Catalin Marinas
Quoted 39 lines · Max Filippov
Quoted 37 lines · Catalin Marinas
Quoted 2 lines · Max Filippov
Is it intentional that threads of a process that invoked munmap syscall can see TLB entries pointing to already freed pages, or it is a bug?
If it happens, this would be a bug. It means that a process can access a physical page that has been allocated to something else, possibly kernel data.
Quoted 11 lines
I'm talking about
zap_pmd_rangeandzap_pte_range:
zap_pmd_range
zap_pte_range
arch_enter_lazy_mmu_mode
ptep_get_and_clear_full
tlb_remove_tlb_entry
__tlb_remove_page
arch_leave_lazy_mmu_mode
cond_reschedQuoted 6 lines
With the default arch_{enter,leave}_lazy_mmu_mode,
tlb_remove_tlb_entryand__tlb_remove_pagethere is a loop in thezap_pte_rangethat clears PTEs and frees corresponding pages, but doesn't flush TLB, and surrounding loop in thezap_pmd_rangethat callscond_resched. If a thread of the same process gets scheduled then it is able to see TLB entries pointing to already freed physical pages.It looks to me like
cond_resched()here introduces a possible bug but it depends on the actual arch code, especially the__tlb_remove_tlb_entry()function. On ARM we record the range intlb_remove_tlb_entry()and queue the pages to be removed in__tlb_remove_page(). It pretty much acts liketlb_fast_mode()== 0 even for the UP case (which is also needed for hardware speculative TLB loads). Thetlb_finish_mmu()takes care of whatever pages are left to be freed.With a dummy
__tlb_remove_tlb_entry()andtlb_fast_mode()== 1,cond_resched()inzap_pmd_range()would cause problems.
Quoted 7 lines
Quoted 5 lines
Quoted 3 lines
So, looks like most architectures in the UP configuration should have this issue (unless they flush TLB in the
switch_mm, even when switching to the same mm):
switch_mm()wouldn't be called if switching to the same mm. You could doHmm... Strange, but as far as I can tell from the
context_switchit would.
You are right. On ARM we have a prev != next check but that's in the switch_mm() implementation.
Signature · 7 lines
Catalin -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Quoted 50 lines · Max Filippov
Quoted 37 lines · Catalin Marinas
Quoted 36 lines · Max Filippov
Quoted 35 lines · Catalin Marinas
Quoted 2 lines · Max Filippov
Is it intentional that threads of a process that invoked munmap syscall can see TLB entries pointing to already freed pages, or it is a bug?
If it happens, this would be a bug. It means that a process can access a physical page that has been allocated to something else, possibly kernel data.
Quoted 11 lines
I'm talking about
zap_pmd_rangeandzap_pte_range:
zap_pmd_range
zap_pte_range
arch_enter_lazy_mmu_mode
ptep_get_and_clear_full
tlb_remove_tlb_entry
__tlb_remove_page
arch_leave_lazy_mmu_mode
cond_reschedQuoted 6 lines
With the default arch_{enter,leave}_lazy_mmu_mode,
tlb_remove_tlb_entryand__tlb_remove_pagethere is a loop in thezap_pte_rangethat clears PTEs and frees corresponding pages, but doesn't flush TLB, and surrounding loop in thezap_pmd_rangethat callscond_resched. If a thread of the same process gets scheduled then it is able to see TLB entries pointing to already freed physical pages.It looks to me like
cond_resched()here introduces a possible bug but it depends on the actual arch code, especially the__tlb_remove_tlb_entry()function. On ARM we record the range intlb_remove_tlb_entry()and queue the pages to be removed in__tlb_remove_page(). It pretty much acts liketlb_fast_mode()== 0 even for the UP case (which is also needed for hardware speculative TLB loads). Thetlb_finish_mmu()takes care of whatever pages are left to be freed.Quoted 8 lines
Quoted 6 lines
Quoted 2 lines
With a dummy
__tlb_remove_tlb_entry()andtlb_fast_mode()== 1,cond_resched()inzap_pmd_range()would cause problems.So, looks like most architectures in the UP configuration should have this issue (unless they flush TLB in the
switch_mm, even when switching to the same mm):
switch_mm()wouldn't be called if switching to the same mm. You could doHmm... Strange, but as far as I can tell from the
context_switchit would.
Quoted 13 lines
Quoted 4 lines
it in
switch_to()but it's not efficient (or before returning to user space on the same processor).Do you happen to have a user-space test for this? Something like one
I only had mtest05 from LTP that triggered TLB/PTE inconsistency, but not anything that would really try to peek at the freed page. I can make such test though.
Quoted 4 lines
thread does an
mmap(), writes some poison value,munmap(). The other thread keeps checking the poison value while trapping and ignoring any SIGSEGV. If it's working correctly, the second thread should either get a SIGSEGV or read the poison value.
I've made a number of such tests and had them running for a couple of days. Checking thread never read anything other than poison value so far.
Signature · 8 lines
Thanks. -- Max -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Quoted 39 lines · Catalin Marinas
Max,
Quoted 4 lines · Max Filippov
Hello arch and mm people.
Is it intentional that threads of a process that invoked munmap syscall can see TLB entries pointing to already freed pages, or it is a bug?
If it happens, this would be a bug. It means that a process can access a physical page that has been allocated to something else, possibly kernel data.
Quoted 11 lines
I'm talking about
zap_pmd_rangeandzap_pte_range:
zap_pmd_range
zap_pte_range
arch_enter_lazy_mmu_mode
ptep_get_and_clear_full
tlb_remove_tlb_entry
__tlb_remove_page
arch_leave_lazy_mmu_mode
cond_reschedQuoted 6 lines
With the default arch_{enter,leave}_lazy_mmu_mode,
tlb_remove_tlb_entryand__tlb_remove_pagethere is a loop in thezap_pte_rangethat clears PTEs and frees corresponding pages, but doesn't flush TLB, and surrounding loop in thezap_pmd_rangethat callscond_resched. If a thread of the same process gets scheduled then it is able to see TLB entries pointing to already freed physical pages.It looks to me like
cond_resched()here introduces a possible bug but it depends on the actual arch code, especially the__tlb_remove_tlb_entry()function. On ARM we record the range intlb_remove_tlb_entry()and queue the pages to be removed in__tlb_remove_page(). It pretty much acts liketlb_fast_mode()== 0 even for the UP case (which is also needed for hardware speculative TLB loads). Thetlb_finish_mmu()takes care of whatever pages are left to be freed.
Quoted 6 lines
With a dummy
__tlb_remove_tlb_entry()andtlb_fast_mode()== 1,cond_resched()inzap_pmd_range()would cause problems.I think possible workarounds:
1.
tlb_fast_mode()always returning 0.
This might add needless page free batching logic so not very lucrative.
Quoted 1 line
2. add a
tlb_flush_mmu(tlb)beforecond_resched()inzap_pmd_range().
For !fullmm flushes it might be no-op on some arches (atleast on ARC) as we use tlb_end_vma() to do TLB range flush. And flushing the entire TLB would be excessive though.
Actually zap_pte_range() already has logic to flush the TLB range (if batching runs out of space). Can we re-use that infrastructure to make sure zap_pte_range() does it's share of TLB flushing before returning and going into cond_resched().
However with that, we need to prevent tlb_end_vma()/tlb_finish_mmu() from duplicating the range flush - which can be done by clearing tlb->need_flush.
Now simplistically this will cause even the fullmm flushes (simple ASID increment on ARC/ARM..) to become TLB walks to flush the individual entries so we can do this for only for !fullmm, assuming that cond_resched() can potentially cause an exit'ing task's thread to be scheduled in and reuse the entries.
Let me go off cook a patch to see if this might work.
-Vineet
[Resending with fixed linux-mm address]
Quoted 39 lines · Catalin Marinas
Max,
Quoted 4 lines · Max Filippov
Hello arch and mm people.
Is it intentional that threads of a process that invoked munmap syscall can see TLB entries pointing to already freed pages, or it is a bug?
If it happens, this would be a bug. It means that a process can access a physical page that has been allocated to something else, possibly kernel data.
Quoted 11 lines
I'm talking about
zap_pmd_rangeandzap_pte_range:
zap_pmd_range
zap_pte_range
arch_enter_lazy_mmu_mode
ptep_get_and_clear_full
tlb_remove_tlb_entry
__tlb_remove_page
arch_leave_lazy_mmu_mode
cond_reschedQuoted 6 lines
With the default arch_{enter,leave}_lazy_mmu_mode,
tlb_remove_tlb_entryand__tlb_remove_pagethere is a loop in thezap_pte_rangethat clears PTEs and frees corresponding pages, but doesn't flush TLB, and surrounding loop in thezap_pmd_rangethat callscond_resched. If a thread of the same process gets scheduled then it is able to see TLB entries pointing to already freed physical pages.It looks to me like
cond_resched()here introduces a possible bug but it depends on the actual arch code, especially the__tlb_remove_tlb_entry()function. On ARM we record the range intlb_remove_tlb_entry()and queue the pages to be removed in__tlb_remove_page(). It pretty much acts liketlb_fast_mode()== 0 even for the UP case (which is also needed for hardware speculative TLB loads). Thetlb_finish_mmu()takes care of whatever pages are left to be freed.
Quoted 6 lines
With a dummy
__tlb_remove_tlb_entry()andtlb_fast_mode()== 1,cond_resched()inzap_pmd_range()would cause problems.I think possible workarounds:
1.
tlb_fast_mode()always returning 0.
This might add needless page free batching logic so not very lucrative.
Quoted 1 line
2. add a
tlb_flush_mmu(tlb)beforecond_resched()inzap_pmd_range().
For !fullmm flushes it might be no-op on some arches (atleast on ARC) as we use tlb_end_vma() to do TLB range flush. And flushing the entire TLB would be excessive though.
Actually zap_pte_range() already has logic to flush the TLB range (if batching runs out of space). Can we re-use that infrastructure to make sure zap_pte_range() does it's share of TLB flushing before returning and going into cond_resched().
However with that, we need to prevent tlb_end_vma()/tlb_finish_mmu() from duplicating the range flush - which can be done by clearing tlb->need_flush.
Now simplistically this will cause even the fullmm flushes (simple ASID increment on ARC/ARM..) to become TLB walks to flush the individual entries so we can do this for only for !fullmm, assuming that cond_resched() can potentially cause an exit'ing task's thread to be scheduled in and reuse the entries.
Let me go off cook a patch to see if this might work.
-Vineet
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>