aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRoland Dreier <rolandd@cisco.com>2009-02-25 16:27:46 -0500
committerRoland Dreier <rolandd@cisco.com>2009-02-25 16:27:46 -0500
commit9206dff15705267c19f8fed391c4fb95975540a3 (patch)
treefc9722069f10675ed77f2dd90e52daef5230be33
parentf3b8436ad9a8ad36b3c9fa1fe030c7f38e5d3d0b (diff)
IB: Remove sysfs files before unregistering device
Move the ib_device_unregister_sysfs() call from ib_dealloc_device() to ib_unregister_device(). The old code allows device unregister to proceed even if some sysfs files are open, which leaves a window where userspace can open a file before a device is removed but then end up reading the file after the device is removed, which leads to various kernel crashes either because the device data structure is freed or because the low-level driver code is gone after module removal. By not returning from ib_unregister_device() until after all sysfs entries are removed, we make sure that data structures and/or module code is not freed until after all sysfs access is done. Reported-by: Jack Morgenstein <jackm@dev.mellanox.co.il> Signed-off-by: Roland Dreier <rolandd@cisco.com>
-rw-r--r--drivers/infiniband/core/device.c4
-rw-r--r--drivers/infiniband/core/sysfs.c3
2 files changed, 6 insertions, 1 deletions
diff --git a/drivers/infiniband/core/device.c b/drivers/infiniband/core/device.c
index 7913b804311e..d1fba4153332 100644
--- a/drivers/infiniband/core/device.c
+++ b/drivers/infiniband/core/device.c
@@ -193,7 +193,7 @@ void ib_dealloc_device(struct ib_device *device)
193 193
194 BUG_ON(device->reg_state != IB_DEV_UNREGISTERED); 194 BUG_ON(device->reg_state != IB_DEV_UNREGISTERED);
195 195
196 ib_device_unregister_sysfs(device); 196 kobject_put(&device->dev.kobj);
197} 197}
198EXPORT_SYMBOL(ib_dealloc_device); 198EXPORT_SYMBOL(ib_dealloc_device);
199 199
@@ -348,6 +348,8 @@ void ib_unregister_device(struct ib_device *device)
348 348
349 mutex_unlock(&device_mutex); 349 mutex_unlock(&device_mutex);
350 350
351 ib_device_unregister_sysfs(device);
352
351 spin_lock_irqsave(&device->client_data_lock, flags); 353 spin_lock_irqsave(&device->client_data_lock, flags);
352 list_for_each_entry_safe(context, tmp, &device->client_data_list, list) 354 list_for_each_entry_safe(context, tmp, &device->client_data_list, list)
353 kfree(context); 355 kfree(context);
diff --git a/drivers/infiniband/core/sysfs.c b/drivers/infiniband/core/sysfs.c
index b43f7d3682d3..5270aeb56e9e 100644
--- a/drivers/infiniband/core/sysfs.c
+++ b/drivers/infiniband/core/sysfs.c
@@ -848,6 +848,9 @@ void ib_device_unregister_sysfs(struct ib_device *device)
848 struct kobject *p, *t; 848 struct kobject *p, *t;
849 struct ib_port *port; 849 struct ib_port *port;
850 850
851 /* Hold kobject until ib_dealloc_device() */
852 kobject_get(&device->dev.kobj);
853
851 list_for_each_entry_safe(p, t, &device->port_list, entry) { 854 list_for_each_entry_safe(p, t, &device->port_list, entry) {
852 list_del(&p->entry); 855 list_del(&p->entry);
853 port = container_of(p, struct ib_port, kobj); 856 port = container_of(p, struct ib_port, kobj);