diff mbox series

KVM: x86:Cancel hrtimer in the process of saving PIT state to reduce the performance overhead caused by hrtimer during guest stop.

Message ID 20250317091917.72477-1-liamni-oc@zhaoxin.com (mailing list archive)
State New
Headers show
Series KVM: x86:Cancel hrtimer in the process of saving PIT state to reduce the performance overhead caused by hrtimer during guest stop. | expand

Commit Message

Liam Ni March 17, 2025, 9:19 a.m. UTC
When using the dump-guest-memory command in QEMU to dump
the virtual machine's memory,the virtual machine will be
paused for a period of time.If the guest (i.e., UEFI) uses
the PIT as the system clock,it will be observed that the
HRTIMER used by the PIT continues to run during the guest
stop process, imposing an additional burden on the system.
Moreover, during the guest restart process,the previously
established HRTIMER will be canceled,and the accumulated
timer events will be flushed.However, before the old
HRTIMER is canceled,the accumulated timer events
will "surreptitiously" inject interrupts into the guest.

SO during the process of saving the KVM PIT state,
the HRTIMER need to be canceled to reduce the performance overhead
caused by HRTIMER during the guest stop process.

i.e. if guest

Signed-off-by: Liam Ni <liamni-oc@zhaoxin.com>
---
 arch/x86/kvm/x86.c | 4 ++++
 1 file changed, 4 insertions(+)

Comments

Sean Christopherson March 17, 2025, 1:38 p.m. UTC | #1
On Mon, Mar 17, 2025, Liam Ni wrote:
> When using the dump-guest-memory command in QEMU to dump
> the virtual machine's memory,the virtual machine will be
> paused for a period of time.If the guest (i.e., UEFI) uses
> the PIT as the system clock,it will be observed that the
> HRTIMER used by the PIT continues to run during the guest
> stop process, imposing an additional burden on the system.
> Moreover, during the guest restart process,the previously
> established HRTIMER will be canceled,and the accumulated
> timer events will be flushed.However, before the old
> HRTIMER is canceled,the accumulated timer events
> will "surreptitiously" inject interrupts into the guest.
> 
> SO during the process of saving the KVM PIT state,
> the HRTIMER need to be canceled to reduce the performance overhead
> caused by HRTIMER during the guest stop process.
> 
> i.e. if guest
> 
> Signed-off-by: Liam Ni <liamni-oc@zhaoxin.com>
> ---
>  arch/x86/kvm/x86.c | 4 ++++
>  1 file changed, 4 insertions(+)
> 
> diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
> index 045c61cc7e54..75355b315aca 100644
> --- a/arch/x86/kvm/x86.c
> +++ b/arch/x86/kvm/x86.c
> @@ -6405,6 +6405,8 @@ static int kvm_vm_ioctl_get_pit(struct kvm *kvm, struct kvm_pit_state *ps)
>  
>  	mutex_lock(&kps->lock);
>  	memcpy(ps, &kps->channels, sizeof(*ps));
> +	hrtimer_cancel(&kvm->arch.vpit->pit_state.timer);
> +	kthread_flush_work(&kvm->arch.vpit->expired);

KVM cannot assume userspace wants to stop the PIT when grabbing a snapshot.  It's
a significant ABI change, and not desirable in all cases.

>  	mutex_unlock(&kps->lock);
>  	return 0;
>  }
> @@ -6428,6 +6430,8 @@ static int kvm_vm_ioctl_get_pit2(struct kvm *kvm, struct kvm_pit_state2 *ps)
>  	memcpy(ps->channels, &kvm->arch.vpit->pit_state.channels,
>  		sizeof(ps->channels));
>  	ps->flags = kvm->arch.vpit->pit_state.flags;
> +	hrtimer_cancel(&kvm->arch.vpit->pit_state.timer);
> +	kthread_flush_work(&kvm->arch.vpit->expired);
>  	mutex_unlock(&kvm->arch.vpit->pit_state.lock);
>  	memset(&ps->reserved, 0, sizeof(ps->reserved));
>  	return 0;
> -- 
> 2.25.1
>
diff mbox series

Patch

diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 045c61cc7e54..75355b315aca 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -6405,6 +6405,8 @@  static int kvm_vm_ioctl_get_pit(struct kvm *kvm, struct kvm_pit_state *ps)
 
 	mutex_lock(&kps->lock);
 	memcpy(ps, &kps->channels, sizeof(*ps));
+	hrtimer_cancel(&kvm->arch.vpit->pit_state.timer);
+	kthread_flush_work(&kvm->arch.vpit->expired);
 	mutex_unlock(&kps->lock);
 	return 0;
 }
@@ -6428,6 +6430,8 @@  static int kvm_vm_ioctl_get_pit2(struct kvm *kvm, struct kvm_pit_state2 *ps)
 	memcpy(ps->channels, &kvm->arch.vpit->pit_state.channels,
 		sizeof(ps->channels));
 	ps->flags = kvm->arch.vpit->pit_state.flags;
+	hrtimer_cancel(&kvm->arch.vpit->pit_state.timer);
+	kthread_flush_work(&kvm->arch.vpit->expired);
 	mutex_unlock(&kvm->arch.vpit->pit_state.lock);
 	memset(&ps->reserved, 0, sizeof(ps->reserved));
 	return 0;