kvm: Check irqchip mode before assign irqfd
authorPeter Xu <peterx@redhat.com>
Sun, 5 May 2019 08:56:42 +0000 (16:56 +0800)
committerPaolo Bonzini <pbonzini@redhat.com>
Fri, 24 May 2019 19:27:12 +0000 (21:27 +0200)
When assigning kvm irqfd we didn't check the irqchip mode but we allow
KVM_IRQFD to succeed with all the irqchip modes.  However it does not
make much sense to create irqfd even without the kernel chips.  Let's
provide a arch-dependent helper to check whether a specific irqfd is
allowed by the arch.  At least for x86, it should make sense to check:

- when irqchip mode is NONE, all irqfds should be disallowed, and,

- when irqchip mode is SPLIT, irqfds that are with resamplefd should
  be disallowed.

For either of the case, previously we'll silently ignore the irq or
the irq ack event if the irqchip mode is incorrect.  However that can
cause misterious guest behaviors and it can be hard to triage.  Let's
fail KVM_IRQFD even earlier to detect these incorrect configurations.

CC: Paolo Bonzini <pbonzini@redhat.com>
CC: Radim Krčmář <rkrcmar@redhat.com>
CC: Alex Williamson <alex.williamson@redhat.com>
CC: Eduardo Habkost <ehabkost@redhat.com>
Signed-off-by: Peter Xu <peterx@redhat.com>
Cc: stable@vger.kernel.org
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>

index faa264822cee3c658280d122cc3495fc93587cf5..007bc654f928a17e731963f2ba1c6cae00f653d5 100644 (file)
@@ -172,3 +172,10 @@ void __kvm_migrate_timers(struct kvm_vcpu *vcpu)
+bool kvm_arch_irqfd_allowed(struct kvm *kvm, struct kvm_irqfd *args)
+       bool resample = args->flags & KVM_IRQFD_FLAG_RESAMPLE;
+       return resample ? irqchip_kernel(kvm) : irqchip_in_kernel(kvm);
index d5005cc265217c4fa4d5de7c2ecc2a29fb599c19..fd210cdd49839dea0f33367376e13a089177c3af 100644 (file)
@@ -114,6 +114,7 @@ static inline int irqchip_in_kernel(struct kvm *kvm)
        return mode != KVM_IRQCHIP_NONE;
+bool kvm_arch_irqfd_allowed(struct kvm *kvm, struct kvm_irqfd *args);
 void kvm_inject_pending_timer_irqs(struct kvm_vcpu *vcpu);
 void kvm_inject_apic_timer_irqs(struct kvm_vcpu *vcpu);
 void kvm_apic_nmi_wd_deliver(struct kvm_vcpu *vcpu);
index 001aeda4c154d4a9ff5b2e9f73cebdc743c2c29b..3972a9564c76381ffaa03eb6be91af66c5b60ef2 100644 (file)
 static struct workqueue_struct *irqfd_cleanup_wq;
+bool __attribute__((weak))
+kvm_arch_irqfd_allowed(struct kvm *kvm, struct kvm_irqfd *args)
+       return true;
 static void
 irqfd_inject(struct work_struct *work)
@@ -297,6 +303,9 @@ kvm_irqfd_assign(struct kvm *kvm, struct kvm_irqfd *args)
        if (!kvm_arch_intc_initialized(kvm))
                return -EAGAIN;
+       if (!kvm_arch_irqfd_allowed(kvm, args))
+               return -EINVAL;
        irqfd = kzalloc(sizeof(*irqfd), GFP_KERNEL_ACCOUNT);
        if (!irqfd)
                return -ENOMEM;