Skip to contentSkip to conversation

PM: Fix dev_pm_put_subsys_data() to not call kfree() while holding device power lock

PATCH Superseded Shuah Khan 4 participants 11 messages May 3, 2013 – May 6, 2013

Subsystems (4)
lore
Share & tools
lore

Shuah Khan

author
#0 lore raw

PATCH 1/1 PM: Fix dev_pm_put_subsys_data() to not call kfree() while holding device power lock

dev_pm_put_subsys_data() calls kfree() while holding device power lock, when the reference count is 0. Fix it to call kfree() after releasing the lock.

---
 drivers/base/power/common.c |    6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)
drivers/base/power/common.c +5 -1
index 39c3252..da05fe2 100644
@@ -73,13 +73,17 @@ int dev_pm_put_subsys_data(struct device *dev)
 
 	if (--psd->refcount == 0) {
 		dev->power.subsys_data = NULL;
-		kfree(psd);
 		ret = 1;
 	}
 
  out:
 	spin_unlock_irq(&dev->power.lock);
 
+	if (ret == 1) {
+		/* kfree() verifies that its argument is nonzero. */
+		kfree(psd);
+	}
+
 	return ret;
 }
 EXPORT_SYMBOL_GPL(dev_pm_put_subsys_data);
Signature · 1 line
1.7.10.4
#1 lore raw

Hi!

Quoted 8 lines

dev_pm_put_subsys_data() calls kfree() while holding device power lock, when the reference count is 0. Fix it to call kfree() after releasing the lock.

---
 drivers/base/power/common.c |    6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

w> diff --git a/drivers/base/power/common.c b/drivers/base/power/common.c

Quoted 11 lines

index 39c3252..da05fe2 100644

drivers/base/power/common.c +0 -1
@@ -73,13 +73,17 @@ int dev_pm_put_subsys_data(struct device *dev)
 
 	if (--psd->refcount == 0) {
 		dev->power.subsys_data = NULL;
-		kfree(psd);
 		ret = 1;
 	}
 

drivers/base/power/common.c int dev_pm_put_subsys_data(struct device *dev) · line 88

Quoted 10 lines
drivers/base/power/common.c +5 -0
  out:
 	spin_unlock_irq(&dev->power.lock);
 
+	if (ret == 1) {
+		/* kfree() verifies that its argument is nonzero. */
+		kfree(psd);
+	}
+
 	return ret;
 }

Wow, that function is fragile. It returns 0/1/-EINVAL, while being documented for 0/1...

Patch does not look obviously wrong, but maybe

@@ -73,13 +73,17 @@ int dev_pm_put_subsys_data(struct device *dev)

if (--psd->refcount == 0) {
dev->power.subsys_data = NULL;
+ spin_unlock_irq(&dev->power.lock);
- kfree(psd);
- ret = 1;
+ return 1;
}

Would be cleaner.
Pavel

Signature · 2 lines
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
#2 lore raw
Quoted 25 lines · Pavel Machek

Hi!

Quoted 8 lines

dev_pm_put_subsys_data() calls kfree() while holding device power lock, when the reference count is 0. Fix it to call kfree() after releasing the lock.

---
 drivers/base/power/common.c |    6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

w> diff --git a/drivers/base/power/common.c b/drivers/base/power/common.c

Quoted 14 lines

index 39c3252..da05fe2 100644

drivers/base/power/common.c +0 -1
@@ -73,13 +73,17 @@ int dev_pm_put_subsys_data(struct device *dev)
 
 	if (--psd->refcount == 0) {
 		dev->power.subsys_data = NULL;
-		kfree(psd);
 		ret = 1;
 	}
 
  out:
 	spin_unlock_irq(&dev->power.lock);
 
Quoted 10 lines

drivers/base/power/common.c int dev_pm_put_subsys_data(struct device *dev) · line 88

Quoted 7 lines
drivers/base/power/common.c +5 -0
+	if (ret == 1) {
+		/* kfree() verifies that its argument is nonzero. */
+		kfree(psd);
+	}
+
 	return ret;
 }

Wow, that function is fragile. It returns 0/1/-EINVAL, while being documented for 0/1...

Oh, it generally should return 1 for !psd.

Quoted 12 lines

Patch does not look obviously wrong, but maybe

(quoted diff) +2 -2
@@ -73,13 +73,17 @@ int dev_pm_put_subsys_data(struct device *dev)
 
 	if (--psd->refcount == 0) {
 		dev->power.subsys_data = NULL;
+		spin_unlock_irq(&dev->power.lock);
-		kfree(psd);
- 		ret = 1;
+		return 1;
 	}
 
