Skip to content

Commit bfd7b2d

Browse files
committed
Merge tag 'devfreq-next-for-6.8' of git://git.kernel.org/pub/scm/linux/kernel/git/chanwoo/linux into pm-devfreq
Merge devfreq updates for v6.8 from Chanwoo Choi: "1. Fix buffer overflow of trans_stat_show sysfs node on devfreq core - Fix buffer overflow of trans_stat_show sysfs node to replace sprintf with scnprintf and then replace it with sysfs_emit according to the syfs guide. 2. Fix the timer list corruption when frequent switching of governor by synchronizing the devfreq_moniotr_start and _stop function." * tag 'devfreq-next-for-6.8' of git://git.kernel.org/pub/scm/linux/kernel/git/chanwoo/linux: PM / devfreq: Synchronize devfreq_monitor_[start/stop] PM / devfreq: Convert to use sysfs_emit_at() API PM / devfreq: Fix buffer overflow in trans_stat_show
2 parents ceb6a6f + aed5ed5 commit bfd7b2d

File tree

2 files changed

+62
-21
lines changed

2 files changed

+62
-21
lines changed

Documentation/ABI/testing/sysfs-class-devfreq

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,9 @@ Description:
5252

5353
echo 0 > /sys/class/devfreq/.../trans_stat
5454

55+
If the transition table is bigger than PAGE_SIZE, reading
56+
this will return an -EFBIG error.
57+
5558
What: /sys/class/devfreq/.../available_frequencies
5659
Date: October 2012
5760
Contact: Nishanth Menon <nm@ti.com>

drivers/devfreq/devfreq.c

Lines changed: 59 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -461,10 +461,14 @@ static void devfreq_monitor(struct work_struct *work)
461461
if (err)
462462
dev_err(&devfreq->dev, "dvfs failed with (%d) error\n", err);
463463

464+
if (devfreq->stop_polling)
465+
goto out;
466+
464467
queue_delayed_work(devfreq_wq, &devfreq->work,
465468
msecs_to_jiffies(devfreq->profile->polling_ms));
466-
mutex_unlock(&devfreq->lock);
467469

470+
out:
471+
mutex_unlock(&devfreq->lock);
468472
trace_devfreq_monitor(devfreq);
469473
}
470474

@@ -483,6 +487,10 @@ void devfreq_monitor_start(struct devfreq *devfreq)
483487
if (IS_SUPPORTED_FLAG(devfreq->governor->flags, IRQ_DRIVEN))
484488
return;
485489

490+
mutex_lock(&devfreq->lock);
491+
if (delayed_work_pending(&devfreq->work))
492+
goto out;
493+
486494
switch (devfreq->profile->timer) {
487495
case DEVFREQ_TIMER_DEFERRABLE:
488496
INIT_DEFERRABLE_WORK(&devfreq->work, devfreq_monitor);
@@ -491,12 +499,16 @@ void devfreq_monitor_start(struct devfreq *devfreq)
491499
INIT_DELAYED_WORK(&devfreq->work, devfreq_monitor);
492500
break;
493501
default:
494-
return;
502+
goto out;
495503
}
496504

497505
if (devfreq->profile->polling_ms)
498506
queue_delayed_work(devfreq_wq, &devfreq->work,
499507
msecs_to_jiffies(devfreq->profile->polling_ms));
508+
509+
out:
510+
devfreq->stop_polling = false;
511+
mutex_unlock(&devfreq->lock);
500512
}
501513
EXPORT_SYMBOL(devfreq_monitor_start);
502514

@@ -513,6 +525,14 @@ void devfreq_monitor_stop(struct devfreq *devfreq)
513525
if (IS_SUPPORTED_FLAG(devfreq->governor->flags, IRQ_DRIVEN))
514526
return;
515527

