Skip to content

Commit af6048e

Browse files
jhovoldgregkh
authored andcommitted
i2c: core: fix hang on adapter registration failure
commit 3c7e164 upstream. Clients may be registered from bus notifier callbacks when the adapter is registered. On a subsequent error during registration, the adapter references taken by such clients prevent the wait for the references to be released from ever completing. Fix this by refactoring client deregistration and deregistering also on late adapter registration failures. Fixes: f8756c6 ("i2c: core: call of_i2c_setup_smbus_alert in i2c_register_adapter") Cc: stable@vger.kernel.org # 4.15 Cc: Phil Reid <preid@electromag.com.au> Signed-off-by: Johan Hovold <johan@kernel.org> Signed-off-by: Wolfram Sang <wsa+renesas@sang-engineering.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent 22cb337 commit af6048e

1 file changed

Lines changed: 29 additions & 20 deletions

File tree

drivers/i2c/i2c-core-base.c

Lines changed: 29 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@
6363
static DEFINE_MUTEX(core_lock);
6464
static DEFINE_IDR(i2c_adapter_idr);
6565

66+
static void i2c_deregister_clients(struct i2c_adapter *adap);
6667
static int i2c_detect(struct i2c_adapter *adapter, struct i2c_driver *driver);
6768

6869
static DEFINE_STATIC_KEY_FALSE(i2c_trace_msg_key);
@@ -1609,6 +1610,7 @@ static int i2c_register_adapter(struct i2c_adapter *adap)
16091610
return 0;
16101611

16111612
out_reg:
1613+
i2c_deregister_clients(adap);
16121614
debugfs_remove_recursive(adap->debugfs);
16131615
init_completion(&adap->dev_released);
16141616
device_unregister(&adap->dev);
@@ -1748,29 +1750,10 @@ static int __process_removed_adapter(struct device_driver *d, void *data)
17481750
return 0;
17491751
}
17501752

1751-
/**
1752-
* i2c_del_adapter - unregister I2C adapter
1753-
* @adap: the adapter being unregistered
1754-
* Context: can sleep
1755-
*
1756-
* This unregisters an I2C adapter which was previously registered
1757-
* by @i2c_add_adapter or @i2c_add_numbered_adapter.
1758-
*/
1759-
void i2c_del_adapter(struct i2c_adapter *adap)
1753+
static void i2c_deregister_clients(struct i2c_adapter *adap)
17601754
{
1761-
struct i2c_adapter *found;
17621755
struct i2c_client *client, *next;
17631756

1764-
/* First make sure that this adapter was ever added */
1765-
mutex_lock(&core_lock);
1766-
found = idr_find(&i2c_adapter_idr, adap->nr);
1767-
mutex_unlock(&core_lock);
1768-
if (found != adap) {
1769-
pr_debug("attempting to delete unregistered adapter [%s]\n", adap->name);
1770-
return;
1771-
}
1772-
1773-
i2c_acpi_remove_space_handler(adap);
17741757
/* Tell drivers about this removal */
17751758
mutex_lock(&core_lock);
17761759
bus_for_each_drv(&i2c_bus_type, NULL, adap,
@@ -1796,6 +1779,32 @@ void i2c_del_adapter(struct i2c_adapter *adap)
17961779
* them up properly, so we give them a chance to do that first. */
17971780
device_for_each_child(&adap->dev, NULL, __unregister_client);
17981781
device_for_each_child(&adap->dev, NULL, __unregister_dummy);
1782+
}
1783+
1784+
/**
1785+
* i2c_del_adapter - unregister I2C adapter
1786+
* @adap: the adapter being unregistered
1787+
* Context: can sleep
1788+
*
1789+
* This unregisters an I2C adapter which was previously registered
1790+
* by @i2c_add_adapter or @i2c_add_numbered_adapter.
1791+
*/
1792+
void i2c_del_adapter(struct i2c_adapter *adap)
1793+
{
1794+
struct i2c_adapter *found;
1795+
1796+
/* First make sure that this adapter was ever added */
1797+
mutex_lock(&core_lock);
1798+
found = idr_find(&i2c_adapter_idr, adap->nr);
1799+
mutex_unlock(&core_lock);
1800+
if (found != adap) {
1801+
pr_debug("attempting to delete unregistered adapter [%s]\n", adap->name);
1802+
return;
1803+
}
1804+
1805+
i2c_acpi_remove_space_handler(adap);
1806+
1807+
i2c_deregister_clients(adap);
17991808

18001809
/* device name is gone after device_unregister */
18011810
dev_dbg(&adap->dev, "adapter [%s] unregistered\n", adap->name);

0 commit comments

Comments
 (0)