KVM: introduce kvm_arch_vcpu_async_ioctl
After the vcpu_load/vcpu_put pushdown, the handling of asynchronous VCPU ioctl is already much clearer in that it is obvious that they bypass vcpu_load and vcpu_put. However, it is still not perfect in that the different state of the VCPU mutex is still hidden in the caller. Separate those ioctls into a new function kvm_arch_vcpu_async_ioctl that returns -ENOIOCTLCMD for more "traditional" synchronous ioctls. Cc: James Hogan <jhogan@kernel.org> Cc: Paul Mackerras <paulus@ozlabs.org> Cc: Christian Borntraeger <borntraeger@de.ibm.com> Reviewed-by: Christoffer Dall <christoffer.dall@linaro.org> Reviewed-by: Cornelia Huck <cohuck@redhat.com> Suggested-by: Cornelia Huck <cohuck@redhat.com> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
This commit is contained in:
parent
9b062471e5
commit
5cb0944c0c
|
@ -22,6 +22,7 @@ config KVM
|
||||||
select PREEMPT_NOTIFIERS
|
select PREEMPT_NOTIFIERS
|
||||||
select ANON_INODES
|
select ANON_INODES
|
||||||
select KVM_GENERIC_DIRTYLOG_READ_PROTECT
|
select KVM_GENERIC_DIRTYLOG_READ_PROTECT
|
||||||
|
select HAVE_KVM_VCPU_ASYNC_IOCTL
|
||||||
select KVM_MMIO
|
select KVM_MMIO
|
||||||
select MMU_NOTIFIER
|
select MMU_NOTIFIER
|
||||||
select SRCU
|
select SRCU
|
||||||
|
|
|
@ -903,12 +903,11 @@ static int kvm_vcpu_ioctl_enable_cap(struct kvm_vcpu *vcpu,
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
long kvm_arch_vcpu_ioctl(struct file *filp, unsigned int ioctl,
|
long kvm_arch_vcpu_async_ioctl(struct file *filp, unsigned int ioctl,
|
||||||
unsigned long arg)
|
unsigned long arg)
|
||||||
{
|
{
|
||||||
struct kvm_vcpu *vcpu = filp->private_data;
|
struct kvm_vcpu *vcpu = filp->private_data;
|
||||||
void __user *argp = (void __user *)arg;
|
void __user *argp = (void __user *)arg;
|
||||||
long r;
|
|
||||||
|
|
||||||
if (ioctl == KVM_INTERRUPT) {
|
if (ioctl == KVM_INTERRUPT) {
|
||||||
struct kvm_mips_interrupt irq;
|
struct kvm_mips_interrupt irq;
|
||||||
|
@ -921,6 +920,16 @@ long kvm_arch_vcpu_ioctl(struct file *filp, unsigned int ioctl,
|
||||||
return kvm_vcpu_ioctl_interrupt(vcpu, &irq);
|
return kvm_vcpu_ioctl_interrupt(vcpu, &irq);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return -ENOIOCTLCMD;
|
||||||
|
}
|
||||||
|
|
||||||
|
long kvm_arch_vcpu_ioctl(struct file *filp, unsigned int ioctl,
|
||||||
|
unsigned long arg)
|
||||||
|
{
|
||||||
|
struct kvm_vcpu *vcpu = filp->private_data;
|
||||||
|
void __user *argp = (void __user *)arg;
|
||||||
|
long r;
|
||||||
|
|
||||||
vcpu_load(vcpu);
|
vcpu_load(vcpu);
|
||||||
|
|
||||||
switch (ioctl) {
|
switch (ioctl) {
|
||||||
|
|
|
@ -22,6 +22,7 @@ config KVM
|
||||||
select PREEMPT_NOTIFIERS
|
select PREEMPT_NOTIFIERS
|
||||||
select ANON_INODES
|
select ANON_INODES
|
||||||
select HAVE_KVM_EVENTFD
|
select HAVE_KVM_EVENTFD
|
||||||
|
select HAVE_KVM_VCPU_ASYNC_IOCTL
|
||||||
select SRCU
|
select SRCU
|
||||||
select KVM_VFIO
|
select KVM_VFIO
|
||||||
select IRQ_BYPASS_MANAGER
|
select IRQ_BYPASS_MANAGER
|
||||||
|
|
|
@ -1607,12 +1607,11 @@ int kvm_arch_vcpu_ioctl_set_mpstate(struct kvm_vcpu *vcpu,
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
long kvm_arch_vcpu_ioctl(struct file *filp,
|
long kvm_arch_vcpu_async_ioctl(struct file *filp,
|
||||||
unsigned int ioctl, unsigned long arg)
|
unsigned int ioctl, unsigned long arg)
|
||||||
{
|
{
|
||||||
struct kvm_vcpu *vcpu = filp->private_data;
|
struct kvm_vcpu *vcpu = filp->private_data;
|
||||||
void __user *argp = (void __user *)arg;
|
void __user *argp = (void __user *)arg;
|
||||||
long r;
|
|
||||||
|
|
||||||
if (ioctl == KVM_INTERRUPT) {
|
if (ioctl == KVM_INTERRUPT) {
|
||||||
struct kvm_interrupt irq;
|
struct kvm_interrupt irq;
|
||||||
|
@ -1620,6 +1619,15 @@ long kvm_arch_vcpu_ioctl(struct file *filp,
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
return kvm_vcpu_ioctl_interrupt(vcpu, &irq);
|
return kvm_vcpu_ioctl_interrupt(vcpu, &irq);
|
||||||
}
|
}
|
||||||
|
return -ENOIOCTLCMD;
|
||||||
|
}
|
||||||
|
|
||||||
|
long kvm_arch_vcpu_ioctl(struct file *filp,
|
||||||
|
unsigned int ioctl, unsigned long arg)
|
||||||
|
{
|
||||||
|
struct kvm_vcpu *vcpu = filp->private_data;
|
||||||
|
void __user *argp = (void __user *)arg;
|
||||||
|
long r;
|
||||||
|
|
||||||
vcpu_load(vcpu);
|
vcpu_load(vcpu);
|
||||||
|
|
||||||
|
|
|
@ -23,6 +23,7 @@ config KVM
|
||||||
select PREEMPT_NOTIFIERS
|
select PREEMPT_NOTIFIERS
|
||||||
select ANON_INODES
|
select ANON_INODES
|
||||||
select HAVE_KVM_CPU_RELAX_INTERCEPT
|
select HAVE_KVM_CPU_RELAX_INTERCEPT
|
||||||
|
select HAVE_KVM_VCPU_ASYNC_IOCTL
|
||||||
select HAVE_KVM_EVENTFD
|
select HAVE_KVM_EVENTFD
|
||||||
select KVM_ASYNC_PF
|
select KVM_ASYNC_PF
|
||||||
select KVM_ASYNC_PF_SYNC
|
select KVM_ASYNC_PF_SYNC
|
||||||
|
|
|
@ -3725,13 +3725,11 @@ static long kvm_s390_guest_mem_op(struct kvm_vcpu *vcpu,
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
long kvm_arch_vcpu_ioctl(struct file *filp,
|
long kvm_arch_vcpu_async_ioctl(struct file *filp,
|
||||||
unsigned int ioctl, unsigned long arg)
|
unsigned int ioctl, unsigned long arg)
|
||||||
{
|
{
|
||||||
struct kvm_vcpu *vcpu = filp->private_data;
|
struct kvm_vcpu *vcpu = filp->private_data;
|
||||||
void __user *argp = (void __user *)arg;
|
void __user *argp = (void __user *)arg;
|
||||||
int idx;
|
|
||||||
long r;
|
|
||||||
|
|
||||||
switch (ioctl) {
|
switch (ioctl) {
|
||||||
case KVM_S390_IRQ: {
|
case KVM_S390_IRQ: {
|
||||||
|
@ -3752,6 +3750,16 @@ long kvm_arch_vcpu_ioctl(struct file *filp,
|
||||||
return kvm_s390_inject_vcpu(vcpu, &s390irq);
|
return kvm_s390_inject_vcpu(vcpu, &s390irq);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return -ENOIOCTLCMD;
|
||||||
|
}
|
||||||
|
|
||||||
|
long kvm_arch_vcpu_ioctl(struct file *filp,
|
||||||
|
unsigned int ioctl, unsigned long arg)
|
||||||
|
{
|
||||||
|
struct kvm_vcpu *vcpu = filp->private_data;
|
||||||
|
void __user *argp = (void __user *)arg;
|
||||||
|
int idx;
|
||||||
|
long r;
|
||||||
|
|
||||||
vcpu_load(vcpu);
|
vcpu_load(vcpu);
|
||||||
|
|
||||||
|
|
|
@ -1260,4 +1260,16 @@ static inline bool vcpu_valid_wakeup(struct kvm_vcpu *vcpu)
|
||||||
}
|
}
|
||||||
#endif /* CONFIG_HAVE_KVM_INVALID_WAKEUPS */
|
#endif /* CONFIG_HAVE_KVM_INVALID_WAKEUPS */
|
||||||
|
|
||||||
|
#ifdef CONFIG_HAVE_KVM_VCPU_ASYNC_IOCTL
|
||||||
|
long kvm_arch_vcpu_async_ioctl(struct file *filp,
|
||||||
|
unsigned int ioctl, unsigned long arg);
|
||||||
|
#else
|
||||||
|
static inline long kvm_arch_vcpu_async_ioctl(struct file *filp,
|
||||||
|
unsigned int ioctl,
|
||||||
|
unsigned long arg)
|
||||||
|
{
|
||||||
|
return -ENOIOCTLCMD;
|
||||||
|
}
|
||||||
|
#endif /* CONFIG_HAVE_KVM_VCPU_ASYNC_IOCTL */
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -51,3 +51,6 @@ config KVM_COMPAT
|
||||||
|
|
||||||
config HAVE_KVM_IRQ_BYPASS
|
config HAVE_KVM_IRQ_BYPASS
|
||||||
bool
|
bool
|
||||||
|
|
||||||
|
config HAVE_KVM_VCPU_ASYNC_IOCTL
|
||||||
|
bool
|
||||||
|
|
|
@ -2544,15 +2544,13 @@ static long kvm_vcpu_ioctl(struct file *filp,
|
||||||
if (unlikely(_IOC_TYPE(ioctl) != KVMIO))
|
if (unlikely(_IOC_TYPE(ioctl) != KVMIO))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
#if defined(CONFIG_S390) || defined(CONFIG_PPC) || defined(CONFIG_MIPS)
|
|
||||||
/*
|
/*
|
||||||
* Special cases: vcpu ioctls that are asynchronous to vcpu execution,
|
* Some architectures have vcpu ioctls that are asynchronous to vcpu
|
||||||
* so vcpu_load() would break it.
|
* execution; mutex_lock() would break them.
|
||||||
*/
|
*/
|
||||||
if (ioctl == KVM_S390_INTERRUPT || ioctl == KVM_S390_IRQ || ioctl == KVM_INTERRUPT)
|
r = kvm_arch_vcpu_async_ioctl(filp, ioctl, arg);
|
||||||
return kvm_arch_vcpu_ioctl(filp, ioctl, arg);
|
if (r != -ENOIOCTLCMD)
|
||||||
#endif
|
return r;
|
||||||
|
|
||||||
|
|
||||||
if (mutex_lock_killable(&vcpu->mutex))
|
if (mutex_lock_killable(&vcpu->mutex))
|
||||||
return -EINTR;
|
return -EINTR;
|
||||||
|
|
Loading…
Reference in a new issue