From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 98759449B05 for ; Tue, 25 Aug 2026 13:01:52 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787662914; cv=none; b=pQo8pQ4lG9DzoW9vRvOJfem5fFrFBcTPt/Y4rqkCt696UTfzvRk5HWfkWFsO4pp+EoB+PQ2sew2T2WfGNrSNSejrv93/dIMUsMiBLbzwQ1qNdPE/AeiXsE/2XYXU0H0Jv9YuA888oFvpOCWiFcwZ0Y176seyS4/VCzgbU533TBo= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787662914; c=relaxed/simple; bh=CwjB3DDE1L+QT3nctOBMh/hyoEnvVGS95+iBBlNE7z8=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=b9eHC8BNOsCb4TzbknkEjutAO7NJzyuowp5a/O5bg2cESuib1HR95SFj8fkhLKKpSEAvz+fpO9c5zazcdpAJW1x3pZXmvfUoXOiqSB68fEiV3Mm3ktFkyHS0uZPD5+XvR416qlz/BEovIAiHF3agBQRGbZ5gjFQsB0D9G1oKT+E= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=a1iy0Hx7; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="a1iy0Hx7" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 7D48A1F00ACA; Tue, 25 Aug 2026 13:01:51 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1787662912; bh=8lft3QqwKFaEiHQCQwfjgLYyLk1XT0/1bLJS/zGD69I=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=a1iy0Hx7OSt+frwpJqKbf1Px7ih2Yea0MEfWA0ikbC2C9TFXbCuv+GhlGTj9PwmtB HkaM1WD+DVHDo5RGFp8m5bFIgpRRP+Wp0z5+Z5bIm/liLsA+zYvFhRflTtgbYlvCtj Zc3LyOXjVlVryU+AQb42yit97b+nbT2uTHwjuirgphIakgM7oPVOCpmixOmtI6NJcp aINTDzIw+S8+X0tHqpUidGB/+/M+F5cgV1PqLGgAyitgRR/Up1W3wFB1Pf03cOPPfA hIouqd9MDIjZ2t+Mr2ax6Ta7R0CfzjTppnw4grMAJtEiSvBjKYea8PeexkLPbCdydH L6QvCLovhTV2A== From: Chao Yu To: jaegeuk@kernel.org Cc: linux-f2fs-devel@lists.sourceforge.net, linux-kernel@vger.kernel.org, Chao Yu Subject: [PATCH v3 04/12] f2fs: cache: introduce writeback thread Date: Tue, 25 Aug 2026 21:01:18 +0800 Message-ID: <20260825130126.2078627-5-chao@kernel.org> X-Mailer: git-send-email 2.55.0.887.g758fc8c411-goog In-Reply-To: <20260825130126.2078627-1-chao@kernel.org> References: <20260825130126.2078627-1-chao@kernel.org> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit 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 --- fs/f2fs/cache.c | 56 +++++++++++++++++++++++++++++++++++++++++++++++++ fs/f2fs/cache.h | 13 ++++++++++++ fs/f2fs/f2fs.h | 3 +++ fs/f2fs/super.c | 31 ++++++++++++++++++++++++++- 4 files changed, 102 insertions(+), 1 deletion(-) diff --git a/fs/f2fs/cache.c b/fs/f2fs/cache.c index 3cee33c69880..dcfea6c2e1bb 100644 --- a/fs/f2fs/cache.c +++ b/fs/f2fs/cache.c @@ -615,3 +615,59 @@ 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; + struct task_struct *task; + 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)); + + task = kthread_run(f2fs_cache_writeback_kthread, sbi, "%s", name); + if (IS_ERR(task)) + return PTR_ERR(task); + + cache_thread->cache_wb_task = 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 618b377590da..ff3d8781119c 100644 --- a/fs/f2fs/cache.h +++ b/fs/f2fs/cache.h @@ -187,4 +187,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/f2fs.h b/fs/f2fs/f2fs.h index 0f855ac7d1e8..9fe9fadbb810 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h @@ -2111,6 +2111,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 32e80c70e141..9bb19f4c5fd2 100644 --- a/fs/f2fs/super.c +++ b/fs/f2fs/super.c @@ -2020,6 +2020,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); /* @@ -2826,6 +2827,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; @@ -2984,6 +2986,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); @@ -3006,7 +3020,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; } @@ -3103,6 +3117,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)) @@ -5497,6 +5518,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); @@ -5519,6 +5546,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