[f2fs-dev] [RFC PATCH 1/2] f2fs: keep dropbehind write bios task-context safe
Wenjie Qi <[email protected]> Thu, 6 Aug 2026 23:07:46 +0800
| Newsgroups | net.sourceforge.lists.linux-f2fs-devel,org.kernel.vger.linux-kernel |
|---|---|
| Message-ID | <[email protected]> |
Keep dropbehind folios in dropbehind-only write bios so ordinary and dropbehind writes do not share the same completion policy. If a dropbehind bio completes outside task context, defer its completion to the existing sbi->wq worker before folio_end_writeback() runs. Other bios keep the existing completion path. Signed-off-by: Wenjie Qi <[email protected]> --- fs/f2fs/data.c | 54 ++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 44 insertions(+), 10 deletions(-) diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c index 30e8084..8a1e407 100644 --- a/fs/f2fs/data.c +++ b/fs/f2fs/data.c @@ -43,9 +43,20 @@ struct f2fs_folio_state { struct f2fs_bio { struct work_struct work; + bool dropbehind; struct bio bio; }; +static inline struct f2fs_bio *f2fs_bio_to_f2bio(struct bio *bio) +{ + return container_of(bio, struct f2fs_bio, bio); +} + +static inline bool f2fs_write_folio_is_dropbehind(const struct f2fs_io_info *fio) +{ + return fio->folio && folio_test_dropbehind(fio->folio); +} + #define F2FS_BIO_POOL_SIZE NR_CURSEG_TYPE int __init f2fs_init_bioset(void) @@ -418,6 +429,15 @@ static void f2fs_write_end_io_work(struct work_struct *work) f2fs_write_end_bio(bio); } +static void f2fs_queue_write_end_io(struct f2fs_sb_info *sbi, struct bio *bio) +{ + struct work_struct *work = &container_of(bio, struct f2fs_bio, + bio)->work; + + INIT_WORK(work, f2fs_write_end_io_work); + queue_work(sbi->wq, work); +} + static void f2fs_write_end_io(struct bio *bio) { struct f2fs_sb_info *sbi; @@ -426,15 +446,15 @@ 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 (f2fs_bio_to_f2bio(bio)->dropbehind && !in_task()) { + f2fs_queue_write_end_io(sbi, bio); + return; + } - w = &container_of(bio, struct f2fs_bio, bio)->work; - INIT_WORK(w, f2fs_write_end_io_work); - queue_work(sbi->wq, w); - } else { + if (in_atomic() && bio->bi_iter.bi_size > sbi->max_atc_write_bio_size) + f2fs_queue_write_end_io(sbi, bio); + else f2fs_write_end_bio(bio); - } } #ifdef CONFIG_BLK_DEV_ZONED @@ -530,6 +550,7 @@ 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); + f2fs_bio_to_f2bio(bio)->dropbehind = false; bio->bi_iter.bi_sector = sector; if (is_read_io(fio->op)) { bio->bi_end_io = f2fs_read_end_io; @@ -796,6 +817,7 @@ int f2fs_submit_page_bio(struct f2fs_io_info *fio) /* Allocate a new bio */ bio = __bio_alloc(fio, 1); + f2fs_bio_to_f2bio(bio)->dropbehind = f2fs_write_folio_is_dropbehind(fio); f2fs_set_bio_crypt_ctx(bio, fio_folio->mapping->host, fio_folio->index, fio, GFP_NOIO); @@ -1010,6 +1032,7 @@ int f2fs_merge_page_bio(struct f2fs_io_info *fio) struct folio *data_folio = fio->encrypted_page ? page_folio(fio->encrypted_page) : fio->folio; struct folio *folio = fio->folio; + bool is_dropbehind = f2fs_write_folio_is_dropbehind(fio); if (!f2fs_is_valid_blkaddr(fio->sbi, fio->new_blkaddr, __is_meta_io(fio) ? META_GENERIC : DATA_GENERIC)) @@ -1017,17 +1040,24 @@ 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 && (f2fs_bio_to_f2bio(bio)->dropbehind != is_dropbehind || + !page_is_mergeable(fio->sbi, bio, *fio->last_block, + fio->new_blkaddr))) f2fs_submit_merged_ipu_write(fio->sbi, &bio, NULL); alloc_new: if (!bio) { bio = __bio_alloc(fio, BIO_MAX_VECS); + f2fs_bio_to_f2bio(bio)->dropbehind = is_dropbehind; f2fs_set_bio_crypt_ctx(bio, folio->mapping->host, folio->index, fio, GFP_NOIO); add_bio_entry(fio->sbi, bio, data_folio, fio->temp); } else { + if (f2fs_bio_to_f2bio(bio)->dropbehind != is_dropbehind) { + f2fs_submit_merged_ipu_write(fio->sbi, &bio, NULL); + goto alloc_new; + } + if (add_ipu_page(fio, &bio, data_folio)) goto alloc_new; } @@ -1073,6 +1103,7 @@ void f2fs_submit_page_write(struct f2fs_io_info *fio) struct folio *bio_folio; struct f2fs_lock_context lc; enum count_type type; + bool is_dropbehind; f2fs_bug_on(sbi, is_read_io(fio->op)); @@ -1100,6 +1131,7 @@ next: } verify_fio_blkaddr(fio); + is_dropbehind = f2fs_write_folio_is_dropbehind(fio); if (fio->encrypted_page) bio_folio = page_folio(fio->encrypted_page); @@ -1115,7 +1147,8 @@ next: inc_page_count(sbi, type); if (io->bio && - (!io_is_mergeable(sbi, io->bio, io, fio, io->last_block_in_bio, + (f2fs_bio_to_f2bio(io->bio)->dropbehind != is_dropbehind || + !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))) @@ -1123,6 +1156,7 @@ next: alloc_new: if (io->bio == NULL) { io->bio = __bio_alloc(fio, BIO_MAX_VECS); + f2fs_bio_to_f2bio(io->bio)->dropbehind = is_dropbehind; f2fs_set_bio_crypt_ctx(io->bio, fio_inode(fio), bio_folio->index, fio, GFP_NOIO); io->fio = *fio; -- 2.43.0 _______________________________________________ Linux-f2fs-devel mailing list [email protected] https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel