KVM: irqfd: Make resampler_list an RCU list
authorDmytro Maluka <dmy@semihalf.com>
Wed, 22 Mar 2023 20:43:43 +0000 (21:43 +0100)
committerPaolo Bonzini <pbonzini@redhat.com>
Mon, 27 Mar 2023 14:13:28 +0000 (10:13 -0400)
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>
include/linux/kvm_host.h
include/linux/kvm_irqfd.h
virt/kvm/eventfd.c

index 8ada23756b0ec223b86eaa94945d070e3e7e9a16..9f508c8e66e12b1fc15c78489eea9cd10b7c7f22 100644 (file)
@@ -755,6 +755,7 @@ struct kvm {
        struct {
                spinlock_t        lock;
                struct list_head  items;
+               /* resampler_list update side is protected by resampler_lock. */
                struct list_head  resampler_list;
                struct mutex      resampler_lock;
        } irqfds;
index dac047abdba7c5d571671da54f95a8c930307d67..8ad43692e3bbb459a75c3e33fd17fbd22b3d03e1 100644 (file)
@@ -31,7 +31,7 @@ struct kvm_kernel_irqfd_resampler {
        /*
         * Entry in list of kvm->irqfd.resampler_list.  Use for sharing
         * resamplers among irqfds on the same gsi.
-        * Accessed and modified under kvm->irqfds.resampler_lock
+        * RCU list modified under kvm->irqfds.resampler_lock
         */
        struct list_head link;
 };
index 2a3ed401ce4653377d55de9b02ccfa9e6086f3f3..61aea70dd888d4553e9c39978979c3cd82222dc6 100644 (file)
@@ -96,8 +96,12 @@ irqfd_resampler_shutdown(struct kvm_kernel_irqfd *irqfd)
        synchronize_srcu(&kvm->irq_srcu);
 
        if (list_empty(&resampler->list)) {
-               list_del(&resampler->link);
+               list_del_rcu(&resampler->link);
                kvm_unregister_irq_ack_notifier(kvm, &resampler->notifier);
+               /*
+                * synchronize_srcu(&kvm->irq_srcu) already called
+                * in kvm_unregister_irq_ack_notifier().
+                */
                kvm_set_irq(kvm, KVM_IRQFD_RESAMPLE_IRQ_SOURCE_ID,
                            resampler->notifier.gsi, 0, false);
                kfree(resampler);
@@ -369,7 +373,7 @@ kvm_irqfd_assign(struct kvm *kvm, struct kvm_irqfd *args)
                        resampler->notifier.irq_acked = irqfd_resampler_ack;
                        INIT_LIST_HEAD(&resampler->link);
 
-                       list_add(&resampler->link, &kvm->irqfds.resampler_list);
+                       list_add_rcu(&resampler->link, &kvm->irqfds.resampler_list);
                        kvm_register_irq_ack_notifier(kvm,
                                                      &resampler->notifier);
                        irqfd->resampler = resampler;