Skip to content

Commit cb21073

Browse files
committed
KVM: Pass new routing entries and irqfd when updating IRTEs
When updating IRTEs in response to a GSI routing or IRQ bypass change, pass the new/current routing information along with the associated irqfd. This will allow KVM x86 to harden, simplify, and deduplicate its code. Since adding/removing a bypass producer is now conveniently protected with irqfds.lock, i.e. can't run concurrently with kvm_irq_routing_update(), use the routing information cached in the irqfd instead of looking up the information in the current GSI routing tables. Opportunistically convert an existing printk() to pr_info() and put its string onto a single line (old code that strictly adhered to 80 chars). Link: https://lore.kernel.org/r/20250611224604.313496-5-seanjc@google.com Signed-off-by: Sean Christopherson <seanjc@google.com>
1 parent e76c274 commit cb21073

File tree

9 files changed

+62
-55
lines changed

9 files changed

+62
-55
lines changed

arch/arm64/kvm/arm.c

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2771,8 +2771,9 @@ bool kvm_arch_irqfd_route_changed(struct kvm_kernel_irq_routing_entry *old,
27712771
return memcmp(&old->msi, &new->msi, sizeof(new->msi));
27722772
}
27732773

2774-
int kvm_arch_update_irqfd_routing(struct kvm *kvm, unsigned int host_irq,
2775-
uint32_t guest_irq, bool set)
2774+
int kvm_arch_update_irqfd_routing(struct kvm_kernel_irqfd *irqfd,
2775+
struct kvm_kernel_irq_routing_entry *old,
2776+
struct kvm_kernel_irq_routing_entry *new)
27762777
{
27772778
/*
27782779
* Remapping the vLPI requires taking the its_lock mutex to resolve
@@ -2781,7 +2782,7 @@ int kvm_arch_update_irqfd_routing(struct kvm *kvm, unsigned int host_irq,
27812782
*
27822783
* Unmap the vLPI and fall back to software LPI injection.
27832784
*/
2784-
return kvm_vgic_v4_unset_forwarding(kvm, host_irq);
2785+
return kvm_vgic_v4_unset_forwarding(irqfd->kvm, irqfd->producer->irq);
27852786
}
27862787

27872788
void kvm_arch_irq_bypass_stop(struct irq_bypass_consumer *cons)

arch/x86/include/asm/kvm_host.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -297,6 +297,7 @@ enum x86_intercept_stage;
297297
*/
298298
#define KVM_APIC_PV_EOI_PENDING 1
299299

300+
struct kvm_kernel_irqfd;
300301
struct kvm_kernel_irq_routing_entry;
301302

302303
/*
@@ -1845,8 +1846,9 @@ struct kvm_x86_ops {
18451846
void (*vcpu_blocking)(struct kvm_vcpu *vcpu);
18461847
void (*vcpu_unblocking)(struct kvm_vcpu *vcpu);
18471848

1848-
int (*pi_update_irte)(struct kvm *kvm, unsigned int host_irq,
1849-
uint32_t guest_irq, bool set);
1849+
int (*pi_update_irte)(struct kvm_kernel_irqfd *irqfd, struct kvm *kvm,
1850+
unsigned int host_irq, uint32_t guest_irq,
1851+
struct kvm_kernel_irq_routing_entry *new);
18501852
void (*pi_start_assignment)(struct kvm *kvm);
18511853
void (*apicv_pre_state_restore)(struct kvm_vcpu *vcpu);
18521854
void (*apicv_post_state_restore)(struct kvm_vcpu *vcpu);

arch/x86/kvm/svm/avic.c

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include <linux/hashtable.h>
1919
#include <linux/amd-iommu.h>
2020
#include <linux/kvm_host.h>
21+
#include <linux/kvm_irqfd.h>
2122

2223
#include <asm/irq_remapping.h>
2324
#include <asm/msr.h>
@@ -886,21 +887,14 @@ get_pi_vcpu_info(struct kvm *kvm, struct kvm_kernel_irq_routing_entry *e,
886887
return 0;
887888
}
888889

889-
/*
890-
* avic_pi_update_irte - set IRTE for Posted-Interrupts
891-
*
892-
* @kvm: kvm
893-
* @host_irq: host irq of the interrupt
894-
* @guest_irq: gsi of the interrupt
895-
* @set: set or unset PI
896-
* returns 0 on success, < 0 on failure
897-
*/
898-
int avic_pi_update_irte(struct kvm *kvm, unsigned int host_irq,
899-
uint32_t guest_irq, bool set)
890+
int avic_pi_update_irte(struct kvm_kernel_irqfd *irqfd, struct kvm *kvm,
891+
unsigned int host_irq, uint32_t guest_irq,
892+
struct kvm_kernel_irq_routing_entry *new)
900893
{
901894
struct kvm_kernel_irq_routing_entry *e;
902895
struct kvm_irq_routing_table *irq_rt;
903896
bool enable_remapped_mode = true;
897+
bool set = !!new;
904898
int idx, ret = 0;
905899

906900
if (!kvm_arch_has_assigned_device(kvm) || !kvm_arch_has_irq_bypass())
@@ -926,6 +920,8 @@ int avic_pi_update_irte(struct kvm *kvm, unsigned int host_irq,
926920
if (e->type != KVM_IRQ_ROUTING_MSI)
927921
continue;
928922

923+
WARN_ON_ONCE(new && memcmp(e, new, sizeof(*new)));
924+
929925
/**
930926
* Here, we setup with legacy mode in the following cases:
931927
* 1. When cannot target interrupt to a specific vcpu.

arch/x86/kvm/svm/svm.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -736,8 +736,9 @@ void avic_vcpu_load(struct kvm_vcpu *vcpu, int cpu);
736736
void avic_vcpu_put(struct kvm_vcpu *vcpu);
737737
void avic_apicv_post_state_restore(struct kvm_vcpu *vcpu);
738738
void avic_refresh_apicv_exec_ctrl(struct kvm_vcpu *vcpu);
739-
int avic_pi_update_irte(struct kvm *kvm, unsigned int host_irq,
740-
uint32_t guest_irq, bool set);
739+
int avic_pi_update_irte(struct kvm_kernel_irqfd *irqfd, struct kvm *kvm,
740+
unsigned int host_irq, uint32_t guest_irq,
741+
struct kvm_kernel_irq_routing_entry *new);
741742
void avic_vcpu_blocking(struct kvm_vcpu *vcpu);
742743
void avic_vcpu_unblocking(struct kvm_vcpu *vcpu);
743744
void avic_ring_doorbell(struct kvm_vcpu *vcpu);

arch/x86/kvm/vmx/posted_intr.c

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
33

44
#include <linux/kvm_host.h>
5+
#include <linux/kvm_irqfd.h>
56

67
#include <asm/irq_remapping.h>
78
#include <asm/cpu.h>
@@ -294,24 +295,17 @@ void vmx_pi_start_assignment(struct kvm *kvm)
294295
kvm_make_all_cpus_request(kvm, KVM_REQ_UNBLOCK);
295296
}
296297

297-
/*
298-
* vmx_pi_update_irte - set IRTE for Posted-Interrupts
299-
*
300-
* @kvm: kvm
301-
* @host_irq: host irq of the interrupt
302-
* @guest_irq: gsi of the interrupt
303-
* @set: set or unset PI
304-
* returns 0 on success, < 0 on failure
305-
*/
306-
int vmx_pi_update_irte(struct kvm *kvm, unsigned int host_irq,
307-
uint32_t guest_irq, bool set)
298+
int vmx_pi_update_irte(struct kvm_kernel_irqfd *irqfd, struct kvm *kvm,
299+
unsigned int host_irq, uint32_t guest_irq,
300+
struct kvm_kernel_irq_routing_entry *new)
308301
{
309302
struct kvm_kernel_irq_routing_entry *e;
310303
struct kvm_irq_routing_table *irq_rt;
311304
bool enable_remapped_mode = true;
312305
struct kvm_lapic_irq irq;
313306
struct kvm_vcpu *vcpu;
314307
struct vcpu_data vcpu_info;
308+
bool set = !!new;
315309
int idx, ret = 0;
316310

317311
if (!vmx_can_use_vtd_pi(kvm))
@@ -329,6 +323,9 @@ int vmx_pi_update_irte(struct kvm *kvm, unsigned int host_irq,
329323
hlist_for_each_entry(e, &irq_rt->map[guest_irq], link) {
330324
if (e->type != KVM_IRQ_ROUTING_MSI)
331325
continue;
326+
327+
WARN_ON_ONCE(new && memcmp(e, new, sizeof(*new)));
328+
332329
/*
333330
* VT-d PI cannot support posting multicast/broadcast
334331
* interrupts to a vCPU, we still use interrupt remapping

arch/x86/kvm/vmx/posted_intr.h

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@
33
#define __KVM_X86_VMX_POSTED_INTR_H
44

55
#include <linux/bitmap.h>
6+
#include <linux/find.h>
7+
#include <linux/kvm_host.h>
8+
69
#include <asm/posted_intr.h>
710

811
void vmx_vcpu_pi_load(struct kvm_vcpu *vcpu, int cpu);
@@ -11,8 +14,9 @@ void pi_wakeup_handler(void);
1114
void __init pi_init_cpu(int cpu);
1215
void pi_apicv_pre_state_restore(struct kvm_vcpu *vcpu);
1316
bool pi_has_pending_interrupt(struct kvm_vcpu *vcpu);
14-
int vmx_pi_update_irte(struct kvm *kvm, unsigned int host_irq,
15-
uint32_t guest_irq, bool set);
17+
int vmx_pi_update_irte(struct kvm_kernel_irqfd *irqfd, struct kvm *kvm,
18+
unsigned int host_irq, uint32_t guest_irq,
19+
struct kvm_kernel_irq_routing_entry *new);
1620
void vmx_pi_start_assignment(struct kvm *kvm);
1721

1822
static inline int pi_find_highest_vector(struct pi_desc *pi_desc)

arch/x86/kvm/x86.c

Lines changed: 20 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -13507,31 +13507,31 @@ int kvm_arch_irq_bypass_add_producer(struct irq_bypass_consumer *cons,
1350713507
struct kvm_kernel_irqfd *irqfd =
1350813508
container_of(cons, struct kvm_kernel_irqfd, consumer);
1350913509
struct kvm *kvm = irqfd->kvm;
13510-
int ret;
13510+
int ret = 0;
1351113511

1351213512
kvm_arch_start_assignment(irqfd->kvm);
1351313513

1351413514
spin_lock_irq(&kvm->irqfds.lock);
1351513515
irqfd->producer = prod;
1351613516

13517-
ret = kvm_x86_call(pi_update_irte)(irqfd->kvm,
13518-
prod->irq, irqfd->gsi, 1);
13519-
if (ret)
13520-
kvm_arch_end_assignment(irqfd->kvm);
13521-
13517+
if (irqfd->irq_entry.type == KVM_IRQ_ROUTING_MSI) {
13518+
ret = kvm_x86_call(pi_update_irte)(irqfd, irqfd->kvm, prod->irq,
13519+
irqfd->gsi, &irqfd->irq_entry);
13520+
if (ret)
13521+
kvm_arch_end_assignment(irqfd->kvm);
13522+
}
1352213523
spin_unlock_irq(&kvm->irqfds.lock);
1352313524

13524-
1352513525
return ret;
1352613526
}
1352713527

1352813528
void kvm_arch_irq_bypass_del_producer(struct irq_bypass_consumer *cons,
1352913529
struct irq_bypass_producer *prod)
1353013530
{
13531-
int ret;
1353213531
struct kvm_kernel_irqfd *irqfd =
1353313532
container_of(cons, struct kvm_kernel_irqfd, consumer);
1353413533
struct kvm *kvm = irqfd->kvm;
13534+
int ret;
1353513535

1353613536
WARN_ON(irqfd->producer != prod);
1353713537

@@ -13544,22 +13544,26 @@ void kvm_arch_irq_bypass_del_producer(struct irq_bypass_consumer *cons,
1354413544
spin_lock_irq(&kvm->irqfds.lock);
1354513545
irqfd->producer = NULL;
1354613546

13547-
ret = kvm_x86_call(pi_update_irte)(irqfd->kvm,
13548-
prod->irq, irqfd->gsi, 0);
13549-
if (ret)
13550-
printk(KERN_INFO "irq bypass consumer (eventfd %p) unregistration"
13551-
" fails: %d\n", irqfd->consumer.eventfd, ret);
13547+
if (irqfd->irq_entry.type == KVM_IRQ_ROUTING_MSI) {
13548+
ret = kvm_x86_call(pi_update_irte)(irqfd, irqfd->kvm, prod->irq,
13549+
irqfd->gsi, NULL);
13550+
if (ret)
13551+
pr_info("irq bypass consumer (eventfd %p) unregistration fails: %d\n",
13552+
irqfd->consumer.eventfd, ret);
13553+
}
1355213554

1355313555
spin_unlock_irq(&kvm->irqfds.lock);
1355413556

1355513557

1355613558
kvm_arch_end_assignment(irqfd->kvm);
1355713559
}
1355813560

13559-
int kvm_arch_update_irqfd_routing(struct kvm *kvm, unsigned int host_irq,
13560-
uint32_t guest_irq, bool set)
13561+
int kvm_arch_update_irqfd_routing(struct kvm_kernel_irqfd *irqfd,
13562+
struct kvm_kernel_irq_routing_entry *old,
13563+
struct kvm_kernel_irq_routing_entry *new)
1356113564
{
13562-
return kvm_x86_call(pi_update_irte)(kvm, host_irq, guest_irq, set);
13565+
return kvm_x86_call(pi_update_irte)(irqfd, irqfd->kvm, irqfd->producer->irq,
13566+
irqfd->gsi, new);
1356313567
}
1356413568

1356513569
bool kvm_arch_irqfd_route_changed(struct kvm_kernel_irq_routing_entry *old,

include/linux/kvm_host.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2401,15 +2401,18 @@ struct kvm_vcpu *kvm_get_running_vcpu(void);
24012401
struct kvm_vcpu * __percpu *kvm_get_running_vcpus(void);
24022402

24032403
#if IS_ENABLED(CONFIG_HAVE_KVM_IRQ_BYPASS)
2404+
struct kvm_kernel_irqfd;
2405+
24042406
bool kvm_arch_has_irq_bypass(void);
24052407
int kvm_arch_irq_bypass_add_producer(struct irq_bypass_consumer *,
24062408
struct irq_bypass_producer *);
24072409
void kvm_arch_irq_bypass_del_producer(struct irq_bypass_consumer *,
24082410
struct irq_bypass_producer *);
24092411
void kvm_arch_irq_bypass_stop(struct irq_bypass_consumer *);
24102412
void kvm_arch_irq_bypass_start(struct irq_bypass_consumer *);
2411-
int kvm_arch_update_irqfd_routing(struct kvm *kvm, unsigned int host_irq,
2412-
uint32_t guest_irq, bool set);
2413+
int kvm_arch_update_irqfd_routing(struct kvm_kernel_irqfd *irqfd,
2414+
struct kvm_kernel_irq_routing_entry *old,
2415+
struct kvm_kernel_irq_routing_entry *new);
24132416
bool kvm_arch_irqfd_route_changed(struct kvm_kernel_irq_routing_entry *,
24142417
struct kvm_kernel_irq_routing_entry *);
24152418
#endif /* CONFIG_HAVE_KVM_IRQ_BYPASS */

virt/kvm/eventfd.c

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -285,9 +285,9 @@ void __attribute__((weak)) kvm_arch_irq_bypass_start(
285285
{
286286
}
287287

288-
int __attribute__((weak)) kvm_arch_update_irqfd_routing(
289-
struct kvm *kvm, unsigned int host_irq,
290-
uint32_t guest_irq, bool set)
288+
int __weak kvm_arch_update_irqfd_routing(struct kvm_kernel_irqfd *irqfd,
289+
struct kvm_kernel_irq_routing_entry *old,
290+
struct kvm_kernel_irq_routing_entry *new)
291291
{
292292
return 0;
293293
}
@@ -618,9 +618,8 @@ void kvm_irq_routing_update(struct kvm *kvm)
618618
#if IS_ENABLED(CONFIG_HAVE_KVM_IRQ_BYPASS)
619619
if (irqfd->producer &&
620620
kvm_arch_irqfd_route_changed(&old, &irqfd->irq_entry)) {
621-
int ret = kvm_arch_update_irqfd_routing(
622-
irqfd->kvm, irqfd->producer->irq,
623-
irqfd->gsi, 1);
621+
int ret = kvm_arch_update_irqfd_routing(irqfd, &old, &irqfd->irq_entry);
622+
624623
WARN_ON(ret);
625624
}
626625
#endif

0 commit comments

Comments
 (0)