Skip to contentSkip to conversation

KVM: some swait cleanups

PATCH In review Peter Xu 3 participants 10 messages Nov 9, 2017 – Nov 13, 2017

Subsystems (5)
x86 KVM Scheduler KVM x86 +1 more subsystems
lore
Share & tools
lore

Peter Xu

author
#0 lore raw

cover KVM: some swait cleanups

A simple cleanup, but it should also make the
kvm_vcpu.stat.halt_wakeup a bit more accurate.

Please review, thanks.

Peter Xu (2):
sched/swait: allow swake_up() to return
KVM: cleanup some users of swake_up()

 arch/x86/kernel/kvm.c |  2 +-
 arch/x86/kvm/lapic.c  |  4 +---
 include/linux/swait.h |  4 ++--
 kernel/sched/swait.c  | 21 ++++++++++++++++-----
 virt/kvm/async_pf.c   |  3 +--
 virt/kvm/kvm_main.c   |  6 +-----
 6 files changed, 22 insertions(+), 18 deletions(-)
Signature · 1 line
2.13.6
author
#1 lore raw

PATCH 1/2 sched/swait: allow swake_up() to return

Let swake_up() to return whether any of the waiters is waked up. One use case of it would be:

  if (swait_active(wq)) {
    swake_up(wq);
    // do something when waiter is waked up
    waked_up++;
  }

Logically it's possible that when reaching swake_up() the wait queue is not active any more, and here doing something like waked_up++ would be inaccurate. To correct it, we need an atomic version of it.

With this patch, we can simply re-write it into:

  if (swake_up(wq)) {
    // do something when waiter is waked up
    waked_up++;
  }

After all we are checking swait_active() inside swake_up() too.

CC Ingo Molnar <[email protected]>
CC Peter Zijlstra <[email protected]>
CC Peter Xu <[email protected]>
---
 include/linux/swait.h |  4 ++--
 kernel/sched/swait.c  | 21 ++++++++++++++++-----
 2 files changed, 18 insertions(+), 7 deletions(-)
include/linux/swait.h +2 -2
index c1f9c62a8a50..c55171280ac8 100644
@@ -84,9 +84,9 @@ static inline int swait_active(struct swait_queue_head *q)
 	return !list_empty(&q->task_list);
 }
 
-extern void swake_up(struct swait_queue_head *q);
+extern bool swake_up(struct swait_queue_head *q);
 extern void swake_up_all(struct swait_queue_head *q);
-extern void swake_up_locked(struct swait_queue_head *q);
+extern bool swake_up_locked(struct swait_queue_head *q);
 
 extern void __prepare_to_swait(struct swait_queue_head *q, struct swait_queue *wait);
 extern void prepare_to_swait(struct swait_queue_head *q, struct swait_queue *wait, int state);
kernel/sched/swait.c +16 -5
index 3d5610dcce11..31f8d677c690 100644
@@ -16,29 +16,40 @@ EXPORT_SYMBOL(__init_swait_queue_head);
  * If for some reason it would return 0, that means the previously waiting
  * task is already running, so it will observe condition true (or has already).
  */
-void swake_up_locked(struct swait_queue_head *q)
+bool swake_up_locked(struct swait_queue_head *q)
 {
 	struct swait_queue *curr;
 
 	if (list_empty(&q->task_list))
-		return;
+		return false;
 
 	curr = list_first_entry(&q->task_list, typeof(*curr), task_list);
 	wake_up_process(curr->task);
 	list_del_init(&curr->task_list);
+	return true;
 }
 EXPORT_SYMBOL(swake_up_locked);
 
-void swake_up(struct swait_queue_head *q)
+/**
+ * swake_up - Wake up one process on the waiting list
+ * @q:        the waitqueue to wake up
+ *
+ * Returns true if some process is waked up, otherwise false if there
+ * is no waiter to wake up.
+ */
+bool swake_up(struct swait_queue_head *q)
 {
+	bool ret;
 	unsigned long flags;
 
 	if (!swait_active(q))
-		return;
+		return false;
 
 	raw_spin_lock_irqsave(&q->lock, flags);
-	swake_up_locked(q);
+	ret = swake_up_locked(q);
 	raw_spin_unlock_irqrestore(&q->lock, flags);
+
+	return ret;
 }
 EXPORT_SYMBOL(swake_up);
 
Signature · 1 line
2.13.6
maintainer
#2 lore raw

Re: [PATCH 1/2] sched/swait: allow swake_up() to return

Quoted 13 lines · Peter Xu

Let swake_up() to return whether any of the waiters is waked up. One use case of it would be:

  if (swait_active(wq)) {
    swake_up(wq);
    // do something when waiter is waked up
    waked_up++;
  }

