]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
writeback: Wake up waiting tasks when finishing the writeback of a chunk.
authorJulian Sun <sunjunchao@bytedance.com>
Tue, 30 Sep 2025 08:53:15 +0000 (16:53 +0800)
committerChristian Brauner <brauner@kernel.org>
Mon, 20 Oct 2025 18:22:39 +0000 (20:22 +0200)
Writing back a large number of pages can take a lots of time.
This issue is exacerbated when the underlying device is slow or
subject to block layer rate limiting, which in turn triggers
unexpected hung task warnings.

We can trigger a wake-up once a chunk has been written back and the
waiting time for writeback exceeds half of
sysctl_hung_task_timeout_secs.
This action allows the hung task detector to be aware of the writeback
progress, thereby eliminating these unexpected hung task warnings.

This patch has passed the xfstests 'check -g quick' test based on ext4,
with no additional failures introduced.

Signed-off-by: Julian Sun <sunjunchao@bytedance.com>
Reviewed-by: Jan Kara <jack@suse.cz>
Suggested-by: Peter Zijlstra <peterz@infradead.org>
Signed-off-by: Christian Brauner <brauner@kernel.org>
fs/fs-writeback.c
include/linux/backing-dev-defs.h

index 2b35e80037feed4c711d55199a4e73eb0fc3ff26..61a980a06ceeb302bb8ca0960334913defc2f383 100644 (file)
@@ -14,6 +14,7 @@
  *             Additions for address_space-based writeback
  */
 
+#include <linux/sched/sysctl.h>
 #include <linux/kernel.h>
 #include <linux/export.h>
 #include <linux/spinlock.h>
@@ -213,7 +214,8 @@ static void wb_queue_work(struct bdi_writeback *wb,
 void wb_wait_for_completion(struct wb_completion *done)
 {
        atomic_dec(&done->cnt);         /* put down the initial count */
-       wait_event(*done->waitq, !atomic_read(&done->cnt));
+       wait_event(*done->waitq,
+                  ({ done->progress_stamp = jiffies; !atomic_read(&done->cnt); }));
 }
 
 #ifdef CONFIG_CGROUP_WRITEBACK
@@ -2014,6 +2016,12 @@ static long writeback_sb_inodes(struct super_block *sb,
                 */
                __writeback_single_inode(inode, &wbc);
 
+               /* Report progress to inform the hung task detector of the progress. */
+               if (work->done && work->done->progress_stamp &&
+                  (jiffies - work->done->progress_stamp) > HZ *
+                  sysctl_hung_task_timeout_secs / 2)
+                       wake_up_all(work->done->waitq);
+
                wbc_detach_inode(&wbc);
                work->nr_pages -= write_chunk - wbc.nr_to_write;
                wrote = write_chunk - wbc.nr_to_write - wbc.pages_skipped;
index c5c9d89c73edcce2b510a201e64b607fe083b136..c8aa749790b14ecfa60f5b6bf4ea39c630c56f77 100644 (file)
@@ -63,6 +63,7 @@ enum wb_reason {
 struct wb_completion {
        atomic_t                cnt;
        wait_queue_head_t       *waitq;
+       unsigned long progress_stamp;   /* The jiffies when slow progress is detected */
 };
 
 #define __WB_COMPLETION_INIT(_waitq)   \