Skip to content

Commit 29aaee6

Browse files
anishdavem330
authored andcommitted
cxgb4: Fix race condition in cleanup
There is a possible race condition when we unregister the PCI Driver and then flush/destroy the global "workq". This could lead to situations where there are tasks on the Work Queue with references to now deleted adapter data structures. Instead, have per-adapter Work Queues which were instantiated and torn down in init_one() and remove_one(), respectively. v2: Remove unnecessary call to flush_workqueue() before destroy_workqueue() Signed-off-by: Anish Bhatt <[email protected]> Signed-off-by: Casey Leedom <[email protected]> Acked-by: Neil Horman <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 061079a commit 29aaee6

File tree

2 files changed

+19
-14
lines changed

2 files changed

+19
-14
lines changed

drivers/net/ethernet/chelsio/cxgb4/cxgb4.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -652,6 +652,7 @@ struct adapter {
652652
struct tid_info tids;
653653
void **tid_release_head;
654654
spinlock_t tid_release_lock;
655+
struct workqueue_struct *workq;
655656
struct work_struct tid_release_task;
656657
struct work_struct db_full_task;
657658
struct work_struct db_drop_task;

drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -643,8 +643,6 @@ static int set_rxmode(struct net_device *dev, int mtu, bool sleep_ok)
643643
return ret;
644644
}
645645

646-
static struct workqueue_struct *workq;
647-
648646
/**
649647
* link_start - enable a port
650648
* @dev: the port to enable
@@ -3340,7 +3338,7 @@ static void cxgb4_queue_tid_release(struct tid_info *t, unsigned int chan,
33403338
adap->tid_release_head = (void **)((uintptr_t)p | chan);
33413339
if (!adap->tid_release_task_busy) {
33423340
adap->tid_release_task_busy = true;
3343-
queue_work(workq, &adap->tid_release_task);
3341+
queue_work(adap->workq, &adap->tid_release_task);
33443342
}
33453343
spin_unlock_bh(&adap->tid_release_lock);
33463344
}
@@ -4140,7 +4138,7 @@ void t4_db_full(struct adapter *adap)
41404138
notify_rdma_uld(adap, CXGB4_CONTROL_DB_FULL);
41414139
t4_set_reg_field(adap, SGE_INT_ENABLE3,
41424140
DBFIFO_HP_INT | DBFIFO_LP_INT, 0);
4143-
queue_work(workq, &adap->db_full_task);
4141+
queue_work(adap->workq, &adap->db_full_task);
41444142
}
41454143
}
41464144

@@ -4150,7 +4148,7 @@ void t4_db_dropped(struct adapter *adap)
41504148
disable_dbs(adap);
41514149
notify_rdma_uld(adap, CXGB4_CONTROL_DB_FULL);
41524150
}
4153-
queue_work(workq, &adap->db_drop_task);
4151+
queue_work(adap->workq, &adap->db_drop_task);
41544152
}
41554153

41564154
static void uld_attach(struct adapter *adap, unsigned int uld)
@@ -6517,6 +6515,12 @@ static int init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
65176515
goto out_disable_device;
65186516
}
65196517

6518+
adapter->workq = create_singlethread_workqueue("cxgb4");
6519+
if (!adapter->workq) {
6520+
err = -ENOMEM;
6521+
goto out_free_adapter;
6522+
}
6523+
65206524
/* PCI device has been enabled */
65216525
adapter->flags |= DEV_ENABLED;
65226526

@@ -6715,6 +6719,9 @@ static int init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
67156719
out_unmap_bar0:
67166720
iounmap(adapter->regs);
67176721
out_free_adapter:
6722+
if (adapter->workq)
6723+
destroy_workqueue(adapter->workq);
6724+
67186725
kfree(adapter);
67196726
out_disable_device:
67206727
pci_disable_pcie_error_reporting(pdev);
@@ -6736,6 +6743,11 @@ static void remove_one(struct pci_dev *pdev)
67366743
if (adapter) {
67376744
int i;
67386745

6746+
/* Tear down per-adapter Work Queue first since it can contain
6747+
* references to our adapter data structure.
6748+
*/
6749+
destroy_workqueue(adapter->workq);
6750+
67396751
if (is_offload(adapter))
67406752
detach_ulds(adapter);
67416753

@@ -6788,20 +6800,14 @@ static int __init cxgb4_init_module(void)
67886800
{
67896801
int ret;
67906802

6791-
workq = create_singlethread_workqueue("cxgb4");
6792-
if (!workq)
6793-
return -ENOMEM;
6794-
67956803
/* Debugfs support is optional, just warn if this fails */
67966804
cxgb4_debugfs_root = debugfs_create_dir(KBUILD_MODNAME, NULL);
67976805
if (!cxgb4_debugfs_root)
67986806
pr_warn("could not create debugfs entry, continuing\n");
67996807

68006808
ret = pci_register_driver(&cxgb4_driver);
6801-
if (ret < 0) {
6809+
if (ret < 0)
68026810
debugfs_remove(cxgb4_debugfs_root);
6803-
destroy_workqueue(workq);
6804-
}
68056811

68066812
register_inet6addr_notifier(&cxgb4_inet6addr_notifier);
68076813

@@ -6813,8 +6819,6 @@ static void __exit cxgb4_cleanup_module(void)
68136819
unregister_inet6addr_notifier(&cxgb4_inet6addr_notifier);
68146820
pci_unregister_driver(&cxgb4_driver);
68156821
debugfs_remove(cxgb4_debugfs_root); /* NULL ok */
6816-
flush_workqueue(workq);
6817-
destroy_workqueue(workq);
68186822
}
68196823

68206824
module_init(cxgb4_init_module);

0 commit comments

Comments
 (0)