Commit 35a88a18 authored by Dexuan Cui's avatar Dexuan Cui Committed by Bjorn Helgaas

PCI: hv: Disable/enable IRQs rather than BH in hv_compose_msi_msg()

Commit de0aa7b2 ("PCI: hv: Fix 2 hang issues in hv_compose_msi_msg()")
uses local_bh_disable()/enable(), because hv_pci_onchannelcallback() can
also run in tasklet context as the channel event callback, so bottom halves
should be disabled to prevent a race condition.

With CONFIG_PROVE_LOCKING=y in the recent mainline, or old kernels that
don't have commit f71b74bc ("irq/softirqs: Use lockdep to assert IRQs
are disabled/enabled"), when the upper layer IRQ code calls
hv_compose_msi_msg() with local IRQs disabled, we'll see a warning at the
beginning of __local_bh_enable_ip():

  IRQs not enabled as expected
    WARNING: CPU: 0 PID: 408 at kernel/softirq.c:162 __local_bh_enable_ip

The warning exposes an issue in de0aa7b2: local_bh_enable() can
potentially call do_softirq(), which is not supposed to run when local IRQs
are disabled. Let's fix this by using local_irq_save()/restore() instead.

Note: hv_pci_onchannelcallback() is not a hot path because it's only called
when the PCI device is hot added and removed, which is infrequent.

Fixes: de0aa7b2 ("PCI: hv: Fix 2 hang issues in hv_compose_msi_msg()")
Signed-off-by: default avatarDexuan Cui <decui@microsoft.com>
Signed-off-by: default avatarLorenzo Pieralisi <lorenzo.pieralisi@arm.com>
Signed-off-by: default avatarBjorn Helgaas <bhelgaas@google.com>
Reviewed-by: default avatarHaiyang Zhang <haiyangz@microsoft.com>
Cc: stable@vger.kernel.org
Cc: Stephen Hemminger <sthemmin@microsoft.com>
Cc: K. Y. Srinivasan <kys@microsoft.com>
parent 83235822
...@@ -1073,6 +1073,7 @@ static void hv_compose_msi_msg(struct irq_data *data, struct msi_msg *msg) ...@@ -1073,6 +1073,7 @@ static void hv_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
struct pci_bus *pbus; struct pci_bus *pbus;
struct pci_dev *pdev; struct pci_dev *pdev;
struct cpumask *dest; struct cpumask *dest;
unsigned long flags;
struct compose_comp_ctxt comp; struct compose_comp_ctxt comp;
struct tran_int_desc *int_desc; struct tran_int_desc *int_desc;
struct { struct {
...@@ -1164,14 +1165,15 @@ static void hv_compose_msi_msg(struct irq_data *data, struct msi_msg *msg) ...@@ -1164,14 +1165,15 @@ static void hv_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
* the channel callback directly when channel->target_cpu is * the channel callback directly when channel->target_cpu is
* the current CPU. When the higher level interrupt code * the current CPU. When the higher level interrupt code
* calls us with interrupt enabled, let's add the * calls us with interrupt enabled, let's add the
* local_bh_disable()/enable() to avoid race. * local_irq_save()/restore() to avoid race:
* hv_pci_onchannelcallback() can also run in tasklet.
*/ */
local_bh_disable(); local_irq_save(flags);
if (hbus->hdev->channel->target_cpu == smp_processor_id()) if (hbus->hdev->channel->target_cpu == smp_processor_id())
hv_pci_onchannelcallback(hbus); hv_pci_onchannelcallback(hbus);
local_bh_enable(); local_irq_restore(flags);
if (hpdev->state == hv_pcichild_ejecting) { if (hpdev->state == hv_pcichild_ejecting) {
dev_err_once(&hbus->hdev->device, dev_err_once(&hbus->hdev->device,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment