KVM: s390: return -EFAULT if lowcore is not mapped during irq delivery
authorJens Freimann <jfrei@linux.vnet.ibm.com>
Thu, 17 Apr 2014 08:10:30 +0000 (10:10 +0200)
committerChristian Borntraeger <borntraeger@de.ibm.com>
Mon, 25 Aug 2014 12:35:56 +0000 (14:35 +0200)
Currently we just kill the userspace process and exit the thread
immediatly without making sure that we don't hold any locks etc.

Improve this by making KVM_RUN return -EFAULT if the lowcore is not
mapped during interrupt delivery. To achieve this we need to pass
the return code of guest memory access routines used in interrupt
delivery all the way back to the KVM_RUN ioctl.

Signed-off-by: Jens Freimann <jfrei@linux.vnet.ibm.com>
Reviewed-by: David Hildenbrand <dahi@linux.vnet.ibm.com>
Reviewed-by: Cornelia Huck <cornelia.huck@de.ibm.com>
Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com>
arch/s390/kvm/interrupt.c
arch/s390/kvm/kvm-s390.c
arch/s390/kvm/kvm-s390.h

index 34d741edb50acc2a3eb0f3fe0898279b2d1a49b2..e2f6240584574e7a668d8ac97ae16f21e3758afd 100644 (file)
@@ -28,7 +28,7 @@
 #define IOINT_AI_MASK 0x04000000
 #define PFAULT_INIT 0x0600
 
-static void deliver_ckc_interrupt(struct kvm_vcpu *vcpu);
+static int deliver_ckc_interrupt(struct kvm_vcpu *vcpu);
 
 static int is_ioint(u64 type)
 {
@@ -307,7 +307,7 @@ static int __deliver_prog_irq(struct kvm_vcpu *vcpu,
        return rc;
 }
 
-static void __do_deliver_interrupt(struct kvm_vcpu *vcpu,
+static int __do_deliver_interrupt(struct kvm_vcpu *vcpu,
                                   struct kvm_s390_interrupt_info *inti)
 {
        const unsigned short table[] = { 2, 4, 4, 6 };
@@ -345,7 +345,7 @@ static void __do_deliver_interrupt(struct kvm_vcpu *vcpu,
        case KVM_S390_INT_CLOCK_COMP:
                trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, inti->type,
                                                 inti->ext.ext_params, 0);
-               deliver_ckc_interrupt(vcpu);
+               rc = deliver_ckc_interrupt(vcpu);
                break;
        case KVM_S390_INT_CPU_TIMER:
                trace_kvm_s390_deliver_interrupt(vcpu->vcpu_id, inti->type,
@@ -504,14 +504,11 @@ static void __do_deliver_interrupt(struct kvm_vcpu *vcpu,
        default:
                BUG();
        }
-       if (rc) {
-               printk("kvm: The guest lowcore is not mapped during interrupt "
-                      "delivery, killing userspace\n");
-               do_exit(SIGKILL);
-       }
+
+       return rc;
 }
 
-static void deliver_ckc_interrupt(struct kvm_vcpu *vcpu)
+static int deliver_ckc_interrupt(struct kvm_vcpu *vcpu)
 {
        int rc;
 
@@ -521,11 +518,7 @@ static void deliver_ckc_interrupt(struct kvm_vcpu *vcpu)
        rc |= read_guest_lc(vcpu, __LC_EXT_NEW_PSW,
                            &vcpu->arch.sie_block->gpsw,
                            sizeof(psw_t));
-       if (rc) {
-               printk("kvm: The guest lowcore is not mapped during interrupt "
-                       "delivery, killing userspace\n");
-               do_exit(SIGKILL);
-       }
+       return rc;
 }
 
 /* Check whether SIGP interpretation facility has an external call pending */
@@ -664,12 +657,13 @@ void kvm_s390_clear_local_irqs(struct kvm_vcpu *vcpu)
                          &vcpu->kvm->arch.sca->cpu[vcpu->vcpu_id].ctrl);
 }
 
-void kvm_s390_deliver_pending_interrupts(struct kvm_vcpu *vcpu)
+int kvm_s390_deliver_pending_interrupts(struct kvm_vcpu *vcpu)
 {
        struct kvm_s390_local_interrupt *li = &vcpu->arch.local_int;
        struct kvm_s390_float_interrupt *fi = vcpu->arch.local_int.float_int;
        struct kvm_s390_interrupt_info  *n, *inti = NULL;
        int deliver;
+       int rc = 0;
 
        __reset_intercept_indicators(vcpu);
        if (atomic_read(&li->active)) {
@@ -688,16 +682,16 @@ void kvm_s390_deliver_pending_interrupts(struct kvm_vcpu *vcpu)
                                atomic_set(&li->active, 0);
                        spin_unlock(&li->lock);
                        if (deliver) {
-                               __do_deliver_interrupt(vcpu, inti);
+                               rc = __do_deliver_interrupt(vcpu, inti);
                                kfree(inti);
                        }
-               } while (deliver);
+               } while (!rc && deliver);
        }
 
