Linux filesystem development
 help / color / mirror / Atom feed
* [PATCH 0/2] writeback: fix timestamp and dirty-state handling in wb switches
@ 2026-10-16 11:52 Julian Sun
  2026-10-16 11:52 ` [PATCH 1/2] writeback: reset dirtied_when when switching wbs Julian Sun
  2026-10-16 11:52 ` [PATCH 2/2] writeback: clear old wb dirty state after inode switches Julian Sun
  0 siblings, 2 replies; 5+ messages in thread
From: Julian Sun @ 2026-10-16 11:52 UTC (permalink / raw)
  To: linux-fsdevel; +Cc: viro, brauner, jack, tj, akpm, roman.gushchin, dennis

Hi,

This series fixes two issues when moving inodes between writeback
structures:

1. Update dirtied_when rather than dirtied_time_when when inserting an
   inode at the newest end of the target dirty list. This maintains the
   list ordering without resetting the lazytime expiration timestamp.
2. Clear the source wb's dirty-I/O state and bandwidth contribution when
   inode migration leaves its dirty-I/O lists empty.

Julian Sun (2):
  writeback: reset dirtied_when when switching wbs
  writeback: clear old wb dirty state after inode switches

 fs/fs-writeback.c  | 7 ++++---
 include/linux/fs.h | 4 +++-
 2 files changed, 7 insertions(+), 4 deletions(-)


base-commit: 6af5ad50442eacebf18174e487efbd8c192e73e7
-- 
2.39.5

^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH 1/2] writeback: reset dirtied_when when switching wbs
  2026-10-16 11:52 [PATCH 0/2] writeback: fix timestamp and dirty-state handling in wb switches Julian Sun
@ 2026-10-16 11:52 ` Julian Sun
  2026-10-16 21:55   ` Tejun Heo
  2026-10-16 11:52 ` [PATCH 2/2] writeback: clear old wb dirty state after inode switches Julian Sun
  1 sibling, 1 reply; 5+ messages in thread
From: Julian Sun @ 2026-10-16 11:52 UTC (permalink / raw)
  To: linux-fsdevel; +Cc: viro, brauner, jack, tj, akpm, roman.gushchin, dennis

When switching a dirty inode to another wb, inode_do_switch_wbs() puts
it at the newest end of the target b_dirty list instead of searching
for its sorted position. This requires updating dirtied_when, which
move_expired_inodes() uses to decide where to stop scanning.

However, the switch updates dirtied_time_when instead. This leaves
b_dirty out of order and can make the scan stop before reaching older
inodes. It also resets the lazytime expiration timestamp, potentially
delaying timestamp writeback.

Update dirtied_when instead, preserving both the constant-time insertion
and the lazytime expiration timestamp. Correct the field name in the
comment and document the distinction between the two inode timestamps.

Fixes: 9a6ebbdbd412 ("writeback: Avoid excessively long inode switching times")
Cc: stable@vger.kernel.org
Assisted-by: LLM
Signed-off-by: Julian Sun <sunjunchao@bytedance.com>
---
 fs/fs-writeback.c  | 6 +++---
 include/linux/fs.h | 4 +++-
 2 files changed, 6 insertions(+), 4 deletions(-)

diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c
index e744f9f9d43f..6984f6c10a86 100644
--- a/fs/fs-writeback.c
+++ b/fs/fs-writeback.c
@@ -468,12 +468,12 @@ static bool inode_do_switch_wbs(struct inode *inode,
 		if (inode_state_read(inode) & I_DIRTY_ALL) {
 			/*
 			 * We need to keep b_dirty list sorted by
-			 * dirtied_time_when. However properly sorting the
+			 * dirtied_when. However properly sorting the
 			 * inode in the list gets too expensive when switching
 			 * many inodes. So just attach inode at the end of the
-			 * dirty list and clobber the dirtied_time_when.
+			 * dirty list and clobber the dirtied_when.
 			 */
-			inode->dirtied_time_when = jiffies;
+			inode->dirtied_when = jiffies;
 			inode_io_list_move_locked(inode, new_wb,
 						  &new_wb->b_dirty);
 		} else {
diff --git a/include/linux/fs.h b/include/linux/fs.h
index f9d1e05e8ae6..c5dd44314170 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -815,7 +815,9 @@ struct inode {
 	/* 32-bit hole */
 	struct rw_semaphore	i_rwsem;
 
-	unsigned long		dirtied_when;	/* jiffies of first dirtying */
+	/* Timestamp for writeback list ordering and age checks (jiffies). */
+	unsigned long		dirtied_when;
+	/* Start time for deciding when lazytime updates need writeback (jiffies). */
 	unsigned long		dirtied_time_when;
 
 	struct hlist_node	i_hash;
-- 
2.39.5


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PATCH 2/2] writeback: clear old wb dirty state after inode switches
  2026-10-16 11:52 [PATCH 0/2] writeback: fix timestamp and dirty-state handling in wb switches Julian Sun
  2026-10-16 11:52 ` [PATCH 1/2] writeback: reset dirtied_when when switching wbs Julian Sun
@ 2026-10-16 11:52 ` Julian Sun
  2026-10-16 21:55   ` Tejun Heo
  1 sibling, 1 reply; 5+ messages in thread
From: Julian Sun @ 2026-10-16 11:52 UTC (permalink / raw)
  To: linux-fsdevel; +Cc: viro, brauner, jack, tj, akpm, roman.gushchin, dennis

Switching an inode to another wb updates the target wb's dirty-I/O state,
but no longer checks whether the source wb's dirty-I/O lists became empty.
The check was lost when inode_io_list_del_locked(inode, old_wb) was
removed to support tracking clean attached inodes.

If the last dirty inode is moved, WB_has_dirty_io remains set on the old
wb and its bandwidth contribution remains in bdi->tot_write_bandwidth.
This can keep an empty wb scheduled for periodic writeback and overstate
the total bandwidth used to distribute writeback work.

Call wb_io_lists_depopulated() on the old wb after the batch of inode
switches, while its list_lock is still held. This clears the flag and
removes the bandwidth contribution if its dirty-I/O lists are empty.

Fixes: f3b6a6df38aa ("writeback, cgroup: keep list of inodes attached to bdi_writeback")
Cc: stable@vger.kernel.org
Assisted-by: LLM
Signed-off-by: Julian Sun <sunjunchao@bytedance.com>
---
 fs/fs-writeback.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c
index 6984f6c10a86..04fca06bd520 100644
--- a/fs/fs-writeback.c
+++ b/fs/fs-writeback.c
@@ -566,6 +566,7 @@ static void process_inode_switch_wbs(struct bdi_writeback *new_wb,
 		}
 	}
 
+	wb_io_lists_depopulated(old_wb);
 	spin_unlock(&new_wb->list_lock);
 	spin_unlock(&old_wb->list_lock);
 
-- 
2.39.5


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* Re: [PATCH 1/2] writeback: reset dirtied_when when switching wbs
  2026-10-16 11:52 ` [PATCH 1/2] writeback: reset dirtied_when when switching wbs Julian Sun
@ 2026-10-16 21:55   ` Tejun Heo
  0 siblings, 0 replies; 5+ messages in thread
From: Tejun Heo @ 2026-10-16 21:55 UTC (permalink / raw)
  To: Julian Sun
  Cc: linux-fsdevel, viro, brauner, jack, akpm, roman.gushchin, dennis

On Fri, Oct 16, 2026 at 07:52:29PM +0800, Julian Sun wrote:
> When switching a dirty inode to another wb, inode_do_switch_wbs() puts
> it at the newest end of the target b_dirty list instead of searching
> for its sorted position. This requires updating dirtied_when, which
> move_expired_inodes() uses to decide where to stop scanning.
>
> However, the switch updates dirtied_time_when instead. This leaves
> b_dirty out of order and can make the scan stop before reaching older
> inodes. It also resets the lazytime expiration timestamp, potentially
> delaying timestamp writeback.
>
> Update dirtied_when instead, preserving both the constant-time insertion
> and the lazytime expiration timestamp. Correct the field name in the
> comment and document the distinction between the two inode timestamps.
>
> Fixes: 9a6ebbdbd412 ("writeback: Avoid excessively long inode switching times")
> Cc: stable@vger.kernel.org
> Assisted-by: LLM
> Signed-off-by: Julian Sun <sunjunchao@bytedance.com>

Acked-by: Tejun Heo <tj@kernel.org>

Thanks.

-- 
tejun

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH 2/2] writeback: clear old wb dirty state after inode switches
  2026-10-16 11:52 ` [PATCH 2/2] writeback: clear old wb dirty state after inode switches Julian Sun
@ 2026-10-16 21:55   ` Tejun Heo
  0 siblings, 0 replies; 5+ messages in thread
From: Tejun Heo @ 2026-10-16 21:55 UTC (permalink / raw)
  To: Julian Sun
  Cc: linux-fsdevel, viro, brauner, jack, akpm, roman.gushchin, dennis

Hello, Julian.

On Fri, Oct 16, 2026 at 07:52:30PM +0800, Julian Sun wrote:
> Call wb_io_lists_depopulated() on the old wb after the batch of inode
> switches, while its list_lock is still held. This clears the flag and
> removes the bandwidth contribution if its dirty-I/O lists are empty.

Liz posted the same fix as part of her series:

  https://lore.kernel.org/all/20261015-wb-dying-cgwb-flush-v7-1-9278d9ebaf5d@honeycomb.io/

Thanks.

-- 
tejun

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2026-10-16 21:55 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-10-16 11:52 [PATCH 0/2] writeback: fix timestamp and dirty-state handling in wb switches Julian Sun
2026-10-16 11:52 ` [PATCH 1/2] writeback: reset dirtied_when when switching wbs Julian Sun
2026-10-16 21:55   ` Tejun Heo
2026-10-16 11:52 ` [PATCH 2/2] writeback: clear old wb dirty state after inode switches Julian Sun
2026-10-16 21:55   ` Tejun Heo

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox