The Linux Kernel Mailing List
 help / color / mirror / Atom feed
From: Chao Yu <chao@kernel.org>
To: jaegeuk@kernel.org
Cc: linux-f2fs-devel@lists.sourceforge.net,
	linux-kernel@vger.kernel.org, Chao Yu <chao@kernel.org>
Subject: [PATCH v1 04/12] f2fs: cache: introduce writeback thread
Date: Thu, 20 Aug 2026 11:17:13 +0800	[thread overview]
Message-ID: <20260820031721.12218-5-chao@kernel.org> (raw)
In-Reply-To: <20260820031721.12218-1-chao@kernel.org>

This patch introduces a background writeback kthread (f2fs_writeback-x:y)
to periodically flush dirty metadata cache entries with a default
interval of 5 seconds.

It manages thread lifecycle across mount, unmount, and remount (rw/ro)
transitions, and hooks synchronous flushing into checkpoint commits.

Signed-off-by: Chao Yu <chao@kernel.org>
---
 fs/f2fs/cache.c      | 54 ++++++++++++++++++++++++++++++++++++++++++++
 fs/f2fs/cache.h      | 13 +++++++++++
 fs/f2fs/checkpoint.c |  1 +
 fs/f2fs/f2fs.h       |  3 +++
 fs/f2fs/super.c      | 31 ++++++++++++++++++++++++-
 5 files changed, 101 insertions(+), 1 deletion(-)

