i2c: Fix userspace_device list corruption
Fix userspace_device list corruption. The corruption was caused by clients not being removed when adapters with such clients were themselves removed. Something like the following would trigger it (assuming i2c-stub gets adapter number 3): # modprobe i2c-stub chip_addr=0x50 # echo 24c08 0x50 > /sys/bus/i2c/devices/i2c-3/new_device # rmmod i2c-stub # modprobe i2c-stub chip_addr=0x50 # echo 24c08 0x50 > /sys/bus/i2c/devices/i2c-3/new_device For the records, the stack trace in the kernel logs look like this: kernel: WARNING: at lib/list_debug.c:30 __list_add+0x8b/0x90() kernel: Hardware name: (...) kernel: list_add corruption. prev->next should be next (c137fc84), but was (null). (prev=f57111b8). kernel: Modules linked in: (...) kernel: Pid: 4669, comm: bash Not tainted 2.6.32-rc8 #259 kernel: Call Trace: kernel: [<c111eb8b>] ? __list_add+0x8b/0x90 kernel: [<c111eb8b>] ? __list_add+0x8b/0x90 kernel: [<c103265c>] warn_slowpath_common+0x6c/0xc0 kernel: [<c111eb8b>] ? __list_add+0x8b/0x90 kernel: [<c10326f6>] warn_slowpath_fmt+0x26/0x30 kernel: [<c111eb8b>] __list_add+0x8b/0x90 kernel: [<c11ba165>] i2c_sysfs_new_device+0x1c5/0x250 kernel: [<c10861be>] ? might_fault+0x2e/0x80 kernel: [<c11b9fa0>] ? i2c_sysfs_new_device+0x0/0x250 kernel: [<c118c625>] dev_attr_store+0x25/0x30 kernel: [<c10e305c>] sysfs_write_file+0x9c/0xf0 kernel: [<c109d35c>] vfs_write+0x9c/0x160 kernel: [<c10e2fc0>] ? sysfs_write_file+0x0/0xf0 kernel: [<c109d4dd>] sys_write+0x3d/0x70 kernel: [<c1002ed8>] sysenter_do_call+0x12/0x36 Signed-off-by: Jean Delvare <khali@linux-fr.org>
This commit is contained in:
parent
03b70d625c
commit
bbd2d9c919
|
@ -762,6 +762,7 @@ int i2c_del_adapter(struct i2c_adapter *adap)
|
|||
{
|
||||
int res = 0;
|
||||
struct i2c_adapter *found;
|
||||
struct i2c_client *client, *next;
|
||||
|
||||
/* First make sure that this adapter was ever added */
|
||||
mutex_lock(&core_lock);
|
||||
|
@ -781,6 +782,16 @@ int i2c_del_adapter(struct i2c_adapter *adap)
|
|||
if (res)
|
||||
return res;
|
||||
|
||||
/* Remove devices instantiated from sysfs */
|
||||
list_for_each_entry_safe(client, next, &userspace_devices, detected) {
|
||||
if (client->adapter == adap) {
|
||||
dev_dbg(&adap->dev, "Removing %s at 0x%x\n",
|
||||
client->name, client->addr);
|
||||
list_del(&client->detected);
|
||||
i2c_unregister_device(client);
|
||||
}
|
||||
}
|
||||
|
||||
/* Detach any active clients. This can't fail, thus we do not
|
||||
checking the returned value. */
|
||||
res = device_for_each_child(&adap->dev, NULL, __unregister_client);
|
||||
|
|
Loading…
Reference in New Issue