Quoted 1 line

Would be cleaner.

What about this:

---
 drivers/base/power/common.c |   12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)
drivers/base/power/common.c +6 -6
Index: linux-pm/drivers/base/power/common.c
===================================================================
@@ -61,24 +61,24 @@ EXPORT_SYMBOL_GPL(dev_pm_get_subsys_data
 int dev_pm_put_subsys_data(struct device *dev)
 {
 	struct pm_subsys_data *psd;
-	int ret = 0;
+	int ret = 1;
 
 	spin_lock_irq(&dev->power.lock);
 
 	psd = dev_to_psd(dev);
-	if (!psd) {
-		ret = -EINVAL;
+	if (!psd)
 		goto out;
-	}
 
 	if (--psd->refcount == 0) {
 		dev->power.subsys_data = NULL;
-		kfree(psd);
-		ret = 1;
+	} else {
+		psd = NULL;
+		ret = 0;
 	}
 
  out:
 	spin_unlock_irq(&dev->power.lock);
+	kfree(psd);
 
 	return ret;
 }
Signature · 2 lines
I speak only for myself.
Rafael J. Wysocki, Intel Open Source Technology Center.
Reviewed-by
#3 lore raw

Hi!

Quoted 17 lines
Quoted 2 lines

Wow, that function is fragile. It returns 0/1/-EINVAL, while being documented for 0/1...

Oh, it generally should return 1 for !psd.

Quoted 12 lines

Patch does not look obviously wrong, but maybe

drivers/base/power/common.c +2 -2
@@ -73,13 +73,17 @@ int dev_pm_put_subsys_data(struct device *dev)
 
 	if (--psd->refcount == 0) {
 		dev->power.subsys_data = NULL;
+		spin_unlock_irq(&dev->power.lock);
-		kfree(psd);
- 		ret = 1;
+		return 1;
 	}
 
Quoted 3 lines
Quoted 1 line

Would be cleaner.

What about this:

Looks good to me.

Pavel

Signature · 2 lines
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
author
#4 lore raw
Quoted 19 lines · Pavel Machek

Hi!

Quoted 17 lines
Quoted 2 lines

Wow, that function is fragile. It returns 0/1/-EINVAL, while being documented for 0/1...

Oh, it generally should return 1 for !psd.

Quoted 12 lines

Patch does not look obviously wrong, but maybe

drivers/base/power/common.c +2 -2
@@ -73,13 +73,17 @@ int dev_pm_put_subsys_data(struct device *dev)
 
 	if (--psd->refcount == 0) {
 		dev->power.subsys_data = NULL;
+		spin_unlock_irq(&dev->power.lock);
-		kfree(psd);
- 		ret = 1;
+		return 1;
 	}
 
Quoted 7 lines
Quoted 3 lines
Quoted 1 line

Would be cleaner.

What about this:

Looks good to me.

Rafael/Pavel,

I redid the patch based on Pavel's comments and just about to send it and then I saw your exchange. This version looks good to me. Do you want me to test the patch and resend?

thanks,
-- Shuah

author
#5 lore raw
Quoted 28 lines · Shuah Khan
Quoted 19 lines · Pavel Machek

Hi!

Quoted 17 lines
Quoted 2 lines

Wow, that function is fragile. It returns 0/1/-EINVAL, while being documented for 0/1...

Oh, it generally should return 1 for !psd.

Quoted 12 lines

Patch does not look obviously wrong, but maybe

drivers/base/power/common.c +2 -2
@@ -73,13 +73,17 @@ int dev_pm_put_subsys_data(struct device *dev)
 
 	if (--psd->refcount == 0) {
 		dev->power.subsys_data = NULL;
+		spin_unlock_irq(&dev->power.lock);
-		kfree(psd);
- 		ret = 1;
+		return 1;
 	}
 
Quoted 7 lines
Quoted 3 lines
Quoted 1 line

Would be cleaner.

What about this:

Looks good to me.

Quoted 8 lines

Rafael/Pavel,

I redid the patch based on Pavel's comments and just about to send it and then I saw your exchange. This version looks good to me. Do you want me to test the patch and resend?

thanks,
-- Shuah

I sent v2 patch that incorporates the comments from Rafael and Pavel.

thanks,

-- Shuah

Shuah Khan Lead Kernel Developer - Open Source Group Samsung Research America (Silicon Valley) [email protected] | (970) 672-0658

author
#6 lore raw

PATCH v2 1/1 PM: Fix dev_pm_put_subsys_data() to not call kfree() while holding device power lock

In reply to Pavel Machek

dev_pm_put_subsys_data() calls kfree() while holding device power lock, when the reference count is 0. Fix it to call kfree() after releasing the lock.

---
 drivers/base/power/common.c |    8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)
