i2c-core: Fix for lockdep validator

If kernel is compiled with CONFIG_PROVE_LOCKING the
validator raises an error when a multiplexer is removed
via sysfs and sub-clients are connected to it. This is a
false positive.
Documentation/lockdep-design.txt recommends to handle this
via calls to mutex_lock_nested().

Based on an earlier fix from Michael Lawnick.

Note that the extra code resolves to nothing unless
CONFIG_DEBUG_LOCK_ALLOC=y.

Signed-off-by: Jean Delvare <khali@linux-fr.org>
Cc: Michael Lawnick <ml.lawnick@gmx.de>
This commit is contained in:
Jean Delvare 2012-09-10 10:14:02 +02:00 committed by Jean Delvare
parent e68bb91baa
commit 390946b172
1 changed files with 20 additions and 2 deletions

View File

@ -636,6 +636,22 @@ static void i2c_adapter_dev_release(struct device *dev)
complete(&adap->dev_released);
}
/*
* This function is only needed for mutex_lock_nested, so it is never
* called unless locking correctness checking is enabled. Thus we
* make it inline to avoid a compiler warning. That's what gcc ends up
* doing anyway.
*/
static inline unsigned int i2c_adapter_depth(struct i2c_adapter *adapter)
{
unsigned int depth = 0;
while ((adapter = i2c_parent_is_i2c_adapter(adapter)))
depth++;
return depth;
}
/*
* Let users instantiate I2C devices through sysfs. This can be used when
* platform initialization code doesn't contain the proper data for
@ -726,7 +742,8 @@ i2c_sysfs_delete_device(struct device *dev, struct device_attribute *attr,
/* Make sure the device was added through sysfs */
res = -ENOENT;
mutex_lock(&adap->userspace_clients_lock);
mutex_lock_nested(&adap->userspace_clients_lock,
i2c_adapter_depth(adap));
list_for_each_entry_safe(client, next, &adap->userspace_clients,
detected) {
if (client->addr == addr) {
@ -1073,7 +1090,8 @@ int i2c_del_adapter(struct i2c_adapter *adap)
return res;
/* Remove devices instantiated from sysfs */
mutex_lock(&adap->userspace_clients_lock);
mutex_lock_nested(&adap->userspace_clients_lock,
i2c_adapter_depth(adap));
list_for_each_entry_safe(client, next, &adap->userspace_clients,
detected) {
dev_dbg(&adap->dev, "Removing %s at 0x%x\n", client->name,