6a50f36878
- Add patch to fix KVM sleeping in atomic issue (rhbz 1237143) - Fix errant with_perf disable that removed perf entirely (rhbz 1237266)
81 lines
2.6 KiB
Diff
81 lines
2.6 KiB
Diff
From: Peter Zijlstra <peterz@infradead.org>
|
|
Date: Thu, 25 Jun 2015 14:55:14 +0200
|
|
Subject: [PATCH] sched,kvm: Fix KVM preempt_notifier usage
|
|
|
|
The preempt-notifier API needs to sleep with the addition of the
|
|
static_key, we do however need to hold off preemption while modifying
|
|
the preempt notifier list, otherwise a preemption could observe an
|
|
inconsistent list state.
|
|
|
|
There is no reason to have preemption disabled in the caller,
|
|
registering a preempt notifier is a purely task local affair.
|
|
|
|
Therefore move the preempt_disable into the functions and change the
|
|
callers to a preemptible context.
|
|
|
|
Cc: Gleb Natapov <gleb@kernel.org>
|
|
Fixes: 1cde2930e154 ("sched/preempt: Add static_key() to preempt_notifiers")
|
|
Reported-and-Tested-by: Pontus Fuchs <pontus.fuchs@gmail.com>
|
|
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
|
|
---
|
|
kernel/sched/core.c | 11 +++++++++++
|
|
virt/kvm/kvm_main.c | 5 +++--
|
|
2 files changed, 14 insertions(+), 2 deletions(-)
|
|
|
|
diff --git a/kernel/sched/core.c b/kernel/sched/core.c
|
|
index b803e1b8ab0c..6169c167ac98 100644
|
|
--- a/kernel/sched/core.c
|
|
+++ b/kernel/sched/core.c
|
|
@@ -2327,7 +2327,12 @@ static struct static_key preempt_notifier_key = STATIC_KEY_INIT_FALSE;
|
|
void preempt_notifier_register(struct preempt_notifier *notifier)
|
|
{
|
|
static_key_slow_inc(&preempt_notifier_key);
|
|
+ /*
|
|
+ * Avoid preemption while changing the preempt notifier list.
|
|
+ */
|
|
+ preempt_disable();
|
|
hlist_add_head(¬ifier->link, ¤t->preempt_notifiers);
|
|
+ preempt_enable();
|
|
}
|
|
EXPORT_SYMBOL_GPL(preempt_notifier_register);
|
|
|
|
@@ -2339,7 +2344,13 @@ EXPORT_SYMBOL_GPL(preempt_notifier_register);
|
|
*/
|
|
void preempt_notifier_unregister(struct preempt_notifier *notifier)
|
|
{
|
|
+ /*
|
|
+ * Avoid preemption while changing the preempt notifier list.
|
|
+ */
|
|
+ preempt_disable();
|
|
hlist_del(¬ifier->link);
|
|
+ preempt_enable();
|
|
+
|
|
static_key_slow_dec(&preempt_notifier_key);
|
|
}
|
|
EXPORT_SYMBOL_GPL(preempt_notifier_unregister);
|
|
diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
|
|
index 848af90b8091..7dc8d3eb9e1f 100644
|
|
--- a/virt/kvm/kvm_main.c
|
|
+++ b/virt/kvm/kvm_main.c
|
|
@@ -127,8 +127,9 @@ int vcpu_load(struct kvm_vcpu *vcpu)
|
|
|
|
if (mutex_lock_killable(&vcpu->mutex))
|
|
return -EINTR;
|
|
- cpu = get_cpu();
|
|
preempt_notifier_register(&vcpu->preempt_notifier);
|
|
+
|
|
+ cpu = get_cpu();
|
|
kvm_arch_vcpu_load(vcpu, cpu);
|
|
put_cpu();
|
|
return 0;
|
|
@@ -138,8 +139,8 @@ void vcpu_put(struct kvm_vcpu *vcpu)
|
|
{
|
|
preempt_disable();
|
|
kvm_arch_vcpu_put(vcpu);
|
|
- preempt_notifier_unregister(&vcpu->preempt_notifier);
|
|
preempt_enable();
|
|
+ preempt_notifier_unregister(&vcpu->preempt_notifier);
|
|
mutex_unlock(&vcpu->mutex);
|
|
}
|
|
|