KVM: Split out a kvm_vcpu_block() helper from kvm_vcpu_halt()
authorSean Christopherson <seanjc@google.com>
Sat, 9 Oct 2021 02:12:07 +0000 (19:12 -0700)
committerPaolo Bonzini <pbonzini@redhat.com>
Wed, 8 Dec 2021 09:24:51 +0000 (04:24 -0500)
Factor out the "block" part of kvm_vcpu_halt() so that x86 can emulate
non-halt wait/sleep/block conditions that should not be subjected to
halt-polling.

No functional change intended.

Reviewed-by: Christian Borntraeger <borntraeger@de.ibm.com>
Reviewed-by: David Matlack <dmatlack@google.com>
Signed-off-by: Sean Christopherson <seanjc@google.com>
Message-Id: <20211009021236.4122790-15-seanjc@google.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
include/linux/kvm_host.h
virt/kvm/kvm_main.c

index ea3c22d..bd13c5b 100644 (file)
@@ -1103,6 +1103,7 @@ void kvm_sigset_activate(struct kvm_vcpu *vcpu);
 void kvm_sigset_deactivate(struct kvm_vcpu *vcpu);
 
 void kvm_vcpu_halt(struct kvm_vcpu *vcpu);
+bool kvm_vcpu_block(struct kvm_vcpu *vcpu);
 void kvm_arch_vcpu_blocking(struct kvm_vcpu *vcpu);
 void kvm_arch_vcpu_unblocking(struct kvm_vcpu *vcpu);
 bool kvm_vcpu_wake_up(struct kvm_vcpu *vcpu);
index 0d301c9..370b95a 100644 (file)
@@ -3272,6 +3272,35 @@ out:
        return ret;
 }
 
+/*
+ * Block the vCPU until the vCPU is runnable, an event arrives, or a signal is
+ * pending.  This is mostly used when halting a vCPU, but may also be used
+ * directly for other vCPU non-runnable states, e.g. x86's Wait-For-SIPI.
+ */
+bool kvm_vcpu_block(struct kvm_vcpu *vcpu)
+{
+       struct rcuwait *wait = kvm_arch_vcpu_get_wait(vcpu);
+       bool waited = false;
+
+       kvm_arch_vcpu_blocking(vcpu);
+
+       prepare_to_rcuwait(wait);
+       for (;;) {
+               set_current_state(TASK_INTERRUPTIBLE);
+
+               if (kvm_vcpu_check_block(vcpu) < 0)
+                       break;
+
+               waited = true;
+               schedule();
+       }
+       finish_rcuwait(wait);
+
+       kvm_arch_vcpu_unblocking(vcpu);
+
+       return waited;
+}
+
 static inline void update_halt_poll_stats(struct kvm_vcpu *vcpu, ktime_t start,
                                          ktime_t end, bool success)
 {
@@ -3294,9 +3323,14 @@ static inline void update_halt_poll_stats(struct kvm_vcpu *vcpu, ktime_t start,
        }
 }
 
+/*
+ * Emulate a vCPU halt condition, e.g. HLT on x86, WFI on arm, etc...  If halt
+ * polling is enabled, busy wait for a short time before blocking to avoid the
+ * expensive block+unblock sequence if a wake event arrives soon after the vCPU
+ * is halted.
+ */
 void kvm_vcpu_halt(struct kvm_vcpu *vcpu)
 {
-       struct rcuwait *wait = kvm_arch_vcpu_get_wait(vcpu);
        bool halt_poll_allowed = !kvm_arch_no_poll(vcpu);
        bool do_halt_poll = halt_poll_allowed && vcpu->halt_poll_ns;
        ktime_t start, cur, poll_end;
@@ -3319,21 +3353,7 @@ void kvm_vcpu_halt(struct kvm_vcpu *vcpu)
                } while (kvm_vcpu_can_poll(cur, stop));
        }
 
-       kvm_arch_vcpu_blocking(vcpu);
-
-       prepare_to_rcuwait(wait);
-       for (;;) {
-               set_current_state(TASK_INTERRUPTIBLE);
-
-               if (kvm_vcpu_check_block(vcpu) < 0)
-                       break;
-
-               waited = true;
-               schedule();
-       }
-       finish_rcuwait(wait);
-
-       kvm_arch_vcpu_unblocking(vcpu);
+       waited = kvm_vcpu_block(vcpu);
 
        cur = ktime_get();
        if (waited) {