diff options
author | Jean Delvare <khali@linux-fr.org> | 2006-09-30 11:18:59 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-09-30 13:58:47 -0400 |
commit | 77ed74da26f50fa28471571ee7a2251b77526d84 (patch) | |
tree | 5db5671bb6f69613103ded68027b1d7e8677c87e /drivers/i2c/i2c-core.c | |
parent | 5ffd1a6aaacc25be8cd0770a51ec6d46add3a276 (diff) |
[PATCH] i2c: Prevent deadlock on i2c client registration
Delay the call to adapter->client_register() until after we are
certain that the client registration is a success. At this point the
client is fully initialized and we no longer hold the adapter->clist
mutex, so this should prevent the deadlocks if the client_register()
callback needs to take that mutex too, as is the case for the bttv
driver.
This fixes bug #7234.
Signed-off-by: Jean Delvare <khali@linux-fr.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'drivers/i2c/i2c-core.c')
-rw-r--r-- | drivers/i2c/i2c-core.c | 25 |
1 files changed, 13 insertions, 12 deletions
diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index 01233f0f7771..7ca81f42d14b 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c | |||
@@ -420,14 +420,6 @@ int i2c_attach_client(struct i2c_client *client) | |||
420 | } | 420 | } |
421 | list_add_tail(&client->list,&adapter->clients); | 421 | list_add_tail(&client->list,&adapter->clients); |
422 | 422 | ||
423 | if (adapter->client_register) { | ||
424 | if (adapter->client_register(client)) { | ||
425 | dev_dbg(&adapter->dev, "client_register " | ||
426 | "failed for client [%s] at 0x%02x\n", | ||
427 | client->name, client->addr); | ||
428 | } | ||
429 | } | ||
430 | |||
431 | client->usage_count = 0; | 423 | client->usage_count = 0; |
432 | 424 | ||
433 | client->dev.parent = &client->adapter->dev; | 425 | client->dev.parent = &client->adapter->dev; |
@@ -445,10 +437,17 @@ int i2c_attach_client(struct i2c_client *client) | |||
445 | res = device_create_file(&client->dev, &dev_attr_client_name); | 437 | res = device_create_file(&client->dev, &dev_attr_client_name); |
446 | if (res) | 438 | if (res) |
447 | goto out_unregister; | 439 | goto out_unregister; |
448 | |||
449 | out_unlock: | ||
450 | mutex_unlock(&adapter->clist_lock); | 440 | mutex_unlock(&adapter->clist_lock); |
451 | return res; | 441 | |
442 | if (adapter->client_register) { | ||
443 | if (adapter->client_register(client)) { | ||
444 | dev_dbg(&adapter->dev, "client_register " | ||
445 | "failed for client [%s] at 0x%02x\n", | ||
446 | client->name, client->addr); | ||
447 | } | ||
448 | } | ||
449 | |||
450 | return 0; | ||
452 | 451 | ||
453 | out_unregister: | 452 | out_unregister: |
454 | init_completion(&client->released); /* Needed? */ | 453 | init_completion(&client->released); /* Needed? */ |
@@ -458,7 +457,9 @@ out_list: | |||
458 | list_del(&client->list); | 457 | list_del(&client->list); |
459 | dev_err(&adapter->dev, "Failed to attach i2c client %s at 0x%02x " | 458 | dev_err(&adapter->dev, "Failed to attach i2c client %s at 0x%02x " |
460 | "(%d)\n", client->name, client->addr, res); | 459 | "(%d)\n", client->name, client->addr, res); |
461 | goto out_unlock; | 460 | out_unlock: |
461 | mutex_unlock(&adapter->clist_lock); | ||
462 | return res; | ||
462 | } | 463 | } |
463 | 464 | ||
464 | 465 | ||