generic-ipi: add smp_mb() before sending the IPI
PATCH 1/3 generic-ipi: add smp_mb() before sending the IPI
smp_mb() (to make the memory operations visible globally) is needed before sending the ipi, if the receiver refers to the data(setup by the sender) in a lock-free fashion.
On x86, x2apic mode accesses for sending IPI's don't have serializing semantics. So the need for smp_mb() before sending the IPI becomes more critical in x2apic mode.
---
kernel/smp.c +10 -0
@@ -76,6 +76,11 @@list_add_tail (&data->list, &dst->list);spin_unlock_irqrestore (&dst->lock, flags); +/* +* Make the list addition visible before sending the ipi. +*/ +smp_mb (); +if (ipi)arch_send_call_function_single_ipi (cpu);
@@ -370,6 +375,11 @@list_add_tail_rcu (&data->csd.list, &call_function_queue);spin_unlock_irqrestore (&call_function_lock, flags); +/* +* Make the list addition visible before sending the ipi. +*/ +smp_mb (); +/* Send a message to all CPUs in the map */ arch_send_call_function_ipi (mask);
PATCH 2/3 x86: Add smp_mb() before sending INVALIDATE_TLB_VECTOR
On x86, x2apic mode accesses for sending IPI's don't have serializing semantics. If the IPI receiver refers(in lock-free fashion) to some memory setup by the sender, the need for smp_mb() before sending the IPI becomes critical in x2apic mode.
Add the smp_mb() in native_flush_tlb_others() before sending the IPI.
---
arch/x86/kernel/tlb_32.c +6 -0
@@ -154,6 +154,12 @@ flush_mm = mm; flush_va = va;cpus_or (flush_cpumask, cpumask, flush_cpumask); + +/* +* Make the above memory operations globally visible before +* sending the IPI. +*/ +smp_mb ();/* * We have to send the IPI only to * CPUs affected.
arch/x86/kernel/tlb_64.c +5 -0
@@ -183,6 +183,11 @@cpus_or (f->flush_cpumask, cpumask, f->flush_cpumask);/* +* Make the above memory operations globally visible before +* sending the IPI. +*/ +smp_mb (); +/* * We have to send the IPI only to * CPUs affected. */
Ingo Molnar
AppliedRe: [patch 2/3] x86: Add smp_mb() before sending INVALIDATE_TLB_VECTOR
Quoted 9 lines · Suresh Siddha
On x86, x2apic mode accesses for sending IPI's don't have serializing semantics. If the IPI receiver refers(in lock-free fashion) to some memory setup by the sender, the need for
smp_mb()before sending the IPI becomes critical in x2apic mode.Add the
smp_mb()innative_flush_tlb_others()before sending the IPI.Signed-off-by Suresh Siddha <[email protected]>
applied to tip/x86/urgent, thanks Suresh!
Jens, you'll send 1/3 and 3/3 to Linus, right?
Ingo
Re: [patch 2/3] x86: Add smp_mb() before sending INVALIDATE_TLB_VECTOR
Quoted 8 lines · Ingo Molnar
Quoted 5 lines · Suresh Siddha
On x86, x2apic mode accesses for sending IPI's don't have serializing semantics. If the IPI receiver refers(in lock-free fashion) to some memory setup by the sender, the need for
smp_mb()before sending the IPI becomes critical in x2apic mode.
Quoted 8 lines
Quoted 4 lines
Add the
smp_mb()innative_flush_tlb_others()before sending the IPI.Signed-off-by Suresh Siddha <[email protected]>applied to tip/x86/urgent, thanks Suresh!
Jens, you'll send 1/3 and 3/3 to Linus, right?
Yes, it's in for-linus and I'll send the pull request today.
Signature · 1 line
Jens Axboe
PATCH 3/3 generic-ipi: fix the smp_mb() usage
In reply to Suresh SiddhaRemove the unnecessary smp_mb() in csd_flag_wait(), as the presence of that smp_mb() doesn't mean anything on the sender, when the ipi receiver is not doing any thing special (like memory fence) after clearing the CSD_FLAG_WAIT.
IPI receiver (on Alpha atleast) needs smp_read_barrier_depends() in the handler before reading the call_single_queue list in a lock-free fashion. Replace the existing smp_mb() (which is unnecessary) with smp_read_barrier_depends()
---
kernel/smp.c +2 -6
@@ -51,10 +51,6 @@ {/* Wait for response */ do { - /* - * We need to see the flags store in the IPI handler - */ - smp_mb(); if (!(data->flags & CSD_FLAG_WAIT)) break; cpu_relax();
@@ -162,7 +158,7 @@* Need to see other stores to list head for checking whether * list is empty without holding q->lock */ -smp_mb (); +smp_read_barrier_depends ();while (!list_empty (&q->list)) {unsigned int data_flags;
@@ -196,7 +192,7 @@/* * See comment on outer loop */ -smp_mb (); +smp_read_barrier_depends (); } }