Logically it's possible that when reaching swake_up() the wait queue is not active any more, and here doing something like waked_up++ would be inaccurate. To correct it, we need an atomic version of it.

Quoted 8 lines

With this patch, we can simply re-write it into:

  if (swake_up(wq)) {
    // do something when waiter is waked up
    waked_up++;
  }

After all we are checking swait_active() inside swake_up() too.

Better subject:

sched/swait: make swake_up() return whether there were any waiters

I like this patch.

Quoted 78 lines
CC Ingo Molnar <[email protected]>
CC Peter Zijlstra <[email protected]>
CC Peter Xu <[email protected]>
---
 include/linux/swait.h |  4 ++--
 kernel/sched/swait.c  | 21 ++++++++++++++++-----
 2 files changed, 18 insertions(+), 7 deletions(-)
include/linux/swait.h +2 -2
index c1f9c62a8a50..c55171280ac8 100644
@@ -84,9 +84,9 @@ static inline int swait_active(struct swait_queue_head *q)
 	return !list_empty(&q->task_list);
 }
 
-extern void swake_up(struct swait_queue_head *q);
+extern bool swake_up(struct swait_queue_head *q);
 extern void swake_up_all(struct swait_queue_head *q);
-extern void swake_up_locked(struct swait_queue_head *q);
+extern bool swake_up_locked(struct swait_queue_head *q);
 
 extern void __prepare_to_swait(struct swait_queue_head *q, struct swait_queue *wait);
 extern void prepare_to_swait(struct swait_queue_head *q, struct swait_queue *wait, int state);
kernel/sched/swait.c +16 -5
index 3d5610dcce11..31f8d677c690 100644
@@ -16,29 +16,40 @@ EXPORT_SYMBOL(__init_swait_queue_head);
  * If for some reason it would return 0, that means the previously waiting
  * task is already running, so it will observe condition true (or has already).
  */
-void swake_up_locked(struct swait_queue_head *q)
+bool swake_up_locked(struct swait_queue_head *q)
 {
 	struct swait_queue *curr;
 
 	if (list_empty(&q->task_list))
-		return;
+		return false;
 
 	curr = list_first_entry(&q->task_list, typeof(*curr), task_list);
 	wake_up_process(curr->task);
 	list_del_init(&curr->task_list);
+	return true;
 }
 EXPORT_SYMBOL(swake_up_locked);
 
-void swake_up(struct swait_queue_head *q)
+/**
+ * swake_up - Wake up one process on the waiting list
+ * @q:        the waitqueue to wake up
+ *
+ * Returns true if some process is waked up, otherwise false if there
+ * is no waiter to wake up.
+ */
+bool swake_up(struct swait_queue_head *q)
 {
+	bool ret;
 	unsigned long flags;
 
 	if (!swait_active(q))
-		return;
+		return false;
 
 	raw_spin_lock_irqsave(&q->lock, flags);
-	swake_up_locked(q);
+	ret = swake_up_locked(q);
 	raw_spin_unlock_irqrestore(&q->lock, flags);
+
+	return ret;
 }
 EXPORT_SYMBOL(swake_up);
 
author
#3 lore raw

Re: [PATCH 1/2] sched/swait: allow swake_up() to return

Quoted 21 lines · Paolo Bonzini
Quoted 20 lines · Peter Xu

Let swake_up() to return whether any of the waiters is waked up. One use case of it would be:

  if (swait_active(wq)) {
    swake_up(wq);
    // do something when waiter is waked up
    waked_up++;
  }

Logically it's possible that when reaching swake_up() the wait queue is not active any more, and here doing something like waked_up++ would be inaccurate. To correct it, we need an atomic version of it.

With this patch, we can simply re-write it into:

  if (swake_up(wq)) {
    // do something when waiter is waked up
    waked_up++;
  }
Quoted 7 lines
Quoted 1 line

After all we are checking swait_active() inside swake_up() too.

Better subject:

sched/swait: make swake_up() return whether there were any waiters

I like this patch.

I'll see how PeterZ would like me to do next, or I can drop this patch and send another clean up which is part of patch 2. Thanks for the positive feedback and commenting. :-)

Signature · 1 line
Peter Xu
maintainer
#4 lore raw

Re: [PATCH 1/2] sched/swait: allow swake_up() to return

In reply to Peter Xu
Quoted 8 lines · Peter Xu

Let swake_up() to return whether any of the waiters is waked up. One use case of it would be:

  if (swait_active(wq)) {
    swake_up(wq);
    // do something when waiter is waked up
    waked_up++;
  }

The word is 'woken', and no that doesn't work. All it says is that there was a waiter, not that you were to one to wake it. Another concurrent wakeup might have done so.

