Split KVM_REQ_KICKED in two bits: KVM_VCPU_KICKED, to indicate whether a vcpu has been IPI'ed, and KVM_VCPU_GUEST_MODE, in a separate vcpu_state variable. Unify remote requests with kvm_vcpu_kick. Synchronous requests wait on KVM_VCPU_GUEST_MODE, via wait_on_bit/wake_up_bit. Signed-off-by: Marcelo Tosatti <mtosatti@xxxxxxxxxx> Index: kvm/arch/x86/kvm/x86.c =================================================================== --- kvm.orig/arch/x86/kvm/x86.c +++ kvm/arch/x86/kvm/x86.c @@ -3586,11 +3586,14 @@ static int vcpu_enter_guest(struct kvm_v local_irq_disable(); - clear_bit(KVM_REQ_KICK, &vcpu->requests); - smp_mb__after_clear_bit(); + set_bit(KVM_VCPU_GUEST_MODE, &vcpu->vcpu_state); + barrier(); if (vcpu->requests || need_resched() || signal_pending(current)) { - set_bit(KVM_REQ_KICK, &vcpu->requests); + clear_bit(KVM_VCPU_KICKED, &vcpu->vcpu_state); + clear_bit(KVM_VCPU_GUEST_MODE, &vcpu->vcpu_state); + smp_mb__after_clear_bit(); + wake_up_bit(&vcpu->vcpu_state, KVM_VCPU_GUEST_MODE); local_irq_enable(); preempt_enable(); r = 1; @@ -3642,7 +3645,10 @@ static int vcpu_enter_guest(struct kvm_v set_debugreg(vcpu->arch.host_dr6, 6); set_debugreg(vcpu->arch.host_dr7, 7); - set_bit(KVM_REQ_KICK, &vcpu->requests); + clear_bit(KVM_VCPU_KICKED, &vcpu->vcpu_state); + clear_bit(KVM_VCPU_GUEST_MODE, &vcpu->vcpu_state); + smp_mb__after_clear_bit(); + wake_up_bit(&vcpu->vcpu_state, KVM_VCPU_GUEST_MODE); local_irq_enable(); ++vcpu->stat.exits; Index: kvm/include/linux/kvm_host.h =================================================================== --- kvm.orig/include/linux/kvm_host.h +++ kvm/include/linux/kvm_host.h @@ -42,6 +42,9 @@ #define KVM_USERSPACE_IRQ_SOURCE_ID 0 +#define KVM_VCPU_GUEST_MODE 0 +#define KVM_VCPU_KICKED 1 + struct kvm; struct kvm_vcpu; extern struct kmem_cache *kvm_vcpu_cache; @@ -83,6 +86,7 @@ struct kvm_vcpu { int cpu; struct kvm_run *run; unsigned long requests; + unsigned long vcpu_state; unsigned long guest_debug; int fpu_active; int guest_fpu_loaded; @@ -362,6 +366,7 @@ void kvm_arch_sync_events(struct kvm *kv int kvm_cpu_has_pending_timer(struct kvm_vcpu *vcpu); void kvm_vcpu_kick(struct kvm_vcpu *vcpu); +void kvm_vcpu_ipi(struct kvm_vcpu *vcpu); int kvm_is_mmio_pfn(pfn_t pfn); Index: kvm/virt/kvm/kvm_main.c =================================================================== --- kvm.orig/virt/kvm/kvm_main.c +++ kvm/virt/kvm/kvm_main.c @@ -119,18 +119,26 @@ void vcpu_put(struct kvm_vcpu *vcpu) void kvm_vcpu_kick(struct kvm_vcpu *vcpu) { - int me; - int cpu = vcpu->cpu; - if (waitqueue_active(&vcpu->wq)) { wake_up_interruptible(&vcpu->wq); ++vcpu->stat.halt_wakeup; } + kvm_vcpu_ipi(vcpu); +} + +void kvm_vcpu_ipi(struct kvm_vcpu *vcpu) +{ + int me; + int cpu = vcpu->cpu; me = get_cpu(); - if (cpu != me && (unsigned)cpu < nr_cpu_ids && cpu_online(cpu)) - if (!test_and_set_bit(KVM_REQ_KICK, &vcpu->requests)) - smp_send_reschedule(cpu); + if (cpu != me && (unsigned)cpu < nr_cpu_ids && cpu_online(cpu)) { + if (test_bit(KVM_VCPU_GUEST_MODE, &vcpu->vcpu_state)) { + if (!test_and_set_bit(KVM_VCPU_KICKED, + &vcpu->vcpu_state)) + smp_send_reschedule(cpu); + } + } put_cpu(); } @@ -168,6 +176,30 @@ static bool make_all_cpus_request(struct return called; } +static int kvm_req_wait(void *unused) +{ + cpu_relax(); + return 0; +} + +static void kvm_vcpu_request(struct kvm_vcpu *vcpu, unsigned int req) +{ + set_bit(req, &vcpu->requests); + barrier(); + kvm_vcpu_ipi(vcpu); + wait_on_bit(&vcpu->vcpu_state, KVM_VCPU_GUEST_MODE, kvm_req_wait, + TASK_UNINTERRUPTIBLE); +} + +static void kvm_vcpus_request(struct kvm *kvm, unsigned int req) +{ + int i; + struct kvm_vcpu *vcpu; + + kvm_for_each_vcpu(i, vcpu, kvm) + kvm_vcpu_request(vcpu, req); +} + void kvm_flush_remote_tlbs(struct kvm *kvm) { if (make_all_cpus_request(kvm, KVM_REQ_TLB_FLUSH)) Index: kvm/arch/ia64/kvm/kvm-ia64.c =================================================================== --- kvm.orig/arch/ia64/kvm/kvm-ia64.c +++ kvm/arch/ia64/kvm/kvm-ia64.c @@ -655,12 +655,13 @@ again: host_ctx = kvm_get_host_context(vcpu); guest_ctx = kvm_get_guest_context(vcpu); - clear_bit(KVM_REQ_KICK, &vcpu->requests); - r = kvm_vcpu_pre_transition(vcpu); if (r < 0) goto vcpu_run_fail; + set_bit(KVM_VCPU_GUEST_MODE, &vcpu->vcpu_state); + barrier(); + up_read(&vcpu->kvm->slots_lock); kvm_guest_enter(); @@ -672,7 +673,10 @@ again: kvm_vcpu_post_transition(vcpu); vcpu->arch.launched = 1; - set_bit(KVM_REQ_KICK, &vcpu->requests); + clear_bit(KVM_VCPU_KICKED, &vcpu->vcpu_state); + clear_bit(KVM_VCPU_GUEST_MODE, &vcpu->vcpu_state); + smp_mb__after_clear_bit(); + wake_up_bit(&vcpu->vcpu_state, KVM_VCPU_GUEST_MODE); local_irq_enable(); /* -- -- To unsubscribe from this list: send the line "unsubscribe kvm" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html