Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 5c0aea0e authored by David Hildenbrand's avatar David Hildenbrand Committed by Paolo Bonzini
Browse files

KVM: x86: don't hold kvm->lock in KVM_SET_GSI_ROUTING



We needed the lock to avoid racing with creation of the irqchip on x86. As
kvm_set_irq_routing() calls srcu_synchronize_expedited(), this lock
might be held for a longer time.

Let's introduce an arch specific callback to check if we can actually
add irq routes. For x86, all we have to do is check if we have an
irqchip in the kernel. We don't need kvm->lock at that point as the
irqchip is marked as inititalized only when actually fully created.

Reported-by: default avatarSteve Rutherford <srutherford@google.com>
Reviewed-by: default avatarRadim Krčmář <rkrcmar@redhat.com>
Fixes: 1df6dded ("KVM: x86: race between KVM_SET_GSI_ROUTING and KVM_CREATE_IRQCHIP")
Signed-off-by: default avatarDavid Hildenbrand <david@redhat.com>
Signed-off-by: default avatarPaolo Bonzini <pbonzini@redhat.com>
parent bcb85c88
Loading
Loading
Loading
Loading
+0 −1
Original line number Diff line number Diff line
@@ -728,7 +728,6 @@ struct kvm_hv {

enum kvm_irqchip_mode {
	KVM_IRQCHIP_NONE,
	KVM_IRQCHIP_INIT_IN_PROGRESS, /* temporarily set during creation */
	KVM_IRQCHIP_KERNEL,       /* created with KVM_CREATE_IRQCHIP */
	KVM_IRQCHIP_SPLIT,        /* created with KVM_CAP_SPLIT_IRQCHIP */
};
+1 −1
Original line number Diff line number Diff line
@@ -111,7 +111,7 @@ static inline int irqchip_in_kernel(struct kvm *kvm)

	/* Matches smp_wmb() when setting irqchip_mode */
	smp_rmb();
	return mode > KVM_IRQCHIP_INIT_IN_PROGRESS;
	return mode != KVM_IRQCHIP_NONE;
}

void kvm_inject_pending_timer_irqs(struct kvm_vcpu *vcpu);
+9 −6
Original line number Diff line number Diff line
@@ -274,16 +274,19 @@ void kvm_fire_mask_notifiers(struct kvm *kvm, unsigned irqchip, unsigned pin,
	srcu_read_unlock(&kvm->irq_srcu, idx);
}

bool kvm_arch_can_set_irq_routing(struct kvm *kvm)
{
	return irqchip_in_kernel(kvm);
}

int kvm_set_routing_entry(struct kvm *kvm,
			  struct kvm_kernel_irq_routing_entry *e,
			  const struct kvm_irq_routing_entry *ue)
{
	/* also allow creation of routes during KVM_IRQCHIP_INIT_IN_PROGRESS */
	if (kvm->arch.irqchip_mode == KVM_IRQCHIP_NONE)
		return -EINVAL;

	/* Matches smp_wmb() when setting irqchip_mode */
	smp_rmb();
	/* We can't check irqchip_in_kernel() here as some callers are
	 * currently inititalizing the irqchip. Other callers should therefore
	 * check kvm_arch_can_set_irq_routing() before calling this function.
	 */
	switch (ue->type) {
	case KVM_IRQ_ROUTING_IRQCHIP:
		if (irqchip_split(kvm))
+1 −10
Original line number Diff line number Diff line
@@ -3919,14 +3919,9 @@ static int kvm_vm_ioctl_enable_cap(struct kvm *kvm,
			goto split_irqchip_unlock;
		if (kvm->created_vcpus)
			goto split_irqchip_unlock;
		kvm->arch.irqchip_mode = KVM_IRQCHIP_INIT_IN_PROGRESS;
		r = kvm_setup_empty_irq_routing(kvm);
		if (r) {
			kvm->arch.irqchip_mode = KVM_IRQCHIP_NONE;
			/* Pairs with smp_rmb() when reading irqchip_mode */
			smp_wmb();
		if (r)
			goto split_irqchip_unlock;
		}
		/* Pairs with irqchip_in_kernel. */
		smp_wmb();
		kvm->arch.irqchip_mode = KVM_IRQCHIP_SPLIT;
@@ -4012,12 +4007,8 @@ long kvm_arch_vm_ioctl(struct file *filp,
			goto create_irqchip_unlock;
		}

		kvm->arch.irqchip_mode = KVM_IRQCHIP_INIT_IN_PROGRESS;
		r = kvm_setup_default_irq_routing(kvm);
		if (r) {
			kvm->arch.irqchip_mode = KVM_IRQCHIP_NONE;
			/* Pairs with smp_rmb() when reading irqchip_mode */
			smp_wmb();
			kvm_ioapic_destroy(kvm);
			kvm_pic_destroy(kvm);
			goto create_irqchip_unlock;
+1 −0
Original line number Diff line number Diff line
@@ -1018,6 +1018,7 @@ static inline int mmu_notifier_retry(struct kvm *kvm, unsigned long mmu_seq)
#define KVM_MAX_IRQ_ROUTES 1024
#endif

bool kvm_arch_can_set_irq_routing(struct kvm *kvm);
int kvm_set_irq_routing(struct kvm *kvm,
			const struct kvm_irq_routing_entry *entries,
			unsigned nr,
Loading