FAILED: patch "[PATCH] f2fs: embed f2fs_gc_kthread in f2fs_sb_info" failed to apply to 6.6-stable tree
Subsystems (2)
[email protected]
maintainerThe patch below does not apply to the 6.6-stable tree.
If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to <[email protected]>.
To reproduce the conflict and resubmit, you may use the following commands:
git fetch https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/ linux-6.6.y
git checkout FETCH_HEAD
git cherry-pick -x 3d7bca9d583793bb7d0bac0d95a24ddd2e129eed
# <resolve conflicts, build, test, etc.>
git commit -s
git send-email --to '<[email protected]>' --in-reply-to '2026090904-bless-finite-ea62@gregkh' --subject-prefix 'PATCH 6.6.y' 'HEAD^..'
Possible dependencies:
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From 3d7bca9d583793bb7d0bac0d95a24ddd2e129eed Mon Sep 17 00:00:00 2001
From: Chao Yu <[email protected]>
Date: Mon, 6 Jul 2026 12:33:21 +0000
Subject: [PATCH] f2fs: embed f2fs_gc_kthread in f2fs_sb_info
Instead of allocating f2fs_gc_kthread dynamically, embed it in f2fs_sb_info. This simplifies lifetime management and prepares for fixing race conditions during teardown.
- __sbi_store - remount|shutdown
- f2fs_stop_gc_thread
- access sbi->gc_thread
- sbi->gc_thread = NULL
- access sbi->gc_thread->f2fs_gc_task
fs/f2fs/debug.c +0 -4
@@ -352,10 +352,6 @@ static void update_mem_info(struct f2fs_sb_info *sbi) get_cache: si->cache_mem =0 ; -/* build gc */ -if (sbi->gc_thread) - si->cache_mem +=sizeof (struct f2fs_gc_kthread ); -/* build merge flush thread */ if (SM_I (sbi)->fcc_info) si->cache_mem +=sizeof (struct flush_cmd_control );
fs/f2fs/f2fs.h +28 -1
@@ -1748,6 +1748,33 @@ struct decompress_io_ctx {#define MAX_COMPRESS_LOG_SIZE 8#define MAX_COMPRESS_WINDOW_SIZE (log_size) ((PAGE_SIZE) << (log_size)) +struct f2fs_gc_kthread { +struct task_struct *f2fs_gc_task; +wait_queue_head_t gc_wait_queue_head; + +/* for gc sleep time */ +unsigned int urgent_sleep_time; +unsigned int min_sleep_time; +unsigned int max_sleep_time; +unsigned int no_gc_sleep_time; + +/* for changing gc mode */ +bool gc_wake; + +/* for GC_MERGE mount option */ +wait_queue_head_t fggc_wq;/* +* caller of f2fs_balance_fs() +* will wait on this wait queue. +*/ + +/* for gc control for zoned devices */ +unsigned int no_zoned_gc_percent; +unsigned int boost_zoned_gc_percent; +unsigned int valid_thresh_ratio; +unsigned int boost_gc_multiple; +unsigned int boost_gc_greedy; +}; +struct f2fs_sb_info {struct super_block *sb;/* pointer to VFS super block */ struct proc_dir_entry *s_proc;/* proc entry */
@@ -1883,7 +1910,7 @@ struct f2fs_sb_info {* semaphore for GC, avoid * race between GC and GC or CP */ -struct f2fs_gc_kthread *gc_thread;/* GC thread */ +struct f2fs_gc_kthread gc_thread;/* GC thread */ struct atgc_management am;/* atgc management */ unsigned int cur_victim_sec;/* current victim section num */ unsigned int gc_mode;/* current GC state */
fs/f2fs/gc.c +15 -21
@@ -31,9 +31,9 @@ static unsigned int count_bits(const unsigned long *addr,static int gc_thread_func (void *data) {struct f2fs_sb_info *sbi = data; -struct f2fs_gc_kthread *gc_th = sbi->gc_thread; -wait_queue_head_t *wq = &sbi->gc_thread->gc_wait_queue_head; -wait_queue_head_t *fggc_wq = &sbi->gc_thread->fggc_wq; +struct f2fs_gc_kthread *gc_th = &sbi->gc_thread; +wait_queue_head_t *wq = &sbi->gc_thread.gc_wait_queue_head; +wait_queue_head_t *fggc_wq = &sbi->gc_thread.fggc_wq;unsigned int wait_ms;struct f2fs_gc_control gc_control = { .victim_segno =NULL_SEGNO ,
@@ -193,13 +193,9 @@ static int gc_thread_func(void *data)int f2fs_start_gc_thread (struct f2fs_sb_info *sbi) { -struct f2fs_gc_kthread *gc_th; +struct f2fs_gc_kthread *gc_th = &sbi->gc_thread;dev_t dev = sbi->sb->s_bdev->bd_dev; - gc_th =f2fs_kmalloc (sbi,sizeof (struct f2fs_gc_kthread ),GFP_KERNEL ); -if (!gc_th) -return -ENOMEM ; - gc_th->urgent_sleep_time =DEF_GC_THREAD_URGENT_SLEEP_TIME ; gc_th->valid_thresh_ratio =DEF_GC_THREAD_VALID_THRESH_RATIO ; gc_th->boost_gc_multiple =BOOST_GC_MULTIPLE ;
@@ -221,16 +217,14 @@ int f2fs_start_gc_thread(struct f2fs_sb_info *sbi) gc_th->gc_wake = false; - sbi->gc_thread = gc_th; -init_waitqueue_head (&sbi->gc_thread->gc_wait_queue_head); -init_waitqueue_head (&sbi->gc_thread->fggc_wq); - sbi->gc_thread->f2fs_gc_task =kthread_run (gc_thread_func, sbi, +init_waitqueue_head (&gc_th->gc_wait_queue_head); +init_waitqueue_head (&gc_th->fggc_wq); + gc_th->f2fs_gc_task =kthread_run (gc_thread_func, sbi,"f2fs_gc-%u:%u" ,MAJOR (dev),MINOR (dev));if (IS_ERR (gc_th->f2fs_gc_task)) {int err =PTR_ERR (gc_th->f2fs_gc_task); -kfree (gc_th); - sbi->gc_thread =NULL ; + gc_th->f2fs_gc_task =NULL ;return err; }
@@ -241,14 +235,14 @@ int f2fs_start_gc_thread(struct f2fs_sb_info *sbi)void f2fs_stop_gc_thread (struct f2fs_sb_info *sbi) { -struct f2fs_gc_kthread *gc_th = sbi->gc_thread; +struct f2fs_gc_kthread *gc_th = &sbi->gc_thread; -if (!gc_th) +if (!gc_th->f2fs_gc_task)return ; +kthread_stop (gc_th->f2fs_gc_task); + gc_th->f2fs_gc_task =NULL ;wake_up_all (&gc_th->fggc_wq); -kfree (gc_th); - sbi->gc_thread =NULL ; }static int select_gc_type (struct f2fs_sb_info *sbi,int gc_type)
@@ -796,7 +790,7 @@ int f2fs_get_victim(struct f2fs_sb_info *sbi, unsigned int *result,if (one_time) { p.one_time_gc = one_time;if (has_enough_free_secs (sbi,0 ,NR_PERSISTENT_LOG )) - valid_thresh_ratio = sbi->gc_thread->valid_thresh_ratio; + valid_thresh_ratio = sbi->gc_thread.valid_thresh_ratio; } retry:
@@ -1807,9 +1801,9 @@ static int do_garbage_collect(struct f2fs_sb_info *sbi,if (f2fs_sb_has_blkzoned (sbi) && !has_enough_free_blocks (sbi, - sbi->gc_thread->boost_zoned_gc_percent)) + sbi->gc_thread.boost_zoned_gc_percent)) window_granularity *= - sbi->gc_thread->boost_gc_multiple; + sbi->gc_thread.boost_gc_multiple; end_segno = start_segno + window_granularity; }
fs/f2fs/gc.h +1 -26
@@ -45,32 +45,7 @@#define NR_GC_CHECKPOINT_SECS (3)/* data/node/dentry sections */ -struct f2fs_gc_kthread { -struct task_struct *f2fs_gc_task; -wait_queue_head_t gc_wait_queue_head; -/* for gc sleep time */ -unsigned int urgent_sleep_time; -unsigned int min_sleep_time; -unsigned int max_sleep_time; -unsigned int no_gc_sleep_time; - -/* for changing gc mode */ -bool gc_wake; - -/* for GC_MERGE mount option */ -wait_queue_head_t fggc_wq;/* -* caller of f2fs_balance_fs() -* will wait on this wait queue. -*/ - -/* for gc control for zoned devices */ -unsigned int no_zoned_gc_percent; -unsigned int boost_zoned_gc_percent; -unsigned int valid_thresh_ratio; -unsigned int boost_gc_multiple; -unsigned int boost_gc_greedy; -};struct gc_inode_list {struct list_head ilist;
@@ -197,6 +172,6 @@ static inline bool need_to_boost_gc(struct f2fs_sb_info *sbi) {if (f2fs_sb_has_blkzoned (sbi))return !has_enough_free_blocks (sbi, - sbi->gc_thread->boost_zoned_gc_percent); + sbi->gc_thread.boost_zoned_gc_percent);return has_enough_invalid_blocks (sbi); }
fs/f2fs/segment.c +4 -5
@@ -452,15 +452,14 @@ void f2fs_balance_fs(struct f2fs_sb_info *sbi, bool need)f2fs_submit_merged_write (sbi,DATA );f2fs_submit_all_merged_ipu_writes (sbi); -if (test_opt (sbi,GC_MERGE ) && sbi->gc_thread && - sbi->gc_thread->f2fs_gc_task) { +if (test_opt (sbi,GC_MERGE ) && sbi->gc_thread.f2fs_gc_task) {DEFINE_WAIT (wait); -prepare_to_wait (&sbi->gc_thread->fggc_wq, &wait, +prepare_to_wait (&sbi->gc_thread.fggc_wq, &wait,TASK_UNINTERRUPTIBLE ); -wake_up (&sbi->gc_thread->gc_wait_queue_head); +wake_up (&sbi->gc_thread.gc_wait_queue_head);io_schedule (); -finish_wait (&sbi->gc_thread->fggc_wq, &wait); +finish_wait (&sbi->gc_thread.fggc_wq, &wait); }else {struct f2fs_gc_control gc_control = { .victim_segno =NULL_SEGNO ,
fs/f2fs/super.c +2 -2
@@ -2943,11 +2943,11 @@ static int __f2fs_remount(struct fs_context *fc, struct super_block *sb)if ((flags &SB_RDONLY ) || (F2FS_OPTION (sbi).bggc_mode ==BGGC_MODE_OFF && !test_opt (sbi,GC_MERGE ))) { -if (sbi->gc_thread) { +if (sbi->gc_thread.f2fs_gc_task) {f2fs_stop_gc_thread (sbi); need_restart_gc = true; } - }else if (!sbi->gc_thread) { + }else if (!sbi->gc_thread.f2fs_gc_task) { err =f2fs_start_gc_thread (sbi);if (err) goto restore_opts;
fs/f2fs/sysfs.c +11 -11
@@ -75,7 +75,7 @@ static ssize_t f2fs_sbi_show(struct f2fs_attr *a,static unsigned char *__struct_ptr (struct f2fs_sb_info *sbi,int struct_type) {if (struct_type ==GC_THREAD ) -return (unsigned char *)sbi->gc_thread; +return (unsigned char *)&sbi->gc_thread;else if (struct_type ==SM_INFO )return (unsigned char *)SM_I (sbi);else if (struct_type ==DCC_INFO )
@@ -664,20 +664,20 @@ static ssize_t __sbi_store(struct f2fs_attr *a, sbi->gc_mode =GC_NORMAL ; }else if (t ==1 ) { sbi->gc_mode =GC_URGENT_HIGH ; -if (sbi->gc_thread) { - sbi->gc_thread->gc_wake = true; +if (sbi->gc_thread.f2fs_gc_task) { + sbi->gc_thread.gc_wake = true;wake_up_interruptible_all ( - &sbi->gc_thread->gc_wait_queue_head); + &sbi->gc_thread.gc_wait_queue_head);wake_up_discard_thread (sbi, true); } }else if (t ==2 ) { sbi->gc_mode =GC_URGENT_LOW ; }else if (t ==3 ) { sbi->gc_mode =GC_URGENT_MID ; -if (sbi->gc_thread) { - sbi->gc_thread->gc_wake = true; +if (sbi->gc_thread.f2fs_gc_task) { + sbi->gc_thread.gc_wake = true;wake_up_interruptible_all ( - &sbi->gc_thread->gc_wait_queue_head); + &sbi->gc_thread.gc_wait_queue_head); } }else {return -EINVAL ;
@@ -934,14 +934,14 @@ static ssize_t __sbi_store(struct f2fs_attr *a,if (!strcmp (a->attr.name,"gc_boost_gc_multiple" )) {if (t <1 || t >SEGS_PER_SEC (sbi))return -EINVAL ; - sbi->gc_thread->boost_gc_multiple = (unsigned int )t; + sbi->gc_thread.boost_gc_multiple = (unsigned int )t;return count; }if (!strcmp (a->attr.name,"gc_boost_gc_greedy" )) {if (t >GC_GREEDY )return -EINVAL ; - sbi->gc_thread->boost_gc_greedy = (unsigned int )t; + sbi->gc_thread.boost_gc_greedy = (unsigned int )t;return count; }
@@ -989,8 +989,8 @@ static ssize_t __sbi_store(struct f2fs_attr *a,if (sbi->cprc_info.f2fs_issue_ckpt)set_user_nice (sbi->cprc_info.f2fs_issue_ckpt,PRIO_TO_NICE (sbi->critical_task_priority)); -if (sbi->gc_thread && sbi->gc_thread->f2fs_gc_task) -set_user_nice (sbi->gc_thread->f2fs_gc_task, +if (sbi->gc_thread.f2fs_gc_task) +set_user_nice (sbi->gc_thread.f2fs_gc_task,PRIO_TO_NICE (sbi->critical_task_priority));return count; }
Sasha Levin
maintainerPATCH 1/1 f2fs: embed f2fs_gc_kthread in f2fs_sb_info
From: Chao Yu <[email protected]>
[ Upstream commit 3d7bca9d583793bb7d0bac0d95a24ddd2e129eed ]
Instead of allocating f2fs_gc_kthread dynamically, embed it in f2fs_sb_info. This simplifies lifetime management and prepares for fixing race conditions during teardown.
- __sbi_store - remount|shutdown
- f2fs_stop_gc_thread
- access sbi->gc_thread
- sbi->gc_thread = NULL
- access sbi->gc_thread->f2fs_gc_task
--- fs/f2fs/debug.c | 4 ---- fs/f2fs/f2fs.h | 22 +++++++++++++++++++++- fs/f2fs/gc.c | 30 ++++++++++++------------------ fs/f2fs/gc.h | 20 -------------------- fs/f2fs/segment.c | 9 ++++----- fs/f2fs/super.c | 4 ++-- fs/f2fs/sysfs.c | 14 +++++++------- 7 files changed, 46 insertions(+), 57 deletions(-)
fs/f2fs/debug.c +0 -4
@@ -286,10 +286,6 @@ static void update_mem_info(struct f2fs_sb_info *sbi) get_cache: si->cache_mem =0 ; -/* build gc */ -if (sbi->gc_thread) - si->cache_mem +=sizeof (struct f2fs_gc_kthread ); -/* build merge flush thread */ if (SM_I (sbi)->fcc_info) si->cache_mem +=sizeof (struct flush_cmd_control );
fs/f2fs/f2fs.h +21 -1
@@ -1556,6 +1556,26 @@ struct decompress_io_ctx {#define MAX_COMPRESS_LOG_SIZE 8#define MAX_COMPRESS_WINDOW_SIZE (log_size) ((PAGE_SIZE) << (log_size)) +struct f2fs_gc_kthread { +struct task_struct *f2fs_gc_task; +wait_queue_head_t gc_wait_queue_head; + +/* for gc sleep time */ +unsigned int urgent_sleep_time; +unsigned int min_sleep_time; +unsigned int max_sleep_time; +unsigned int no_gc_sleep_time; + +/* for changing gc mode */ +bool gc_wake; + +/* for GC_MERGE mount option */ +wait_queue_head_t fggc_wq;/* +* caller of f2fs_balance_fs() +* will wait on this wait queue. +*/ +}; +struct f2fs_sb_info {struct super_block *sb;/* pointer to VFS super block */ struct proc_dir_entry *s_proc;/* proc entry */
@@ -1677,7 +1697,7 @@ struct f2fs_sb_info {* semaphore for GC, avoid * race between GC and GC or CP */ -struct f2fs_gc_kthread *gc_thread;/* GC thread */ +struct f2fs_gc_kthread gc_thread;/* GC thread */ struct atgc_management am;/* atgc management */ unsigned int cur_victim_sec;/* current victim section num */ unsigned int gc_mode;/* current GC state */
fs/f2fs/gc.c +12 -18
@@ -31,9 +31,9 @@ static unsigned int count_bits(const unsigned long *addr,static int gc_thread_func (void *data) {struct f2fs_sb_info *sbi = data; -struct f2fs_gc_kthread *gc_th = sbi->gc_thread; -wait_queue_head_t *wq = &sbi->gc_thread->gc_wait_queue_head; -wait_queue_head_t *fggc_wq = &sbi->gc_thread->fggc_wq; +struct f2fs_gc_kthread *gc_th = &sbi->gc_thread; +wait_queue_head_t *wq = &sbi->gc_thread.gc_wait_queue_head; +wait_queue_head_t *fggc_wq = &sbi->gc_thread.fggc_wq;unsigned int wait_ms;struct f2fs_gc_control gc_control = { .victim_segno =NULL_SEGNO ,
@@ -171,13 +171,9 @@ static int gc_thread_func(void *data)int f2fs_start_gc_thread (struct f2fs_sb_info *sbi) { -struct f2fs_gc_kthread *gc_th; +struct f2fs_gc_kthread *gc_th = &sbi->gc_thread;dev_t dev = sbi->sb->s_bdev->bd_dev; - gc_th =f2fs_kmalloc (sbi,sizeof (struct f2fs_gc_kthread ),GFP_KERNEL ); -if (!gc_th) -return -ENOMEM ; - gc_th->urgent_sleep_time =DEF_GC_THREAD_URGENT_SLEEP_TIME ; gc_th->min_sleep_time =DEF_GC_THREAD_MIN_SLEEP_TIME ; gc_th->max_sleep_time =DEF_GC_THREAD_MAX_SLEEP_TIME ;
@@ -185,16 +181,14 @@ int f2fs_start_gc_thread(struct f2fs_sb_info *sbi) gc_th->gc_wake = false; - sbi->gc_thread = gc_th; -init_waitqueue_head (&sbi->gc_thread->gc_wait_queue_head); -init_waitqueue_head (&sbi->gc_thread->fggc_wq); - sbi->gc_thread->f2fs_gc_task =kthread_run (gc_thread_func, sbi, +init_waitqueue_head (&gc_th->gc_wait_queue_head); +init_waitqueue_head (&gc_th->fggc_wq); + gc_th->f2fs_gc_task =kthread_run (gc_thread_func, sbi,"f2fs_gc-%u:%u" ,MAJOR (dev),MINOR (dev));if (IS_ERR (gc_th->f2fs_gc_task)) {int err =PTR_ERR (gc_th->f2fs_gc_task); -kfree (gc_th); - sbi->gc_thread =NULL ; + gc_th->f2fs_gc_task =NULL ;return err; }
@@ -203,14 +197,14 @@ int f2fs_start_gc_thread(struct f2fs_sb_info *sbi)void f2fs_stop_gc_thread (struct f2fs_sb_info *sbi) { -struct f2fs_gc_kthread *gc_th = sbi->gc_thread; +struct f2fs_gc_kthread *gc_th = &sbi->gc_thread; -if (!gc_th) +if (!gc_th->f2fs_gc_task)return ; +kthread_stop (gc_th->f2fs_gc_task); + gc_th->f2fs_gc_task =NULL ;wake_up_all (&gc_th->fggc_wq); -kfree (gc_th); - sbi->gc_thread =NULL ; }static int select_gc_type (struct f2fs_sb_info *sbi,int gc_type)
fs/f2fs/gc.h +0 -20
@@ -32,26 +32,6 @@#define NR_GC_CHECKPOINT_SECS (3)/* data/node/dentry sections */ -struct f2fs_gc_kthread { -struct task_struct *f2fs_gc_task; -wait_queue_head_t gc_wait_queue_head; - -/* for gc sleep time */ -unsigned int urgent_sleep_time; -unsigned int min_sleep_time; -unsigned int max_sleep_time; -unsigned int no_gc_sleep_time; - -/* for changing gc mode */ -bool gc_wake; - -/* for GC_MERGE mount option */ -wait_queue_head_t fggc_wq;/* -* caller of f2fs_balance_fs() -* will wait on this wait queue. -*/ -}; -struct gc_inode_list {struct list_head ilist;struct radix_tree_root iroot;
fs/f2fs/segment.c +4 -5
@@ -440,15 +440,14 @@ void f2fs_balance_fs(struct f2fs_sb_info *sbi, bool need)f2fs_submit_merged_write (sbi,DATA );f2fs_submit_all_merged_ipu_writes (sbi); -if (test_opt (sbi,GC_MERGE ) && sbi->gc_thread && - sbi->gc_thread->f2fs_gc_task) { +if (test_opt (sbi,GC_MERGE ) && sbi->gc_thread.f2fs_gc_task) {DEFINE_WAIT (wait); -prepare_to_wait (&sbi->gc_thread->fggc_wq, &wait, +prepare_to_wait (&sbi->gc_thread.fggc_wq, &wait,TASK_UNINTERRUPTIBLE ); -wake_up (&sbi->gc_thread->gc_wait_queue_head); +wake_up (&sbi->gc_thread.gc_wait_queue_head);io_schedule (); -finish_wait (&sbi->gc_thread->fggc_wq, &wait); +finish_wait (&sbi->gc_thread.fggc_wq, &wait); }else {struct f2fs_gc_control gc_control = { .victim_segno =NULL_SEGNO ,
fs/f2fs/super.c +2 -2
@@ -2457,11 +2457,11 @@ static int f2fs_remount(struct super_block *sb, int *flags, char *data)if ((*flags &SB_RDONLY ) || (F2FS_OPTION (sbi).bggc_mode ==BGGC_MODE_OFF && !test_opt (sbi,GC_MERGE ))) { -if (sbi->gc_thread) { +if (sbi->gc_thread.f2fs_gc_task) {f2fs_stop_gc_thread (sbi); need_restart_gc = true; } - }else if (!sbi->gc_thread) { + }else if (!sbi->gc_thread.f2fs_gc_task) { err =f2fs_start_gc_thread (sbi);if (err) goto restore_opts;
fs/f2fs/sysfs.c +7 -7
@@ -74,7 +74,7 @@ static ssize_t f2fs_sbi_show(struct f2fs_attr *a,static unsigned char *__struct_ptr (struct f2fs_sb_info *sbi,int struct_type) {if (struct_type ==GC_THREAD ) -return (unsigned char *)sbi->gc_thread; +return (unsigned char *)&sbi->gc_thread;else if (struct_type ==SM_INFO )return (unsigned char *)SM_I (sbi);else if (struct_type ==DCC_INFO )
@@ -579,20 +579,20 @@ static ssize_t __sbi_store(struct f2fs_attr *a, sbi->gc_mode =GC_NORMAL ; }else if (t ==1 ) { sbi->gc_mode =GC_URGENT_HIGH ; -if (sbi->gc_thread) { - sbi->gc_thread->gc_wake = true; +if (sbi->gc_thread.f2fs_gc_task) { + sbi->gc_thread.gc_wake = true;wake_up_interruptible_all ( - &sbi->gc_thread->gc_wait_queue_head); + &sbi->gc_thread.gc_wait_queue_head);wake_up_discard_thread (sbi, true); } }else if (t ==2 ) { sbi->gc_mode =GC_URGENT_LOW ; }else if (t ==3 ) { sbi->gc_mode =GC_URGENT_MID ; -if (sbi->gc_thread) { - sbi->gc_thread->gc_wake = true; +if (sbi->gc_thread.f2fs_gc_task) { + sbi->gc_thread.gc_wake = true;wake_up_interruptible_all ( - &sbi->gc_thread->gc_wait_queue_head); + &sbi->gc_thread.gc_wait_queue_head); } }else {return -EINVAL ;
Signature · 1 line
2.53.0