summaryrefslogtreecommitdiffstats
path: root/drivers/infiniband
diff options
context:
space:
mode:
authorSean Hefty2008-02-22 19:40:45 +0100
committerRoland Dreier2008-02-29 22:27:52 +0100
commit84ba284cd78c130818e2de53150f39b92504593b (patch)
tree28d0af4c0bd5ff24eb3aa988464fff8641d64248 /drivers/infiniband
parentMAINTAINERS: update ipath owner (diff)
downloadkernel-qcow2-linux-84ba284cd78c130818e2de53150f39b92504593b.tar.gz
kernel-qcow2-linux-84ba284cd78c130818e2de53150f39b92504593b.tar.xz
kernel-qcow2-linux-84ba284cd78c130818e2de53150f39b92504593b.zip
IB/cm: Flush workqueue when removing device
When a CM MAD is received, it is queued to a CM workqueue for processing. The queued work item references the port and device on which the MAD was received. If that device is removed from the system before the work item can execute, the work item will reference freed memory. To fix this, flush the workqueue after unregistering to receive MAD, and before the device is be freed. Signed-off-by: Sean Hefty <sean.hefty@intel.com> Signed-off-by: Roland Dreier <rolandd@cisco.com>
Diffstat (limited to 'drivers/infiniband')
-rw-r--r--drivers/infiniband/core/cm.c3
1 files changed, 2 insertions, 1 deletions
diff --git a/drivers/infiniband/core/cm.c b/drivers/infiniband/core/cm.c
index b10ade92efed..4df405157086 100644
--- a/drivers/infiniband/core/cm.c
+++ b/drivers/infiniband/core/cm.c
@@ -3759,6 +3759,7 @@ static void cm_remove_one(struct ib_device *device)
port = cm_dev->port[i-1];
ib_modify_port(device, port->port_num, 0, &port_modify);
ib_unregister_mad_agent(port->mad_agent);
+ flush_workqueue(cm.wq);
cm_remove_port_fs(port);
}
kobject_put(&cm_dev->dev_obj);
@@ -3813,6 +3814,7 @@ static void __exit ib_cm_cleanup(void)
cancel_delayed_work(&timewait_info->work.work);
spin_unlock_irq(&cm.lock);
+ ib_unregister_client(&cm_client);
destroy_workqueue(cm.wq);
list_for_each_entry_safe(timewait_info, tmp, &cm.timewait_list, list) {
@@ -3820,7 +3822,6 @@ static void __exit ib_cm_cleanup(void)
kfree(timewait_info);
}
- ib_unregister_client(&cm_client);
class_unregister(&cm_class);
idr_destroy(&cm.local_id_table);
}