cxgb4: fix IRQ free race during driver unload
[ Upstream commit 015fe6fd29c4b9ac0f61b8c4455ef88e6018b9cc ]
IRQs are requested during driver's ndo_open() and then later
freed up in disable_interrupts() during driver unload.
A race exists where driver can set the CXGB4_FULL_INIT_DONE
flag in ndo_open() after the disable_interrupts() in driver
unload path checks it, and hence misses calling free_irq().
Fix by unregistering netdevice first and sync with driver's
ndo_open(). This ensures disable_interrupts() checks the flag
correctly and frees up the IRQs properly.
Fixes: b37987e8db
("cxgb4: Disable interrupts and napi before unregistering netdev")
Signed-off-by: Shahjada Abul Husain <shahjada@chelsio.com>
Signed-off-by: Raju Rangoju <rajur@chelsio.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:

committed by
Greg Kroah-Hartman

parent
d92337bf54
commit
3714e0bb0d
@@ -2643,6 +2643,9 @@ static void detach_ulds(struct adapter *adap)
|
|||||||
{
|
{
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
|
|
||||||
|
if (!is_uld(adap))
|
||||||
|
return;
|
||||||
|
|
||||||
mutex_lock(&uld_mutex);
|
mutex_lock(&uld_mutex);
|
||||||
list_del(&adap->list_node);
|
list_del(&adap->list_node);
|
||||||
|
|
||||||
@@ -7145,10 +7148,13 @@ static void remove_one(struct pci_dev *pdev)
|
|||||||
*/
|
*/
|
||||||
destroy_workqueue(adapter->workq);
|
destroy_workqueue(adapter->workq);
|
||||||
|
|
||||||
if (is_uld(adapter)) {
|
detach_ulds(adapter);
|
||||||
detach_ulds(adapter);
|
|
||||||
t4_uld_clean_up(adapter);
|
for_each_port(adapter, i)
|
||||||
}
|
if (adapter->port[i]->reg_state == NETREG_REGISTERED)
|
||||||
|
unregister_netdev(adapter->port[i]);
|
||||||
|
|
||||||
|
t4_uld_clean_up(adapter);
|
||||||
|
|
||||||
adap_free_hma_mem(adapter);
|
adap_free_hma_mem(adapter);
|
||||||
|
|
||||||
@@ -7156,10 +7162,6 @@ static void remove_one(struct pci_dev *pdev)
|
|||||||
|
|
||||||
cxgb4_free_mps_ref_entries(adapter);
|
cxgb4_free_mps_ref_entries(adapter);
|
||||||
|
|
||||||
for_each_port(adapter, i)
|
|
||||||
if (adapter->port[i]->reg_state == NETREG_REGISTERED)
|
|
||||||
unregister_netdev(adapter->port[i]);
|
|
||||||
|
|
||||||
debugfs_remove_recursive(adapter->debugfs_root);
|
debugfs_remove_recursive(adapter->debugfs_root);
|
||||||
|
|
||||||
if (!is_t4(adapter->params.chip))
|
if (!is_t4(adapter->params.chip))
|
||||||
|
@@ -581,6 +581,9 @@ void t4_uld_clean_up(struct adapter *adap)
|
|||||||
{
|
{
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
|
|
||||||
|
if (!is_uld(adap))
|
||||||
|
return;
|
||||||
|
|
||||||
mutex_lock(&uld_mutex);
|
mutex_lock(&uld_mutex);
|
||||||
for (i = 0; i < CXGB4_ULD_MAX; i++) {
|
for (i = 0; i < CXGB4_ULD_MAX; i++) {
|
||||||
if (!adap->uld[i].handle)
|
if (!adap->uld[i].handle)
|
||||||
|
Reference in New Issue
Block a user