From patchwork Mon Mar 9 23:23:50 2009 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Marcelo Tosatti X-Patchwork-Id: 10745 Received: from vger.kernel.org (vger.kernel.org [209.132.176.167]) by demeter.kernel.org (8.14.2/8.14.2) with ESMTP id n29NPWJT030242 for ; Mon, 9 Mar 2009 23:25:32 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752204AbZCIXZc (ORCPT ); Mon, 9 Mar 2009 19:25:32 -0400 Received: (majordomo@vger.kernel.org) by vger.kernel.org id S1751481AbZCIXZc (ORCPT ); Mon, 9 Mar 2009 19:25:32 -0400 Received: from mx2.redhat.com ([66.187.237.31]:33601 "EHLO mx2.redhat.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751223AbZCIXZb (ORCPT ); Mon, 9 Mar 2009 19:25:31 -0400 Received: from int-mx2.corp.redhat.com (int-mx2.corp.redhat.com [172.16.27.26]) by mx2.redhat.com (8.13.8/8.13.8) with ESMTP id n29NP0Hh026850; Mon, 9 Mar 2009 19:25:01 -0400 Received: from ns3.rdu.redhat.com (ns3.rdu.redhat.com [10.11.255.199]) by int-mx2.corp.redhat.com (8.13.1/8.13.1) with ESMTP id n29NOvlB006922; Mon, 9 Mar 2009 19:24:58 -0400 Received: from amt.cnet (vpn-10-104.str.redhat.com [10.32.10.104]) by ns3.rdu.redhat.com (8.13.8/8.13.8) with ESMTP id n29NOsTg006314; Mon, 9 Mar 2009 19:24:56 -0400 Received: from amt.cnet (amt.cnet [127.0.0.1]) by amt.cnet (Postfix) with ESMTP id 5B7BB6801DF; Mon, 9 Mar 2009 20:24:01 -0300 (BRT) Received: (from marcelo@localhost) by amt.cnet (8.14.3/8.14.3/Submit) id n29NNowq006933; Mon, 9 Mar 2009 20:23:50 -0300 Date: Mon, 9 Mar 2009 20:23:50 -0300 From: Marcelo Tosatti To: Avi Kivity , "Zhang, Xiantao" Cc: Ingo Molnar , kvm@vger.kernel.org, Gleb Natapov , Peter Zijlstra Subject: Re: KVM: x86: use smp_send_reschedule in kvm_vcpu_kick Message-ID: <20090309232350.GA6837@amt.cnet> References: <20090303001405.GA5889@amt.cnet> <49B4ECB6.8060505@redhat.com> <20090309105855.GA14242@elte.hu> <1236596946.8389.340.camel@laptop> MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: <1236596946.8389.340.camel@laptop> User-Agent: Mutt/1.5.18 (2008-05-17) X-Scanned-By: MIMEDefang 2.58 on 172.16.27.26 Sender: kvm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org On Mon, Mar 09, 2009 at 12:09:06PM +0100, Peter Zijlstra wrote: > On Mon, 2009-03-09 at 11:58 +0100, Ingo Molnar wrote: > > * Avi Kivity wrote: > > > > > Looks good. The only worry I have is that we depend on > > > smp_reschedule_interrupt() being a no-op. I guess that's a > > > reasonable assumption though. > > > > It's a reasonable current assumption - but it might change in > > the future - so please also put it into the changelog that KVM > > will revert it or fix it differently if the scheduler grows some > > functionality there. > > Alternatively, do something like the below, then anybody poking at that > code will know to prod the KVM folks when they change anything. > > [ I suspect other kvm arches will need to a similar comment ] OK, reworked patch: - change ia64 in addition to x86 - add comment on smp send reschedule handlers about KVM's usage Untested on IA64. KVM: use smp_send_reschedule in kvm_vcpu_kick KVM uses a function call IPI to cause the exit of a guest running on a physical cpu. For virtual interrupt notification there is no need to wait on IPI receival, or to execute any function. This is exactly what the reschedule IPI does, without the overhead of function IPI. So use it instead of smp_call_function_single in kvm_vcpu_kick. Also change the "guest_mode" variable to a bit in vcpu->requests, and use that to collapse multiple IPI's that would be issued between the first one and zeroing of guest mode. This allows kvm_vcpu_kick to called with interrupts disabled. Signed-off-by: Marcelo Tosatti --- To unsubscribe from this list: send the line "unsubscribe kvm" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html diff --git a/arch/ia64/kernel/irq_ia64.c b/arch/ia64/kernel/irq_ia64.c index 28d3d48..0e8242d 100644 --- a/arch/ia64/kernel/irq_ia64.c +++ b/arch/ia64/kernel/irq_ia64.c @@ -607,6 +607,9 @@ static struct irqaction ipi_irqaction = { .name = "IPI" }; +/* + * KVM uses this interrupt to force a cpu out of guest mode + */ static struct irqaction resched_irqaction = { .handler = dummy_handler, .flags = IRQF_DISABLED, diff --git a/arch/ia64/kvm/kvm-ia64.c b/arch/ia64/kvm/kvm-ia64.c index e1984cb..080dcdb 100644 --- a/arch/ia64/kvm/kvm-ia64.c +++ b/arch/ia64/kvm/kvm-ia64.c @@ -633,7 +633,7 @@ again: goto out; } - vcpu->guest_mode = 1; + clear_bit(KVM_REQ_KICK, &vcpu->requests); kvm_guest_enter(); down_read(&vcpu->kvm->slots_lock); r = vti_vcpu_run(vcpu, kvm_run); @@ -645,7 +645,7 @@ again: } vcpu->arch.launched = 1; - vcpu->guest_mode = 0; + set_bit(KVM_REQ_KICK, &vcpu->requests); local_irq_enable(); /* @@ -1802,24 +1802,17 @@ void kvm_arch_hardware_unsetup(void) { } -static void vcpu_kick_intr(void *info) -{ -#ifdef DEBUG - struct kvm_vcpu *vcpu = (struct kvm_vcpu *)info; - printk(KERN_DEBUG"vcpu_kick_intr %p \n", vcpu); -#endif -} - void kvm_vcpu_kick(struct kvm_vcpu *vcpu) { - int ipi_pcpu = vcpu->cpu; - int cpu = get_cpu(); + int me = get_cpu(); + int cpu = vcpu->cpu; if (waitqueue_active(&vcpu->wq)) wake_up_interruptible(&vcpu->wq); - if (vcpu->guest_mode && cpu != ipi_pcpu) - smp_call_function_single(ipi_pcpu, vcpu_kick_intr, vcpu, 0); + 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); put_cpu(); } diff --git a/arch/x86/kernel/smp.c b/arch/x86/kernel/smp.c index e6faa33..ca4fa7f 100644 --- a/arch/x86/kernel/smp.c +++ b/arch/x86/kernel/smp.c @@ -173,6 +173,9 @@ void smp_reschedule_interrupt(struct pt_regs *regs) { ack_APIC_irq(); inc_irq_stat(irq_resched_count); + /* + * KVM uses this interrupt to force a cpu out of guest mode + */ } void smp_call_function_interrupt(struct pt_regs *regs) diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index b556b6a..c68168c 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -3133,6 +3133,9 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) local_irq_disable(); + clear_bit(KVM_REQ_KICK, &vcpu->requests); + smp_mb__after_clear_bit(); + if (vcpu->requests || need_resched() || signal_pending(current)) { local_irq_enable(); preempt_enable(); @@ -3140,13 +3143,6 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) goto out; } - vcpu->guest_mode = 1; - /* - * Make sure that guest_mode assignment won't happen after - * testing the pending IRQ vector bitmap. - */ - smp_wmb(); - if (vcpu->arch.exception.pending) __queue_exception(vcpu); else if (irqchip_in_kernel(vcpu->kvm)) @@ -3188,7 +3184,7 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) set_debugreg(vcpu->arch.host_dr6, 6); set_debugreg(vcpu->arch.host_dr7, 7); - vcpu->guest_mode = 0; + set_bit(KVM_REQ_KICK, &vcpu->requests); local_irq_enable(); ++vcpu->stat.exits; @@ -4429,28 +4425,19 @@ int kvm_arch_vcpu_runnable(struct kvm_vcpu *vcpu) || vcpu->arch.nmi_pending; } -static void vcpu_kick_intr(void *info) -{ -#ifdef DEBUG - struct kvm_vcpu *vcpu = (struct kvm_vcpu *)info; - printk(KERN_DEBUG "vcpu_kick_intr %p \n", vcpu); -#endif -} - void kvm_vcpu_kick(struct kvm_vcpu *vcpu) { - int ipi_pcpu = vcpu->cpu; - int cpu = get_cpu(); + int me = get_cpu(); + int cpu = vcpu->cpu; if (waitqueue_active(&vcpu->wq)) { wake_up_interruptible(&vcpu->wq); ++vcpu->stat.halt_wakeup; } - /* - * We may be called synchronously with irqs disabled in guest mode, - * So need not to call smp_call_function_single() in that case. - */ - if (vcpu->guest_mode && vcpu->cpu != cpu) - smp_call_function_single(ipi_pcpu, vcpu_kick_intr, vcpu, 0); + + 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); + put_cpu(); } diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h index 3b91ec9..4d7da7d 100644 --- a/include/linux/kvm_host.h +++ b/include/linux/kvm_host.h @@ -38,6 +38,7 @@ #define KVM_REQ_UNHALT 6 #define KVM_REQ_MMU_SYNC 7 #define KVM_REQ_KVMCLOCK_UPDATE 8 +#define KVM_REQ_KICK 9 #define KVM_USERSPACE_IRQ_SOURCE_ID 0 @@ -72,7 +73,6 @@ struct kvm_vcpu { struct mutex mutex; int cpu; struct kvm_run *run; - int guest_mode; unsigned long requests; unsigned long guest_debug; int fpu_active;