Merge tag 'kvm-arm-for-v4.16' of git://git.kernel.org/pub/scm/linux/kernel/git/kvmarm...
[sfrench/cifs-2.6.git] / virt / kvm / arm / arm.c
index 639dca0c056090aec0266fe663331a19e263c5eb..92b95ae9a2ca04b5a474201e0908d265973b1959 100644 (file)
@@ -295,6 +295,9 @@ void kvm_arch_vcpu_postcreate(struct kvm_vcpu *vcpu)
 
 void kvm_arch_vcpu_free(struct kvm_vcpu *vcpu)
 {
+       if (vcpu->arch.has_run_once && unlikely(!irqchip_in_kernel(vcpu->kvm)))
+               static_branch_dec(&userspace_irqchip_in_use);
+
        kvm_mmu_free_memory_caches(vcpu);
        kvm_timer_vcpu_terminate(vcpu);
        kvm_pmu_vcpu_destroy(vcpu);
@@ -304,8 +307,6 @@ void kvm_arch_vcpu_free(struct kvm_vcpu *vcpu)
 
 void kvm_arch_vcpu_destroy(struct kvm_vcpu *vcpu)
 {
-       if (vcpu->arch.has_run_once && unlikely(!irqchip_in_kernel(vcpu->kvm)))
-               static_branch_dec(&userspace_irqchip_in_use);
        kvm_arch_vcpu_free(vcpu);
 }
 
@@ -383,17 +384,24 @@ static void vcpu_power_off(struct kvm_vcpu *vcpu)
 int kvm_arch_vcpu_ioctl_get_mpstate(struct kvm_vcpu *vcpu,
                                    struct kvm_mp_state *mp_state)
 {
+       vcpu_load(vcpu);
+
        if (vcpu->arch.power_off)
                mp_state->mp_state = KVM_MP_STATE_STOPPED;
        else
                mp_state->mp_state = KVM_MP_STATE_RUNNABLE;
 
+       vcpu_put(vcpu);
        return 0;
 }
 
 int kvm_arch_vcpu_ioctl_set_mpstate(struct kvm_vcpu *vcpu,
                                    struct kvm_mp_state *mp_state)
 {
+       int ret = 0;
+
+       vcpu_load(vcpu);
+
        switch (mp_state->mp_state) {
        case KVM_MP_STATE_RUNNABLE:
                vcpu->arch.power_off = false;
@@ -402,10 +410,11 @@ int kvm_arch_vcpu_ioctl_set_mpstate(struct kvm_vcpu *vcpu,
                vcpu_power_off(vcpu);
                break;
        default:
-               return -EINVAL;
+               ret = -EINVAL;
        }
 
-       return 0;
+       vcpu_put(vcpu);
+       return ret;
 }
 
 /**
@@ -629,21 +638,27 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run)
        if (unlikely(!kvm_vcpu_initialized(vcpu)))
                return -ENOEXEC;
 
+       vcpu_load(vcpu);
+
        ret = kvm_vcpu_first_run_init(vcpu);
        if (ret)
-               return ret;
+               goto out;
 
        if (run->exit_reason == KVM_EXIT_MMIO) {
                ret = kvm_handle_mmio_return(vcpu, vcpu->run);
                if (ret)
-                       return ret;
-               if (kvm_arm_handle_step_debug(vcpu, vcpu->run))
-                       return 0;
+                       goto out;
+               if (kvm_arm_handle_step_debug(vcpu, vcpu->run)) {
+                       ret = 0;
+                       goto out;
+               }
 
        }
 
-       if (run->immediate_exit)
-               return -EINTR;
+       if (run->immediate_exit) {
+               ret = -EINTR;
+               goto out;
+       }
 
        kvm_sigset_activate(vcpu);
 
@@ -795,6 +810,8 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run)
 
        kvm_sigset_deactivate(vcpu);
 
+out:
+       vcpu_put(vcpu);
        return ret;
 }
 
@@ -1010,66 +1027,88 @@ long kvm_arch_vcpu_ioctl(struct file *filp,
        struct kvm_vcpu *vcpu = filp->private_data;
        void __user *argp = (void __user *)arg;
        struct kvm_device_attr attr;
+       long r;
+
+       vcpu_load(vcpu);
 
        switch (ioctl) {
        case KVM_ARM_VCPU_INIT: {
                struct kvm_vcpu_init init;
 
+               r = -EFAULT;
                if (copy_from_user(&init, argp, sizeof(init)))
-                       return -EFAULT;
+                       break;
 
-               return kvm_arch_vcpu_ioctl_vcpu_init(vcpu, &init);
+               r = kvm_arch_vcpu_ioctl_vcpu_init(vcpu, &init);
+               break;
        }
        case KVM_SET_ONE_REG:
        case KVM_GET_ONE_REG: {
                struct kvm_one_reg reg;
 
+               r = -ENOEXEC;
                if (unlikely(!kvm_vcpu_initialized(vcpu)))
-                       return -ENOEXEC;
+                       break;
 
+               r = -EFAULT;
                if (copy_from_user(&reg, argp, sizeof(reg)))
-                       return -EFAULT;
+                       break;
+
                if (ioctl == KVM_SET_ONE_REG)
-                       return kvm_arm_set_reg(vcpu, &reg);
+                       r = kvm_arm_set_reg(vcpu, &reg);
                else
-                       return kvm_arm_get_reg(vcpu, &reg);
+                       r = kvm_arm_get_reg(vcpu, &reg);
+               break;
        }
        case KVM_GET_REG_LIST: {
                struct kvm_reg_list __user *user_list = argp;
                struct kvm_reg_list reg_list;
                unsigned n;
 
+               r = -ENOEXEC;
                if (unlikely(!kvm_vcpu_initialized(vcpu)))
-                       return -ENOEXEC;
+                       break;
 
+               r = -EFAULT;
                if (copy_from_user(&reg_list, user_list, sizeof(reg_list)))
-                       return -EFAULT;
+                       break;
                n = reg_list.n;
                reg_list.n = kvm_arm_num_regs(vcpu);
                if (copy_to_user(user_list, &reg_list, sizeof(reg_list)))
-                       return -EFAULT;
+                       break;
+               r = -E2BIG;
                if (n < reg_list.n)
-                       return -E2BIG;
-               return kvm_arm_copy_reg_indices(vcpu, user_list->reg);
+                       break;
+               r = kvm_arm_copy_reg_indices(vcpu, user_list->reg);
+               break;
        }
        case KVM_SET_DEVICE_ATTR: {
+               r = -EFAULT;
                if (copy_from_user(&attr, argp, sizeof(attr)))
-                       return -EFAULT;
-               return kvm_arm_vcpu_set_attr(vcpu, &attr);
+                       break;
+               r = kvm_arm_vcpu_set_attr(vcpu, &attr);
+               break;
        }
        case KVM_GET_DEVICE_ATTR: {
+               r = -EFAULT;
                if (copy_from_user(&attr, argp, sizeof(attr)))
-                       return -EFAULT;
-               return kvm_arm_vcpu_get_attr(vcpu, &attr);
+                       break;
+               r = kvm_arm_vcpu_get_attr(vcpu, &attr);
+               break;
        }
        case KVM_HAS_DEVICE_ATTR: {
+               r = -EFAULT;
                if (copy_from_user(&attr, argp, sizeof(attr)))
-                       return -EFAULT;
-               return kvm_arm_vcpu_has_attr(vcpu, &attr);
+                       break;
+               r = kvm_arm_vcpu_has_attr(vcpu, &attr);
+               break;
        }
        default:
-               return -EINVAL;
+               r = -EINVAL;
        }
+
+       vcpu_put(vcpu);
+       return r;
 }
 
 /**