Skip to contentSkip to conversation

gpiolib: fix oops in gpio_get_value_cansleep()

PATCH In review David Brownell 4 participants 9 messages Oct 16, 2008 – Oct 17, 2008 GPIO

lore
Share & tools
lore
#0 lore raw

PATCH 1/1 gpiolib: fix oops in gpio_get_value_cansleep()

From: David Brownell <[email protected]>

We can get the following oops from gpio_get_value_cansleep() when a GPIO controller doesn't provide a get() callback:

 Unable to handle kernel paging request for instruction fetch
 Faulting instruction address: 0x00000000
 Oops: Kernel access of bad area, sig: 11 [#1]
 [...]
 NIP [00000000] 0x0
 LR [c0182fb0] gpio_get_value_cansleep+0x40/0x50
 Call Trace:
 [c7b79e80] [c0183f28] gpio_value_show+0x5c/0x94
 [c7b79ea0] [c01a584c] dev_attr_show+0x30/0x7c
 [c7b79eb0] [c00d6b48] fill_read_buffer+0x68/0xe0
 [c7b79ed0] [c00d6c54] sysfs_read_file+0x94/0xbc
 [c7b79ef0] [c008f24c] vfs_read+0xb4/0x16c
 [c7b79f10] [c008f580] sys_read+0x4c/0x90
 [c7b79f40] [c0013a14] ret_from_syscall+0x0/0x38

It's OK to request the value of *any* GPIO; most GPIOs are bidirectional, so configuring them as outputs just enables an output driver and doesn't disable the input logic.

So the problem is that gpio_get_value_cansleep() isn't making the same sanity check that gpio_get_value() does: making sure this GPIO isn't one of the atypical "no input logic" cases.

---
 drivers/gpio/gpiolib.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/gpio/gpiolib.c +1 -1
@@ -1056,7 +1056,7 @@ int gpio_get_value_cansleep(unsigned gpi
 
 	might_sleep_if(extra_checks);
 	chip = gpio_to_chip(gpio);
-	return chip->get(chip, gpio - chip->base);
+	return chip->get ? chip->get(chip, gpio - chip->base) : 0;
 }
 EXPORT_SYMBOL_GPL(gpio_get_value_cansleep);
 
#1 lore raw
Quoted 1 line · David Brownell

From: David Brownell <[email protected]>

[...]

Quoted 13 lines

So the problem is that gpio_get_value_cansleep() isn't making the same sanity check that gpio_get_value() does: making sure this GPIO isn't one of the atypical "no input logic" cases.

---
 drivers/gpio/gpiolib.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

drivers/gpio/gpiolib.c int gpio_get_value_cansleep(unsigned gpi · line 1059

Quoted 5 lines
drivers/gpio/gpiolib.c +1 -1
@@ -1056,7 +1056,7 @@ int gpio_get_value_cansleep(unsigned gpi
 
 	might_sleep_if(extra_checks);
 	chip = gpio_to_chip(gpio);
-	return chip->get(chip, gpio - chip->base);
+	return chip->get ? chip->get(chip, gpio - chip->base) : 0;

Why don't we check the .set in the gpio_set_value? Because we must always call gpio_direction_output()? It is not exactly the same we work with the input direction.. is this documented anywhere?

Signature · 3 lines
Anton Vorontsov
email: [email protected]
irc://irc.freenode.net/bd2
#2 lore raw
Quoted 5 lines · Anton Vorontsov
Quoted 2 lines

-     return chip->get(chip, gpio - chip->base);
+     return chip->get ? chip->get(chip, gpio - chip->base) : 0;

Why don't we check the .set in the gpio_set_value? Because we must always call gpio_direction_output()?

Yes. The output driver needs to be explicitly enabled, to avoid misbehaving electic circuitry.

Quoted 2 lines

It is not exactly the
same we work with the input direction.. is this documented anywhere?

In Documentation/gpio.txt since the very first versions.

See the section on "Spinlock-Safe GPIO access", where special cases for reading the value of output GPIOs are desribed. Other aspects are mentioned in other spots.

For example, open drain signals -- as used with I2C and other protocols -- only drive the "low" signal level, and if code wants a "high" level it's got to verify that nobody else is driving that shared line to low. By reading it back, even though it's configured as output.

- Dave

#3 lore raw
Quoted 20 lines · David Brownell
Quoted 5 lines · Anton Vorontsov
Quoted 2 lines

-     return chip->get(chip, gpio - chip->base);
+     return chip->get ? chip->get(chip, gpio - chip->base) : 0;

Why don't we check the .set in the gpio_set_value? Because we must always call gpio_direction_output()?

Yes. The output driver needs to be explicitly enabled, to avoid misbehaving electic circuitry.

Quoted 2 lines

It is not exactly the
same we work with the input direction.. is this documented anywhere?

In Documentation/gpio.txt since the very first versions.

See the section on "Spinlock-Safe GPIO access", where special cases for reading the value of output GPIOs are desribed. Other aspects are mentioned in other spots.

Quoted 5 lines

For example, open drain signals -- as used with I2C and other protocols -- only drive the "low" signal level, and if code wants a "high" level it's got to verify that nobody else is driving that shared line to low. By reading it back, even though it's configured as output.

I see. Much thanks for the explanations.

Signature · 3 lines
Anton Vorontsov
email: [email protected]
irc://irc.freenode.net/bd2
#4 lore raw
In reply to David Brownell
Quoted 4 lines · On Thu, 16 Oct 2008 08:45:22 -0700 David Brownell <[email protected]> wrote:

From: David Brownell <[email protected]>

We can get the following oops from gpio_get_value_cansleep() when a GPIO controller doesn't provide a get() callback:

We can, but do we? ;)

iow: is this needed in any -stable release?

Quoted 40 lines
 Unable to handle kernel paging request for instruction fetch
 Faulting instruction address: 0x00000000
 Oops: Kernel access of bad area, sig: 11 [#1]
 [...]
 NIP [00000000] 0x0
 LR [c0182fb0] gpio_get_value_cansleep+0x40/0x50
 Call Trace:
 [c7b79e80] [c0183f28] gpio_value_show+0x5c/0x94
 [c7b79ea0] [c01a584c] dev_attr_show+0x30/0x7c
 [c7b79eb0] [c00d6b48] fill_read_buffer+0x68/0xe0
 [c7b79ed0] [c00d6c54] sysfs_read_file+0x94/0xbc
 [c7b79ef0] [c008f24c] vfs_read+0xb4/0x16c
 [c7b79f10] [c008f580] sys_read+0x4c/0x90
 [c7b79f40] [c0013a14] ret_from_syscall+0x0/0x38

It's OK to request the value of *any* GPIO; most GPIOs are bidirectional, so configuring them as outputs just enables an output driver and doesn't disable the input logic.

So the problem is that gpio_get_value_cansleep() isn't making the same sanity check that gpio_get_value() does: making sure this GPIO isn't one of the atypical "no input logic" cases.

---
 drivers/gpio/gpiolib.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/gpio/gpiolib.c +1 -1
@@ -1056,7 +1056,7 @@ int gpio_get_value_cansleep(unsigned gpi
 
 	might_sleep_if(extra_checks);
 	chip = gpio_to_chip(gpio);
-	return chip->get(chip, gpio - chip->base);
+	return chip->get ? chip->get(chip, gpio - chip->base) : 0;
 }
 EXPORT_SYMBOL_GPL(gpio_get_value_cansleep);
 
#5 lore raw
Quoted 6 lines · Andrew Morton
Quoted 4 lines

From: David Brownell <[email protected]>

We can get the following oops from gpio_get_value_cansleep() when a GPIO controller doesn't provide a get() callback:

We can, but do we? ;)

I think it's unlikely without the sysfs interface.

Quoted 1 line

iow: is this needed in any -stable release?

The bug has been there since 2.6.25 but nobody else seems to have reported it. Is the general policy to fix all oopses that *could* appear? I'd send it for 2.6.27-stable, since that's got the sysfs hooks. And older kernels if bug likelihood isn't a major concern.

- Dave

#6 lore raw
Quoted 11 lines · On Thu, 16 Oct 2008 17:44:33 -0700 David Brownell <[email protected]> wrote:
Quoted 6 lines · Andrew Morton
Quoted 4 lines

From: David Brownell <[email protected]>

We can get the following oops from gpio_get_value_cansleep() when a GPIO controller doesn't provide a get() callback:

We can, but do we? ;)

I think it's unlikely without the sysfs interface.

Quoted 7 lines
Quoted 1 line

iow: is this needed in any -stable release?

The bug has been there since 2.6.25 but nobody else seems to have reported it. Is the general policy to fix all oopses that *could* appear? I'd send it for 2.6.27-stable, since that's got the sysfs hooks. And older kernels if bug likelihood isn't a major concern.

OK. 2.6.27 definitely (major distros are basing on that).

As for earlier kernels: I'd say so. An oops is farily serious. Although an oops in a sysfs handler tends to be fairly tame, as the code usually doesn't hold locks or many allocated resources.

Anyway - making decisions like this is why we pay [email protected] the big bucks :)