diff --git a/fs/f2fs/cache.c b/fs/f2fs/cache.c
index c071364822c4..cb5b26046162 100644
--- a/fs/f2fs/cache.c
+++ b/fs/f2fs/cache.c
@@ -611,3 +611,57 @@ unsigned long f2fs_shrink_cache(struct f2fs_sb_info *sbi,
 {
 	return f2fs_do_shrink_cache(META_CACHE(sbi), nr_to_scan);
 }
+
+static int f2fs_cache_writeback_kthread(void *data)
+{
+	struct f2fs_sb_info *sbi = data;
+	struct f2fs_cache_kthread *cache_thread = &sbi->cache_thread;
+	wait_queue_head_t *wq = &cache_thread->cache_wb_wq;
+	unsigned int interval = DEF_DIRTY_CACHE_TIMEOUT;
+
+	set_freezable();
+
+	while (!kthread_should_stop()) {
+		wait_event_freezable_timeout(*wq,
+				kthread_should_stop() ||
+				cache_thread->cache_wb_task == NULL,
+				msecs_to_jiffies(interval));
+
+		if (kthread_should_stop())
+			break;
+		if (f2fs_cp_error(sbi))
+			continue;
+	}
+	return 0;
+}
+
+int f2fs_start_cache_wb_thread(struct f2fs_sb_info *sbi)
+{
+	struct f2fs_cache_kthread *cache_thread = &sbi->cache_thread;
+	dev_t dev = sbi->sb->s_dev;
+	char name[36];
+
+	if (cache_thread->cache_wb_task)
+		return 0;
+
+	init_waitqueue_head(&cache_thread->cache_wb_wq);
+	snprintf(name, sizeof(name), "f2fs_writeback-%u:%u",
+			MAJOR(dev), MINOR(dev));
+
+	cache_thread->cache_wb_task = kthread_run(f2fs_cache_writeback_kthread,
+						sbi, "%s", name);
+	if (IS_ERR(cache_thread->cache_wb_task))
+		return PTR_ERR(cache_thread->cache_wb_task);
+	return 0;
+}
+
+void f2fs_stop_cache_wb_thread(struct f2fs_sb_info *sbi)
+{
+	struct f2fs_cache_kthread *cache_thread = &sbi->cache_thread;
+
+	if (!cache_thread->cache_wb_task)
+		return;
+
+	kthread_stop(cache_thread->cache_wb_task);
+	cache_thread->cache_wb_task = NULL;
+}
diff --git a/fs/f2fs/cache.h b/fs/f2fs/cache.h
index d92b6f3ed585..5e9fe8c0b15c 100644
--- a/fs/f2fs/cache.h
+++ b/fs/f2fs/cache.h
@@ -191,4 +191,17 @@ void f2fs_stop_cache_wb_thread(struct f2fs_sb_info *sbi);
 unsigned long f2fs_shrink_cache(struct f2fs_sb_info *sbi,
 				unsigned long nr_to_scan);
 
+#define DEF_DIRTY_CACHE_TIMEOUT 5000
+
+struct f2fs_cache_kthread {
+	struct task_struct *cache_wb_task;
+	wait_queue_head_t cache_wb_wq;
+	atomic_t cache_wb_trigger;
+	unsigned int cache_wb_interval_ms;
+};
+
+int f2fs_start_cache_wb_thread(struct f2fs_sb_info *sbi);
+void f2fs_stop_cache_wb_thread(struct f2fs_sb_info *sbi);
+void f2fs_sync_cache_wb(struct f2fs_sb_info *sbi);
+
 #endif /* _LINUX_F2FS_CACHE_H */
diff --git a/fs/f2fs/checkpoint.c b/fs/f2fs/checkpoint.c
index f81ba8cc861a..729d19680caf 100644
--- a/fs/f2fs/checkpoint.c
+++ b/fs/f2fs/checkpoint.c
@@ -1596,6 +1596,7 @@ static int block_operations(struct f2fs_sb_info *sbi)
 	 * sbi->node_change is used only for AIO write_begin path which produces
 	 * dirty node blocks and some checkpoint values by block allocation.
 	 */
+
 	__prepare_cp_block(sbi);
 	f2fs_up_write(&sbi->node_change);
 	return err;
diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
index 9b7c60bbb137..6e20b3586f26 100644
--- a/fs/f2fs/f2fs.h
+++ b/fs/f2fs/f2fs.h
@@ -2108,6 +2108,9 @@ struct f2fs_sb_info {
 
 	/* f2fs internal cache */
 	struct f2fs_cached_block_list meta_blocks;
+
+	/* internal cache flush thread */
+	struct f2fs_cache_kthread cache_thread;
 };
 
 /* Definitions to access f2fs_sb_info */
diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c
index bcfb1f97850e..89affe72f4fc 100644
--- a/fs/f2fs/super.c
+++ b/fs/f2fs/super.c
@@ -1998,6 +1998,7 @@ static void f2fs_put_super(struct super_block *sb)
 	 * flush all issued checkpoints and stop checkpoint issue thread.
 	 * after then, all checkpoints should be done by each process context.
 	 */
+	f2fs_stop_cache_wb_thread(sbi);
 	f2fs_stop_ckpt_thread(sbi);
 
 	/*
@@ -2799,6 +2800,7 @@ static int __f2fs_remount(struct fs_context *fc, struct super_block *sb)
 	unsigned int flags = fc->sb_flags;
 	int err;
 	bool need_restart_gc = false, need_stop_gc = false;
+	bool need_restart_wb = false, need_stop_wb = false;
 	bool need_restart_flush = false, need_stop_flush = false;
 	bool need_restart_discard = false, need_stop_discard = false;
 	bool need_enable_checkpoint = false, need_disable_checkpoint = false;
@@ -2957,6 +2959,18 @@ static int __f2fs_remount(struct fs_context *fc, struct super_block *sb)
 		need_stop_gc = true;
 	}
 
+	if (flags & SB_RDONLY) {
+		if (sbi->cache_thread.cache_wb_task) {
+			f2fs_stop_cache_wb_thread(sbi);
+			need_restart_wb = true;
+		}
+	} else if (!sbi->cache_thread.cache_wb_task) {
+		err = f2fs_start_cache_wb_thread(sbi);
+		if (err)
+			goto restore_gc;
+		need_stop_wb = true;
+	}
+
 	if (flags & SB_RDONLY) {
 		sync_inodes_sb(sb);
 
@@ -2979,7 +2993,7 @@ static int __f2fs_remount(struct fs_context *fc, struct super_block *sb)
 	} else {
 		err = f2fs_create_flush_cmd_control(sbi);
 		if (err)
-			goto restore_gc;
+			goto restore_wb;
 		need_stop_flush = true;
 	}
 
@@ -3075,6 +3089,13 @@ static int __f2fs_remount(struct fs_context *fc, struct super_block *sb)
 		clear_opt(sbi, FLUSH_MERGE);
 		f2fs_destroy_flush_cmd_control(sbi, false);
 	}
+restore_wb:
+	if (need_restart_wb) {
+		if (f2fs_start_cache_wb_thread(sbi))
+			f2fs_warn(sbi, "background cache writeback thread has stopped");
+	} else if (need_stop_wb) {
+		f2fs_stop_cache_wb_thread(sbi);
+	}
 restore_gc:
 	if (need_restart_gc) {
 		if (f2fs_start_gc_thread(sbi))
@@ -5461,6 +5482,12 @@ static int f2fs_fill_super(struct super_block *sb, struct fs_context *fc)
 			goto sync_free_meta;
 	}
 
+	if (!f2fs_readonly(sb)) {
+		err = f2fs_start_cache_wb_thread(sbi);
+		if (err)
+			goto stop_gc_thread;
+	}
+
 	/* recover broken superblock */
 	if (recovery) {
 		err = f2fs_commit_super(sbi, true);
@@ -5483,6 +5510,8 @@ static int f2fs_fill_super(struct super_block *sb, struct fs_context *fc)
 	sbi->umount_lock_holder = NULL;
 	return 0;
 
+stop_gc_thread:
+	f2fs_stop_gc_thread(sbi);
 sync_free_meta:
 	/* safe to flush all the data */
 	sync_filesystem(sbi->sb);
-- 
2.49.0


  parent reply	other threads:[~2026-08-20  3:17 UTC|newest]

Thread overview: 17+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-08-20  3:17 [PATCH v1 00/12] f2fs: introduce metadata cache Chao Yu
2026-08-20  3:17 ` [PATCH v1 01/12] f2fs: cache: implement " Chao Yu
2026-08-20  5:08   ` [f2fs-dev] " Jaegeuk Kim
2026-08-20  5:13     ` Chao Yu
2026-08-20  3:17 ` [PATCH v1 02/12] f2fs: cache: initialize meta cache Chao Yu
2026-08-20  3:17 ` [PATCH v1 03/12] f2fs: cache: introduce shrinker Chao Yu
2026-08-20  3:17 ` Chao Yu [this message]
2026-08-20  5:09   ` [f2fs-dev] [PATCH v1 04/12] f2fs: cache: introduce writeback thread Jaegeuk Kim
2026-08-20  3:17 ` [PATCH v1 05/12] f2fs: cache: use meta cache Chao Yu
2026-08-20  5:11   ` [f2fs-dev] " Jaegeuk Kim
2026-08-20  3:17 ` [PATCH v1 06/12] f2fs: cache: initialize node cache Chao Yu
2026-08-20  3:17 ` [PATCH v1 07/12] f2fs: cache: use " Chao Yu
2026-08-20  3:17 ` [PATCH v1 08/12] f2fs: cache: initialize compress cache Chao Yu
2026-08-20  3:17 ` [PATCH v1 09/12] f2fs: cache: use " Chao Yu
2026-08-20  3:17 ` [PATCH v1 10/12] f2fs: cache: support fault injection Chao Yu
2026-08-20  3:17 ` [PATCH v1 11/12] f2fs: cache: introduce tracepoints Chao Yu
2026-08-20  3:17 ` [PATCH v1 12/12] f2fs: cache: show per-cache usage in debugfs Chao Yu

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260820031721.12218-5-chao@kernel.org \
    --to=chao@kernel.org \
    --cc=jaegeuk@kernel.org \
    --cc=linux-f2fs-devel@lists.sourceforge.net \
    --cc=linux-kernel@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox