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@vger.kernel.org Signed-off-by: Hongyu Jin --- 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