irqfd wakeup takes a seqcount-protected copy of irqfd->irq_entry before injecting an interrupt. Architectures that need to classify an injection by its irqfd producer need any derived arch state to be part of that same snapshot. The irqfd object had per-irqfd arch side state, but that state describes the current producer, not the specific route snapshot used for an in-flight injection. Keeping the metadata there can race with route updates and teardown: the inatomic injection path may observe a new route with old arch metadata, or old arch metadata after the route has already been invalidated. Add optional arch-owned irqfd metadata to struct kvm_kernel_irq_routing_entry and initialize it whenever KVM refreshes or clears an irqfd route. Remove the old per-irqfd arch side-state fields so the route snapshot is the only place carrying this producer provenance. Userspace MSI injection uses a zero-initialized temporary route, so it is never reported as irqfd-originated. This provides the sequencing needed by RISC-V AIA to distinguish MRIF notice MSI delivery from normal MSI injection without consulting mutable irqfd state outside irq_entry_sc. Signed-off-by: Zhanpeng Zhang --- include/linux/kvm_host.h | 7 +++++++ include/linux/kvm_irqfd.h | 4 ---- virt/kvm/eventfd.c | 5 +++++ virt/kvm/irqchip.c | 4 +++- 4 files changed, 15 insertions(+), 5 deletions(-) diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h index 5bd76cf394fa..254f8fd132cc 100644 --- a/include/linux/kvm_host.h +++ b/include/linux/kvm_host.h @@ -685,6 +685,13 @@ struct kvm_kernel_irq_routing_entry { struct kvm_hv_sint hv_sint; struct kvm_xen_evtchn xen_evtchn; }; + /* + * Optional arch-owned irqfd metadata. It is updated under + * irq_entry_sc together with the route so irqfd_wakeup() observes a + * single consistent snapshot. + */ + struct kvm_vcpu *irqfd_arch_vcpu; + void *irqfd_arch_data; struct hlist_node link; }; diff --git a/include/linux/kvm_irqfd.h b/include/linux/kvm_irqfd.h index ef8c134ded8a..44fd2a20b09e 100644 --- a/include/linux/kvm_irqfd.h +++ b/include/linux/kvm_irqfd.h @@ -58,10 +58,6 @@ struct kvm_kernel_irqfd { struct work_struct shutdown; struct irq_bypass_consumer consumer; struct irq_bypass_producer *producer; - - struct kvm_vcpu *irq_bypass_vcpu; - struct list_head vcpu_list; - void *irq_bypass_data; }; #endif /* __LINUX_KVM_IRQFD_H */ diff --git a/virt/kvm/eventfd.c b/virt/kvm/eventfd.c index a7794ffdb976..399ef2bdce5d 100644 --- a/virt/kvm/eventfd.c +++ b/virt/kvm/eventfd.c @@ -273,6 +273,9 @@ static void irqfd_update(struct kvm *kvm, struct kvm_kernel_irqfd *irqfd) else irqfd->irq_entry.type = 0; + irqfd->irq_entry.irqfd_arch_vcpu = NULL; + irqfd->irq_entry.irqfd_arch_data = NULL; + write_seqcount_end(&irqfd->irq_entry_sc); } @@ -594,6 +597,8 @@ kvm_irqfd_deassign(struct kvm *kvm, struct kvm_irqfd *args) */ write_seqcount_begin(&irqfd->irq_entry_sc); irqfd->irq_entry.type = 0; + irqfd->irq_entry.irqfd_arch_vcpu = NULL; + irqfd->irq_entry.irqfd_arch_data = NULL; write_seqcount_end(&irqfd->irq_entry_sc); irqfd_deactivate(irqfd); } diff --git a/virt/kvm/irqchip.c b/virt/kvm/irqchip.c index 6ccabfd32287..b163f7ed3c1e 100644 --- a/virt/kvm/irqchip.c +++ b/virt/kvm/irqchip.c @@ -47,7 +47,7 @@ int kvm_irq_map_chip_pin(struct kvm *kvm, unsigned irqchip, unsigned pin) int kvm_send_userspace_msi(struct kvm *kvm, struct kvm_msi *msi) { - struct kvm_kernel_irq_routing_entry route; + struct kvm_kernel_irq_routing_entry route = {}; if (!kvm_arch_irqchip_in_kernel(kvm) || (msi->flags & ~KVM_MSI_VALID_DEVID)) return -EINVAL; @@ -145,6 +145,8 @@ static int setup_routing_entry(struct kvm *kvm, e->gsi = gsi; e->type = ue->type; + e->irqfd_arch_vcpu = NULL; + e->irqfd_arch_data = NULL; r = kvm_set_routing_entry(kvm, e, ue); if (r) return r; -- 2.50.1 (Apple Git-155)