Here are the membarrier changes I plan on sending for the
4.15 merge window.
This series includes selftests improvements for sys_membarrier,
improvement of powerpc handling of the memory barrier required
by sys_membarrier in switch_mm(), and adds a new core serializing
membarrier, currently only implemented on x86. Architectures
wishing to provide the core serializing membarrier need to
select ARCH_HAS_MEMBARRIER_SYNC_CORE and document how they
provide the core serialization required by that command in their
architecture code.
Andy, I know you told me you had changes coming up in x86 entry.S
for 4.15, but I figure that managing the merge conflict between your
changes in 4.15 and those added comments should be straightforward.
Anyway, I kind of suspect that at any given point in time you will
always have changes of some sort to propose to entry.S, so now seems
to be a time as appropriate as ever to push the core serializing
membarrier comments.
Feedback is welcome!
Thanks,
Mathieu
Mathieu Desnoyers (6):
membarrier: selftest: Test private expedited cmd
membarrier: powerpc: Skip memory barrier in switch_mm() (v6)
membarrier: Document scheduler barrier requirements (v5)
membarrier: Provide core serializing command
membarrier: x86: Provide core serializing command
membarrier: selftest: Test private expedited sync core cmd
MAINTAINERS | 2 +
arch/powerpc/Kconfig | 1 +
arch/powerpc/include/asm/membarrier.h | 32 ++++
arch/powerpc/kernel/Makefile | 2 +
arch/powerpc/kernel/membarrier.c | 37 ++++
arch/powerpc/mm/mmu_context.c | 7 +
arch/x86/Kconfig | 2 +
arch/x86/entry/entry_32.S | 5 +
arch/x86/entry/entry_64.S | 8 +
arch/x86/include/asm/membarrier.h | 36 ++++
arch/x86/kernel/Makefile | 1 +
arch/x86/kernel/membarrier.c | 39 +++++
arch/x86/mm/tlb.c | 6 +
include/linux/sched/mm.h | 36 +++-
include/uapi/linux/membarrier.h | 14 +-
init/Kconfig | 6 +
kernel/sched/core.c | 53 +++---
kernel/sched/membarrier.c | 55 ++++--
.../testing/selftests/membarrier/membarrier_test.c | 186 +++++++++++++++++++--
19 files changed, 470 insertions(+), 58 deletions(-)
create mode 100644 arch/powerpc/include/asm/membarrier.h
create mode 100644 arch/powerpc/kernel/membarrier.c
create mode 100644 arch/x86/include/asm/membarrier.h
create mode 100644 arch/x86/kernel/membarrier.c
--
2.11.0
Document the membarrier requirement on having a full memory barrier in
__schedule() after coming from user-space, before storing to rq->curr.
It is provided by smp_mb__after_spinlock() in __schedule().
Document that membarrier requires a full barrier on transition from
kernel thread to userspace thread. We currently have an implicit barrier
from atomic_dec_and_test() in mmdrop() that ensures this.
The x86 switch_mm_irqs_off() full barrier is currently provided by many
cpumask update operations as well as write_cr3(). Document that
write_cr3() provides this barrier.
Changes since v1:
- Update comments to match reality for code paths which are after
storing to rq->curr, before returning to user-space, based on feedback
from Andrea Parri.
Changes since v2:
- Update changelog (smp_mb__before_spinlock -> smp_mb__after_spinlock).
Based on feedback from Andrea Parri.
Changes since v3:
- Clarify comments following feeback from Peter Zijlstra.
Changes since v4:
- Update comment regarding powerpc barrier.
Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
CC: Peter Zijlstra <peterz@infradead.org>
CC: Paul E. McKenney <redacted>
CC: Boqun Feng <redacted>
CC: Andrew Hunter <redacted>
CC: Maged Michael <redacted>
CC: gromer@google.com
CC: Avi Kivity <redacted>
CC: Benjamin Herrenschmidt <benh@kernel.crashing.org>
CC: Paul Mackerras <redacted>
CC: Michael Ellerman <mpe@ellerman.id.au>
CC: Dave Watson <redacted>
CC: Thomas Gleixner <redacted>
CC: Ingo Molnar <mingo@redhat.com>
CC: "H. Peter Anvin" <hpa@zytor.com>
CC: Andrea Parri <parri.andrea@gmail.com>
CC: x86@kernel.org
---
arch/x86/mm/tlb.c | 5 +++++
include/linux/sched/mm.h | 5 +++++
kernel/sched/core.c | 37 ++++++++++++++++++++++++++-----------
3 files changed, 36 insertions(+), 11 deletions(-)
Provide core serializing membarrier command to support memory reclaim
by JIT.
Each architecture needs to explicitly opt into that support by
documenting in their architecture code how they provide the core
serializing instructions required when returning from the membarrier
IPI, and after the scheduler has updated the curr->mm pointer (before
going back to user-space). They should then define
ARCH_HAS_MEMBARRIER_SYNC_CORE to enable support for that command on
their architecture.
Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers-vg+e7yoeK/dWk0Htik3J/w@public.gmane.org>
CC: Peter Zijlstra <redacted>
CC: Andy Lutomirski <redacted>
CC: Paul E. McKenney <redacted>
CC: Boqun Feng <redacted>
CC: Andrew Hunter <redacted>
CC: Maged Michael <redacted>
CC: gromer-hpIqsD4AKlfQT0dZR+AlfA@public.gmane.org
CC: Avi Kivity <avi-VrcmuVmyx1hWk0Htik3J/w@public.gmane.org>
CC: Benjamin Herrenschmidt <redacted>
CC: Paul Mackerras <redacted>
CC: Michael Ellerman <mpe-Gsx/Oe8HsFggBc27wqDAHg@public.gmane.org>
CC: Dave Watson <redacted>
CC: Thomas Gleixner <redacted>
CC: Ingo Molnar <redacted>
CC: "H. Peter Anvin" <redacted>
CC: Andrea Parri <redacted>
---
include/linux/sched/mm.h | 9 +++++--
include/uapi/linux/membarrier.h | 14 ++++++++---
init/Kconfig | 3 +++
kernel/sched/membarrier.c | 56 ++++++++++++++++++++++++++++++-----------
4 files changed, 61 insertions(+), 21 deletions(-)
@@ -132,6 +132,63 @@ static int test_membarrier_private_expedited_success(void)return0;}+staticinttest_membarrier_private_expedited_sync_core_fail(void)+{+intcmd=MEMBARRIER_CMD_PRIVATE_EXPEDITED_SYNC_CORE,flags=0;+constchar*test_name="sys membarrier MEMBARRIER_CMD_PRIVATE_EXPEDITED_SYNC_CORE not registered failure";++if(sys_membarrier(cmd,flags)!=-1){+ksft_exit_fail_msg(+"%s test: flags = %d. Should fail, but passed\n",+test_name,flags);+}+if(errno!=EPERM){+ksft_exit_fail_msg(+"%s test: flags = %d. Should return (%d: \"%s\"), but returned (%d: \"%s\").\n",+test_name,flags,EPERM,strerror(EPERM),+errno,strerror(errno));+}++ksft_test_result_pass(+"%s test: flags = %d, errno = %d\n",+test_name,flags,errno);+return0;+}++staticinttest_membarrier_register_private_expedited_sync_core_success(void)+{+intcmd=MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED_SYNC_CORE,flags=0;+constchar*test_name="sys membarrier MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED_SYNC_CORE";++if(sys_membarrier(cmd,flags)!=0){+ksft_exit_fail_msg(+"%s test: flags = %d, errno = %d\n",+test_name,flags,errno);+}++ksft_test_result_pass(+"%s test: flags = %d\n",+test_name,flags);+return0;+}++staticinttest_membarrier_private_expedited_sync_core_success(void)+{+intcmd=MEMBARRIER_CMD_PRIVATE_EXPEDITED,flags=0;+constchar*test_name="sys membarrier MEMBARRIER_CMD_PRIVATE_EXPEDITED_SYNC_CORE";++if(sys_membarrier(cmd,flags)!=0){+ksft_exit_fail_msg(+"%s test: flags = %d, errno = %d\n",+test_name,flags,errno);+}++ksft_test_result_pass(+"%s test: flags = %d\n",+test_name,flags);+return0;+}+staticinttest_membarrier(void){intstatus;
@@ -154,6 +211,22 @@ static int test_membarrier(void)status=test_membarrier_private_expedited_success();if(status)returnstatus;+status=sys_membarrier(MEMBARRIER_CMD_QUERY,0);+if(status<0){+ksft_test_result_fail("sys_membarrier() failed\n");+returnstatus;+}+if(status&MEMBARRIER_CMD_PRIVATE_EXPEDITED_SYNC_CORE){+status=test_membarrier_private_expedited_sync_core_fail();+if(status)+returnstatus;+status=test_membarrier_register_private_expedited_sync_core_success();+if(status)+returnstatus;+status=test_membarrier_private_expedited_sync_core_success();+if(status)+returnstatus;+}return0;}
@@ -173,8 +246,10 @@ static int test_membarrier_query(void)}ksft_exit_fail_msg("sys_membarrier() failed\n");}-if(!(ret&MEMBARRIER_CMD_SHARED))+if(!(ret&MEMBARRIER_CMD_SHARED)){+ksft_test_result_fail("sys_membarrier() CMD_SHARED query failed\n");ksft_exit_fail_msg("sys_membarrier is not supported.\n");+}ksft_test_result_pass("sys_membarrier available\n");return0;
There are two places where core serialization is needed by membarrier:
1) When returning from the membarrier IPI,
2) After scheduler updates curr to a thread with a different mm, before
going back to user-space, since the curr->mm is used by membarrier to
check whether it needs to send an IPI to that CPU.
x86-32 uses only iret both as return from interrupt, and to go back to
user-space. The iret instruction is core serializing.
x86-64 uses iret as return from interrupt, which takes care of the IPI.
However, it can return to user-space through either sysretl (compat
code), sysretq, or iret. Given that sysret{l,q} is not core serializing,
we rely instead on write_cr3() performed by switch_mm() to provide core
serialization after changing the current mm, and deal with the special
case of kthread -> uthread (temporarily keeping current mm into
active_mm) by adding a sync_core() in that specific case.
Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers-vg+e7yoeK/dWk0Htik3J/w@public.gmane.org>
CC: Peter Zijlstra <redacted>
CC: Andy Lutomirski <redacted>
CC: Paul E. McKenney <redacted>
CC: Boqun Feng <redacted>
CC: Andrew Hunter <redacted>
CC: Maged Michael <redacted>
CC: gromer-hpIqsD4AKlfQT0dZR+AlfA@public.gmane.org
CC: Avi Kivity <avi-VrcmuVmyx1hWk0Htik3J/w@public.gmane.org>
CC: Benjamin Herrenschmidt <redacted>
CC: Paul Mackerras <redacted>
CC: Michael Ellerman <mpe-Gsx/Oe8HsFggBc27wqDAHg@public.gmane.org>
CC: Dave Watson <redacted>
CC: Thomas Gleixner <redacted>
CC: Ingo Molnar <redacted>
CC: "H. Peter Anvin" <redacted>
CC: Andrea Parri <redacted>
CC: x86-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org
---
MAINTAINERS | 2 ++
arch/powerpc/include/asm/membarrier.h | 8 ++++++-
arch/powerpc/kernel/membarrier.c | 3 ++-
arch/x86/Kconfig | 2 ++
arch/x86/entry/entry_32.S | 5 +++++
arch/x86/entry/entry_64.S | 8 +++++++
arch/x86/include/asm/membarrier.h | 36 ++++++++++++++++++++++++++++++++
arch/x86/kernel/Makefile | 1 +
arch/x86/kernel/membarrier.c | 39 +++++++++++++++++++++++++++++++++++
arch/x86/mm/tlb.c | 7 ++++---
include/linux/sched/mm.h | 9 +++++++-
kernel/sched/core.c | 6 +++++-
12 files changed, 119 insertions(+), 7 deletions(-)
create mode 100644 arch/x86/include/asm/membarrier.h
create mode 100644 arch/x86/kernel/membarrier.c
@@ -54,6 +54,8 @@ config X86selectARCH_HAS_FORTIFY_SOURCEselectARCH_HAS_GCOV_PROFILE_ALLselectARCH_HAS_KCOVifX86_64+selectARCH_HAS_MEMBARRIER_HOOKS+selectARCH_HAS_MEMBARRIER_SYNC_COREselectARCH_HAS_PMEM_APIifX86_64# Causing hangs/crashes, see the commit that added this change for details.selectARCH_HAS_REFCOUNTifBROKEN
From: Andy Lutomirski <luto@kernel.org> Date: 2017-11-09 19:08:14
On Wed, Nov 8, 2017 at 10:35 AM, Mathieu Desnoyers
[off-list ref] wrote:
+/*
+ * x86-64 implements return to user-space through sysret, which is not a
+ * core-serializing instruction. Therefore, we need an explicit core
+ * serializing instruction after going from kernel thread back to
+ * user-space thread (active_mm moved back to current mm).
+ */
+static inline void membarrier_arch_mm_sync_core(struct mm_struct *mm)
+{
+ if (likely(!(atomic_read(&mm->membarrier_state) &
+ MEMBARRIER_STATE_SYNC_CORE)))
+ return;
+ sync_core();
+}
IMO there should be an extremely clear specification somewhere for
what this function is supposed to do.
If I remember correctly, it's supposed to promise that the icache is
synced before the next time we return to usermode for the current mm
on this CPU. If that's correct, then let's document it very
explicitly and let's also drop the "membarrier" from the name -- it's
a primitive we'll need anyway given the existing migration bug.
----- On Nov 9, 2017, at 2:07 PM, Andy Lutomirski luto-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org wrote:
On Wed, Nov 8, 2017 at 10:35 AM, Mathieu Desnoyers
[off-list ref] wrote:
quoted
+/*
+ * x86-64 implements return to user-space through sysret, which is not a
+ * core-serializing instruction. Therefore, we need an explicit core
+ * serializing instruction after going from kernel thread back to
+ * user-space thread (active_mm moved back to current mm).
+ */
+static inline void membarrier_arch_mm_sync_core(struct mm_struct *mm)
+{
+ if (likely(!(atomic_read(&mm->membarrier_state) &
+ MEMBARRIER_STATE_SYNC_CORE)))
+ return;
+ sync_core();
+}
IMO there should be an extremely clear specification somewhere for
what this function is supposed to do.
If I remember correctly, it's supposed to promise that the icache is
synced before the next time we return to usermode for the current mm
on this CPU. If that's correct, then let's document it very
explicitly and let's also drop the "membarrier" from the name -- it's
a primitive we'll need anyway given the existing migration bug.
I understand that on x86 (specifically), synchronizing the icache and
doing a core serializing instruction may mean the same thing.
However, on architectures like ARM, icache sync differs from core
serialization. Those architectures typically have either a user-space
accessible instruction or a system call to perform the icache flush.
The missing part for JIT is core serialization (also called context
synchronization). icache flush is already handled by pre-existing
means.
So the promise here given by membarrier_arch_mm_sync_core() is that
a core serializing instruction is issued before the next time we return
to usermode on the current thread. However, we only need that guarantee
if the current thread's mm is a registered MEMBARRIER_{...}_SYNC_CORE user.
Regarding the existing migration bug, what I think you want is a kind
of weaker "sync_core()", which ensures that a core serializing
instruction is issued before the next time the current thread returns
to usermode.
It could be e.g.: set_tsk_need_core_sync() which would set a
TIF_NEED_CORE_SYNC thread flag on the current thread.
Clearly, when this kind of thread flag is introduced as an
optimization over sync_core(), I would like to use that. However,
I don't think it replaces the membarrier_arch_mm_sync_core() entirely,
given that it would not check for the mm membarrier "SYNC_CORE"
registration state. It appears to me to be merely an optimization over
directly invoking sync_core.
What I suggest is that I update the comment above
membarrier_arch_mm_sync_core to spell out more clearly that all we
need is to have a core serializing instruction issued before the next
time the current thread returns to user-space. I can still use
sync_core for now, and we can then improve the implementation
whenever a new thread flag is introduced. The new comment would look
like:
/*
* x86-64 implements return to user-space through sysret, which is not a
* core-serializing instruction. Therefore, we need an explicit core
* serializing instruction after going from kernel thread back to
* user-space thread (active_mm moved back to current mm).
*
* This function ensures that a core serializing instruction is issued
* before the current thread returns to user-space.
*/
Thoughts ?
Thanks,
Mathieu
--
Mathieu Desnoyers
EfficiOS Inc.
http://www.efficios.com
From: Andy Lutomirski <luto@kernel.org> Date: 2017-11-10 01:19:58
On Thu, Nov 9, 2017 at 11:35 AM, Mathieu Desnoyers
[off-list ref] wrote:
----- On Nov 9, 2017, at 2:07 PM, Andy Lutomirski luto@kernel.org wrote:
quoted
On Wed, Nov 8, 2017 at 10:35 AM, Mathieu Desnoyers
[off-list ref] wrote:
quoted
+/*
+ * x86-64 implements return to user-space through sysret, which is not a
+ * core-serializing instruction. Therefore, we need an explicit core
+ * serializing instruction after going from kernel thread back to
+ * user-space thread (active_mm moved back to current mm).
+ */
+static inline void membarrier_arch_mm_sync_core(struct mm_struct *mm)
+{
+ if (likely(!(atomic_read(&mm->membarrier_state) &
+ MEMBARRIER_STATE_SYNC_CORE)))
+ return;
+ sync_core();
+}
IMO there should be an extremely clear specification somewhere for
what this function is supposed to do.
If I remember correctly, it's supposed to promise that the icache is
synced before the next time we return to usermode for the current mm
on this CPU. If that's correct, then let's document it very
explicitly and let's also drop the "membarrier" from the name -- it's
a primitive we'll need anyway given the existing migration bug.
I understand that on x86 (specifically), synchronizing the icache and
doing a core serializing instruction may mean the same thing.
However, on architectures like ARM, icache sync differs from core
serialization. Those architectures typically have either a user-space
accessible instruction or a system call to perform the icache flush.
The missing part for JIT is core serialization (also called context
synchronization). icache flush is already handled by pre-existing
means.
Can you explain what "core serialization" means for the non-ARM-using
dummies in the audience? :) That is, what does it actually guarantee.
So the promise here given by membarrier_arch_mm_sync_core() is that
a core serializing instruction is issued before the next time we return
to usermode on the current thread. However, we only need that guarantee
if the current thread's mm is a registered MEMBARRIER_{...}_SYNC_CORE user.
Why not make is so that it guarantees core serialization before the
next time we return to usermode on the current thread regardless of
membarrier details and to push the membarrier details into the caller?
Also, do you really mean "current thread" or do you mean "current
mm", perhaps, or even "current CPU"? The latter makes the most sense
to me.
Regarding the existing migration bug, what I think you want is a kind
of weaker "sync_core()", which ensures that a core serializing
instruction is issued before the next time the current thread returns
to usermode.
ISTM that would also satisfy membarrier's needs.
It could be e.g.: set_tsk_need_core_sync() which would set a
TIF_NEED_CORE_SYNC thread flag on the current thread.
Nah, only x86 and maybe power are weird enough to need thread info
flags. Let's keep implementation details like that out of the
interface.
What I suggest is that I update the comment above
membarrier_arch_mm_sync_core to spell out more clearly that all we
need is to have a core serializing instruction issued before the next
time the current thread returns to user-space.
I would want more justification before x86 adds the "current thread"
mechanism. x86 has an existing bug that needs fixing. Once that bug
is fixed, I think you don't need anything that follows the thread
around if it migrates before the core sync happens. With that bug
unfixed, I think this whole exercise is pointless on x86 -- we're
already buggy, and your series doesn't actually fix the bug.
I can still use
sync_core for now, and we can then improve the implementation
whenever a new thread flag is introduced. The new comment would look
like:
/*
* x86-64 implements return to user-space through sysret, which is not a
* core-serializing instruction. Therefore, we need an explicit core
* serializing instruction after going from kernel thread back to
* user-space thread (active_mm moved back to current mm).
*
* This function ensures that a core serializing instruction is issued
* before the current thread returns to user-space.
*/
What I'm suggesting is that you put something like the second
paragraph into the generic header. But I still think that acting on
the current *thread* is a mistake. On any architecture where you sync
a thread properly but then get unsynced on migration, you have a
problem just like x86 has now. Once we've logically synced a thread,
I think it needs to remain synced regardless of migration. Also, what
happens to all the other non-running threads that belong to the same
mm? I.e. what's at all special about current?
--Andy
----- On Nov 9, 2017, at 8:19 PM, Andy Lutomirski luto@kernel.org wrote:
On Thu, Nov 9, 2017 at 11:35 AM, Mathieu Desnoyers
[off-list ref] wrote:
quoted
----- On Nov 9, 2017, at 2:07 PM, Andy Lutomirski luto@kernel.org wrote:
quoted
On Wed, Nov 8, 2017 at 10:35 AM, Mathieu Desnoyers
[off-list ref] wrote:
quoted
+/*
+ * x86-64 implements return to user-space through sysret, which is not a
+ * core-serializing instruction. Therefore, we need an explicit core
+ * serializing instruction after going from kernel thread back to
+ * user-space thread (active_mm moved back to current mm).
+ */
+static inline void membarrier_arch_mm_sync_core(struct mm_struct *mm)
+{
+ if (likely(!(atomic_read(&mm->membarrier_state) &
+ MEMBARRIER_STATE_SYNC_CORE)))
+ return;
+ sync_core();
+}
IMO there should be an extremely clear specification somewhere for
what this function is supposed to do.
If I remember correctly, it's supposed to promise that the icache is
synced before the next time we return to usermode for the current mm
on this CPU. If that's correct, then let's document it very
explicitly and let's also drop the "membarrier" from the name -- it's
a primitive we'll need anyway given the existing migration bug.
I understand that on x86 (specifically), synchronizing the icache and
doing a core serializing instruction may mean the same thing.
However, on architectures like ARM, icache sync differs from core
serialization. Those architectures typically have either a user-space
accessible instruction or a system call to perform the icache flush.
The missing part for JIT is core serialization (also called context
synchronization). icache flush is already handled by pre-existing
means.
Can you explain what "core serialization" means for the non-ARM-using
dummies in the audience? :) That is, what does it actually guarantee.
Those parts of the ARMv7 A/R Architecture Reference Manual are relevant:
A3.8.3 Memory barriers
"Instruction Synchronization Barrier (ISB)"
"An ISB instruction flushes the pipeline in the processor, so that all
instructions that come after the ISB instruction in program order are
fetched from cache or memory only after the ISB instruction has completed.
Using an ISB ensures that the effects of context-changing operations
executed before the ISB are visible to the instructions fetched after
the ISB instruction. Examples of context-changing operations that require
the insertion of an ISB instruction to ensure the effects of the operation
are visible to instructions fetched after the ISB instruction are:
• completed cache, TLB, and branch predictor maintenance operations
• changes to system control registers.
Any context-changing operations appearing in program order after the
ISB instruction only take effect after the ISB has been executed."
The following sections explain more about cache maintenance operations:
A3.9.3 Implication of caches for the application programmer
B2.2.9 Ordering of cache and branch predictor maintenance operations
AFAIU, ARMv7 has incoherent icache and dcache, so updating code requires
the appropriate barriers (DMB), d-cache and i-cache maintenance operations,
and a context synchronizing instruction (e.g. ISB) per core that has
observed the old code before it returns to user-space and possibly
starts executing the new code.
quoted
So the promise here given by membarrier_arch_mm_sync_core() is that
a core serializing instruction is issued before the next time we return
to usermode on the current thread. However, we only need that guarantee
if the current thread's mm is a registered MEMBARRIER_{...}_SYNC_CORE user.
Why not make is so that it guarantees core serialization before the
next time we return to usermode on the current thread regardless of
membarrier details and to push the membarrier details into the caller?
Also, do you really mean "current thread" or do you mean "current
mm", perhaps, or even "current CPU"? The latter makes the most sense
to me.
You're right, it's not about the current thread. We could have this
situation:
CPU 0
Process P1 (mm needs core serialization)
Thread T1
Thread T2
Let's consider that arch_mm_sync_core() is issued for thread T1. The goal
here is to ensure that CPU 0 issues a core serializing instruction before
returning to user-space for any thread of P1 on CPU 0. Given that only
switching mm ends up triggering this, we could very well have T2 scheduled
right before we are about to go back to T1's userspace. Running T2 without
issuing a core serializing instruction would be a bug.
The exact condition we're looking for is "we want to execute a core
serializing instruction before the current CPU returns to user-space
for the current mm".
Indeed, just blindly issuing the isync insn before the current CPU
returns to user-space fits that description (it's a slightly stronger
guarantee than the bare minimum, which should be fine).
quoted
Regarding the existing migration bug, what I think you want is a kind
of weaker "sync_core()", which ensures that a core serializing
instruction is issued before the next time the current thread returns
to usermode.
^ should be "before the next time the current CPU returns to usermode".
ISTM that would also satisfy membarrier's needs.
quoted
It could be e.g.: set_tsk_need_core_sync() which would set a
TIF_NEED_CORE_SYNC thread flag on the current thread.
Nah, only x86 and maybe power are weird enough to need thread info
flags. Let's keep implementation details like that out of the
interface.
ok. And anyhow, it's not a per-thread thing, as discussed above.
quoted
What I suggest is that I update the comment above
membarrier_arch_mm_sync_core to spell out more clearly that all we
need is to have a core serializing instruction issued before the next
time the current thread returns to user-space.
I would want more justification before x86 adds the "current thread"
mechanism. x86 has an existing bug that needs fixing. Once that bug
is fixed, I think you don't need anything that follows the thread
around if it migrates before the core sync happens. With that bug
unfixed, I think this whole exercise is pointless on x86 -- we're
already buggy, and your series doesn't actually fix the bug.
So let's consider we add:
sync_core_before_usermode()
which would ensure that the current CPU issues a core serializing
instruction before returning to usermode. A trivial way to implement
it right away on x86 would be:
/*
* Issue a core serializing instruction before the current CPU returns
* to user-mode.
*/
static inline void sync_core_before_usermode()
{
sync_core();
}
Then all we need to do in order to fix the migration bug would be
to invoke sync_core_before_usermode() whenever a task is migrated
to a new CPU. This could be done by adding a "need_sync_core" flag
to the scheduler runqueue, set by migration, which would ensure the
scheduler invokes sync_core_before_usermode() before its CPU returns
to usermode.
Later on, as an optimization, we can then do more fancy stuff like
just setting a per-cpu mask, which is tested before returning to
user-mode. But I would prefer to get the most simple fix in place
first, and then focus on optimization later on.
quoted
I can still use
sync_core for now, and we can then improve the implementation
whenever a new thread flag is introduced. The new comment would look
like:
/*
* x86-64 implements return to user-space through sysret, which is not a
* core-serializing instruction. Therefore, we need an explicit core
* serializing instruction after going from kernel thread back to
* user-space thread (active_mm moved back to current mm).
*
* This function ensures that a core serializing instruction is issued
* before the current thread returns to user-space.
*/
What I'm suggesting is that you put something like the second
paragraph into the generic header. But I still think that acting on
the current *thread* is a mistake. On any architecture where you sync
a thread properly but then get unsynced on migration, you have a
problem just like x86 has now. Once we've logically synced a thread,
I think it needs to remain synced regardless of migration. Also, what
happens to all the other non-running threads that belong to the same
mm? I.e. what's at all special about current?
Yeah, as discussed above, you're right. It's not about the current thread,
but rather about "before any thread part of the given mm returns to
usermode on the current CPU".
Does my sync_core_before_usermode() and migration fix proposal make sense ?
I can then move my arch-specific membarrier_arch_mm_sync_core to a generic header
and call it "membarrier_mm_sync_core_before_usermode", and implement it as:
if (unlikely(atomic_read(&mm->membarrier_state) & MEMBARRIER_STATE_SYNC_CORE))
sync_core_before_usermode();
The reason for having the membarrier_mm_sync_core_before_usermode rather than
having the mask check in the caller is because we want to handle CONFIG_MEMBARRIER=n.
Thoughts ?
Thanks,
Mathieu
Allow PowerPC to skip the full memory barrier in switch_mm(), and
only issue the barrier when scheduling into a task belonging to a
process that has registered to use expedited private.
Threads targeting the same VM but which belong to different thread
groups is a tricky case. It has a few consequences:
It turns out that we cannot rely on get_nr_threads(p) to count the
number of threads using a VM. We can use
(atomic_read(&mm->mm_users) == 1 && get_nr_threads(p) == 1)
instead to skip the synchronize_sched() for cases where the VM only has
a single user, and that user only has a single thread.
It also turns out that we cannot use for_each_thread() to set
thread flags in all threads using a VM, as it only iterates on the
thread group.
Therefore, test the membarrier state variable directly rather than
relying on thread flags. This means
membarrier_register_private_expedited() needs to set the
MEMBARRIER_STATE_SWITCH_MM flag, issue synchronize_sched(), and only
then set MEMBARRIER_STATE_PRIVATE_EXPEDITED_READY which allows private
expedited membarrier commands to succeed. membarrier_arch_switch_mm()
now tests for the MEMBARRIER_STATE_SWITCH_MM flag.
Changes since v1:
- Use test_ti_thread_flag(next, ...) instead of test_thread_flag() in
powerpc membarrier_arch_sched_in(), given that we want to specifically
check the next thread state.
- Add missing ARCH_HAS_MEMBARRIER_HOOKS in Kconfig.
- Use task_thread_info() to pass thread_info from task to
*_ti_thread_flag().
Changes since v2:
- Move membarrier_arch_sched_in() call to finish_task_switch().
- Check for NULL t->mm in membarrier_arch_fork().
- Use membarrier_sched_in() in generic code, which invokes the
arch-specific membarrier_arch_sched_in(). This fixes allnoconfig
build on PowerPC.
- Move asm/membarrier.h include under CONFIG_MEMBARRIER, fixing
allnoconfig build on PowerPC.
- Build and runtime tested on PowerPC.
Changes since v3:
- Simply rely on copy_mm() to copy the membarrier_private_expedited mm
field on fork.
- powerpc: test thread flag instead of reading
membarrier_private_expedited in membarrier_arch_fork().
- powerpc: skip memory barrier in membarrier_arch_sched_in() if coming
from kernel thread, since mmdrop() implies a full barrier.
- Set membarrier_private_expedited to 1 only after arch registration
code, thus eliminating a race where concurrent commands could succeed
when they should fail if issued concurrently with process
registration.
- Use READ_ONCE() for membarrier_private_expedited field access in
membarrier_private_expedited. Matches WRITE_ONCE() performed in
process registration.
Changes since v4:
- Move powerpc hook from sched_in() to switch_mm(), based on feedback
from Nicholas Piggin.
Changes since v5:
- Rebase on v4.14-rc6.
- Fold "Fix: membarrier: Handle CLONE_VM + !CLONE_THREAD correctly on
powerpc (v2)"
Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
CC: Peter Zijlstra <peterz@infradead.org>
CC: Paul E. McKenney <redacted>
CC: Boqun Feng <redacted>
CC: Andrew Hunter <redacted>
CC: Maged Michael <redacted>
CC: gromer@google.com
CC: Avi Kivity <redacted>
CC: Benjamin Herrenschmidt <benh@kernel.crashing.org>
CC: Paul Mackerras <redacted>
CC: Michael Ellerman <mpe@ellerman.id.au>
CC: Dave Watson <redacted>
CC: Alan Stern <stern@rowland.harvard.edu>
CC: Will Deacon <redacted>
CC: Andy Lutomirski <luto@kernel.org>
CC: Ingo Molnar <mingo@redhat.com>
CC: Alexander Viro <viro@zeniv.linux.org.uk>
CC: Nicholas Piggin <npiggin@gmail.com>
CC: linuxppc-dev@lists.ozlabs.org
CC: linux-arch@vger.kernel.org
---
MAINTAINERS | 2 ++
arch/powerpc/Kconfig | 1 +
arch/powerpc/include/asm/membarrier.h | 26 +++++++++++++++++++++++++
arch/powerpc/kernel/Makefile | 2 ++
arch/powerpc/kernel/membarrier.c | 36 +++++++++++++++++++++++++++++++++++
arch/powerpc/mm/mmu_context.c | 7 +++++++
include/linux/sched/mm.h | 15 +++++++++++++++
init/Kconfig | 3 +++
kernel/sched/core.c | 10 ----------
kernel/sched/membarrier.c | 1 +
10 files changed, 93 insertions(+), 10 deletions(-)
create mode 100644 arch/powerpc/include/asm/membarrier.h
create mode 100644 arch/powerpc/kernel/membarrier.c
Test the new MEMBARRIER_CMD_PRIVATE_EXPEDITED and
MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED commands.
Add checks expecting specific error values on system calls expected to
fail.
Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
Acked-by: Shuah Khan <redacted>
Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
CC: Peter Zijlstra <peterz@infradead.org>
CC: Paul E. McKenney <redacted>
CC: Boqun Feng <redacted>
CC: Andrew Hunter <redacted>
CC: Maged Michael <redacted>
CC: gromer@google.com
CC: Avi Kivity <redacted>
CC: Benjamin Herrenschmidt <benh@kernel.crashing.org>
CC: Paul Mackerras <redacted>
CC: Michael Ellerman <mpe@ellerman.id.au>
CC: Dave Watson <redacted>
CC: Alan Stern <stern@rowland.harvard.edu>
CC: Will Deacon <redacted>
CC: Andy Lutomirski <luto@kernel.org>
CC: Alice Ferrazzi <redacted>
CC: Paul Elder <redacted>
CC: linux-kselftest@vger.kernel.org
CC: linux-arch@vger.kernel.org
---
.../testing/selftests/membarrier/membarrier_test.c | 109 ++++++++++++++++++---
1 file changed, 94 insertions(+), 15 deletions(-)