Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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

+67 -26
+3
Documentation/ABI/testing/sysfs-class-devfreq
··· 52 52 53 53 echo 0 > /sys/class/devfreq/.../trans_stat 54 54 55 + If the transition table is bigger than PAGE_SIZE, reading 56 + this will return an -EFBIG error. 57 + 55 58 What: /sys/class/devfreq/.../available_frequencies 56 59 Date: October 2012 57 60 Contact: Nishanth Menon <nm@ti.com>
+64 -26
drivers/devfreq/devfreq.c
··· 461 461 if (err) 462 462 dev_err(&devfreq->dev, "dvfs failed with (%d) error\n", err); 463 463 464 + if (devfreq->stop_polling) 465 + goto out; 466 + 464 467 queue_delayed_work(devfreq_wq, &devfreq->work, 465 468 msecs_to_jiffies(devfreq->profile->polling_ms)); 466 - mutex_unlock(&devfreq->lock); 467 469 470 + out: 471 + mutex_unlock(&devfreq->lock); 468 472 trace_devfreq_monitor(devfreq); 469 473 } 470 474 ··· 487 483 if (IS_SUPPORTED_FLAG(devfreq->governor->flags, IRQ_DRIVEN)) 488 484 return; 489 485 486 + mutex_lock(&devfreq->lock); 487 + if (delayed_work_pending(&devfreq->work)) 488 + goto out; 489 + 490 490 switch (devfreq->profile->timer) { 491 491 case DEVFREQ_TIMER_DEFERRABLE: 492 492 INIT_DEFERRABLE_WORK(&devfreq->work, devfreq_monitor); ··· 499 491 INIT_DELAYED_WORK(&devfreq->work, devfreq_monitor); 500 492 break; 501 493 default: 502 - return; 494 + goto out; 503 495 } 504 496 505 497 if (devfreq->profile->polling_ms) 506 498 queue_delayed_work(devfreq_wq, &devfreq->work, 507 499 msecs_to_jiffies(devfreq->profile->polling_ms)); 500 + 501 + out: 502 + devfreq->stop_polling = false; 503 + mutex_unlock(&devfreq->lock); 508 504 } 509 505 EXPORT_SYMBOL(devfreq_monitor_start); 510 506 ··· 525 513 if (IS_SUPPORTED_FLAG(devfreq->governor->flags, IRQ_DRIVEN)) 526 514 return; 527 515 516 + mutex_lock(&devfreq->lock); 517 + if (devfreq->stop_polling) { 518 + mutex_unlock(&devfreq->lock); 519 + return; 520 + } 521 + 522 + devfreq->stop_polling = true; 523 + mutex_unlock(&devfreq->lock); 528 524 cancel_delayed_work_sync(&devfreq->work); 529 525 } 530 526 EXPORT_SYMBOL(devfreq_monitor_stop); ··· 1708 1688 struct device_attribute *attr, char *buf) 1709 1689 { 1710 1690 struct devfreq *df = to_devfreq(dev); 1711 - ssize_t len; 1691 + ssize_t len = 0; 1712 1692 int i, j; 1713 1693 unsigned int max_state; 1714 1694 ··· 1717 1697 max_state = df->max_state; 1718 1698 1719 1699 if (max_state == 0) 1720 - return sprintf(buf, "Not Supported.\n"); 1700 + return sysfs_emit(buf, "Not Supported.\n"); 1721 1701 1722 1702 mutex_lock(&df->lock); 1723 1703 if (!df->stop_polling && ··· 1727 1707 } 1728 1708 mutex_unlock(&df->lock); 1729 1709 1730 - len = sprintf(buf, " From : To\n"); 1731 - len += sprintf(buf + len, " :"); 1732 - for (i = 0; i < max_state; i++) 1733 - len += sprintf(buf + len, "%10lu", 1734 - df->freq_table[i]); 1735 - 1736 - len += sprintf(buf + len, " time(ms)\n"); 1737 - 1710 + len += sysfs_emit_at(buf, len, " From : To\n"); 1711 + len += sysfs_emit_at(buf, len, " :"); 1738 1712 for (i = 0; i < max_state; i++) { 1739 - if (df->freq_table[i] == df->previous_freq) 1740 - len += sprintf(buf + len, "*"); 1741 - else 1742 - len += sprintf(buf + len, " "); 1743 - 1744 - len += sprintf(buf + len, "%10lu:", df->freq_table[i]); 1745 - for (j = 0; j < max_state; j++) 1746 - len += sprintf(buf + len, "%10u", 1747 - df->stats.trans_table[(i * max_state) + j]); 1748 - 1749 - len += sprintf(buf + len, "%10llu\n", (u64) 1750 - jiffies64_to_msecs(df->stats.time_in_state[i])); 1713 + if (len >= PAGE_SIZE - 1) 1714 + break; 1715 + len += sysfs_emit_at(buf, len, "%10lu", 1716 + df->freq_table[i]); 1751 1717 } 1752 1718 1753 - len += sprintf(buf + len, "Total transition : %u\n", 1754 - df->stats.total_trans); 1719 + if (len >= PAGE_SIZE - 1) 1720 + return PAGE_SIZE - 1; 1721 + len += sysfs_emit_at(buf, len, " time(ms)\n"); 1722 + 1723 + for (i = 0; i < max_state; i++) { 1724 + if (len >= PAGE_SIZE - 1) 1725 + break; 1726 + if (df->freq_table[2] == df->previous_freq) 1727 + len += sysfs_emit_at(buf, len, "*"); 1728 + else 1729 + len += sysfs_emit_at(buf, len, " "); 1730 + if (len >= PAGE_SIZE - 1) 1731 + break; 1732 + len += sysfs_emit_at(buf, len, "%10lu:", df->freq_table[i]); 1733 + for (j = 0; j < max_state; j++) { 1734 + if (len >= PAGE_SIZE - 1) 1735 + break; 1736 + len += sysfs_emit_at(buf, len, "%10u", 1737 + df->stats.trans_table[(i * max_state) + j]); 1738 + } 1739 + if (len >= PAGE_SIZE - 1) 1740 + break; 1741 + len += sysfs_emit_at(buf, len, "%10llu\n", (u64) 1742 + jiffies64_to_msecs(df->stats.time_in_state[i])); 1743 + } 1744 + 1745 + if (len < PAGE_SIZE - 1) 1746 + len += sysfs_emit_at(buf, len, "Total transition : %u\n", 1747 + df->stats.total_trans); 1748 + if (len >= PAGE_SIZE - 1) { 1749 + pr_warn_once("devfreq transition table exceeds PAGE_SIZE. Disabling\n"); 1750 + return -EFBIG; 1751 + } 1752 + 1755 1753 return len; 1756 1754 } 1757 1755