drivers/base/power/common.c +5 -3
index 39c3252..e5b99f7 100644
@@ -61,24 +61,26 @@ EXPORT_SYMBOL_GPL(dev_pm_get_subsys_data);
 int dev_pm_put_subsys_data(struct device *dev)
 {
 	struct pm_subsys_data *psd;
-	int ret = 0;
+	int ret = 1;
 
 	spin_lock_irq(&dev->power.lock);
 
 	psd = dev_to_psd(dev);
 	if (!psd) {
-		ret = -EINVAL;
 		goto out;
 	}
 
 	if (--psd->refcount == 0) {
 		dev->power.subsys_data = NULL;
-		kfree(psd);
 		ret = 1;
+	} else {
+		psd = NULL;
+		ret = 0;
 	}
 
  out:
 	spin_unlock_irq(&dev->power.lock);
+	kfree(psd);
 
 	return ret;
 }
Signature · 1 line
1.7.10.4
#7 lore raw
Quoted 9 lines · Shuah Khan

dev_pm_put_subsys_data() calls kfree() while holding device power lock, when the reference count is 0. Fix it to call kfree() after releasing the lock.

---
 drivers/base/power/common.c |    8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)

Is this causing a problem now, and it should go into 3.10 and earlier kernels (if so, which ones?), or can it just wait until 3.11 as it's just a cleanup fix?

thanks,

greg k-h

author
#8 lore raw
Quoted 11 lines · On Mon, 2013-05-06 at 12:41 -0700, [email protected] wrote:
Quoted 9 lines · Shuah Khan

dev_pm_put_subsys_data() calls kfree() while holding device power lock, when the reference count is 0. Fix it to call kfree() after releasing the lock.

---
 drivers/base/power/common.c |    8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)
Quoted 3 lines

Is this causing a problem now, and it should go into 3.10 and earlier kernels (if so, which ones?), or can it just wait until 3.11 as it's just a cleanup fix?

It can wait until 3.11. At this point I don't have any evidence that this is actually causing problems. So please treat this as a cleanup fix found during code review.

thanks,
-- Shuah

Signature · 3 lines
Shuah Khan Lead Kernel Developer - Open Source Group 
Samsung Research America (Silicon Valley)
[email protected] | (970) 672-0658
#9 lore raw
In reply to [email protected]
Quoted 11 lines · On Monday, May 06, 2013 12:41:19 PM [email protected] wrote:
Quoted 9 lines · Shuah Khan

dev_pm_put_subsys_data() calls kfree() while holding device power lock, when the reference count is 0. Fix it to call kfree() after releasing the lock.

---
 drivers/base/power/common.c |    8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)
Quoted 3 lines

Is this causing a problem now, and it should go into 3.10 and earlier kernels (if so, which ones?), or can it just wait until 3.11 as it's just a cleanup fix?

I think it's OK to push the fix for 3.10, but I'll take care of this (I have a bunch of fixes for 3.10 anyway, but I'll send a pull request after -rc1, because people are sending me fixes pretty much continuously ATM).

Thanks,
Rafael

Signature · 2 lines
I speak only for myself.
Rafael J. Wysocki, Intel Open Source Technology Center.
maintainer Acked-by
#10 lore raw
Quoted 12 lines · Rafael J. Wysocki
Quoted 11 lines · On Monday, May 06, 2013 12:41:19 PM [email protected] wrote:
Quoted 9 lines · Shuah Khan

dev_pm_put_subsys_data() calls kfree() while holding device power lock, when the reference count is 0. Fix it to call kfree() after releasing the lock.

---
 drivers/base/power/common.c |    8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)
Quoted 7 lines
Quoted 3 lines

Is this causing a problem now, and it should go into 3.10 and earlier kernels (if so, which ones?), or can it just wait until 3.11 as it's just a cleanup fix?

I think it's OK to push the fix for 3.10, but I'll take care of this (I have a bunch of fixes for 3.10 anyway, but I'll send a pull request after -rc1, because people are sending me fixes pretty much continuously ATM).

Ok, feel free to add: