Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > linux.kernel > #1243309 > unrolled thread
| Started by | Kosuke Tatsukawa <tatsu@ab.jp.nec.com> |
|---|---|
| First post | 2015-10-09 14:30 +0200 |
| Last post | 2015-10-09 16:00 +0200 |
| Articles | 3 — 3 participants |
Back to article view | Back to linux.kernel
[PATCH v2] kvm: fix waitqueue_active without memory barrier in virt/kvm/async_pf.c Kosuke Tatsukawa <tatsu@ab.jp.nec.com> - 2015-10-09 14:30 +0200
Re: [PATCH v2] kvm: fix waitqueue_active without memory barrier in virt/kvm/async_pf.c Peter Zijlstra <peterz@infradead.org> - 2015-10-09 15:00 +0200
Re: [PATCH v2] kvm: fix waitqueue_active without memory barrier in virt/kvm/async_pf.c Paolo Bonzini <pbonzini@redhat.com> - 2015-10-09 16:00 +0200
| From | Kosuke Tatsukawa <tatsu@ab.jp.nec.com> |
|---|---|
| Date | 2015-10-09 14:30 +0200 |
| Subject | [PATCH v2] kvm: fix waitqueue_active without memory barrier in virt/kvm/async_pf.c |
| Message-ID | <qhEYa-21U-21@gated-at.bofh.it> |
async_pf_execute() seems to be missing a memory barrier which might
cause the waker to not notice the waiter and miss sending a wake_up as
in the following figure.
async_pf_execute kvm_vcpu_block
------------------------------------------------------------------------
spin_lock(&vcpu->async_pf.lock);
if (waitqueue_active(&vcpu->wq))
/* The CPU might reorder the test for
the waitqueue up here, before
prior writes complete */
prepare_to_wait(&vcpu->wq, &wait,
TASK_INTERRUPTIBLE);
/*if (kvm_vcpu_check_block(vcpu) < 0) */
/*if (kvm_arch_vcpu_runnable(vcpu)) { */
...
return (vcpu->arch.mp_state == KVM_MP_STATE_RUNNABLE &&
!vcpu->arch.apf.halted)
|| !list_empty_careful(&vcpu->async_pf.done)
...
return 0;
list_add_tail(&apf->link,
&vcpu->async_pf.done);
spin_unlock(&vcpu->async_pf.lock);
waited = true;
schedule();
------------------------------------------------------------------------
The attached patch adds the missing memory barrier.
I found this issue when I was looking through the linux source code
for places calling waitqueue_active() before wake_up*(), but without
preceding memory barriers, after sending a patch to fix a similar
issue in drivers/tty/n_tty.c (Details about the original issue can be
found here: https://lkml.org/lkml/2015/9/28/849).
Signed-off-by: Kosuke Tatsukawa <tatsu@ab.jp.nec.com>
---
v2:
- Fixed comment based on feedback from Paolo
v1:
- https://lkml.org/lkml/2015/10/8/994
---
virt/kvm/async_pf.c | 6 ++++++
1 files changed, 6 insertions(+), 0 deletions(-)
diff --git a/virt/kvm/async_pf.c b/virt/kvm/async_pf.c
index 44660ae..a0999d7 100644
--- a/virt/kvm/async_pf.c
+++ b/virt/kvm/async_pf.c
@@ -94,6 +94,12 @@ static void async_pf_execute(struct work_struct *work)
trace_kvm_async_pf_completed(addr, gva);
+ /*
+ * Memory barrier is required here to make sure change to
+ * vcpu->async_pf.done is visible from other CPUs. This memory
+ * barrier pairs with prepare_to_wait's set_current_state()
+ */
+ smp_mb();
if (waitqueue_active(&vcpu->wq))
wake_up_interruptible(&vcpu->wq);
--
1.7.1
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[toc] | [next] | [standalone]
| From | Peter Zijlstra <peterz@infradead.org> |
|---|---|
| Date | 2015-10-09 15:00 +0200 |
| Message-ID | <qhFrc-2zB-15@gated-at.bofh.it> |
| In reply to | #1243309 |
On Fri, Oct 09, 2015 at 12:21:55PM +0000, Kosuke Tatsukawa wrote: > + * Memory barrier is required here to make sure change to > + * vcpu->async_pf.done is visible from other CPUs. This memory > + * barrier pairs with prepare_to_wait's set_current_state() That is not how memory barriers work; they don't 'make visible'. They simply ensure order between operations. X = Y = 0 CPU0 CPU1 [S] X=1 [S] Y=1 MB MB [L] y=Y [L] x=X assert(x || y) The issue of the memory barrier does not mean the store is visible, it merely means that the load _must_ happen after the store (in the above scenario). This gives a guarantee that not both x and y can be 0. Because either being 0, means the other has not yet executed and must therefore observe your store. Nothing more, nothing less. So your comment is misleading at best. -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Paolo Bonzini <pbonzini@redhat.com> |
|---|---|
| Date | 2015-10-09 16:00 +0200 |
| Message-ID | <qhGng-3UO-23@gated-at.bofh.it> |
| In reply to | #1243322 |
On 09/10/2015 14:55, Peter Zijlstra wrote: > On Fri, Oct 09, 2015 at 12:21:55PM +0000, Kosuke Tatsukawa wrote: > >> + * Memory barrier is required here to make sure change to >> + * vcpu->async_pf.done is visible from other CPUs. This memory >> + * barrier pairs with prepare_to_wait's set_current_state() > > That is not how memory barriers work; they don't 'make visible'. They > simply ensure order between operations. > > X = Y = 0 > > CPU0 CPU1 > > [S] X=1 [S] Y=1 > MB MB > [L] y=Y [L] x=X > > assert(x || y) > > The issue of the memory barrier does not mean the store is visible, it > merely means that the load _must_ happen after the store (in the above > scenario). > > This gives a guarantee that not both x and y can be 0. Because either > being 0, means the other has not yet executed and must therefore observe > your store. > > Nothing more, nothing less. > > So your comment is misleading at best. Yeah, I will just reword the comment when applying. Thanks Kosuke-san for your contribution! Paolo -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [standalone]
Back to top | Article view | linux.kernel
csiph-web