528+
mutex_lock(&devfreq->lock);
529+
if (devfreq->stop_polling) {
530+
mutex_unlock(&devfreq->lock);
531+
return;
532+
}
533+
534+
devfreq->stop_polling = true;
535+
mutex_unlock(&devfreq->lock);
516536
cancel_delayed_work_sync(&devfreq->work);
517537
}
518538
EXPORT_SYMBOL(devfreq_monitor_stop);
@@ -1688,7 +1708,7 @@ static ssize_t trans_stat_show(struct device *dev,
16881708
struct device_attribute *attr, char *buf)
16891709
{
16901710
struct devfreq *df = to_devfreq(dev);
1691-
ssize_t len;
1711+
ssize_t len = 0;
16921712
int i, j;
16931713
unsigned int max_state;
16941714

@@ -1697,7 +1717,7 @@ static ssize_t trans_stat_show(struct device *dev,
16971717
max_state = df->max_state;
16981718

16991719
if (max_state == 0)
1700-
return sprintf(buf, "Not Supported.\n");
1720+
return sysfs_emit(buf, "Not Supported.\n");
17011721

17021722
mutex_lock(&df->lock);
17031723
if (!df->stop_polling &&
@@ -1707,31 +1727,49 @@ static ssize_t trans_stat_show(struct device *dev,
17071727
}
17081728
mutex_unlock(&df->lock);
17091729

1710-
len = sprintf(buf, " From : To\n");
1711-
len += sprintf(buf + len, " :");
1712-
for (i = 0; i < max_state; i++)
1713-
len += sprintf(buf + len, "%10lu",
1714-
df->freq_table[i]);
1730+
len += sysfs_emit_at(buf, len, " From : To\n");
1731+
len += sysfs_emit_at(buf, len, " :");
1732+
for (i = 0; i < max_state; i++) {
1733+
if (len >= PAGE_SIZE - 1)
1734+
break;
1735+
len += sysfs_emit_at(buf, len, "%10lu",
1736+
df->freq_table[i]);
1737+
}
17151738

1716-
len += sprintf(buf + len, " time(ms)\n");
1739+
if (len >= PAGE_SIZE - 1)
1740+
return PAGE_SIZE - 1;
1741+
len += sysfs_emit_at(buf, len, " time(ms)\n");
17171742

17181743
for (i = 0; i < max_state; i++) {
1719-
if (df->freq_table[i] == df->previous_freq)
1720-
len += sprintf(buf + len, "*");
1744+
if (len >= PAGE_SIZE - 1)
1745+
break;
1746+
if (df->freq_table[2] == df->previous_freq)
1747+
len += sysfs_emit_at(buf, len, "*");
17211748
else
1722-
len += sprintf(buf + len, " ");
1723-
1724-
len += sprintf(buf + len, "%10lu:", df->freq_table[i]);
1725-
for (j = 0; j < max_state; j++)
1726-
len += sprintf(buf + len, "%10u",
1749+
len += sysfs_emit_at(buf, len, " ");
1750+
if (len >= PAGE_SIZE - 1)
1751+
break;
1752+
len += sysfs_emit_at(buf, len, "%10lu:", df->freq_table[i]);
1753+
for (j = 0; j < max_state; j++) {
1754+
if (len >= PAGE_SIZE - 1)
1755+
break;
1756+
len += sysfs_emit_at(buf, len, "%10u",
17271757
df->stats.trans_table[(i * max_state) + j]);
1758+
}
1759+
if (len >= PAGE_SIZE - 1)
1760+
break;
1761+
len += sysfs_emit_at(buf, len, "%10llu\n", (u64)
1762+
jiffies64_to_msecs(df->stats.time_in_state[i]));
1763+
}
17281764

1729-
len += sprintf(buf + len, "%10llu\n", (u64)
1730-
jiffies64_to_msecs(df->stats.time_in_state[i]));
1765+
if (len < PAGE_SIZE - 1)
1766+
len += sysfs_emit_at(buf, len, "Total transition : %u\n",
1767+
df->stats.total_trans);
1768+
if (len >= PAGE_SIZE - 1) {
1769+
pr_warn_once("devfreq transition table exceeds PAGE_SIZE. Disabling\n");
1770+
return -EFBIG;
17311771
}
17321772

1733-
len += sprintf(buf + len, "Total transition : %u\n",
1734-
df->stats.total_trans);
17351773
return len;
17361774
}
17371775

0 commit comments

Comments
 (0)