From: Roger Pau Monne Date: Mon, 28 Jan 2019 14:22:45 +0000 (+0100) Subject: pvh/dom0: fix deadlock in GSI mapping X-Git-Tag: 4.12-rc2~13 X-Git-Url: http://xenbits.xensource.com/gitweb?a=commitdiff_plain;h=603ad88fe8a681a2c5408c3f432d7083dd1c41b1;p=people%2Fdwmw2%2Fxen.git pvh/dom0: fix deadlock in GSI mapping The current GSI mapping code can cause the following deadlock: (XEN) *** Dumping CPU0 host state: *** (XEN) ----[ Xen-4.12.0-rc x86_64 debug=y Tainted: C ]---- [...] (XEN) Xen call trace: (XEN) [] vmac.c#_spin_lock_cb+0x32/0x70 (XEN) [] vmac.c#hvm_gsi_assert+0x2f/0x60 <- pick hvm.irq_lock (XEN) [] io.c#hvm_dirq_assist+0xd9/0x130 <- pick event_lock (XEN) [] io.c#dpci_softirq+0xdb/0x120 (XEN) [] softirq.c#__do_softirq+0x46/0xa0 (XEN) [] domain.c#idle_loop+0x35/0x90 (XEN) [...] (XEN) *** Dumping CPU3 host state: *** (XEN) ----[ Xen-4.12.0-rc x86_64 debug=y Tainted: C ]---- [...] (XEN) Xen call trace: (XEN) [] vmac.c#_spin_lock_cb+0x3d/0x70 (XEN) [] vmac.c#allocate_and_map_gsi_pirq+0xc8/0x130 <- pick event_lock (XEN) [] vioapic.c#vioapic_hwdom_map_gsi+0x80/0x130 (XEN) [] vioapic.c#vioapic_write_redirent+0x119/0x1c0 <- pick hvm.irq_lock (XEN) [] vioapic.c#vioapic_write+0x35/0x40 (XEN) [] vmac.c#hvm_process_io_intercept+0xd2/0x230 (XEN) [] vmac.c#hvm_io_intercept+0x22/0x50 (XEN) [] emulate.c#hvmemul_do_io+0x21b/0x3c0 (XEN) [] emulate.c#hvmemul_do_io_buffer+0x32/0x70 (XEN) [] emulate.c#hvmemul_do_mmio_buffer+0x29/0x30 (XEN) [] emulate.c#hvmemul_phys_mmio_access+0xf9/0x1b0 (XEN) [] emulate.c#hvmemul_linear_mmio_access+0xf0/0x180 (XEN) [] emulate.c#hvmemul_linear_mmio_write+0x21/0x30 (XEN) [] emulate.c#linear_write+0xa2/0x100 (XEN) [] emulate.c#hvmemul_write+0xb5/0x120 (XEN) [] vmac.c#x86_emulate+0x132aa/0x149a0 (XEN) [] vmac.c#x86_emulate_wrapper+0x29/0x70 (XEN) [] emulate.c#_hvm_emulate_one+0x50/0x140 (XEN) [] vmac.c#hvm_emulate_one_insn+0x41/0x100 (XEN) [] guest_4.o#sh_page_fault__guest_4+0x976/0xd30 (XEN) [] vmac.c#vmx_vmexit_handler+0x949/0xea0 (XEN) [] vmac.c#vmx_asm_vmexit_handler+0xfa/0x270 In order to solve it move the vioapic_hwdom_map_gsi outside of the locked region in vioapic_write_redirent. vioapic_hwdom_map_gsi will not access any of the vioapic fields, so there's no need to call the function holding the hvm.irq_lock. Signed-off-by: Roger Pau Monné Reviewed-by: Wei Liu Reviewed-by: Jan Beulich Release-acked-by: Juergen Gross --- diff --git a/xen/arch/x86/hvm/vioapic.c b/xen/arch/x86/hvm/vioapic.c index 2b74f92d51..2d71c33c1c 100644 --- a/xen/arch/x86/hvm/vioapic.c +++ b/xen/arch/x86/hvm/vioapic.c @@ -236,20 +236,6 @@ static void vioapic_write_redirent( *pent = ent; - if ( is_hardware_domain(d) && unmasked ) - { - int ret; - - ret = vioapic_hwdom_map_gsi(gsi, ent.fields.trig_mode, - ent.fields.polarity); - if ( ret ) - { - /* Mask the entry again. */ - pent->fields.mask = 1; - unmasked = 0; - } - } - if ( gsi == 0 ) { vlapic_adjust_i8259_target(d); @@ -266,6 +252,24 @@ static void vioapic_write_redirent( spin_unlock(&d->arch.hvm.irq_lock); + if ( is_hardware_domain(d) && unmasked ) + { + /* + * NB: don't call vioapic_hwdom_map_gsi while holding hvm.irq_lock + * since it can cause deadlocks as event_lock is taken by + * allocate_and_map_gsi_pirq, and that will invert the locking order + * used by other parts of the code. + */ + int ret = vioapic_hwdom_map_gsi(gsi, ent.fields.trig_mode, + ent.fields.polarity); + if ( ret ) + { + gprintk(XENLOG_ERR, + "unable to bind gsi %u to hardware domain: %d\n", gsi, ret); + unmasked = 0; + } + } + if ( gsi == 0 || unmasked ) pt_may_unmask_irq(d, NULL); }