Skip to contentSkip to conversation

cpufreq: Correct a freq check in cpufreq_set_policy

PATCH Superseded Pan Xinhui 3 participants 7 messages Jul 28, 2015 – Aug 5, 2015

Subsystems (2)
lore
Share & tools
lore

Pan Xinhui

author
#0 lore raw

PATCH 1/1 cpufreq: Correct a freq check in cpufreq_set_policy

From: Pan Xinhui <[email protected]>

This check was originally added by commit 9c9a43ed2734 ("[CPUFREQ] return error when failing to set minfreq").It attempt to return an error on obviously incorrect limits when we echo xxx >.../scaling_max,min_freq Actually we just need check if new_policy->min > new_policy->max. Because at least one of max/min is copied from cpufreq_get_policy().

For example, when we echo xxx > .../scaling_min_freq, new_policy is copied from policy in cpufreq_get_policy. new_policy->max is same with policy->max. new_policy->min is set to a new value.

Let me explain it in deduction method, first statment in if ():
new_policy->min > policy->max
policy->max == new_policy->max
==> new_policy->min > new_policy->max

second statment in if():
new_policy->max < policy->min
policy->max < policy->min
==>new_policy->min > new_policy->max (induction method)

So we have proved that we only need check if new_policy->min > new_policy->max.

After apply this patch, we can also modify ->min and ->max in same time if new freq range is very much different from current freq range. For example, if current freq range is 480000-960000, then we want to set this range to 1120000-2240000, we would fail in the past because new_policy->min > policy->max. As long as the cpufreq range is valid, we has no reason to reject the user. So correct the check.

---
 drivers/cpufreq/cpufreq.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/cpufreq/cpufreq.c +1 -1
index 6424e05..8772346 100644
@@ -2276,7 +2276,7 @@ static int cpufreq_set_policy(struct cpufreq_policy *policy,
 
 	memcpy(&new_policy->cpuinfo, &policy->cpuinfo, sizeof(policy->cpuinfo));
 
-	if (new_policy->min > policy->max || new_policy->max < policy->min)
+	if (new_policy->min > new_policy->max)
 		return -EINVAL;
 
 	/* verify the cpu speed can be set within this limit */
Signature · 1 line
1.9.1
maintainer
#1 lore raw
Quoted 25 lines · Pan Xinhui

From: Pan Xinhui <[email protected]>

This check was originally added by commit 9c9a43ed2734 ("[CPUFREQ] return error when failing to set minfreq").It attempt to return an error on obviously incorrect limits when we echo xxx >.../scaling_max,min_freq Actually we just need check if new_policy->min > new_policy->max. Because at least one of max/min is copied from cpufreq_get_policy().

For example, when we echo xxx > .../scaling_min_freq, new_policy is copied from policy in cpufreq_get_policy. new_policy->max is same with policy->max. new_policy->min is set to a new value.

Let me explain it in deduction method, first statment in if ():
new_policy->min > policy->max
policy->max == new_policy->max
==> new_policy->min > new_policy->max

second statment in if():
new_policy->max < policy->min
policy->max < policy->min
==>new_policy->min > new_policy->max (induction method)

So we have proved that we only need check if new_policy->min > new_policy->max.

Quoted 8 lines

After apply this patch, we can also modify ->min and ->max in same time if new freq range is very much different from current freq range. For example, if current freq range is 480000-960000, then we want to set this range to 1120000-2240000, we would fail in the past because new_policy->min > policy->max. As long as the cpufreq range is valid, we has no reason to reject the user. So correct the check.

Does this patch depend on the other patch you sent where you are trying to update both min/max in the same call to cpufreq_set_policy()? If so, they should have been part of the same series in proper order, as you have sent them as separate patches.

Now, if we don't consider your first patch at all, then this patch is obviously wrong. We need to take care of both the checks.

Signature · 1 line
viresh
author
#2 lore raw

hi, Viresh
thanks for your quick reply! :)

Quoted 33 lines · Viresh Kumar
Quoted 32 lines · Pan Xinhui

From: Pan Xinhui <[email protected]>

This check was originally added by commit 9c9a43ed2734 ("[CPUFREQ] return error when failing to set minfreq").It attempt to return an error on obviously incorrect limits when we echo xxx >.../scaling_max,min_freq Actually we just need check if new_policy->min > new_policy->max. Because at least one of max/min is copied from cpufreq_get_policy().

For example, when we echo xxx > .../scaling_min_freq, new_policy is copied from policy in cpufreq_get_policy. new_policy->max is same with policy->max. new_policy->min is set to a new value.

Let me explain it in deduction method, first statment in if ():
new_policy->min > policy->max
policy->max == new_policy->max
==> new_policy->min > new_policy->max

second statment in if():
new_policy->max < policy->min
policy->max < policy->min
==>new_policy->min > new_policy->max (induction method)

