KVM: some swait cleanups
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
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.
--- include/linux/swait.h | 4 ++-- kernel/sched/swait.c | 21 ++++++++++++++++----- 2 files changed, 18 insertions(+), 7 deletions(-)
include/linux/swait.h +2 -2
@@ -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
@@ -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
Paolo Bonzini
maintainerRe: [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()insideswake_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]>Signed-off-by 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@@ -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@@ -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);
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()insideswake_up()too.Better subject:
sched/swait: make
swake_up()return whether there were any waitersI 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
Peter Zijlstra
maintainerRe: [PATCH 1/2] sched/swait: allow swake_up() to return
In reply to Peter XuQuoted 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()insideswake_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.
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()insideswake_up()too.We're not in fact; you've been staring at old code; see commit:
35a2897c2a30("sched/wait: Remove the locklessswait_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
Peter Zijlstra
maintainerRe: [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 ofswait_active(), since even if we dropped that list check in35a2897c2a30, we'll do that again inswake_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.
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 ofswait_active(), since even if we dropped that list check in35a2897c2a30, we'll do that again inswake_up_locked().See commits:
Quoted 7 lines
8cd641e3c7cb("sched/wait: Addswq_has_sleeper()")5e0018b3e39e("kvm: Serialize wq active checks inkvm_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
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 ofswait_active(), since even if we dropped that list check in35a2897c2a30, we'll do that again inswake_up_locked().See commits:
8cd641e3c7cb("sched/wait: Addswq_has_sleeper()")5e0018b3e39e("kvm: Serialize wq active checks inkvm_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
PATCH 2/2 KVM: cleanup some users of swake_up()
In reply to Peter XuCleanup 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
@@ -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
@@ -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
@@ -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
@@ -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