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:
Paolo Bonzini 2017-12-12 17:41:34 +01:00
parent 9b062471e5
commit 5cb0944c0c
9 changed files with 58 additions and 17 deletions

View file

@ -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

View file

@ -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) {

View file

@ -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

View file

@ -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);

View file

@ -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

View file

@ -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);

View file

@ -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

View file

@ -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

View file

@ -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;