So we have proved that we only need check if new_policy->min > new_policy->max.

After apply this patch, we can also modify ->min and ->max in same time if new freq range is very much different from current freq range. For example, if current freq range is 480000-960000, then we want to set this range to 1120000-2240000, we would fail in the past because new_policy->min > policy->max. As long as the cpufreq range is valid, we has no reason to reject the user. So correct the check.

Quoted 7 lines
Quoted 1 line

Does this patch depend on the other patch you sent where you are trying to update both min/max in the same call to cpufreq_set_policy()? If so, they should have been part of the same series in proper order, as you have sent them as separate patches.

Thanks for pointing out my mistakes. I will send them in a same series with proper order. Sorry for that.

Quoted 3 lines

Now, if we don't consider your first patch at all, then this patch is obviously wrong. We need to take care of both the checks.

Agree, we need take care of every checks. BUT, As We have proved, it's equal to check if (new_policy->min > new_policy->max). I don't why it's wrong. with/without this patch, echo 0 > .../scaling_min_freq has no error. min freq is just set to the limit min freq. I prefer to treat it as a feature. :) So I don't add new_policy->min < policy->cpuinfo.min_freq || new_policy->max > policy->cpuinfo.max_freq.

We have ->verify callback, no need to worry about that an out-of-limit cpufreq will harm kernel. This check is just to tell userspace that *the cpufreq you are trying to set is wrong, pls double check.*

thanks
xinhui

maintainer Acked-by on v1 1/1
#3 lore raw
In reply to Pan Xinhui
Quoted 42 lines · Pan Xinhui

From: Pan Xinhui <[email protected]>

This check was originally added by commit 9c9a43ed2734 ("[CPUFREQ] return error when failing to set minfreq").It attempt to return an error on obviously incorrect limits when we echo xxx >.../scaling_max,min_freq Actually we just need check if new_policy->min > new_policy->max. Because at least one of max/min is copied from cpufreq_get_policy().

For example, when we echo xxx > .../scaling_min_freq, new_policy is copied from policy in cpufreq_get_policy. new_policy->max is same with policy->max. new_policy->min is set to a new value.

Let me explain it in deduction method, first statment in if ():
new_policy->min > policy->max
policy->max == new_policy->max
==> new_policy->min > new_policy->max

second statment in if():
new_policy->max < policy->min
policy->max < policy->min
==>new_policy->min > new_policy->max (induction method)

So we have proved that we only need check if new_policy->min > new_policy->max.

After apply this patch, we can also modify ->min and ->max in same time if new freq range is very much different from current freq range. For example, if current freq range is 480000-960000, then we want to set this range to 1120000-2240000, we would fail in the past because new_policy->min > policy->max. As long as the cpufreq range is valid, we has no reason to reject the user. So correct the check.

---
 drivers/cpufreq/cpufreq.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/cpufreq/cpufreq.c +0 -0
index 6424e05..8772346 100644