Quoted 5 lines

Logically it's possible that when reaching swake_up() the wait queue is not active any more, and here doing something like waked_up++ would be inaccurate. To correct it, we need an atomic version of it.

Quoted 8 lines

With this patch, we can simply re-write it into:

  if (swake_up(wq)) {
    // do something when waiter is waked up
    waked_up++;
  }

After all we are checking swait_active() inside swake_up() too.

We're not in fact; you've been staring at old code; see commit:

35a2897c2a30 ("sched/wait: Remove the lockless swait_active() check in swake_up*()")

Also, you're changing the interface relative to the regular wait interface. The two should be similar wherever possible.

author
#5 lore raw

Re: [PATCH 1/2] sched/swait: allow swake_up() to return

Quoted 10 lines · Peter Zijlstra
Quoted 8 lines · Peter Xu

Let swake_up() to return whether any of the waiters is waked up. One use case of it would be:

  if (swait_active(wq)) {
    swake_up(wq);
    // do something when waiter is waked up
    waked_up++;
  }
Quoted 3 lines

The word is 'woken', and no that doesn't work. All it says is that there was a waiter, not that you were to one to wake it. Another concurrent wakeup might have done so.

Yes. Or IIUC the waiter can be calling finish_swait() somehow so it removed itself from the list before being woken.

Quoted 13 lines
Quoted 13 lines

Logically it's possible that when reaching swake_up() the wait queue is not active any more, and here doing something like waked_up++ would be inaccurate. To correct it, we need an atomic version of it.

With this patch, we can simply re-write it into:

  if (swake_up(wq)) {
    // do something when waiter is waked up
    waked_up++;
  }
Quoted 5 lines
Quoted 1 line

After all we are checking swait_active() inside swake_up() too.

We're not in fact; you've been staring at old code; see commit:

35a2897c2a30 ("sched/wait: Remove the lockless swait_active() check in swake_up*()")

I thought the tree was new enough, but obviously I was wrong... Thanks for the pointer.

Quoted 4 lines

Also, you're changing the interface relative to the regular wait interface. The two should be similar wherever possible.

Indeed.

I came to this when reading kvm_vcpu_wake_up(), so that only affects some statistic which may not be that critical. However I don't know whether there would be any other real use case that we would like to know exactly whether a call to [s]wake_up() has really done something or just returned with a NOP.

Anyway, please let me know if you think the same change to wake_up() would be meaningful, otherwise I can drop this patch and post another KVM-only one to clean up the redundant callers of swait_active(), since even if we dropped that list check in 35a2897c2a30, we'll do that again in swake_up_locked().

And after knowing 35a2897c2a30, I do think that calling swait_active() before swake_up() is not good since that call is without a lock as well, just like what can happen before 35a2897c2a30.

