Skip to contentSkip to conversation

memstick: core: fix device_register() error handling

PATCH Applied Vasiliy Kulikov 6 participants 13 messages Sep 19, 2010 – Sep 23, 2010

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

PATCH 4/14 memstick: core: fix device_register() error handling

If device_register() fails then call put_device(). See comment to device_register.

---
compile tested.

 drivers/memstick/core/memstick.c |    1 +
 1 files changed, 1 insertions(+), 0 deletions(-)
drivers/memstick/core/memstick.c +1 -0
index c00fe82..4303b7e 100644
@@ -465,6 +465,7 @@ static void memstick_check(struct work_struct *work)
 		if (!host->card) {
 			host->card = card;
 			if (device_register(&card->dev)) {
+				put_device(&card->dev);
 				kfree(host->card);
 				host->card = NULL;
 			}
Signature · 1 line
1.7.0.4
#1 lore raw
Quoted 15 lines · On Sun, 19 Sep 2010 16:54:49 +0400 Vasiliy Kulikov <[email protected]> wrote:

If device_register() fails then call put_device(). See comment to device_register.

---
compile tested.

 drivers/memstick/core/memstick.c |    1 +
 1 files changed, 1 insertions(+), 0 deletions(-)
drivers/memstick/core/memstick.c +0 -0
index c00fe82..4303b7e 100644

drivers/memstick/core/memstick.c static void memstick_check(struct work_struct *work) · line 471

Quoted 7 lines
drivers/memstick/core/memstick.c +1 -0
@@ -465,6 +465,7 @@ static void memstick_check(struct work_struct *work)
 		if (!host->card) {
 			host->card = card;
 			if (device_register(&card->dev)) {
+				put_device(&card->dev);
 				kfree(host->card);
 				host->card = NULL;
 			}

A failed device_register() takes a bogus ref on the not-registered device? It's no surprise that people are getting this wrong.

The principle of least surprise says: fix device_register()!

#2 lore raw
Quoted 29 lines · Andrew Morton
Quoted 15 lines · On Sun, 19 Sep 2010 16:54:49 +0400 Vasiliy Kulikov <[email protected]> wrote:

If device_register() fails then call put_device(). See comment to device_register.

---
compile tested.

 drivers/memstick/core/memstick.c |    1 +
 1 files changed, 1 insertions(+), 0 deletions(-)
drivers/memstick/core/memstick.c +0 -0
index c00fe82..4303b7e 100644

drivers/memstick/core/memstick.c static void memstick_check(struct work_struct *work) · line 471

Quoted 7 lines
drivers/memstick/core/memstick.c +1 -0
@@ -465,6 +465,7 @@ static void memstick_check(struct work_struct *work)
 		if (!host->card) {
 			host->card = card;
 			if (device_register(&card->dev)) {
+				put_device(&card->dev);
 				kfree(host->card);
 				host->card = NULL;
 			}

A failed device_register() takes a bogus ref on the not-registered device? It's no surprise that people are getting this wrong.

Quoted 1 line

The principle of least surprise says: fix device_register()!

One might think that, but it's a bit more difficult.

How does device_register know it should destroy the device if it fails?

Here's how it works:
- device_register is just a wrapper around device_initialize() and device_add()
- device_initialize() can't do anything wrong, so it's safe, BUT, at this point in time, the reference for the device is incremented, so any caller must now drop the reference and properly free stuff.
- device_add() does a lot.

Hm, I guess, because we "know" in device_register() that we must drop something if device_add() fails, then I guess it's not being consistant with it's own calls...

So, something as simple as this?

drivers/base/core.c +6 -4
index d1b2c9a..4ba8599 100644
@@ -1084,14 +1084,16 @@ name_error:
  * have a clearly defined need to use and refcount the device
  * before it is added to the hierarchy.
  *
- * NOTE: _Never_ directly free @dev after calling this function, even
- * if it returned an error! Always use put_device() to give up the
- * reference initialized in this function instead.
  */
 int device_register(struct device *dev)
 {
+	int retval;
+
 	device_initialize(dev);
-	return device_add(dev);
+	retval = device_add(dev);
+	if (retval)
+		put_device(dev);
+	return retval;
 }
 
 /**

Kay, what am I missing here, why can't we just do this? Hm, the side-affect might be that if device_register() fails, NO ONE had better touch that device again, as it might have just been freed from the system. I wonder if that will cause problems...

thanks,

greg k-h

#3 lore raw
Quoted 12 lines · Greg KH

 int device_register(struct device *dev)
 {
+       int retval;
+
       device_initialize(dev);
-       return device_add(dev);
+       retval = device_add(dev);
+       if (retval)
+               put_device(dev);
+       return retval;
 }

Quoted 4 lines

Kay, what am I missing here, why can't we just do this?  Hm, the side-affect might be that if device_register() fails, NO ONE had better touch that device again, as it might have just been freed from the system.  I wonder if that will cause problems...

That looks right, besides that there might be callers already doing this. Which needs to be checked.

I never liked this pretty useless "convenience API", which just wraps two simple functions and the first one can never fail anyway.

We better remove that device_register() stuff entirely in the long run, it's not doing any good. At the kobject level we killed the same stuff already long ago.

Kay

#4 lore raw
Quoted 22 lines · Kay Sievers
Quoted 12 lines · Greg KH

int device_register(struct device *dev)
{

drivers/base/core.c +6 -1
+       int retval;
+
       device_initialize(dev);
-       return device_add(dev);
+       retval = device_add(dev);
+       if (retval)
+               put_device(dev);
+       return retval;
 }
Quoted 4 lines

Kay, what am I missing here, why can't we just do this? Hm, the side-affect might be that if device_register() fails, NO ONE had better touch that device again, as it might have just been freed from the system. I wonder if that will cause problems...

That looks right, besides that there might be callers already doing this. Which needs to be checked.

Quoted 7 lines

I never liked this pretty useless "convenience API", which just wraps two simple functions and the first one can never fail anyway.

We better remove that device_register() stuff entirely in the long run, it's not doing any good. At the kobject level we killed the same stuff already long ago.

That would be fine, and ping me when you do it, I'll help with my driver. But don't forget to let us have a way to embed a device inside a bigger structure.

For meanwhile Please check the patch James sent to add_device that cleans up the allocation of the kobj.name member. (And the comment made there)

Quoted 1 line

Kay

Thanks
Boaz

#5 lore raw
Quoted 26 lines · Boaz Harrosh
Quoted 25 lines · Kay Sievers
Quoted 12 lines · Greg KH

int device_register(struct device *dev)
{

drivers/base/core.c +6 -1
+       int retval;
+
       device_initialize(dev);
-       return device_add(dev);
+       retval = device_add(dev);
+       if (retval)
+               put_device(dev);
+       return retval;
 }
Quoted 4 lines

Kay, what am I missing here, why can't we just do this? Hm, the side-affect might be that if device_register() fails, NO ONE had better touch that device again, as it might have just been freed from the system. I wonder if that will cause problems...

That looks right, besides that there might be callers already doing this. Which needs to be checked.

I never liked this pretty useless "convenience API", which just wraps two simple functions and the first one can never fail anyway.

Quoted 8 lines
Quoted 4 lines

We better remove that device_register() stuff entirely in the long run, it's not doing any good. At the kobject level we killed the same stuff already long ago.

That would be fine, and ping me when you do it, I'll help with my driver. But don't forget to let us have a way to embed a device inside a bigger structure.

That's what you should be doing anyway, so it shouldn't be a problem.

Quoted 2 lines

For meanwhile Please check the patch James sent to add_device that cleans up the allocation of the kobj.name member. (And the comment made there)

See my other email why that isn't a good idea.

thanks,

greg k-h

#6 lore raw
Quoted 36 lines · Greg KH
Quoted 26 lines · Boaz Harrosh
Quoted 25 lines · Kay Sievers
Quoted 12 lines · Greg KH

int device_register(struct device *dev)
{

drivers/base/core.c +6 -1
+       int retval;
+
       device_initialize(dev);
-       return device_add(dev);
+       retval = device_add(dev);
+       if (retval)
+               put_device(dev);
+       return retval;
 }
Quoted 4 lines

Kay, what am I missing here, why can't we just do this? Hm, the side-affect might be that if device_register() fails, NO ONE had better touch that device again, as it might have just been freed from the system. I wonder if that will cause problems...

That looks right, besides that there might be callers already doing this. Which needs to be checked.

I never liked this pretty useless "convenience API", which just wraps two simple functions and the first one can never fail anyway.

Quoted 8 lines
Quoted 4 lines

We better remove that device_register() stuff entirely in the long run, it's not doing any good. At the kobject level we killed the same stuff already long ago.

That would be fine, and ping me when you do it, I'll help with my driver. But don't forget to let us have a way to embed a device inside a bigger structure.

Quoted 6 lines

That's what you should be doing anyway, so it shouldn't be a problem.

Quoted 2 lines

For meanwhile Please check the patch James sent to add_device that cleans up the allocation of the kobj.name member. (And the comment made there)

See my other email why that isn't a good idea.

What other email? ... neither you nor Kay replied after either Boaz's patch or the corrected one were posted.

James

#7 lore raw
Quoted 39 lines · James Bottomley
Quoted 38 lines · Greg KH
Quoted 26 lines · Boaz Harrosh
Quoted 25 lines · Kay Sievers
Quoted 12 lines · Greg KH

int device_register(struct device *dev)
{

drivers/base/core.c +6 -1
+       int retval;
+
       device_initialize(dev);
-       return device_add(dev);
+       retval = device_add(dev);
+       if (retval)
+               put_device(dev);
+       return retval;
 }
Quoted 4 lines

Kay, what am I missing here, why can't we just do this? Hm, the side-affect might be that if device_register() fails, NO ONE had better touch that device again, as it might have just been freed from the system. I wonder if that will cause problems...

That looks right, besides that there might be callers already doing this. Which needs to be checked.

I never liked this pretty useless "convenience API", which just wraps two simple functions and the first one can never fail anyway.

Quoted 8 lines
Quoted 4 lines

We better remove that device_register() stuff entirely in the long run, it's not doing any good. At the kobject level we killed the same stuff already long ago.

That would be fine, and ping me when you do it, I'll help with my driver. But don't forget to let us have a way to embed a device inside a bigger structure.

That's what you should be doing anyway, so it shouldn't be a problem.

Quoted 7 lines
Quoted 4 lines
Quoted 2 lines

For meanwhile Please check the patch James sent to add_device that cleans up the allocation of the kobj.name member. (And the comment made there)

See my other email why that isn't a good idea.

What other email? ... neither you nor Kay replied after either Boaz's patch or the corrected one were posted.

See my other email a minute ago in response to this thread.

thanks,

greg k-h

#8 lore raw
Quoted 4 lines · Greg KH
Quoted 2 lines

What other email? ... neither you nor Kay replied after either Boaz's patch or the corrected one were posted.

See my other email a minute ago in response to this thread.

Can we start again? You've been replying to a patch to do a put_device() in device_register() which everyone agrees looks wrong.

The proposal to fix all of this is to free the kobject name and NULL it out in device_add(). That fixes all the places you and kay broke when you added the variable length name stuff.

James

#9 lore raw
In reply to Kay Sievers
Quoted 14 lines · Kay Sievers
Quoted 11 lines · Greg KH

 int device_register(struct device *dev)
 {
+       int retval;
+
       device_initialize(dev);
-       return device_add(dev);
+       retval = device_add(dev);
+       if (retval)
+               put_device(dev);
+       return retval;
 }

Quoted 7 lines
Quoted 4 lines

Kay, what am I missing here, why can't we just do this?  Hm, the side-affect might be that if device_register() fails, NO ONE had better touch that device again, as it might have just been freed from the system.  I wonder if that will cause problems...

That looks right, besides that there might be callers already doing this. Which needs to be checked.

Yes, it would be. I'll go through the tree.

Quoted 2 lines

I never liked this pretty useless "convenience API", which just wraps two simple functions and the first one can never fail anyway.

Agreed.

Quoted 3 lines

We better remove that device_register() stuff entirely in the long run, it's not doing any good. At the kobject level we killed the same stuff already long ago.

It's one of the things on my "to change" list.

thanks,

greg k-h
--
To unsubscribe from this list: send the line "unsubscribe kernel-janitors" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html

#10 lore raw
Quoted 20 lines · Greg KH
Quoted 19 lines · Kay Sievers
Quoted 16 lines · Greg KH

 int device_register(struct device *dev)
 {
+       int retval;
+
       device_initialize(dev);
-       return device_add(dev);
+       retval = device_add(dev);
+       if (retval)
+               put_device(dev);
+       return retval;
 }

Kay, what am I missing here, why can't we just do this?  Hm, the side-affect might be that if device_register() fails, NO ONE had better touch that device again, as it might have just been freed from the system.  I wonder if that will cause problems...

Quoted 4 lines
Quoted 2 lines

That looks right, besides that there might be callers already doing this. Which needs to be checked.

Yes, it would be. I'll go through the tree.

As I see with this in-device_register patch we should check for 2 things:

1) nobody should call put_device() because of failed device_register().

2) dev has to be already got, other words its ref counter should not be zero.

Correct?

Signature · 5 lines
Vasiliy
--
To unsubscribe from this list: send the line "unsubscribe kernel-janitors" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
#11 lore raw
In reply to Greg KH
Quoted 63 lines · Greg KH
Quoted 29 lines · Andrew Morton
Quoted 15 lines · On Sun, 19 Sep 2010 16:54:49 +0400 Vasiliy Kulikov <[email protected]> wrote:

If device_register() fails then call put_device(). See comment to device_register.

---
compile tested.

 drivers/memstick/core/memstick.c |    1 +
 1 files changed, 1 insertions(+), 0 deletions(-)
drivers/memstick/core/memstick.c +0 -0
index c00fe82..4303b7e 100644

drivers/memstick/core/memstick.c static void memstick_check(struct work_struct *work) · line 471

Quoted 7 lines
drivers/memstick/core/memstick.c +1 -0
@@ -465,6 +465,7 @@ static void memstick_check(struct work_struct *work)
 		if (!host->card) {
 			host->card = card;
 			if (device_register(&card->dev)) {
+				put_device(&card->dev);
 				kfree(host->card);
 				host->card = NULL;
 			}

A failed device_register() takes a bogus ref on the not-registered device? It's no surprise that people are getting this wrong.

Quoted 1 line

The principle of least surprise says: fix device_register()!

One might think that, but it's a bit more difficult.

How does device_register know it should destroy the device if it fails?

Here's how it works:
- device_register is just a wrapper around device_initialize() and device_add()
- device_initialize() can't do anything wrong, so it's safe, BUT, at this point in time, the reference for the device is incremented, so any caller must now drop the reference and properly free stuff.
- device_add() does a lot.

Hm, I guess, because we "know" in device_register() that we must drop something if device_add() fails, then I guess it's not being consistant with it's own calls...

So, something as simple as this?

drivers/base/core.c +0 -3
index d1b2c9a..4ba8599 100644
@@ -1084,14 +1084,16 @@ name_error:
  * have a clearly defined need to use and refcount the device
  * before it is added to the hierarchy.
  *
- * NOTE: _Never_ directly free @dev after calling this function, even
- * if it returned an error! Always use put_device() to give up the
- * reference initialized in this function instead.

drivers/base/core.c name_error: · line 1095

Quoted 10 lines
drivers/base/core.c +5 -1
  */
 int device_register(struct device *dev)
 {
+	int retval;
+
 	device_initialize(dev);
-	return device_add(dev);
+	retval = device_add(dev);
+	if (retval)
+		put_device(dev);

This is all theoretically sound. But it will crash my device driver and a dozen more like mine.

Because the passed *dev is an embedded structure inside a bigger driver-specific structure. (Hence the call to device_register).

The kref inside the *dev is used to also govern the lifetime of the outer struct. With a registered release and the use of a container_of.

Now up until now, and was fine before the set_name changes. If device_register failed the build-up function would just deallocate the outer struct together with the inner device. If you call put_device(dev) here then the release function will be called. Which is a double free. And also the release function is coded to expect a fully setup device, though calling device_unregister, and all the other resources contained in the outer struct.

So in short it would work but not with current code, and not with out a major restructuring.

What about the patch James sent to just free the name string and be done with it?

Quoted 7 lines
drivers/base/core.c +1 -0
+	return retval;
 }
 
 /**
Quoted 5 lines

Kay, what am I missing here, why can't we just do this? Hm, the side-affect might be that if device_register() fails, NO ONE had better touch that device again, as it might have just been freed from the system. I wonder if that will cause problems...

Exactly. Lets please let us recap the scope here. device_register is specifically for Embedded devices where the life time rules are "delicate" to say the least. All we have is the name string memory leak. Can we fix that and not force a major Kernel re-write.

Quoted 3 lines

thanks,

greg k-h

Thanks
Boaz

#12 lore raw
Quoted 69 lines · Boaz Harrosh
Quoted 68 lines · Greg KH
Quoted 29 lines · Andrew Morton
Quoted 15 lines · On Sun, 19 Sep 2010 16:54:49 +0400 Vasiliy Kulikov <[email protected]> wrote:

If device_register() fails then call put_device(). See comment to device_register.

---
compile tested.

 drivers/memstick/core/memstick.c |    1 +
 1 files changed, 1 insertions(+), 0 deletions(-)
drivers/memstick/core/memstick.c +0 -0
index c00fe82..4303b7e 100644

drivers/memstick/core/memstick.c static void memstick_check(struct work_struct *work) · line 471

Quoted 7 lines
drivers/memstick/core/memstick.c +1 -0
@@ -465,6 +465,7 @@ static void memstick_check(struct work_struct *work)
 		if (!host->card) {
 			host->card = card;
 			if (device_register(&card->dev)) {
+				put_device(&card->dev);
 				kfree(host->card);
 				host->card = NULL;
 			}

A failed device_register() takes a bogus ref on the not-registered device? It's no surprise that people are getting this wrong.

Quoted 1 line

The principle of least surprise says: fix device_register()!

One might think that, but it's a bit more difficult.

How does device_register know it should destroy the device if it fails?

Here's how it works:
- device_register is just a wrapper around device_initialize() and device_add()
- device_initialize() can't do anything wrong, so it's safe, BUT, at this point in time, the reference for the device is incremented, so any caller must now drop the reference and properly free stuff.
- device_add() does a lot.

Hm, I guess, because we "know" in device_register() that we must drop something if device_add() fails, then I guess it's not being consistant with it's own calls...

So, something as simple as this?

drivers/base/core.c +2 -3
index d1b2c9a..4ba8599 100644
@@ -1084,14 +1084,16 @@ name_error:
  * have a clearly defined need to use and refcount the device
  * before it is added to the hierarchy.
  *
- * NOTE: _Never_ directly free @dev after calling this function, even
- * if it returned an error! Always use put_device() to give up the
- * reference initialized in this function instead.
  */
 int device_register(struct device *dev)
 {
+	int retval;
+
Quoted 8 lines

drivers/base/core.c name_error: · line 1095

Quoted 5 lines
drivers/base/core.c +3 -1
 	device_initialize(dev);
-	return device_add(dev);
+	retval = device_add(dev);
+	if (retval)
+		put_device(dev);

This is all theoretically sound. But it will crash my device driver and a dozen more like mine.

Then they are broken :)

Quoted 2 lines

Because the passed *dev is an embedded structure inside a bigger driver-specific structure. (Hence the call to device_register).

So, you would like to keep the way the code currently works in that if device_register() fails, you are responsible for calling put_device() on your own when finished?

Quoted 3 lines

The kref inside the *dev is used to also govern the lifetime of the outer struct. With a registered release and the use of a container_of.

That's as it should be.

Quoted 8 lines

Now up until now, and was fine before the set_name changes. If device_register failed the build-up function would just deallocate the outer struct together with the inner device. If you call put_device(dev) here then the release function will be called. Which is a double free. And also the release function is coded to expect a fully setup device, though calling device_unregister, and all the other resources contained in the outer struct.

Well, you don't do the double free then :)

Quoted 2 lines

So in short it would work but not with current code, and not with out a major restructuring.

Do you have an example of a driver that would break so I can look at it?

Quoted 2 lines

What about the patch James sent to just free the name string and be done with it?

Don't poke into the kobject structure from the driver core, that's not nice and not allowed.

Quoted 7 lines
Quoted 7 lines
drivers/base/core.c +1 -0
+	return retval;
 }
 
 /**
Quoted 10 lines
Quoted 5 lines

Kay, what am I missing here, why can't we just do this? Hm, the side-affect might be that if device_register() fails, NO ONE had better touch that device again, as it might have just been freed from the system. I wonder if that will cause problems...

Exactly. Lets please let us recap the scope here. device_register is specifically for Embedded devices where the life time rules are "delicate" to say the least. All we have is the name string memory leak. Can we fix that and not force a major Kernel re-write.

device_register was never written for embedded people at all, so don't think that.

And why are your lifetime rules any more "delicate" than anyone elses? Is it because the code is perhaps broken? :)

thanks,

greg k-h