aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorCorey Minyard <cminyard@mvista.com>2018-08-30 14:06:21 -0400
committerCorey Minyard <cminyard@mvista.com>2018-08-31 09:43:12 -0400
commit0745dde62835be7e2afe62fcdb482fcad79cb743 (patch)
treed85790181a516f065f45d9c480071b6242a40637
parentc86ba91be75702c013bbf7379542920b6920e98f (diff)
ipmi: Fix I2C client removal in the SSIF driver
The SSIF driver was removing any client that came in through the platform interface, but it should only remove clients that it added. On a failure in the probe function, this could result in the following oops when the driver is removed and the client gets unregistered twice: CPU: 107 PID: 30266 Comm: rmmod Not tainted 4.18.0+ #80 Hardware name: Cavium Inc. Saber/Saber, BIOS Cavium reference firmware version 7.0 08/04/2018 pstate: 60400009 (nZCv daif +PAN -UAO) pc : kernfs_find_ns+0x28/0x120 lr : kernfs_find_and_get_ns+0x40/0x60 sp : ffff00002310fb50 x29: ffff00002310fb50 x28: ffff800a8240f800 x27: 0000000000000000 x26: 0000000000000000 x25: 0000000056000000 x24: ffff000009073000 x23: ffff000008998b38 x22: 0000000000000000 x21: ffff800ed86de820 x20: 0000000000000000 x19: ffff00000913a1d8 x18: 0000000000000000 x17: 0000000000000000 x16: 0000000000000000 x15: 0000000000000000 x14: 5300737265766972 x13: 643d4d4554535953 x12: 0000000000000030 x11: 0000000000000030 x10: 0101010101010101 x9 : ffff800ea06cc3f9 x8 : 0000000000000000 x7 : 0000000000000141 x6 : ffff000009073000 x5 : ffff800adb706b00 x4 : 0000000000000000 x3 : 00000000ffffffff x2 : 0000000000000000 x1 : ffff000008998b38 x0 : ffff000008356760 Process rmmod (pid: 30266, stack limit = 0x00000000e218418d) Call trace: kernfs_find_ns+0x28/0x120 kernfs_find_and_get_ns+0x40/0x60 sysfs_unmerge_group+0x2c/0x6c dpm_sysfs_remove+0x34/0x70 device_del+0x58/0x30c device_unregister+0x30/0x7c i2c_unregister_device+0x84/0x90 [i2c_core] ssif_platform_remove+0x38/0x98 [ipmi_ssif] platform_drv_remove+0x2c/0x6c device_release_driver_internal+0x168/0x1f8 driver_detach+0x50/0xbc bus_remove_driver+0x74/0xe8 driver_unregister+0x34/0x5c platform_driver_unregister+0x20/0x2c cleanup_ipmi_ssif+0x50/0xd82c [ipmi_ssif] __arm64_sys_delete_module+0x1b4/0x220 el0_svc_handler+0x104/0x160 el0_svc+0x8/0xc Code: aa1e03e0 aa0203f6 aa0103f7 d503201f (7940e280) ---[ end trace 09f0e34cce8e2d8c ]--- Kernel panic - not syncing: Fatal exception SMP: stopping secondary CPUs Kernel Offset: disabled CPU features: 0x23800c38 So track the clients that the SSIF driver adds and only remove those. Reported-by: George Cherian <george.cherian@cavium.com> Signed-off-by: Corey Minyard <cminyard@mvista.com> Tested-by: George Cherian <george.cherian@cavium.com> Cc: <stable@vger.kernel.org> # 4.14.x
-rw-r--r--drivers/char/ipmi/ipmi_ssif.c17
1 files changed, 6 insertions, 11 deletions
diff --git a/drivers/char/ipmi/ipmi_ssif.c b/drivers/char/ipmi/ipmi_ssif.c
index c12edc8e91df..265d6a6583bc 100644
--- a/drivers/char/ipmi/ipmi_ssif.c
+++ b/drivers/char/ipmi/ipmi_ssif.c
@@ -181,6 +181,8 @@ struct ssif_addr_info {
181 struct device *dev; 181 struct device *dev;
182 struct i2c_client *client; 182 struct i2c_client *client;
183 183
184 struct i2c_client *added_client;
185
184 struct mutex clients_mutex; 186 struct mutex clients_mutex;
185 struct list_head clients; 187 struct list_head clients;
186 188
@@ -1641,15 +1643,7 @@ static int ssif_probe(struct i2c_client *client, const struct i2c_device_id *id)
1641 1643
1642 out: 1644 out:
1643 if (rv) { 1645 if (rv) {
1644 /* 1646 addr_info->client = NULL;
1645 * Note that if addr_info->client is assigned, we
1646 * leave it. The i2c client hangs around even if we
1647 * return a failure here, and the failure here is not
1648 * propagated back to the i2c code. This seems to be
1649 * design intent, strange as it may be. But if we
1650 * don't leave it, ssif_platform_remove will not remove
1651 * the client like it should.
1652 */
1653 dev_err(&client->dev, "Unable to start IPMI SSIF: %d\n", rv); 1647 dev_err(&client->dev, "Unable to start IPMI SSIF: %d\n", rv);
1654 kfree(ssif_info); 1648 kfree(ssif_info);
1655 } 1649 }
@@ -1669,7 +1663,8 @@ static int ssif_adapter_handler(struct device *adev, void *opaque)
1669 if (adev->type != &i2c_adapter_type) 1663 if (adev->type != &i2c_adapter_type)
1670 return 0; 1664 return 0;
1671 1665
1672 i2c_new_device(to_i2c_adapter(adev), &addr_info->binfo); 1666 addr_info->added_client = i2c_new_device(to_i2c_adapter(adev),
1667 &addr_info->binfo);
1673 1668
1674 if (!addr_info->adapter_name) 1669 if (!addr_info->adapter_name)
1675 return 1; /* Only try the first I2C adapter by default. */ 1670 return 1; /* Only try the first I2C adapter by default. */
@@ -1842,7 +1837,7 @@ static int ssif_platform_remove(struct platform_device *dev)
1842 return 0; 1837 return 0;
1843 1838
1844 mutex_lock(&ssif_infos_mutex); 1839 mutex_lock(&ssif_infos_mutex);
1845 i2c_unregister_device(addr_info->client); 1840 i2c_unregister_device(addr_info->added_client);
1846 1841
1847 list_del(&addr_info->link); 1842 list_del(&addr_info->link);
1848 kfree(addr_info); 1843 kfree(addr_info);