Re: [f2fs-dev] [PATCH v7] f2fs: use post-decrement count for cp_wait wakeup

Chao Yu via Linux-f2fs-devel <[email protected]>
Newsgroups net.sourceforge.lists.linux-f2fs-devel,org.kernel.vger.linux-kernel,org.kernel.vger.stable
Message-ID <[email protected]>
On 6/18/26 18:05, Wenjie Qi wrote:
> f2fs_write_end_io() decrements the writeback page counter and then reads
> it again with get_pages() to decide whether the last F2FS_WB_CP_DATA
> completion should wake cp_wait.
> 
> That second read can miss the zero transition as below:

Looks comments of v7 patch is quite different from the one of v1 patch?

Quoted from v1:

"f2fs_write_end_io() currently decrements the writeback page counter before
waking sbi->cp_wait for the last F2FS_WB_CP_DATA completion.

That decrement can drop the F2FS_WB_CP_DATA count to zero. It can unblock
a concurrent unmount path waiting in f2fs_wait_on_all_pages(). Unmount can
continue through f2fs_put_super() and eventually free sbi while the end_io
callback is still about to evaluate wq_has_sleeper() and wake_up() on
sbi->cp_wait.

Commit 2d9c4a4ed4ee ("f2fs: fix UAF caused by decrementing sbi->nr_pages[]
in f2fs_write_end_io()") fixed one post-decrement sbi access by moving the
warm-node-list handling before dec_page_count(). The compressed writeback
path follows the same rule and documents that dec_page_count() must be the
last access to sbi when it can drop F2FS_WB_CP_DATA to zero.

Apply the same ordering rule to the cp_wait wakeup. Check whether this is
the last F2FS_WB_CP_DATA completion and wake the waiter before the counter
decrement. Then the callback no longer dereferences sbi->cp_wait after the
lifetime boundary. A waiter that runs before the decrement may observe old
count and sleep until the one-jiffy timeout, but correctness no longer
depends on touching sbi after the counter reaches zero."

I may found something interesting: v7 codes try to fix UAF bug described in
v1 comment, however v7 comment tries to explain what v2 codes want to do.

I suspect your LLM goes another direction after prompted w/ my comments on
patch v1? Let me know I'm wrong. :P

Thanks,

> 
> checkpoint          end_io A              submitter B
> - f2fs_wait_on_all_pages
>   - get_pages() > 0
>   - prepare_to_wait(cp_wait)
>   - io_schedule_timeout
>                      - f2fs_write_end_io
>                       - dec_page_count
>                        : count 1 -> 0
>                                           - f2fs_submit_page_write
>                                            - inc_page_count
>                                             : count 0 -> 1
>                       - get_pages() > 0
>                         : skip wake_up(cp_wait)
> 
> The checkpoint thread can then keep sleeping until
> DEFAULT_SCHEDULE_TIMEOUT, even though end_io A completed the old last
> F2FS_WB_CP_DATA page.
> 
> Use the post-decrement value for F2FS_WB_CP_DATA completions so the wakeup
> decision is tied to this completion.  Keep the existing dec_page_count()
> path for other writeback counters.
> 
> Fixes: e234088758fc ("f2fs: avoid wait if IO end up when do_checkpoint for better performance")
> Fixes: ce2739e482bc ("f2fs: fix to avoid UAF in f2fs_write_end_io()")
> Cc: [email protected]
> Signed-off-by: Wenjie Qi <[email protected]>
> ---
>   fs/f2fs/data.c | 12 +++++++-----
>   fs/f2fs/f2fs.h |  6 ++++++
>   2 files changed, 13 insertions(+), 5 deletions(-)
> 
> diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c
> index d83a21998ec2..2afdcd209d54 100644
> --- a/fs/f2fs/data.c
> +++ b/fs/f2fs/data.c
> @@ -392,15 +392,17 @@ static void f2fs_write_end_io(struct bio *bio)
>   		if (f2fs_in_warm_node_list(folio))
>   			f2fs_del_fsync_node_entry(sbi, folio);
>   
> -		dec_page_count(sbi, type);
> -
>   		/*
>   		 * we should access sbi before folio_end_writeback() to
>   		 * avoid racing w/ kill_f2fs_super()
>   		 */
> -		if (type == F2FS_WB_CP_DATA && !get_pages(sbi, type) &&
> -				wq_has_sleeper(&sbi->cp_wait))
> -			wake_up(&sbi->cp_wait);
> +		if (type == F2FS_WB_CP_DATA) {
> +			if (!dec_page_count_return(sbi, type) &&
> +			    wq_has_sleeper(&sbi->cp_wait))
> +				wake_up(&sbi->cp_wait);
> +		} else {
> +			dec_page_count(sbi, type);
> +		}
>   
>   		folio_clear_f2fs_gcing(folio);
>   		folio_end_writeback(folio);
> diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
> index 9f24287de4c3..db750cef371d 100644
> --- a/fs/f2fs/f2fs.h
> +++ b/fs/f2fs/f2fs.h
> @@ -2776,6 +2776,12 @@ static inline void dec_page_count(struct f2fs_sb_info *sbi, int count_type)
>   	atomic_dec(&sbi->nr_pages[count_type]);
>   }
>   
> +static inline int dec_page_count_return(struct f2fs_sb_info *sbi,
> +					int count_type)
> +{
> +	return atomic_dec_return(&sbi->nr_pages[count_type]);
> +}
> +
>   static inline void inode_dec_dirty_pages(struct inode *inode)
>   {
>   	if (!S_ISDIR(inode->i_mode) && !S_ISREG(inode->i_mode) &&
> 
> base-commit: c0b65f6129c7fbb526e921dd60261650f1b2bef9



_______________________________________________
Linux-f2fs-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.