Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

forcedeth: fix unilateral interrupt disabling in netpoll path

Forcedeth currently uses disable_irq_lockdep and enable_irq_lockdep, which in
some configurations simply calls local_irq_disable. This causes errant warnings
in the netpoll path as in netpoll_send_skb_on_dev, where we disable irqs using
local_irq_save, leading to the following warning:

WARNING: at net/core/netpoll.c:352 netpoll_send_skb_on_dev+0x243/0x250() (Not
tainted)
Hardware name:
netpoll_send_skb_on_dev(): eth0 enabled interrupts in poll
(nv_start_xmit_optimized+0x0/0x860 [forcedeth])
Modules linked in: netconsole(+) configfs ipv6 iptable_filter ip_tables ppdev
parport_pc parport sg microcode serio_raw edac_core edac_mce_amd k8temp
snd_hda_codec_realtek snd_hda_codec_generic forcedeth snd_hda_intel
snd_hda_codec snd_hwdep snd_seq snd_seq_device snd_pcm snd_timer snd soundcore
snd_page_alloc i2c_nforce2 i2c_core shpchp ext4 jbd2 mbcache sr_mod cdrom sd_mod
crc_t10dif pata_amd ata_generic pata_acpi sata_nv dm_mirror dm_region_hash
dm_log dm_mod [last unloaded: scsi_wait_scan]
Pid: 1940, comm: modprobe Not tainted 2.6.32-573.7.1.el6.x86_64.debug #1
Call Trace:
[<ffffffff8107bbc1>] ? warn_slowpath_common+0x91/0xe0
[<ffffffff8107bcc6>] ? warn_slowpath_fmt+0x46/0x60
[<ffffffffa00fe5b0>] ? nv_start_xmit_optimized+0x0/0x860 [forcedeth]
[<ffffffff814b3593>] ? netpoll_send_skb_on_dev+0x243/0x250
[<ffffffff814b37c9>] ? netpoll_send_udp+0x229/0x270
[<ffffffffa02e3299>] ? write_msg+0x39/0x110 [netconsole]
[<ffffffffa02e331b>] ? write_msg+0xbb/0x110 [netconsole]
[<ffffffff8107bd55>] ? __call_console_drivers+0x75/0x90
[<ffffffff8107bdba>] ? _call_console_drivers+0x4a/0x80
[<ffffffff8107c445>] ? release_console_sem+0xe5/0x250
[<ffffffff8107d200>] ? register_console+0x190/0x3e0
[<ffffffffa02e71a6>] ? init_netconsole+0x1a6/0x216 [netconsole]
[<ffffffffa02e7000>] ? init_netconsole+0x0/0x216 [netconsole]
[<ffffffff810020d0>] ? do_one_initcall+0xc0/0x280
[<ffffffff810d4933>] ? sys_init_module+0xe3/0x260
[<ffffffff8100b0d2>] ? system_call_fastpath+0x16/0x1b
---[ end trace f349c7af88e6a6d5 ]---
console [netcon0] enabled
netconsole: network logging started

Fix it by modifying the forcedeth code to use
disable_irq_nosync_lockdep_irqsavedisable_irq_nosync_lockdep_irqsave instead,
which saves and restores irq state properly. This also saves us a little code
in the process

Tested by the reporter, with successful restuls

Patch applies to the head of the net tree

Signed-off-by: Neil Horman <nhorman@tuxdriver.com>
CC: "David S. Miller" <davem@davemloft.net>
Reported-by: Vasily Averin <vvs@sw.ru>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Neil Horman and committed by
David S. Miller
0b7c8743 6f5cadee

+11 -13
+11 -13
drivers/net/ethernet/nvidia/forcedeth.c
··· 4076 4076 struct fe_priv *np = netdev_priv(dev); 4077 4077 u8 __iomem *base = get_hwbase(dev); 4078 4078 u32 mask = 0; 4079 + unsigned long flags; 4080 + unsigned int irq = 0; 4079 4081 4080 4082 /* 4081 4083 * First disable irq(s) and then ··· 4087 4085 4088 4086 if (!using_multi_irqs(dev)) { 4089 4087 if (np->msi_flags & NV_MSI_X_ENABLED) 4090 - disable_irq_lockdep(np->msi_x_entry[NV_MSI_X_VECTOR_ALL].vector); 4088 + irq = np->msi_x_entry[NV_MSI_X_VECTOR_ALL].vector; 4091 4089 else 4092 - disable_irq_lockdep(np->pci_dev->irq); 4090 + irq = np->pci_dev->irq; 4093 4091 mask = np->irqmask; 4094 4092 } else { 4095 4093 if (np->nic_poll_irq & NVREG_IRQ_RX_ALL) { 4096 - disable_irq_lockdep(np->msi_x_entry[NV_MSI_X_VECTOR_RX].vector); 4094 + irq = np->msi_x_entry[NV_MSI_X_VECTOR_RX].vector; 4097 4095 mask |= NVREG_IRQ_RX_ALL; 4098 4096 } 4099 4097 if (np->nic_poll_irq & NVREG_IRQ_TX_ALL) { 4100 - disable_irq_lockdep(np->msi_x_entry[NV_MSI_X_VECTOR_TX].vector); 4098 + irq = np->msi_x_entry[NV_MSI_X_VECTOR_TX].vector; 4101 4099 mask |= NVREG_IRQ_TX_ALL; 4102 4100 } 4103 4101 if (np->nic_poll_irq & NVREG_IRQ_OTHER) { 4104 - disable_irq_lockdep(np->msi_x_entry[NV_MSI_X_VECTOR_OTHER].vector); 4102 + irq = np->msi_x_entry[NV_MSI_X_VECTOR_OTHER].vector; 4105 4103 mask |= NVREG_IRQ_OTHER; 4106 4104 } 4107 4105 } 4108 - /* disable_irq() contains synchronize_irq, thus no irq handler can run now */ 4106 + 4107 + disable_irq_nosync_lockdep_irqsave(irq, &flags); 4108 + synchronize_irq(irq); 4109 4109 4110 4110 if (np->recover_error) { 4111 4111 np->recover_error = 0; ··· 4160 4156 nv_nic_irq_optimized(0, dev); 4161 4157 else 4162 4158 nv_nic_irq(0, dev); 4163 - if (np->msi_flags & NV_MSI_X_ENABLED) 4164 - enable_irq_lockdep(np->msi_x_entry[NV_MSI_X_VECTOR_ALL].vector); 4165 - else 4166 - enable_irq_lockdep(np->pci_dev->irq); 4167 4159 } else { 4168 4160 if (np->nic_poll_irq & NVREG_IRQ_RX_ALL) { 4169 4161 np->nic_poll_irq &= ~NVREG_IRQ_RX_ALL; 4170 4162 nv_nic_irq_rx(0, dev); 4171 - enable_irq_lockdep(np->msi_x_entry[NV_MSI_X_VECTOR_RX].vector); 4172 4163 } 4173 4164 if (np->nic_poll_irq & NVREG_IRQ_TX_ALL) { 4174 4165 np->nic_poll_irq &= ~NVREG_IRQ_TX_ALL; 4175 4166 nv_nic_irq_tx(0, dev); 4176 - enable_irq_lockdep(np->msi_x_entry[NV_MSI_X_VECTOR_TX].vector); 4177 4167 } 4178 4168 if (np->nic_poll_irq & NVREG_IRQ_OTHER) { 4179 4169 np->nic_poll_irq &= ~NVREG_IRQ_OTHER; 4180 4170 nv_nic_irq_other(0, dev); 4181 - enable_irq_lockdep(np->msi_x_entry[NV_MSI_X_VECTOR_OTHER].vector); 4182 4171 } 4183 4172 } 4184 4173 4174 + enable_irq_lockdep_irqrestore(irq, &flags); 4185 4175 } 4186 4176 4187 4177 #ifdef CONFIG_NET_POLL_CONTROLLER