Re: [patch 3/4] KVM: use smp_send_reschedule in kvm_vcpu_kick

2009-05-08 Thread Gleb Natapov
On Thu, May 07, 2009 at 05:55:12PM -0300, mtosa...@redhat.com wrote:
 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 mtosa...@redhat.com
 
Acked-by: Gleb Natapov g...@redhat.com

Except one small nitpick below.
 Index: kvm-pending/arch/x86/kvm/x86.c
 ===
 --- kvm-pending.orig/arch/x86/kvm/x86.c
 +++ kvm-pending/arch/x86/kvm/x86.c
 @@ -3259,6 +3259,9 @@ static int vcpu_enter_guest(struct kvm_v
  
   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();
 @@ -3266,13 +3269,6 @@ static int vcpu_enter_guest(struct kvm_v
   goto out;
   }
  
 - vcpu-guest_mode = 1;
 - /*
 -  * Make sure that guest_mode assignment won't happen after
 -  * testing the pending IRQ vector bitmap.
 -  */
 - smp_wmb();
 -
Can you leave this comment. I like it :)

--
Gleb.
--
To unsubscribe from this list: send the line unsubscribe kvm in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[patch 3/4] KVM: use smp_send_reschedule in kvm_vcpu_kick

2009-05-07 Thread mtosatti
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 mtosa...@redhat.com

Index: kvm-pending/arch/ia64/kernel/irq_ia64.c
===
--- kvm-pending.orig/arch/ia64/kernel/irq_ia64.c
+++ kvm-pending/arch/ia64/kernel/irq_ia64.c
@@ -610,6 +610,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,
Index: kvm-pending/arch/ia64/kvm/kvm-ia64.c
===
--- kvm-pending.orig/arch/ia64/kvm/kvm-ia64.c
+++ kvm-pending/arch/ia64/kvm/kvm-ia64.c
@@ -668,7 +668,7 @@ again:
host_ctx = kvm_get_host_context(vcpu);
guest_ctx = kvm_get_guest_context(vcpu);
 
-   vcpu-guest_mode = 1;
+   clear_bit(KVM_REQ_KICK, vcpu-requests);
 
r = kvm_vcpu_pre_transition(vcpu);
if (r  0)
@@ -685,7 +685,7 @@ again:
kvm_vcpu_post_transition(vcpu);
 
vcpu-arch.launched = 1;
-   vcpu-guest_mode = 0;
+   set_bit(KVM_REQ_KICK, vcpu-requests);
local_irq_enable();
 
/*
@@ -1879,24 +1879,18 @@ 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_DEBUGvcpu_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;
+   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);
+   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);
put_cpu();
 }
 
Index: kvm-pending/arch/x86/kernel/smp.c
===
--- kvm-pending.orig/arch/x86/kernel/smp.c
+++ kvm-pending/arch/x86/kernel/smp.c
@@ -172,6 +172,9 @@ void smp_reschedule_interrupt(struct pt_
 {
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)
Index: kvm-pending/arch/x86/kvm/x86.c
===
--- kvm-pending.orig/arch/x86/kvm/x86.c
+++ kvm-pending/arch/x86/kvm/x86.c
@@ -3259,6 +3259,9 @@ static int vcpu_enter_guest(struct kvm_v
 
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();
@@ -3266,13 +3269,6 @@ static int vcpu_enter_guest(struct kvm_v
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
@@ -3317,7 +3313,7 @@ static int vcpu_enter_guest(struct kvm_v
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;
@@ -4611,30 +4607,20 @@ int kvm_arch_vcpu_runnable(struct kvm_vc
   || 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;
+   int me;
+   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 

[patch 3/4] KVM: use smp_send_reschedule in kvm_vcpu_kick

2009-04-27 Thread mtosatti
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 mtosa...@redhat.com

Index: kvm/arch/ia64/kernel/irq_ia64.c
===
--- kvm.orig/arch/ia64/kernel/irq_ia64.c
+++ kvm/arch/ia64/kernel/irq_ia64.c
@@ -610,6 +610,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,
Index: kvm/arch/ia64/kvm/kvm-ia64.c
===
--- kvm.orig/arch/ia64/kvm/kvm-ia64.c
+++ kvm/arch/ia64/kvm/kvm-ia64.c
@@ -668,7 +668,7 @@ again:
host_ctx = kvm_get_host_context(vcpu);
guest_ctx = kvm_get_guest_context(vcpu);
 
-   vcpu-guest_mode = 1;
+   clear_bit(KVM_REQ_KICK, vcpu-requests);
 
r = kvm_vcpu_pre_transition(vcpu);
if (r  0)
@@ -685,7 +685,7 @@ again:
kvm_vcpu_post_transition(vcpu);
 
vcpu-arch.launched = 1;
-   vcpu-guest_mode = 0;
+   set_bit(KVM_REQ_KICK, vcpu-requests);
local_irq_enable();
 
/*
@@ -1884,24 +1884,18 @@ 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_DEBUGvcpu_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;
+   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);
+   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);
put_cpu();
 }
 
Index: kvm/arch/x86/kernel/smp.c
===
--- kvm.orig/arch/x86/kernel/smp.c
+++ kvm/arch/x86/kernel/smp.c
@@ -172,6 +172,9 @@ void smp_reschedule_interrupt(struct pt_
 {
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)
Index: kvm/arch/x86/kvm/x86.c
===
--- kvm.orig/arch/x86/kvm/x86.c
+++ kvm/arch/x86/kvm/x86.c
@@ -3197,6 +3197,9 @@ static int vcpu_enter_guest(struct kvm_v
 
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();
@@ -3204,13 +3207,6 @@ static int vcpu_enter_guest(struct kvm_v
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))
@@ -3252,7 +3248,7 @@ static int vcpu_enter_guest(struct kvm_v
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;
@@ -4550,30 +4546,20 @@ int kvm_arch_vcpu_runnable(struct kvm_vc
   || 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;
+   int me;
+   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.
-*/
-