[PATCH] writeback: don't requeue inode already on b_dirty

From: Hongyu Jin

Date: Wed Oct 21 2026 - 03:37:19 EST


Since commit 846a3351ddfe ("writeback: Avoid skipping inode writeback"),
writeback_single_inode() calls redirty_tail_locked() for any inode left
dirty. When that inode is already on b_dirty and older than the newest
inode there, redirty_tail_locked() moves it to the head and stamps
dirtied_when with jiffies.

Append to an f2fs file so the i_size update puts it on DIRTY_META, and
dirty a newer inode before each checkpoint. Every 17s the checkpoint
syncs that file and redirty_tail_locked() stamps a new dirtied_when.
17s is shorter than the default 30s dirty_expire_interval, so kupdate
never expires it. Dirty pages pile up until writeback or fsync().

An inode that was I_DIRTY on entry is already on b_dirty, so only
redirty it if it was not. The b_dirty_time case fixed by commit
846a3351ddfe ("writeback: Avoid skipping inode writeback") enters without
I_DIRTY and is still handled.

Fixes: 846a3351ddfe ("writeback: Avoid skipping inode writeback")
Cc: stable@xxxxxxxxxxxxxxx
Signed-off-by: Hongyu Jin <hongyu.jin@xxxxxxxxxx>
---
fs/fs-writeback.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c
index 58a6403780aa..fb33a63710ec 100644
--- a/fs/fs-writeback.c
+++ b/fs/fs-writeback.c
@@ -1898,6 +1898,7 @@ static int writeback_single_inode(struct inode *inode,
struct writeback_control *wbc)
{
struct bdi_writeback *wb;
+ bool was_dirty;
int ret = 0;

spin_lock(&inode->i_lock);
@@ -1932,6 +1933,7 @@ static int writeback_single_inode(struct inode *inode,
!(inode_state_read(inode) & I_METADATA_WRITEBACK))
goto out;
}
+ was_dirty = inode_state_read(inode) & I_DIRTY;
inode_state_set(inode, I_SYNC);
wbc_attach_and_unlock_inode(wbc, inode);

@@ -1954,7 +1956,7 @@ static int writeback_single_inode(struct inode *inode,
if (!(inode_state_read(inode) & I_DIRTY_ALL))
inode_cgwb_move_to_attached(inode, wb);
else if (!(inode_state_read(inode) & I_SYNC_QUEUED)) {
- if ((inode_state_read(inode) & I_DIRTY))
+ if ((inode_state_read(inode) & I_DIRTY) && !was_dirty)
redirty_tail_locked(inode, wb);
else if (inode_state_read(inode) & I_DIRTY_TIME) {
inode->dirtied_when = jiffies;
--
2.53.0