mirror of
https://github.com/rd-stuffs/msm-4.14.git
synced 2025-02-20 11:45:48 +08:00
PCI: hv: Disable/enable IRQs rather than BH in hv_compose_msi_msg()
commit 35a88a18d7ea58600e11590405bc93b08e16e7f5 upstream. Commit de0aa7b2f97d ("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 f71b74bca637 ("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 de0aa7b2f97d: 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: de0aa7b2f97d ("PCI: hv: Fix 2 hang issues in hv_compose_msi_msg()") Signed-off-by: Dexuan Cui <decui@microsoft.com> Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com> Signed-off-by: Bjorn Helgaas <bhelgaas@google.com> Reviewed-by: Haiyang Zhang <haiyangz@microsoft.com> Cc: stable@vger.kernel.org Cc: Stephen Hemminger <sthemmin@microsoft.com> Cc: K. Y. Srinivasan <kys@microsoft.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
aa6be39671
commit
b5199c61e9
@ -1091,6 +1091,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 {
|
||||||
@ -1182,14 +1183,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,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user