From: Joerg Roedel <[email protected]> Implement the KVM_CREATE_VCPU ioctl per plane. Also introduce an empty IOCTL path for the plane-vcpus, including per-architecture call-backs.
Co-developed-by: Carlos López <[email protected]> Signed-off-by: Joerg Roedel <[email protected]> --- arch/arm64/kvm/arm.c | 5 ++ arch/loongarch/kvm/vcpu.c | 5 ++ arch/mips/kvm/mips.c | 5 ++ arch/powerpc/kvm/powerpc.c | 5 ++ arch/riscv/kvm/vcpu.c | 5 ++ arch/s390/kvm/kvm-s390.c | 5 ++ arch/x86/kvm/x86.c | 29 ++++++++++++ include/linux/kvm_host.h | 12 +++-- virt/kvm/kvm_main.c | 97 ++++++++++++++++++++++++++++---------- 9 files changed, 141 insertions(+), 27 deletions(-) diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c index d7a4b9b239dc..b2bfea5df7e0 100644 --- a/arch/arm64/kvm/arm.c +++ b/arch/arm64/kvm/arm.c @@ -1824,6 +1824,11 @@ static int kvm_arm_vcpu_set_events(struct kvm_vcpu *vcpu, return __kvm_arm_vcpu_set_events(vcpu, events); } +bool kvm_arch_is_vcpu_plane_ioctl(unsigned ioctl) +{ + return false; +} + long kvm_arch_vcpu_ioctl(struct file *filp, unsigned int ioctl, unsigned long arg) { diff --git a/arch/loongarch/kvm/vcpu.c b/arch/loongarch/kvm/vcpu.c index bab3c66ae58d..0b66b8186923 100644 --- a/arch/loongarch/kvm/vcpu.c +++ b/arch/loongarch/kvm/vcpu.c @@ -1232,6 +1232,11 @@ static int kvm_loongarch_vcpu_set_attr(struct kvm_vcpu *vcpu, return ret; } +bool kvm_arch_is_vcpu_plane_ioctl(unsigned ioctl) +{ + return false; +} + long kvm_arch_vcpu_ioctl(struct file *filp, unsigned int ioctl, unsigned long arg) { diff --git a/arch/mips/kvm/mips.c b/arch/mips/kvm/mips.c index e22d2a267e03..28795bad178b 100644 --- a/arch/mips/kvm/mips.c +++ b/arch/mips/kvm/mips.c @@ -933,6 +933,11 @@ long kvm_arch_vcpu_unlocked_ioctl(struct file *filp, unsigned int ioctl, return -ENOIOCTLCMD; } +bool kvm_arch_is_vcpu_plane_ioctl(unsigned ioctl) +{ + return false; +} + long kvm_arch_vcpu_ioctl(struct file *filp, unsigned int ioctl, unsigned long arg) { diff --git a/arch/powerpc/kvm/powerpc.c b/arch/powerpc/kvm/powerpc.c index 35658cded0cb..476f7ea02c79 100644 --- a/arch/powerpc/kvm/powerpc.c +++ b/arch/powerpc/kvm/powerpc.c @@ -2055,6 +2055,11 @@ long kvm_arch_vcpu_unlocked_ioctl(struct file *filp, unsigned int ioctl, return -ENOIOCTLCMD; } +bool kvm_arch_is_vcpu_plane_ioctl(unsigned ioctl) +{ + return false; +} + long kvm_arch_vcpu_ioctl(struct file *filp, unsigned int ioctl, unsigned long arg) { diff --git a/arch/riscv/kvm/vcpu.c b/arch/riscv/kvm/vcpu.c index 66cde226eb87..17680b659bdd 100644 --- a/arch/riscv/kvm/vcpu.c +++ b/arch/riscv/kvm/vcpu.c @@ -263,6 +263,11 @@ long kvm_arch_vcpu_unlocked_ioctl(struct file *filp, unsigned int ioctl, return -ENOIOCTLCMD; } +bool kvm_arch_is_vcpu_plane_ioctl(unsigned ioctl) +{ + return false; +} + long kvm_arch_vcpu_ioctl(struct file *filp, unsigned int ioctl, unsigned long arg) { diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c index 94c40b2aa759..261859cb1bb6 100644 --- a/arch/s390/kvm/kvm-s390.c +++ b/arch/s390/kvm/kvm-s390.c @@ -5454,6 +5454,11 @@ static int kvm_s390_handle_pv_vcpu_dump(struct kvm_vcpu *vcpu, return ret; } +bool kvm_arch_is_vcpu_plane_ioctl(unsigned ioctl) +{ + return false; +} + long kvm_arch_vcpu_ioctl(struct file *filp, unsigned int ioctl, unsigned long arg) { diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index d6bf0425525c..623838885753 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -6227,6 +6227,35 @@ static int kvm_get_reg_list(struct kvm_vcpu *vcpu, return 0; } +bool kvm_arch_is_vcpu_plane_ioctl(unsigned ioctl) +{ + switch (ioctl) { + case KVM_GET_DEBUGREGS: + case KVM_SET_DEBUGREGS: + case KVM_GET_LAPIC: + case KVM_SET_LAPIC: + case KVM_GET_MSRS: + case KVM_SET_MSRS: + case KVM_GET_NESTED_STATE: + case KVM_SET_NESTED_STATE: + case KVM_GET_ONE_REG: + case KVM_SET_ONE_REG: + case KVM_GET_SREGS2: + case KVM_SET_SREGS2: + case KVM_GET_VCPU_EVENTS: + case KVM_SET_VCPU_EVENTS: + case KVM_GET_XCRS: + case KVM_SET_XCRS: + case KVM_GET_XSAVE: + case KVM_GET_XSAVE2: + case KVM_SET_XSAVE: + case KVM_GET_REG_LIST: + return true; + default: + return false; + } +} + long kvm_arch_vcpu_ioctl(struct file *filp, unsigned int ioctl, unsigned long arg) { diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h index 385e1ee8fd3a..b8c3f8f11cb4 100644 --- a/include/linux/kvm_host.h +++ b/include/linux/kvm_host.h @@ -1126,7 +1126,7 @@ static inline struct kvm_vcpu *kvm_get_vcpu(struct kvm *kvm, int i) #define kvm_for_each_vcpu(idx, vcpup, kvm) \ plane_for_each_vcpu(idx, vcpup, kvm->planes[0]) -static inline struct kvm_vcpu *kvm_get_vcpu_by_id(struct kvm *kvm, int id) +static inline struct kvm_vcpu *plane_get_vcpu_by_id(struct kvm_plane *plane, int id) { struct kvm_vcpu *vcpu = NULL; unsigned long i; @@ -1134,15 +1134,20 @@ static inline struct kvm_vcpu *kvm_get_vcpu_by_id(struct kvm *kvm, int id) if (id < 0) return NULL; if (id < KVM_MAX_VCPUS) - vcpu = kvm_get_vcpu(kvm, id); + vcpu = plane_get_vcpu(plane, id); if (vcpu && vcpu->vcpu_id == id) return vcpu; - kvm_for_each_vcpu(i, vcpu, kvm) + plane_for_each_vcpu(i, vcpu, plane) if (vcpu->vcpu_id == id) return vcpu; return NULL; } +static inline struct kvm_vcpu *kvm_get_vcpu_by_id(struct kvm *kvm, int id) +{ + return plane_get_vcpu_by_id(kvm->planes[0], id); +} + static inline bool kvm_is_vcpu_creation_in_progress(struct kvm *kvm) { lockdep_assert_held(&kvm->lock); @@ -1688,6 +1693,7 @@ bool kvm_mmu_unmap_gfn_range(struct kvm *kvm, struct kvm_gfn_range *range); long kvm_arch_dev_ioctl(struct file *filp, unsigned int ioctl, unsigned long arg); +bool kvm_arch_is_vcpu_plane_ioctl(unsigned ioctl); long kvm_arch_vcpu_ioctl(struct file *filp, unsigned int ioctl, unsigned long arg); long kvm_arch_vcpu_unlocked_ioctl(struct file *filp, diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index 2d0d5f4fd356..8839f91fd15e 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c @@ -538,14 +538,11 @@ static void kvm_vcpu_init(struct kvm_vcpu *vcpu, struct kvm *kvm, unsigned id) { vcpu->cpu = -1; vcpu->kvm = kvm; - vcpu->plane = kvm->planes[0]; vcpu->vcpu_id = id; kvm_async_pf_vcpu_init(vcpu); vcpu->last_used_slot = NULL; - vcpu->plane_level = 0; - /* Fill the stats id string for the vcpu */ snprintf(vcpu->stats_id, sizeof(vcpu->stats_id), "kvm-%d/vcpu-%d", task_pid_nr(current), id); @@ -4306,9 +4303,13 @@ static struct file_operations kvm_vcpu_fops = { */ static int create_vcpu_fd(struct kvm_vcpu *vcpu) { - char name[8 + 1 + ITOA_MAX_LEN + 1]; + char name[14 + 1 + (2 * ITOA_MAX_LEN) + 1]; + + if (vcpu->plane_level == 0) + snprintf(name, sizeof(name), "kvm-vcpu:%d", vcpu->vcpu_id); + else + snprintf(name, sizeof(name), "kvm-vcpu-plane%d:%d", vcpu->plane_level, vcpu->vcpu_id); - snprintf(name, sizeof(name), "kvm-vcpu:%d", vcpu->vcpu_id); return anon_inode_getfd(name, &kvm_vcpu_fops, vcpu, O_RDWR | O_CLOEXEC); } @@ -4327,13 +4328,17 @@ DEFINE_SIMPLE_ATTRIBUTE(vcpu_get_pid_fops, vcpu_get_pid, NULL, "%llu\n"); static void kvm_create_vcpu_debugfs(struct kvm_vcpu *vcpu) { + char dir_name[10 + (2 * ITOA_MAX_LEN) + 1]; struct dentry *debugfs_dentry; - char dir_name[ITOA_MAX_LEN * 2]; if (!debugfs_initialized()) return; - snprintf(dir_name, sizeof(dir_name), "vcpu%d", vcpu->vcpu_id); + if (vcpu->plane_level == 0) + snprintf(dir_name, sizeof(dir_name), "vcpu%d", vcpu->vcpu_id); + else + snprintf(dir_name, sizeof(dir_name), "vcpu%d-plane%d", vcpu->plane_level, vcpu->vcpu_id); + debugfs_dentry = debugfs_create_dir(dir_name, vcpu->kvm->debugfs_dentry); debugfs_create_file("pid", 0444, debugfs_dentry, vcpu, @@ -4346,10 +4351,11 @@ static void kvm_create_vcpu_debugfs(struct kvm_vcpu *vcpu) /* * Creates some virtual cpus. Good luck creating more than one. */ -static int kvm_vm_ioctl_create_vcpu(struct kvm *kvm, unsigned long id) +static int kvm_plane_ioctl_create_vcpu(struct kvm_plane *plane, unsigned long id) { - int r = -EINVAL; + struct kvm *kvm = plane->kvm; struct kvm_vcpu *vcpu; + int r; mutex_lock(&kvm->lock); if (kvm->created_vcpus >= kvm->max_vcpus) { @@ -4366,11 +4372,28 @@ static int kvm_vm_ioctl_create_vcpu(struct kvm *kvm, unsigned long id) if (!vcpu) return -ENOMEM; - r = kvm_vcpu_init_common(vcpu, kvm, id); - if (r) + r = -EEXIST; + if (plane_get_vcpu_by_id(plane, id)) goto vcpu_free; + if (plane->level > 0) { + struct kvm_vcpu *vcpu_plane0 = kvm_get_vcpu_by_id(kvm, id); + + /* Plane0 VCPU must exist before creating non-plane0 VCPUs */ + r = -EINVAL; + if (vcpu_plane0 == NULL) + goto vcpu_free; + + vcpu->common = vcpu_plane0->common; + } else { + r = kvm_vcpu_init_common(vcpu, kvm, id); + if (r) + goto vcpu_free; + } + vcpu->vcpu_idx = vcpu->common->vcpu_idx; + vcpu->plane = plane; + vcpu->plane_level = plane->level; vcpu->run = vcpu->common->run; kvm_vcpu_init(vcpu, kvm, id); @@ -4381,12 +4404,7 @@ static int kvm_vm_ioctl_create_vcpu(struct kvm *kvm, unsigned long id) mutex_lock(&kvm->lock); - if (kvm_get_vcpu_by_id(kvm, id)) { - r = -EEXIST; - goto unlock_vcpu_destroy; - } - - r = xa_insert(&kvm->planes[0]->vcpu_array, vcpu->vcpu_idx, vcpu, GFP_KERNEL_ACCOUNT); + r = xa_insert(&plane->vcpu_array, vcpu->vcpu_idx, vcpu, GFP_KERNEL_ACCOUNT); WARN_ON_ONCE(r == -EBUSY); if (r) goto unlock_vcpu_destroy; @@ -4416,7 +4434,7 @@ static int kvm_vm_ioctl_create_vcpu(struct kvm *kvm, unsigned long id) kvm_put_xa_erase: kvm_vcpu_unlock(vcpu); kvm_put_kvm_no_destroy(kvm); - xa_erase(&kvm->planes[0]->vcpu_array, vcpu->vcpu_idx); + xa_erase(&plane->vcpu_array, vcpu->vcpu_idx); unlock_vcpu_destroy: mutex_unlock(&kvm->lock); kvm_arch_vcpu_destroy(vcpu); @@ -4550,7 +4568,7 @@ static int kvm_wait_for_vcpu_online(struct kvm_vcpu *vcpu) /* * Acquire and release the vCPU's mutex to wait for vCPU creation to - * complete (kvm_vm_ioctl_create_vcpu() holds the mutex until the vCPU + * complete (kvm_plane_ioctl_create_vcpu() holds the mutex until the vCPU * is fully online). */ if (mutex_lock_killable(kvm_vcpu_mutex(vcpu))) @@ -4564,6 +4582,22 @@ static int kvm_wait_for_vcpu_online(struct kvm_vcpu *vcpu) return 0; } +static inline bool kvm_is_vcpu_plane_ioctl(unsigned ioctl) +{ + switch (ioctl) { + case KVM_GET_FPU: + case KVM_SET_FPU: + case KVM_GET_REGS: + case KVM_SET_REGS: + case KVM_GET_SREGS: + case KVM_SET_SREGS: + case KVM_TRANSLATE: + return true; + default: + return kvm_arch_is_vcpu_plane_ioctl(ioctl); + } +} + static long kvm_vcpu_ioctl(struct file *filp, unsigned int ioctl, unsigned long arg) { @@ -4576,6 +4610,9 @@ static long kvm_vcpu_ioctl(struct file *filp, if (vcpu->kvm->mm != current->mm || vcpu->kvm->vm_dead) return -EIO; + if (vcpu->plane_level > 0 && !kvm_is_vcpu_plane_ioctl(ioctl)) + return -EINVAL; + if (unlikely(_IOC_TYPE(ioctl) != KVMIO)) return -EINVAL; @@ -4858,6 +4895,21 @@ static long kvm_vcpu_compat_ioctl(struct file *filp, } #endif +static long __kvm_plane_ioctl(struct kvm_plane *plane, unsigned int ioctl, unsigned long arg) +{ + long r; + + switch (ioctl) { + case KVM_CREATE_VCPU: + r = kvm_plane_ioctl_create_vcpu(plane, arg); + break; + default: + r = -ENOTTY; + } + + return r; +} + static long kvm_plane_ioctl(struct file *filp, unsigned int ioctl, unsigned long arg) { @@ -4866,10 +4918,7 @@ static long kvm_plane_ioctl(struct file *filp, unsigned int ioctl, if (plane->kvm->mm != current->mm || plane->kvm->vm_dead) return -EIO; - switch (ioctl) { - default: - return -ENOTTY; - } + return __kvm_plane_ioctl(plane, ioctl, arg); } static int kvm_plane_release(struct inode *inode, struct file *filp) @@ -5396,7 +5445,7 @@ static long kvm_vm_ioctl(struct file *filp, r = kvm_vm_ioctl_create_plane(kvm, arg); break; case KVM_CREATE_VCPU: - r = kvm_vm_ioctl_create_vcpu(kvm, arg); + r = __kvm_plane_ioctl(kvm->planes[0], ioctl, arg); break; case KVM_ENABLE_CAP: { struct kvm_enable_cap cap; -- 2.53.0
