Re: [PATCH v3 1/2] f2fs: complete dropbehind write bios in safe task context
From: Christoph Hellwig
Date: Tue Aug 25 2026 - 01:48:54 EST
On Mon, Aug 24, 2026 at 06:33:46PM +0800, Wenjie Qi wrote:
> Buffered RWF_DONTCACHE writes invalidate dropbehind folios from writeback
> completion. Keep normal and dropbehind folios in separate write bios, and
> defer dropbehind bios to sbi->wq unless completion runs in preemptible task
> context.
>
> Use an F2FS-local context check for this decision. Task context alone is
> not sufficient: preemption may still be disabled, or completion may run in
> a preemptible RCU read-side critical section.
>
> Keep the existing large-ATC deferral unchanged.
Please reuse all the helpers added in common code in 7.3 for deferring
bios and tsting if that that is neeeded instead of badly reinventing
the logic. It also is really helpful to Cc people involved with the
code and the relevant mailing lists.
>
> Signed-off-by: Wenjie Qi <qiwenjie@xxxxxxxxxx>
> ---
> fs/f2fs/data.c | 50 ++++++++++++++++++++++++++++++++++++++++++--------
> 1 file changed, 42 insertions(+), 8 deletions(-)
>
> diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c
> index 6ae0eb37d20..774a3e2d8e3 100644
> --- a/fs/f2fs/data.c
> +++ b/fs/f2fs/data.c
> @@ -21,6 +21,7 @@
> #include <linux/fiemap.h>
> #include <linux/iomap.h>
> #include <linux/fserror.h>
> +#include <linux/rcupdate.h>
>
> #include "f2fs.h"
> #include "node.h"
> @@ -43,9 +44,29 @@ struct f2fs_folio_state {
>
> struct f2fs_bio {
> struct work_struct work;
> + bool dropbehind;
> struct bio bio;
> };
>
> +static struct f2fs_bio *to_f2fs_bio(struct bio *bio)
> +{
> + return container_of(bio, struct f2fs_bio, bio);
> +}
> +
> +/* Keep in sync with the proposed block-layer bio_in_atomic(). */
> +static bool f2fs_bio_in_atomic(void)
> +{
> +#ifdef CONFIG_PREEMPTION
> + if (rcu_preempt_depth())
> + return true;
> +#endif
> +#ifndef CONFIG_PREEMPT_COUNT
> + return true;
> +#else
> + return !preemptible();
> +#endif
> +}
> +
> #define F2FS_BIO_POOL_SIZE NR_CURSEG_TYPE
>
> int __init f2fs_init_bioset(void)
> @@ -426,12 +447,13 @@ static void f2fs_write_end_io(struct bio *bio)
>
> sbi = bio->bi_private;
>
> - if (in_atomic() && bio->bi_iter.bi_size > sbi->max_atc_write_bio_size) {
> - struct work_struct *w;
> + if ((to_f2fs_bio(bio)->dropbehind && f2fs_bio_in_atomic()) ||
> + (in_atomic() &&
> + bio->bi_iter.bi_size > sbi->max_atc_write_bio_size)) {
> + struct work_struct *work = &to_f2fs_bio(bio)->work;
>
> - w = &container_of(bio, struct f2fs_bio, bio)->work;
> - INIT_WORK(w, f2fs_write_end_io_work);
> - queue_work(sbi->wq, w);
> + INIT_WORK(work, f2fs_write_end_io_work);
> + queue_work(sbi->wq, work);
> } else {
> f2fs_write_end_bio(bio);
> }
> @@ -530,6 +552,8 @@ static struct bio *__bio_alloc(struct f2fs_io_info *fio, int npages)
> bio = bio_alloc_bioset(bdev, npages,
> fio->op | fio->op_flags | f2fs_io_flags(fio),
> GFP_NOIO, &f2fs_bioset);
> + to_f2fs_bio(bio)->dropbehind =
> + !is_read_io(fio->op) && folio_test_dropbehind(fio->folio);
> bio->bi_iter.bi_sector = sector;
> if (is_read_io(fio->op)) {
> bio->bi_end_io = f2fs_read_end_io;
> @@ -825,6 +849,13 @@ static bool page_is_mergeable(struct f2fs_sb_info *sbi, struct bio *bio,
> return bio->bi_bdev == f2fs_target_device(sbi, cur_blkaddr, NULL);
> }
>
> +static bool f2fs_bio_dropbehind_mergeable(struct bio *bio,
> + struct f2fs_io_info *fio)
> +{
> + return to_f2fs_bio(bio)->dropbehind ==
> + folio_test_dropbehind(fio->folio);
> +}
> +
> static bool io_type_is_mergeable(struct f2fs_bio_info *io,
> struct f2fs_io_info *fio)
> {
> @@ -1017,8 +1048,10 @@ int f2fs_merge_page_bio(struct f2fs_io_info *fio)
>
> trace_f2fs_submit_folio_bio(data_folio, fio);
>
> - if (bio && !page_is_mergeable(fio->sbi, bio, *fio->last_block,
> - fio->new_blkaddr))
> + if (bio &&
> + (!page_is_mergeable(fio->sbi, bio, *fio->last_block,
> + fio->new_blkaddr) ||
> + !f2fs_bio_dropbehind_mergeable(bio, fio)))
> f2fs_submit_merged_ipu_write(fio->sbi, &bio, NULL);
> alloc_new:
> if (!bio) {
> @@ -1118,7 +1151,8 @@ void f2fs_submit_page_write(struct f2fs_io_info *fio)
> (!io_is_mergeable(sbi, io->bio, io, fio, io->last_block_in_bio,
> fio->new_blkaddr) ||
> !f2fs_crypt_mergeable_bio(io->bio, fio_inode(fio),
> - bio_folio->index, fio)))
> + bio_folio->index, fio) ||
> + !f2fs_bio_dropbehind_mergeable(io->bio, fio)))
> __submit_merged_bio(io);
> alloc_new:
> if (io->bio == NULL) {
> --
> 2.43.0
>
---end quoted text---