Unverified Commit e1668808 authored by Christian Brauner's avatar Christian Brauner
Browse files

Merge patch series "Fix vm.dirtytime_expire_seconds=0 causing 100% CPU"

Laveesh Bansal <laveeshb@laveeshbansal.com> says:

Setting vm.dirtytime_expire_seconds to 0 causes wakeup_dirtytime_writeback()
to reschedule itself with a delay of 0, creating an infinite busy loop that
spins kworker at 100% CPU.

This series:
- Patch 1: Fixes the bug by handling interval=0 as "disable writeback"
           (consistent with dirty_writeback_centisecs behavior)
- Patch 2: Documents that setting the value to 0 disables writeback

Tested by booting kernels in QEMU with virtme-ng:
- Buggy kernel: kworker CPU spikes to ~73% when interval set to 0
- Fixed kernel: CPU remains normal, writeback correctly disabled
- Re-enabling (0 -> non-zero): writeback resumes correctly

* patches from https://patch.msgid.link/20260106145059.543282-1-laveeshb@laveeshbansal.com:
  docs: clarify that dirtytime_expire_seconds=0 disables writeback
  writeback: fix 100% CPU usage when dirtytime_expire_interval is 0

Link: https://patch.msgid.link/20260106145059.543282-1-laveeshb@laveeshbansal.com


Signed-off-by: default avatarChristian Brauner <brauner@kernel.org>
parents c644bce6 30ef9a20
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -231,6 +231,8 @@ eventually gets pushed out to disk. This tunable is used to define when dirty
inode is old enough to be eligible for writeback by the kernel flusher threads.
And, it is also used as the interval to wakeup dirtytime_writeback thread.

Setting this to zero disables periodic dirtytime writeback.


dirty_writeback_centisecs
=========================
+10 −4
Original line number Diff line number Diff line
@@ -2492,6 +2492,7 @@ static void wakeup_dirtytime_writeback(struct work_struct *w)
				wb_wakeup(wb);
	}
	rcu_read_unlock();
	if (dirtytime_expire_interval)
		schedule_delayed_work(&dirtytime_work, dirtytime_expire_interval * HZ);
}

@@ -2501,8 +2502,12 @@ static int dirtytime_interval_handler(const struct ctl_table *table, int write,
	int ret;

	ret = proc_dointvec_minmax(table, write, buffer, lenp, ppos);
	if (ret == 0 && write)
	if (ret == 0 && write) {
		if (dirtytime_expire_interval)
			mod_delayed_work(system_percpu_wq, &dirtytime_work, 0);
		else
			cancel_delayed_work_sync(&dirtytime_work);
	}
	return ret;
}

@@ -2519,6 +2524,7 @@ static const struct ctl_table vm_fs_writeback_table[] = {

static int __init start_dirtytime_writeback(void)
{
	if (dirtytime_expire_interval)
		schedule_delayed_work(&dirtytime_work, dirtytime_expire_interval * HZ);
	register_sysctl_init("vm", vm_fs_writeback_table);
	return 0;