(I am not 100% sure whether I fully understand the problem mentioned
in 35a2897c2a30, but I think it's the memory barrier in the lock/unlock that matters.)

Thanks,

Signature · 1 line
Peter Xu
maintainer
#6 lore raw

Re: [PATCH 1/2] sched/swait: allow swake_up() to return

Quoted 11 lines · Peter Xu

I came to this when reading kvm_vcpu_wake_up(), so that only affects some statistic which may not be that critical. However I don't know whether there would be any other real use case that we would like to know exactly whether a call to [s]wake_up() has really done something or just returned with a NOP.

Anyway, please let me know if you think the same change to wake_up() would be meaningful, otherwise I can drop this patch and post another KVM-only one to clean up the redundant callers of swait_active(), since even if we dropped that list check in 35a2897c2a30, we'll do that again in swake_up_locked().

See commits:

8cd641e3c7cb ("sched/wait: Add swq_has_sleeper()") 5e0018b3e39e ("kvm: Serialize wq active checks in kvm_vcpu_wake_up()")

In any case, I don't think we want the change you propose. The numbers don't mean much and there's no point in making all the callers in the kernel slower for it.

author
#7 lore raw

Re: [PATCH 1/2] sched/swait: allow swake_up() to return

Quoted 15 lines · Peter Zijlstra
Quoted 11 lines · Peter Xu

I came to this when reading kvm_vcpu_wake_up(), so that only affects some statistic which may not be that critical. However I don't know whether there would be any other real use case that we would like to know exactly whether a call to [s]wake_up() has really done something or just returned with a NOP.

Anyway, please let me know if you think the same change to wake_up() would be meaningful, otherwise I can drop this patch and post another KVM-only one to clean up the redundant callers of swait_active(), since even if we dropped that list check in 35a2897c2a30, we'll do that again in swake_up_locked().

See commits:

Quoted 7 lines

8cd641e3c7cb ("sched/wait: Add swq_has_sleeper()") 5e0018b3e39e ("kvm: Serialize wq active checks in kvm_vcpu_wake_up()")

In any case, I don't think we want the change you propose. The numbers don't mean much and there's no point in making all the callers in the kernel slower for it.

I see. And also we can introduce a new API for that if really needed.

I'll repost with KVM only changes. Thanks for reviewing.

Signature · 1 line
Peter Xu
author
#8 lore raw

Re: [PATCH 1/2] sched/swait: allow swake_up() to return

Quoted 20 lines · Peter Xu
Quoted 19 lines · Peter Zijlstra
Quoted 11 lines · Peter Xu

I came to this when reading kvm_vcpu_wake_up(), so that only affects some statistic which may not be that critical. However I don't know whether there would be any other real use case that we would like to know exactly whether a call to [s]wake_up() has really done something or just returned with a NOP.

Anyway, please let me know if you think the same change to wake_up() would be meaningful, otherwise I can drop this patch and post another KVM-only one to clean up the redundant callers of swait_active(), since even if we dropped that list check in 35a2897c2a30, we'll do that again in swake_up_locked().

See commits:

8cd641e3c7cb ("sched/wait: Add swq_has_sleeper()") 5e0018b3e39e ("kvm: Serialize wq active checks in kvm_vcpu_wake_up()")

Quoted 7 lines
Quoted 3 lines

In any case, I don't think we want the change you propose. The numbers don't mean much and there's no point in making all the callers in the kernel slower for it.

I see. And also we can introduce a new API for that if really needed.

I'll repost with KVM only changes. Thanks for reviewing.

Wait... I see that https://lkml.org/lkml/2017/9/5/622 seems to have fixed all the occurences. So I'll drop the series. Thanks,

Signature · 1 line
Peter Xu
author
#9 lore raw

PATCH 2/2 KVM: cleanup some users of swake_up()

In reply to Peter Xu

Cleanup kvm_vcpu_wake_up() to use the new swake_up() interface, I think kvm_vcpu.stat.halt_wakeup should be more accurate. Meanwhile, touch up some other part of kvm codes to avoid checking swait_active() twice.

---
 arch/x86/kernel/kvm.c | 2 +-
 arch/x86/kvm/lapic.c  | 4 +---
 virt/kvm/async_pf.c   | 3 +--
 virt/kvm/kvm_main.c   | 6 +-----
 4 files changed, 4 insertions(+), 11 deletions(-)
arch/x86/kernel/kvm.c +1 -1
index d04e30e3c0ff..7772a5ba71fd 100644
@@ -180,7 +180,7 @@ static void apf_task_wake_one(struct kvm_task_sleep_node *n)
 	hlist_del_init(&n->link);
 	if (n->halted)
 		smp_send_reschedule(n->cpu);
-	else if (swait_active(&n->wq))
+	else
 		swake_up(&n->wq);
 }
 
arch/x86/kvm/lapic.c +1 -3
index 589dcc117086..e9729f7171d3 100644
@@ -1325,9 +1325,7 @@ static void apic_timer_expired(struct kvm_lapic *apic)
 
 	atomic_inc(&apic->lapic_timer.pending);
 	kvm_set_pending_timer(vcpu);
-
-	if (swait_active(q))
-		swake_up(q);
+	swake_up(q);
 
 	if (apic_lvtt_tscdeadline(apic))
 		ktimer->expired_tscdeadline = ktimer->tscdeadline;
virt/kvm/async_pf.c +1 -2
index bb298a200cd3..e3569751e6e8 100644
@@ -110,8 +110,7 @@ static void async_pf_execute(struct work_struct *work)
 	 * This memory barrier pairs with prepare_to_wait's set_current_state()
 	 */
 	smp_mb();
-	if (swait_active(&vcpu->wq))
-		swake_up(&vcpu->wq);
+	swake_up(&vcpu->wq);
 
 	mmput(mm);
 	kvm_put_kvm(vcpu->kvm);
virt/kvm/kvm_main.c +1 -5
index 4d81f6ded88e..d962db6063dd 100644
@@ -2182,11 +2182,7 @@ EXPORT_SYMBOL_GPL(kvm_vcpu_block);
 
 bool kvm_vcpu_wake_up(struct kvm_vcpu *vcpu)
 {
-	struct swait_queue_head *wqp;
-
-	wqp = kvm_arch_vcpu_wq(vcpu);
-	if (swait_active(wqp)) {
-		swake_up(wqp);
+	if (swake_up(kvm_arch_vcpu_wq(vcpu))) {
 		++vcpu->stat.halt_wakeup;
 		return true;
 	}
Signature · 1 line
2.13.6