Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > linux.kernel > #1243309 > unrolled thread

[PATCH v2] kvm: fix waitqueue_active without memory barrier in virt/kvm/async_pf.c

Started byKosuke Tatsukawa <tatsu@ab.jp.nec.com>
First post2015-10-09 14:30 +0200
Last post2015-10-09 16:00 +0200
Articles 3 — 3 participants

Back to article view | Back to linux.kernel


Contents

  [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

#1243309 — [PATCH v2] kvm: fix waitqueue_active without memory barrier in virt/kvm/async_pf.c

FromKosuke Tatsukawa <tatsu@ab.jp.nec.com>
Date2015-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]


#1243322

FromPeter Zijlstra <peterz@infradead.org>
Date2015-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]


#1243393

FromPaolo Bonzini <pbonzini@redhat.com>
Date2015-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