Skip to contentSkip to conversation

i2c: guard against oopses from bad init sequences

PATCH In review David Brownell 2 participants 5 messages Sep 23, 2008 – Sep 30, 2008 3 messages not in the archive

Subsystems (2)
lore
Share & tools
lore
#0 lore raw

PATCH 1/1 i2c: guard against oopses from bad init sequences

From: David Brownell <[email protected]>

Guard I2C against oopsing because of init sequence problems, by verifying that i2c_init() has been called before calling any routines that rely on that initialization. This specific test just requires that bus_register(&i2c_bus_type) was called.

Examples of this kind of oopsing come from subystems and drivers which register I2C drivers in their subsys_initcall code but which are statically linked before I2C by drivers/Makefile.

---
Alternatively have postcore_initcall(i2c_init), which may be better ... the initcall levels are pretty limited, and in these cases the "subsystem" of interest builds on I2C and needs to work before device_initcall. Having I2C use subsys_initcall kind of forces things into fs_initcall.

I'd encourage the anti-oopsing paranoia in any case, even if i2c switches to postcore_initcall (or earlier).

 drivers/i2c/i2c-core.c |   10 ++++++++++
 1 file changed, 10 insertions(+)
drivers/i2c/i2c-core.c +10 -0
@@ -443,6 +443,12 @@ static int i2c_register_adapter(struct i
 
 	mutex_lock(&core_lock);
 
+	/* can't register until after driver model init */
+	if (WARN_ON(!i2c_bus_type.p)) {
+		res = -ENOENT;
+		goto out_list;
+	}
+
 	/* Add the adapter to the driver core.
 	 * If the parent pointer is not set up,
 	 * we add this adapter to the host bus.
@@ -696,6 +702,10 @@ int i2c_register_driver(struct module *o
 {
 	int res;
 
+	/* can't register until after driver model init */
+	if (WARN_ON(!i2c_bus_type.p))
+		return -ENOENT;
+
 	/* new style driver methods can't mix with legacy ones */
 	if (is_newstyle_driver(driver)) {
 		if (driver->attach_adapter || driver->detach_adapter

_______________________________________________
i2c mailing list
[email protected]
http://lists.lm-sensors.org/mailman/listinfo/i2c

A message that is not in the archive (sent off-list or not yet received): 200809231138.19583.david-b-yBeKhBN/[email protected]

#2 lore raw

Hi David,

Quoted 19 lines · David Brownell

From: David Brownell <[email protected]>

Guard I2C against oopsing because of init sequence problems, by verifying that i2c_init() has been called before calling any routines that rely on that initialization. This specific test just requires that bus_register(&i2c_bus_type) was called.

Examples of this kind of oopsing come from subystems and drivers which register I2C drivers in their subsys_initcall code but which are statically linked before I2C by drivers/Makefile.

---
Alternatively have postcore_initcall(i2c_init), which may be better ... the initcall levels are pretty limited, and in these cases the "subsystem" of interest builds on I2C and needs to work before device_initcall. Having I2C use subsys_initcall kind of forces things into fs_initcall.

Quoted 2 lines

I'd encourage the anti-oopsing paranoia in any case, even if i2c switches to postcore_initcall (or earlier).

I'm confused. If i2c_register_adapter() is called before i2c_init(), your patch prevents an oops, but things will still not work, right? So this doesn't seem to add much value. In any case we need to fix the init sequence, so let's just do that.

Quoted 30 lines
 drivers/i2c/i2c-core.c |   10 ++++++++++
 1 file changed, 10 insertions(+)
drivers/i2c/i2c-core.c +10 -0
@@ -443,6 +443,12 @@ static int i2c_register_adapter(struct i
 
 	mutex_lock(&core_lock);
 
+	/* can't register until after driver model init */
+	if (WARN_ON(!i2c_bus_type.p)) {
+		res = -ENOENT;
+		goto out_list;
+	}
+
 	/* Add the adapter to the driver core.
 	 * If the parent pointer is not set up,
 	 * we add this adapter to the host bus.
@@ -696,6 +702,10 @@ int i2c_register_driver(struct module *o
 {
 	int res;
 
+	/* can't register until after driver model init */
+	if (WARN_ON(!i2c_bus_type.p))
+		return -ENOENT;
+
 	/* new style driver methods can't mix with legacy ones */
 	if (is_newstyle_driver(driver)) {
 		if (driver->attach_adapter || driver->detach_adapter
Signature · 6 lines
Jean Delvare

_______________________________________________
i2c mailing list
[email protected]
http://lists.lm-sensors.org/mailman/listinfo/i2c

A message that is not in the archive (sent off-list or not yet received): [email protected]

#4 lore raw
Quoted 13 lines · Jean Delvare

Hi David,

Quoted 10 lines · David Brownell

From: David Brownell <[email protected]>

Guard I2C against oopsing because of init sequence problems...

Alternatively have postcore_initcall(i2c_init), which may be better ... the initcall levels are pretty limited, and in these cases the "subsystem" of interest builds on I2C and needs to work before device_initcall. Having I2C use subsys_initcall kind of forces things into fs_initcall.

Quoted 5 lines
Quoted 2 lines

I'd encourage the anti-oopsing paranoia in any case, even if i2c switches to postcore_initcall (or earlier).

I'm confused. If i2c_register_adapter() is called before i2c_init(), your patch prevents an oops, but things will still not work, right?

And it warns about exactly where the problem came from, because of the WARN_ON. That addresses a long-standing debuggability problem which has afflicted these issues.

Quoted 3 lines

So
this doesn't seem to add much value. In any case we need to fix the init sequence, so let's just do that.

I'll send in a separate patch switching the driver model init to a postcore_initcall() -- it's not arch-specific and there seems no reason to have it earlier.

Semi-related: that module init/exit code is at a wierd place, in the middle of that file ... vs the conventional location at the end. OK to change that? In the same patch, or separate?

- Dave

_______________________________________________
i2c mailing list
[email protected]
http://lists.lm-sensors.org/mailman/listinfo/i2c

#5 lore raw
In reply to a message not in the archive

Hi David,

Quoted 28 lines · David Brownell

From: David Brownell <[email protected]>

Guard I2C against oopsing because of init sequence problems, by verifying that i2c_init() has been called before calling any routines that rely on that initialization. This specific test just requires that bus_register(&i2c_bus_type) was called.

Examples of this kind of oopsing come from subystems and drivers which register I2C drivers in their subsys_initcall code but which are statically linked before I2C by drivers/Makefile.

---
Alternatively have postcore_initcall(i2c_init), which may be better ... the initcall levels are pretty limited, and in these cases the "subsystem" of interest builds on I2C and needs to work before device_initcall. Having I2C use subsys_initcall kind of forces things into fs_initcall.

I'd encourage the anti-oopsing paranoia in any case, even if i2c switches to postcore_initcall (or earlier).

 drivers/i2c/i2c-core.c |   10 ++++++++++
 1 file changed, 10 insertions(+)

drivers/i2c/i2c-core.c static int i2c_register_adapter(struct i · line 451

Quoted 9 lines
drivers/i2c/i2c-core.c +6 -0
@@ -443,6 +443,12 @@ static int i2c_register_adapter(struct i
 
 	mutex_lock(&core_lock);
 
+	/* can't register until after driver model init */
+	if (WARN_ON(!i2c_bus_type.p)) {
+		res = -ENOENT;
+		goto out_list;
+	}
+

Why don't you test before acquiring core_lock? Or even, before doing anything else, as you do in i2c_register_driver. That's more consistent and makes the error path lighter.

Quoted 4 lines
drivers/i2c/i2c-core.c +0 -0
 	/* Add the adapter to the driver core.
 	 * If the parent pointer is not set up,
 	 * we add this adapter to the host bus.

drivers/i2c/i2c-core.c int i2c_register_driver(struct module *o · line 711

Quoted 10 lines
drivers/i2c/i2c-core.c +4 -0
@@ -696,6 +702,10 @@ int i2c_register_driver(struct module *o
 {
 	int res;
 
+	/* can't register until after driver model init */
+	if (WARN_ON(!i2c_bus_type.p))
+		return -ENOENT;
+
 	/* new style driver methods can't mix with legacy ones */
 	if (is_newstyle_driver(driver)) {
 		if (driver->attach_adapter || driver->detach_adapter

Also, I see that you still have some love for unique error codes even where they don't match the actual error. There's hardly a file or directory involved here... I think -EAGAIN would make more sense, as the i2c bus type will become available at some later point in time.

So, I would apply the following patch if that's OK with you:

 drivers/i2c/i2c-core.c |    8 ++++++++
 1 file changed, 8 insertions(+)
drivers/i2c/i2c-core.c +8 -0
@@ -437,6 +437,10 @@ static int i2c_register_adapter(struct i
 {
 	int res = 0, dummy;
 
+	/* Can't register until after driver model init */
+	if (WARN_ON(!i2c_bus_type.p))
+		return -EAGAIN;
+
 	mutex_init(&adap->bus_lock);
 	mutex_init(&adap->clist_lock);
 	INIT_LIST_HEAD(&adap->clients);
@@ -696,6 +700,10 @@ int i2c_register_driver(struct module *o
 {
 	int res;
 
+	/* Can't register until after driver model init */
+	if (WARN_ON(!i2c_bus_type.p))
+		return -EAGAIN;
+
 	/* new style driver methods can't mix with legacy ones */
 	if (is_newstyle_driver(driver)) {
 		if (driver->attach_adapter || driver->detach_adapter
Signature · 6 lines
Jean Delvare

_______________________________________________
i2c mailing list
[email protected]
http://lists.lm-sensors.org/mailman/listinfo/i2c

A message that is not in the archive (sent off-list or not yet received): [email protected]

#7 lore raw
Quoted 6 lines · Jean Delvare
Quoted 6 lines
drivers/i2c/i2c-core.c +0 -0
@@ -443,6 +443,12 @@ static int i2c_register_adapter(struct i
 
 	mutex_lock(&core_lock);
 
Quoted 10 lines

drivers/i2c/i2c-core.c static int i2c_register_adapter(struct i · line 451

Quoted 6 lines
drivers/i2c/i2c-core.c +6 -0
+	/* can't register until after driver model init */
+	if (WARN_ON(!i2c_bus_type.p)) {
+		res = -ENOENT;
+		goto out_list;
+	}
+

Why don't you test before acquiring core_lock? Or even, before doing anything else, as you do in i2c_register_driver. That's more consistent and makes the error path lighter.

One or the other was an afterthought. I don't recall which one. ;)

Quoted 1 line

So, I would apply the following patch if that's OK with you:

Sure ... I'll be happy to have such issues be more diagnosable.

- Dave

Quoted 19 lines
 drivers/i2c/i2c-core.c |    8 ++++++++
 1 file changed, 8 insertions(+)
drivers/i2c/i2c-core.c +4 -0
@@ -437,6 +437,10 @@ static int i2c_register_adapter(struct i
 {
 	int res = 0, dummy;
 
+	/* Can't register until after driver model init */
+	if (WARN_ON(!i2c_bus_type.p))
+		return -EAGAIN;
+
 	mutex_init(&adap->bus_lock);
 	mutex_init(&adap->clist_lock);
 	INIT_LIST_HEAD(&adap->clients);

drivers/i2c/i2c-core.c int i2c_register_driver(struct module *o · line 709

Quoted 10 lines
drivers/i2c/i2c-core.c +4 -0
@@ -696,6 +700,10 @@ int i2c_register_driver(struct module *o
 {
 	int res;
 
+	/* Can't register until after driver model init */
+	if (WARN_ON(!i2c_bus_type.p))
+		return -EAGAIN;
+
 	/* new style driver methods can't mix with legacy ones */
 	if (is_newstyle_driver(driver)) {
 		if (driver->attach_adapter || driver->detach_adapter

_______________________________________________
i2c mailing list
[email protected]
http://lists.lm-sensors.org/mailman/listinfo/i2c