[S390] s390-kvm: leave sie context on work. Removes preemption requirement
Christian Borntraeger [Wed, 7 May 2008 07:22:53 +0000 (09:22 +0200)]
From: Martin Schwidefsky <schwidefsky@de.ibm.com>

This patch fixes a bug with cpu bound guest on kvm-s390. Sometimes it
was impossible to deliver a signal to a spinning guest. We used
preemption as a circumvention. The preemption notifiers called
vcpu_load, which checked for pending signals and triggered a host
intercept. But even with preemption, a sigkill was not delivered
immediately.

This patch changes the low level host interrupt handler to check for the
SIE  instruction, if TIF_WORK is set. In that case we change the
instruction pointer of the return PSW to rerun the vcpu_run loop. The kvm
code sees an intercept reason 0 if that happens. This patch adds accounting
for these types of intercept as well.

The advantages:
- works with and without preemption
- signals are delivered immediately
- much better host latencies without preemption

Acked-by: Carsten Otte <cotte@de.ibm.com>
Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>

arch/s390/kernel/entry64.S
arch/s390/kvm/Kconfig
arch/s390/kvm/intercept.c
arch/s390/kvm/kvm-s390.c
include/asm-s390/kvm_host.h

index a57909d..fee1017 100644 (file)
@@ -607,14 +607,37 @@ io_restore_trace_psw:
 #endif
 
 #
-# switch to kernel stack, then check TIF bits
+# There is work todo, we need to check if we return to userspace, then
+# check, if we are in SIE, if yes leave it
 #
 io_work:
        tm      SP_PSW+1(%r15),0x01     # returning to user ?
 #ifndef CONFIG_PREEMPT
+#if defined(CONFIG_KVM) || defined(CONFIG_KVM_MODULE)
+       jnz     io_work_user            # yes -> no need to check for SIE
+       la      %r1, BASED(sie_opcode)  # we return to kernel here
+       lg      %r2, SP_PSW+8(%r15)
+       clc     0(2,%r1), 0(%r2)        # is current instruction = SIE?
+       jne     io_restore              # no-> return to kernel
+       lg      %r1, SP_PSW+8(%r15)     # yes-> add 4 bytes to leave SIE
+       aghi    %r1, 4
+       stg     %r1, SP_PSW+8(%r15)
+       j       io_restore              # return to kernel
+#else
        jno     io_restore              # no-> skip resched & signal
+#endif
 #else
        jnz     io_work_user            # yes -> do resched & signal
+#if defined(CONFIG_KVM) || defined(CONFIG_KVM_MODULE)
+       la      %r1, BASED(sie_opcode)
+       lg      %r2, SP_PSW+8(%r15)
+       clc     0(2,%r1), 0(%r2)        # is current instruction = SIE?
+       jne     0f                      # no -> leave PSW alone
+       lg      %r1, SP_PSW+8(%r15)     # yes-> add 4 bytes to leave SIE
+       aghi    %r1, 4
+       stg     %r1, SP_PSW+8(%r15)
+0:
+#endif
        # check for preemptive scheduling
        icm     %r0,15,__TI_precount(%r9)
        jnz     io_restore              # preemption is disabled
@@ -652,6 +675,11 @@ io_work_loop:
        j       io_restore
 io_work_done:
 
+#if defined(CONFIG_KVM) || defined(CONFIG_KVM_MODULE)
+sie_opcode:
+       .long 0xb2140000
+#endif
+
 #
 # _TIF_MCCK_PENDING is set, call handler
 #
index 1761b74..e051cad 100644 (file)
@@ -22,7 +22,6 @@ config KVM
        select PREEMPT_NOTIFIERS
        select ANON_INODES
        select S390_SWITCH_AMODE
-       select PREEMPT
        ---help---
          Support hosting paravirtualized guest machines using the SIE
          virtualization capability on the mainframe. This should work
index 349581a..47a0b64 100644 (file)
@@ -105,6 +105,9 @@ static intercept_handler_t instruction_handlers[256] = {
 static int handle_noop(struct kvm_vcpu *vcpu)
 {
        switch (vcpu->arch.sie_block->icptcode) {
+       case 0x0:
+               vcpu->stat.exit_null++;
+               break;
        case 0x10:
                vcpu->stat.exit_external_request++;
                break;
index 98d1e73..0ac36a6 100644 (file)
@@ -31,6 +31,7 @@
 
 struct kvm_stats_debugfs_item debugfs_entries[] = {
        { "userspace_handled", VCPU_STAT(exit_userspace) },
+       { "exit_null", VCPU_STAT(exit_null) },
        { "exit_validity", VCPU_STAT(exit_validity) },
        { "exit_stop_request", VCPU_STAT(exit_stop_request) },
        { "exit_external_request", VCPU_STAT(exit_external_request) },
@@ -221,10 +222,6 @@ void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
        vcpu->arch.guest_fpregs.fpc &= FPC_VALID_MASK;
        restore_fp_regs(&vcpu->arch.guest_fpregs);
        restore_access_regs(vcpu->arch.guest_acrs);
-
-       if (signal_pending(current))
-               atomic_set_mask(CPUSTAT_STOP_INT,
-                       &vcpu->arch.sie_block->cpuflags);
 }
 
 void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu)
index f8204a4..18cbd8a 100644 (file)
@@ -104,6 +104,7 @@ struct sie_block {
 
 struct kvm_vcpu_stat {
        u32 exit_userspace;
+       u32 exit_null;
        u32 exit_external_request;
        u32 exit_external_interrupt;
        u32 exit_stop_request;