KVM: do not call kvm_set_irq from irq disabled section
The assigned device interrupt work handler calls kvm_set_irq, which can sleep, for example, waiting for the ioapic mutex, from irq disabled section.
https://bugzilla.kernel.org/show_bug.cgi?id=15725
Fix by dropping assigned_dev_lock (and re-enabling interrupts) before invoking kvm_set_irq for the KVM_DEV_IRQ_HOST_MSIX case. Other cases do not require the lock or interrupts disabled (a new work instance will be queued in case of concurrent interrupt).
KVM-Stable-Tag.
virt/kvm/assigned-dev.c +11 -2
@@ -64,24 +64,33 @@ static void kvm_assigned_dev_interrupt_work_handler(struct work_struct *work) interrupt_work); kvm = assigned_dev->kvm; -spin_lock_irq (&assigned_dev->assigned_dev_lock);if (assigned_dev->irq_requested_type &KVM_DEV_IRQ_HOST_MSIX ) {struct kvm_guest_msix_entry *guest_entries = assigned_dev->guest_msix_entries; + +spin_lock_irq (&assigned_dev->assigned_dev_lock);for (i =0 ; i < assigned_dev->entries_nr; i++) {if (!(guest_entries[i].flags &KVM_ASSIGNED_MSIX_PENDING ))continue ; guest_entries[i].flags &= ~KVM_ASSIGNED_MSIX_PENDING ; +/* +* If kvm_assigned_dev_intr sets pending for an +* entry smaller than this work instance is +* currently processing, a new work instance +* will be queued. +*/ +spin_unlock_irq (&assigned_dev->assigned_dev_lock);kvm_set_irq (assigned_dev->kvm, assigned_dev->irq_source_id, guest_entries[i].vector,1 ); +spin_lock_irq (&assigned_dev->assigned_dev_lock); } +spin_unlock_irq (&assigned_dev->assigned_dev_lock); }else kvm_set_irq (assigned_dev->kvm, assigned_dev->irq_source_id, assigned_dev->guest_irq,1 ); -spin_unlock_irq (&assigned_dev->assigned_dev_lock); }static irqreturn_t kvm_assigned_dev_intr (int irq,void *dev_id)
Hi Marcelo,
Thanks for the patch.
I put it into my kernel source tree and tested the freshly build kernel in my testing environment. The problem is now - almost - gone. The only suspicious message (ONE occurrence immediate after starting the Server 2008 R2 VM) in syslog is now:
BUG: scheduling while atomic: qemu/3674/0x00000002 Modules linked in: tun bridge stp llc ext3 jbd uhci_hcd snd_hda_codec_realtek snd_seq_dummy snd_seq_oss snd_seq_midi_event snd_seq snd_seq_device snd_pcm_oss snd_mixer_oss snd_hda_intel snd_hda_codec snd_hwdep snd_pcm snd_timer snd soundcore snd_page_alloc i915 drm_kms_helper drm i2c_algo_bit video output i2c_i801 i2c_core ide_pci_generic ide_core button intel_agp ehci_hcd thermal e1000e iTCO_wdt iTCO_vendor_support processor usbcore kvm_intel evdev sg psmouse pcspkr serio_raw kvm rtc_cmos rtc_core rtc_lib ext4 mbcache jbd2 crc16 dm_mod sr_mod cdrom sd_mod ata_generic pata_acpi ahci libata scsi_mod Pid: 3674, comm: qemu Not tainted 2.6.33.2-KVM_patch #4 Call Trace: [<ffffffff8133d414>] ? schedule+0x544/0xa60 [<ffffffffa01839ad>] ? mmu_zap_unsync_children+0x17d/0x200 [kvm] [<ffffffff8133e612>] ? __mutex_lock_slowpath+0x162/0x350 [<ffffffff8133e809>] ? mutex_lock+0x9/0x20 [<ffffffffa016cc87>] ? kvm_ioapic_set_irq+0x47/0x160 [kvm] [<ffffffffa016d914>] ? kvm_set_irq+0xf4/0x190 [kvm] [<ffffffffa016d9b0>] ? kvm_set_ioapic_irq+0x0/0x50 [kvm] [<ffffffffa016da00>] ? kvm_set_pic_irq+0x0/0x50 [kvm] [<ffffffffa018587f>] ? paging64_walk_addr+0x25f/0x750 [kvm] [<ffffffff8133e70d>] ? __mutex_lock_slowpath+0x25d/0x350 [<ffffffffa016e905>] ? kvm_assigned_dev_ack_irq+0x35/0x90 [kvm] [<ffffffffa016d771>] ? kvm_notify_acked_irq+0x71/0x120 [kvm] [<ffffffffa016ce13>] ? kvm_ioapic_update_eoi+0x73/0xd0 [kvm] [<ffffffffa0192689>] ? apic_reg_write+0x569/0x700 [kvm] [<ffffffffa0192939>] ? apic_mmio_write+0x69/0x70 [kvm] [<ffffffffa0178fec>] ? emulator_write_emulated_onepage+0xac/0x1b0 [kvm] [<ffffffffa018d9c5>] ? x86_emulate_insn+0x1d25/0x4d20 [kvm] [<ffffffffa018b98e>] ? x86_decode_insn+0x96e/0xba0 [kvm] [<ffffffffa018442c>] ? kvm_mmu_unprotect_page_virt+0xec/0x100 [kvm] [<ffffffffa0178c13>] ? emulate_instruction+0xd3/0x380 [kvm] [<ffffffff8133fe3e>] ? __down_read+0xce/0xd0 [<ffffffffa0191c69>] ? apic_update_ppr+0x29/0x70 [kvm] [<ffffffffa01fcc08>] ? handle_apic_access+0x18/0x40 [kvm_intel] [<ffffffffa017ba7d>] ? kvm_arch_vcpu_ioctl_run+0x3ad/0xcf0 [kvm] [<ffffffff81081af7>] ? wake_futex+0x37/0x70 [<ffffffffa0168d5c>] ? kvm_vcpu_ioctl+0x53c/0x910 [kvm] [<ffffffff81013ab3>] ? __switch_to_xtra+0x163/0x1a0 [<ffffffff810088b1>] ? __switch_to+0x271/0x340 [<ffffffff81121405>] ? vfs_ioctl+0x35/0xd0 [<ffffffff811215c8>] ? do_vfs_ioctl+0x88/0x570 [<ffffffff8133d1c9>] ? schedule+0x2f9/0xa60 [<ffffffff81121b30>] ? sys_ioctl+0x80/0xa0 [<ffffffff810cf4ea>] ? fire_user_return_notifiers+0x3a/0x70 [<ffffffff8100a042>] ? system_call_fastpath+0x16/0x1b
kvm: emulating exchange as write
Honestly my knowledge of the kvm internals is not sufficient to decide if this bug report still belongs to my problem or is something different. So if you need more information or additional testing please let me know..
Best regards
Ralf Bonenkamp
-----Ursprüngliche Nachricht-----
Von: Marcelo Tosatti [mailto:[email protected]]
Gesendet: Dienstag, 20. April 2010 17:54
An: kvm
Cc: Ralf Bonenkamp; Chris Wright; Yang, Sheng
Betreff: *** GMX Spamverdacht *** [UNTESTED] KVM: do not call kvm_set_irq from irq disabled section
The assigned device interrupt work handler calls kvm_set_irq, which can sleep, for example, waiting for the ioapic mutex, from irq disabled section.
https://bugzilla.kernel.org/show_bug.cgi?id=15725
Fix by dropping assigned_dev_lock (and re-enabling interrupts) before invoking kvm_set_irq for the KVM_DEV_IRQ_HOST_MSIX case. Other cases do not require the lock or interrupts disabled (a new work instance will be queued in case of concurrent interrupt).
KVM-Stable-Tag.
Quoted 24 lines · Ralf
Hi Marcelo,
Thanks for the patch.
I put it into my kernel source tree and tested the freshly build kernel in
my testing environment. The problem is now - almost - gone. The only suspicious message (ONE occurrence immediate after starting the Server 2008 R2 VM) in syslog is now:BUG: scheduling while atomic: qemu/3674/0x00000002 Modules linked in: tun bridge stp llc ext3 jbd uhci_hcd snd_hda_codec_realtek snd_seq_dummy snd_seq_oss snd_seq_midi_event snd_seq snd_seq_device snd_pcm_oss snd_mixer_oss snd_hda_intel snd_hda_codec snd_hwdep snd_pcm snd_timer snd soundcore snd_page_alloc i915 drm_kms_helper drm i2c_algo_bit video output i2c_i801 i2c_core ide_pci_generic ide_core button intel_agp ehci_hcd thermal e1000e iTCO_wdt iTCO_vendor_support processor usbcore kvm_intel evdev sg psmouse pcspkr serio_raw kvm rtc_cmos rtc_core rtc_lib ext4 mbcache jbd2 crc16 dm_mod sr_mod cdrom sd_mod ata_generic pata_acpi ahci libata scsi_mod Pid: 3674, comm: qemu Not tainted 2.6.33.2-KVM_patch #4 Call Trace: [<ffffffff8133d414>] ? schedule+0x544/0xa60 [<ffffffffa01839ad>] ? mmu_zap_unsync_children+0x17d/0x200 [kvm] [<ffffffff8133e612>] ? __mutex_lock_slowpath+0x162/0x350 [<ffffffff8133e809>] ? mutex_lock+0x9/0x20
Quoted 8 lines
[<ffffffffa016cc87>] ? kvm_ioapic_set_irq+0x47/0x160 [kvm] [<ffffffffa016d914>] ? kvm_set_irq+0xf4/0x190 [kvm] [<ffffffffa016d9b0>] ? kvm_set_ioapic_irq+0x0/0x50 [kvm] [<ffffffffa016da00>] ? kvm_set_pic_irq+0x0/0x50 [kvm] [<ffffffffa018587f>] ? paging64_walk_addr+0x25f/0x750 [kvm] [<ffffffff8133e70d>] ? __mutex_lock_slowpath+0x25d/0x350 [<ffffffffa016e905>] ? kvm_assigned_dev_ack_irq+0x35/0x90 [kvm] [<ffffffffa016d771>] ? kvm_notify_acked_irq+0x71/0x120 [kvm]
Seems this time is kvm_notify_acked_irq() with RCU.
Signature · 2 lines
regards Yang, Sheng
Quoted 54 lines
[<
ffffffffa016ce13>] ?kvm_ioapic_update_eoi+0x73/0xd0[kvm] [<ffffffffa0192689>] ?apic_reg_write+0x569/0x700[kvm] [<ffffffffa0192939>] ?apic_mmio_write+0x69/0x70[kvm] [<ffffffffa0178fec>] ?emulator_write_emulated_onepage+0xac/0x1b0[kvm] [<ffffffffa018d9c5>] ?x86_emulate_insn+0x1d25/0x4d20[kvm] [<ffffffffa018b98e>] ?x86_decode_insn+0x96e/0xba0[kvm] [<ffffffffa018442c>] ?kvm_mmu_unprotect_page_virt+0xec/0x100[kvm] [<ffffffffa0178c13>] ?emulate_instruction+0xd3/0x380[kvm] [<ffffffff8133fe3e>] ?__down_read+0xce/0xd0[<ffffffffa0191c69>] ?apic_update_ppr+0x29/0x70[kvm] [<ffffffffa01fcc08>] ?handle_apic_access+0x18/0x40[kvm_intel] [<ffffffffa017ba7d>] ?kvm_arch_vcpu_ioctl_run+0x3ad/0xcf0[kvm] [<ffffffff81081af7>] ?wake_futex+0x37/0x70[<ffffffffa0168d5c>] ?kvm_vcpu_ioctl+0x53c/0x910[kvm] [<ffffffff81013ab3>] ?__switch_to_xtra+0x163/0x1a0[<ffffffff810088b1>] ?__switch_to+0x271/0x340[<ffffffff81121405>] ?vfs_ioctl+0x35/0xd0[<ffffffff811215c8>] ?do_vfs_ioctl+0x88/0x570[<ffffffff8133d1c9>] ?schedule+0x2f9/0xa60[<ffffffff81121b30>] ?sys_ioctl+0x80/0xa0[<ffffffff810cf4ea>] ?fire_user_return_notifiers+0x3a/0x70[<ffffffff8100a042>] ?system_call_fastpath+0x16/0x1b
kvm: emulating exchange as writeHonestly my knowledge of the kvm internals is not sufficient to decide if
this bug report still belongs to my problem or is something different. So if you need more information or additional testing please let me know..Best regards
Ralf Bonenkamp-----Ursprüngliche Nachricht-----
Von: Marcelo Tosatti [mailto:[email protected]]
Gesendet: Dienstag, 20. April 2010 17:54
An: kvm
Cc: Ralf Bonenkamp; Chris Wright; Yang, Sheng
Betreff: *** GMX Spamverdacht *** [UNTESTED] KVM: do not callkvm_set_irq
from irq disabled sectionThe assigned device interrupt work handler calls
kvm_set_irq, which can sleep, for example, waiting for the ioapic mutex, from irq disabled section.https://bugzilla.kernel.org/show_bug.cgi?id=15725
Fix by dropping
assigned_dev_lock(and re-enabling interrupts) before invokingkvm_set_irqfor theKVM_DEV_IRQ_HOST_MSIXcase. Other cases do not require the lock or interrupts disabled (a new work instance will be queued in case of concurrent interrupt).KVM-Stable-Tag.
Signed-off-by Marcelo Tosatti <[email protected]>
Quoted 10 lines · On Tuesday 20 April 2010 23:54:01 Marcelo Tosatti wrote:
The assigned device interrupt work handler calls
kvm_set_irq, which can sleep, for example, waiting for the ioapic mutex, from irq disabled section.https://bugzilla.kernel.org/show_bug.cgi?id=15725
Fix by dropping
assigned_dev_lock(and re-enabling interrupts) before invokingkvm_set_irqfor theKVM_DEV_IRQ_HOST_MSIXcase. Other cases do not require the lock or interrupts disabled (a new work instance will be queued in case of concurrent interrupt).
Looks fine, but depends on the new work would be queued sounds a little tricky...
How about a local_irq_disable() at the beginning? It can ensure no concurrent interrupts would happen as well I think.
Quoted 9 lines
KVM-Stable-Tag.
Signed-off-by Marcelo Tosatti <[email protected]>virt/kvm/assigned-dev.c +0
-0
virt/kvm/assigned-dev.c static void · line 70
Quoted 8 lines
virt/kvm/assigned-dev.c +0
-1@@ -64,24 +64,33 @@ static void kvm_assigned_dev_interrupt_work_handler(struct work_struct *work) interrupt_work); kvm = assigned_dev->kvm; -spin_lock_irq (&assigned_dev->assigned_dev_lock);if (assigned_dev->irq_requested_type &KVM_DEV_IRQ_HOST_MSIX ) {struct kvm_guest_msix_entry *guest_entries = assigned_dev->guest_msix_entries;
irq_requested_type and guest_msix_entries should also protected by the lock. So how about another spin_lock()/unlock() pair wraps the second kvm_set_irq()?
Quoted 13 lines
virt/kvm/assigned-dev.c +8
-0+ +spin_lock_irq (&assigned_dev->assigned_dev_lock);for (i =0 ; i < assigned_dev->entries_nr; i++) {if (!(guest_entries[i].flags &KVM_ASSIGNED_MSIX_PENDING ))continue ; guest_entries[i].flags &= ~KVM_ASSIGNED_MSIX_PENDING ; +/* +* If kvm_assigned_dev_intr sets pending for an +* entry smaller than this work instance is +* currently processing, a new work instance +* will be queued. +*/
virt/kvm/assigned-dev.c static void kvm_assigned_dev_interrupt_work_handler(struct work_struct *work) · line 92
Quoted 10 lines
virt/kvm/assigned-dev.c +3
-0+spin_unlock_irq (&assigned_dev->assigned_dev_lock);kvm_set_irq (assigned_dev->kvm, assigned_dev->irq_source_id, guest_entries[i].vector,1 ); +spin_lock_irq (&assigned_dev->assigned_dev_lock); } +spin_unlock_irq (&assigned_dev->assigned_dev_lock); }else kvm_set_irq (assigned_dev->kvm, assigned_dev->irq_source_id, assigned_dev->guest_irq,1 );
Or could we make kvm_set_irq() atomic? Though the code path is a little long for spinlock.
Quoted 5 lines
virt/kvm/assigned-dev.c +0
-1-spin_unlock_irq (&assigned_dev->assigned_dev_lock); }static irqreturn_t kvm_assigned_dev_intr (int irq,void *dev_id)
Signature · 2 lines
regards Yang, Sheng
Quoted 7 lines · Sheng
Quoted 6 lines · On Tuesday 20 April 2010 23:54:01 Marcelo Tosatti wrote:
The assigned device interrupt work handler calls
kvm_set_irq, which can sleep, for example, waiting for the ioapic mutex, from irq disabled section.
Quoted 7 lines
Quoted 4 lines
Fix by dropping
assigned_dev_lock(and re-enabling interrupts) before invokingkvm_set_irqfor theKVM_DEV_IRQ_HOST_MSIXcase. Other cases do not require the lock or interrupts disabled (a new work instance will be queued in case of concurrent interrupt).Looks fine, but depends on the new work would be queued sounds a little tricky...
I think thats guaranteed behaviour, so you can schedule_work() from within a worker.
Quoted 16 lines
How about a
local_irq_disable()at the beginning? It can ensure no concurrent interrupts would happen as well I think.Quoted 13 lines
KVM-Stable-Tag.
Signed-off-by Marcelo Tosatti <[email protected]>virt/kvm/assigned-dev.c +0
-0@@ -64,24 +64,33 @@ static void kvm_assigned_dev_interrupt_work_handler(struct work_struct *work) interrupt_work); kvm = assigned_dev->kvm;
Quoted 7 lines
virt/kvm/assigned-dev.c static void kvm_assigned_dev_interrupt_work_handler(struct work_struct *work) · line 69
Quoted 4 lines
virt/kvm/assigned-dev.c +0
-1-spin_lock_irq (&assigned_dev->assigned_dev_lock);if (assigned_dev->irq_requested_type &KVM_DEV_IRQ_HOST_MSIX ) {struct kvm_guest_msix_entry *guest_entries = assigned_dev->guest_msix_entries;
irq_requested_typeandguest_msix_entriesshould also protected by the lock. So how about another spin_lock()/unlock() pair wraps the secondkvm_set_irq()?
Don't think its necessary because irq_requested_type and guest_msix_entries never change once setup.
They only change via deassign_irq, which first disables the IRQ and flushes pending work.
Quoted 18 lines
Quoted 18 lines
virt/kvm/assigned-dev.c +10
-0+ +spin_lock_irq (&assigned_dev->assigned_dev_lock);for (i =0 ; i < assigned_dev->entries_nr; i++) {if (!(guest_entries[i].flags &KVM_ASSIGNED_MSIX_PENDING ))continue ; guest_entries[i].flags &= ~KVM_ASSIGNED_MSIX_PENDING ; +/* +* If kvm_assigned_dev_intr sets pending for an +* entry smaller than this work instance is +* currently processing, a new work instance +* will be queued. +*/ +spin_unlock_irq (&assigned_dev->assigned_dev_lock);kvm_set_irq (assigned_dev->kvm, assigned_dev->irq_source_id, guest_entries[i].vector,1 ); +spin_lock_irq (&assigned_dev->assigned_dev_lock);
Quoted 8 lines
virt/kvm/assigned-dev.c static void kvm_assigned_dev_interrupt_work_handler(struct work_struct *work) · line 92
Quoted 5 lines
virt/kvm/assigned-dev.c +1
-0} +spin_unlock_irq (&assigned_dev->assigned_dev_lock); }else kvm_set_irq (assigned_dev->kvm, assigned_dev->irq_source_id, assigned_dev->guest_irq,1 );Or could we make
kvm_set_irq()atomic? Though the code path is a little long for spinlock.
Yes, given the sleep-inside-RCU-protected section bug from kvm_notify_acked_irq, either that or convert IRQ locking to SRCU.
But as you said, the code paths are long and potentially slow, so probably SRCU is a better alternative.
Gleb?
Quoted 10 lines · Marcelo Tosatti
Quoted 2 lines
Or could we make
kvm_set_irq()atomic? Though the code path is a little long for spinlock.Yes, given the sleep-inside-RCU-protected section bug from
kvm_notify_acked_irq, either that or convert IRQ locking to SRCU.But as you said, the code paths are long and potentially slow, so probably SRCU is a better alternative.
Gleb?
kvm_set_irq() was converted to rcu from mutex to make msix interrupt injection scalable.
--
Gleb.
Quoted 7 lines · Gleb Natapov
Quoted 6 lines · Marcelo Tosatti
Quoted 2 lines
Or could we make
kvm_set_irq()atomic? Though the code path is a little long for spinlock.Yes, given the sleep-inside-RCU-protected section bug from
kvm_notify_acked_irq, either that or convert IRQ locking to SRCU.
Quoted 6 lines
Quoted 4 lines
But as you said, the code paths are long and potentially slow, so probably SRCU is a better alternative.
Gleb?
kvm_set_irq()was converted to rcu from mutex to make msix interrupt injection scalable.
We meant ioapic lock. See the last report from Ralf on this thread.
Quoted 8 lines · Marcelo Tosatti
Quoted 7 lines · Gleb Natapov
Quoted 6 lines · Marcelo Tosatti
Quoted 2 lines
Or could we make
kvm_set_irq()atomic? Though the code path is a little long for spinlock.Yes, given the sleep-inside-RCU-protected section bug from
kvm_notify_acked_irq, either that or convert IRQ locking to SRCU.
Quoted 8 lines
Quoted 6 lines
Quoted 4 lines
But as you said, the code paths are long and potentially slow, so probably SRCU is a better alternative.
Gleb?
kvm_set_irq()was converted to rcu from mutex to make msix interrupt injection scalable.We meant ioapic lock. See the last report from Ralf on this thread.
Can we solve the problem by calling ack notifier outside rcu read section in kvm_notify_acked_irq()?
--
Gleb.
Quoted 12 lines · Gleb Natapov
Quoted 11 lines · Marcelo Tosatti
Quoted 10 lines · Gleb Natapov
Quoted 9 lines · Marcelo Tosatti
Quoted 2 lines
Or could we make
kvm_set_irq()atomic? Though the code path is a little long for spinlock.Yes, given the sleep-inside-RCU-protected section bug from
kvm_notify_acked_irq, either that or convert IRQ locking to SRCU.But as you said, the code paths are long and potentially slow, so probably SRCU is a better alternative.
Quoted 7 lines
Quoted 5 lines
Quoted 3 lines
Quoted 1 line
Gleb?
kvm_set_irq()was converted to rcu from mutex to make msix interrupt injection scalable.We meant ioapic lock. See the last report from Ralf on this thread.
Can we solve the problem by calling ack notifier outside rcu read section in
kvm_notify_acked_irq()?
The unregister path does
- remove_from_list(entry)
- synchronize_rcu
- kfree(entry)
So if kvm_notify_acked_irq sleeps, synchronize_rcu can succeed, and the notifier entry can be freed.
Quoted 21 lines · Marcelo Tosatti
Quoted 12 lines · Gleb Natapov
Quoted 11 lines · Marcelo Tosatti
Quoted 10 lines · Gleb Natapov
Quoted 9 lines · Marcelo Tosatti
Quoted 2 lines
Or could we make
kvm_set_irq()atomic? Though the code path is a little long for spinlock.Yes, given the sleep-inside-RCU-protected section bug from
kvm_notify_acked_irq, either that or convert IRQ locking to SRCU.But as you said, the code paths are long and potentially slow, so probably SRCU is a better alternative.
Quoted 7 lines
Quoted 5 lines
Quoted 3 lines
Quoted 1 line
Gleb?
kvm_set_irq()was converted to rcu from mutex to make msix interrupt injection scalable.We meant ioapic lock. See the last report from Ralf on this thread.
Can we solve the problem by calling ack notifier outside rcu read section in
kvm_notify_acked_irq()?
Quoted 8 lines
The unregister path does
-
remove_from_list(entry)
-synchronize_rcu
- kfree(entry)So if
kvm_notify_acked_irqsleeps,synchronize_rcucan succeed, and the notifier entry can be freed.
What I mean is kvm_notify_acked_irq() will iterate over all ack entries in rcu read protected section, but instead of calling callback it will collect them into the array and call them outside rcu read section. At this point it doesn't matter if entry is unregistered since the copy is used to actually call the notifier.
--
Gleb.
Quoted 28 lines · Gleb Natapov
Quoted 27 lines · Marcelo Tosatti
Quoted 12 lines · Gleb Natapov
Quoted 11 lines · Marcelo Tosatti
Quoted 10 lines · Gleb Natapov
Quoted 9 lines · Marcelo Tosatti
Quoted 2 lines
Or could we make
kvm_set_irq()atomic? Though the code path is a little long for spinlock.Yes, given the sleep-inside-RCU-protected section bug from
kvm_notify_acked_irq, either that or convert IRQ locking to SRCU.But as you said, the code paths are long and potentially slow, so probably SRCU is a better alternative.
Quoted 7 lines
Quoted 5 lines
Quoted 3 lines
Quoted 1 line
Gleb?
kvm_set_irq()was converted to rcu from mutex to make msix interrupt injection scalable.We meant ioapic lock. See the last report from Ralf on this thread.
Can we solve the problem by calling ack notifier outside rcu read section in
kvm_notify_acked_irq()?The unregister path does
-
remove_from_list(entry)
-synchronize_rcu
- kfree(entry)
Quoted 7 lines
Quoted 2 lines
So if
kvm_notify_acked_irqsleeps,synchronize_rcucan succeed, and the notifier entry can be freed.What I mean is
kvm_notify_acked_irq()will iterate over all ack entries in rcu read protected section, but instead of calling callback it will collect them into the array and call them outside rcu read section. At this point it doesn't matter if entry is unregistered since the copy is used to actually call the notifier.
Here it is, but no, this trick can't be done safely for ack notifiers because they are unregistered at runtime by device assignment.
How does the freeing path knows it can proceed to free its entry if there is no reliable way to know if there is a reference to itself? (think "priv" gets freed between rcu_read_unlock and ->irq_acked with the patch below).
I can convert to SRCU if you have no objections.
arch/x86/kvm/i8254.c +3 -2
@@ -241,8 +241,8 @@ int pit_has_pending_timer(struct kvm_vcpu *vcpu)static void kvm_pit_ack_irq (struct kvm_irq_ack_notifier *kian) { - struct kvm_kpit_state *ps = container_of(kian, struct kvm_kpit_state, - irq_ack_notifier); +struct kvm_kpit_state *ps = kian->priv; +raw_spin_lock (&ps->inject_lock);if (atomic_dec_return (&ps->pit_timer.pending) <0 )atomic_inc (&ps->pit_timer.pending);
@@ -636,6 +636,7 @@ struct kvm_pit *kvm_create_pit(struct kvm *kvm, u32 flags) CLOCK_MONOTONIC, HRTIMER_MODE_ABS); pit_state->irq_ack_notifier.gsi =0 ; pit_state->irq_ack_notifier.irq_acked = kvm_pit_ack_irq; + pit_state->irq_ack_notifier.priv = &pit->pit_state;kvm_register_irq_ack_notifier (kvm, &pit_state->irq_ack_notifier); pit_state->pit_timer.reinject = true;mutex_unlock (&pit->pit_state.lock);
include/linux/kvm_host.h +1 -0
@@ -404,6 +404,7 @@ struct kvm_irq_ack_notifier {struct hlist_node link;unsigned gsi;void (*irq_acked)(struct kvm_irq_ack_notifier *kian); +void *priv; };#define KVM_ASSIGNED_MSIX_PENDING 0x1
virt/kvm/assigned-dev.c +2 -2
@@ -121,8 +121,7 @@ static void kvm_assigned_dev_ack_irq(struct kvm_irq_ack_notifier *kian)if (kian->gsi ==-1 )return ; - dev = container_of(kian, struct kvm_assigned_dev_kernel, - ack_notifier); + dev = kian->priv;kvm_set_irq (dev->kvm, dev->irq_source_id, dev->guest_irq,0 );
@@ -563,6 +562,7 @@ static int kvm_vm_ioctl_assign_device(struct kvm *kvm, match->irq_source_id =-1 ; match->kvm = kvm; match->ack_notifier.irq_acked = kvm_assigned_dev_ack_irq; + match->ack_notifier.priv = match;INIT_WORK (&match->interrupt_work, kvm_assigned_dev_interrupt_work_handler);
virt/kvm/irq_comm.c +12 -3
@@ -175,11 +175,14 @@ int kvm_set_irq(struct kvm *kvm, int irq_source_id, u32 irq, int level)return ret; } +#define MAX_ACK_NOTIFIER_PER_GSI 4 +void kvm_notify_acked_irq (struct kvm *kvm,unsigned irqchip,unsigned pin) {struct kvm_irq_ack_notifier *kian; +struct kvm_irq_ack_notifier acks[MAX_ACK_NOTIFIER_PER_GSI ];struct hlist_node *n; -int gsi; +int gsi, i, acks_nr =0 ;trace_kvm_ack_irq (irqchip, pin);
@@ -188,9 +191,15 @@ void kvm_notify_acked_irq(struct kvm *kvm, unsigned irqchip, unsigned pin)if (gsi !=-1 )hlist_for_each_entry_rcu (kian, n, &kvm->irq_ack_notifier_list, link) -if (kian->gsi == gsi) - kian->irq_acked (kian); +if (kian->gsi == gsi) { +if (acks_nr ==MAX_ACK_NOTIFIER_PER_GSI ) +break ; + acks[acks_nr++] = *kian; + }rcu_read_unlock (); + +for (i =0 ; i < acks_nr; i++) + acks[i].irq_acked (&acks[i]); } void kvm_register_irq_ack_notifier(struct kvm *kvm,
Quoted 37 lines · Marcelo Tosatti
Quoted 28 lines · Gleb Natapov
Quoted 27 lines · Marcelo Tosatti
Quoted 12 lines · Gleb Natapov
Quoted 11 lines · Marcelo Tosatti
Quoted 10 lines · Gleb Natapov
Quoted 9 lines · Marcelo Tosatti
Quoted 2 lines
Or could we make
kvm_set_irq()atomic? Though the code path is a little long for spinlock.Yes, given the sleep-inside-RCU-protected section bug from
kvm_notify_acked_irq, either that or convert IRQ locking to SRCU.But as you said, the code paths are long and potentially slow, so probably SRCU is a better alternative.
Quoted 7 lines
Quoted 5 lines
Quoted 3 lines
Quoted 1 line
Gleb?
kvm_set_irq()was converted to rcu from mutex to make msix interrupt injection scalable.We meant ioapic lock. See the last report from Ralf on this thread.
Can we solve the problem by calling ack notifier outside rcu read section in
kvm_notify_acked_irq()?The unregister path does
-
remove_from_list(entry)
-synchronize_rcu
- kfree(entry)Quoted 7 lines
Quoted 2 lines
So if
kvm_notify_acked_irqsleeps,synchronize_rcucan succeed, and the notifier entry can be freed.What I mean is
kvm_notify_acked_irq()will iterate over all ack entries in rcu read protected section, but instead of calling callback it will collect them into the array and call them outside rcu read section. At this point it doesn't matter if entry is unregistered since the copy is used to actually call the notifier.
Quoted 8 lines
Here it is, but no, this trick can't be done safely for ack notifiers because they are unregistered at runtime by device assignment.
How does the freeing path knows it can proceed to free its entry if there is no reliable way to know if there is a reference to itself? (think "priv" gets freed between
rcu_read_unlockand ->irq_acked with the patch below).
Yeah, I see :(
Quoted 2 lines
I can convert to SRCU if you have no objections.
AFAIR there was a disadvantage comparing to RCU, but I don't remember what it was exactly. What about converting PIC/IOAPIC mutexes into spinlocks?
--
Gleb.
Quoted 46 lines · Gleb Natapov
Quoted 37 lines · Marcelo Tosatti
Quoted 28 lines · Gleb Natapov
Quoted 27 lines · Marcelo Tosatti
Quoted 12 lines · Gleb Natapov
Quoted 11 lines · Marcelo Tosatti
Quoted 10 lines · Gleb Natapov
Quoted 9 lines · Marcelo Tosatti
Quoted 2 lines
Or could we make
kvm_set_irq()atomic? Though the code path is a little long for spinlock.Yes, given the sleep-inside-RCU-protected section bug from
kvm_notify_acked_irq, either that or convert IRQ locking to SRCU.But as you said, the code paths are long and potentially slow, so probably SRCU is a better alternative.
Quoted 7 lines
Quoted 5 lines
Quoted 3 lines
Quoted 1 line
Gleb?
kvm_set_irq()was converted to rcu from mutex to make msix interrupt injection scalable.We meant ioapic lock. See the last report from Ralf on this thread.
Can we solve the problem by calling ack notifier outside rcu read section in
kvm_notify_acked_irq()?The unregister path does
-
remove_from_list(entry)
-synchronize_rcu
- kfree(entry)Quoted 7 lines
Quoted 2 lines
So if
kvm_notify_acked_irqsleeps,synchronize_rcucan succeed, and the notifier entry can be freed.What I mean is
kvm_notify_acked_irq()will iterate over all ack entries in rcu read protected section, but instead of calling callback it will collect them into the array and call them outside rcu read section. At this point it doesn't matter if entry is unregistered since the copy is used to actually call the notifier.Quoted 8 lines
Here it is, but no, this trick can't be done safely for ack notifiers because they are unregistered at runtime by device assignment.
How does the freeing path knows it can proceed to free its entry if there is no reliable way to know if there is a reference to itself? (think "priv" gets freed between
rcu_read_unlockand ->irq_acked with the patch below).
Quoted 6 lines
Yeah, I see :(
Quoted 2 lines
I can convert to SRCU if you have no objections.
AFAIR there was a disadvantage comparing to RCU, but I don't remember what it was exactly.
http://www.mentby.com/paul-e-mckenney/kvm-patch-v3-13-kvm-fix-race-in-irqrouting-logic.html
But for KVM IRQ path's it should not matter much since usage of grace periods is rare (registration/unregistration is very rare compared to read side), and the IRQ path's are already large and slow, so the added overhead should not be noticeable.
Quoted 1 line
What about converting PIC/IOAPIC mutexes into spinlocks?
Works for me, but on large guests the spinning will be noticeable. I believe.
Avi?
Quoted 54 lines · Marcelo Tosatti
Quoted 46 lines · Gleb Natapov
Quoted 37 lines · Marcelo Tosatti
Quoted 28 lines · Gleb Natapov
Quoted 27 lines · Marcelo Tosatti
Quoted 12 lines · Gleb Natapov
Quoted 11 lines · Marcelo Tosatti
Quoted 10 lines · Gleb Natapov
Quoted 9 lines · Marcelo Tosatti
Quoted 2 lines
Or could we make
kvm_set_irq()atomic? Though the code path is a little long for spinlock.Yes, given the sleep-inside-RCU-protected section bug from
kvm_notify_acked_irq, either that or convert IRQ locking to SRCU.But as you said, the code paths are long and potentially slow, so probably SRCU is a better alternative.
Quoted 7 lines
Quoted 5 lines
Quoted 3 lines
Quoted 1 line
Gleb?
kvm_set_irq()was converted to rcu from mutex to make msix interrupt injection scalable.We meant ioapic lock. See the last report from Ralf on this thread.
Can we solve the problem by calling ack notifier outside rcu read section in
kvm_notify_acked_irq()?The unregister path does
-
remove_from_list(entry)
-synchronize_rcu
- kfree(entry)Quoted 7 lines
Quoted 2 lines
So if
kvm_notify_acked_irqsleeps,synchronize_rcucan succeed, and the notifier entry can be freed.What I mean is
kvm_notify_acked_irq()will iterate over all ack entries in rcu read protected section, but instead of calling callback it will collect them into the array and call them outside rcu read section. At this point it doesn't matter if entry is unregistered since the copy is used to actually call the notifier.Quoted 8 lines
Here it is, but no, this trick can't be done safely for ack notifiers because they are unregistered at runtime by device assignment.
How does the freeing path knows it can proceed to free its entry if there is no reliable way to know if there is a reference to itself? (think "priv" gets freed between
rcu_read_unlockand ->irq_acked with the patch below).Quoted 6 lines
Yeah, I see :(
Quoted 2 lines
I can convert to SRCU if you have no objections.
AFAIR there was a disadvantage comparing to RCU, but I don't remember what it was exactly.
Quoted 7 lines
http://www.mentby.com/paul-e-mckenney/kvm-patch-v3-13-kvm-fix-race-in-irqrouting-logic.html
But for KVM IRQ path's it should not matter much since usage of grace periods is rare (registration/unregistration is very rare compared to read side), and the IRQ path's are already large and slow, so the added overhead should not be noticeable.
msix path shouldn't be slow and this is the case we are trying to optimize.
SRCU's read-side primitives are also significantly slower than those of RCU.
Sounds not too optimistic.
Quoted 4 lines
Quoted 1 line
What about converting PIC/IOAPIC mutexes into spinlocks?
Works for me, but on large guests the spinning will be noticeable. I believe.
For interrupts going through IOPIC, but we know this is not scalable anyway.
Quoted 2 lines
Avi?
--
Gleb.
Quoted 10 lines · Gleb Natapov
Quoted 7 lines
Quoted 4 lines
What about converting PIC/IOAPIC mutexes into spinlocks?
Works for me, but on large guests the spinning will be noticeable. I believe.
For interrupts going through IOPIC, but we know this is not scalable anyway.
Yes. We also wanted to convert the ioapic/pic to spinlocks so we could queue the interrupt from the PIT directly instead of using KVM_REQ_PENDING_TIMER which keeps confusing me. Chris Lalancette posted a patchset for this a while back but it was never completed.
I'm not really happy with adding lots of spin_lock_irqsave()s though, especially on the ioapic which may iterate over all vcpus (not worried about scaling, but about a malicious guest hurting host latency).
An alternative is make kvm_set_irq() irq safe: if msi, do things immediately, otherwise post a work item. So we can call kvm_set_irq() directly from the interrupt.
Alternative alternative (perhaps better for short term): switch assigned_dev_lock to a mutex (we're already in a work handler, no need for spinlock). The race between the irq and removal of an assigned device is closed by free_irq():
lock
mark assigned device as going away
unlock
free_irq()
actually kill it
like invalid mmu pages.
Signature · 1 line
Do not meddle in the internals of kernels, for they are subtle and quick to panic.
Quoted 8 lines · Avi Kivity
Quoted 7 lines · Gleb Natapov
Quoted 7 lines
Quoted 4 lines
What about converting PIC/IOAPIC mutexes into spinlocks?
Works for me, but on large guests the spinning will be noticeable. I believe.
Quoted 8 lines
Quoted 3 lines
For interrupts going through IOPIC, but we know this is not scalable anyway.
Yes. We also wanted to convert the ioapic/pic to spinlocks so we could queue the interrupt from the PIT directly instead of using
KVM_REQ_PENDING_TIMERwhich keeps confusing me. Chris Lalancette posted a patchset for this a while back but it was never completed.
Yeah, I'm sorry I never completed it. It turns out that with the HPET changes that went in around the time I was looking at it, that set of patches wasn't really required to fix the problem I was seeing with kdump.
That being said, if it's useful to somebody, I can repost the patches (though they are woefully out-of-date now). Let me know if you want to see them again.
Signature · 1 line
Chris Lalancette
Quoted 22 lines · Chris Lalancette
Quoted 11 lines · Avi Kivity
Quoted 9 lines · Gleb Natapov
Quoted 9 lines
Quoted 5 lines
What about converting PIC/IOAPIC mutexes into spinlocks?
Works for me, but on large guests the spinning will be noticeable. I believe.
Quoted 9 lines
Quoted 4 lines
For interrupts going through IOPIC, but we know this is not scalable anyway.
Yes. We also wanted to convert the ioapic/pic to spinlocks so we could queue the interrupt from the PIT directly instead of using
KVM_REQ_PENDING_TIMERwhich keeps confusing me. Chris Lalancette posted a patchset for this a while back but it was never completed.
Quoted 8 lines
Yeah, I'm sorry I never completed it. It turns out that with the HPET changes that went in around the time I was looking at it, that set of patches wasn't really required to fix the problem I was seeing with kdump.
That being said, if it's useful to somebody, I can repost the patches (though they are woefully out-of-date now). Let me know if you want to see them again.
Let's see if one of the alternatives works out. I prefer to keep the critical sections short.
Signature · 1 line
Do not meddle in the internals of kernels, for they are subtle and quick to panic.
KVM: convert ioapic lock to spinlock
In reply to Avi KivityRalf, can you give this patch a try, please? (revert the first one first).
-----
kvm_set_irq is used from non sleepable contexes, so convert ioapic from mutex to spinlock.
virt/kvm/ioapic.c +15 -15
@@ -196,7 +196,7 @@ int kvm_ioapic_set_irq(struct kvm_ioapic *ioapic, int irq, int level)union kvm_ioapic_redirect_entry entry;int ret =1 ; -mutex_lock (&ioapic->lock); +spin_lock (&ioapic->lock);if (irq >=0 && irq <IOAPIC_NUM_PINS ) { entry = ioapic->redirtbl[irq]; level ^= entry.fields.polarity;
@@ -213,7 +213,7 @@ int kvm_ioapic_set_irq(struct kvm_ioapic *ioapic, int irq, int level) }trace_kvm_ioapic_set_irq (entry.bits, irq, ret ==0 ); } -mutex_unlock (&ioapic->lock); +spin_unlock (&ioapic->lock);return ret; }
@@ -237,9 +237,9 @@ static void __kvm_ioapic_update_eoi(struct kvm_ioapic *ioapic, int vector,* is dropped it will be put into irr and will be delivered * after ack notifier returns. */ -mutex_unlock (&ioapic->lock); +spin_unlock (&ioapic->lock);kvm_notify_acked_irq (ioapic->kvm,KVM_IRQCHIP_IOAPIC , i); -mutex_lock (&ioapic->lock); +spin_lock (&ioapic->lock);if (trigger_mode !=IOAPIC_LEVEL_TRIG )continue ;
@@ -258,9 +258,9 @@ void kvm_ioapic_update_eoi(struct kvm *kvm, int vector, int trigger_mode)smp_rmb ();if (!test_bit (vector, ioapic->handled_vectors))return ; -mutex_lock (&ioapic->lock); +spin_lock (&ioapic->lock);__kvm_ioapic_update_eoi (ioapic, vector, trigger_mode); -mutex_unlock (&ioapic->lock); +spin_unlock (&ioapic->lock); }static inline struct kvm_ioapic *to_ioapic (struct kvm_io_device *dev)
@@ -286,7 +286,7 @@ static int ioapic_mmio_read(struct kvm_io_device *this, gpa_t addr, int len,ASSERT (!(addr &0xf ));/* check alignment */ addr &=0xff ; -mutex_lock (&ioapic->lock); +spin_lock (&ioapic->lock);switch (addr) {case IOAPIC_REG_SELECT : result = ioapic->ioregsel;
@@ -300,7 +300,7 @@ static int ioapic_mmio_read(struct kvm_io_device *this, gpa_t addr, int len, result =0 ;break ; } -mutex_unlock (&ioapic->lock); +spin_unlock (&ioapic->lock);switch (len) {case 8 :
@@ -337,7 +337,7 @@ static int ioapic_mmio_write(struct kvm_io_device *this, gpa_t addr, int len, } addr &=0xff ; -mutex_lock (&ioapic->lock); +spin_lock (&ioapic->lock);switch (addr) {case IOAPIC_REG_SELECT : ioapic->ioregsel = data;
@@ -355,7 +355,7 @@ static int ioapic_mmio_write(struct kvm_io_device *this, gpa_t addr, int len,default :break ; } -mutex_unlock (&ioapic->lock); +spin_unlock (&ioapic->lock);return 0 ; }
@@ -385,7 +385,7 @@ int kvm_ioapic_init(struct kvm *kvm) ioapic =kzalloc (sizeof (struct kvm_ioapic ),GFP_KERNEL );if (!ioapic)return -ENOMEM ; -mutex_init (&ioapic->lock); +spin_lock_init (&ioapic->lock); kvm->arch.vioapic = ioapic;kvm_ioapic_reset (ioapic);kvm_iodevice_init (&ioapic->dev, &ioapic_mmio_ops);
@@ -418,9 +418,9 @@ int kvm_get_ioapic(struct kvm *kvm, struct kvm_ioapic_state *state)if (!ioapic)return -EINVAL ; -mutex_lock (&ioapic->lock); +spin_lock (&ioapic->lock);memcpy (state, ioapic,sizeof (struct kvm_ioapic_state )); -mutex_unlock (&ioapic->lock); +spin_unlock (&ioapic->lock);return 0 ; }
@@ -430,9 +430,9 @@ int kvm_set_ioapic(struct kvm *kvm, struct kvm_ioapic_state *state)if (!ioapic)return -EINVAL ; -mutex_lock (&ioapic->lock); +spin_lock (&ioapic->lock);memcpy (ioapic, state,sizeof (struct kvm_ioapic_state ));update_handled_vectors (ioapic); -mutex_unlock (&ioapic->lock); +spin_unlock (&ioapic->lock);return 0 ; }
virt/kvm/ioapic.h +1 -1
@@ -45,7 +45,7 @@ struct kvm_ioapic {struct kvm_io_device dev;struct kvm *kvm;void (*ack_notifier)(void *opaque,int irq); -struct mutex lock; +spinlock_t lock;DECLARE_BITMAP (handled_vectors,256 ); };
Quoted 31 lines · Marcelo Tosatti
The assigned device interrupt work handler calls
kvm_set_irq, which can sleep, for example, waiting for the ioapic mutex, from irq disabled section.https://bugzilla.kernel.org/show_bug.cgi?id=15725
Fix by dropping
assigned_dev_lock(and re-enabling interrupts) before invokingkvm_set_irqfor theKVM_DEV_IRQ_HOST_MSIXcase. Other cases do not require the lock or interrupts disabled (a new work instance will be queued in case of concurrent interrupt).KVM-Stable-Tag.
Signed-off-by Marcelo Tosatti<[email protected]>virt/kvm/assigned-dev.c +2
-1@@ -64,24 +64,33 @@ static void kvm_assigned_dev_interrupt_work_handler(struct work_struct *work) interrupt_work); kvm = assigned_dev->kvm; -spin_lock_irq (&assigned_dev->assigned_dev_lock);if (assigned_dev->irq_requested_type&KVM_DEV_IRQ_HOST_MSIX ) {struct kvm_guest_msix_entry *guest_entries = assigned_dev->guest_msix_entries; + +spin_lock_irq (&assigned_dev->assigned_dev_lock);for (i =0 ; i< assigned_dev->entries_nr; i++) {if (!(guest_entries[i].flags&KVM_ASSIGNED_MSIX_PENDING ))
virt/kvm/assigned-dev.c static void kvm_assigned_dev_interrupt_work_handler(struct work_struct *work) · line 84
Quoted 10 lines
virt/kvm/assigned-dev.c +7
-0continue ; guest_entries[i].flags&= ~KVM_ASSIGNED_MSIX_PENDING ; +/* +* If kvm_assigned_dev_intr sets pending for an +* entry smaller than this work instance is +* currently processing, a new work instance +* will be queued. +*/ +spin_unlock_irq (&assigned_dev->assigned_dev_lock);
What happens if assigned_dev->entries_nr is changed here?
virt/kvm/assigned-dev.c static void kvm_assigned_dev_interrupt_work_handler(struct work_struct *work) · line 95
Quoted 13 lines
virt/kvm/assigned-dev.c +2
-1kvm_set_irq (assigned_dev->kvm, assigned_dev->irq_source_id, guest_entries[i].vector,1 ); +spin_lock_irq (&assigned_dev->assigned_dev_lock); } +spin_unlock_irq (&assigned_dev->assigned_dev_lock); }else kvm_set_irq (assigned_dev->kvm, assigned_dev->irq_source_id, assigned_dev->guest_irq,1 ); -spin_unlock_irq (&assigned_dev->assigned_dev_lock); }
A less dangerous fix is to copy all vectors to be triggered into a local array, drop the lock, and replay the array into kvm_set_irq(). The else branch could do this as well.
Signature · 1 line
error compiling committee.c: too many arguments to function
Quoted 35 lines · Avi Kivity
Quoted 34 lines · Marcelo Tosatti
The assigned device interrupt work handler calls
kvm_set_irq, which can sleep, for example, waiting for the ioapic mutex, from irq disabled section.https://bugzilla.kernel.org/show_bug.cgi?id=15725
Fix by dropping
assigned_dev_lock(and re-enabling interrupts) before invokingkvm_set_irqfor theKVM_DEV_IRQ_HOST_MSIXcase. Other cases do not require the lock or interrupts disabled (a new work instance will be queued in case of concurrent interrupt).KVM-Stable-Tag.
Signed-off-by Marcelo Tosatti<[email protected]>virt/kvm/assigned-dev.c +3
-1@@ -64,24 +64,33 @@ static void kvm_assigned_dev_interrupt_work_handler(struct work_struct *work) interrupt_work); kvm = assigned_dev->kvm; -spin_lock_irq (&assigned_dev->assigned_dev_lock);if (assigned_dev->irq_requested_type&KVM_DEV_IRQ_HOST_MSIX ) {struct kvm_guest_msix_entry *guest_entries = assigned_dev->guest_msix_entries; + +spin_lock_irq (&assigned_dev->assigned_dev_lock);for (i =0 ; i< assigned_dev->entries_nr; i++) {if (!(guest_entries[i].flags&KVM_ASSIGNED_MSIX_PENDING ))continue ; guest_entries[i].flags&= ~KVM_ASSIGNED_MSIX_PENDING ; +/*
Quoted 8 lines
virt/kvm/assigned-dev.c static void kvm_assigned_dev_interrupt_work_handler(struct work_struct *work) · line 83
Quoted 6 lines
virt/kvm/assigned-dev.c +6
-0+* If kvm_assigned_dev_intr sets pending for an +* entry smaller than this work instance is +* currently processing, a new work instance +* will be queued. +*/ +spin_unlock_irq (&assigned_dev->assigned_dev_lock);What happens if
assigned_dev->entries_nris changed here?
It does not. Interrupts and work instances are stopped before irq_requested_type or entries_nr can change.
Quoted 10 lines
Quoted 10 lines
virt/kvm/assigned-dev.c +2
-0kvm_set_irq (assigned_dev->kvm, assigned_dev->irq_source_id, guest_entries[i].vector,1 ); +spin_lock_irq (&assigned_dev->assigned_dev_lock); } +spin_unlock_irq (&assigned_dev->assigned_dev_lock); }else kvm_set_irq (assigned_dev->kvm, assigned_dev->irq_source_id, assigned_dev->guest_irq,1 );
Quoted 6 lines
virt/kvm/assigned-dev.c static void kvm_assigned_dev_interrupt_work_handler(struct work_struct *work) · line 94
Quoted 2 lines
virt/kvm/assigned-dev.c +0
-1-spin_unlock_irq (&assigned_dev->assigned_dev_lock); }A less dangerous fix is to copy all vectors to be triggered into a local array, drop the lock, and replay the array into
kvm_set_irq(). The else branch could do this as well.
Its a bit large, 256 max vectors.
Quoted 29 lines · Marcelo Tosatti
Quoted 20 lines
Quoted 20 lines
virt/kvm/assigned-dev.c +3
-1@@ -64,24 +64,33 @@ static void kvm_assigned_dev_interrupt_work_handler(struct work_struct *work) interrupt_work); kvm = assigned_dev->kvm; -spin_lock_irq (&assigned_dev->assigned_dev_lock);if (assigned_dev->irq_requested_type&KVM_DEV_IRQ_HOST_MSIX ) {struct kvm_guest_msix_entry *guest_entries = assigned_dev->guest_msix_entries; + +spin_lock_irq (&assigned_dev->assigned_dev_lock);for (i =0 ; i< assigned_dev->entries_nr; i++) {if (!(guest_entries[i].flags&KVM_ASSIGNED_MSIX_PENDING ))continue ; guest_entries[i].flags&= ~KVM_ASSIGNED_MSIX_PENDING ; +/* Quoted 9 lines
virt/kvm/assigned-dev.c static void kvm_assigned_dev_interrupt_work_handler(struct work_struct *work) · line 93
Quoted 7 lines
virt/kvm/assigned-dev.c +6
-0+* If kvm_assigned_dev_intr sets pending for an +* entry smaller than this work instance is +* currently processing, a new work instance +* will be queued. +*/ +spin_unlock_irq (&assigned_dev->assigned_dev_lock);What happens if
assigned_dev->entries_nris changed here?
Quoted 3 lines
It does not. Interrupts and work instances are stopped before
irq_requested_typeorentries_nrcan change.
Interesting. A comment please.
Quoted 11 lines
Quoted 11 lines
Quoted 11 lines
virt/kvm/assigned-dev.c +2
-0kvm_set_irq (assigned_dev->kvm, assigned_dev->irq_source_id, guest_entries[i].vector,1 ); +spin_lock_irq (&assigned_dev->assigned_dev_lock); } +spin_unlock_irq (&assigned_dev->assigned_dev_lock); }else kvm_set_irq (assigned_dev->kvm, assigned_dev->irq_source_id, assigned_dev->guest_irq,1 );
Quoted 9 lines
Quoted 7 lines
virt/kvm/assigned-dev.c static void kvm_assigned_dev_interrupt_work_handler(struct work_struct *work) · line 95
Quoted 3 lines
virt/kvm/assigned-dev.c +0
-1-spin_unlock_irq (&assigned_dev->assigned_dev_lock); }A less dangerous fix is to copy all vectors to be triggered into a local array, drop the lock, and replay the array into
kvm_set_irq(). The else branch could do this as well.Its a bit large, 256 max vectors.
Yeah.
Signature · 1 line
error compiling committee.c: too many arguments to function