i2c-core: Fix for lockdep validator
authorJean Delvare <khali@linux-fr.org>
Mon, 10 Sep 2012 08:14:02 +0000 (10:14 +0200)
committerJean Delvare <khali@endymion.delvare>
Mon, 10 Sep 2012 08:14:02 +0000 (10:14 +0200)
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>
drivers/i2c/i2c-core.c

index 2efa56c..2091ae8 100644 (file)
@@ -637,6 +637,22 @@ static void i2c_adapter_dev_release(struct device *dev)
 }
 
 /*
+ * 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
  * whatever reason. Also useful for drivers that do device detection and
@@ -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,