KVM: x86: Convert tsc_write_lock to raw_spinlock
PATCH 1/1 KVM: x86: Convert tsc_write_lock to raw_spinlock
Code under this lock requires non-preemptibility. Ensure this also over -rt by converting it to raw spinlock.
--- arch/x86/include/asm/kvm_host.h | 2 +- arch/x86/kvm/x86.c | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-)
arch/x86/include/asm/kvm_host.h +1 -1
@@ -448,7 +448,7 @@ struct kvm_arch {unsigned long irq_sources_bitmap;s64 kvmclock_offset; -spinlock_t tsc_write_lock; +raw_spinlock_t tsc_write_lock;u64 last_tsc_nsec;u64 last_tsc_offset;u64 last_tsc_write;
arch/x86/kvm/x86.c +3 -3
@@ -1017,7 +1017,7 @@ void kvm_write_tsc(struct kvm_vcpu *vcpu, u64 data)unsigned long flags;s64 sdiff; -spin_lock_irqsave (&kvm->arch.tsc_write_lock, flags); +raw_spin_lock_irqsave (&kvm->arch.tsc_write_lock, flags); offset = data -native_read_tsc (); ns =get_kernel_ns (); elapsed = ns - kvm->arch.last_tsc_nsec;
@@ -1050,7 +1050,7 @@ void kvm_write_tsc(struct kvm_vcpu *vcpu, u64 data) kvm->arch.last_tsc_write = data; kvm->arch.last_tsc_offset = offset; kvm_x86_ops->write_tsc_offset (vcpu, offset); -spin_unlock_irqrestore (&kvm->arch.tsc_write_lock, flags); +raw_spin_unlock_irqrestore (&kvm->arch.tsc_write_lock, flags);/* Reset of TSC must disable overshoot protection below */ vcpu->arch.hv_clock.tsc_timestamp =0 ;
@@ -6009,7 +6009,7 @@ int kvm_arch_init_vm(struct kvm *kvm)/* Reserve bit 0 of irq_sources_bitmap for userspace irq source */ set_bit (KVM_USERSPACE_IRQ_SOURCE_ID , &kvm->arch.irq_sources_bitmap); -spin_lock_init (&kvm->arch.tsc_write_lock); +raw_spin_lock_init (&kvm->arch.tsc_write_lock);return 0 ; }
Signature · 1 line
1.7.1
Quoted 3 lines · Jan Kiszka
Code under this lock requires non-preemptibility. Ensure this also over -rt by converting it to raw spinlock.
Oh dear, I had forgotten about that. I believe kvm_lock might have the same assumption in a few places regarding clock.
Quoted 7 lines · Zachary Amsden
Quoted 3 lines · Jan Kiszka
Code under this lock requires non-preemptibility. Ensure this also over -rt by converting it to raw spinlock.
Oh dear, I had forgotten about that. I believe
kvm_lockmight have the same assumption in a few places regarding clock.
I only found a problematic section in kvmclock_cpufreq_notifier. Didn't see this during my tests as I have CPUFREQ disabled in my .config.
We may need something like this as converting kvm_lock would likely be overkill:
arch/x86/kvm/x86.c +4 -2
@@ -4530,7 +4530,7 @@ static int kvmclock_cpufreq_notifier(struct notifier_block *nb, unsigned long vastruct cpufreq_freqs *freq = data;struct kvm *kvm;struct kvm_vcpu *vcpu; -int i, send_ipi =0 ; +int i, me, send_ipi =0 ;/* * We allow guests to temporarily run on slowing clocks,
@@ -4583,9 +4583,11 @@ static int kvmclock_cpufreq_notifier(struct notifier_block *nb, unsigned long vakvm_for_each_vcpu (i, vcpu, kvm) {if (vcpu->cpu != freq->cpu)continue ; + me =get_cpu ();kvm_make_request (KVM_REQ_CLOCK_UPDATE , vcpu); -if (vcpu->cpu !=smp_processor_id ()) +if (vcpu->cpu != me) send_ipi =1 ; +put_cpu (); } }spin_unlock (&kvm_lock);
Jan
Signature · 2 lines
Siemens AG, Corporate Technology, CT T DE IT 1 Corporate Competence Center Embedded Linux
Quoted 44 lines · Jan Kiszka
Quoted 9 lines · Zachary Amsden
Quoted 4 lines · Jan Kiszka
Code under this lock requires non-preemptibility. Ensure this also over -rt by converting it to raw spinlock.
Oh dear, I had forgotten about that. I believe
kvm_lockmight have the same assumption in a few places regarding clock.I only found a problematic section in
kvmclock_cpufreq_notifier. Didn't see this during my tests as I have CPUFREQ disabled in my .config.We may need something like this as converting
kvm_lockwould likely be overkill:arch/x86/kvm/x86.c +4
-2@@ -4530,7 +4530,7 @@ static int kvmclock_cpufreq_notifier(struct notifier_block *nb, unsigned long vastruct cpufreq_freqs *freq = data;struct kvm *kvm;struct kvm_vcpu *vcpu; -int i, send_ipi =0 ; +int i, me, send_ipi =0 ;/* * We allow guests to temporarily run on slowing clocks, @@ -4583,9 +4583,11 @@ static int kvmclock_cpufreq_notifier(struct notifier_block *nb, unsigned long vakvm_for_each_vcpu (i, vcpu, kvm) {if (vcpu->cpu != freq->cpu)continue ; + me =get_cpu ();kvm_make_request (KVM_REQ_CLOCK_UPDATE , vcpu); -if (vcpu->cpu !=smp_processor_id ()) +if (vcpu->cpu != me) send_ipi =1 ; +put_cpu (); } }spin_unlock (&kvm_lock);
Quoted 3 lines
Jan
That looks like a good solution, and I do believe that is the only place the lock is used in that fashion - please add a comment though in the giant comment block above that preemption protection is needed for RT. Also, gcc should catch this, but moving the me variable into the kvm_for_each_vcpu loop should allow for better register allocation.
The only other thing I can think of is that RT lock preemption may break some of the CPU initialization semantics enforced by kvm_lock if you happen to get a hotplug event just as the module is loading. That should be rare, but if it is indeed a bug, it would be nice to fix, it would be a panic for sure not to initialize VMX.
Cheers,
Zach
Quoted 55 lines · Zachary Amsden
Quoted 44 lines · Jan Kiszka
Quoted 9 lines · Zachary Amsden
Quoted 4 lines · Jan Kiszka
Code under this lock requires non-preemptibility. Ensure this also over -rt by converting it to raw spinlock.
Oh dear, I had forgotten about that. I believe
kvm_lockmight have the same assumption in a few places regarding clock.I only found a problematic section in
kvmclock_cpufreq_notifier. Didn't see this during my tests as I have CPUFREQ disabled in my .config.We may need something like this as converting
kvm_lockwould likely be overkill:arch/x86/kvm/x86.c +4
-2@@ -4530,7 +4530,7 @@ static int kvmclock_cpufreq_notifier(struct notifier_block *nb, unsigned long vastruct cpufreq_freqs *freq = data;struct kvm *kvm;struct kvm_vcpu *vcpu; -int i, send_ipi =0 ; +int i, me, send_ipi =0 ;/* * We allow guests to temporarily run on slowing clocks, @@ -4583,9 +4583,11 @@ static int kvmclock_cpufreq_notifier(struct notifier_block *nb, unsigned long vakvm_for_each_vcpu (i, vcpu, kvm) {if (vcpu->cpu != freq->cpu)continue ; + me =get_cpu ();kvm_make_request (KVM_REQ_CLOCK_UPDATE , vcpu); -if (vcpu->cpu !=smp_processor_id ()) +if (vcpu->cpu != me) send_ipi =1 ; +put_cpu (); } }spin_unlock (&kvm_lock);Quoted 3 lines
Jan
That looks like a good solution, and I do believe that is the only place the lock is used in that fashion - please add a comment though in the giant comment block above that preemption protection is needed for RT. Also, gcc should catch this, but moving the me variable into the
kvm_for_each_vcpuloop should allow for better register allocation.
Quoted 5 lines
The only other thing I can think of is that RT lock preemption may break some of the CPU initialization semantics enforced by
kvm_lockif you happen to get a hotplug event just as the module is loading. That should be rare, but if it is indeed a bug, it would be nice to fix, it would be a panic for sure not to initialize VMX.
Hmm, is a cpu hotplug notifier allowed to run sleepy code? Can't imagine. So we already have a strong reason to convert kvm_lock to a raw_spinlock which obsoletes the above workaround.
Jan
Signature · 2 lines
Siemens AG, Corporate Technology, CT T DE IT 1 Corporate Competence Center Embedded Linux
Quoted 68 lines · Jan Kiszka
Quoted 60 lines · Zachary Amsden
Quoted 48 lines · Jan Kiszka
Quoted 12 lines · Zachary Amsden
Quoted 5 lines · Jan Kiszka
Code under this lock requires non-preemptibility. Ensure this also over -rt by converting it to raw spinlock.
Oh dear, I had forgotten about that. I believe
kvm_lockmight have the same assumption in a few places regarding clock.I only found a problematic section in
kvmclock_cpufreq_notifier. Didn't see this during my tests as I have CPUFREQ disabled in my .config.We may need something like this as converting
kvm_lockwould likely be overkill:arch/x86/kvm/x86.c +4
-2@@ -4530,7 +4530,7 @@ static int kvmclock_cpufreq_notifier(struct notifier_block *nb, unsigned long vastruct cpufreq_freqs *freq = data;struct kvm *kvm;struct kvm_vcpu *vcpu; -int i, send_ipi =0 ; +int i, me, send_ipi =0 ;/* * We allow guests to temporarily run on slowing clocks, @@ -4583,9 +4583,11 @@ static int kvmclock_cpufreq_notifier(struct notifier_block *nb, unsigned long vakvm_for_each_vcpu (i, vcpu, kvm) {if (vcpu->cpu != freq->cpu)continue ; + me =get_cpu ();kvm_make_request (KVM_REQ_CLOCK_UPDATE , vcpu); -if (vcpu->cpu !=smp_processor_id ()) +if (vcpu->cpu != me) send_ipi =1 ; +put_cpu (); } }spin_unlock (&kvm_lock);Quoted 4 lines
Jan
That looks like a good solution, and I do believe that is the only place the lock is used in that fashion - please add a comment though in the giant comment block above that preemption protection is needed for RT. Also, gcc should catch this, but moving the me variable into the
kvm_for_each_vcpuloop should allow for better register allocation.Quoted 6 lines
The only other thing I can think of is that RT lock preemption may break some of the CPU initialization semantics enforced by
kvm_lockif you happen to get a hotplug event just as the module is loading. That should be rare, but if it is indeed a bug, it would be nice to fix, it would be a panic for sure not to initialize VMX.
Quoted 4 lines
Hmm, is a cpu hotplug notifier allowed to run sleepy code? Can't imagine. So we already have a strong reason to convert
kvm_lockto araw_spinlockwhich obsoletes the above workaround.
I don't know as it is allowed to sleep, it doesn't call any sleeping functions to my knowledge. What worries me in the RT case is that the spinlock acquired for hardware_enable might be preempted and run on another CPU, which obviously isn't what you want.
Zach
Quoted 74 lines · Zachary Amsden
Quoted 68 lines · Jan Kiszka
Quoted 60 lines · Zachary Amsden
Quoted 48 lines · Jan Kiszka
Quoted 12 lines · Zachary Amsden
Quoted 5 lines · Jan Kiszka
Code under this lock requires non-preemptibility. Ensure this also over -rt by converting it to raw spinlock.
Oh dear, I had forgotten about that. I believe
kvm_lockmight have the same assumption in a few places regarding clock.I only found a problematic section in
kvmclock_cpufreq_notifier. Didn't see this during my tests as I have CPUFREQ disabled in my .config.We may need something like this as converting
kvm_lockwould likely be overkill:arch/x86/kvm/x86.c +4
-2@@ -4530,7 +4530,7 @@ static int kvmclock_cpufreq_notifier(struct notifier_block *nb, unsigned long vastruct cpufreq_freqs *freq = data;struct kvm *kvm;struct kvm_vcpu *vcpu; -int i, send_ipi =0 ; +int i, me, send_ipi =0 ;/* * We allow guests to temporarily run on slowing clocks, @@ -4583,9 +4583,11 @@ static int kvmclock_cpufreq_notifier(struct notifier_block *nb, unsigned long vakvm_for_each_vcpu (i, vcpu, kvm) {if (vcpu->cpu != freq->cpu)continue ; + me =get_cpu ();kvm_make_request (KVM_REQ_CLOCK_UPDATE , vcpu); -if (vcpu->cpu !=smp_processor_id ()) +if (vcpu->cpu != me) send_ipi =1 ; +put_cpu (); } }spin_unlock (&kvm_lock);Quoted 4 lines
Jan
That looks like a good solution, and I do believe that is the only place the lock is used in that fashion - please add a comment though in the giant comment block above that preemption protection is needed for RT. Also, gcc should catch this, but moving the me variable into the
kvm_for_each_vcpuloop should allow for better register allocation.Quoted 6 lines
The only other thing I can think of is that RT lock preemption may break some of the CPU initialization semantics enforced by
kvm_lockif you happen to get a hotplug event just as the module is loading. That should be rare, but if it is indeed a bug, it would be nice to fix, it would be a panic for sure not to initialize VMX.Quoted 4 lines
Hmm, is a cpu hotplug notifier allowed to run sleepy code? Can't imagine. So we already have a strong reason to convert
kvm_lockto araw_spinlockwhich obsoletes the above workaround.
Quoted 4 lines
I don't know as it is allowed to sleep, it doesn't call any sleeping functions to my knowledge. What worries me in the RT case is that the spinlock acquired for
hardware_enablemight be preempted and run on another CPU, which obviously isn't what you want.
I see now, there are calls to raw_smp_processor_id.
I think it's best to make this a raw lock. At this chance, some read-only users of vm_list should be rcu'ified. Will have a look.
Jan
Signature · 2 lines
Siemens AG, Corporate Technology, CT T DE IT 1 Corporate Competence Center Embedded Linux
Quoted 10 lines · Jan Kiszka
Quoted 5 lines
I don't know as it is allowed to sleep, it doesn't call any sleeping functions to my knowledge. What worries me in the RT case is that the spinlock acquired for
hardware_enablemight be preempted and run on another CPU, which obviously isn't what you want.I see now, there are calls to
raw_smp_processor_id.I think it's best to make this a raw lock. At this chance, some read-only users of
vm_listshould be rcu'ified. Will have a look.
vm_list is rarely used, for either read or write. I don't see the need to rcu it.
Signature · 1 line
error compiling committee.c: too many arguments to function
Quoted 7 lines · Avi Kivity
Quoted 6 lines · Jan Kiszka
Quoted 5 lines
I don't know as it is allowed to sleep, it doesn't call any sleeping functions to my knowledge. What worries me in the RT case is that the spinlock acquired for
hardware_enablemight be preempted and run on another CPU, which obviously isn't what you want.
Quoted 7 lines
Quoted 4 lines
I see now, there are calls to
raw_smp_processor_id.I think it's best to make this a raw lock. At this chance, some read-only users of
vm_listshould be rcu'ified. Will have a look.
vm_listis rarely used, for either read or write. I don't see the need to rcu it.
Avoid that code under this lock expands the preempt-disabled period, specifically under -rt, and specifically as the number of objects over which we loop is user-defined.
Jan
Signature · 2 lines
Siemens AG, Corporate Technology, CT T DE IT 1 Corporate Competence Center Embedded Linux
Quoted 13 lines · Jan Kiszka
Quoted 12 lines · Avi Kivity
Quoted 10 lines · Jan Kiszka
Quoted 5 lines
I don't know as it is allowed to sleep, it doesn't call any sleeping functions to my knowledge. What worries me in the RT case is that the spinlock acquired for
hardware_enablemight be preempted and run on another CPU, which obviously isn't what you want.I see now, there are calls to
raw_smp_processor_id.I think it's best to make this a raw lock. At this chance, some read-only users of
vm_listshould be rcu'ified. Will have a look.
Quoted 6 lines
Quoted 2 lines
vm_listis rarely used, for either read or write. I don't see the need to rcu it.Avoid that code under this lock expands the preempt-disabled period, specifically under -rt, and specifically as the number of objects over which we loop is user-defined.
Good point; even under non-rt.
(well, actually, cpufreq_notifier and kvm_arch_hardware_enable are already non preemptible, and the stats code should just go away?)
Signature · 1 line
error compiling committee.c: too many arguments to function
Quoted 17 lines · Avi Kivity
Quoted 16 lines · Jan Kiszka
Quoted 14 lines · Avi Kivity
Quoted 10 lines · Jan Kiszka
Quoted 5 lines
I don't know as it is allowed to sleep, it doesn't call any sleeping functions to my knowledge. What worries me in the RT case is that the spinlock acquired for
hardware_enablemight be preempted and run on another CPU, which obviously isn't what you want.I see now, there are calls to
raw_smp_processor_id.I think it's best to make this a raw lock. At this chance, some read-only users of
vm_listshould be rcu'ified. Will have a look.
vm_listis rarely used, for either read or write. I don't see the need to rcu it.
Quoted 8 lines
Quoted 3 lines
Avoid that code under this lock expands the preempt-disabled period, specifically under -rt, and specifically as the number of objects over which we loop is user-defined.
Good point; even under non-rt.
(well, actually,
cpufreq_notifierandkvm_arch_hardware_enableare already non preemptible, and the stats code should just go away?)
The stats code is trivial to convert, so it doesn't matter.
But what about mmu_shrink and its list_move_tail? How is this synchronized against kvm_destroy_vm - already today?
Jan
Signature · 2 lines
Siemens AG, Corporate Technology, CT T DE IT 1 Corporate Competence Center Embedded Linux
Quoted 5 lines · Jan Kiszka
Quoted 3 lines
(well, actually,
cpufreq_notifierandkvm_arch_hardware_enableare already non preemptible, and the stats code should just go away?)The stats code is trivial to convert, so it doesn't matter.
Removal is easier.
Quoted 2 lines
But what about
mmu_shrinkand itslist_move_tail? How is this synchronized againstkvm_destroy_vm- already today?
kvm_destroy_vm() takes kvm_lock. If a vm is destroyed before mmu_shrink(), mmu_shrink() will never see it. If we reach mmu_shrink() before kvm_destroy_vm(), the latter will wait until mmu_shrink() is done.
Signature · 1 line
error compiling committee.c: too many arguments to function
Quoted 8 lines · Avi Kivity
Quoted 5 lines · Jan Kiszka
Quoted 3 lines
(well, actually,
cpufreq_notifierandkvm_arch_hardware_enableare already non preemptible, and the stats code should just go away?)The stats code is trivial to convert, so it doesn't matter.
Removal is easier.
Is that stat interface no longer used?
Quoted 8 lines
Quoted 3 lines
But what about
mmu_shrinkand itslist_move_tail? How is this synchronized againstkvm_destroy_vm- already today?
kvm_destroy_vm()takeskvm_lock. If a vm is destroyed beforemmu_shrink(),mmu_shrink()will never see it. If we reachmmu_shrink()beforekvm_destroy_vm(), the latter will wait untilmmu_shrink()is done.
Ah, I was confused. Would require some more logic if we wanted to make the loop lock-less, though.
Jan
Signature · 2 lines
Siemens AG, Corporate Technology, CT T DE IT 1 Corporate Competence Center Embedded Linux
Quoted 11 lines · Jan Kiszka
Quoted 8 lines · Avi Kivity
Quoted 5 lines · Jan Kiszka
Quoted 3 lines
(well, actually,
cpufreq_notifierandkvm_arch_hardware_enableare already non preemptible, and the stats code should just go away?)The stats code is trivial to convert, so it doesn't matter.
Removal is easier.
Is that stat interface no longer used?
It's there for compatibility. I'm itching to remove it. See qemu-kvm.git/kvm/kvm_stat for the only known user, and for the replacement via tracepoints.
Tracepoints have marginally lower overhead when disabled, and somewhat higher overhead when enabled. A disadvantage of tracepoints is that it is harder to associate an event with a vm when that event is triggered by a workqueue, but I don't think it matters in practice (kvm_stat doesn't even provide a per-vm breakdown).
Quoted 11 lines
Quoted 8 lines
Quoted 3 lines
But what about
mmu_shrinkand itslist_move_tail? How is this synchronized againstkvm_destroy_vm- already today?
kvm_destroy_vm()takeskvm_lock. If a vm is destroyed beforemmu_shrink(),mmu_shrink()will never see it. If we reachmmu_shrink()beforekvm_destroy_vm(), the latter will wait untilmmu_shrink()is done.Ah, I was confused. Would require some more logic if we wanted to make the loop lock-less, though.
Yes, the usual rcu_read_lock() / grab reference / rcu_read_unlock().
Signature · 1 line
error compiling committee.c: too many arguments to function
Quoted 9 lines · Avi Kivity
Quoted 8 lines · Jan Kiszka
Quoted 7 lines · Avi Kivity
Quoted 5 lines · Jan Kiszka
Quoted 3 lines
(well, actually,
cpufreq_notifierandkvm_arch_hardware_enableare already non preemptible, and the stats code should just go away?)The stats code is trivial to convert, so it doesn't matter.
Quoted 7 lines
Quoted 3 lines
Quoted 1 line
Removal is easier.
Is that stat interface no longer used?
It's there for compatibility. I'm itching to remove it. See qemu-kvm.git/kvm/kvm_stat for the only known user, and for the replacement via tracepoints.
OK, but that will first take a grace period.
Quoted 6 lines
Tracepoints have marginally lower overhead when disabled, and somewhat higher overhead when enabled. A disadvantage of tracepoints is that it is harder to associate an event with a vm when that event is triggered by a workqueue, but I don't think it matters in practice (
kvm_statdoesn't even provide a per-vm breakdown).
What about using the perf infrastructure for this? Besides that perf can reuse tracepoints, maybe there is even a more efficient way of added new stat sources.
Jan
Signature · 2 lines
Siemens AG, Corporate Technology, CT T DE IT 1 Corporate Competence Center Embedded Linux
Quoted 10 lines · Jan Kiszka
Quoted 6 lines
Tracepoints have marginally lower overhead when disabled, and somewhat higher overhead when enabled. A disadvantage of tracepoints is that it is harder to associate an event with a vm when that event is triggered by a workqueue, but I don't think it matters in practice (
kvm_statdoesn't even provide a per-vm breakdown).What about using the perf infrastructure for this? Besides that perf can reuse tracepoints, maybe there is even a more efficient way of added new stat sources.
We are using the perf infrastructure for this (using tracepoints).
Signature · 1 line
error compiling committee.c: too many arguments to function
Avi Kivity
AppliedQuoted 2 lines · Jan Kiszka
Code under this lock requires non-preemptibility. Ensure this also over -rt by converting it to raw spinlock.
Applied, thanks.
Signature · 1 line
error compiling committee.c: too many arguments to function