drivers/cpufreq/cpufreq.c static int cpufreq_set_policy(struct cpufreq_policy *policy, · line 2280

Quoted 6 lines
drivers/cpufreq/cpufreq.c +1 -1
@@ -2276,7 +2276,7 @@ static int cpufreq_set_policy(struct cpufreq_policy *policy,
 
 	memcpy(&new_policy->cpuinfo, &policy->cpuinfo, sizeof(policy->cpuinfo));
 
-	if (new_policy->min > policy->max || new_policy->max < policy->min)
+	if (new_policy->min > new_policy->max)
 		return -EINVAL;
Signature · 1 line
viresh
#4 lore raw
In reply to Pan Xinhui
Quoted 42 lines · Pan Xinhui

From: Pan Xinhui <[email protected]>

This check was originally added by commit 9c9a43ed2734 ("[CPUFREQ] return error when failing to set minfreq").It attempt to return an error on obviously incorrect limits when we echo xxx >.../scaling_max,min_freq Actually we just need check if new_policy->min > new_policy->max. Because at least one of max/min is copied from cpufreq_get_policy().

For example, when we echo xxx > .../scaling_min_freq, new_policy is copied from policy in cpufreq_get_policy. new_policy->max is same with policy->max. new_policy->min is set to a new value.

Let me explain it in deduction method, first statment in if ():
new_policy->min > policy->max
policy->max == new_policy->max
==> new_policy->min > new_policy->max

second statment in if():
new_policy->max < policy->min
policy->max < policy->min
==>new_policy->min > new_policy->max (induction method)

So we have proved that we only need check if new_policy->min > new_policy->max.

After apply this patch, we can also modify ->min and ->max in same time if new freq range is very much different from current freq range. For example, if current freq range is 480000-960000, then we want to set this range to 1120000-2240000, we would fail in the past because new_policy->min > policy->max. As long as the cpufreq range is valid, we has no reason to reject the user. So correct the check.

---
 drivers/cpufreq/cpufreq.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/cpufreq/cpufreq.c +0 -0
index 6424e05..8772346 100644

drivers/cpufreq/cpufreq.c static int cpufreq_set_policy(struct cpufreq_policy *policy, · line 2279

Quoted 4 lines
drivers/cpufreq/cpufreq.c +0 -1
@@ -2276,7 +2276,7 @@ static int cpufreq_set_policy(struct cpufreq_policy *policy,
 
 	memcpy(&new_policy->cpuinfo, &policy->cpuinfo, sizeof(policy->cpuinfo));
 
-	if (new_policy->min > policy->max || new_policy->max < policy->min)

Please add a comment here mentioning the fact that this *relies* on new_policy being a copy of policy with one field updated.

Quoted 5 lines
drivers/cpufreq/cpufreq.c +1 -0
+	if (new_policy->min > new_policy->max)
 		return -EINVAL;
 
 	/* verify the cpu speed can be set within this limit */
Signature · 2 lines
I speak only for myself.
Rafael J. Wysocki, Intel Open Source Technology Center.
author
#5 lore raw

PATCH v2 1/1 cpufreq: Correct a freq check in cpufreq_set_policy

In reply to Pan Xinhui

From: Pan Xinhui <[email protected]>

This check was originally added by commit 9c9a43ed2734 ("[CPUFREQ] return error when failing to set minfreq").It attempt to return an error on obviously incorrect limits when we echo xxx >.../scaling_max,min_freq Actually we just need check if new_policy->min > new_policy->max. Because at least one of max/min is copied from cpufreq_get_policy().

For example, when we echo xxx > .../scaling_min_freq, new_policy is copied from policy in cpufreq_get_policy. new_policy->max is same with policy->max. new_policy->min is set to a new value.

Let me explain it in deduction method, first statement in if ():
new_policy->min > policy->max
policy->max == new_policy->max
==> new_policy->min > new_policy->max

second statement in if():
new_policy->max < policy->min
policy->max < policy->min
==>new_policy->min > new_policy->max (induction method)

So we have proved that we only need check if new_policy->min > new_policy->max.

After apply this patch, we can also modify ->min and ->max at same time if new freq range is very much different from current freq range. For example, if current freq range is 480000-960000, then we want to set this range to 1120000-2240000, we would fail in the past because new_policy->min > policy->max. As long as the cpufreq range is valid, we has no reason to reject the user. So correct the check to avoid such case.

---
Change from V1:
just update comments.

---
 drivers/cpufreq/cpufreq.c | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)
drivers/cpufreq/cpufreq.c +5 -1
index 26063af..a32f50b 100644
@@ -2245,7 +2245,11 @@ static int cpufreq_set_policy(struct cpufreq_policy *policy,
 
 	memcpy(&new_policy->cpuinfo, &policy->cpuinfo, sizeof(policy->cpuinfo));
 
-	if (new_policy->min > policy->max || new_policy->max < policy->min)
+	/*
+	* This check works well when we store new min/max freq attributes,
+	* because new_policy is a copy of policy with one field updated.
+	*/
+	if (new_policy->min > new_policy->max)
 		return -EINVAL;
 
 	/* verify the cpu speed can be set within this limit */
Signature · 1 line
1.9.1
#6 lore raw
Quoted 33 lines · Pan Xinhui

From: Pan Xinhui <[email protected]>

This check was originally added by commit 9c9a43ed2734 ("[CPUFREQ] return error when failing to set minfreq").It attempt to return an error on obviously incorrect limits when we echo xxx >.../scaling_max,min_freq Actually we just need check if new_policy->min > new_policy->max. Because at least one of max/min is copied from cpufreq_get_policy().

For example, when we echo xxx > .../scaling_min_freq, new_policy is copied from policy in cpufreq_get_policy. new_policy->max is same with policy->max. new_policy->min is set to a new value.

Let me explain it in deduction method, first statement in if ():
new_policy->min > policy->max
policy->max == new_policy->max
==> new_policy->min > new_policy->max

second statement in if():
new_policy->max < policy->min
policy->max < policy->min
==>new_policy->min > new_policy->max (induction method)

So we have proved that we only need check if new_policy->min > new_policy->max.

After apply this patch, we can also modify ->min and ->max at same time if new freq range is very much different from current freq range. For example, if current freq range is 480000-960000, then we want to set this range to 1120000-2240000, we would fail in the past because new_policy->min > policy->max. As long as the cpufreq range is valid, we has no reason to reject the user. So correct the check to avoid such case.

Quoted 1 line

Queued up for 4.3, thanks!

Signature · 2 lines
I speak only for myself.
Rafael J. Wysocki, Intel Open Source Technology Center.