#7 lore raw
Quoted 21 lines · Andrew Morton
Quoted 11 lines · On Thu, 16 Oct 2008 17:44:33 -0700 David Brownell <[email protected]> wrote:
Quoted 6 lines · Andrew Morton
Quoted 4 lines

From: David Brownell <[email protected]>

We can get the following oops from gpio_get_value_cansleep() when a GPIO controller doesn't provide a get() callback:

We can, but do we? ;)

I think it's unlikely without the sysfs interface.

Quoted 7 lines
Quoted 1 line

iow: is this needed in any -stable release?

The bug has been there since 2.6.25 but nobody else seems to have reported it. Is the general policy to fix all oopses that *could* appear? I'd send it for 2.6.27-stable, since that's got the sysfs hooks. And older kernels if bug likelihood isn't a major concern.

Quoted 8 lines

OK. 2.6.27 definitely (major distros are basing on that).

As for earlier kernels: I'd say so. An oops is farily serious. Although an oops in a sysfs handler tends to be fairly tame, as the code usually doesn't hold locks or many allocated resources.

Anyway - making decisions like this is why we pay [email protected] the big bucks :)

"Pay"? We get paid for this in something becides a full inbox?

I'm not holding my breath :)

Send us the git commit id when it's in Linus's tree and we'll see what is needed to backport this or not.

thanks,

greg k-h

#8 lore raw
Quoted 1 line · Greg KH

"Pay"?  We get paid for this in something becides a full inbox?

Yours is just "full"?? Lucky you! Mine's overflowing.

Bits are falling on the floor, running out the end of cat5 cables, radiating into the 802.11g aether, cluttering up magnetic media, and worse ... ;)

Quoted 1 line

I'm not holding my breath :)