-       if (kvm_cpu_has_pending_timer(vcpu))
-               deliver_ckc_interrupt(vcpu);
+       if (!rc && kvm_cpu_has_pending_timer(vcpu))
+               rc = deliver_ckc_interrupt(vcpu);
 
-       if (atomic_read(&fi->active)) {
+       if (!rc && atomic_read(&fi->active)) {
                do {
                        deliver = 0;
                        spin_lock(&fi->lock);
@@ -714,11 +708,13 @@ void kvm_s390_deliver_pending_interrupts(struct kvm_vcpu *vcpu)
                                atomic_set(&fi->active, 0);
                        spin_unlock(&fi->lock);
                        if (deliver) {
-                               __do_deliver_interrupt(vcpu, inti);
+                               rc = __do_deliver_interrupt(vcpu, inti);
                                kfree(inti);
                        }
-               } while (deliver);
+               } while (!rc && deliver);
        }
+
+       return rc;
 }
 
 int kvm_s390_inject_program_int(struct kvm_vcpu *vcpu, u16 code)
index 56193becdca59b605d3364b0f0a7fad13239f419..c2caa175320c0199476b91e5bdd5e9a5c35f62ae 100644 (file)
@@ -1198,8 +1198,11 @@ static int vcpu_pre_run(struct kvm_vcpu *vcpu)
        if (test_cpu_flag(CIF_MCCK_PENDING))
                s390_handle_mcck();
 
-       if (!kvm_is_ucontrol(vcpu->kvm))
-               kvm_s390_deliver_pending_interrupts(vcpu);
+       if (!kvm_is_ucontrol(vcpu->kvm)) {
+               rc = kvm_s390_deliver_pending_interrupts(vcpu);
+               if (rc)
+                       return rc;
+       }
 
        rc = kvm_s390_handle_requests(vcpu);
        if (rc)
index 54c25fd5bed6756778a72c7115e9e8acd60a183c..99abcb56e478d88855cdb9548d103458e1f952c9 100644 (file)
@@ -138,7 +138,7 @@ static inline int kvm_s390_user_cpu_state_ctrl(struct kvm *kvm)
 int kvm_s390_handle_wait(struct kvm_vcpu *vcpu);
 void kvm_s390_vcpu_wakeup(struct kvm_vcpu *vcpu);
 enum hrtimer_restart kvm_s390_idle_wakeup(struct hrtimer *timer);
-void kvm_s390_deliver_pending_interrupts(struct kvm_vcpu *vcpu);
+int kvm_s390_deliver_pending_interrupts(struct kvm_vcpu *vcpu);
 void kvm_s390_clear_local_irqs(struct kvm_vcpu *vcpu);
 void kvm_s390_clear_float_irqs(struct kvm *kvm);
 int __must_check kvm_s390_inject_vm(struct kvm *kvm,