Unverified Commit 543467d6 authored by Laveesh Bansal's avatar Laveesh Bansal Committed by Christian Brauner
Browse files

writeback: fix 100% CPU usage when dirtytime_expire_interval is 0

When vm.dirtytime_expire_seconds is set to 0, wakeup_dirtytime_writeback()
schedules delayed work with a delay of 0, causing immediate execution.
The function then reschedules itself with 0 delay again, creating an
infinite busy loop that causes 100% kworker CPU usage.

Fix by:
- Only scheduling delayed work in wakeup_dirtytime_writeback() when
  dirtytime_expire_interval is non-zero
- Cancelling the delayed work in dirtytime_interval_handler() when
  the interval is set to 0
- Adding a guard in start_dirtytime_writeback() for defensive coding

Tested by booting kernel in QEMU with virtme-ng:
- Before fix: kworker CPU spikes to ~73%
- After fix: CPU remains at normal levels
- Setting interval back to non-zero correctly resumes writeback

Fixes: a2f48706 ("fs: make sure the timestamps for lazytime inodes eventually get written")
Cc: stable@vger.kernel.org
Closes: https://bugzilla.kernel.org/show_bug.cgi?id=220227


Signed-off-by: default avatarLaveesh Bansal <laveeshb@laveeshbansal.com>
Link: https://patch.msgid.link/20260106145059.543282-2-laveeshb@laveeshbansal.com


Reviewed-by: default avatarJan Kara <jack@suse.cz>
Signed-off-by: default avatarChristian Brauner <brauner@kernel.org>
parent c644bce6
Loading
Loading
Loading
Loading
+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;