mm/vmstat.c | 37 ++++++++++++++++++++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-)
The refresh workqueue is re-queued after last timer is triggered, so when
the refresh interval is set, it doesn't take effect immediately.
It leads a problem like this: if current interval is 8640000s (100 days),
and we want changing it to 1s, the new interval can't take effect until
100 days later.
So call mod_delayed_work() after updating interval to make the new value
take effect immediately.
Signed-off-by: Yang Yingliang <yangyingliang@huawei.com>
---
mm/vmstat.c | 37 ++++++++++++++++++++++++++++++++++++-
1 file changed, 36 insertions(+), 1 deletion(-)
diff --git a/mm/vmstat.c b/mm/vmstat.c
index 2370c6fb1fcd..7b4a9c30cc80 100644
--- a/mm/vmstat.c
+++ b/mm/vmstat.c
@@ -1968,6 +1968,9 @@ static int sysctl_stat_interval __read_mostly = HZ;
static int vmstat_late_init_done;
#ifdef CONFIG_PROC_FS
+static int sysctl_stat_interval_handler(const struct ctl_table *table, int write,
+ void *buffer, size_t *length, loff_t *ppos);
+
static void refresh_vm_stats(struct work_struct *work)
{
refresh_cpu_vm_stats(true);
@@ -2151,6 +2154,38 @@ static void vmstat_shepherd(struct work_struct *w)
round_jiffies_relative(sysctl_stat_interval));
}
+#ifdef CONFIG_PROC_FS
+static int sysctl_stat_interval_handler(const struct ctl_table *table, int write,
+ void *buffer, size_t *length, loff_t *ppos)
+{
+ int cpu;
+ int ret = proc_dointvec_jiffies(table, write, buffer, length, ppos);
+
+ if (ret || !write)
+ return ret;
+
+ cpus_read_lock();
+ for_each_online_cpu(cpu) {
+ struct delayed_work *dw = &per_cpu(vmstat_work, cpu);
+
+ scoped_guard(rcu) {
+ if (cpu_is_isolated(cpu))
+ continue;
+
+ if (delayed_work_pending(dw))
+ mod_delayed_work(system_wq, dw, round_jiffies_relative(sysctl_stat_interval));
+ }
+
+ cond_resched();
+ }
+ cpus_read_unlock();
+
+ mod_delayed_work(system_wq, &shepherd, round_jiffies_relative(sysctl_stat_interval));
+
+ return ret;
+}
+#endif
+
static void __init start_shepherd_timer(void)
{
int cpu;
@@ -2237,7 +2272,7 @@ static const struct ctl_table vmstat_table[] = {
.data = &sysctl_stat_interval,
.maxlen = sizeof(sysctl_stat_interval),
.mode = 0644,
- .proc_handler = proc_dointvec_jiffies,
+ .proc_handler = sysctl_stat_interval_handler,
},
{
.procname = "stat_refresh",
--
2.25.1
On 3/26/26 08:55, Yang Yingliang wrote: > The refresh workqueue is re-queued after last timer is triggered, so when > the refresh interval is set, it doesn't take effect immediately. > > It leads a problem like this: if current interval is 8640000s (100 days), > and we want changing it to 1s, the new interval can't take effect until > 100 days later. Well, yes. But, the default is set to HZ. If you set the default to 100days you are probably doing something very wrong in the first place? What's the use case that warrants the complexity? Even when set to, say, 30s, waiting 30s is not that bad. Would we maybe just want to set an upper limit to which we clamp? That would be a lot simpler. -- Cheers, David
© 2016 - 2026 Red Hat, Inc.