From 77ed74da26f50fa28471571ee7a2251b77526d84 Mon Sep 17 00:00:00 2001
From: Jean Delvare <khali@linux-fr.org>
Date: Sat, 30 Sep 2006 17:18:59 +0200
Subject: [PATCH] [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>
---
 drivers/i2c/i2c-core.c | 25 +++++++++++++------------
 1 file changed, 13 insertions(+), 12 deletions(-)

diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c
index 01233f0f777..7ca81f42d14 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)
 	}
 	list_add_tail(&client->list,&adapter->clients);
 	
-	if (adapter->client_register)  {
-		if (adapter->client_register(client))  {
-			dev_dbg(&adapter->dev, "client_register "
-				"failed for client [%s] at 0x%02x\n",
-				client->name, client->addr);
-		}
-	}
-
 	client->usage_count = 0;
 
 	client->dev.parent = &client->adapter->dev;
@@ -445,10 +437,17 @@ int i2c_attach_client(struct i2c_client *client)
 	res = device_create_file(&client->dev, &dev_attr_client_name);
 	if (res)
 		goto out_unregister;
-
-out_unlock:
 	mutex_unlock(&adapter->clist_lock);
-	return res;
+
+	if (adapter->client_register)  {
+		if (adapter->client_register(client)) {
+			dev_dbg(&adapter->dev, "client_register "
+				"failed for client [%s] at 0x%02x\n",
+				client->name, client->addr);
+		}
+	}
+
+	return 0;
 
 out_unregister:
 	init_completion(&client->released); /* Needed? */
@@ -458,7 +457,9 @@ out_list:
 	list_del(&client->list);
 	dev_err(&adapter->dev, "Failed to attach i2c client %s at 0x%02x "
 		"(%d)\n", client->name, client->addr, res);
-	goto out_unlock;
+out_unlock:
+	mutex_unlock(&adapter->clist_lock);
+	return res;
 }
 
 
-- 
2.41.3