Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

KVM: irqfd: Make resampler_list an RCU list

It is useful to be able to do read-only traversal of the list of all the
registered irqfd resamplers without locking the resampler_lock mutex.
In particular, we are going to traverse it to search for a resampler
registered for the given irq of an irqchip, and that will be done with
an irqchip spinlock (ioapic->lock) held, so it is undesirable to lock a
mutex in this context. So turn this list into an RCU list.

For protecting the read side, reuse kvm->irq_srcu which is already used
for protecting a number of irq related things (kvm->irq_routing,
irqfd->resampler->list, kvm->irq_ack_notifier_list,
kvm->arch.mask_notifier_list).

Signed-off-by: Dmytro Maluka <dmy@semihalf.com>
Message-Id: <20230322204344.50138-2-dmy@semihalf.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>

authored by

Dmytro Maluka and committed by
Paolo Bonzini
d583fbd7 e5c972c1

+8 -3
+1
include/linux/kvm_host.h
··· 755 755 struct { 756 756 spinlock_t lock; 757 757 struct list_head items; 758 + /* resampler_list update side is protected by resampler_lock. */ 758 759 struct list_head resampler_list; 759 760 struct mutex resampler_lock; 760 761 } irqfds;
+1 -1
include/linux/kvm_irqfd.h
··· 31 31 /* 32 32 * Entry in list of kvm->irqfd.resampler_list. Use for sharing 33 33 * resamplers among irqfds on the same gsi. 34 - * Accessed and modified under kvm->irqfds.resampler_lock 34 + * RCU list modified under kvm->irqfds.resampler_lock 35 35 */ 36 36 struct list_head link; 37 37 };
+6 -2
virt/kvm/eventfd.c
··· 96 96 synchronize_srcu(&kvm->irq_srcu); 97 97 98 98 if (list_empty(&resampler->list)) { 99 - list_del(&resampler->link); 99 + list_del_rcu(&resampler->link); 100 100 kvm_unregister_irq_ack_notifier(kvm, &resampler->notifier); 101 + /* 102 + * synchronize_srcu(&kvm->irq_srcu) already called 103 + * in kvm_unregister_irq_ack_notifier(). 104 + */ 101 105 kvm_set_irq(kvm, KVM_IRQFD_RESAMPLE_IRQ_SOURCE_ID, 102 106 resampler->notifier.gsi, 0, false); 103 107 kfree(resampler); ··· 373 369 resampler->notifier.irq_acked = irqfd_resampler_ack; 374 370 INIT_LIST_HEAD(&resampler->link); 375 371 376 - list_add(&resampler->link, &kvm->irqfds.resampler_list); 372 + list_add_rcu(&resampler->link, &kvm->irqfds.resampler_list); 377 373 kvm_register_irq_ack_notifier(kvm, 378 374 &resampler->notifier); 379 375 irqfd->resampler = resampler;