i2c-core: fix for dep-lock validator
Subsystems (2)
PATCH 1/1 i2c-core: fix for dep-lock 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()
---
Documentation originally recommends to use an enum. This is not applicable for a tree with unlimited depth. This is why I use the adapter id which is expected to be unique and monotonic increasing with the depth of the tree.
drivers/i2c/i2c-core.c renamed from drivers/i2c/i2c-core.c.dist +2 -2
@@ -628,7 +628,7 @@ i2c_sysfs_delete_device(struct device *d/* 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_id (adap));list_for_each_entry_safe (client, next, &adap->userspace_clients, detected) {if (client->addr == addr) {
@@ -936,7 +936,7 @@ int i2c_del_adapter(struct i2c_adapter *return res;/* Remove devices instantiated from sysfs */ -mutex_lock (&adap->userspace_clients_lock); +mutex_lock_nested (&adap->userspace_clients_lock,i2c_adapter_id (adap));list_for_each_entry_safe (client, next, &adap->userspace_clients, detected) { dev_dbg(&adap->dev, "Removing %s at 0x%x\n", client->name,
A message that is not in the archive (sent off-list or not yet received): [email protected]
Am 05.09.2012 14:04, schrieb Michael Lawnick:
Quoted 28 lines
If kernel is compiled with
CONFIG_PROVE_LOCKINGthe 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.txtrecommends to handle this via calls tomutex_lock_nested()Signed-off-by Michael Lawnick <[email protected]>Cc Jean Delvare <[email protected]---
Documentation originally recommends to use an enum. This is not applicable for a tree with unlimited depth. This is why I use the adapter id which is expected to be unique and monotonic increasing with the depth of the tree.drivers/i2c/i2c-core.c renamed from drivers/i2c/i2c-core.c.dist +1
-1@@ -628,7 +628,7 @@ i2c_sysfs_delete_device(struct device *d/* 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_id (adap));list_for_each_entry_safe (client, next, &adap->userspace_clients, detected) {if (client->addr == addr) {
drivers/i2c/i2c-core.c int i2c_del_adapter(struct i2c_adapter * · line 942
Quoted 8 lines
drivers/i2c/i2c-core.c renamed from drivers/i2c/i2c-core.c.dist +1
-1@@ -936,7 +936,7 @@ int i2c_del_adapter(struct i2c_adapter *return res;/* Remove devices instantiated from sysfs */ -mutex_lock (&adap->userspace_clients_lock); +mutex_lock_nested (&adap->userspace_clients_lock,i2c_adapter_id (adap));list_for_each_entry_safe (client, next, &adap->userspace_clients, detected) { dev_dbg(&adap->dev, "Removing %s at 0x%x\n", client->name,
This will get problems with maximum log level :-( Please ignore, other solution is under construction.
Signature · 2 lines
KR Michael
A message that is not in the archive (sent off-list or not yet received): [email protected]
Hi Michael,
Quoted 31 lines · Michael Lawnick
Am 05.09.2012 14:04, schrieb Michael Lawnick:
Quoted 30 lines
If kernel is compiled with
CONFIG_PROVE_LOCKINGthe 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.txtrecommends to handle this via calls tomutex_lock_nested()Signed-off-by Michael Lawnick <[email protected]>Cc Jean Delvare <[email protected]---
Documentation originally recommends to use an enum. This is not applicable for a tree with unlimited depth. This is why I use the adapter id which is expected to be unique and monotonic increasing with the depth of the tree.drivers/i2c/i2c-core.c renamed from drivers/i2c/i2c-core.c.dist +1
-1@@ -628,7 +628,7 @@ i2c_sysfs_delete_device(struct device *d/* 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_id (adap));list_for_each_entry_safe (client, next, &adap->userspace_clients, detected) {if (client->addr == addr) {@@ -936,7 +936,7 @@ int i2c_del_adapter(struct i2c_adapter *return res;
Quoted 8 lines
drivers/i2c/i2c-core.c int i2c_del_adapter(struct i2c_adapter * · line 942
Quoted 6 lines
drivers/i2c/i2c-core.c renamed from drivers/i2c/i2c-core.c.dist +1
-1/* Remove devices instantiated from sysfs */ -mutex_lock (&adap->userspace_clients_lock); +mutex_lock_nested (&adap->userspace_clients_lock,i2c_adapter_id (adap));list_for_each_entry_safe (client, next, &adap->userspace_clients, detected) { dev_dbg(&adap->dev, "Removing %s at 0x%x\n", client->name,This will get problems with maximum log level :-(
Yes, I noticed the problem too. Actually I have a reply for you in my draft folder, saying exactly that.
Quoted 1 line
Please ignore, other solution is under construction.
I do have one too, based on the depth level of each adapter:
drivers/i2c/i2c-core.c +16 -3
@@ -636,6 +636,16 @@ static void i2c_adapter_dev_release(strucomplete (&adap->dev_released); } +static 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 +736,8 @@ i2c_sysfs_delete_device(struct device *d/* 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) {
@@ -869,7 +880,8 @@ static int i2c_register_adapter(struct iif (res) goto out_list; -dev_dbg (&adap->dev,"adapter [%s] registered\n" , adap->name); +dev_dbg (&adap->dev,"adapter [%s] registered, depth %u\n" , adap->name, +i2c_adapter_depth (adap));#ifdef CONFIG_I2C_COMPAT res = class_compat_create_link(i2c_adapter_compat_class, &adap->dev,
@@ -1073,7 +1085,8 @@ int i2c_del_adapter(struct i2c_adapter *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,
I was about to test it but was side-tracked by a different issue.
Signature · 1 line
Jean Delvare
A message that is not in the archive (sent off-list or not yet received): [email protected]
Hi Jean,
Am 07.09.2012 15:28, schrieb Jean Delvare:
Quoted 52 lines
I do have one too, based on the depth level of each adapter:
drivers/i2c/i2c-core.c +16
-3@@ -636,6 +636,16 @@ static void i2c_adapter_dev_release(strucomplete (&adap->dev_released); } +static 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 +736,8 @@ i2c_sysfs_delete_device(struct device *d/* 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) {@@ -869,7 +880,8 @@ static int i2c_register_adapter(struct iif (res) goto out_list; -dev_dbg (&adap->dev,"adapter [%s] registered\n" , adap->name); +dev_dbg (&adap->dev,"adapter [%s] registered, depth %u\n" , adap->name, +i2c_adapter_depth (adap));#ifdef CONFIG_I2C_COMPAT res = class_compat_create_link(i2c_adapter_compat_class, &adap->dev,@@ -1073,7 +1085,8 @@ int i2c_del_adapter(struct i2c_adapter *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,
Quoted 2 lines
I was about to test it but was side-tracked by a different issue.
I did not test yet, but thought already in same direction. The draw back of this is that there is still maximum tree depth, but we could say 8 should be enough and the performance issue. May be introducing the depth into struct i2c_adapter and setting it to parent->depth + 1?
Signature · 2 lines
KR Michael
A message that is not in the archive (sent off-list or not yet received): [email protected]
Quoted 4 lines · Michael Lawnick
I did not test yet, but thought already in same direction. The draw back of this is that there is still maximum tree depth, but we could say 8 should be enough and the performance issue. May be introducing the depth into struct
i2c_adapterand setting it toparent->depth+ 1?
I think we are safe with max depth 8 (actually 7.) I still have to see a setup with depth > 1, and I seriously don't expect ever seeing one with depth > 3.
As far as performance is concerned, I thought about storing the depth value in struct i2c_adapter, but in fact I suspect the call to i2c_adapter_depth(adap) will be dropped at compilation time if CONFIG_PROVE_LOCKING isn't set, so the overhead should be zero. While a small overhead will be present if we store the value (the compiler won't be able to optimize that away.) I couldn't find the time to check this, though, which is why my original reply is still in my draft folder.
Signature · 1 line
Jean Delvare
A message that is not in the archive (sent off-list or not yet received): [email protected]
Quoted 4 lines · Jean Delvare
As far as performance is concerned, I thought about storing the depth value in struct
i2c_adapter, but in fact I suspect the call toi2c_adapter_depth(adap)will be dropped at compilation time ifCONFIG_PROVE_LOCKINGisn't set, so the overhead should be zero.
I confirm the nonexistent overhead, except that the relevant configuration option isn't CONFIG_PROVE_LOCKING but CONFIG_DEBUG_LOCK_ALLOC. I think this is acceptable, that's not an option distribution kernels would enable.
Signature · 1 line
Jean Delvare
Quoted 5 lines · Michael Lawnick
Documentation originally recommends to use an enum. This is not applicable for a tree with unlimited depth. This is why I use the adapter id which is expected to be unique and monotonic increasing with the depth of the tree.
For the records, "monotonic increasing with the depth of the tree" isn't guaranteed. It is generally true, but with i2c adapter removal and hot-plugging, it can happen that an adapter has a lower id than its parent. For example:
* Register adapters 0, 1 and 2.
* Remove adapter 1.
* Instantiate a multiplexer on bus 2. The first child adapter will get number 1, and 1 < 2.
That being said, after looking at the code, I don't think lockdep cares about locks with lower class being taken first. OTOH it cares about locking order being always the same, and with i2c adapters coming and going, this would have been impossible to guarantee with your first implementation (although I very much doubt this would have been a problem in practice.)
Of course these points are all moot anyway as we have a better implementation which (hopefully) doesn't suffer from any of the problems yours had.
Signature · 1 line
Jean Delvare