From 39bee2e6acc2522d88feb324b18178b34cb7b75a Mon Sep 17 00:00:00 2001 From: Sergey Shtylyov Date: Tue, 20 Dec 2022 20:17:32 +0300 Subject: f2fs: file: drop useless initializer in expand_inode_data() In expand_inode_data(), the 'new_size' local variable is initialized to the result of i_size_read(), however this value isn't ever used, so we can drop this initializer... Found by Linux Verification Center (linuxtesting.org) with the SVACE static analysis tool. Signed-off-by: Sergey Shtylyov Reviewed-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/file.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'fs/f2fs') diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c index ecbc8c135b49..6426b50b70b8 100644 --- a/fs/f2fs/file.c +++ b/fs/f2fs/file.c @@ -1697,7 +1697,7 @@ static int expand_inode_data(struct inode *inode, loff_t offset, .err_gc_skipped = true, .nr_free_secs = 0 }; pgoff_t pg_start, pg_end; - loff_t new_size = i_size_read(inode); + loff_t new_size; loff_t off_end; block_t expanded = 0; int err; -- cgit v1.2.3 From f35474ec0059c318f9d1aff1d492a5494beb6293 Mon Sep 17 00:00:00 2001 From: Chao Yu Date: Wed, 21 Dec 2022 20:14:45 +0800 Subject: f2fs: fix to support .migrate_folio for compressed inode Add missed .migrate_folio for compressed inode, in order to support migration of compressed inode's page. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/compress.c | 1 + 1 file changed, 1 insertion(+) (limited to 'fs/f2fs') diff --git a/fs/f2fs/compress.c b/fs/f2fs/compress.c index 2532f369cb10..719b0a0184b0 100644 --- a/fs/f2fs/compress.c +++ b/fs/f2fs/compress.c @@ -1813,6 +1813,7 @@ unsigned int f2fs_cluster_blocks_are_contiguous(struct dnode_of_data *dn) const struct address_space_operations f2fs_compress_aops = { .release_folio = f2fs_release_folio, .invalidate_folio = f2fs_invalidate_folio, + .migrate_folio = filemap_migrate_folio, }; struct address_space *COMPRESS_MAPPING(struct f2fs_sb_info *sbi) -- cgit v1.2.3 From b3107b3854c93ea380ac373c0032fcf15f31178a Mon Sep 17 00:00:00 2001 From: Chao Yu Date: Tue, 20 Dec 2022 19:56:02 +0800 Subject: f2fs: remove unused PAGE_PRIVATE_ATOMIC_WRITE Commit 3db1de0e582c ("f2fs: change the current atomic write way") has removed all users of PAGE_PRIVATE_ATOMIC_WRITE, remove its definition and related functions. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/f2fs.h | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) (limited to 'fs/f2fs') diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index e8953c3dc81a..9c7df2f1df73 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h @@ -1396,19 +1396,17 @@ static inline void f2fs_clear_bit(unsigned int nr, char *addr); * Layout A: lowest bit should be 1 * | bit0 = 1 | bit1 | bit2 | ... | bit MAX | private data .... | * bit 0 PAGE_PRIVATE_NOT_POINTER - * bit 1 PAGE_PRIVATE_ATOMIC_WRITE - * bit 2 PAGE_PRIVATE_DUMMY_WRITE - * bit 3 PAGE_PRIVATE_ONGOING_MIGRATION - * bit 4 PAGE_PRIVATE_INLINE_INODE - * bit 5 PAGE_PRIVATE_REF_RESOURCE - * bit 6- f2fs private data + * bit 1 PAGE_PRIVATE_DUMMY_WRITE + * bit 2 PAGE_PRIVATE_ONGOING_MIGRATION + * bit 3 PAGE_PRIVATE_INLINE_INODE + * bit 4 PAGE_PRIVATE_REF_RESOURCE + * bit 5- f2fs private data * * Layout B: lowest bit should be 0 * page.private is a wrapped pointer. */ enum { PAGE_PRIVATE_NOT_POINTER, /* private contains non-pointer data */ - PAGE_PRIVATE_ATOMIC_WRITE, /* data page from atomic write path */ PAGE_PRIVATE_DUMMY_WRITE, /* data page for padding aligned IO */ PAGE_PRIVATE_ONGOING_MIGRATION, /* data page which is on-going migrating */ PAGE_PRIVATE_INLINE_INODE, /* inode page contains inline data */ @@ -1453,19 +1451,16 @@ PAGE_PRIVATE_GET_FUNC(nonpointer, NOT_POINTER); PAGE_PRIVATE_GET_FUNC(reference, REF_RESOURCE); PAGE_PRIVATE_GET_FUNC(inline, INLINE_INODE); PAGE_PRIVATE_GET_FUNC(gcing, ONGOING_MIGRATION); -PAGE_PRIVATE_GET_FUNC(atomic, ATOMIC_WRITE); PAGE_PRIVATE_GET_FUNC(dummy, DUMMY_WRITE); PAGE_PRIVATE_SET_FUNC(reference, REF_RESOURCE); PAGE_PRIVATE_SET_FUNC(inline, INLINE_INODE); PAGE_PRIVATE_SET_FUNC(gcing, ONGOING_MIGRATION); -PAGE_PRIVATE_SET_FUNC(atomic, ATOMIC_WRITE); PAGE_PRIVATE_SET_FUNC(dummy, DUMMY_WRITE); PAGE_PRIVATE_CLEAR_FUNC(reference, REF_RESOURCE); PAGE_PRIVATE_CLEAR_FUNC(inline, INLINE_INODE); PAGE_PRIVATE_CLEAR_FUNC(gcing, ONGOING_MIGRATION); -PAGE_PRIVATE_CLEAR_FUNC(atomic, ATOMIC_WRITE); PAGE_PRIVATE_CLEAR_FUNC(dummy, DUMMY_WRITE); static inline unsigned long get_page_private_data(struct page *page) -- cgit v1.2.3 From 6779b5db90c5b925293f7ccc5ed5336c5b24ed50 Mon Sep 17 00:00:00 2001 From: Chao Yu Date: Wed, 21 Dec 2022 20:13:45 +0800 Subject: f2fs: fix to call clear_page_private_reference in .{release,invalid}_folio b763f3bedc2d ("f2fs: restructure f2fs page.private layout") missed to call clear_page_private_reference() in .{release,invalid}_folio, fix it, though it's not a big deal since folio_detach_private() was called to clear all privae info and reference count in the page. BTW, remove page_private_reference() definition as it never be used. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/data.c | 2 ++ fs/f2fs/f2fs.h | 1 - 2 files changed, 2 insertions(+), 1 deletion(-) (limited to 'fs/f2fs') diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c index 97e816590cd9..017c9746a705 100644 --- a/fs/f2fs/data.c +++ b/fs/f2fs/data.c @@ -3698,6 +3698,7 @@ void f2fs_invalidate_folio(struct folio *folio, size_t offset, size_t length) } } + clear_page_private_reference(&folio->page); clear_page_private_gcing(&folio->page); if (test_opt(sbi, COMPRESS_CACHE) && @@ -3723,6 +3724,7 @@ bool f2fs_release_folio(struct folio *folio, gfp_t wait) clear_page_private_data(&folio->page); } + clear_page_private_reference(&folio->page); clear_page_private_gcing(&folio->page); folio_detach_private(folio); diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index 9c7df2f1df73..5fdefb82509d 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h @@ -1448,7 +1448,6 @@ static inline void clear_page_private_##name(struct page *page) \ } PAGE_PRIVATE_GET_FUNC(nonpointer, NOT_POINTER); -PAGE_PRIVATE_GET_FUNC(reference, REF_RESOURCE); PAGE_PRIVATE_GET_FUNC(inline, INLINE_INODE); PAGE_PRIVATE_GET_FUNC(gcing, ONGOING_MIGRATION); PAGE_PRIVATE_GET_FUNC(dummy, DUMMY_WRITE); -- cgit v1.2.3 From 8d3c1fa3fa5eacfd14f5b018eddb6c1a91c57783 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 28 Nov 2022 10:15:09 +0100 Subject: f2fs: don't rely on F2FS_MAP_* in f2fs_iomap_begin When testing with a mixed zoned / convention device combination, there are regular but not 100% reproducible failures in xfstests generic/113 where the __is_valid_data_blkaddr assert hits due to finding a hole. This seems to be because f2fs_map_blocks can set this flag on a hole when it was found in the extent cache. Rework f2fs_iomap_begin to just check the special block numbers directly. This has the added benefits of the WARN_ON showing which invalid block address we found, and being properly error out on delalloc blocks that are confusingly called unwritten but not actually suitable for direct I/O. Fixes: 1517c1a7a445 ("f2fs: implement iomap operations") Signed-off-by: Christoph Hellwig Reviewed-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/data.c | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) (limited to 'fs/f2fs') diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c index 017c9746a705..86585c0922f2 100644 --- a/fs/f2fs/data.c +++ b/fs/f2fs/data.c @@ -4153,20 +4153,24 @@ static int f2fs_iomap_begin(struct inode *inode, loff_t offset, loff_t length, */ map.m_len = fscrypt_limit_io_blocks(inode, map.m_lblk, map.m_len); - if (map.m_flags & (F2FS_MAP_MAPPED | F2FS_MAP_UNWRITTEN)) { - iomap->length = blks_to_bytes(inode, map.m_len); - if (map.m_flags & F2FS_MAP_MAPPED) { - iomap->type = IOMAP_MAPPED; - iomap->flags |= IOMAP_F_MERGED; - } else { - iomap->type = IOMAP_UNWRITTEN; - } - if (WARN_ON_ONCE(!__is_valid_data_blkaddr(map.m_pblk))) - return -EINVAL; + /* + * We should never see delalloc or compressed extents here based on + * prior flushing and checks. + */ + if (WARN_ON_ONCE(map.m_pblk == NEW_ADDR)) + return -EINVAL; + if (WARN_ON_ONCE(map.m_pblk == COMPRESS_ADDR)) + return -EINVAL; + if (map.m_pblk != NULL_ADDR) { + iomap->length = blks_to_bytes(inode, map.m_len); + iomap->type = IOMAP_MAPPED; + iomap->flags |= IOMAP_F_MERGED; iomap->bdev = map.m_bdev; iomap->addr = blks_to_bytes(inode, map.m_pblk); } else { + if (flags & IOMAP_WRITE) + return -ENOTBLK; iomap->length = blks_to_bytes(inode, next_pgofs) - iomap->offset; iomap->type = IOMAP_HOLE; -- cgit v1.2.3 From 62a134bd8941198eee8b23584e35be6a9ab835d1 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 28 Nov 2022 10:15:10 +0100 Subject: f2fs: decouple F2FS_MAP_ from buffer head flags m_flags is never interchanged with the buffer_heads b_flags directly, so use separate codepoints from that. Signed-off-by: Christoph Hellwig Reviewed-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/f2fs.h | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'fs/f2fs') diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index 5fdefb82509d..28828a8c959f 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h @@ -692,13 +692,11 @@ struct extent_tree_info { }; /* - * This structure is taken from ext4_map_blocks. - * - * Note that, however, f2fs uses NEW and MAPPED flags for f2fs_map_blocks(). + * State of block returned by f2fs_map_blocks. */ -#define F2FS_MAP_NEW (1 << BH_New) -#define F2FS_MAP_MAPPED (1 << BH_Mapped) -#define F2FS_MAP_UNWRITTEN (1 << BH_Unwritten) +#define F2FS_MAP_NEW (1U << 0) +#define F2FS_MAP_MAPPED (1U << 1) +#define F2FS_MAP_UNWRITTEN (1U << 2) #define F2FS_MAP_FLAGS (F2FS_MAP_NEW | F2FS_MAP_MAPPED |\ F2FS_MAP_UNWRITTEN) -- cgit v1.2.3 From da8c7fecc9c7ba91b6d5ff5726189f269686a40c Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 28 Nov 2022 10:15:11 +0100 Subject: f2fs: rename F2FS_MAP_UNWRITTEN to F2FS_MAP_DELALLOC NEW_ADDR blocks are purely in-memory preallocated blocks, and thus equivalent to what the core FS code calls delayed allocations, and not unwritten extents which do have on-disk blocks allocated from which reads always return zeroes until they are converted to written status. Signed-off-by: Christoph Hellwig Reviewed-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/data.c | 8 ++++---- fs/f2fs/f2fs.h | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) (limited to 'fs/f2fs') diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c index 86585c0922f2..93625d9900e8 100644 --- a/fs/f2fs/data.c +++ b/fs/f2fs/data.c @@ -1660,9 +1660,9 @@ next_block: bidx = f2fs_target_device_index(sbi, blkaddr); if (map->m_len == 0) { - /* preallocated unwritten block should be mapped for fiemap. */ + /* reserved delalloc block should be mapped for fiemap. */ if (blkaddr == NEW_ADDR) - map->m_flags |= F2FS_MAP_UNWRITTEN; + map->m_flags |= F2FS_MAP_DELALLOC; map->m_flags |= F2FS_MAP_MAPPED; map->m_pblk = blkaddr; @@ -1984,7 +1984,7 @@ next: compr_appended = false; /* In a case of compressed cluster, append this to the last extent */ - if (compr_cluster && ((map.m_flags & F2FS_MAP_UNWRITTEN) || + if (compr_cluster && ((map.m_flags & F2FS_MAP_DELALLOC) || !(map.m_flags & F2FS_MAP_FLAGS))) { compr_appended = true; goto skip_fill; @@ -2030,7 +2030,7 @@ skip_fill: compr_cluster = false; size += blks_to_bytes(inode, 1); } - } else if (map.m_flags & F2FS_MAP_UNWRITTEN) { + } else if (map.m_flags & F2FS_MAP_DELALLOC) { flags = FIEMAP_EXTENT_UNWRITTEN; } diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index 28828a8c959f..fea2735167e5 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h @@ -696,9 +696,9 @@ struct extent_tree_info { */ #define F2FS_MAP_NEW (1U << 0) #define F2FS_MAP_MAPPED (1U << 1) -#define F2FS_MAP_UNWRITTEN (1U << 2) +#define F2FS_MAP_DELALLOC (1U << 2) #define F2FS_MAP_FLAGS (F2FS_MAP_NEW | F2FS_MAP_MAPPED |\ - F2FS_MAP_UNWRITTEN) + F2FS_MAP_DELALLOC) struct f2fs_map_blocks { struct block_device *m_bdev; /* for multi-device dio */ -- cgit v1.2.3 From bc29835a9d4860df93a663d659e07dfdd8b4f629 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 28 Nov 2022 10:15:12 +0100 Subject: f2fs: split __submit_bio Split __submit_bio into one function each for reads and writes, and a helper for aligning writes. Signed-off-by: Christoph Hellwig Reviewed-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/compress.c | 2 +- fs/f2fs/data.c | 111 ++++++++++++++++++++++++++++------------------------- fs/f2fs/f2fs.h | 4 +- 3 files changed, 61 insertions(+), 56 deletions(-) (limited to 'fs/f2fs') diff --git a/fs/f2fs/compress.c b/fs/f2fs/compress.c index 719b0a0184b0..e4db3b7932a3 100644 --- a/fs/f2fs/compress.c +++ b/fs/f2fs/compress.c @@ -1070,7 +1070,7 @@ retry: if (ret) goto out; if (bio) - f2fs_submit_bio(sbi, bio, DATA); + f2fs_submit_read_bio(sbi, bio, DATA); ret = f2fs_init_compress_ctx(cc); if (ret) diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c index 93625d9900e8..f5ef7d07191b 100644 --- a/fs/f2fs/data.c +++ b/fs/f2fs/data.c @@ -507,65 +507,66 @@ static bool f2fs_crypt_mergeable_bio(struct bio *bio, const struct inode *inode, return fscrypt_mergeable_bio(bio, inode, next_idx); } -static inline void __submit_bio(struct f2fs_sb_info *sbi, - struct bio *bio, enum page_type type) +void f2fs_submit_read_bio(struct f2fs_sb_info *sbi, struct bio *bio, + enum page_type type) { - if (!is_read_io(bio_op(bio))) { - unsigned int start; + WARN_ON_ONCE(!is_read_io(bio_op(bio))); + trace_f2fs_submit_read_bio(sbi->sb, type, bio); - if (type != DATA && type != NODE) - goto submit_io; + iostat_update_submit_ctx(bio, type); + submit_bio(bio); +} - if (f2fs_lfs_mode(sbi) && current->plug) - blk_finish_plug(current->plug); +static void f2fs_align_write_bio(struct f2fs_sb_info *sbi, struct bio *bio) +{ + unsigned int start = + (bio->bi_iter.bi_size >> F2FS_BLKSIZE_BITS) % F2FS_IO_SIZE(sbi); - if (!F2FS_IO_ALIGNED(sbi)) - goto submit_io; + if (start == 0) + return; - start = bio->bi_iter.bi_size >> F2FS_BLKSIZE_BITS; - start %= F2FS_IO_SIZE(sbi); + /* fill dummy pages */ + for (; start < F2FS_IO_SIZE(sbi); start++) { + struct page *page = + mempool_alloc(sbi->write_io_dummy, + GFP_NOIO | __GFP_NOFAIL); + f2fs_bug_on(sbi, !page); - if (start == 0) - goto submit_io; + lock_page(page); - /* fill dummy pages */ - for (; start < F2FS_IO_SIZE(sbi); start++) { - struct page *page = - mempool_alloc(sbi->write_io_dummy, - GFP_NOIO | __GFP_NOFAIL); - f2fs_bug_on(sbi, !page); + zero_user_segment(page, 0, PAGE_SIZE); + set_page_private_dummy(page); - lock_page(page); + if (bio_add_page(bio, page, PAGE_SIZE, 0) < PAGE_SIZE) + f2fs_bug_on(sbi, 1); + } +} - zero_user_segment(page, 0, PAGE_SIZE); - set_page_private_dummy(page); +static void f2fs_submit_write_bio(struct f2fs_sb_info *sbi, struct bio *bio, + enum page_type type) +{ + WARN_ON_ONCE(is_read_io(bio_op(bio))); + + if (type == DATA || type == NODE) { + if (f2fs_lfs_mode(sbi) && current->plug) + blk_finish_plug(current->plug); - if (bio_add_page(bio, page, PAGE_SIZE, 0) < PAGE_SIZE) - f2fs_bug_on(sbi, 1); + if (F2FS_IO_ALIGNED(sbi)) { + f2fs_align_write_bio(sbi, bio); + /* + * In the NODE case, we lose next block address chain. + * So, we need to do checkpoint in f2fs_sync_file. + */ + if (type == NODE) + set_sbi_flag(sbi, SBI_NEED_CP); } - /* - * In the NODE case, we lose next block address chain. So, we - * need to do checkpoint in f2fs_sync_file. - */ - if (type == NODE) - set_sbi_flag(sbi, SBI_NEED_CP); } -submit_io: - if (is_read_io(bio_op(bio))) - trace_f2fs_submit_read_bio(sbi->sb, type, bio); - else - trace_f2fs_submit_write_bio(sbi->sb, type, bio); + trace_f2fs_submit_write_bio(sbi->sb, type, bio); iostat_update_submit_ctx(bio, type); submit_bio(bio); } -void f2fs_submit_bio(struct f2fs_sb_info *sbi, - struct bio *bio, enum page_type type) -{ - __submit_bio(sbi, bio, type); -} - static void __submit_merged_bio(struct f2fs_bio_info *io) { struct f2fs_io_info *fio = &io->fio; @@ -573,12 +574,13 @@ static void __submit_merged_bio(struct f2fs_bio_info *io) if (!io->bio) return; - if (is_read_io(fio->op)) + if (is_read_io(fio->op)) { trace_f2fs_prepare_read_bio(io->sbi->sb, fio->type, io->bio); - else + f2fs_submit_read_bio(io->sbi, io->bio, fio->type); + } else { trace_f2fs_prepare_write_bio(io->sbi->sb, fio->type, io->bio); - - __submit_bio(io->sbi, io->bio, fio->type); + f2fs_submit_write_bio(io->sbi, io->bio, fio->type); + } io->bio = NULL; } @@ -746,7 +748,10 @@ int f2fs_submit_page_bio(struct f2fs_io_info *fio) inc_page_count(fio->sbi, is_read_io(fio->op) ? __read_io_type(page) : WB_DATA_TYPE(fio->page)); - __submit_bio(fio->sbi, bio, fio->type); + if (is_read_io(bio_op(bio))) + f2fs_submit_read_bio(fio->sbi, bio, fio->type); + else + f2fs_submit_write_bio(fio->sbi, bio, fio->type); return 0; } @@ -848,7 +853,7 @@ static int add_ipu_page(struct f2fs_io_info *fio, struct bio **bio, /* page can't be merged into bio; submit the bio */ del_bio_entry(be); - __submit_bio(sbi, *bio, DATA); + f2fs_submit_write_bio(sbi, *bio, DATA); break; } f2fs_up_write(&io->bio_list_lock); @@ -911,7 +916,7 @@ void f2fs_submit_merged_ipu_write(struct f2fs_sb_info *sbi, } if (found) - __submit_bio(sbi, target, DATA); + f2fs_submit_write_bio(sbi, target, DATA); if (bio && *bio) { bio_put(*bio); *bio = NULL; @@ -1107,7 +1112,7 @@ static int f2fs_submit_page_read(struct inode *inode, struct page *page, } inc_page_count(sbi, F2FS_RD_DATA); f2fs_update_iostat(sbi, NULL, FS_DATA_READ_IO, F2FS_BLKSIZE); - __submit_bio(sbi, bio, DATA); + f2fs_submit_read_bio(sbi, bio, DATA); return 0; } @@ -2137,7 +2142,7 @@ zero_out: *last_block_in_bio, block_nr) || !f2fs_crypt_mergeable_bio(bio, inode, page->index, NULL))) { submit_and_realloc: - __submit_bio(F2FS_I_SB(inode), bio, DATA); + f2fs_submit_read_bio(F2FS_I_SB(inode), bio, DATA); bio = NULL; } if (bio == NULL) { @@ -2284,7 +2289,7 @@ skip_reading_dnode: *last_block_in_bio, blkaddr) || !f2fs_crypt_mergeable_bio(bio, inode, page->index, NULL))) { submit_and_realloc: - __submit_bio(sbi, bio, DATA); + f2fs_submit_read_bio(sbi, bio, DATA); bio = NULL; } @@ -2445,7 +2450,7 @@ next_page: #endif } if (bio) - __submit_bio(F2FS_I_SB(inode), bio, DATA); + f2fs_submit_read_bio(F2FS_I_SB(inode), bio, DATA); return ret; } diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index fea2735167e5..0e240ac13ca1 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h @@ -3780,8 +3780,8 @@ int __init f2fs_init_bioset(void); void f2fs_destroy_bioset(void); int f2fs_init_bio_entry_cache(void); void f2fs_destroy_bio_entry_cache(void); -void f2fs_submit_bio(struct f2fs_sb_info *sbi, - struct bio *bio, enum page_type type); +void f2fs_submit_read_bio(struct f2fs_sb_info *sbi, struct bio *bio, + enum page_type type); int f2fs_init_write_merge_io(struct f2fs_sb_info *sbi); void f2fs_submit_merged_write(struct f2fs_sb_info *sbi, enum page_type type); void f2fs_submit_merged_write_cond(struct f2fs_sb_info *sbi, -- cgit v1.2.3 From 04a91ab016847440c8c937dda628079070f38c7a Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 28 Nov 2022 10:15:14 +0100 Subject: f2fs: add a f2fs_lookup_extent_cache_block helper All but three callers of f2fs_lookup_extent_cache just want the block address. Add a small helper to simplify them. Signed-off-by: Christoph Hellwig Reviewed-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/data.c | 51 ++++++++++++++++++-------------------------------- fs/f2fs/extent_cache.c | 11 +++++++++++ fs/f2fs/f2fs.h | 2 ++ fs/f2fs/gc.c | 5 ++--- 4 files changed, 33 insertions(+), 36 deletions(-) (limited to 'fs/f2fs') diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c index f5ef7d07191b..e80d7d250993 100644 --- a/fs/f2fs/data.c +++ b/fs/f2fs/data.c @@ -1214,14 +1214,9 @@ int f2fs_reserve_block(struct dnode_of_data *dn, pgoff_t index) int f2fs_get_block(struct dnode_of_data *dn, pgoff_t index) { - struct extent_info ei = {0, }; - struct inode *inode = dn->inode; - - if (f2fs_lookup_read_extent_cache(inode, index, &ei)) { - dn->data_blkaddr = ei.blk + index - ei.fofs; + if (f2fs_lookup_read_extent_cache_block(dn->inode, index, + &dn->data_blkaddr)) return 0; - } - return f2fs_reserve_block(dn, index); } @@ -1232,15 +1227,14 @@ struct page *f2fs_get_read_data_page(struct inode *inode, pgoff_t index, struct address_space *mapping = inode->i_mapping; struct dnode_of_data dn; struct page *page; - struct extent_info ei = {0, }; int err; page = f2fs_grab_cache_page(mapping, index, for_write); if (!page) return ERR_PTR(-ENOMEM); - if (f2fs_lookup_read_extent_cache(inode, index, &ei)) { - dn.data_blkaddr = ei.blk + index - ei.fofs; + if (f2fs_lookup_read_extent_cache_block(inode, index, + &dn.data_blkaddr)) { if (!f2fs_is_valid_blkaddr(F2FS_I_SB(inode), dn.data_blkaddr, DATA_GENERIC_ENHANCE_READ)) { err = -EFSCORRUPTED; @@ -2641,7 +2635,6 @@ int f2fs_do_write_data_page(struct f2fs_io_info *fio) struct page *page = fio->page; struct inode *inode = page->mapping->host; struct dnode_of_data dn; - struct extent_info ei = {0, }; struct node_info ni; bool ipu_force = false; int err = 0; @@ -2653,9 +2646,8 @@ int f2fs_do_write_data_page(struct f2fs_io_info *fio) set_new_dnode(&dn, inode, NULL, NULL, 0); if (need_inplace_update(fio) && - f2fs_lookup_read_extent_cache(inode, page->index, &ei)) { - fio->old_blkaddr = ei.blk + page->index - ei.fofs; - + f2fs_lookup_read_extent_cache_block(inode, page->index, + &fio->old_blkaddr)) { if (!f2fs_is_valid_blkaddr(fio->sbi, fio->old_blkaddr, DATA_GENERIC_ENHANCE)) { f2fs_handle_error(fio->sbi, @@ -3328,7 +3320,6 @@ static int prepare_write_begin(struct f2fs_sb_info *sbi, struct dnode_of_data dn; struct page *ipage; bool locked = false; - struct extent_info ei = {0, }; int err = 0; int flag; @@ -3376,20 +3367,16 @@ restart: } } else if (locked) { err = f2fs_get_block(&dn, index); - } else { - if (f2fs_lookup_read_extent_cache(inode, index, &ei)) { - dn.data_blkaddr = ei.blk + index - ei.fofs; - } else { - /* hole case */ - err = f2fs_get_dnode_of_data(&dn, index, LOOKUP_NODE); - if (err || dn.data_blkaddr == NULL_ADDR) { - f2fs_put_dnode(&dn); - f2fs_do_map_lock(sbi, F2FS_GET_BLOCK_PRE_AIO, - true); - WARN_ON(flag != F2FS_GET_BLOCK_PRE_AIO); - locked = true; - goto restart; - } + } else if (!f2fs_lookup_read_extent_cache_block(inode, index, + &dn.data_blkaddr)) { + /* hole case */ + err = f2fs_get_dnode_of_data(&dn, index, LOOKUP_NODE); + if (err || dn.data_blkaddr == NULL_ADDR) { + f2fs_put_dnode(&dn); + f2fs_do_map_lock(sbi, F2FS_GET_BLOCK_PRE_AIO, true); + WARN_ON(flag != F2FS_GET_BLOCK_PRE_AIO); + locked = true; + goto restart; } } @@ -3409,7 +3396,6 @@ static int __find_data_block(struct inode *inode, pgoff_t index, { struct dnode_of_data dn; struct page *ipage; - struct extent_info ei = {0, }; int err = 0; ipage = f2fs_get_node_page(F2FS_I_SB(inode), inode->i_ino); @@ -3418,9 +3404,8 @@ static int __find_data_block(struct inode *inode, pgoff_t index, set_new_dnode(&dn, inode, ipage, ipage, 0); - if (f2fs_lookup_read_extent_cache(inode, index, &ei)) { - dn.data_blkaddr = ei.blk + index - ei.fofs; - } else { + if (!f2fs_lookup_read_extent_cache_block(inode, index, + &dn.data_blkaddr)) { /* hole case */ err = f2fs_get_dnode_of_data(&dn, index, LOOKUP_NODE); if (err) { diff --git a/fs/f2fs/extent_cache.c b/fs/f2fs/extent_cache.c index 342af24b2f8c..1daf8c88c09b 100644 --- a/fs/f2fs/extent_cache.c +++ b/fs/f2fs/extent_cache.c @@ -1047,6 +1047,17 @@ bool f2fs_lookup_read_extent_cache(struct inode *inode, pgoff_t pgofs, return __lookup_extent_tree(inode, pgofs, ei, EX_READ); } +bool f2fs_lookup_read_extent_cache_block(struct inode *inode, pgoff_t index, + block_t *blkaddr) +{ + struct extent_info ei = {}; + + if (!f2fs_lookup_read_extent_cache(inode, index, &ei)) + return false; + *blkaddr = ei.blk + index - ei.fofs; + return true; +} + void f2fs_update_read_extent_cache(struct dnode_of_data *dn) { return __update_extent_cache(dn, EX_READ); diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index 0e240ac13ca1..cc737f2a9e82 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h @@ -4182,6 +4182,8 @@ void f2fs_destroy_extent_cache(void); void f2fs_init_read_extent_tree(struct inode *inode, struct page *ipage); bool f2fs_lookup_read_extent_cache(struct inode *inode, pgoff_t pgofs, struct extent_info *ei); +bool f2fs_lookup_read_extent_cache_block(struct inode *inode, pgoff_t index, + block_t *blkaddr); void f2fs_update_read_extent_cache(struct dnode_of_data *dn); void f2fs_update_read_extent_cache_range(struct dnode_of_data *dn, pgoff_t fofs, block_t blkaddr, unsigned int len); diff --git a/fs/f2fs/gc.c b/fs/f2fs/gc.c index 6e2cae3d2e71..83e68ec7763d 100644 --- a/fs/f2fs/gc.c +++ b/fs/f2fs/gc.c @@ -1150,7 +1150,6 @@ static int ra_data_block(struct inode *inode, pgoff_t index) struct address_space *mapping = inode->i_mapping; struct dnode_of_data dn; struct page *page; - struct extent_info ei = {0, }; struct f2fs_io_info fio = { .sbi = sbi, .ino = inode->i_ino, @@ -1168,8 +1167,8 @@ static int ra_data_block(struct inode *inode, pgoff_t index) if (!page) return -ENOMEM; - if (f2fs_lookup_read_extent_cache(inode, index, &ei)) { - dn.data_blkaddr = ei.blk + index - ei.fofs; + if (f2fs_lookup_read_extent_cache_block(inode, index, + &dn.data_blkaddr)) { if (unlikely(!f2fs_is_valid_blkaddr(sbi, dn.data_blkaddr, DATA_GENERIC_ENHANCE_READ))) { err = -EFSCORRUPTED; -- cgit v1.2.3 From cf342d3beda000b4c60990755ca7800de5038785 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 28 Nov 2022 10:15:15 +0100 Subject: f2fs: add a f2fs_get_block_locked helper This allows to keep the f2fs_do_map_lock based locking scheme private to data.c. Signed-off-by: Christoph Hellwig Reviewed-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/data.c | 16 ++++++++++++++-- fs/f2fs/f2fs.h | 3 +-- fs/f2fs/file.c | 4 +--- 3 files changed, 16 insertions(+), 7 deletions(-) (limited to 'fs/f2fs') diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c index e80d7d250993..904dfd1f16d0 100644 --- a/fs/f2fs/data.c +++ b/fs/f2fs/data.c @@ -1212,7 +1212,7 @@ int f2fs_reserve_block(struct dnode_of_data *dn, pgoff_t index) return err; } -int f2fs_get_block(struct dnode_of_data *dn, pgoff_t index) +static int f2fs_get_block(struct dnode_of_data *dn, pgoff_t index) { if (f2fs_lookup_read_extent_cache_block(dn->inode, index, &dn->data_blkaddr)) @@ -1451,7 +1451,7 @@ alloc: return 0; } -void f2fs_do_map_lock(struct f2fs_sb_info *sbi, int flag, bool lock) +static void f2fs_do_map_lock(struct f2fs_sb_info *sbi, int flag, bool lock) { if (flag == F2FS_GET_BLOCK_PRE_AIO) { if (lock) @@ -1466,6 +1466,18 @@ void f2fs_do_map_lock(struct f2fs_sb_info *sbi, int flag, bool lock) } } +int f2fs_get_block_locked(struct dnode_of_data *dn, pgoff_t index) +{ + struct f2fs_sb_info *sbi = F2FS_I_SB(dn->inode); + int err; + + f2fs_do_map_lock(sbi, F2FS_GET_BLOCK_PRE_AIO, true); + err = f2fs_get_block(dn, index); + f2fs_do_map_lock(sbi, F2FS_GET_BLOCK_PRE_AIO, false); + + return err; +} + /* * f2fs_map_blocks() tries to find or build mapping relationship which * maps continuous logical blocks to physical blocks, and return such diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index cc737f2a9e82..744cb442085f 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h @@ -3800,7 +3800,7 @@ void f2fs_set_data_blkaddr(struct dnode_of_data *dn); void f2fs_update_data_blkaddr(struct dnode_of_data *dn, block_t blkaddr); int f2fs_reserve_new_blocks(struct dnode_of_data *dn, blkcnt_t count); int f2fs_reserve_new_block(struct dnode_of_data *dn); -int f2fs_get_block(struct dnode_of_data *dn, pgoff_t index); +int f2fs_get_block_locked(struct dnode_of_data *dn, pgoff_t index); int f2fs_reserve_block(struct dnode_of_data *dn, pgoff_t index); struct page *f2fs_get_read_data_page(struct inode *inode, pgoff_t index, blk_opf_t op_flags, bool for_write, pgoff_t *next_pgofs); @@ -3811,7 +3811,6 @@ struct page *f2fs_get_lock_data_page(struct inode *inode, pgoff_t index, struct page *f2fs_get_new_data_page(struct inode *inode, struct page *ipage, pgoff_t index, bool new_i_size); int f2fs_do_write_data_page(struct f2fs_io_info *fio); -void f2fs_do_map_lock(struct f2fs_sb_info *sbi, int flag, bool lock); int f2fs_map_blocks(struct inode *inode, struct f2fs_map_blocks *map, int create, int flag); int f2fs_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c index 6426b50b70b8..705a7eb4df99 100644 --- a/fs/f2fs/file.c +++ b/fs/f2fs/file.c @@ -113,10 +113,8 @@ static vm_fault_t f2fs_vm_page_mkwrite(struct vm_fault *vmf) if (need_alloc) { /* block allocation */ - f2fs_do_map_lock(sbi, F2FS_GET_BLOCK_PRE_AIO, true); set_new_dnode(&dn, inode, NULL, NULL, 0); - err = f2fs_get_block(&dn, page->index); - f2fs_do_map_lock(sbi, F2FS_GET_BLOCK_PRE_AIO, false); + err = f2fs_get_block_locked(&dn, page->index); } #ifdef CONFIG_F2FS_FS_COMPRESSION -- cgit v1.2.3 From 2f51ade9524c609fcc4b05f230ecda356cd10b85 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 28 Nov 2022 10:15:16 +0100 Subject: f2fs: f2fs_do_map_lock Split f2fs_do_map_lock into a lock and unlock helper to make the code using it easier to read. Signed-off-by: Christoph Hellwig Reviewed-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/data.c | 45 +++++++++++++++++++++++---------------------- 1 file changed, 23 insertions(+), 22 deletions(-) (limited to 'fs/f2fs') diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c index 904dfd1f16d0..212f2797e379 100644 --- a/fs/f2fs/data.c +++ b/fs/f2fs/data.c @@ -1451,19 +1451,20 @@ alloc: return 0; } -static void f2fs_do_map_lock(struct f2fs_sb_info *sbi, int flag, bool lock) +static void f2fs_map_lock(struct f2fs_sb_info *sbi, int flag) { - if (flag == F2FS_GET_BLOCK_PRE_AIO) { - if (lock) - f2fs_down_read(&sbi->node_change); - else - f2fs_up_read(&sbi->node_change); - } else { - if (lock) - f2fs_lock_op(sbi); - else - f2fs_unlock_op(sbi); - } + if (flag == F2FS_GET_BLOCK_PRE_AIO) + f2fs_down_read(&sbi->node_change); + else + f2fs_lock_op(sbi); +} + +static void f2fs_map_unlock(struct f2fs_sb_info *sbi, int flag) +{ + if (flag == F2FS_GET_BLOCK_PRE_AIO) + f2fs_up_read(&sbi->node_change); + else + f2fs_unlock_op(sbi); } int f2fs_get_block_locked(struct dnode_of_data *dn, pgoff_t index) @@ -1471,9 +1472,9 @@ int f2fs_get_block_locked(struct dnode_of_data *dn, pgoff_t index) struct f2fs_sb_info *sbi = F2FS_I_SB(dn->inode); int err; - f2fs_do_map_lock(sbi, F2FS_GET_BLOCK_PRE_AIO, true); + f2fs_map_lock(sbi, F2FS_GET_BLOCK_PRE_AIO); err = f2fs_get_block(dn, index); - f2fs_do_map_lock(sbi, F2FS_GET_BLOCK_PRE_AIO, false); + f2fs_map_unlock(sbi, F2FS_GET_BLOCK_PRE_AIO); return err; } @@ -1548,7 +1549,7 @@ int f2fs_map_blocks(struct inode *inode, struct f2fs_map_blocks *map, next_dnode: if (map->m_may_create) - f2fs_do_map_lock(sbi, flag, true); + f2fs_map_lock(sbi, flag); /* When reading holes, we need its node page */ set_new_dnode(&dn, inode, NULL, NULL, 0); @@ -1732,7 +1733,7 @@ skip: f2fs_put_dnode(&dn); if (map->m_may_create) { - f2fs_do_map_lock(sbi, flag, false); + f2fs_map_unlock(sbi, flag); f2fs_balance_fs(sbi, dn.node_changed); } goto next_dnode; @@ -1778,7 +1779,7 @@ sync_out: f2fs_put_dnode(&dn); unlock_out: if (map->m_may_create) { - f2fs_do_map_lock(sbi, flag, false); + f2fs_map_unlock(sbi, flag); f2fs_balance_fs(sbi, dn.node_changed); } out: @@ -3350,7 +3351,7 @@ static int prepare_write_begin(struct f2fs_sb_info *sbi, if (f2fs_has_inline_data(inode) || (pos & PAGE_MASK) >= i_size_read(inode)) { - f2fs_do_map_lock(sbi, flag, true); + f2fs_map_lock(sbi, flag); locked = true; } @@ -3385,7 +3386,7 @@ restart: err = f2fs_get_dnode_of_data(&dn, index, LOOKUP_NODE); if (err || dn.data_blkaddr == NULL_ADDR) { f2fs_put_dnode(&dn); - f2fs_do_map_lock(sbi, F2FS_GET_BLOCK_PRE_AIO, true); + f2fs_map_lock(sbi, F2FS_GET_BLOCK_PRE_AIO); WARN_ON(flag != F2FS_GET_BLOCK_PRE_AIO); locked = true; goto restart; @@ -3399,7 +3400,7 @@ out: f2fs_put_dnode(&dn); unlock_out: if (locked) - f2fs_do_map_lock(sbi, flag, false); + f2fs_map_unlock(sbi, flag); return err; } @@ -3438,7 +3439,7 @@ static int __reserve_data_block(struct inode *inode, pgoff_t index, struct page *ipage; int err = 0; - f2fs_do_map_lock(sbi, F2FS_GET_BLOCK_PRE_AIO, true); + f2fs_map_lock(sbi, F2FS_GET_BLOCK_PRE_AIO); ipage = f2fs_get_node_page(sbi, inode->i_ino); if (IS_ERR(ipage)) { @@ -3454,7 +3455,7 @@ static int __reserve_data_block(struct inode *inode, pgoff_t index, f2fs_put_dnode(&dn); unlock_out: - f2fs_do_map_lock(sbi, F2FS_GET_BLOCK_PRE_AIO, false); + f2fs_map_unlock(sbi, F2FS_GET_BLOCK_PRE_AIO); return err; } -- cgit v1.2.3 From 44b0dfebbd829c64c242c0c6ee10f8a88ecfa8b3 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 28 Nov 2022 10:15:17 +0100 Subject: f2fs: reflow prepare_write_begin Reflow prepare_write_begin so that it reads more straight forward, and so that there is one place that does an extent cache lookup instead of three, two of which are hidden in f2fs_get_block calls. Signed-off-by: Christoph Hellwig Reviewed-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/data.c | 61 ++++++++++++++++++++++++++++++---------------------------- 1 file changed, 32 insertions(+), 29 deletions(-) (limited to 'fs/f2fs') diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c index 212f2797e379..efd3ebaa4fc8 100644 --- a/fs/f2fs/data.c +++ b/fs/f2fs/data.c @@ -3333,8 +3333,8 @@ static int prepare_write_begin(struct f2fs_sb_info *sbi, struct dnode_of_data dn; struct page *ipage; bool locked = false; + int flag = F2FS_GET_BLOCK_PRE_AIO; int err = 0; - int flag; /* * If a whole page is being written and we already preallocated all the @@ -3344,13 +3344,12 @@ static int prepare_write_begin(struct f2fs_sb_info *sbi, return 0; /* f2fs_lock_op avoids race between write CP and convert_inline_page */ - if (f2fs_has_inline_data(inode) && pos + len > MAX_INLINE_DATA(inode)) - flag = F2FS_GET_BLOCK_DEFAULT; - else - flag = F2FS_GET_BLOCK_PRE_AIO; - - if (f2fs_has_inline_data(inode) || - (pos & PAGE_MASK) >= i_size_read(inode)) { + if (f2fs_has_inline_data(inode)) { + if (pos + len > MAX_INLINE_DATA(inode)) + flag = F2FS_GET_BLOCK_DEFAULT; + f2fs_map_lock(sbi, flag); + locked = true; + } else if ((pos & PAGE_MASK) >= i_size_read(inode)) { f2fs_map_lock(sbi, flag); locked = true; } @@ -3371,32 +3370,36 @@ restart: set_inode_flag(inode, FI_DATA_EXIST); if (inode->i_nlink) set_page_private_inline(ipage); - } else { - err = f2fs_convert_inline_page(&dn, page); - if (err) - goto out; - if (dn.data_blkaddr == NULL_ADDR) - err = f2fs_get_block(&dn, index); + goto out; } - } else if (locked) { - err = f2fs_get_block(&dn, index); - } else if (!f2fs_lookup_read_extent_cache_block(inode, index, - &dn.data_blkaddr)) { + err = f2fs_convert_inline_page(&dn, page); + if (err || dn.data_blkaddr != NULL_ADDR) + goto out; + } + + if (!f2fs_lookup_read_extent_cache_block(inode, index, + &dn.data_blkaddr)) { + if (locked) { + err = f2fs_reserve_block(&dn, index); + goto out; + } + /* hole case */ err = f2fs_get_dnode_of_data(&dn, index, LOOKUP_NODE); - if (err || dn.data_blkaddr == NULL_ADDR) { - f2fs_put_dnode(&dn); - f2fs_map_lock(sbi, F2FS_GET_BLOCK_PRE_AIO); - WARN_ON(flag != F2FS_GET_BLOCK_PRE_AIO); - locked = true; - goto restart; - } + if (!err && dn.data_blkaddr != NULL_ADDR) + goto out; + f2fs_put_dnode(&dn); + f2fs_map_lock(sbi, F2FS_GET_BLOCK_PRE_AIO); + WARN_ON(flag != F2FS_GET_BLOCK_PRE_AIO); + locked = true; + goto restart; } - - /* convert_inline_page can make node_changed */ - *blk_addr = dn.data_blkaddr; - *node_changed = dn.node_changed; out: + if (!err) { + /* convert_inline_page can make node_changed */ + *blk_addr = dn.data_blkaddr; + *node_changed = dn.node_changed; + } f2fs_put_dnode(&dn); unlock_out: if (locked) -- cgit v1.2.3 From 3cf684f2f8e0229714fb6d051508b42d3320e78f Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 28 Nov 2022 10:15:18 +0100 Subject: f2fs: simplify __allocate_data_block Just use a simple if block for the conditional call to inc_valid_block_count. Signed-off-by: Christoph Hellwig Reviewed-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/data.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) (limited to 'fs/f2fs') diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c index efd3ebaa4fc8..697020cef820 100644 --- a/fs/f2fs/data.c +++ b/fs/f2fs/data.c @@ -1431,13 +1431,12 @@ static int __allocate_data_block(struct dnode_of_data *dn, int seg_type) return err; dn->data_blkaddr = f2fs_data_blkaddr(dn); - if (dn->data_blkaddr != NULL_ADDR) - goto alloc; - - if (unlikely((err = inc_valid_block_count(sbi, dn->inode, &count)))) - return err; + if (dn->data_blkaddr == NULL_ADDR) { + err = inc_valid_block_count(sbi, dn->inode, &count); + if (unlikely(err)) + return err; + } -alloc: set_summary(&sum, dn->nid, dn->ofs_in_node, ni.version); old_blkaddr = dn->data_blkaddr; f2fs_allocate_data_block(sbi, NULL, old_blkaddr, &dn->data_blkaddr, -- cgit v1.2.3 From ffdeab71d5cf0bcd45467b3badb3a1ef8f19a565 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 28 Nov 2022 10:15:19 +0100 Subject: f2fs: remove f2fs_get_block Fold f2fs_get_block into the two remaining callers to simplify the call chain a bit. Signed-off-by: Christoph Hellwig Reviewed-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/data.c | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) (limited to 'fs/f2fs') diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c index 697020cef820..e6f94591717b 100644 --- a/fs/f2fs/data.c +++ b/fs/f2fs/data.c @@ -1212,14 +1212,6 @@ int f2fs_reserve_block(struct dnode_of_data *dn, pgoff_t index) return err; } -static int f2fs_get_block(struct dnode_of_data *dn, pgoff_t index) -{ - if (f2fs_lookup_read_extent_cache_block(dn->inode, index, - &dn->data_blkaddr)) - return 0; - return f2fs_reserve_block(dn, index); -} - struct page *f2fs_get_read_data_page(struct inode *inode, pgoff_t index, blk_opf_t op_flags, bool for_write, pgoff_t *next_pgofs) @@ -1469,10 +1461,12 @@ static void f2fs_map_unlock(struct f2fs_sb_info *sbi, int flag) int f2fs_get_block_locked(struct dnode_of_data *dn, pgoff_t index) { struct f2fs_sb_info *sbi = F2FS_I_SB(dn->inode); - int err; + int err = 0; f2fs_map_lock(sbi, F2FS_GET_BLOCK_PRE_AIO); - err = f2fs_get_block(dn, index); + if (!f2fs_lookup_read_extent_cache_block(dn->inode, index, + &dn->data_blkaddr)) + err = f2fs_reserve_block(dn, index); f2fs_map_unlock(sbi, F2FS_GET_BLOCK_PRE_AIO); return err; @@ -3450,7 +3444,9 @@ static int __reserve_data_block(struct inode *inode, pgoff_t index, } set_new_dnode(&dn, inode, ipage, ipage, 0); - err = f2fs_get_block(&dn, index); + if (!f2fs_lookup_read_extent_cache_block(dn.inode, index, + &dn.data_blkaddr)) + err = f2fs_reserve_block(&dn, index); *blk_addr = dn.data_blkaddr; *node_changed = dn.node_changed; -- cgit v1.2.3 From cd8fc5226bef3a1fda13a0e61794a039ca46744a Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 28 Nov 2022 10:15:20 +0100 Subject: f2fs: remove the create argument to f2fs_map_blocks The create argument is always identicaly to map->m_may_create, so use that consistently. Signed-off-by: Christoph Hellwig Reviewed-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/data.c | 63 +++++++++++++++++++-------------------------- fs/f2fs/f2fs.h | 3 +-- fs/f2fs/file.c | 12 ++++----- include/trace/events/f2fs.h | 11 +++----- 4 files changed, 38 insertions(+), 51 deletions(-) (limited to 'fs/f2fs') diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c index e6f94591717b..1cc5c6cb3146 100644 --- a/fs/f2fs/data.c +++ b/fs/f2fs/data.c @@ -1477,8 +1477,7 @@ int f2fs_get_block_locked(struct dnode_of_data *dn, pgoff_t index) * maps continuous logical blocks to physical blocks, and return such * info via f2fs_map_blocks structure. */ -int f2fs_map_blocks(struct inode *inode, struct f2fs_map_blocks *map, - int create, int flag) +int f2fs_map_blocks(struct inode *inode, struct f2fs_map_blocks *map, int flag) { unsigned int maxblocks = map->m_len; struct dnode_of_data dn; @@ -1507,38 +1506,31 @@ int f2fs_map_blocks(struct inode *inode, struct f2fs_map_blocks *map, pgofs = (pgoff_t)map->m_lblk; end = pgofs + maxblocks; - if (!create && f2fs_lookup_read_extent_cache(inode, pgofs, &ei)) { - if (f2fs_lfs_mode(sbi) && flag == F2FS_GET_BLOCK_DIO && - map->m_may_create) - goto next_dnode; + if (map->m_may_create || + !f2fs_lookup_read_extent_cache(inode, pgofs, &ei)) + goto next_dnode; - map->m_pblk = ei.blk + pgofs - ei.fofs; - map->m_len = min((pgoff_t)maxblocks, ei.fofs + ei.len - pgofs); - map->m_flags = F2FS_MAP_MAPPED; - if (map->m_next_extent) - *map->m_next_extent = pgofs + map->m_len; + /* Found the map in read extent cache */ + map->m_pblk = ei.blk + pgofs - ei.fofs; + map->m_len = min((pgoff_t)maxblocks, ei.fofs + ei.len - pgofs); + map->m_flags = F2FS_MAP_MAPPED; + if (map->m_next_extent) + *map->m_next_extent = pgofs + map->m_len; - /* for hardware encryption, but to avoid potential issue in future */ - if (flag == F2FS_GET_BLOCK_DIO) - f2fs_wait_on_block_writeback_range(inode, + /* for hardware encryption, but to avoid potential issue in future */ + if (flag == F2FS_GET_BLOCK_DIO) + f2fs_wait_on_block_writeback_range(inode, map->m_pblk, map->m_len); - if (map->m_multidev_dio) { - block_t blk_addr = map->m_pblk; - - bidx = f2fs_target_device_index(sbi, map->m_pblk); + if (map->m_multidev_dio) { + bidx = f2fs_target_device_index(sbi, map->m_pblk); - map->m_bdev = FDEV(bidx).bdev; - map->m_pblk -= FDEV(bidx).start_blk; - map->m_len = min(map->m_len, + map->m_bdev = FDEV(bidx).bdev; + map->m_pblk -= FDEV(bidx).start_blk; + map->m_len = min(map->m_len, FDEV(bidx).end_blk + 1 - map->m_pblk); - - if (map->m_may_create) - f2fs_update_device_state(sbi, inode->i_ino, - blk_addr, map->m_len); - } - goto out; } + goto out; next_dnode: if (map->m_may_create) @@ -1602,7 +1594,7 @@ next_block: set_inode_flag(inode, FI_APPEND_WRITE); } } else { - if (create) { + if (map->m_may_create) { if (unlikely(f2fs_cp_error(sbi))) { err = -EIO; goto sync_out; @@ -1776,7 +1768,7 @@ unlock_out: f2fs_balance_fs(sbi, dn.node_changed); } out: - trace_f2fs_map_blocks(inode, map, create, flag, err); + trace_f2fs_map_blocks(inode, map, flag, err); return err; } @@ -1798,7 +1790,7 @@ bool f2fs_overwrite_io(struct inode *inode, loff_t pos, size_t len) while (map.m_lblk < last_lblk) { map.m_len = last_lblk - map.m_lblk; - err = f2fs_map_blocks(inode, &map, 0, F2FS_GET_BLOCK_DEFAULT); + err = f2fs_map_blocks(inode, &map, F2FS_GET_BLOCK_DEFAULT); if (err || map.m_len == 0) return false; map.m_lblk += map.m_len; @@ -1972,7 +1964,7 @@ next: map.m_len = cluster_size - count_in_cluster; } - ret = f2fs_map_blocks(inode, &map, 0, F2FS_GET_BLOCK_FIEMAP); + ret = f2fs_map_blocks(inode, &map, F2FS_GET_BLOCK_FIEMAP); if (ret) goto out; @@ -2105,7 +2097,7 @@ static int f2fs_read_single_page(struct inode *inode, struct page *page, map->m_lblk = block_in_file; map->m_len = last_block - block_in_file; - ret = f2fs_map_blocks(inode, map, 0, F2FS_GET_BLOCK_DEFAULT); + ret = f2fs_map_blocks(inode, map, F2FS_GET_BLOCK_DEFAULT); if (ret) goto out; got_it: @@ -3807,7 +3799,7 @@ static sector_t f2fs_bmap(struct address_space *mapping, sector_t block) map.m_next_pgofs = NULL; map.m_seg_type = NO_CHECK_TYPE; - if (!f2fs_map_blocks(inode, &map, 0, F2FS_GET_BLOCK_BMAP)) + if (!f2fs_map_blocks(inode, &map, F2FS_GET_BLOCK_BMAP)) blknr = map.m_pblk; } out: @@ -3915,7 +3907,7 @@ retry: map.m_seg_type = NO_CHECK_TYPE; map.m_may_create = false; - ret = f2fs_map_blocks(inode, &map, 0, F2FS_GET_BLOCK_FIEMAP); + ret = f2fs_map_blocks(inode, &map, F2FS_GET_BLOCK_FIEMAP); if (ret) goto out; @@ -4140,8 +4132,7 @@ static int f2fs_iomap_begin(struct inode *inode, loff_t offset, loff_t length, if (flags & IOMAP_WRITE) map.m_may_create = true; - err = f2fs_map_blocks(inode, &map, flags & IOMAP_WRITE, - F2FS_GET_BLOCK_DIO); + err = f2fs_map_blocks(inode, &map, F2FS_GET_BLOCK_DIO); if (err) return err; diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index 744cb442085f..60f421fe14ee 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h @@ -3811,8 +3811,7 @@ struct page *f2fs_get_lock_data_page(struct inode *inode, pgoff_t index, struct page *f2fs_get_new_data_page(struct inode *inode, struct page *ipage, pgoff_t index, bool new_i_size); int f2fs_do_write_data_page(struct f2fs_io_info *fio); -int f2fs_map_blocks(struct inode *inode, struct f2fs_map_blocks *map, - int create, int flag); +int f2fs_map_blocks(struct inode *inode, struct f2fs_map_blocks *map, int flag); int f2fs_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, u64 start, u64 len); int f2fs_encrypt_one_page(struct f2fs_io_info *fio); diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c index 705a7eb4df99..939c7247c367 100644 --- a/fs/f2fs/file.c +++ b/fs/f2fs/file.c @@ -1743,7 +1743,7 @@ next_alloc: f2fs_unlock_op(sbi); map.m_seg_type = CURSEG_COLD_DATA_PINNED; - err = f2fs_map_blocks(inode, &map, 1, F2FS_GET_BLOCK_PRE_DIO); + err = f2fs_map_blocks(inode, &map, F2FS_GET_BLOCK_PRE_DIO); file_dont_truncate(inode); f2fs_up_write(&sbi->pin_sem); @@ -1756,7 +1756,7 @@ next_alloc: map.m_len = expanded; } else { - err = f2fs_map_blocks(inode, &map, 1, F2FS_GET_BLOCK_PRE_AIO); + err = f2fs_map_blocks(inode, &map, F2FS_GET_BLOCK_PRE_AIO); expanded = map.m_len; } out_err: @@ -2604,7 +2604,7 @@ static int f2fs_defragment_range(struct f2fs_sb_info *sbi, */ while (map.m_lblk < pg_end) { map.m_len = pg_end - map.m_lblk; - err = f2fs_map_blocks(inode, &map, 0, F2FS_GET_BLOCK_DEFAULT); + err = f2fs_map_blocks(inode, &map, F2FS_GET_BLOCK_DEFAULT); if (err) goto out; @@ -2651,7 +2651,7 @@ static int f2fs_defragment_range(struct f2fs_sb_info *sbi, do_map: map.m_len = pg_end - map.m_lblk; - err = f2fs_map_blocks(inode, &map, 0, F2FS_GET_BLOCK_DEFAULT); + err = f2fs_map_blocks(inode, &map, F2FS_GET_BLOCK_DEFAULT); if (err) goto clear_out; @@ -3225,7 +3225,7 @@ int f2fs_precache_extents(struct inode *inode) map.m_len = end - map.m_lblk; f2fs_down_write(&fi->i_gc_rwsem[WRITE]); - err = f2fs_map_blocks(inode, &map, 0, F2FS_GET_BLOCK_PRECACHE); + err = f2fs_map_blocks(inode, &map, F2FS_GET_BLOCK_PRECACHE); f2fs_up_write(&fi->i_gc_rwsem[WRITE]); if (err) return err; @@ -4464,7 +4464,7 @@ static int f2fs_preallocate_blocks(struct kiocb *iocb, struct iov_iter *iter, flag = F2FS_GET_BLOCK_PRE_AIO; } - ret = f2fs_map_blocks(inode, &map, 1, flag); + ret = f2fs_map_blocks(inode, &map, flag); /* -ENOSPC|-EDQUOT are fine to report the number of allocated blocks. */ if (ret < 0 && !((ret == -ENOSPC || ret == -EDQUOT) && map.m_len > 0)) return ret; diff --git a/include/trace/events/f2fs.h b/include/trace/events/f2fs.h index 31d994e6b4ca..9183a0a11e26 100644 --- a/include/trace/events/f2fs.h +++ b/include/trace/events/f2fs.h @@ -569,10 +569,10 @@ TRACE_EVENT(f2fs_file_write_iter, ); TRACE_EVENT(f2fs_map_blocks, - TP_PROTO(struct inode *inode, struct f2fs_map_blocks *map, - int create, int flag, int ret), + TP_PROTO(struct inode *inode, struct f2fs_map_blocks *map, int flag, + int ret), - TP_ARGS(inode, map, create, flag, ret), + TP_ARGS(inode, map, flag, ret), TP_STRUCT__entry( __field(dev_t, dev) @@ -584,7 +584,6 @@ TRACE_EVENT(f2fs_map_blocks, __field(int, m_seg_type) __field(bool, m_may_create) __field(bool, m_multidev_dio) - __field(int, create) __field(int, flag) __field(int, ret) ), @@ -599,7 +598,6 @@ TRACE_EVENT(f2fs_map_blocks, __entry->m_seg_type = map->m_seg_type; __entry->m_may_create = map->m_may_create; __entry->m_multidev_dio = map->m_multidev_dio; - __entry->create = create; __entry->flag = flag; __entry->ret = ret; ), @@ -607,7 +605,7 @@ TRACE_EVENT(f2fs_map_blocks, TP_printk("dev = (%d,%d), ino = %lu, file offset = %llu, " "start blkaddr = 0x%llx, len = 0x%llx, flags = %u, " "seg_type = %d, may_create = %d, multidevice = %d, " - "create = %d, flag = %d, err = %d", + "flag = %d, err = %d", show_dev_ino(__entry), (unsigned long long)__entry->m_lblk, (unsigned long long)__entry->m_pblk, @@ -616,7 +614,6 @@ TRACE_EVENT(f2fs_map_blocks, __entry->m_seg_type, __entry->m_may_create, __entry->m_multidev_dio, - __entry->create, __entry->flag, __entry->ret) ); -- cgit v1.2.3 From 0094e98bd1477a6b7d97c25b47b19a7317c35279 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 28 Nov 2022 10:15:21 +0100 Subject: f2fs: factor a f2fs_map_blocks_cached helper Add a helper to deal with everything needed to return a f2fs_map_blocks structure based on a lookup in the extent cache. Signed-off-by: Christoph Hellwig Reviewed-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/data.c | 65 ++++++++++++++++++++++++++++++++++------------------------ 1 file changed, 38 insertions(+), 27 deletions(-) (limited to 'fs/f2fs') diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c index 1cc5c6cb3146..cb77f64e521e 100644 --- a/fs/f2fs/data.c +++ b/fs/f2fs/data.c @@ -1472,6 +1472,41 @@ int f2fs_get_block_locked(struct dnode_of_data *dn, pgoff_t index) return err; } +static bool f2fs_map_blocks_cached(struct inode *inode, + struct f2fs_map_blocks *map, int flag) +{ + struct f2fs_sb_info *sbi = F2FS_I_SB(inode); + unsigned int maxblocks = map->m_len; + pgoff_t pgoff = (pgoff_t)map->m_lblk; + struct extent_info ei = {}; + + if (!f2fs_lookup_read_extent_cache(inode, pgoff, &ei)) + return false; + + map->m_pblk = ei.blk + pgoff - ei.fofs; + map->m_len = min((pgoff_t)maxblocks, ei.fofs + ei.len - pgoff); + map->m_flags = F2FS_MAP_MAPPED; + if (map->m_next_extent) + *map->m_next_extent = pgoff + map->m_len; + + /* for hardware encryption, but to avoid potential issue in future */ + if (flag == F2FS_GET_BLOCK_DIO) + f2fs_wait_on_block_writeback_range(inode, + map->m_pblk, map->m_len); + + if (f2fs_allow_multi_device_dio(sbi, flag)) { + int bidx = f2fs_target_device_index(sbi, map->m_pblk); + struct f2fs_dev_info *dev = &sbi->devs[bidx]; + + map->m_bdev = dev->bdev; + map->m_pblk -= dev->start_blk; + map->m_len = min(map->m_len, dev->end_blk + 1 - map->m_pblk); + } else { + map->m_bdev = inode->i_sb->s_bdev; + } + return true; +} + /* * f2fs_map_blocks() tries to find or build mapping relationship which * maps continuous logical blocks to physical blocks, and return such @@ -1487,7 +1522,6 @@ int f2fs_map_blocks(struct inode *inode, struct f2fs_map_blocks *map, int flag) int err = 0, ofs = 1; unsigned int ofs_in_node, last_ofs_in_node; blkcnt_t prealloc; - struct extent_info ei = {0, }; block_t blkaddr; unsigned int start_pgofs; int bidx = 0; @@ -1495,6 +1529,9 @@ int f2fs_map_blocks(struct inode *inode, struct f2fs_map_blocks *map, int flag) if (!maxblocks) return 0; + if (!map->m_may_create && f2fs_map_blocks_cached(inode, map, flag)) + goto out; + map->m_bdev = inode->i_sb->s_bdev; map->m_multidev_dio = f2fs_allow_multi_device_dio(F2FS_I_SB(inode), flag); @@ -1506,32 +1543,6 @@ int f2fs_map_blocks(struct inode *inode, struct f2fs_map_blocks *map, int flag) pgofs = (pgoff_t)map->m_lblk; end = pgofs + maxblocks; - if (map->m_may_create || - !f2fs_lookup_read_extent_cache(inode, pgofs, &ei)) - goto next_dnode; - - /* Found the map in read extent cache */ - map->m_pblk = ei.blk + pgofs - ei.fofs; - map->m_len = min((pgoff_t)maxblocks, ei.fofs + ei.len - pgofs); - map->m_flags = F2FS_MAP_MAPPED; - if (map->m_next_extent) - *map->m_next_extent = pgofs + map->m_len; - - /* for hardware encryption, but to avoid potential issue in future */ - if (flag == F2FS_GET_BLOCK_DIO) - f2fs_wait_on_block_writeback_range(inode, - map->m_pblk, map->m_len); - - if (map->m_multidev_dio) { - bidx = f2fs_target_device_index(sbi, map->m_pblk); - - map->m_bdev = FDEV(bidx).bdev; - map->m_pblk -= FDEV(bidx).start_blk; - map->m_len = min(map->m_len, - FDEV(bidx).end_blk + 1 - map->m_pblk); - } - goto out; - next_dnode: if (map->m_may_create) f2fs_map_lock(sbi, flag); -- cgit v1.2.3 From 817c968b79d02588370e3d1dc5e5961cfd57d2b1 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 28 Nov 2022 10:15:22 +0100 Subject: f2fs: factor out a f2fs_map_no_dnode Factor out a helper to return a hole when no dnode was found. Signed-off-by: Christoph Hellwig Reviewed-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/data.c | 47 ++++++++++++++++++++++++----------------------- 1 file changed, 24 insertions(+), 23 deletions(-) (limited to 'fs/f2fs') diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c index cb77f64e521e..2f05d6f75083 100644 --- a/fs/f2fs/data.c +++ b/fs/f2fs/data.c @@ -1472,6 +1472,28 @@ int f2fs_get_block_locked(struct dnode_of_data *dn, pgoff_t index) return err; } +static int f2fs_map_no_dnode(struct inode *inode, + struct f2fs_map_blocks *map, struct dnode_of_data *dn, + pgoff_t pgoff) +{ + struct f2fs_sb_info *sbi = F2FS_I_SB(inode); + + /* + * There is one exceptional case that read_node_page() may return + * -ENOENT due to filesystem has been shutdown or cp_error, return + * -EIO in that case. + */ + if (map->m_may_create && + (is_sbi_flag_set(sbi, SBI_IS_SHUTDOWN) || f2fs_cp_error(sbi))) + return -EIO; + + if (map->m_next_pgofs) + *map->m_next_pgofs = f2fs_get_next_page_offset(dn, pgoff); + if (map->m_next_extent) + *map->m_next_extent = f2fs_get_next_page_offset(dn, pgoff); + return 0; +} + static bool f2fs_map_blocks_cached(struct inode *inode, struct f2fs_map_blocks *map, int flag) { @@ -1553,29 +1575,8 @@ next_dnode: if (err) { if (flag == F2FS_GET_BLOCK_BMAP) map->m_pblk = 0; - - if (err == -ENOENT) { - /* - * There is one exceptional case that read_node_page() - * may return -ENOENT due to filesystem has been - * shutdown or cp_error, so force to convert error - * number to EIO for such case. - */ - if (map->m_may_create && - (is_sbi_flag_set(sbi, SBI_IS_SHUTDOWN) || - f2fs_cp_error(sbi))) { - err = -EIO; - goto unlock_out; - } - - err = 0; - if (map->m_next_pgofs) - *map->m_next_pgofs = - f2fs_get_next_page_offset(&dn, pgofs); - if (map->m_next_extent) - *map->m_next_extent = - f2fs_get_next_page_offset(&dn, pgofs); - } + if (err == -ENOENT) + err = f2fs_map_no_dnode(inode, map, &dn, pgofs); goto unlock_out; } -- cgit v1.2.3 From fdbf69a7f5be2896af3a9a6213fb0ab8e194b190 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 28 Nov 2022 10:15:23 +0100 Subject: f2fs: refactor the hole reporting and allocation logic in f2fs_map_blocks Add a is_hole local variable to figure out if the block number might need allocation, and untangle to logic to report the hole or fill it with a block allocation. Signed-off-by: Christoph Hellwig Reviewed-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/data.c | 113 ++++++++++++++++++++++++++++----------------------------- 1 file changed, 56 insertions(+), 57 deletions(-) (limited to 'fs/f2fs') diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c index 2f05d6f75083..c25ae041c0a5 100644 --- a/fs/f2fs/data.c +++ b/fs/f2fs/data.c @@ -1547,6 +1547,7 @@ int f2fs_map_blocks(struct inode *inode, struct f2fs_map_blocks *map, int flag) block_t blkaddr; unsigned int start_pgofs; int bidx = 0; + bool is_hole; if (!maxblocks) return 0; @@ -1587,78 +1588,76 @@ next_dnode: next_block: blkaddr = f2fs_data_blkaddr(&dn); - - if (__is_valid_data_blkaddr(blkaddr) && - !f2fs_is_valid_blkaddr(sbi, blkaddr, DATA_GENERIC_ENHANCE)) { + is_hole = !__is_valid_data_blkaddr(blkaddr); + if (!is_hole && + !f2fs_is_valid_blkaddr(sbi, blkaddr, DATA_GENERIC_ENHANCE)) { err = -EFSCORRUPTED; f2fs_handle_error(sbi, ERROR_INVALID_BLKADDR); goto sync_out; } - if (__is_valid_data_blkaddr(blkaddr)) { - /* use out-place-update for driect IO under LFS mode */ - if (f2fs_lfs_mode(sbi) && flag == F2FS_GET_BLOCK_DIO && - map->m_may_create) { + /* use out-place-update for direct IO under LFS mode */ + if (map->m_may_create && + (is_hole || (f2fs_lfs_mode(sbi) && flag == F2FS_GET_BLOCK_DIO))) { + if (unlikely(f2fs_cp_error(sbi))) { + err = -EIO; + goto sync_out; + } + + switch (flag) { + case F2FS_GET_BLOCK_PRE_AIO: + if (blkaddr == NULL_ADDR) { + prealloc++; + last_ofs_in_node = dn.ofs_in_node; + } + break; + case F2FS_GET_BLOCK_PRE_DIO: + case F2FS_GET_BLOCK_DIO: err = __allocate_data_block(&dn, map->m_seg_type); if (err) goto sync_out; - blkaddr = dn.data_blkaddr; + if (flag == F2FS_GET_BLOCK_PRE_DIO) + file_need_truncate(inode); set_inode_flag(inode, FI_APPEND_WRITE); + break; + default: + WARN_ON_ONCE(1); + err = -EIO; + goto sync_out; } - } else { - if (map->m_may_create) { - if (unlikely(f2fs_cp_error(sbi))) { - err = -EIO; - goto sync_out; - } - if (flag == F2FS_GET_BLOCK_PRE_AIO) { - if (blkaddr == NULL_ADDR) { - prealloc++; - last_ofs_in_node = dn.ofs_in_node; - } - } else { - WARN_ON(flag != F2FS_GET_BLOCK_PRE_DIO && - flag != F2FS_GET_BLOCK_DIO); - err = __allocate_data_block(&dn, - map->m_seg_type); - if (!err) { - if (flag == F2FS_GET_BLOCK_PRE_DIO) - file_need_truncate(inode); - set_inode_flag(inode, FI_APPEND_WRITE); - } - } - if (err) - goto sync_out; + + blkaddr = dn.data_blkaddr; + if (is_hole) map->m_flags |= F2FS_MAP_NEW; - blkaddr = dn.data_blkaddr; - } else { - if (f2fs_compressed_file(inode) && - f2fs_sanity_check_cluster(&dn) && - (flag != F2FS_GET_BLOCK_FIEMAP || - IS_ENABLED(CONFIG_F2FS_CHECK_FS))) { - err = -EFSCORRUPTED; - f2fs_handle_error(sbi, - ERROR_CORRUPTED_CLUSTER); - goto sync_out; - } - if (flag == F2FS_GET_BLOCK_BMAP) { - map->m_pblk = 0; - goto sync_out; - } - if (flag == F2FS_GET_BLOCK_PRECACHE) - goto sync_out; - if (flag == F2FS_GET_BLOCK_FIEMAP && - blkaddr == NULL_ADDR) { - if (map->m_next_pgofs) - *map->m_next_pgofs = pgofs + 1; - goto sync_out; - } - if (flag != F2FS_GET_BLOCK_FIEMAP) { - /* for defragment case */ + } else if (is_hole) { + if (f2fs_compressed_file(inode) && + f2fs_sanity_check_cluster(&dn) && + (flag != F2FS_GET_BLOCK_FIEMAP || + IS_ENABLED(CONFIG_F2FS_CHECK_FS))) { + err = -EFSCORRUPTED; + f2fs_handle_error(sbi, + ERROR_CORRUPTED_CLUSTER); + goto sync_out; + } + + switch (flag) { + case F2FS_GET_BLOCK_PRECACHE: + goto sync_out; + case F2FS_GET_BLOCK_BMAP: + map->m_pblk = 0; + goto sync_out; + case F2FS_GET_BLOCK_FIEMAP: + if (blkaddr == NULL_ADDR) { if (map->m_next_pgofs) *map->m_next_pgofs = pgofs + 1; goto sync_out; } + break; + default: + /* for defragment case */ + if (map->m_next_pgofs) + *map->m_next_pgofs = pgofs + 1; + goto sync_out; } } -- cgit v1.2.3 From fdb7ccc3f9cb316c399b072c7a75a106678eb421 Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Sat, 19 Nov 2022 03:18:39 +0800 Subject: f2fs: introduce IS_F2FS_IPU_* macro IS_F2FS_IPU_* macro can be used to identify whether f2fs ipu related policies are enabled. BTW, convert to use BIT() instead of open code. Signed-off-by: Yangtao Li Signed-off-by: Jaegeuk Kim --- fs/f2fs/data.c | 25 ++++++++++--------------- fs/f2fs/segment.c | 4 ++-- fs/f2fs/segment.h | 15 +++++++++++++++ fs/f2fs/super.c | 4 ++-- 4 files changed, 29 insertions(+), 19 deletions(-) (limited to 'fs/f2fs') diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c index c25ae041c0a5..60fb44a200c1 100644 --- a/fs/f2fs/data.c +++ b/fs/f2fs/data.c @@ -2539,34 +2539,29 @@ static inline bool check_inplace_update_policy(struct inode *inode, struct f2fs_io_info *fio) { struct f2fs_sb_info *sbi = F2FS_I_SB(inode); - unsigned int policy = SM_I(sbi)->ipu_policy; - if (policy & (0x1 << F2FS_IPU_HONOR_OPU_WRITE) && - is_inode_flag_set(inode, FI_OPU_WRITE)) + if (IS_F2FS_IPU_HONOR_OPU_WRITE(sbi) && + is_inode_flag_set(inode, FI_OPU_WRITE)) return false; - if (policy & (0x1 << F2FS_IPU_FORCE)) + if (IS_F2FS_IPU_FORCE(sbi)) return true; - if (policy & (0x1 << F2FS_IPU_SSR) && f2fs_need_SSR(sbi)) + if (IS_F2FS_IPU_SSR(sbi) && f2fs_need_SSR(sbi)) return true; - if (policy & (0x1 << F2FS_IPU_UTIL) && - utilization(sbi) > SM_I(sbi)->min_ipu_util) + if (IS_F2FS_IPU_UTIL(sbi) && utilization(sbi) > SM_I(sbi)->min_ipu_util) return true; - if (policy & (0x1 << F2FS_IPU_SSR_UTIL) && f2fs_need_SSR(sbi) && - utilization(sbi) > SM_I(sbi)->min_ipu_util) + if (IS_F2FS_IPU_SSR_UTIL(sbi) && f2fs_need_SSR(sbi) && + utilization(sbi) > SM_I(sbi)->min_ipu_util) return true; /* * IPU for rewrite async pages */ - if (policy & (0x1 << F2FS_IPU_ASYNC) && - fio && fio->op == REQ_OP_WRITE && - !(fio->op_flags & REQ_SYNC) && - !IS_ENCRYPTED(inode)) + if (IS_F2FS_IPU_ASYNC(sbi) && fio && fio->op == REQ_OP_WRITE && + !(fio->op_flags & REQ_SYNC) && !IS_ENCRYPTED(inode)) return true; /* this is only set during fdatasync */ - if (policy & (0x1 << F2FS_IPU_FSYNC) && - is_inode_flag_set(inode, FI_NEED_IPU)) + if (IS_F2FS_IPU_FSYNC(sbi) && is_inode_flag_set(inode, FI_NEED_IPU)) return true; if (unlikely(fio && is_sbi_flag_set(sbi, SBI_CP_DISABLED) && diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c index ae3c4e5474ef..37117cb530ae 100644 --- a/fs/f2fs/segment.c +++ b/fs/f2fs/segment.c @@ -3487,7 +3487,7 @@ int f2fs_inplace_write_data(struct f2fs_io_info *fio) stat_inc_inplace_blocks(fio->sbi); - if (fio->bio && !(SM_I(sbi)->ipu_policy & (1 << F2FS_IPU_NOCACHE))) + if (fio->bio && !IS_F2FS_IPU_NOCACHE(sbi)) err = f2fs_merge_page_bio(fio); else err = f2fs_submit_page_bio(fio); @@ -5126,7 +5126,7 @@ int f2fs_build_segment_manager(struct f2fs_sb_info *sbi) sm_info->rec_prefree_segments = DEF_MAX_RECLAIM_PREFREE_SEGMENTS; if (!f2fs_lfs_mode(sbi)) - sm_info->ipu_policy = 1 << F2FS_IPU_FSYNC; + sm_info->ipu_policy = BIT(F2FS_IPU_FSYNC); sm_info->min_ipu_util = DEF_MIN_IPU_UTIL; sm_info->min_fsync_blocks = DEF_MIN_FSYNC_BLOCKS; sm_info->min_seq_blocks = sbi->blocks_per_seg; diff --git a/fs/f2fs/segment.h b/fs/f2fs/segment.h index 3ad1b7b6fa94..e77518c49f38 100644 --- a/fs/f2fs/segment.h +++ b/fs/f2fs/segment.h @@ -681,6 +681,21 @@ enum { F2FS_IPU_HONOR_OPU_WRITE, }; +#define F2FS_IPU_POLICY(name) \ +static inline int IS_##name(struct f2fs_sb_info *sbi) \ +{ \ + return SM_I(sbi)->ipu_policy & BIT(name); \ +} + +F2FS_IPU_POLICY(F2FS_IPU_FORCE); +F2FS_IPU_POLICY(F2FS_IPU_SSR); +F2FS_IPU_POLICY(F2FS_IPU_UTIL); +F2FS_IPU_POLICY(F2FS_IPU_SSR_UTIL); +F2FS_IPU_POLICY(F2FS_IPU_FSYNC); +F2FS_IPU_POLICY(F2FS_IPU_ASYNC); +F2FS_IPU_POLICY(F2FS_IPU_NOCACHE); +F2FS_IPU_POLICY(F2FS_IPU_HONOR_OPU_WRITE); + static inline unsigned int curseg_segno(struct f2fs_sb_info *sbi, int type) { diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c index 1f812b9ce985..87d56a9883e6 100644 --- a/fs/f2fs/super.c +++ b/fs/f2fs/super.c @@ -4089,8 +4089,8 @@ static void f2fs_tuning_parameters(struct f2fs_sb_info *sbi) if (f2fs_block_unit_discard(sbi)) SM_I(sbi)->dcc_info->discard_granularity = MIN_DISCARD_GRANULARITY; - SM_I(sbi)->ipu_policy = 1 << F2FS_IPU_FORCE | - 1 << F2FS_IPU_HONOR_OPU_WRITE; + SM_I(sbi)->ipu_policy = BIT(F2FS_IPU_FORCE) | + BIT(F2FS_IPU_HONOR_OPU_WRITE); } sbi->readdir_ra = true; -- cgit v1.2.3 From 5eaac835f27f2de6b73412d7c24e755733b49de0 Mon Sep 17 00:00:00 2001 From: Chao Yu Date: Fri, 16 Dec 2022 23:50:00 +0800 Subject: f2fs: fix to avoid potential deadlock There is a potential deadlock reported by syzbot as below: F2FS-fs (loop2): invalid crc value F2FS-fs (loop2): Found nat_bits in checkpoint F2FS-fs (loop2): Mounted with checkpoint version = 48b305e4 ====================================================== WARNING: possible circular locking dependency detected 6.1.0-rc8-syzkaller-33330-ga5541c0811a0 #0 Not tainted ------------------------------------------------------ syz-executor.2/32123 is trying to acquire lock: ffff0000c0e1a608 (&mm->mmap_lock){++++}-{3:3}, at: __might_fault+0x54/0xb4 mm/memory.c:5644 but task is already holding lock: ffff0001317c6088 (&sbi->sb_lock){++++}-{3:3}, at: f2fs_down_write fs/f2fs/f2fs.h:2205 [inline] ffff0001317c6088 (&sbi->sb_lock){++++}-{3:3}, at: f2fs_ioc_get_encryption_pwsalt fs/f2fs/file.c:2334 [inline] ffff0001317c6088 (&sbi->sb_lock){++++}-{3:3}, at: __f2fs_ioctl+0x1370/0x3318 fs/f2fs/file.c:4151 which lock already depends on the new lock. Chain exists of: &mm->mmap_lock --> &nm_i->nat_tree_lock --> &sbi->sb_lock Possible unsafe locking scenario: CPU0 CPU1 ---- ---- lock(&sbi->sb_lock); lock(&nm_i->nat_tree_lock); lock(&sbi->sb_lock); lock(&mm->mmap_lock); Let's try to avoid above deadlock condition by moving __might_fault() out of sbi->sb_lock coverage. Fixes: 95fa90c9e5a7 ("f2fs: support recording errors into superblock") Link: https://lore.kernel.org/linux-f2fs-devel/000000000000cd5fe305ef617fe2@google.com/T/#u Reported-by: syzbot+4793f6096d174c90b4f7@syzkaller.appspotmail.com Signed-off-by: Chao Yu Reviewed-by: Eric Biggers Signed-off-by: Jaegeuk Kim --- fs/f2fs/file.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'fs/f2fs') diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c index 939c7247c367..bef0ee57e88d 100644 --- a/fs/f2fs/file.c +++ b/fs/f2fs/file.c @@ -2336,6 +2336,7 @@ static int f2fs_ioc_get_encryption_pwsalt(struct file *filp, unsigned long arg) { struct inode *inode = file_inode(filp); struct f2fs_sb_info *sbi = F2FS_I_SB(inode); + u8 encrypt_pw_salt[16]; int err; if (!f2fs_sb_has_encrypt(sbi)) @@ -2360,12 +2361,14 @@ static int f2fs_ioc_get_encryption_pwsalt(struct file *filp, unsigned long arg) goto out_err; } got_it: - if (copy_to_user((__u8 __user *)arg, sbi->raw_super->encrypt_pw_salt, - 16)) - err = -EFAULT; + memcpy(encrypt_pw_salt, sbi->raw_super->encrypt_pw_salt, 16); out_err: f2fs_up_write(&sbi->sb_lock); mnt_drop_write_file(filp); + + if (!err && copy_to_user((__u8 __user *)arg, encrypt_pw_salt, 16)) + err = -EFAULT; + return err; } -- cgit v1.2.3 From 8358014d6be8f3cb507d247d6a623e5961f848d0 Mon Sep 17 00:00:00 2001 From: Chao Yu Date: Thu, 15 Dec 2022 14:05:06 +0800 Subject: f2fs: avoid to check PG_error flag After below changes: commit 14db0b3c7b83 ("fscrypt: stop using PG_error to track error status") commit 98dc08bae678 ("fsverity: stop using PG_error to track error status") There is no place in f2fs we will set PG_error flag in page, let's remove other PG_error usage in f2fs, as a step towards freeing the PG_error flag for other uses. Cc: Eric Biggers Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/data.c | 2 -- fs/f2fs/gc.c | 1 - fs/f2fs/inline.c | 1 - fs/f2fs/node.c | 3 --- fs/f2fs/segment.c | 1 - 5 files changed, 8 deletions(-) (limited to 'fs/f2fs') diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c index 60fb44a200c1..af906ed6d53d 100644 --- a/fs/f2fs/data.c +++ b/fs/f2fs/data.c @@ -2701,7 +2701,6 @@ got_it: goto out_writepage; set_page_writeback(page); - ClearPageError(page); f2fs_put_dnode(&dn); if (fio->need_lock == LOCK_REQ) f2fs_unlock_op(fio->sbi); @@ -2737,7 +2736,6 @@ got_it: goto out_writepage; set_page_writeback(page); - ClearPageError(page); if (fio->compr_blocks && fio->old_blkaddr == COMPRESS_ADDR) f2fs_i_compr_blocks_update(inode, fio->compr_blocks - 1, false); diff --git a/fs/f2fs/gc.c b/fs/f2fs/gc.c index 83e68ec7763d..7444c392eab1 100644 --- a/fs/f2fs/gc.c +++ b/fs/f2fs/gc.c @@ -1364,7 +1364,6 @@ static int move_data_block(struct inode *inode, block_t bidx, dec_page_count(fio.sbi, F2FS_DIRTY_META); set_page_writeback(fio.encrypted_page); - ClearPageError(page); fio.op = REQ_OP_WRITE; fio.op_flags = REQ_SYNC; diff --git a/fs/f2fs/inline.c b/fs/f2fs/inline.c index 21a495234ffd..08e302d32118 100644 --- a/fs/f2fs/inline.c +++ b/fs/f2fs/inline.c @@ -174,7 +174,6 @@ int f2fs_convert_inline_page(struct dnode_of_data *dn, struct page *page) /* write data page to try to make data consistent */ set_page_writeback(page); - ClearPageError(page); fio.old_blkaddr = dn->data_blkaddr; set_inode_flag(dn->inode, FI_HOT_DATA); f2fs_outplace_write_data(dn, &fio); diff --git a/fs/f2fs/node.c b/fs/f2fs/node.c index dde4c0458704..558b318f7316 100644 --- a/fs/f2fs/node.c +++ b/fs/f2fs/node.c @@ -1650,7 +1650,6 @@ static int __write_node_page(struct page *page, bool atomic, bool *submitted, } set_page_writeback(page); - ClearPageError(page); fio.old_blkaddr = ni.blk_addr; f2fs_do_write_node_page(nid, &fio); @@ -2079,8 +2078,6 @@ int f2fs_wait_on_node_pages_writeback(struct f2fs_sb_info *sbi, spin_unlock_irqrestore(&sbi->fsync_node_lock, flags); f2fs_wait_on_page_writeback(page, NODE, true, false); - if (TestClearPageError(page)) - ret = -EIO; put_page(page); diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c index 37117cb530ae..a27ffc627264 100644 --- a/fs/f2fs/segment.c +++ b/fs/f2fs/segment.c @@ -3422,7 +3422,6 @@ void f2fs_do_write_meta_page(struct f2fs_sb_info *sbi, struct page *page, fio.op_flags &= ~REQ_META; set_page_writeback(page); - ClearPageError(page); f2fs_submit_page_write(&fio); stat_inc_meta_count(sbi, page->index); -- cgit v1.2.3 From 185a453bf1b5688f8c77f2646b0b6f3b1cbdddca Mon Sep 17 00:00:00 2001 From: Yuwei Guan Date: Tue, 13 Dec 2022 17:34:19 +0800 Subject: f2fs: deliver the accumulated 'issued' to __issue_discard_cmd_orderly() Any of the following scenarios will send more than the number of max_requests at a time, which will not meet the design of the max_requests limit. - Set max_ordered_discard larger than discard_granularity from userspace. - It is a small size device, discard_granularity can be tuned to 1 in f2fs_tuning_parameters(). We need to deliver the accumulated @issued to __issue_discard_cmd_orderly() to meet the max_requests limit. BTW, convert the parameter type of @issued in __submit_discard_cmd(). Signed-off-by: Yuwei Guan Cc: Bagas Sanjaya Reviewed-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/segment.c | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) (limited to 'fs/f2fs') diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c index a27ffc627264..e2f95f46d298 100644 --- a/fs/f2fs/segment.c +++ b/fs/f2fs/segment.c @@ -1095,9 +1095,8 @@ static void __update_discard_tree_range(struct f2fs_sb_info *sbi, block_t start, block_t len); /* this function is copied from blkdev_issue_discard from block/blk-lib.c */ static int __submit_discard_cmd(struct f2fs_sb_info *sbi, - struct discard_policy *dpolicy, - struct discard_cmd *dc, - unsigned int *issued) + struct discard_policy *dpolicy, + struct discard_cmd *dc, int *issued) { struct block_device *bdev = dc->bdev; unsigned int max_discard_blocks = @@ -1378,8 +1377,8 @@ static void __queue_discard_cmd(struct f2fs_sb_info *sbi, mutex_unlock(&SM_I(sbi)->dcc_info->cmd_lock); } -static unsigned int __issue_discard_cmd_orderly(struct f2fs_sb_info *sbi, - struct discard_policy *dpolicy) +static void __issue_discard_cmd_orderly(struct f2fs_sb_info *sbi, + struct discard_policy *dpolicy, int *issued) { struct discard_cmd_control *dcc = SM_I(sbi)->dcc_info; struct discard_cmd *prev_dc = NULL, *next_dc = NULL; @@ -1387,7 +1386,6 @@ static unsigned int __issue_discard_cmd_orderly(struct f2fs_sb_info *sbi, struct discard_cmd *dc; struct blk_plug plug; unsigned int pos = dcc->next_pos; - unsigned int issued = 0; bool io_interrupted = false; mutex_lock(&dcc->cmd_lock); @@ -1414,9 +1412,9 @@ static unsigned int __issue_discard_cmd_orderly(struct f2fs_sb_info *sbi, } dcc->next_pos = dc->lstart + dc->len; - err = __submit_discard_cmd(sbi, dpolicy, dc, &issued); + err = __submit_discard_cmd(sbi, dpolicy, dc, issued); - if (issued >= dpolicy->max_requests) + if (*issued >= dpolicy->max_requests) break; next: node = rb_next(&dc->rb_node); @@ -1432,10 +1430,8 @@ next: mutex_unlock(&dcc->cmd_lock); - if (!issued && io_interrupted) - issued = -1; - - return issued; + if (!(*issued) && io_interrupted) + *issued = -1; } static unsigned int __wait_all_discard_cmd(struct f2fs_sb_info *sbi, struct discard_policy *dpolicy); @@ -1463,8 +1459,10 @@ retry: if (i + 1 < dpolicy->granularity) break; - if (i + 1 < dcc->max_ordered_discard && dpolicy->ordered) - return __issue_discard_cmd_orderly(sbi, dpolicy); + if (i + 1 < dcc->max_ordered_discard && dpolicy->ordered) { + __issue_discard_cmd_orderly(sbi, dpolicy, &issued); + return issued; + } pend_list = &dcc->pend_list[i]; -- cgit v1.2.3 From ebaaec351e4fef86afe38002b6a8c15178fd3610 Mon Sep 17 00:00:00 2001 From: Zhang Qilong Date: Tue, 6 Sep 2022 22:53:47 +0800 Subject: f2fs: start freeing cluster pages from the unused number We can start freeing cluster page(s) from which compression is not used. It will get better performance. Signed-off-by: Zhang Qilong Signed-off-by: Jaegeuk Kim --- fs/f2fs/compress.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'fs/f2fs') diff --git a/fs/f2fs/compress.c b/fs/f2fs/compress.c index e4db3b7932a3..dd1caba46eed 100644 --- a/fs/f2fs/compress.c +++ b/fs/f2fs/compress.c @@ -690,9 +690,7 @@ static int f2fs_compress_pages(struct compress_ctx *cc) vm_unmap_ram(cc->cbuf, cc->nr_cpages); vm_unmap_ram(cc->rbuf, cc->cluster_size); - for (i = 0; i < cc->nr_cpages; i++) { - if (i < new_nr_cpages) - continue; + for (i = new_nr_cpages; i < cc->nr_cpages; i++) { f2fs_compress_free_page(cc->cpages[i]); cc->cpages[i] = NULL; } -- cgit v1.2.3 From b5a711acab305e04278c136c841ba37c589c16a1 Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Tue, 29 Nov 2022 20:29:28 +0800 Subject: f2fs: judge whether discard_unit is section only when have CONFIG_BLK_DEV_ZONED The current logic, regardless of whether CONFIG_BLK_DEV_ZONED is enabled or not, will judge whether discard_unit is SECTION, when f2fs_sb_has_blkzoned. In fact, when CONFIG_BLK_DEV_ZONED is not enabled, this judgment is a path that will never be accessed. At this time, -EINVAL will be returned in the parse_options function, accompanied by the message "Zoned block device support is not enabled". Let's wrap this discard_unit judgment with CONFIG_BLK_DEV_ZONED. Signed-off-by: Yangtao Li Reviewed-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/super.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) (limited to 'fs/f2fs') diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c index 87d56a9883e6..1d057a4c6642 100644 --- a/fs/f2fs/super.c +++ b/fs/f2fs/super.c @@ -1294,19 +1294,18 @@ default_check: * zone alignment optimization. This is optional for host-aware * devices, but mandatory for host-managed zoned block devices. */ -#ifndef CONFIG_BLK_DEV_ZONED - if (f2fs_sb_has_blkzoned(sbi)) { - f2fs_err(sbi, "Zoned block device support is not enabled"); - return -EINVAL; - } -#endif if (f2fs_sb_has_blkzoned(sbi)) { +#ifdef CONFIG_BLK_DEV_ZONED if (F2FS_OPTION(sbi).discard_unit != DISCARD_UNIT_SECTION) { f2fs_info(sbi, "Zoned block device doesn't need small discard, set discard_unit=section by default"); F2FS_OPTION(sbi).discard_unit = DISCARD_UNIT_SECTION; } +#else + f2fs_err(sbi, "Zoned block device support is not enabled"); + return -EINVAL; +#endif } #ifdef CONFIG_F2FS_FS_COMPRESSION -- cgit v1.2.3 From a1357a91ec9ee72cf7683ac17b5f26dd5b4e6e5f Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Thu, 29 Dec 2022 21:18:28 +0800 Subject: f2fs: mark f2fs_init_compress_mempool w/ __init f2fs_init_compress_mempool() only initializes the memory pool during the f2fs module init phase. Let's mark it as __init like any other function. Signed-off-by: Yangtao Li Reviewed-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/compress.c | 2 +- fs/f2fs/f2fs.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'fs/f2fs') diff --git a/fs/f2fs/compress.c b/fs/f2fs/compress.c index dd1caba46eed..b196b881f3bb 100644 --- a/fs/f2fs/compress.c +++ b/fs/f2fs/compress.c @@ -564,7 +564,7 @@ module_param(num_compress_pages, uint, 0444); MODULE_PARM_DESC(num_compress_pages, "Number of intermediate compress pages to preallocate"); -int f2fs_init_compress_mempool(void) +int __init f2fs_init_compress_mempool(void) { compress_page_pool = mempool_create_page_pool(num_compress_pages, 0); return compress_page_pool ? 0 : -ENOMEM; diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index 60f421fe14ee..378734b0d99a 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h @@ -4251,7 +4251,7 @@ bool f2fs_compress_write_end(struct inode *inode, void *fsdata, int f2fs_truncate_partial_cluster(struct inode *inode, u64 from, bool lock); void f2fs_compress_write_end_io(struct bio *bio, struct page *page); bool f2fs_is_compress_backend_ready(struct inode *inode); -int f2fs_init_compress_mempool(void); +int __init f2fs_init_compress_mempool(void); void f2fs_destroy_compress_mempool(void); void f2fs_decompress_cluster(struct decompress_io_ctx *dic, bool in_task); void f2fs_end_read_compressed_page(struct page *page, bool failed, @@ -4320,7 +4320,7 @@ static inline struct page *f2fs_compress_control_page(struct page *page) WARN_ON_ONCE(1); return ERR_PTR(-EINVAL); } -static inline int f2fs_init_compress_mempool(void) { return 0; } +static inline int __init f2fs_init_compress_mempool(void) { return 0; } static inline void f2fs_destroy_compress_mempool(void) { } static inline void f2fs_decompress_cluster(struct decompress_io_ctx *dic, bool in_task) { } -- cgit v1.2.3 From 390d0b99212e42c6f9116562a8442888f6a0141d Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Thu, 22 Dec 2022 03:26:34 +0800 Subject: f2fs: remove unnecessary blank lines Just cleanup. Signed-off-by: Yangtao Li Signed-off-by: Jaegeuk Kim --- fs/f2fs/f2fs.h | 2 -- 1 file changed, 2 deletions(-) (limited to 'fs/f2fs') diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index 378734b0d99a..d1fcaa973a53 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h @@ -1382,8 +1382,6 @@ enum { MEMORY_MODE_LOW, /* memory mode for low memry devices */ }; - - static inline int f2fs_test_bit(unsigned int nr, char *addr); static inline void f2fs_set_bit(unsigned int nr, char *addr); static inline void f2fs_clear_bit(unsigned int nr, char *addr); -- cgit v1.2.3 From 1cd7565449de6e838ff5a3fa75fbd2ce58c6d955 Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Wed, 21 Dec 2022 03:12:12 +0800 Subject: f2fs: add a f2fs_ prefix to punch_hole() and expand_inode_data() For example, f2fs_collapse_range(), f2fs_collapse_range(), f2fs_insert_range(), the functions used in f2fs_fallocate() are all prefixed with f2fs_, so let's keep the name consistent. Signed-off-by: Yangtao Li Reviewed-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/file.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'fs/f2fs') diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c index bef0ee57e88d..58b4200f7fdf 100644 --- a/fs/f2fs/file.c +++ b/fs/f2fs/file.c @@ -1110,7 +1110,7 @@ int f2fs_truncate_hole(struct inode *inode, pgoff_t pg_start, pgoff_t pg_end) return 0; } -static int punch_hole(struct inode *inode, loff_t offset, loff_t len) +static int f2fs_punch_hole(struct inode *inode, loff_t offset, loff_t len) { pgoff_t pg_start, pg_end; loff_t off_start, off_end; @@ -1682,7 +1682,7 @@ static int f2fs_insert_range(struct inode *inode, loff_t offset, loff_t len) return ret; } -static int expand_inode_data(struct inode *inode, loff_t offset, +static int f2fs_expand_inode_data(struct inode *inode, loff_t offset, loff_t len, int mode) { struct f2fs_sb_info *sbi = F2FS_I_SB(inode); @@ -1830,7 +1830,7 @@ static long f2fs_fallocate(struct file *file, int mode, if (offset >= inode->i_size) goto out; - ret = punch_hole(inode, offset, len); + ret = f2fs_punch_hole(inode, offset, len); } else if (mode & FALLOC_FL_COLLAPSE_RANGE) { ret = f2fs_collapse_range(inode, offset, len); } else if (mode & FALLOC_FL_ZERO_RANGE) { @@ -1838,7 +1838,7 @@ static long f2fs_fallocate(struct file *file, int mode, } else if (mode & FALLOC_FL_INSERT_RANGE) { ret = f2fs_insert_range(inode, offset, len); } else { - ret = expand_inode_data(inode, offset, len, mode); + ret = f2fs_expand_inode_data(inode, offset, len, mode); } if (!ret) { -- cgit v1.2.3 From c40e15a9a59f79e79d9500f1fd019321ec35b959 Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Wed, 21 Dec 2022 02:39:04 +0800 Subject: f2fs: merge f2fs_show_injection_info() into time_to_inject() There is no need to additionally use f2fs_show_injection_info() to output information. Concatenate time_to_inject() and __time_to_inject() via a macro. In the new __time_to_inject() function, pass in the caller function name and parent function. In this way, we no longer need the f2fs_show_injection_info() function, and let's remove it. Suggested-by: Chao Yu Signed-off-by: Yangtao Li Reviewed-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/checkpoint.c | 5 +---- fs/f2fs/data.c | 8 ++------ fs/f2fs/dir.c | 4 +--- fs/f2fs/f2fs.h | 44 ++++++++++++++------------------------------ fs/f2fs/file.c | 4 +--- fs/f2fs/gc.c | 4 +--- fs/f2fs/inode.c | 4 +--- fs/f2fs/node.c | 4 +--- fs/f2fs/segment.c | 5 +---- fs/f2fs/super.c | 8 ++------ 10 files changed, 25 insertions(+), 65 deletions(-) (limited to 'fs/f2fs') diff --git a/fs/f2fs/checkpoint.c b/fs/f2fs/checkpoint.c index 56f7d0d6a8b2..d68b3c991888 100644 --- a/fs/f2fs/checkpoint.c +++ b/fs/f2fs/checkpoint.c @@ -171,10 +171,8 @@ static bool __is_bitmap_valid(struct f2fs_sb_info *sbi, block_t blkaddr, bool f2fs_is_valid_blkaddr(struct f2fs_sb_info *sbi, block_t blkaddr, int type) { - if (time_to_inject(sbi, FAULT_BLKADDR)) { - f2fs_show_injection_info(sbi, FAULT_BLKADDR); + if (time_to_inject(sbi, FAULT_BLKADDR)) return false; - } switch (type) { case META_NAT: @@ -622,7 +620,6 @@ int f2fs_acquire_orphan_inode(struct f2fs_sb_info *sbi) if (time_to_inject(sbi, FAULT_ORPHAN)) { spin_unlock(&im->ino_lock); - f2fs_show_injection_info(sbi, FAULT_ORPHAN); return -ENOSPC; } diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c index af906ed6d53d..c940da1c540f 100644 --- a/fs/f2fs/data.c +++ b/fs/f2fs/data.c @@ -295,10 +295,8 @@ static void f2fs_read_end_io(struct bio *bio) iostat_update_and_unbind_ctx(bio, 0); ctx = bio->bi_private; - if (time_to_inject(sbi, FAULT_READ_IO)) { - f2fs_show_injection_info(sbi, FAULT_READ_IO); + if (time_to_inject(sbi, FAULT_READ_IO)) bio->bi_status = BLK_STS_IOERR; - } if (bio->bi_status) { f2fs_finish_read_bio(bio, intask); @@ -335,10 +333,8 @@ static void f2fs_write_end_io(struct bio *bio) iostat_update_and_unbind_ctx(bio, 1); sbi = bio->bi_private; - if (time_to_inject(sbi, FAULT_WRITE_IO)) { - f2fs_show_injection_info(sbi, FAULT_WRITE_IO); + if (time_to_inject(sbi, FAULT_WRITE_IO)) bio->bi_status = BLK_STS_IOERR; - } bio_for_each_segment_all(bvec, bio, iter_all) { struct page *page = bvec->bv_page; diff --git a/fs/f2fs/dir.c b/fs/f2fs/dir.c index 8e025157f35c..9ccdbe120425 100644 --- a/fs/f2fs/dir.c +++ b/fs/f2fs/dir.c @@ -732,10 +732,8 @@ int f2fs_add_regular_entry(struct inode *dir, const struct f2fs_filename *fname, } start: - if (time_to_inject(F2FS_I_SB(dir), FAULT_DIR_DEPTH)) { - f2fs_show_injection_info(F2FS_I_SB(dir), FAULT_DIR_DEPTH); + if (time_to_inject(F2FS_I_SB(dir), FAULT_DIR_DEPTH)) return -ENOSPC; - } if (unlikely(current_depth == MAX_DIR_HASH_DEPTH)) return -ENOSPC; diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index d1fcaa973a53..53d7ca96df63 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h @@ -1867,12 +1867,10 @@ struct f2fs_sb_info { }; #ifdef CONFIG_F2FS_FAULT_INJECTION -#define f2fs_show_injection_info(sbi, type) \ - printk_ratelimited("%sF2FS-fs (%s) : inject %s in %s of %pS\n", \ - KERN_INFO, sbi->sb->s_id, \ - f2fs_fault_name[type], \ - __func__, __builtin_return_address(0)) -static inline bool time_to_inject(struct f2fs_sb_info *sbi, int type) +#define time_to_inject(sbi, type) __time_to_inject(sbi, type, __func__, \ + __builtin_return_address(0)) +static inline bool __time_to_inject(struct f2fs_sb_info *sbi, int type, + const char *func, const char *parent_func) { struct f2fs_fault_info *ffi = &F2FS_OPTION(sbi).fault_info; @@ -1885,12 +1883,14 @@ static inline bool time_to_inject(struct f2fs_sb_info *sbi, int type) atomic_inc(&ffi->inject_ops); if (atomic_read(&ffi->inject_ops) >= ffi->inject_rate) { atomic_set(&ffi->inject_ops, 0); + printk_ratelimited("%sF2FS-fs (%s) : inject %s in %s of %pS\n", + KERN_INFO, sbi->sb->s_id, f2fs_fault_name[type], + func, parent_func); return true; } return false; } #else -#define f2fs_show_injection_info(sbi, type) do { } while (0) static inline bool time_to_inject(struct f2fs_sb_info *sbi, int type) { return false; @@ -2223,10 +2223,8 @@ static inline void f2fs_lock_op(struct f2fs_sb_info *sbi) static inline int f2fs_trylock_op(struct f2fs_sb_info *sbi) { - if (time_to_inject(sbi, FAULT_LOCK_OP)) { - f2fs_show_injection_info(sbi, FAULT_LOCK_OP); + if (time_to_inject(sbi, FAULT_LOCK_OP)) return 0; - } return f2fs_down_read_trylock(&sbi->cp_rwsem); } @@ -2314,7 +2312,6 @@ static inline int inc_valid_block_count(struct f2fs_sb_info *sbi, return ret; if (time_to_inject(sbi, FAULT_BLOCK)) { - f2fs_show_injection_info(sbi, FAULT_BLOCK); release = *count; goto release_quota; } @@ -2594,10 +2591,8 @@ static inline int inc_valid_node_count(struct f2fs_sb_info *sbi, return err; } - if (time_to_inject(sbi, FAULT_BLOCK)) { - f2fs_show_injection_info(sbi, FAULT_BLOCK); + if (time_to_inject(sbi, FAULT_BLOCK)) goto enospc; - } spin_lock(&sbi->stat_lock); @@ -2721,11 +2716,8 @@ static inline struct page *f2fs_grab_cache_page(struct address_space *mapping, if (page) return page; - if (time_to_inject(F2FS_M_SB(mapping), FAULT_PAGE_ALLOC)) { - f2fs_show_injection_info(F2FS_M_SB(mapping), - FAULT_PAGE_ALLOC); + if (time_to_inject(F2FS_M_SB(mapping), FAULT_PAGE_ALLOC)) return NULL; - } } if (!for_write) @@ -2742,10 +2734,8 @@ static inline struct page *f2fs_pagecache_get_page( struct address_space *mapping, pgoff_t index, int fgp_flags, gfp_t gfp_mask) { - if (time_to_inject(F2FS_M_SB(mapping), FAULT_PAGE_GET)) { - f2fs_show_injection_info(F2FS_M_SB(mapping), FAULT_PAGE_GET); + if (time_to_inject(F2FS_M_SB(mapping), FAULT_PAGE_GET)) return NULL; - } return pagecache_get_page(mapping, index, fgp_flags, gfp_mask); } @@ -2795,10 +2785,8 @@ static inline void *f2fs_kmem_cache_alloc(struct kmem_cache *cachep, if (nofail) return f2fs_kmem_cache_alloc_nofail(cachep, flags); - if (time_to_inject(sbi, FAULT_SLAB_ALLOC)) { - f2fs_show_injection_info(sbi, FAULT_SLAB_ALLOC); + if (time_to_inject(sbi, FAULT_SLAB_ALLOC)) return NULL; - } return kmem_cache_alloc(cachep, flags); } @@ -3372,10 +3360,8 @@ static inline bool is_dot_dotdot(const u8 *name, size_t len) static inline void *f2fs_kmalloc(struct f2fs_sb_info *sbi, size_t size, gfp_t flags) { - if (time_to_inject(sbi, FAULT_KMALLOC)) { - f2fs_show_injection_info(sbi, FAULT_KMALLOC); + if (time_to_inject(sbi, FAULT_KMALLOC)) return NULL; - } return kmalloc(size, flags); } @@ -3389,10 +3375,8 @@ static inline void *f2fs_kzalloc(struct f2fs_sb_info *sbi, static inline void *f2fs_kvmalloc(struct f2fs_sb_info *sbi, size_t size, gfp_t flags) { - if (time_to_inject(sbi, FAULT_KVMALLOC)) { - f2fs_show_injection_info(sbi, FAULT_KVMALLOC); + if (time_to_inject(sbi, FAULT_KVMALLOC)) return NULL; - } return kvmalloc(size, flags); } diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c index 58b4200f7fdf..f5c1b7814954 100644 --- a/fs/f2fs/file.c +++ b/fs/f2fs/file.c @@ -782,10 +782,8 @@ int f2fs_truncate(struct inode *inode) trace_f2fs_truncate(inode); - if (time_to_inject(F2FS_I_SB(inode), FAULT_TRUNCATE)) { - f2fs_show_injection_info(F2FS_I_SB(inode), FAULT_TRUNCATE); + if (time_to_inject(F2FS_I_SB(inode), FAULT_TRUNCATE)) return -EIO; - } err = f2fs_dquot_initialize(inode); if (err) diff --git a/fs/f2fs/gc.c b/fs/f2fs/gc.c index 7444c392eab1..e59c006c10f7 100644 --- a/fs/f2fs/gc.c +++ b/fs/f2fs/gc.c @@ -72,11 +72,9 @@ static int gc_thread_func(void *data) continue; } - if (time_to_inject(sbi, FAULT_CHECKPOINT)) { - f2fs_show_injection_info(sbi, FAULT_CHECKPOINT); + if (time_to_inject(sbi, FAULT_CHECKPOINT)) f2fs_stop_checkpoint(sbi, false, STOP_CP_REASON_FAULT_INJECT); - } if (!sb_start_write_trylock(sbi->sb)) { stat_other_skip_bggc_count(sbi); diff --git a/fs/f2fs/inode.c b/fs/f2fs/inode.c index ff6cf66ed46b..01b9e6f85f6b 100644 --- a/fs/f2fs/inode.c +++ b/fs/f2fs/inode.c @@ -809,10 +809,8 @@ retry: if (F2FS_HAS_BLOCKS(inode)) err = f2fs_truncate(inode); - if (time_to_inject(sbi, FAULT_EVICT_INODE)) { - f2fs_show_injection_info(sbi, FAULT_EVICT_INODE); + if (time_to_inject(sbi, FAULT_EVICT_INODE)) err = -EIO; - } if (!err) { f2fs_lock_op(sbi); diff --git a/fs/f2fs/node.c b/fs/f2fs/node.c index 558b318f7316..fbd1d25fecc2 100644 --- a/fs/f2fs/node.c +++ b/fs/f2fs/node.c @@ -2541,10 +2541,8 @@ bool f2fs_alloc_nid(struct f2fs_sb_info *sbi, nid_t *nid) struct f2fs_nm_info *nm_i = NM_I(sbi); struct free_nid *i = NULL; retry: - if (time_to_inject(sbi, FAULT_ALLOC_NID)) { - f2fs_show_injection_info(sbi, FAULT_ALLOC_NID); + if (time_to_inject(sbi, FAULT_ALLOC_NID)) return false; - } spin_lock(&nm_i->nid_list_lock); diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c index e2f95f46d298..ba8331434703 100644 --- a/fs/f2fs/segment.c +++ b/fs/f2fs/segment.c @@ -384,10 +384,8 @@ int f2fs_commit_atomic_write(struct inode *inode) */ void f2fs_balance_fs(struct f2fs_sb_info *sbi, bool need) { - if (time_to_inject(sbi, FAULT_CHECKPOINT)) { - f2fs_show_injection_info(sbi, FAULT_CHECKPOINT); + if (time_to_inject(sbi, FAULT_CHECKPOINT)) f2fs_stop_checkpoint(sbi, false, STOP_CP_REASON_FAULT_INJECT); - } /* balance_fs_bg is able to be pending */ if (need && excess_cached_nats(sbi)) @@ -1140,7 +1138,6 @@ static int __submit_discard_cmd(struct f2fs_sb_info *sbi, dc->len += len; if (time_to_inject(sbi, FAULT_DISCARD)) { - f2fs_show_injection_info(sbi, FAULT_DISCARD); err = -EIO; } else { err = __blkdev_issue_discard(bdev, diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c index 1d057a4c6642..5fc83771042d 100644 --- a/fs/f2fs/super.c +++ b/fs/f2fs/super.c @@ -1371,10 +1371,8 @@ static struct inode *f2fs_alloc_inode(struct super_block *sb) { struct f2fs_inode_info *fi; - if (time_to_inject(F2FS_SB(sb), FAULT_SLAB_ALLOC)) { - f2fs_show_injection_info(F2FS_SB(sb), FAULT_SLAB_ALLOC); + if (time_to_inject(F2FS_SB(sb), FAULT_SLAB_ALLOC)) return NULL; - } fi = alloc_inode_sb(sb, f2fs_inode_cachep, GFP_F2FS_ZERO); if (!fi) @@ -2594,10 +2592,8 @@ retry: int f2fs_dquot_initialize(struct inode *inode) { - if (time_to_inject(F2FS_I_SB(inode), FAULT_DQUOT_INIT)) { - f2fs_show_injection_info(F2FS_I_SB(inode), FAULT_DQUOT_INIT); + if (time_to_inject(F2FS_I_SB(inode), FAULT_DQUOT_INIT)) return -ESRCH; - } return dquot_initialize(inode); } -- cgit v1.2.3 From f08142bc3a60f5af632ba48dc2fef8797043086d Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Sat, 17 Dec 2022 13:24:48 +0800 Subject: f2fs: convert to use MIN_DISCARD_GRANULARITY macro Commit 1cd2e6d54435 ("f2fs: define MIN_DISCARD_GRANULARITY macro") introduce it, let's convert to use MIN_DISCARD_GRANULARITY macro. Signed-off-by: Yangtao Li Reviewed-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/segment.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'fs/f2fs') diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c index ba8331434703..f8e0ccfa0f52 100644 --- a/fs/f2fs/segment.c +++ b/fs/f2fs/segment.c @@ -1604,9 +1604,9 @@ static unsigned int __wait_all_discard_cmd(struct f2fs_sb_info *sbi, return __wait_discard_cmd_range(sbi, dpolicy, 0, UINT_MAX); /* wait all */ - __init_discard_policy(sbi, &dp, DPOLICY_FSTRIM, 1); + __init_discard_policy(sbi, &dp, DPOLICY_FSTRIM, MIN_DISCARD_GRANULARITY); discard_blks = __wait_discard_cmd_range(sbi, &dp, 0, UINT_MAX); - __init_discard_policy(sbi, &dp, DPOLICY_UMOUNT, 1); + __init_discard_policy(sbi, &dp, DPOLICY_UMOUNT, MIN_DISCARD_GRANULARITY); discard_blks += __wait_discard_cmd_range(sbi, &dp, 0, UINT_MAX); return discard_blks; @@ -1689,7 +1689,8 @@ static int issue_discard_thread(void *data) if (sbi->gc_mode == GC_URGENT_HIGH || !f2fs_available_free_memory(sbi, DISCARD_CACHE)) - __init_discard_policy(sbi, &dpolicy, DPOLICY_FORCE, 1); + __init_discard_policy(sbi, &dpolicy, DPOLICY_FORCE, + MIN_DISCARD_GRANULARITY); else __init_discard_policy(sbi, &dpolicy, DPOLICY_BG, dcc->discard_granularity); -- cgit v1.2.3 From 45c98f5a58f36c35ecf5a149cbf69cf5fd022120 Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Mon, 12 Dec 2022 21:36:44 +0800 Subject: f2fs: convert discard_wake and gc_wake to bool type discard_wake and gc_wake have only two values, 0 or 1. So there is no need to use int type to store them. BTW, move discard_wake to the end of the discard_cmd_control structure. Before: - sizeof(struct discard_cmd_control): 8392 After move: - sizeof(struct discard_cmd_control): 8384 Signed-off-by: Yangtao Li Reviewed-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/f2fs.h | 2 +- fs/f2fs/gc.c | 4 ++-- fs/f2fs/gc.h | 2 +- fs/f2fs/segment.c | 2 +- fs/f2fs/segment.h | 2 +- fs/f2fs/sysfs.c | 4 ++-- 6 files changed, 8 insertions(+), 8 deletions(-) (limited to 'fs/f2fs') diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index 53d7ca96df63..c9c6ae966ba8 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h @@ -402,7 +402,6 @@ struct discard_cmd_control { struct list_head wait_list; /* store on-flushing entries */ struct list_head fstrim_list; /* in-flight discard from fstrim */ wait_queue_head_t discard_wait_queue; /* waiting queue for wake-up */ - unsigned int discard_wake; /* to wake up discard thread */ struct mutex cmd_lock; unsigned int nr_discards; /* # of discards in the list */ unsigned int max_discards; /* max. discards to be issued */ @@ -420,6 +419,7 @@ struct discard_cmd_control { atomic_t discard_cmd_cnt; /* # of cached cmd count */ struct rb_root_cached root; /* root of discard rb-tree */ bool rbtree_check; /* config for consistence check */ + bool discard_wake; /* to wake up discard thread */ }; /* for the list of fsync inodes, used only during recovery */ diff --git a/fs/f2fs/gc.c b/fs/f2fs/gc.c index e59c006c10f7..97e846263c7c 100644 --- a/fs/f2fs/gc.c +++ b/fs/f2fs/gc.c @@ -57,7 +57,7 @@ static int gc_thread_func(void *data) /* give it a try one time */ if (gc_th->gc_wake) - gc_th->gc_wake = 0; + gc_th->gc_wake = false; if (try_to_freeze()) { stat_other_skip_bggc_count(sbi); @@ -183,7 +183,7 @@ int f2fs_start_gc_thread(struct f2fs_sb_info *sbi) gc_th->max_sleep_time = DEF_GC_THREAD_MAX_SLEEP_TIME; gc_th->no_gc_sleep_time = DEF_GC_THREAD_NOGC_SLEEP_TIME; - gc_th->gc_wake = 0; + gc_th->gc_wake = false; sbi->gc_thread = gc_th; init_waitqueue_head(&sbi->gc_thread->gc_wait_queue_head); diff --git a/fs/f2fs/gc.h b/fs/f2fs/gc.h index 19b956c2d697..15bd1d680f67 100644 --- a/fs/f2fs/gc.h +++ b/fs/f2fs/gc.h @@ -41,7 +41,7 @@ struct f2fs_gc_kthread { unsigned int no_gc_sleep_time; /* for changing gc mode */ - unsigned int gc_wake; + bool gc_wake; /* for GC_MERGE mount option */ wait_queue_head_t fggc_wq; /* diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c index f8e0ccfa0f52..8aafa1f32ecc 100644 --- a/fs/f2fs/segment.c +++ b/fs/f2fs/segment.c @@ -1696,7 +1696,7 @@ static int issue_discard_thread(void *data) dcc->discard_granularity); if (dcc->discard_wake) - dcc->discard_wake = 0; + dcc->discard_wake = false; /* clean up pending candidates before going to sleep */ if (atomic_read(&dcc->queued_discard)) diff --git a/fs/f2fs/segment.h b/fs/f2fs/segment.h index e77518c49f38..ad6a9c19f46a 100644 --- a/fs/f2fs/segment.h +++ b/fs/f2fs/segment.h @@ -939,6 +939,6 @@ static inline void wake_up_discard_thread(struct f2fs_sb_info *sbi, bool force) if (!wakeup || !is_idle(sbi, DISCARD_TIME)) return; wake_up: - dcc->discard_wake = 1; + dcc->discard_wake = true; wake_up_interruptible_all(&dcc->discard_wait_queue); } diff --git a/fs/f2fs/sysfs.c b/fs/f2fs/sysfs.c index 83a366f3ee80..805b632a3af0 100644 --- a/fs/f2fs/sysfs.c +++ b/fs/f2fs/sysfs.c @@ -511,7 +511,7 @@ out: } else if (t == 1) { sbi->gc_mode = GC_URGENT_HIGH; if (sbi->gc_thread) { - sbi->gc_thread->gc_wake = 1; + sbi->gc_thread->gc_wake = true; wake_up_interruptible_all( &sbi->gc_thread->gc_wait_queue_head); wake_up_discard_thread(sbi, true); @@ -521,7 +521,7 @@ out: } else if (t == 3) { sbi->gc_mode = GC_URGENT_MID; if (sbi->gc_thread) { - sbi->gc_thread->gc_wake = 1; + sbi->gc_thread->gc_wake = true; wake_up_interruptible_all( &sbi->gc_thread->gc_wait_queue_head); } -- cgit v1.2.3 From 7a2b15cfa8dbbd54beb4e2ce7b2f42eb0ad00425 Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Thu, 22 Dec 2022 03:19:32 +0800 Subject: f2fs: support accounting iostat count and avg_bytes Previously, we supported to account iostat io_bytes, in this patch, it adds to account iostat count and avg_bytes: time: 1671648667 io_bytes count avg_bytes [WRITE] app buffered data: 31 2 15 Signed-off-by: Yangtao Li Reviewed-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/f2fs.h | 7 +-- fs/f2fs/iostat.c | 129 ++++++++++++++++++++++---------------------- fs/f2fs/segment.c | 2 +- include/trace/events/f2fs.h | 2 +- 4 files changed, 69 insertions(+), 71 deletions(-) (limited to 'fs/f2fs') diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index c9c6ae966ba8..d4729f8af247 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h @@ -1191,7 +1191,7 @@ enum iostat_type { FS_META_READ_IO, /* meta read IOs */ /* other */ - FS_DISCARD, /* discard */ + FS_DISCARD_IO, /* discard */ NR_IO_TYPE, }; @@ -1854,8 +1854,9 @@ struct f2fs_sb_info { #ifdef CONFIG_F2FS_IOSTAT /* For app/fs IO statistics */ spinlock_t iostat_lock; - unsigned long long rw_iostat[NR_IO_TYPE]; - unsigned long long prev_rw_iostat[NR_IO_TYPE]; + unsigned long long iostat_count[NR_IO_TYPE]; + unsigned long long iostat_bytes[NR_IO_TYPE]; + unsigned long long prev_iostat_bytes[NR_IO_TYPE]; bool iostat_enable; unsigned long iostat_next_period; unsigned int iostat_period_ms; diff --git a/fs/f2fs/iostat.c b/fs/f2fs/iostat.c index 3166a8939ed4..acf834c77291 100644 --- a/fs/f2fs/iostat.c +++ b/fs/f2fs/iostat.c @@ -18,79 +18,68 @@ static struct kmem_cache *bio_iostat_ctx_cache; static mempool_t *bio_iostat_ctx_pool; +static inline unsigned long long iostat_get_avg_bytes(struct f2fs_sb_info *sbi, + enum iostat_type type) +{ + return sbi->iostat_count[type] ? div64_u64(sbi->iostat_bytes[type], + sbi->iostat_count[type]) : 0; +} + +#define IOSTAT_INFO_SHOW(name, type) \ + seq_printf(seq, "%-23s %-16llu %-16llu %-16llu\n", \ + name":", sbi->iostat_bytes[type], \ + sbi->iostat_count[type], \ + iostat_get_avg_bytes(sbi, type)) + int __maybe_unused iostat_info_seq_show(struct seq_file *seq, void *offset) { struct super_block *sb = seq->private; struct f2fs_sb_info *sbi = F2FS_SB(sb); - time64_t now = ktime_get_real_seconds(); if (!sbi->iostat_enable) return 0; - seq_printf(seq, "time: %-16llu\n", now); + seq_printf(seq, "time: %-16llu\n", ktime_get_real_seconds()); + seq_printf(seq, "\t\t\t%-16s %-16s %-16s\n", + "io_bytes", "count", "avg_bytes"); /* print app write IOs */ seq_puts(seq, "[WRITE]\n"); - seq_printf(seq, "app buffered data: %-16llu\n", - sbi->rw_iostat[APP_BUFFERED_IO]); - seq_printf(seq, "app direct data: %-16llu\n", - sbi->rw_iostat[APP_DIRECT_IO]); - seq_printf(seq, "app mapped data: %-16llu\n", - sbi->rw_iostat[APP_MAPPED_IO]); - seq_printf(seq, "app buffered cdata: %-16llu\n", - sbi->rw_iostat[APP_BUFFERED_CDATA_IO]); - seq_printf(seq, "app mapped cdata: %-16llu\n", - sbi->rw_iostat[APP_MAPPED_CDATA_IO]); + IOSTAT_INFO_SHOW("app buffered data", APP_BUFFERED_IO); + IOSTAT_INFO_SHOW("app direct data", APP_DIRECT_IO); + IOSTAT_INFO_SHOW("app mapped data", APP_MAPPED_IO); + IOSTAT_INFO_SHOW("app buffered cdata", APP_BUFFERED_CDATA_IO); + IOSTAT_INFO_SHOW("app mapped cdata", APP_MAPPED_CDATA_IO); /* print fs write IOs */ - seq_printf(seq, "fs data: %-16llu\n", - sbi->rw_iostat[FS_DATA_IO]); - seq_printf(seq, "fs cdata: %-16llu\n", - sbi->rw_iostat[FS_CDATA_IO]); - seq_printf(seq, "fs node: %-16llu\n", - sbi->rw_iostat[FS_NODE_IO]); - seq_printf(seq, "fs meta: %-16llu\n", - sbi->rw_iostat[FS_META_IO]); - seq_printf(seq, "fs gc data: %-16llu\n", - sbi->rw_iostat[FS_GC_DATA_IO]); - seq_printf(seq, "fs gc node: %-16llu\n", - sbi->rw_iostat[FS_GC_NODE_IO]); - seq_printf(seq, "fs cp data: %-16llu\n", - sbi->rw_iostat[FS_CP_DATA_IO]); - seq_printf(seq, "fs cp node: %-16llu\n", - sbi->rw_iostat[FS_CP_NODE_IO]); - seq_printf(seq, "fs cp meta: %-16llu\n", - sbi->rw_iostat[FS_CP_META_IO]); + IOSTAT_INFO_SHOW("fs data", FS_DATA_IO); + IOSTAT_INFO_SHOW("fs cdata", FS_CDATA_IO); + IOSTAT_INFO_SHOW("fs node", FS_NODE_IO); + IOSTAT_INFO_SHOW("fs meta", FS_META_IO); + IOSTAT_INFO_SHOW("fs gc data", FS_GC_DATA_IO); + IOSTAT_INFO_SHOW("fs gc node", FS_GC_NODE_IO); + IOSTAT_INFO_SHOW("fs cp data", FS_CP_DATA_IO); + IOSTAT_INFO_SHOW("fs cp node", FS_CP_NODE_IO); + IOSTAT_INFO_SHOW("fs cp meta", FS_CP_META_IO); /* print app read IOs */ seq_puts(seq, "[READ]\n"); - seq_printf(seq, "app buffered data: %-16llu\n", - sbi->rw_iostat[APP_BUFFERED_READ_IO]); - seq_printf(seq, "app direct data: %-16llu\n", - sbi->rw_iostat[APP_DIRECT_READ_IO]); - seq_printf(seq, "app mapped data: %-16llu\n", - sbi->rw_iostat[APP_MAPPED_READ_IO]); - seq_printf(seq, "app buffered cdata: %-16llu\n", - sbi->rw_iostat[APP_BUFFERED_CDATA_READ_IO]); - seq_printf(seq, "app mapped cdata: %-16llu\n", - sbi->rw_iostat[APP_MAPPED_CDATA_READ_IO]); + IOSTAT_INFO_SHOW("app buffered data", APP_BUFFERED_READ_IO); + IOSTAT_INFO_SHOW("app direct data", APP_DIRECT_READ_IO); + IOSTAT_INFO_SHOW("app mapped data", APP_MAPPED_READ_IO); + IOSTAT_INFO_SHOW("app buffered cdata", APP_BUFFERED_CDATA_READ_IO); + IOSTAT_INFO_SHOW("app mapped cdata", APP_MAPPED_CDATA_READ_IO); /* print fs read IOs */ - seq_printf(seq, "fs data: %-16llu\n", - sbi->rw_iostat[FS_DATA_READ_IO]); - seq_printf(seq, "fs gc data: %-16llu\n", - sbi->rw_iostat[FS_GDATA_READ_IO]); - seq_printf(seq, "fs cdata: %-16llu\n", - sbi->rw_iostat[FS_CDATA_READ_IO]); - seq_printf(seq, "fs node: %-16llu\n", - sbi->rw_iostat[FS_NODE_READ_IO]); - seq_printf(seq, "fs meta: %-16llu\n", - sbi->rw_iostat[FS_META_READ_IO]); + IOSTAT_INFO_SHOW("fs data", FS_DATA_READ_IO); + IOSTAT_INFO_SHOW("fs gc data", FS_GDATA_READ_IO); + IOSTAT_INFO_SHOW("fs cdata", FS_CDATA_READ_IO); + IOSTAT_INFO_SHOW("fs node", FS_NODE_READ_IO); + IOSTAT_INFO_SHOW("fs meta", FS_META_READ_IO); /* print other IOs */ seq_puts(seq, "[OTHER]\n"); - seq_printf(seq, "fs discard: %-16llu\n", - sbi->rw_iostat[FS_DISCARD]); + IOSTAT_INFO_SHOW("fs discard", FS_DISCARD_IO); return 0; } @@ -141,9 +130,9 @@ static inline void f2fs_record_iostat(struct f2fs_sb_info *sbi) msecs_to_jiffies(sbi->iostat_period_ms); for (i = 0; i < NR_IO_TYPE; i++) { - iostat_diff[i] = sbi->rw_iostat[i] - - sbi->prev_rw_iostat[i]; - sbi->prev_rw_iostat[i] = sbi->rw_iostat[i]; + iostat_diff[i] = sbi->iostat_bytes[i] - + sbi->prev_iostat_bytes[i]; + sbi->prev_iostat_bytes[i] = sbi->iostat_bytes[i]; } spin_unlock_irqrestore(&sbi->iostat_lock, flags); @@ -159,8 +148,9 @@ void f2fs_reset_iostat(struct f2fs_sb_info *sbi) spin_lock_irq(&sbi->iostat_lock); for (i = 0; i < NR_IO_TYPE; i++) { - sbi->rw_iostat[i] = 0; - sbi->prev_rw_iostat[i] = 0; + sbi->iostat_count[i] = 0; + sbi->iostat_bytes[i] = 0; + sbi->prev_iostat_bytes[i] = 0; } spin_unlock_irq(&sbi->iostat_lock); @@ -169,6 +159,13 @@ void f2fs_reset_iostat(struct f2fs_sb_info *sbi) spin_unlock_irq(&sbi->iostat_lat_lock); } +static inline void __f2fs_update_iostat(struct f2fs_sb_info *sbi, + enum iostat_type type, unsigned long long io_bytes) +{ + sbi->iostat_bytes[type] += io_bytes; + sbi->iostat_count[type]++; +} + void f2fs_update_iostat(struct f2fs_sb_info *sbi, struct inode *inode, enum iostat_type type, unsigned long long io_bytes) { @@ -178,33 +175,33 @@ void f2fs_update_iostat(struct f2fs_sb_info *sbi, struct inode *inode, return; spin_lock_irqsave(&sbi->iostat_lock, flags); - sbi->rw_iostat[type] += io_bytes; + __f2fs_update_iostat(sbi, type, io_bytes); if (type == APP_BUFFERED_IO || type == APP_DIRECT_IO) - sbi->rw_iostat[APP_WRITE_IO] += io_bytes; + __f2fs_update_iostat(sbi, APP_WRITE_IO, io_bytes); if (type == APP_BUFFERED_READ_IO || type == APP_DIRECT_READ_IO) - sbi->rw_iostat[APP_READ_IO] += io_bytes; + __f2fs_update_iostat(sbi, APP_READ_IO, io_bytes); #ifdef CONFIG_F2FS_FS_COMPRESSION if (inode && f2fs_compressed_file(inode)) { if (type == APP_BUFFERED_IO) - sbi->rw_iostat[APP_BUFFERED_CDATA_IO] += io_bytes; + __f2fs_update_iostat(sbi, APP_BUFFERED_CDATA_IO, io_bytes); if (type == APP_BUFFERED_READ_IO) - sbi->rw_iostat[APP_BUFFERED_CDATA_READ_IO] += io_bytes; + __f2fs_update_iostat(sbi, APP_BUFFERED_CDATA_READ_IO, io_bytes); if (type == APP_MAPPED_READ_IO) - sbi->rw_iostat[APP_MAPPED_CDATA_READ_IO] += io_bytes; + __f2fs_update_iostat(sbi, APP_MAPPED_CDATA_READ_IO, io_bytes); if (type == APP_MAPPED_IO) - sbi->rw_iostat[APP_MAPPED_CDATA_IO] += io_bytes; + __f2fs_update_iostat(sbi, APP_MAPPED_CDATA_IO, io_bytes); if (type == FS_DATA_READ_IO) - sbi->rw_iostat[FS_CDATA_READ_IO] += io_bytes; + __f2fs_update_iostat(sbi, FS_CDATA_READ_IO, io_bytes); if (type == FS_DATA_IO) - sbi->rw_iostat[FS_CDATA_IO] += io_bytes; + __f2fs_update_iostat(sbi, FS_CDATA_IO, io_bytes); } #endif diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c index 8aafa1f32ecc..311243dda4ce 100644 --- a/fs/f2fs/segment.c +++ b/fs/f2fs/segment.c @@ -1182,7 +1182,7 @@ static int __submit_discard_cmd(struct f2fs_sb_info *sbi, atomic_inc(&dcc->issued_discard); - f2fs_update_iostat(sbi, NULL, FS_DISCARD, len * F2FS_BLKSIZE); + f2fs_update_iostat(sbi, NULL, FS_DISCARD_IO, len * F2FS_BLKSIZE); lstart += len; start += len; diff --git a/include/trace/events/f2fs.h b/include/trace/events/f2fs.h index 9183a0a11e26..3852085198fb 100644 --- a/include/trace/events/f2fs.h +++ b/include/trace/events/f2fs.h @@ -1972,7 +1972,7 @@ TRACE_EVENT(f2fs_iostat, __entry->fs_cdrio = iostat[FS_CDATA_READ_IO]; __entry->fs_nrio = iostat[FS_NODE_READ_IO]; __entry->fs_mrio = iostat[FS_META_READ_IO]; - __entry->fs_discard = iostat[FS_DISCARD]; + __entry->fs_discard = iostat[FS_DISCARD_IO]; ), TP_printk("dev = (%d,%d), " -- cgit v1.2.3 From 193a639fed92793ad10e327cfb2be7175be01425 Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Thu, 22 Dec 2022 03:20:01 +0800 Subject: f2fs: add iostat support for flush In this patch, it adds to account flush count. Signed-off-by: Yangtao Li Signed-off-by: Jaegeuk Kim --- fs/f2fs/f2fs.h | 1 + fs/f2fs/iostat.c | 1 + fs/f2fs/segment.c | 2 ++ 3 files changed, 4 insertions(+) (limited to 'fs/f2fs') diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index d4729f8af247..331c330ea31d 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h @@ -1192,6 +1192,7 @@ enum iostat_type { /* other */ FS_DISCARD_IO, /* discard */ + FS_FLUSH_IO, /* flush */ NR_IO_TYPE, }; diff --git a/fs/f2fs/iostat.c b/fs/f2fs/iostat.c index acf834c77291..91b384bea5ac 100644 --- a/fs/f2fs/iostat.c +++ b/fs/f2fs/iostat.c @@ -80,6 +80,7 @@ int __maybe_unused iostat_info_seq_show(struct seq_file *seq, void *offset) /* print other IOs */ seq_puts(seq, "[OTHER]\n"); IOSTAT_INFO_SHOW("fs discard", FS_DISCARD_IO); + IOSTAT_INFO_SHOW("fs flush", FS_FLUSH_IO); return 0; } diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c index 311243dda4ce..976316218bd3 100644 --- a/fs/f2fs/segment.c +++ b/fs/f2fs/segment.c @@ -506,6 +506,8 @@ static int __submit_flush_wait(struct f2fs_sb_info *sbi, trace_f2fs_issue_flush(bdev, test_opt(sbi, NOBARRIER), test_opt(sbi, FLUSH_MERGE), ret); + if (!ret) + f2fs_update_iostat(sbi, NULL, FS_FLUSH_IO, 0); return ret; } -- cgit v1.2.3 From c5f9db2548d0ac988df81aa34cc63f3b2ed374f9 Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Thu, 22 Dec 2022 16:18:55 +0800 Subject: f2fs: drop useless initializer and unneeded local variable No need to initialize idx twice. BTW, remove the unnecessary cnt variable. Signed-off-by: Yangtao Li Signed-off-by: Jaegeuk Kim --- fs/f2fs/iostat.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'fs/f2fs') diff --git a/fs/f2fs/iostat.c b/fs/f2fs/iostat.c index 91b384bea5ac..ed8176939aa5 100644 --- a/fs/f2fs/iostat.c +++ b/fs/f2fs/iostat.c @@ -87,8 +87,7 @@ int __maybe_unused iostat_info_seq_show(struct seq_file *seq, void *offset) static inline void __record_iostat_latency(struct f2fs_sb_info *sbi) { - int io, idx = 0; - unsigned int cnt; + int io, idx; struct f2fs_iostat_latency iostat_lat[MAX_IO_TYPE][NR_PAGE_TYPE]; struct iostat_lat_info *io_lat = sbi->iostat_io_lat; unsigned long flags; @@ -96,12 +95,11 @@ static inline void __record_iostat_latency(struct f2fs_sb_info *sbi) spin_lock_irqsave(&sbi->iostat_lat_lock, flags); for (idx = 0; idx < MAX_IO_TYPE; idx++) { for (io = 0; io < NR_PAGE_TYPE; io++) { - cnt = io_lat->bio_cnt[idx][io]; iostat_lat[idx][io].peak_lat = jiffies_to_msecs(io_lat->peak_lat[idx][io]); - iostat_lat[idx][io].cnt = cnt; - iostat_lat[idx][io].avg_lat = cnt ? - jiffies_to_msecs(io_lat->sum_lat[idx][io]) / cnt : 0; + iostat_lat[idx][io].cnt = io_lat->bio_cnt[idx][io]; + iostat_lat[idx][io].avg_lat = iostat_lat[idx][io].cnt ? + jiffies_to_msecs(io_lat->sum_lat[idx][io]) / iostat_lat[idx][io].cnt : 0; io_lat->sum_lat[idx][io] = 0; io_lat->peak_lat[idx][io] = 0; io_lat->bio_cnt[idx][io] = 0; -- cgit v1.2.3 From 120e0ea12d90ad15127ad50944975fc8c81666b7 Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Wed, 4 Jan 2023 19:40:29 +0800 Subject: f2fs: introduce discard_io_aware_gran sysfs node The current discard_io_aware_gran is a fixed value, change it to be configurable through the sys node. Signed-off-by: Yangtao Li Signed-off-by: Jaegeuk Kim --- Documentation/ABI/testing/sysfs-fs-f2fs | 9 +++++++++ fs/f2fs/f2fs.h | 1 + fs/f2fs/segment.c | 3 ++- fs/f2fs/sysfs.c | 13 +++++++++++++ 4 files changed, 25 insertions(+), 1 deletion(-) (limited to 'fs/f2fs') diff --git a/Documentation/ABI/testing/sysfs-fs-f2fs b/Documentation/ABI/testing/sysfs-fs-f2fs index aaa379bb8a8f..75420c242cc4 100644 --- a/Documentation/ABI/testing/sysfs-fs-f2fs +++ b/Documentation/ABI/testing/sysfs-fs-f2fs @@ -708,3 +708,12 @@ Description: Support configuring fault injection type, should be FAULT_LOCK_OP 0x000020000 FAULT_BLKADDR 0x000040000 =================== =========== + +What: /sys/fs/f2fs//discard_io_aware_gran +Date: January 2023 +Contact: "Yangtao Li" +Description: Controls background discard granularity of inner discard thread + when is not in idle. Inner thread will not issue discards with size that + is smaller than granularity. The unit size is one block(4KB), now only + support configuring in range of [0, 512]. + Default: 512 diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index 331c330ea31d..f3c5f7740c1a 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h @@ -409,6 +409,7 @@ struct discard_cmd_control { unsigned int min_discard_issue_time; /* min. interval between discard issue */ unsigned int mid_discard_issue_time; /* mid. interval between discard issue */ unsigned int max_discard_issue_time; /* max. interval between discard issue */ + unsigned int discard_io_aware_gran; /* minimum discard granularity not be aware of I/O */ unsigned int discard_urgent_util; /* utilization which issue discard proactively */ unsigned int discard_granularity; /* discard granularity */ unsigned int max_ordered_discard; /* maximum discard granularity issued by lba order */ diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c index 976316218bd3..bd1cd98fa6eb 100644 --- a/fs/f2fs/segment.c +++ b/fs/f2fs/segment.c @@ -1059,7 +1059,7 @@ static void __init_discard_policy(struct f2fs_sb_info *sbi, dpolicy->granularity = granularity; dpolicy->max_requests = dcc->max_discard_request; - dpolicy->io_aware_gran = MAX_PLIST_NUM; + dpolicy->io_aware_gran = dcc->discard_io_aware_gran; dpolicy->timeout = false; if (discard_type == DPOLICY_BG) { @@ -2063,6 +2063,7 @@ static int create_discard_cmd_control(struct f2fs_sb_info *sbi) if (!dcc) return -ENOMEM; + dcc->discard_io_aware_gran = MAX_PLIST_NUM; dcc->discard_granularity = DEFAULT_DISCARD_GRANULARITY; dcc->max_ordered_discard = DEFAULT_MAX_ORDERED_DISCARD_GRANULARITY; if (F2FS_OPTION(sbi).discard_unit == DISCARD_UNIT_SEGMENT) diff --git a/fs/f2fs/sysfs.c b/fs/f2fs/sysfs.c index 805b632a3af0..e396851a6dd1 100644 --- a/fs/f2fs/sysfs.c +++ b/fs/f2fs/sysfs.c @@ -473,6 +473,17 @@ out: return count; } + if (!strcmp(a->attr.name, "discard_io_aware_gran")) { + if (t > MAX_PLIST_NUM) + return -EINVAL; + if (!f2fs_block_unit_discard(sbi)) + return -EINVAL; + if (t == *ui) + return count; + *ui = t; + return count; + } + if (!strcmp(a->attr.name, "discard_granularity")) { if (t == 0 || t > MAX_PLIST_NUM) return -EINVAL; @@ -825,6 +836,7 @@ F2FS_RW_ATTR(DCC_INFO, discard_cmd_control, max_discard_request, max_discard_req F2FS_RW_ATTR(DCC_INFO, discard_cmd_control, min_discard_issue_time, min_discard_issue_time); F2FS_RW_ATTR(DCC_INFO, discard_cmd_control, mid_discard_issue_time, mid_discard_issue_time); F2FS_RW_ATTR(DCC_INFO, discard_cmd_control, max_discard_issue_time, max_discard_issue_time); +F2FS_RW_ATTR(DCC_INFO, discard_cmd_control, discard_io_aware_gran, discard_io_aware_gran); F2FS_RW_ATTR(DCC_INFO, discard_cmd_control, discard_urgent_util, discard_urgent_util); F2FS_RW_ATTR(DCC_INFO, discard_cmd_control, discard_granularity, discard_granularity); F2FS_RW_ATTR(DCC_INFO, discard_cmd_control, max_ordered_discard, max_ordered_discard); @@ -960,6 +972,7 @@ static struct attribute *f2fs_attrs[] = { ATTR_LIST(min_discard_issue_time), ATTR_LIST(mid_discard_issue_time), ATTR_LIST(max_discard_issue_time), + ATTR_LIST(discard_io_aware_gran), ATTR_LIST(discard_urgent_util), ATTR_LIST(discard_granularity), ATTR_LIST(max_ordered_discard), -- cgit v1.2.3 From 2f3a9ae990a7881c9a57a073bb52ebe34fdc3160 Mon Sep 17 00:00:00 2001 From: Chao Yu Date: Mon, 9 Jan 2023 11:44:49 +0800 Subject: f2fs: introduce trace_f2fs_replace_atomic_write_block Commit 3db1de0e582c ("f2fs: change the current atomic write way") removed old tracepoints, but it missed to add new one, this patch fixes to introduce trace_f2fs_replace_atomic_write_block to trace atomic_write commit flow. Fixes: 3db1de0e582c ("f2fs: change the current atomic write way") Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/segment.c | 3 +++ include/trace/events/f2fs.h | 37 +++++++++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+) (limited to 'fs/f2fs') diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c index bd1cd98fa6eb..ebfa759527ac 100644 --- a/fs/f2fs/segment.c +++ b/fs/f2fs/segment.c @@ -255,6 +255,9 @@ retry: } f2fs_put_dnode(&dn); + + trace_f2fs_replace_atomic_write_block(inode, F2FS_I(inode)->cow_inode, + index, *old_addr, new_addr, recover); return 0; } diff --git a/include/trace/events/f2fs.h b/include/trace/events/f2fs.h index 3852085198fb..fe6bcf5f917d 100644 --- a/include/trace/events/f2fs.h +++ b/include/trace/events/f2fs.h @@ -1290,6 +1290,43 @@ DEFINE_EVENT(f2fs__page, f2fs_vm_page_mkwrite, TP_ARGS(page, type) ); +TRACE_EVENT(f2fs_replace_atomic_write_block, + + TP_PROTO(struct inode *inode, struct inode *cow_inode, pgoff_t index, + block_t old_addr, block_t new_addr, bool recovery), + + TP_ARGS(inode, cow_inode, index, old_addr, new_addr, recovery), + + TP_STRUCT__entry( + __field(dev_t, dev) + __field(ino_t, ino) + __field(ino_t, cow_ino) + __field(pgoff_t, index) + __field(block_t, old_addr) + __field(block_t, new_addr) + __field(bool, recovery) + ), + + TP_fast_assign( + __entry->dev = inode->i_sb->s_dev; + __entry->ino = inode->i_ino; + __entry->cow_ino = cow_inode->i_ino; + __entry->index = index; + __entry->old_addr = old_addr; + __entry->new_addr = new_addr; + __entry->recovery = recovery; + ), + + TP_printk("dev = (%d,%d), ino = %lu, cow_ino = %lu, index = %lu, " + "old_addr = 0x%llx, new_addr = 0x%llx, recovery = %d", + show_dev_ino(__entry), + __entry->cow_ino, + (unsigned long)__entry->index, + (unsigned long long)__entry->old_addr, + (unsigned long long)__entry->new_addr, + __entry->recovery) +); + TRACE_EVENT(f2fs_filemap_fault, TP_PROTO(struct inode *inode, pgoff_t index, unsigned long ret), -- cgit v1.2.3 From 0e8d040bfa4c476d7d2a23119527c744c7de13cd Mon Sep 17 00:00:00 2001 From: Chao Yu Date: Mon, 9 Jan 2023 11:44:50 +0800 Subject: f2fs: clear atomic_write_task in f2fs_abort_atomic_write() Otherwise, last .atomic_write_task will be remained in structure f2fs_inode_info, resulting in aborting atomic_write accidentally in race case. Meanwhile, clear original_i_size as well. Fixes: 7a10f0177e11 ("f2fs: don't give partially written atomic data from process crash") Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/segment.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'fs/f2fs') diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c index ebfa759527ac..5e603b808487 100644 --- a/fs/f2fs/segment.c +++ b/fs/f2fs/segment.c @@ -201,9 +201,12 @@ void f2fs_abort_atomic_write(struct inode *inode, bool clean) clear_inode_flag(inode, FI_ATOMIC_FILE); stat_dec_atomic_inode(inode); + F2FS_I(inode)->atomic_write_task = NULL; + if (clean) { truncate_inode_pages_final(inode->i_mapping); f2fs_i_size_write(inode, fi->original_i_size); + fi->original_i_size = 0; } } -- cgit v1.2.3 From 71a298ca208e48bd69e1bf61a22a762624885093 Mon Sep 17 00:00:00 2001 From: Chao Yu Date: Mon, 9 Jan 2023 11:47:34 +0800 Subject: f2fs: remove unneeded f2fs_cp_error() in f2fs_create_whiteout() f2fs_rename() has checked CP_ERROR_FLAG, so remove redundant check in f2fs_create_whiteout(). Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/namei.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'fs/f2fs') diff --git a/fs/f2fs/namei.c b/fs/f2fs/namei.c index 6032589099ce..82923273f4bb 100644 --- a/fs/f2fs/namei.c +++ b/fs/f2fs/namei.c @@ -926,9 +926,6 @@ static int f2fs_tmpfile(struct user_namespace *mnt_userns, struct inode *dir, static int f2fs_create_whiteout(struct user_namespace *mnt_userns, struct inode *dir, struct inode **whiteout) { - if (unlikely(f2fs_cp_error(F2FS_I_SB(dir)))) - return -EIO; - return __f2fs_tmpfile(mnt_userns, dir, NULL, S_IFCHR | WHITEOUT_MODE, true, whiteout); } -- cgit v1.2.3 From d48a7b3a72f121655d95b5157c32c7d555e44c05 Mon Sep 17 00:00:00 2001 From: Chao Yu Date: Mon, 9 Jan 2023 11:49:20 +0800 Subject: f2fs: fix to do sanity check on extent cache correctly In do_read_inode(), sanity_check_inode() should be called after f2fs_init_read_extent_tree(), fix it. Fixes: 72840cccc0a1 ("f2fs: allocate the extent_cache by default") Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/inode.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'fs/f2fs') diff --git a/fs/f2fs/inode.c b/fs/f2fs/inode.c index 01b9e6f85f6b..fd2ee5554985 100644 --- a/fs/f2fs/inode.c +++ b/fs/f2fs/inode.c @@ -413,12 +413,6 @@ static int do_read_inode(struct inode *inode) fi->i_inline_xattr_size = 0; } - if (!sanity_check_inode(inode, node_page)) { - f2fs_put_page(node_page, 1); - f2fs_handle_error(sbi, ERROR_CORRUPTED_INODE); - return -EFSCORRUPTED; - } - /* check data exist */ if (f2fs_has_inline_data(inode) && !f2fs_exist_data(inode)) __recover_inline_status(inode, node_page); @@ -482,6 +476,12 @@ static int do_read_inode(struct inode *inode) f2fs_init_read_extent_tree(inode, node_page); f2fs_init_age_extent_tree(inode); + if (!sanity_check_inode(inode, node_page)) { + f2fs_put_page(node_page, 1); + f2fs_handle_error(sbi, ERROR_CORRUPTED_INODE); + return -EFSCORRUPTED; + } + f2fs_put_page(node_page, 1); stat_inc_inline_xattr(inode); -- cgit v1.2.3 From 2381a68556c0d2cb027f9dbfabc654a899782c62 Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Mon, 16 Jan 2023 22:12:28 +0800 Subject: f2fs: fix to show discard_unit mount opt Convert to show discard_unit only when has DISCARD opt. Signed-off-by: Yangtao Li Signed-off-by: Jaegeuk Kim --- fs/f2fs/super.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'fs/f2fs') diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c index 5fc83771042d..ab8a77ffc1f4 100644 --- a/fs/f2fs/super.c +++ b/fs/f2fs/super.c @@ -1908,10 +1908,17 @@ static int f2fs_show_options(struct seq_file *seq, struct dentry *root) seq_puts(seq, ",disable_roll_forward"); if (test_opt(sbi, NORECOVERY)) seq_puts(seq, ",norecovery"); - if (test_opt(sbi, DISCARD)) + if (test_opt(sbi, DISCARD)) { seq_puts(seq, ",discard"); - else + if (F2FS_OPTION(sbi).discard_unit == DISCARD_UNIT_BLOCK) + seq_printf(seq, ",discard_unit=%s", "block"); + else if (F2FS_OPTION(sbi).discard_unit == DISCARD_UNIT_SEGMENT) + seq_printf(seq, ",discard_unit=%s", "segment"); + else if (F2FS_OPTION(sbi).discard_unit == DISCARD_UNIT_SECTION) + seq_printf(seq, ",discard_unit=%s", "section"); + } else { seq_puts(seq, ",nodiscard"); + } if (test_opt(sbi, NOHEAP)) seq_puts(seq, ",no_heap"); else @@ -2035,13 +2042,6 @@ static int f2fs_show_options(struct seq_file *seq, struct dentry *root) if (test_opt(sbi, ATGC)) seq_puts(seq, ",atgc"); - if (F2FS_OPTION(sbi).discard_unit == DISCARD_UNIT_BLOCK) - seq_printf(seq, ",discard_unit=%s", "block"); - else if (F2FS_OPTION(sbi).discard_unit == DISCARD_UNIT_SEGMENT) - seq_printf(seq, ",discard_unit=%s", "segment"); - else if (F2FS_OPTION(sbi).discard_unit == DISCARD_UNIT_SECTION) - seq_printf(seq, ",discard_unit=%s", "section"); - if (F2FS_OPTION(sbi).memory_mode == MEMORY_MODE_NORMAL) seq_printf(seq, ",memory=%s", "normal"); else if (F2FS_OPTION(sbi).memory_mode == MEMORY_MODE_LOW) -- cgit v1.2.3 From b1c5ef26e4e80277641afcfedffe598c3023c095 Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Fri, 13 Jan 2023 03:14:04 +0800 Subject: f2fs: return true if all cmd were issued or no cmd need to be issued for f2fs_issue_discard_timeout() f2fs_issue_discard_timeout() returns whether discard cmds are dropped, which does not match the meaning of the function. Let's change it to return whether all discard cmd are issued. After commit 4d67490498ac ("f2fs: Don't create discard thread when device doesn't support realtime discard"), f2fs_issue_discard_timeout() is alse called by f2fs_remount(). Since the comments of f2fs_issue_discard_timeout() doesn't make much sense, let's update it. Signed-off-by: Yangtao Li Signed-off-by: Jaegeuk Kim --- fs/f2fs/segment.c | 13 ++++++++++--- fs/f2fs/super.c | 7 +++---- 2 files changed, 13 insertions(+), 7 deletions(-) (limited to 'fs/f2fs') diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c index 5e603b808487..95a5e6ef7e80 100644 --- a/fs/f2fs/segment.c +++ b/fs/f2fs/segment.c @@ -1656,7 +1656,14 @@ void f2fs_stop_discard_thread(struct f2fs_sb_info *sbi) } } -/* This comes from f2fs_put_super */ +/** + * f2fs_issue_discard_timeout() - Issue all discard cmd within UMOUNT_DISCARD_TIMEOUT + * @sbi: the f2fs_sb_info data for discard cmd to issue + * + * When UMOUNT_DISCARD_TIMEOUT is exceeded, all remaining discard commands will be dropped + * + * Return true if issued all discard cmd or no discard cmd need issue, otherwise return false. + */ bool f2fs_issue_discard_timeout(struct f2fs_sb_info *sbi) { struct discard_cmd_control *dcc = SM_I(sbi)->dcc_info; @@ -1664,7 +1671,7 @@ bool f2fs_issue_discard_timeout(struct f2fs_sb_info *sbi) bool dropped; if (!atomic_read(&dcc->discard_cmd_cnt)) - return false; + return true; __init_discard_policy(sbi, &dpolicy, DPOLICY_UMOUNT, dcc->discard_granularity); @@ -1675,7 +1682,7 @@ bool f2fs_issue_discard_timeout(struct f2fs_sb_info *sbi) __wait_all_discard_cmd(sbi, NULL); f2fs_bug_on(sbi, atomic_read(&dcc->discard_cmd_cnt)); - return dropped; + return !dropped; } static int issue_discard_thread(void *data) diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c index ab8a77ffc1f4..fddff5deaed2 100644 --- a/fs/f2fs/super.c +++ b/fs/f2fs/super.c @@ -1546,7 +1546,7 @@ static void f2fs_put_super(struct super_block *sb) { struct f2fs_sb_info *sbi = F2FS_SB(sb); int i; - bool dropped; + bool done; /* unregister procfs/sysfs entries in advance to avoid race case */ f2fs_unregister_sysfs(sbi); @@ -1576,9 +1576,8 @@ static void f2fs_put_super(struct super_block *sb) } /* be sure to wait for any on-going discard commands */ - dropped = f2fs_issue_discard_timeout(sbi); - - if (f2fs_realtime_discard_enable(sbi) && !sbi->discard_blks && !dropped) { + done = f2fs_issue_discard_timeout(sbi); + if (f2fs_realtime_discard_enable(sbi) && !sbi->discard_blks && done) { struct cp_control cpc = { .reason = CP_UMOUNT | CP_TRIMMED, }; -- cgit v1.2.3 From 9b13a8662ea61430005d3de3fc1d73e383b1ce5a Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Tue, 17 Jan 2023 21:24:42 +0800 Subject: f2fs: fix to check warm_data_age_threshold hot_data_age_threshold is a non-zero positive number, and condition 2 includes condition 1, so there is no need to additionally judge whether t is 0. And let's remove it. Signed-off-by: Yangtao Li Signed-off-by: Jaegeuk Kim --- fs/f2fs/sysfs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'fs/f2fs') diff --git a/fs/f2fs/sysfs.c b/fs/f2fs/sysfs.c index e396851a6dd1..3c6425f9ed0a 100644 --- a/fs/f2fs/sysfs.c +++ b/fs/f2fs/sysfs.c @@ -689,7 +689,7 @@ out: } if (!strcmp(a->attr.name, "warm_data_age_threshold")) { - if (t == 0 || t <= sbi->hot_data_age_threshold) + if (t <= sbi->hot_data_age_threshold) return -EINVAL; if (t == *ui) return count; -- cgit v1.2.3 From b1b9896718bc1a212dc288ad66a5fa2fef11353d Mon Sep 17 00:00:00 2001 From: Alexander Potapenko Date: Mon, 21 Nov 2022 12:21:32 +0100 Subject: fs: f2fs: initialize fsdata in pagecache_write() When aops->write_begin() does not initialize fsdata, KMSAN may report an error passing the latter to aops->write_end(). Fix this by unconditionally initializing fsdata. Suggested-by: Eric Biggers Fixes: 95ae251fe828 ("f2fs: add fs-verity support") Signed-off-by: Alexander Potapenko Reviewed-by: Eric Biggers Signed-off-by: Jaegeuk Kim --- fs/f2fs/verity.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'fs/f2fs') diff --git a/fs/f2fs/verity.c b/fs/f2fs/verity.c index c352fff88a5e..3f4f3295f1c6 100644 --- a/fs/f2fs/verity.c +++ b/fs/f2fs/verity.c @@ -81,7 +81,7 @@ static int pagecache_write(struct inode *inode, const void *buf, size_t count, size_t n = min_t(size_t, count, PAGE_SIZE - offset_in_page(pos)); struct page *page; - void *fsdata; + void *fsdata = NULL; int res; res = aops->write_begin(NULL, mapping, pos, n, &page, &fsdata); -- cgit v1.2.3 From 9a5571cff4ffcfc24847df9fd545cc5799ac0ee5 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Sun, 22 Jan 2023 23:04:14 -0800 Subject: f2fs: fix information leak in f2fs_move_inline_dirents() When converting an inline directory to a regular one, f2fs is leaking uninitialized memory to disk because it doesn't initialize the entire directory block. Fix this by zero-initializing the block. This bug was introduced by commit 4ec17d688d74 ("f2fs: avoid unneeded initializing when converting inline dentry"), which didn't consider the security implications of leaking uninitialized memory to disk. This was found by running xfstest generic/435 on a KMSAN-enabled kernel. Fixes: 4ec17d688d74 ("f2fs: avoid unneeded initializing when converting inline dentry") Cc: # v4.3+ Signed-off-by: Eric Biggers Reviewed-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/inline.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) (limited to 'fs/f2fs') diff --git a/fs/f2fs/inline.c b/fs/f2fs/inline.c index 08e302d32118..72269e7efd26 100644 --- a/fs/f2fs/inline.c +++ b/fs/f2fs/inline.c @@ -421,18 +421,17 @@ static int f2fs_move_inline_dirents(struct inode *dir, struct page *ipage, dentry_blk = page_address(page); + /* + * Start by zeroing the full block, to ensure that all unused space is + * zeroed and no uninitialized memory is leaked to disk. + */ + memset(dentry_blk, 0, F2FS_BLKSIZE); + make_dentry_ptr_inline(dir, &src, inline_dentry); make_dentry_ptr_block(dir, &dst, dentry_blk); /* copy data from inline dentry block to new dentry block */ memcpy(dst.bitmap, src.bitmap, src.nr_bitmap); - memset(dst.bitmap + src.nr_bitmap, 0, dst.nr_bitmap - src.nr_bitmap); - /* - * we do not need to zero out remainder part of dentry and filename - * field, since we have used bitmap for marking the usage status of - * them, besides, we can also ignore copying/zeroing reserved space - * of dentry block, because them haven't been used so far. - */ memcpy(dst.dentry, src.dentry, SIZE_OF_DIR_ENTRY * src.max); memcpy(dst.filename, src.filename, src.max * F2FS_SLOT_LEN); -- cgit v1.2.3 From e6261beb0c629403dc58997294dd521bd23664af Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Mon, 23 Jan 2023 17:46:01 +0800 Subject: f2fs: allow set compression option of files without blocks Files created by truncate have a size but no blocks, so they can be allowed to set compression option. Fixes: e1e8debec656 ("f2fs: add F2FS_IOC_SET_COMPRESS_OPTION ioctl") Signed-off-by: Yangtao Li Reviewed-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/file.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'fs/f2fs') diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c index f5c1b7814954..391da47761e3 100644 --- a/fs/f2fs/file.c +++ b/fs/f2fs/file.c @@ -3941,7 +3941,7 @@ static int f2fs_ioc_set_compress_option(struct file *filp, unsigned long arg) goto out; } - if (inode->i_size != 0) { + if (F2FS_HAS_BLOCKS(inode)) { ret = -EFBIG; goto out; } -- cgit v1.2.3 From ae267fc1cfe9f941afcb90dc963ee6448dae73cf Mon Sep 17 00:00:00 2001 From: Chao Yu Date: Mon, 9 Jan 2023 11:44:51 +0800 Subject: f2fs: fix to abort atomic write only during do_exist() Commit 7a10f0177e11 ("f2fs: don't give partially written atomic data from process crash") attempted to drop atomic write data after process crash, however, f2fs_abort_atomic_write() may be called from noncrash case, fix it by adding missed PF_EXITING check condition f2fs_file_flush(). - application crashs - do_exit - exit_signals -- sets PF_EXITING - exit_files - put_files_struct - close_files - filp_close - flush (f2fs_file_flush) - check atomic_write_task && PF_EXITING - f2fs_abort_atomic_write Fixes: 7a10f0177e11 ("f2fs: don't give partially written atomic data from process crash") Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/file.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'fs/f2fs') diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c index 391da47761e3..eaae2ad3957b 100644 --- a/fs/f2fs/file.c +++ b/fs/f2fs/file.c @@ -1876,7 +1876,8 @@ static int f2fs_file_flush(struct file *file, fl_owner_t id) * until all the writers close its file. Since this should be done * before dropping file lock, it needs to do in ->flush. */ - if (F2FS_I(inode)->atomic_write_task == current) + if (F2FS_I(inode)->atomic_write_task == current && + (current->flags & PF_EXITING)) f2fs_abort_atomic_write(inode, true); return 0; } -- cgit v1.2.3 From 2163a691c5f3d30326ff09193c97aec47cec9eba Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Thu, 19 Jan 2023 07:36:18 +0100 Subject: f2fs: remove __add_sum_entry This function just assigns a summary entry. This can be done entirely typesafe with an open code struct assignment that relies on array indexing. Signed-off-by: Christoph Hellwig Reviewed-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/segment.c | 23 ++--------------------- 1 file changed, 2 insertions(+), 21 deletions(-) (limited to 'fs/f2fs') diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c index 95a5e6ef7e80..39071003c6d7 100644 --- a/fs/f2fs/segment.c +++ b/fs/f2fs/segment.c @@ -2339,19 +2339,6 @@ bool f2fs_is_checkpointed_data(struct f2fs_sb_info *sbi, block_t blkaddr) return is_cp; } -/* - * This function should be resided under the curseg_mutex lock - */ -static void __add_sum_entry(struct f2fs_sb_info *sbi, int type, - struct f2fs_summary *sum) -{ - struct curseg_info *curseg = CURSEG_I(sbi, type); - void *addr = curseg->sum_blk; - - addr += curseg->next_blkoff * sizeof(struct f2fs_summary); - memcpy(addr, sum, sizeof(struct f2fs_summary)); -} - /* * Calculate the number of current summary pages for writing */ @@ -3278,13 +3265,7 @@ void f2fs_allocate_data_block(struct f2fs_sb_info *sbi, struct page *page, f2fs_wait_discard_bio(sbi, *new_blkaddr); - /* - * __add_sum_entry should be resided under the curseg_mutex - * because, this function updates a summary entry in the - * current summary block. - */ - __add_sum_entry(sbi, type, sum); - + curseg->sum_blk->entries[curseg->next_blkoff] = *sum; __refresh_next_blkoff(sbi, curseg); stat_inc_block_count(sbi, curseg); @@ -3587,7 +3568,7 @@ void f2fs_do_replace_block(struct f2fs_sb_info *sbi, struct f2fs_summary *sum, } curseg->next_blkoff = GET_BLKOFF_FROM_SEG0(sbi, new_blkaddr); - __add_sum_entry(sbi, type, sum); + curseg->sum_blk->entries[curseg->next_blkoff] = *sum; if (!recover_curseg || recover_newaddr) { if (!from_gc) -- cgit v1.2.3 From 5a4fed7cd97ac3d9708982d3801e132e2a36c126 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Thu, 19 Jan 2023 07:36:19 +0100 Subject: f2fs: simplify do_checkpoint For each loop add a local curseg_info pointer insted of looking it up for each of the three fields. Signed-off-by: Christoph Hellwig Reviewed-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/checkpoint.c | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) (limited to 'fs/f2fs') diff --git a/fs/f2fs/checkpoint.c b/fs/f2fs/checkpoint.c index d68b3c991888..7e2b44db1587 100644 --- a/fs/f2fs/checkpoint.c +++ b/fs/f2fs/checkpoint.c @@ -1470,20 +1470,18 @@ static int do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc) ckpt->elapsed_time = cpu_to_le64(get_mtime(sbi, true)); ckpt->free_segment_count = cpu_to_le32(free_segments(sbi)); for (i = 0; i < NR_CURSEG_NODE_TYPE; i++) { - ckpt->cur_node_segno[i] = - cpu_to_le32(curseg_segno(sbi, i + CURSEG_HOT_NODE)); - ckpt->cur_node_blkoff[i] = - cpu_to_le16(curseg_blkoff(sbi, i + CURSEG_HOT_NODE)); - ckpt->alloc_type[i + CURSEG_HOT_NODE] = - curseg_alloc_type(sbi, i + CURSEG_HOT_NODE); + struct curseg_info *curseg = CURSEG_I(sbi, i + CURSEG_HOT_NODE); + + ckpt->cur_node_segno[i] = cpu_to_le32(curseg->segno); + ckpt->cur_node_blkoff[i] = cpu_to_le16(curseg->next_blkoff); + ckpt->alloc_type[i + CURSEG_HOT_NODE] = curseg->alloc_type; } for (i = 0; i < NR_CURSEG_DATA_TYPE; i++) { - ckpt->cur_data_segno[i] = - cpu_to_le32(curseg_segno(sbi, i + CURSEG_HOT_DATA)); - ckpt->cur_data_blkoff[i] = - cpu_to_le16(curseg_blkoff(sbi, i + CURSEG_HOT_DATA)); - ckpt->alloc_type[i + CURSEG_HOT_DATA] = - curseg_alloc_type(sbi, i + CURSEG_HOT_DATA); + struct curseg_info *curseg = CURSEG_I(sbi, i + CURSEG_HOT_DATA); + + ckpt->cur_data_segno[i] = cpu_to_le32(curseg->segno); + ckpt->cur_data_blkoff[i] = cpu_to_le16(curseg->next_blkoff); + ckpt->alloc_type[i + CURSEG_HOT_DATA] = curseg->alloc_type; } /* 2 cp + n data seg summary + orphan inode blocks */ -- cgit v1.2.3 From 6392e9ff8bba228746e37b78b960de6de855fc9d Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Thu, 19 Jan 2023 07:36:20 +0100 Subject: f2fs: add a f2fs_curseg_valid_blocks helper Add a helper to return the valid blocks on log and SSR segments, and replace the last two uses of curseg_blkoff with it. Signed-off-by: Christoph Hellwig Reviewed-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/segment.c | 32 +++++++++++++++----------------- fs/f2fs/segment.h | 6 ------ 2 files changed, 15 insertions(+), 23 deletions(-) (limited to 'fs/f2fs') diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c index 39071003c6d7..50af5fcb88e9 100644 --- a/fs/f2fs/segment.c +++ b/fs/f2fs/segment.c @@ -2339,6 +2339,15 @@ bool f2fs_is_checkpointed_data(struct f2fs_sb_info *sbi, block_t blkaddr) return is_cp; } +static unsigned short f2fs_curseg_valid_blocks(struct f2fs_sb_info *sbi, int type) +{ + struct curseg_info *curseg = CURSEG_I(sbi, type); + + if (sbi->ckpt->alloc_type[type] == SSR) + return sbi->blocks_per_seg; + return curseg->next_blkoff; +} + /* * Calculate the number of current summary pages for writing */ @@ -2348,15 +2357,11 @@ int f2fs_npages_for_summary_flush(struct f2fs_sb_info *sbi, bool for_ra) int i, sum_in_page; for (i = CURSEG_HOT_DATA; i <= CURSEG_COLD_DATA; i++) { - if (sbi->ckpt->alloc_type[i] == SSR) - valid_sum_count += sbi->blocks_per_seg; - else { - if (for_ra) - valid_sum_count += le16_to_cpu( - F2FS_CKPT(sbi)->cur_data_blkoff[i]); - else - valid_sum_count += curseg_blkoff(sbi, i); - } + if (sbi->ckpt->alloc_type[i] != SSR && for_ra) + valid_sum_count += + le16_to_cpu(F2FS_CKPT(sbi)->cur_data_blkoff[i]); + else + valid_sum_count += f2fs_curseg_valid_blocks(sbi, i); } sum_in_page = (PAGE_SIZE - 2 * SUM_JOURNAL_SIZE - @@ -3877,15 +3882,8 @@ static void write_compacted_summaries(struct f2fs_sb_info *sbi, block_t blkaddr) /* Step 3: write summary entries */ for (i = CURSEG_HOT_DATA; i <= CURSEG_COLD_DATA; i++) { - unsigned short blkoff; - seg_i = CURSEG_I(sbi, i); - if (sbi->ckpt->alloc_type[i] == SSR) - blkoff = sbi->blocks_per_seg; - else - blkoff = curseg_blkoff(sbi, i); - - for (j = 0; j < blkoff; j++) { + for (j = 0; j < f2fs_curseg_valid_blocks(sbi, i); j++) { if (!page) { page = f2fs_grab_meta_page(sbi, blkaddr++); kaddr = (unsigned char *)page_address(page); diff --git a/fs/f2fs/segment.h b/fs/f2fs/segment.h index ad6a9c19f46a..0f3f05cb8c29 100644 --- a/fs/f2fs/segment.h +++ b/fs/f2fs/segment.h @@ -710,12 +710,6 @@ static inline unsigned char curseg_alloc_type(struct f2fs_sb_info *sbi, return curseg->alloc_type; } -static inline unsigned short curseg_blkoff(struct f2fs_sb_info *sbi, int type) -{ - struct curseg_info *curseg = CURSEG_I(sbi, type); - return curseg->next_blkoff; -} - static inline void check_seg_range(struct f2fs_sb_info *sbi, unsigned int segno) { f2fs_bug_on(sbi, segno > TOTAL_SEGS(sbi) - 1); -- cgit v1.2.3 From 2df79573ef0215431dc4be6b0d4b084204a0820a Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Thu, 19 Jan 2023 07:36:22 +0100 Subject: f2fs: refactor __allocate_new_segment Simplify the check whether to allocate a new segment or reuse an open one. Signed-off-by: Christoph Hellwig Reviewed-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/segment.c | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) (limited to 'fs/f2fs') diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c index 50af5fcb88e9..3712752d395a 100644 --- a/fs/f2fs/segment.c +++ b/fs/f2fs/segment.c @@ -2913,16 +2913,12 @@ static void __allocate_new_segment(struct f2fs_sb_info *sbi, int type, struct curseg_info *curseg = CURSEG_I(sbi, type); unsigned int old_segno; - if (!curseg->inited) - goto alloc; - - if (force || curseg->next_blkoff || - get_valid_blocks(sbi, curseg->segno, new_sec)) - goto alloc; - - if (!get_ckpt_valid_blocks(sbi, curseg->segno, new_sec)) + if (!force && curseg->inited && + !curseg->next_blkoff && + !get_valid_blocks(sbi, curseg->segno, new_sec) && + !get_ckpt_valid_blocks(sbi, curseg->segno, new_sec)) return; -alloc: + old_segno = curseg->segno; new_curseg(sbi, type, true); stat_inc_seg_type(sbi, curseg); -- cgit v1.2.3 From dede3525edbff6e6244668f81d66a48105d3e43b Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Thu, 19 Jan 2023 07:36:23 +0100 Subject: f2fs: remove __allocate_new_section Just fold this trivial wrapper into the only caller. Signed-off-by: Christoph Hellwig Reviewed-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/segment.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) (limited to 'fs/f2fs') diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c index 3712752d395a..55720251755e 100644 --- a/fs/f2fs/segment.c +++ b/fs/f2fs/segment.c @@ -2925,17 +2925,11 @@ static void __allocate_new_segment(struct f2fs_sb_info *sbi, int type, locate_dirty_segment(sbi, old_segno); } -static void __allocate_new_section(struct f2fs_sb_info *sbi, - int type, bool force) -{ - __allocate_new_segment(sbi, type, true, force); -} - void f2fs_allocate_new_section(struct f2fs_sb_info *sbi, int type, bool force) { f2fs_down_read(&SM_I(sbi)->curseg_lock); down_write(&SIT_I(sbi)->sentry_lock); - __allocate_new_section(sbi, type, force); + __allocate_new_segment(sbi, type, true, force); up_write(&SIT_I(sbi)->sentry_lock); f2fs_up_read(&SM_I(sbi)->curseg_lock); } -- cgit v1.2.3 From 4a2095887340e75dfb07575950fcdb7fbcbec64b Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Thu, 19 Jan 2023 07:36:24 +0100 Subject: f2fs: refactor next blk selection Remove __refresh_next_blkoff by opencoding the SSR vs LFS segment check in the only caller, and then add helpers for SSR block selection and blkoff randomization instead. Signed-off-by: Christoph Hellwig Reviewed-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/segment.c | 48 +++++++++++++++++++++++------------------------- 1 file changed, 23 insertions(+), 25 deletions(-) (limited to 'fs/f2fs') diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c index 55720251755e..14a9651e4f31 100644 --- a/fs/f2fs/segment.c +++ b/fs/f2fs/segment.c @@ -2632,30 +2632,10 @@ static int __next_free_blkoff(struct f2fs_sb_info *sbi, return __find_rev_next_zero_bit(target_map, sbi->blocks_per_seg, start); } -/* - * If a segment is written by LFS manner, next block offset is just obtained - * by increasing the current block offset. However, if a segment is written by - * SSR manner, next block offset obtained by calling __next_free_blkoff - */ -static void __refresh_next_blkoff(struct f2fs_sb_info *sbi, - struct curseg_info *seg) +static int f2fs_find_next_ssr_block(struct f2fs_sb_info *sbi, + struct curseg_info *seg) { - if (seg->alloc_type == SSR) { - seg->next_blkoff = - __next_free_blkoff(sbi, seg->segno, - seg->next_blkoff + 1); - } else { - seg->next_blkoff++; - if (F2FS_OPTION(sbi).fs_mode == FS_MODE_FRAGMENT_BLK) { - /* To allocate block chunks in different sizes, use random number */ - if (--seg->fragment_remained_chunk <= 0) { - seg->fragment_remained_chunk = - get_random_u32_inclusive(1, sbi->max_fragment_chunk); - seg->next_blkoff += - get_random_u32_inclusive(1, sbi->max_fragment_hole); - } - } - } + return __next_free_blkoff(sbi, seg->segno, seg->next_blkoff + 1); } bool f2fs_segment_has_free_slot(struct f2fs_sb_info *sbi, int segno) @@ -3232,6 +3212,19 @@ static int __get_segment_type(struct f2fs_io_info *fio) return type; } +static void f2fs_randomize_chunk(struct f2fs_sb_info *sbi, + struct curseg_info *seg) +{ + /* To allocate block chunks in different sizes, use random number */ + if (--seg->fragment_remained_chunk > 0) + return; + + seg->fragment_remained_chunk = + get_random_u32_inclusive(1, sbi->max_fragment_chunk); + seg->next_blkoff += + get_random_u32_inclusive(1, sbi->max_fragment_hole); +} + void f2fs_allocate_data_block(struct f2fs_sb_info *sbi, struct page *page, block_t old_blkaddr, block_t *new_blkaddr, struct f2fs_summary *sum, int type, @@ -3261,8 +3254,13 @@ void f2fs_allocate_data_block(struct f2fs_sb_info *sbi, struct page *page, f2fs_wait_discard_bio(sbi, *new_blkaddr); curseg->sum_blk->entries[curseg->next_blkoff] = *sum; - __refresh_next_blkoff(sbi, curseg); - + if (curseg->alloc_type == SSR) { + curseg->next_blkoff = f2fs_find_next_ssr_block(sbi, curseg); + } else { + curseg->next_blkoff++; + if (F2FS_OPTION(sbi).fs_mode == FS_MODE_FRAGMENT_BLK) + f2fs_randomize_chunk(sbi, curseg); + } stat_inc_block_count(sbi, curseg); if (from_gc) { -- cgit v1.2.3 From 88c9edfd3c4cf129d6259085c4cc899051fa1fdc Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Thu, 19 Jan 2023 07:36:25 +0100 Subject: f2fs: remove __has_curseg_space Just open code the logic in the only caller, where it is more obvious. Signed-off-by: Christoph Hellwig Reviewed-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/segment.c | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) (limited to 'fs/f2fs') diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c index 14a9651e4f31..f46a8c0daeb3 100644 --- a/fs/f2fs/segment.c +++ b/fs/f2fs/segment.c @@ -3087,13 +3087,6 @@ out: return err; } -static bool __has_curseg_space(struct f2fs_sb_info *sbi, - struct curseg_info *curseg) -{ - return curseg->next_blkoff < f2fs_usable_blks_in_seg(sbi, - curseg->segno); -} - int f2fs_rw_hint_to_seg_type(enum rw_hint hint) { switch (hint) { @@ -3235,6 +3228,7 @@ void f2fs_allocate_data_block(struct f2fs_sb_info *sbi, struct page *page, unsigned long long old_mtime; bool from_gc = (type == CURSEG_ALL_DATA_ATGC); struct seg_entry *se = NULL; + bool segment_full = false; f2fs_down_read(&SM_I(sbi)->curseg_lock); @@ -3261,6 +3255,8 @@ void f2fs_allocate_data_block(struct f2fs_sb_info *sbi, struct page *page, if (F2FS_OPTION(sbi).fs_mode == FS_MODE_FRAGMENT_BLK) f2fs_randomize_chunk(sbi, curseg); } + if (curseg->next_blkoff >= f2fs_usable_blks_in_seg(sbi, curseg->segno)) + segment_full = true; stat_inc_block_count(sbi, curseg); if (from_gc) { @@ -3279,10 +3275,11 @@ void f2fs_allocate_data_block(struct f2fs_sb_info *sbi, struct page *page, if (GET_SEGNO(sbi, old_blkaddr) != NULL_SEGNO) update_sit_entry(sbi, old_blkaddr, -1); - if (!__has_curseg_space(sbi, curseg)) { - /* - * Flush out current segment and replace it with new segment. - */ + /* + * If the current segment is full, flush it out and replace it with a + * new segment. + */ + if (segment_full) { if (from_gc) { get_atssr_segment(sbi, type, se->type, AT_SSR, se->mtime); -- cgit v1.2.3 From a28bca0f47feb5cdfc22be0e563bd4da2aed74f7 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Thu, 19 Jan 2023 07:36:21 +0100 Subject: f2fs: factor the read/write tracing logic into a helper Factor the logic to log a path for reads and writs into a helper shared between the read_iter and write_iter methods. Signed-off-by: Christoph Hellwig Signed-off-by: Jaegeuk Kim --- fs/f2fs/file.c | 61 +++++++++++++++++++++++++--------------------------------- 1 file changed, 26 insertions(+), 35 deletions(-) (limited to 'fs/f2fs') diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c index eaae2ad3957b..65199574cd7d 100644 --- a/fs/f2fs/file.c +++ b/fs/f2fs/file.c @@ -4341,6 +4341,27 @@ out: return ret; } +static void f2fs_trace_rw_file_path(struct kiocb *iocb, size_t count, int rw) +{ + struct inode *inode = file_inode(iocb->ki_filp); + char *buf, *path; + + buf = f2fs_kmalloc(F2FS_I_SB(inode), PATH_MAX, GFP_KERNEL); + if (!buf) + return; + path = dentry_path_raw(file_dentry(iocb->ki_filp), buf, PATH_MAX); + if (IS_ERR(path)) + goto free_buf; + if (rw == WRITE) + trace_f2fs_datawrite_start(inode, iocb->ki_pos, count, + current->pid, path, current->comm); + else + trace_f2fs_dataread_start(inode, iocb->ki_pos, count, + current->pid, path, current->comm); +free_buf: + kfree(buf); +} + static ssize_t f2fs_file_read_iter(struct kiocb *iocb, struct iov_iter *to) { struct inode *inode = file_inode(iocb->ki_filp); @@ -4350,24 +4371,9 @@ static ssize_t f2fs_file_read_iter(struct kiocb *iocb, struct iov_iter *to) if (!f2fs_is_compress_backend_ready(inode)) return -EOPNOTSUPP; - if (trace_f2fs_dataread_start_enabled()) { - char *p = f2fs_kmalloc(F2FS_I_SB(inode), PATH_MAX, GFP_KERNEL); - char *path; - - if (!p) - goto skip_read_trace; + if (trace_f2fs_dataread_start_enabled()) + f2fs_trace_rw_file_path(iocb, iov_iter_count(to), READ); - path = dentry_path_raw(file_dentry(iocb->ki_filp), p, PATH_MAX); - if (IS_ERR(path)) { - kfree(p); - goto skip_read_trace; - } - - trace_f2fs_dataread_start(inode, pos, iov_iter_count(to), - current->pid, path, current->comm); - kfree(p); - } -skip_read_trace: if (f2fs_should_use_dio(inode, iocb, to)) { ret = f2fs_dio_read_iter(iocb, to); } else { @@ -4673,24 +4679,9 @@ static ssize_t f2fs_file_write_iter(struct kiocb *iocb, struct iov_iter *from) if (preallocated < 0) { ret = preallocated; } else { - if (trace_f2fs_datawrite_start_enabled()) { - char *p = f2fs_kmalloc(F2FS_I_SB(inode), - PATH_MAX, GFP_KERNEL); - char *path; - - if (!p) - goto skip_write_trace; - path = dentry_path_raw(file_dentry(iocb->ki_filp), - p, PATH_MAX); - if (IS_ERR(path)) { - kfree(p); - goto skip_write_trace; - } - trace_f2fs_datawrite_start(inode, orig_pos, orig_count, - current->pid, path, current->comm); - kfree(p); - } -skip_write_trace: + if (trace_f2fs_datawrite_start_enabled()) + f2fs_trace_rw_file_path(iocb, orig_count, WRITE); + /* Do the actual write. */ ret = dio ? f2fs_dio_write_iter(iocb, from, &may_need_sync) : -- cgit v1.2.3 From 2eae077e6e46f9046d383631145750e043820dce Mon Sep 17 00:00:00 2001 From: Chao Yu Date: Thu, 2 Feb 2023 15:04:56 +0800 Subject: f2fs: reduce stack memory cost by using bitfield in struct f2fs_io_info This patch tries to use bitfield in struct f2fs_io_info to improve memory usage. struct f2fs_io_info { ... unsigned int need_lock:8; /* indicate we need to lock cp_rwsem */ unsigned int version:8; /* version of the node */ unsigned int submitted:1; /* indicate IO submission */ unsigned int in_list:1; /* indicate fio is in io_list */ unsigned int is_por:1; /* indicate IO is from recovery or not */ unsigned int retry:1; /* need to reallocate block address */ unsigned int encrypted:1; /* indicate file is encrypted */ unsigned int post_read:1; /* require post read */ ... }; After this patch, size of struct f2fs_io_info reduces from 136 to 120. [Nathan: fix a compile warning (single-bit-bitfield-constant-conversion)] Signed-off-by: Nathan Chancellor Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/checkpoint.c | 6 +++--- fs/f2fs/compress.c | 5 +++-- fs/f2fs/data.c | 10 +++++----- fs/f2fs/f2fs.h | 18 +++++++++--------- fs/f2fs/gc.c | 8 ++++---- fs/f2fs/node.c | 2 +- fs/f2fs/segment.c | 6 +++--- 7 files changed, 28 insertions(+), 27 deletions(-) (limited to 'fs/f2fs') diff --git a/fs/f2fs/checkpoint.c b/fs/f2fs/checkpoint.c index 7e2b44db1587..89ce08b0ff7c 100644 --- a/fs/f2fs/checkpoint.c +++ b/fs/f2fs/checkpoint.c @@ -70,7 +70,7 @@ static struct page *__get_meta_page(struct f2fs_sb_info *sbi, pgoff_t index, .old_blkaddr = index, .new_blkaddr = index, .encrypted_page = NULL, - .is_por = !is_meta, + .is_por = !is_meta ? 1 : 0, }; int err; @@ -237,8 +237,8 @@ int f2fs_ra_meta_pages(struct f2fs_sb_info *sbi, block_t start, int nrpages, .op = REQ_OP_READ, .op_flags = sync ? (REQ_META | REQ_PRIO) : REQ_RAHEAD, .encrypted_page = NULL, - .in_list = false, - .is_por = (type == META_POR), + .in_list = 0, + .is_por = (type == META_POR) ? 1 : 0, }; struct blk_plug plug; int err; diff --git a/fs/f2fs/compress.c b/fs/f2fs/compress.c index b196b881f3bb..a469cdde6bac 100644 --- a/fs/f2fs/compress.c +++ b/fs/f2fs/compress.c @@ -1213,10 +1213,11 @@ static int f2fs_write_compressed_pages(struct compress_ctx *cc, .page = NULL, .encrypted_page = NULL, .compressed_page = NULL, - .submitted = false, + .submitted = 0, .io_type = io_type, .io_wbc = wbc, - .encrypted = fscrypt_inode_uses_fs_layer_crypto(cc->inode), + .encrypted = fscrypt_inode_uses_fs_layer_crypto(cc->inode) ? + 1 : 0, }; struct dnode_of_data dn; struct node_info ni; diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c index c940da1c540f..754841bce389 100644 --- a/fs/f2fs/data.c +++ b/fs/f2fs/data.c @@ -992,7 +992,7 @@ next: bio_page = fio->page; /* set submitted = true as a return value */ - fio->submitted = true; + fio->submitted = 1; inc_page_count(sbi, WB_DATA_TYPE(bio_page)); @@ -1008,7 +1008,7 @@ alloc_new: (fio->type == DATA || fio->type == NODE) && fio->new_blkaddr & F2FS_IO_SIZE_MASK(sbi)) { dec_page_count(sbi, WB_DATA_TYPE(bio_page)); - fio->retry = true; + fio->retry = 1; goto skip; } io->bio = __bio_alloc(fio, BIO_MAX_VECS); @@ -2776,10 +2776,10 @@ int f2fs_write_single_data_page(struct page *page, int *submitted, .old_blkaddr = NULL_ADDR, .page = page, .encrypted_page = NULL, - .submitted = false, + .submitted = 0, .compr_blocks = compr_blocks, .need_lock = LOCK_RETRY, - .post_read = f2fs_post_read_required(inode), + .post_read = f2fs_post_read_required(inode) ? 1 : 0, .io_type = io_type, .io_wbc = wbc, .bio = bio, @@ -2900,7 +2900,7 @@ out: } if (submitted) - *submitted = fio.submitted ? 1 : 0; + *submitted = fio.submitted; return 0; diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index f3c5f7740c1a..5449c8277339 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h @@ -1210,19 +1210,19 @@ struct f2fs_io_info { struct page *encrypted_page; /* encrypted page */ struct page *compressed_page; /* compressed page */ struct list_head list; /* serialize IOs */ - bool submitted; /* indicate IO submission */ - int need_lock; /* indicate we need to lock cp_rwsem */ - bool in_list; /* indicate fio is in io_list */ - bool is_por; /* indicate IO is from recovery or not */ - bool retry; /* need to reallocate block address */ - int compr_blocks; /* # of compressed block addresses */ - bool encrypted; /* indicate file is encrypted */ - bool post_read; /* require post read */ + unsigned int compr_blocks; /* # of compressed block addresses */ + unsigned int need_lock:8; /* indicate we need to lock cp_rwsem */ + unsigned int version:8; /* version of the node */ + unsigned int submitted:1; /* indicate IO submission */ + unsigned int in_list:1; /* indicate fio is in io_list */ + unsigned int is_por:1; /* indicate IO is from recovery or not */ + unsigned int retry:1; /* need to reallocate block address */ + unsigned int encrypted:1; /* indicate file is encrypted */ + unsigned int post_read:1; /* require post read */ enum iostat_type io_type; /* io type */ struct writeback_control *io_wbc; /* writeback control */ struct bio **bio; /* bio for ipu */ sector_t *last_block; /* last block number in bio */ - unsigned char version; /* version of the node */ }; struct bio_entry { diff --git a/fs/f2fs/gc.c b/fs/f2fs/gc.c index 97e846263c7c..0a9dfa459860 100644 --- a/fs/f2fs/gc.c +++ b/fs/f2fs/gc.c @@ -1156,8 +1156,8 @@ static int ra_data_block(struct inode *inode, pgoff_t index) .op = REQ_OP_READ, .op_flags = 0, .encrypted_page = NULL, - .in_list = false, - .retry = false, + .in_list = 0, + .retry = 0, }; int err; @@ -1245,8 +1245,8 @@ static int move_data_block(struct inode *inode, block_t bidx, .op = REQ_OP_READ, .op_flags = 0, .encrypted_page = NULL, - .in_list = false, - .retry = false, + .in_list = 0, + .retry = 0, }; struct dnode_of_data dn; struct f2fs_summary sum; diff --git a/fs/f2fs/node.c b/fs/f2fs/node.c index fbd1d25fecc2..19a1fee88a36 100644 --- a/fs/f2fs/node.c +++ b/fs/f2fs/node.c @@ -1586,7 +1586,7 @@ static int __write_node_page(struct page *page, bool atomic, bool *submitted, .op_flags = wbc_to_write_flags(wbc), .page = page, .encrypted_page = NULL, - .submitted = false, + .submitted = 0, .io_type = io_type, .io_wbc = wbc, }; diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c index f46a8c0daeb3..69b01b5c0ce0 100644 --- a/fs/f2fs/segment.c +++ b/fs/f2fs/segment.c @@ -3314,10 +3314,10 @@ void f2fs_allocate_data_block(struct f2fs_sb_info *sbi, struct page *page, struct f2fs_bio_info *io; if (F2FS_IO_ALIGNED(sbi)) - fio->retry = false; + fio->retry = 0; INIT_LIST_HEAD(&fio->list); - fio->in_list = true; + fio->in_list = 1; io = sbi->write_io[fio->type] + fio->temp; spin_lock(&io->io_lock); list_add_tail(&fio->list, &io->io_list); @@ -3398,7 +3398,7 @@ void f2fs_do_write_meta_page(struct f2fs_sb_info *sbi, struct page *page, .new_blkaddr = page->index, .page = page, .encrypted_page = NULL, - .in_list = false, + .in_list = 0, }; if (unlikely(page->index >= MAIN_BLKADDR(sbi))) -- cgit v1.2.3 From b90e5086df6bf5ba819216d5ecf0667370bd565f Mon Sep 17 00:00:00 2001 From: Chao Yu Date: Sat, 28 Jan 2023 18:30:11 +0800 Subject: f2fs: clean up i_compress_flag and i_compress_level usage .i_compress_level was introduced by commit 3fde13f817e2 ("f2fs: compress: support compress level"), but never be used. This patch updates as below: - load high 8-bits of on-disk .i_compress_flag to in-memory .i_compress_level - load low 8-bits of on-disk .i_compress_flag to in-memory .i_compress_flag - change type of in-memory .i_compress_flag from unsigned short to unsigned char. w/ above changes, we can avoid unneeded bit shift whenever during .init_compress_ctx(), and shrink size of struct f2fs_inode_info. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/compress.c | 8 +++----- fs/f2fs/f2fs.h | 7 +++---- fs/f2fs/inode.c | 16 +++++++++++++--- 3 files changed, 19 insertions(+), 12 deletions(-) (limited to 'fs/f2fs') diff --git a/fs/f2fs/compress.c b/fs/f2fs/compress.c index a469cdde6bac..e4851f7a43d8 100644 --- a/fs/f2fs/compress.c +++ b/fs/f2fs/compress.c @@ -241,7 +241,7 @@ static int lz4_init_compress_ctx(struct compress_ctx *cc) unsigned int size = LZ4_MEM_COMPRESS; #ifdef CONFIG_F2FS_FS_LZ4HC - if (F2FS_I(cc->inode)->i_compress_flag >> COMPRESS_LEVEL_OFFSET) + if (F2FS_I(cc->inode)->i_compress_level) size = LZ4HC_MEM_COMPRESS; #endif @@ -267,8 +267,7 @@ static void lz4_destroy_compress_ctx(struct compress_ctx *cc) #ifdef CONFIG_F2FS_FS_LZ4HC static int lz4hc_compress_pages(struct compress_ctx *cc) { - unsigned char level = F2FS_I(cc->inode)->i_compress_flag >> - COMPRESS_LEVEL_OFFSET; + unsigned char level = F2FS_I(cc->inode)->i_compress_level; int len; if (level) @@ -340,8 +339,7 @@ static int zstd_init_compress_ctx(struct compress_ctx *cc) zstd_cstream *stream; void *workspace; unsigned int workspace_size; - unsigned char level = F2FS_I(cc->inode)->i_compress_flag >> - COMPRESS_LEVEL_OFFSET; + unsigned char level = F2FS_I(cc->inode)->i_compress_level; if (!level) level = F2FS_ZSTD_DEFAULT_CLEVEL; diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index 5449c8277339..e80144384acb 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h @@ -869,7 +869,7 @@ struct f2fs_inode_info { unsigned char i_compress_algorithm; /* algorithm type */ unsigned char i_log_cluster_size; /* log of cluster size */ unsigned char i_compress_level; /* compress level (lz4hc,zstd) */ - unsigned short i_compress_flag; /* compress flag */ + unsigned char i_compress_flag; /* compress flag */ unsigned int i_cluster_size; /* cluster size */ unsigned int atomic_write_cnt; @@ -4358,9 +4358,8 @@ static inline int set_compress_context(struct inode *inode) if ((F2FS_I(inode)->i_compress_algorithm == COMPRESS_LZ4 || F2FS_I(inode)->i_compress_algorithm == COMPRESS_ZSTD) && F2FS_OPTION(sbi).compress_level) - F2FS_I(inode)->i_compress_flag |= - F2FS_OPTION(sbi).compress_level << - COMPRESS_LEVEL_OFFSET; + F2FS_I(inode)->i_compress_level = + F2FS_OPTION(sbi).compress_level; F2FS_I(inode)->i_flags |= F2FS_COMPR_FL; set_inode_flag(inode, FI_COMPRESSED_FILE); stat_inc_compr_inode(inode); diff --git a/fs/f2fs/inode.c b/fs/f2fs/inode.c index fd2ee5554985..61a991b490ee 100644 --- a/fs/f2fs/inode.c +++ b/fs/f2fs/inode.c @@ -460,11 +460,17 @@ static int do_read_inode(struct inode *inode) (fi->i_flags & F2FS_COMPR_FL)) { if (F2FS_FITS_IN_INODE(ri, fi->i_extra_isize, i_log_cluster_size)) { + unsigned short compress_flag; + atomic_set(&fi->i_compr_blocks, le64_to_cpu(ri->i_compr_blocks)); fi->i_compress_algorithm = ri->i_compress_algorithm; fi->i_log_cluster_size = ri->i_log_cluster_size; - fi->i_compress_flag = le16_to_cpu(ri->i_compress_flag); + compress_flag = le16_to_cpu(ri->i_compress_flag); + fi->i_compress_level = compress_flag >> + COMPRESS_LEVEL_OFFSET; + fi->i_compress_flag = compress_flag & + (BIT(COMPRESS_LEVEL_OFFSET) - 1); fi->i_cluster_size = 1 << fi->i_log_cluster_size; set_inode_flag(inode, FI_COMPRESSED_FILE); } @@ -686,13 +692,17 @@ void f2fs_update_inode(struct inode *inode, struct page *node_page) if (f2fs_sb_has_compression(F2FS_I_SB(inode)) && F2FS_FITS_IN_INODE(ri, F2FS_I(inode)->i_extra_isize, i_log_cluster_size)) { + unsigned short compress_flag; + ri->i_compr_blocks = cpu_to_le64(atomic_read( &F2FS_I(inode)->i_compr_blocks)); ri->i_compress_algorithm = F2FS_I(inode)->i_compress_algorithm; - ri->i_compress_flag = - cpu_to_le16(F2FS_I(inode)->i_compress_flag); + compress_flag = F2FS_I(inode)->i_compress_flag | + F2FS_I(inode)->i_compress_level << + COMPRESS_LEVEL_OFFSET; + ri->i_compress_flag = cpu_to_le16(compress_flag); ri->i_log_cluster_size = F2FS_I(inode)->i_log_cluster_size; } -- cgit v1.2.3 From 933141e4eb49d8b48721e2377835063a1e8fb823 Mon Sep 17 00:00:00 2001 From: Chao Yu Date: Sat, 28 Jan 2023 18:32:26 +0800 Subject: f2fs: fix to handle F2FS_IOC_START_ATOMIC_REPLACE in f2fs_compat_ioctl() Otherwise, 32-bits binary call ioctl(F2FS_IOC_START_ATOMIC_REPLACE) will fail in 64-bits kernel. Fixes: 41e8f85a75fc ("f2fs: introduce F2FS_IOC_START_ATOMIC_REPLACE") Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/file.c | 1 + 1 file changed, 1 insertion(+) (limited to 'fs/f2fs') diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c index 65199574cd7d..f05148a9dc99 100644 --- a/fs/f2fs/file.c +++ b/fs/f2fs/file.c @@ -4814,6 +4814,7 @@ long f2fs_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) case F2FS_IOC32_MOVE_RANGE: return f2fs_compat_ioc_move_range(file, arg); case F2FS_IOC_START_ATOMIC_WRITE: + case F2FS_IOC_START_ATOMIC_REPLACE: case F2FS_IOC_COMMIT_ATOMIC_WRITE: case F2FS_IOC_START_VOLATILE_WRITE: case F2FS_IOC_RELEASE_VOLATILE_WRITE: -- cgit v1.2.3 From 3aa51c61cb4a4dcb40df51ac61171e9ac5a35321 Mon Sep 17 00:00:00 2001 From: Jaegeuk Kim Date: Mon, 30 Jan 2023 15:20:09 -0800 Subject: f2fs: retry to update the inode page given data corruption If the storage gives a corrupted node block due to short power failure and reset, f2fs stops the entire operations by setting the checkpoint failure flag. Let's give more chances to live by re-issuing IOs for a while in such critical path. Cc: stable@vger.kernel.org Suggested-by: Randall Huang Suggested-by: Chao Yu Reviewed-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/inode.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) (limited to 'fs/f2fs') diff --git a/fs/f2fs/inode.c b/fs/f2fs/inode.c index 61a991b490ee..28c9c72dda2a 100644 --- a/fs/f2fs/inode.c +++ b/fs/f2fs/inode.c @@ -724,18 +724,19 @@ void f2fs_update_inode_page(struct inode *inode) { struct f2fs_sb_info *sbi = F2FS_I_SB(inode); struct page *node_page; + int count = 0; retry: node_page = f2fs_get_node_page(sbi, inode->i_ino); if (IS_ERR(node_page)) { int err = PTR_ERR(node_page); - if (err == -ENOMEM) { - cond_resched(); + /* The node block was truncated. */ + if (err == -ENOENT) + return; + + if (err == -ENOMEM || ++count <= DEFAULT_RETRY_IO_COUNT) goto retry; - } else if (err != -ENOENT) { - f2fs_stop_checkpoint(sbi, false, - STOP_CP_REASON_UPDATE_INODE); - } + f2fs_stop_checkpoint(sbi, false, STOP_CP_REASON_UPDATE_INODE); return; } f2fs_update_inode(inode, node_page); -- cgit v1.2.3 From 0dbbf0fb38d5ec5d4138d1aeaeb43d9217b9a592 Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Sat, 21 Jan 2023 00:16:55 +0800 Subject: f2fs: fix to avoid potential memory corruption in __update_iostat_latency() Add iotype sanity check to avoid potential memory corruption. This is to fix the compile error below: fs/f2fs/iostat.c:231 __update_iostat_latency() error: buffer overflow 'io_lat->peak_lat[type]' 3 <= 3 vim +228 fs/f2fs/iostat.c 211 static inline void __update_iostat_latency(struct bio_iostat_ctx *iostat_ctx, 212 enum iostat_lat_type type) 213 { 214 unsigned long ts_diff; 215 unsigned int page_type = iostat_ctx->type; 216 struct f2fs_sb_info *sbi = iostat_ctx->sbi; 217 struct iostat_lat_info *io_lat = sbi->iostat_io_lat; 218 unsigned long flags; 219 220 if (!sbi->iostat_enable) 221 return; 222 223 ts_diff = jiffies - iostat_ctx->submit_ts; 224 if (page_type >= META_FLUSH) ^^^^^^^^^^ 225 page_type = META; 226 227 spin_lock_irqsave(&sbi->iostat_lat_lock, flags); @228 io_lat->sum_lat[type][page_type] += ts_diff; ^^^^^^^^^ Mixup between META_FLUSH and NR_PAGE_TYPE leads to memory corruption. Fixes: a4b6817625e7 ("f2fs: introduce periodic iostat io latency traces") Reported-by: kernel test robot Reported-by: Dan Carpenter Suggested-by: Chao Yu Suggested-by: Jaegeuk Kim Signed-off-by: Yangtao Li Reviewed-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/iostat.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'fs/f2fs') diff --git a/fs/f2fs/iostat.c b/fs/f2fs/iostat.c index ed8176939aa5..96637756eae8 100644 --- a/fs/f2fs/iostat.c +++ b/fs/f2fs/iostat.c @@ -223,8 +223,12 @@ static inline void __update_iostat_latency(struct bio_iostat_ctx *iostat_ctx, return; ts_diff = jiffies - iostat_ctx->submit_ts; - if (iotype >= META_FLUSH) + if (iotype == META_FLUSH) { iotype = META; + } else if (iotype >= NR_PAGE_TYPE) { + f2fs_warn(sbi, "%s: %d over NR_PAGE_TYPE", __func__, iotype); + return; + } if (rw == 0) { idx = READ_IO; -- cgit v1.2.3 From 8c0ed062ce27f6b7f0a568cb241e2b4dd2d9e6a6 Mon Sep 17 00:00:00 2001 From: Chao Yu Date: Tue, 31 Jan 2023 22:47:00 +0800 Subject: f2fs: fix to update age extent correctly during truncation nr_free may be less than len, we should update age extent cache w/ range [fofs, len] rather than [fofs, nr_free]. Fixes: 71644dff4811 ("f2fs: add block_age-based extent cache") Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/file.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'fs/f2fs') diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c index f05148a9dc99..a83117325b87 100644 --- a/fs/f2fs/file.c +++ b/fs/f2fs/file.c @@ -617,7 +617,7 @@ void f2fs_truncate_data_blocks_range(struct dnode_of_data *dn, int count) fofs = f2fs_start_bidx_of_node(ofs_of_node(dn->node_page), dn->inode) + ofs; f2fs_update_read_extent_cache_range(dn, fofs, 0, len); - f2fs_update_age_extent_cache_range(dn, fofs, nr_free); + f2fs_update_age_extent_cache_range(dn, fofs, len); dec_valid_block_count(sbi, dn->inode, nr_free); } dn->ofs_in_node = ofs; -- cgit v1.2.3 From a84153f939808102dfa10904aa0f743e734a3e1d Mon Sep 17 00:00:00 2001 From: Chao Yu Date: Tue, 31 Jan 2023 22:47:01 +0800 Subject: f2fs: fix to update age extent in f2fs_do_zero_range() We should update age extent in f2fs_do_zero_range() like we did in f2fs_truncate_data_blocks_range(). Fixes: 71644dff4811 ("f2fs: add block_age-based extent cache") Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/file.c | 1 + 1 file changed, 1 insertion(+) (limited to 'fs/f2fs') diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c index a83117325b87..a17aca50c18c 100644 --- a/fs/f2fs/file.c +++ b/fs/f2fs/file.c @@ -1494,6 +1494,7 @@ static int f2fs_do_zero_range(struct dnode_of_data *dn, pgoff_t start, } f2fs_update_read_extent_cache_range(dn, start, 0, index - start); + f2fs_update_age_extent_cache_range(dn, start, index - start); return ret; } -- cgit v1.2.3 From b03a41a495df35f8e8d25220878bd6b8472d9396 Mon Sep 17 00:00:00 2001 From: qixiaoyu1 Date: Thu, 2 Feb 2023 16:20:27 +0800 Subject: f2fs: fix wrong calculation of block age Currently we wrongly calculate the new block age to old * LAST_AGE_WEIGHT / 100. Fix it to new * (100 - LAST_AGE_WEIGHT) / 100 + old * LAST_AGE_WEIGHT / 100. Signed-off-by: qixiaoyu1 Signed-off-by: xiongping1 Reviewed-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/extent_cache.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) (limited to 'fs/f2fs') diff --git a/fs/f2fs/extent_cache.c b/fs/f2fs/extent_cache.c index 1daf8c88c09b..c8efc957c230 100644 --- a/fs/f2fs/extent_cache.c +++ b/fs/f2fs/extent_cache.c @@ -874,11 +874,18 @@ unlock_out: static unsigned long long __calculate_block_age(unsigned long long new, unsigned long long old) { - unsigned long long diff; + unsigned int rem_old, rem_new; + unsigned long long res; - diff = (new >= old) ? new - (new - old) : new + (old - new); + res = div_u64_rem(new, 100, &rem_new) * (100 - LAST_AGE_WEIGHT) + + div_u64_rem(old, 100, &rem_old) * LAST_AGE_WEIGHT; - return div_u64(diff * LAST_AGE_WEIGHT, 100); + if (rem_new) + res += rem_new * (100 - LAST_AGE_WEIGHT) / 100; + if (rem_old) + res += rem_old * LAST_AGE_WEIGHT / 100; + + return res; } /* This returns a new age and allocated blocks in ei */ -- cgit v1.2.3 From 844545c51a5b2a524b22a2fe9d0b353b827d24b4 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Thu, 2 Feb 2023 17:02:39 -0800 Subject: f2fs: fix cgroup writeback accounting with fs-layer encryption When writing a page from an encrypted file that is using filesystem-layer encryption (not inline encryption), f2fs encrypts the pagecache page into a bounce page, then writes the bounce page. It also passes the bounce page to wbc_account_cgroup_owner(). That's incorrect, because the bounce page is a newly allocated temporary page that doesn't have the memory cgroup of the original pagecache page. This makes wbc_account_cgroup_owner() not account the I/O to the owner of the pagecache page as it should. Fix this by always passing the pagecache page to wbc_account_cgroup_owner(). Fixes: 578c647879f7 ("f2fs: implement cgroup writeback support") Cc: stable@vger.kernel.org Reported-by: Matthew Wilcox (Oracle) Signed-off-by: Eric Biggers Acked-by: Tejun Heo Reviewed-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/data.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'fs/f2fs') diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c index 754841bce389..8a636500db0e 100644 --- a/fs/f2fs/data.c +++ b/fs/f2fs/data.c @@ -739,7 +739,7 @@ int f2fs_submit_page_bio(struct f2fs_io_info *fio) } if (fio->io_wbc && !is_read_io(fio->op)) - wbc_account_cgroup_owner(fio->io_wbc, page, PAGE_SIZE); + wbc_account_cgroup_owner(fio->io_wbc, fio->page, PAGE_SIZE); inc_page_count(fio->sbi, is_read_io(fio->op) ? __read_io_type(page) : WB_DATA_TYPE(fio->page)); @@ -949,7 +949,7 @@ alloc_new: } if (fio->io_wbc) - wbc_account_cgroup_owner(fio->io_wbc, page, PAGE_SIZE); + wbc_account_cgroup_owner(fio->io_wbc, fio->page, PAGE_SIZE); inc_page_count(fio->sbi, WB_DATA_TYPE(page)); @@ -1023,7 +1023,7 @@ alloc_new: } if (fio->io_wbc) - wbc_account_cgroup_owner(fio->io_wbc, bio_page, PAGE_SIZE); + wbc_account_cgroup_owner(fio->io_wbc, fio->page, PAGE_SIZE); io->last_block_in_bio = fio->new_blkaddr; -- cgit v1.2.3 From 04d7a7ae43fc4eed800efadbb4a18059172afb19 Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Thu, 2 Feb 2023 17:41:23 +0800 Subject: f2fs: fix f2fs_show_options to show nogc_merge mount option Commit 5911d2d1d1a3 ("f2fs: introduce gc_merge mount option") forgot to show nogc_merge option, let's fix it. Signed-off-by: Yangtao Li Signed-off-by: Jaegeuk Kim --- fs/f2fs/super.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'fs/f2fs') diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c index fddff5deaed2..4ec2cbbc47eb 100644 --- a/fs/f2fs/super.c +++ b/fs/f2fs/super.c @@ -1902,6 +1902,8 @@ static int f2fs_show_options(struct seq_file *seq, struct dentry *root) if (test_opt(sbi, GC_MERGE)) seq_puts(seq, ",gc_merge"); + else + seq_puts(seq, ",nogc_merge"); if (test_opt(sbi, DISABLE_ROLL_FORWARD)) seq_puts(seq, ",disable_roll_forward"); -- cgit v1.2.3 From d23be468eada21c828058e0e8d60409eaec373ab Mon Sep 17 00:00:00 2001 From: qixiaoyu1 Date: Sat, 4 Feb 2023 17:43:45 +0800 Subject: f2fs: add sysfs nodes to set last_age_weight Signed-off-by: qixiaoyu1 Signed-off-by: xiongping1 Reviewed-by: Chao Yu Signed-off-by: Jaegeuk Kim --- Documentation/ABI/testing/sysfs-fs-f2fs | 5 +++++ fs/f2fs/extent_cache.c | 15 +++++++++------ fs/f2fs/f2fs.h | 1 + fs/f2fs/sysfs.c | 11 +++++++++++ 4 files changed, 26 insertions(+), 6 deletions(-) (limited to 'fs/f2fs') diff --git a/Documentation/ABI/testing/sysfs-fs-f2fs b/Documentation/ABI/testing/sysfs-fs-f2fs index 75420c242cc4..0f17adc80488 100644 --- a/Documentation/ABI/testing/sysfs-fs-f2fs +++ b/Documentation/ABI/testing/sysfs-fs-f2fs @@ -717,3 +717,8 @@ Description: Controls background discard granularity of inner discard thread is smaller than granularity. The unit size is one block(4KB), now only support configuring in range of [0, 512]. Default: 512 + +What: /sys/fs/f2fs//last_age_weight +Date: January 2023 +Contact: "Ping Xiong" +Description: When DATA SEPARATION is on, it controls the weight of last data block age. diff --git a/fs/f2fs/extent_cache.c b/fs/f2fs/extent_cache.c index c8efc957c230..aef308e871ab 100644 --- a/fs/f2fs/extent_cache.c +++ b/fs/f2fs/extent_cache.c @@ -871,19 +871,21 @@ unlock_out: } #endif -static unsigned long long __calculate_block_age(unsigned long long new, +static unsigned long long __calculate_block_age(struct f2fs_sb_info *sbi, + unsigned long long new, unsigned long long old) { unsigned int rem_old, rem_new; unsigned long long res; + unsigned int weight = sbi->last_age_weight; - res = div_u64_rem(new, 100, &rem_new) * (100 - LAST_AGE_WEIGHT) - + div_u64_rem(old, 100, &rem_old) * LAST_AGE_WEIGHT; + res = div_u64_rem(new, 100, &rem_new) * (100 - weight) + + div_u64_rem(old, 100, &rem_old) * weight; if (rem_new) - res += rem_new * (100 - LAST_AGE_WEIGHT) / 100; + res += rem_new * (100 - weight) / 100; if (rem_old) - res += rem_old * LAST_AGE_WEIGHT / 100; + res += rem_old * weight / 100; return res; } @@ -917,7 +919,7 @@ static int __get_new_block_age(struct inode *inode, struct extent_info *ei, cur_age = ULLONG_MAX - tei.last_blocks + cur_blocks; if (tei.age) - ei->age = __calculate_block_age(cur_age, tei.age); + ei->age = __calculate_block_age(sbi, cur_age, tei.age); else ei->age = cur_age; ei->last_blocks = cur_blocks; @@ -1244,6 +1246,7 @@ void f2fs_init_extent_cache_info(struct f2fs_sb_info *sbi) atomic64_set(&sbi->allocated_data_blocks, 0); sbi->hot_data_age_threshold = DEF_HOT_DATA_AGE_THRESHOLD; sbi->warm_data_age_threshold = DEF_WARM_DATA_AGE_THRESHOLD; + sbi->last_age_weight = LAST_AGE_WEIGHT; } int __init f2fs_create_extent_cache(void) diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index e80144384acb..44f2d76525bf 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h @@ -1671,6 +1671,7 @@ struct f2fs_sb_info { /* The threshold used for hot and warm data seperation*/ unsigned int hot_data_age_threshold; unsigned int warm_data_age_threshold; + unsigned int last_age_weight; /* basic filesystem units */ unsigned int log_sectors_per_block; /* log2 sectors per block */ diff --git a/fs/f2fs/sysfs.c b/fs/f2fs/sysfs.c index 3c6425f9ed0a..8789b3b53fb6 100644 --- a/fs/f2fs/sysfs.c +++ b/fs/f2fs/sysfs.c @@ -697,6 +697,15 @@ out: return count; } + if (!strcmp(a->attr.name, "last_age_weight")) { + if (t > 100) + return -EINVAL; + if (t == *ui) + return count; + *ui = (unsigned int)t; + return count; + } + *ui = (unsigned int)t; return count; @@ -956,6 +965,7 @@ F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, revoked_atomic_block, revoked_atomic_block) /* For block age extent cache */ F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, hot_data_age_threshold, hot_data_age_threshold); F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, warm_data_age_threshold, warm_data_age_threshold); +F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, last_age_weight, last_age_weight); #define ATTR_LIST(name) (&f2fs_attr_##name.attr) static struct attribute *f2fs_attrs[] = { @@ -1055,6 +1065,7 @@ static struct attribute *f2fs_attrs[] = { ATTR_LIST(revoked_atomic_block), ATTR_LIST(hot_data_age_threshold), ATTR_LIST(warm_data_age_threshold), + ATTR_LIST(last_age_weight), NULL, }; ATTRIBUTE_GROUPS(f2fs); -- cgit v1.2.3 From d9bac032ac0de8f510b44904b6eb7272679883d1 Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Wed, 1 Feb 2023 18:47:02 +0800 Subject: f2fs: use iostat_lat_type directly as a parameter in the iostat_update_and_unbind_ctx() Convert to use iostat_lat_type as parameter instead of raw number. BTW, move NUM_PREALLOC_IOSTAT_CTXS to the header file, adjust iostat_lat[{0,1,2}] to iostat_lat[{READ_IO,WRITE_SYNC_IO,WRITE_ASYNC_IO}] in tracepoint function, and rename iotype to page_type to match the definition. Reported-by: kernel test robot Reported-by: Dan Carpenter Signed-off-by: Yangtao Li Reviewed-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/data.c | 4 ++-- fs/f2fs/iostat.c | 48 ++++++++++++++++++---------------------- fs/f2fs/iostat.h | 19 ++++++++-------- include/trace/events/f2fs.h | 54 ++++++++++++++++++++++----------------------- 4 files changed, 60 insertions(+), 65 deletions(-) (limited to 'fs/f2fs') diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c index 8a636500db0e..890644cc2e3d 100644 --- a/fs/f2fs/data.c +++ b/fs/f2fs/data.c @@ -292,7 +292,7 @@ static void f2fs_read_end_io(struct bio *bio) struct bio_post_read_ctx *ctx; bool intask = in_task(); - iostat_update_and_unbind_ctx(bio, 0); + iostat_update_and_unbind_ctx(bio); ctx = bio->bi_private; if (time_to_inject(sbi, FAULT_READ_IO)) @@ -330,7 +330,7 @@ static void f2fs_write_end_io(struct bio *bio) struct bio_vec *bvec; struct bvec_iter_all iter_all; - iostat_update_and_unbind_ctx(bio, 1); + iostat_update_and_unbind_ctx(bio); sbi = bio->bi_private; if (time_to_inject(sbi, FAULT_WRITE_IO)) diff --git a/fs/f2fs/iostat.c b/fs/f2fs/iostat.c index 96637756eae8..3d5bfb1ad585 100644 --- a/fs/f2fs/iostat.c +++ b/fs/f2fs/iostat.c @@ -14,7 +14,6 @@ #include "iostat.h" #include -#define NUM_PREALLOC_IOSTAT_CTXS 128 static struct kmem_cache *bio_iostat_ctx_cache; static mempool_t *bio_iostat_ctx_pool; @@ -210,53 +209,48 @@ void f2fs_update_iostat(struct f2fs_sb_info *sbi, struct inode *inode, } static inline void __update_iostat_latency(struct bio_iostat_ctx *iostat_ctx, - int rw, bool is_sync) + enum iostat_lat_type lat_type) { unsigned long ts_diff; - unsigned int iotype = iostat_ctx->type; + unsigned int page_type = iostat_ctx->type; struct f2fs_sb_info *sbi = iostat_ctx->sbi; struct iostat_lat_info *io_lat = sbi->iostat_io_lat; - int idx; unsigned long flags; if (!sbi->iostat_enable) return; ts_diff = jiffies - iostat_ctx->submit_ts; - if (iotype == META_FLUSH) { - iotype = META; - } else if (iotype >= NR_PAGE_TYPE) { - f2fs_warn(sbi, "%s: %d over NR_PAGE_TYPE", __func__, iotype); + if (page_type == META_FLUSH) { + page_type = META; + } else if (page_type >= NR_PAGE_TYPE) { + f2fs_warn(sbi, "%s: %d over NR_PAGE_TYPE", __func__, page_type); return; } - if (rw == 0) { - idx = READ_IO; - } else { - if (is_sync) - idx = WRITE_SYNC_IO; - else - idx = WRITE_ASYNC_IO; - } - spin_lock_irqsave(&sbi->iostat_lat_lock, flags); - io_lat->sum_lat[idx][iotype] += ts_diff; - io_lat->bio_cnt[idx][iotype]++; - if (ts_diff > io_lat->peak_lat[idx][iotype]) - io_lat->peak_lat[idx][iotype] = ts_diff; + io_lat->sum_lat[lat_type][page_type] += ts_diff; + io_lat->bio_cnt[lat_type][page_type]++; + if (ts_diff > io_lat->peak_lat[lat_type][page_type]) + io_lat->peak_lat[lat_type][page_type] = ts_diff; spin_unlock_irqrestore(&sbi->iostat_lat_lock, flags); } -void iostat_update_and_unbind_ctx(struct bio *bio, int rw) +void iostat_update_and_unbind_ctx(struct bio *bio) { struct bio_iostat_ctx *iostat_ctx = bio->bi_private; - bool is_sync = bio->bi_opf & REQ_SYNC; + enum iostat_lat_type lat_type; - if (rw == 0) - bio->bi_private = iostat_ctx->post_read_ctx; - else + if (op_is_write(bio_op(bio))) { + lat_type = bio->bi_opf & REQ_SYNC ? + WRITE_SYNC_IO : WRITE_ASYNC_IO; bio->bi_private = iostat_ctx->sbi; - __update_iostat_latency(iostat_ctx, rw, is_sync); + } else { + lat_type = READ_IO; + bio->bi_private = iostat_ctx->post_read_ctx; + } + + __update_iostat_latency(iostat_ctx, lat_type); mempool_free(iostat_ctx, bio_iostat_ctx_pool); } diff --git a/fs/f2fs/iostat.h b/fs/f2fs/iostat.h index 2c048307b6e0..eb99d05cf272 100644 --- a/fs/f2fs/iostat.h +++ b/fs/f2fs/iostat.h @@ -8,20 +8,21 @@ struct bio_post_read_ctx; +enum iostat_lat_type { + READ_IO = 0, + WRITE_SYNC_IO, + WRITE_ASYNC_IO, + MAX_IO_TYPE, +}; + #ifdef CONFIG_F2FS_IOSTAT +#define NUM_PREALLOC_IOSTAT_CTXS 128 #define DEFAULT_IOSTAT_PERIOD_MS 3000 #define MIN_IOSTAT_PERIOD_MS 100 /* maximum period of iostat tracing is 1 day */ #define MAX_IOSTAT_PERIOD_MS 8640000 -enum { - READ_IO, - WRITE_SYNC_IO, - WRITE_ASYNC_IO, - MAX_IO_TYPE, -}; - struct iostat_lat_info { unsigned long sum_lat[MAX_IO_TYPE][NR_PAGE_TYPE]; /* sum of io latencies */ unsigned long peak_lat[MAX_IO_TYPE][NR_PAGE_TYPE]; /* peak io latency */ @@ -57,7 +58,7 @@ static inline struct bio_post_read_ctx *get_post_read_ctx(struct bio *bio) return iostat_ctx->post_read_ctx; } -extern void iostat_update_and_unbind_ctx(struct bio *bio, int rw); +extern void iostat_update_and_unbind_ctx(struct bio *bio); extern void iostat_alloc_and_bind_ctx(struct f2fs_sb_info *sbi, struct bio *bio, struct bio_post_read_ctx *ctx); extern int f2fs_init_iostat_processing(void); @@ -67,7 +68,7 @@ extern void f2fs_destroy_iostat(struct f2fs_sb_info *sbi); #else static inline void f2fs_update_iostat(struct f2fs_sb_info *sbi, struct inode *inode, enum iostat_type type, unsigned long long io_bytes) {} -static inline void iostat_update_and_unbind_ctx(struct bio *bio, int rw) {} +static inline void iostat_update_and_unbind_ctx(struct bio *bio) {} static inline void iostat_alloc_and_bind_ctx(struct f2fs_sb_info *sbi, struct bio *bio, struct bio_post_read_ctx *ctx) {} static inline void iostat_update_submit_ctx(struct bio *bio, diff --git a/include/trace/events/f2fs.h b/include/trace/events/f2fs.h index fe6bcf5f917d..1322d34a5dfc 100644 --- a/include/trace/events/f2fs.h +++ b/include/trace/events/f2fs.h @@ -2082,33 +2082,33 @@ TRACE_EVENT(f2fs_iostat_latency, TP_fast_assign( __entry->dev = sbi->sb->s_dev; - __entry->d_rd_peak = iostat_lat[0][DATA].peak_lat; - __entry->d_rd_avg = iostat_lat[0][DATA].avg_lat; - __entry->d_rd_cnt = iostat_lat[0][DATA].cnt; - __entry->n_rd_peak = iostat_lat[0][NODE].peak_lat; - __entry->n_rd_avg = iostat_lat[0][NODE].avg_lat; - __entry->n_rd_cnt = iostat_lat[0][NODE].cnt; - __entry->m_rd_peak = iostat_lat[0][META].peak_lat; - __entry->m_rd_avg = iostat_lat[0][META].avg_lat; - __entry->m_rd_cnt = iostat_lat[0][META].cnt; - __entry->d_wr_s_peak = iostat_lat[1][DATA].peak_lat; - __entry->d_wr_s_avg = iostat_lat[1][DATA].avg_lat; - __entry->d_wr_s_cnt = iostat_lat[1][DATA].cnt; - __entry->n_wr_s_peak = iostat_lat[1][NODE].peak_lat; - __entry->n_wr_s_avg = iostat_lat[1][NODE].avg_lat; - __entry->n_wr_s_cnt = iostat_lat[1][NODE].cnt; - __entry->m_wr_s_peak = iostat_lat[1][META].peak_lat; - __entry->m_wr_s_avg = iostat_lat[1][META].avg_lat; - __entry->m_wr_s_cnt = iostat_lat[1][META].cnt; - __entry->d_wr_as_peak = iostat_lat[2][DATA].peak_lat; - __entry->d_wr_as_avg = iostat_lat[2][DATA].avg_lat; - __entry->d_wr_as_cnt = iostat_lat[2][DATA].cnt; - __entry->n_wr_as_peak = iostat_lat[2][NODE].peak_lat; - __entry->n_wr_as_avg = iostat_lat[2][NODE].avg_lat; - __entry->n_wr_as_cnt = iostat_lat[2][NODE].cnt; - __entry->m_wr_as_peak = iostat_lat[2][META].peak_lat; - __entry->m_wr_as_avg = iostat_lat[2][META].avg_lat; - __entry->m_wr_as_cnt = iostat_lat[2][META].cnt; + __entry->d_rd_peak = iostat_lat[READ_IO][DATA].peak_lat; + __entry->d_rd_avg = iostat_lat[READ_IO][DATA].avg_lat; + __entry->d_rd_cnt = iostat_lat[READ_IO][DATA].cnt; + __entry->n_rd_peak = iostat_lat[READ_IO][NODE].peak_lat; + __entry->n_rd_avg = iostat_lat[READ_IO][NODE].avg_lat; + __entry->n_rd_cnt = iostat_lat[READ_IO][NODE].cnt; + __entry->m_rd_peak = iostat_lat[READ_IO][META].peak_lat; + __entry->m_rd_avg = iostat_lat[READ_IO][META].avg_lat; + __entry->m_rd_cnt = iostat_lat[READ_IO][META].cnt; + __entry->d_wr_s_peak = iostat_lat[WRITE_SYNC_IO][DATA].peak_lat; + __entry->d_wr_s_avg = iostat_lat[WRITE_SYNC_IO][DATA].avg_lat; + __entry->d_wr_s_cnt = iostat_lat[WRITE_SYNC_IO][DATA].cnt; + __entry->n_wr_s_peak = iostat_lat[WRITE_SYNC_IO][NODE].peak_lat; + __entry->n_wr_s_avg = iostat_lat[WRITE_SYNC_IO][NODE].avg_lat; + __entry->n_wr_s_cnt = iostat_lat[WRITE_SYNC_IO][NODE].cnt; + __entry->m_wr_s_peak = iostat_lat[WRITE_SYNC_IO][META].peak_lat; + __entry->m_wr_s_avg = iostat_lat[WRITE_SYNC_IO][META].avg_lat; + __entry->m_wr_s_cnt = iostat_lat[WRITE_SYNC_IO][META].cnt; + __entry->d_wr_as_peak = iostat_lat[WRITE_ASYNC_IO][DATA].peak_lat; + __entry->d_wr_as_avg = iostat_lat[WRITE_ASYNC_IO][DATA].avg_lat; + __entry->d_wr_as_cnt = iostat_lat[WRITE_ASYNC_IO][DATA].cnt; + __entry->n_wr_as_peak = iostat_lat[WRITE_ASYNC_IO][NODE].peak_lat; + __entry->n_wr_as_avg = iostat_lat[WRITE_ASYNC_IO][NODE].avg_lat; + __entry->n_wr_as_cnt = iostat_lat[WRITE_ASYNC_IO][NODE].cnt; + __entry->m_wr_as_peak = iostat_lat[WRITE_ASYNC_IO][META].peak_lat; + __entry->m_wr_as_avg = iostat_lat[WRITE_ASYNC_IO][META].avg_lat; + __entry->m_wr_as_cnt = iostat_lat[WRITE_ASYNC_IO][META].cnt; ), TP_printk("dev = (%d,%d), " -- cgit v1.2.3 From 267c159f9c7bcb7009dae16889b880c5ed8759a8 Mon Sep 17 00:00:00 2001 From: Jaegeuk Kim Date: Sun, 5 Feb 2023 19:13:39 -0800 Subject: f2fs: fix kernel crash due to null io->bio We should return when io->bio is null before doing anything. Otherwise, panic. BUG: kernel NULL pointer dereference, address: 0000000000000010 RIP: 0010:__submit_merged_write_cond+0x164/0x240 [f2fs] Call Trace: f2fs_submit_merged_write+0x1d/0x30 [f2fs] commit_checkpoint+0x110/0x1e0 [f2fs] f2fs_write_checkpoint+0x9f7/0xf00 [f2fs] ? __pfx_issue_checkpoint_thread+0x10/0x10 [f2fs] __checkpoint_and_complete_reqs+0x84/0x190 [f2fs] ? preempt_count_add+0x82/0xc0 ? __pfx_issue_checkpoint_thread+0x10/0x10 [f2fs] issue_checkpoint_thread+0x4c/0xf0 [f2fs] ? __pfx_autoremove_wake_function+0x10/0x10 kthread+0xff/0x130 ? __pfx_kthread+0x10/0x10 ret_from_fork+0x2c/0x50 Cc: stable@vger.kernel.org # v5.18+ Fixes: 64bf0eef0171 ("f2fs: pass the bio operation to bio_alloc_bioset") Reviewed-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/data.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'fs/f2fs') diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c index 890644cc2e3d..d04220cc2d26 100644 --- a/fs/f2fs/data.c +++ b/fs/f2fs/data.c @@ -653,6 +653,9 @@ static void __f2fs_submit_merged_write(struct f2fs_sb_info *sbi, f2fs_down_write(&io->io_rwsem); + if (!io->bio) + goto unlock_out; + /* change META to META_FLUSH in the checkpoint procedure */ if (type >= META_FLUSH) { io->fio.type = META_FLUSH; @@ -661,6 +664,7 @@ static void __f2fs_submit_merged_write(struct f2fs_sb_info *sbi, io->bio->bi_opf |= REQ_PREFLUSH | REQ_FUA; } __submit_merged_bio(io); +unlock_out: f2fs_up_write(&io->io_rwsem); } -- cgit v1.2.3 From 146949defda868378992171b9e42318b06fcd482 Mon Sep 17 00:00:00 2001 From: Jinyoung CHOI Date: Mon, 6 Feb 2023 20:56:00 +0900 Subject: f2fs: fix typos in comments This patch is to fix typos in f2fs files. Signed-off-by: Jinyoung Choi Reviewed-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/checkpoint.c | 4 ++-- fs/f2fs/compress.c | 2 +- fs/f2fs/data.c | 8 ++++---- fs/f2fs/extent_cache.c | 4 ++-- fs/f2fs/file.c | 6 +++--- fs/f2fs/namei.c | 2 +- fs/f2fs/segment.c | 2 +- 7 files changed, 14 insertions(+), 14 deletions(-) (limited to 'fs/f2fs') diff --git a/fs/f2fs/checkpoint.c b/fs/f2fs/checkpoint.c index 89ce08b0ff7c..1369ec892a2c 100644 --- a/fs/f2fs/checkpoint.c +++ b/fs/f2fs/checkpoint.c @@ -792,7 +792,7 @@ static void write_orphan_inodes(struct f2fs_sb_info *sbi, block_t start_blk) */ head = &im->ino_list; - /* loop for each orphan inode entry and write them in Jornal block */ + /* loop for each orphan inode entry and write them in journal block */ list_for_each_entry(orphan, head, list) { if (!page) { page = f2fs_grab_meta_page(sbi, start_blk++); @@ -1122,7 +1122,7 @@ retry: } else { /* * We should submit bio, since it exists several - * wribacking dentry pages in the freeing inode. + * writebacking dentry pages in the freeing inode. */ f2fs_submit_merged_write(sbi, DATA); cond_resched(); diff --git a/fs/f2fs/compress.c b/fs/f2fs/compress.c index e4851f7a43d8..b40dec3d7f79 100644 --- a/fs/f2fs/compress.c +++ b/fs/f2fs/compress.c @@ -1225,7 +1225,7 @@ static int f2fs_write_compressed_pages(struct compress_ctx *cc, loff_t psize; int i, err; - /* we should bypass data pages to proceed the kworkder jobs */ + /* we should bypass data pages to proceed the kworker jobs */ if (unlikely(f2fs_cp_error(sbi))) { mapping_set_error(cc->rpages[0]->mapping, -EIO); goto out_free; diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c index d04220cc2d26..28e09682b056 100644 --- a/fs/f2fs/data.c +++ b/fs/f2fs/data.c @@ -2386,7 +2386,7 @@ static int f2fs_mpage_readpages(struct inode *inode, #ifdef CONFIG_F2FS_FS_COMPRESSION if (f2fs_compressed_file(inode)) { - /* there are remained comressed pages, submit them */ + /* there are remained compressed pages, submit them */ if (!f2fs_cluster_can_merge_page(&cc, page->index)) { ret = f2fs_read_multi_pages(&cc, &bio, max_nr_pages, @@ -2792,7 +2792,7 @@ int f2fs_write_single_data_page(struct page *page, int *submitted, trace_f2fs_writepage(page, DATA); - /* we should bypass data pages to proceed the kworkder jobs */ + /* we should bypass data pages to proceed the kworker jobs */ if (unlikely(f2fs_cp_error(sbi))) { mapping_set_error(page->mapping, -EIO); /* @@ -2911,7 +2911,7 @@ out: redirty_out: redirty_page_for_writepage(wbc, page); /* - * pageout() in MM traslates EAGAIN, so calls handle_write_error() + * pageout() in MM translates EAGAIN, so calls handle_write_error() * -> mapping_set_error() -> set_bit(AS_EIO, ...). * file_write_and_wait_range() will see EIO error, which is critical * to return value of fsync() followed by atomic_write failure to user. @@ -2945,7 +2945,7 @@ out: } /* - * This function was copied from write_cche_pages from mm/page-writeback.c. + * This function was copied from write_cache_pages from mm/page-writeback.c. * The major change is making write step of cold data page separately from * warm/hot data page. */ diff --git a/fs/f2fs/extent_cache.c b/fs/f2fs/extent_cache.c index aef308e871ab..8d922c592dae 100644 --- a/fs/f2fs/extent_cache.c +++ b/fs/f2fs/extent_cache.c @@ -233,7 +233,7 @@ struct rb_node **f2fs_lookup_rb_tree_for_insert(struct f2fs_sb_info *sbi, * @prev_ex: extent before ofs * @next_ex: extent after ofs * @insert_p: insert point for new extent at ofs - * in order to simpfy the insertion after. + * in order to simplify the insertion after. * tree must stay unchanged between lookup and insertion. */ struct rb_entry *f2fs_lookup_rb_tree_ret(struct rb_root_cached *root, @@ -718,7 +718,7 @@ static void __update_extent_tree_range(struct inode *inode, if (!en) en = next_en; - /* 2. invlidate all extent nodes in range [fofs, fofs + len - 1] */ + /* 2. invalidate all extent nodes in range [fofs, fofs + len - 1] */ while (en && en->ei.fofs < end) { unsigned int org_end; int parts = 0; /* # of parts current extent split into */ diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c index a17aca50c18c..300eae8b5415 100644 --- a/fs/f2fs/file.c +++ b/fs/f2fs/file.c @@ -303,7 +303,7 @@ static int f2fs_do_sync_file(struct file *file, loff_t start, loff_t end, * for OPU case, during fsync(), node can be persisted before * data when lower device doesn't support write barrier, result * in data corruption after SPO. - * So for strict fsync mode, force to use atomic write sematics + * So for strict fsync mode, force to use atomic write semantics * to keep write order in between data/node and last node to * avoid potential data corruption. */ @@ -1806,7 +1806,7 @@ static long f2fs_fallocate(struct file *file, int mode, return -EOPNOTSUPP; /* - * Pinned file should not support partial trucation since the block + * Pinned file should not support partial truncation since the block * can be used by applications. */ if ((f2fs_compressed_file(inode) || f2fs_is_pinned_file(inode)) && @@ -1856,7 +1856,7 @@ out: static int f2fs_release_file(struct inode *inode, struct file *filp) { /* - * f2fs_relase_file is called at every close calls. So we should + * f2fs_release_file is called at every close calls. So we should * not drop any inmemory pages by close called by other process. */ if (!(filp->f_mode & FMODE_WRITE) || diff --git a/fs/f2fs/namei.c b/fs/f2fs/namei.c index 82923273f4bb..f9aafb7ac44d 100644 --- a/fs/f2fs/namei.c +++ b/fs/f2fs/namei.c @@ -963,7 +963,7 @@ static int f2fs_rename(struct user_namespace *mnt_userns, struct inode *old_dir, /* * If new_inode is null, the below renaming flow will - * add a link in old_dir which can conver inline_dir. + * add a link in old_dir which can convert inline_dir. * After then, if we failed to get the entry due to other * reasons like ENOMEM, we had to remove the new entry. * Instead of adding such the error handling routine, let's diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c index 69b01b5c0ce0..ead3f35f501d 100644 --- a/fs/f2fs/segment.c +++ b/fs/f2fs/segment.c @@ -3616,7 +3616,7 @@ void f2fs_wait_on_page_writeback(struct page *page, /* submit cached LFS IO */ f2fs_submit_merged_write_cond(sbi, NULL, page, 0, type); - /* sbumit cached IPU IO */ + /* submit cached IPU IO */ f2fs_submit_merged_ipu_write(sbi, NULL, page); if (ordered) { wait_on_page_writeback(page); -- cgit v1.2.3 From c5bf83483382600988d7db5ffe9fcd1936b491fd Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Mon, 6 Feb 2023 22:43:08 +0800 Subject: f2fs: fix to set ipu policy For LFS mode, it should update outplace and no need inplace update. When using LFS mode for small-volume devices, IPU will not be used, and the OPU writing method is actually used, but F2FS_IPU_FORCE can be read from the ipu_policy node, which is different from the actual situation. And remount to lfs mode should be disallowed when f2fs ipu is enabled, let's fix it. Fixes: 84b89e5d943d ("f2fs: add auto tuning for small devices") Signed-off-by: Yangtao Li Reviewed-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/segment.h | 10 +++++++++- fs/f2fs/super.c | 15 +++++++++++---- fs/f2fs/sysfs.c | 9 +++++++++ 3 files changed, 29 insertions(+), 5 deletions(-) (limited to 'fs/f2fs') diff --git a/fs/f2fs/segment.h b/fs/f2fs/segment.h index 0f3f05cb8c29..8ee5e5db9287 100644 --- a/fs/f2fs/segment.h +++ b/fs/f2fs/segment.h @@ -670,6 +670,8 @@ static inline int utilization(struct f2fs_sb_info *sbi) #define SMALL_VOLUME_SEGMENTS (16 * 512) /* 16GB */ +#define F2FS_IPU_DISABLE 0 + enum { F2FS_IPU_FORCE, F2FS_IPU_SSR, @@ -679,10 +681,16 @@ enum { F2FS_IPU_ASYNC, F2FS_IPU_NOCACHE, F2FS_IPU_HONOR_OPU_WRITE, + F2FS_IPU_MAX, }; +static inline bool IS_F2FS_IPU_DISABLE(struct f2fs_sb_info *sbi) +{ + return SM_I(sbi)->ipu_policy == F2FS_IPU_DISABLE; +} + #define F2FS_IPU_POLICY(name) \ -static inline int IS_##name(struct f2fs_sb_info *sbi) \ +static inline bool IS_##name(struct f2fs_sb_info *sbi) \ { \ return SM_I(sbi)->ipu_policy & BIT(name); \ } diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c index 4ec2cbbc47eb..c11a161ba5be 100644 --- a/fs/f2fs/super.c +++ b/fs/f2fs/super.c @@ -1346,12 +1346,12 @@ default_check: } if (test_opt(sbi, DISABLE_CHECKPOINT) && f2fs_lfs_mode(sbi)) { - f2fs_err(sbi, "LFS not compatible with checkpoint=disable"); + f2fs_err(sbi, "LFS is not compatible with checkpoint=disable"); return -EINVAL; } if (test_opt(sbi, ATGC) && f2fs_lfs_mode(sbi)) { - f2fs_err(sbi, "LFS not compatible with ATGC"); + f2fs_err(sbi, "LFS is not compatible with ATGC"); return -EINVAL; } @@ -2304,6 +2304,12 @@ static int f2fs_remount(struct super_block *sb, int *flags, char *data) } } #endif + if (f2fs_lfs_mode(sbi) && !IS_F2FS_IPU_DISABLE(sbi)) { + err = -EINVAL; + f2fs_warn(sbi, "LFS is not compatible with IPU"); + goto restore_opts; + } + /* disallow enable atgc dynamically */ if (no_atgc == !!test_opt(sbi, ATGC)) { err = -EINVAL; @@ -4085,8 +4091,9 @@ static void f2fs_tuning_parameters(struct f2fs_sb_info *sbi) if (f2fs_block_unit_discard(sbi)) SM_I(sbi)->dcc_info->discard_granularity = MIN_DISCARD_GRANULARITY; - SM_I(sbi)->ipu_policy = BIT(F2FS_IPU_FORCE) | - BIT(F2FS_IPU_HONOR_OPU_WRITE); + if (!f2fs_lfs_mode(sbi)) + SM_I(sbi)->ipu_policy = BIT(F2FS_IPU_FORCE) | + BIT(F2FS_IPU_HONOR_OPU_WRITE); } sbi->readdir_ra = true; diff --git a/fs/f2fs/sysfs.c b/fs/f2fs/sysfs.c index 8789b3b53fb6..6082e132257a 100644 --- a/fs/f2fs/sysfs.c +++ b/fs/f2fs/sysfs.c @@ -706,6 +706,15 @@ out: return count; } + if (!strcmp(a->attr.name, "ipu_policy")) { + if (t >= BIT(F2FS_IPU_MAX)) + return -EINVAL; + if (t && f2fs_lfs_mode(sbi)) + return -EINVAL; + SM_I(sbi)->ipu_policy = (unsigned int)t; + return count; + } + *ui = (unsigned int)t; return count; -- cgit v1.2.3 From 269d119481008cd725ce32553332593c0ecfc91c Mon Sep 17 00:00:00 2001 From: Chao Yu Date: Tue, 7 Feb 2023 21:48:08 +0800 Subject: f2fs: fix to do sanity check on extent cache correctly In do_read_inode(), sanity check for extent cache should be called after f2fs_init_read_extent_tree(), fix it. Fixes: 72840cccc0a1 ("f2fs: allocate the extent_cache by default") Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/extent_cache.c | 25 +++++++++++++++++++++++++ fs/f2fs/f2fs.h | 1 + fs/f2fs/inode.c | 22 ++++++---------------- 3 files changed, 32 insertions(+), 16 deletions(-) (limited to 'fs/f2fs') diff --git a/fs/f2fs/extent_cache.c b/fs/f2fs/extent_cache.c index 8d922c592dae..28b12553f2b3 100644 --- a/fs/f2fs/extent_cache.c +++ b/fs/f2fs/extent_cache.c @@ -19,6 +19,31 @@ #include "node.h" #include +bool sanity_check_extent_cache(struct inode *inode) +{ + struct f2fs_sb_info *sbi = F2FS_I_SB(inode); + struct f2fs_inode_info *fi = F2FS_I(inode); + struct extent_info *ei; + + if (!fi->extent_tree[EX_READ]) + return true; + + ei = &fi->extent_tree[EX_READ]->largest; + + if (ei->len && + (!f2fs_is_valid_blkaddr(sbi, ei->blk, + DATA_GENERIC_ENHANCE) || + !f2fs_is_valid_blkaddr(sbi, ei->blk + ei->len - 1, + DATA_GENERIC_ENHANCE))) { + set_sbi_flag(sbi, SBI_NEED_FSCK); + f2fs_warn(sbi, "%s: inode (ino=%lx) extent info [%u, %u, %u] is incorrect, run fsck to fix", + __func__, inode->i_ino, + ei->blk, ei->fofs, ei->len); + return false; + } + return true; +} + static void __set_extent_info(struct extent_info *ei, unsigned int fofs, unsigned int len, block_t blk, bool keep_clen, diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index 44f2d76525bf..21596e0266ba 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h @@ -4137,6 +4137,7 @@ void f2fs_leave_shrinker(struct f2fs_sb_info *sbi); /* * extent_cache.c */ +bool sanity_check_extent_cache(struct inode *inode); struct rb_entry *f2fs_lookup_rb_tree(struct rb_root_cached *root, struct rb_entry *cached_re, unsigned int ofs); struct rb_node **f2fs_lookup_rb_tree_ext(struct f2fs_sb_info *sbi, diff --git a/fs/f2fs/inode.c b/fs/f2fs/inode.c index 28c9c72dda2a..2c250120d5da 100644 --- a/fs/f2fs/inode.c +++ b/fs/f2fs/inode.c @@ -262,22 +262,6 @@ static bool sanity_check_inode(struct inode *inode, struct page *node_page) return false; } - if (fi->extent_tree[EX_READ]) { - struct extent_info *ei = &fi->extent_tree[EX_READ]->largest; - - if (ei->len && - (!f2fs_is_valid_blkaddr(sbi, ei->blk, - DATA_GENERIC_ENHANCE) || - !f2fs_is_valid_blkaddr(sbi, ei->blk + ei->len - 1, - DATA_GENERIC_ENHANCE))) { - set_sbi_flag(sbi, SBI_NEED_FSCK); - f2fs_warn(sbi, "%s: inode (ino=%lx) extent info [%u, %u, %u] is incorrect, run fsck to fix", - __func__, inode->i_ino, - ei->blk, ei->fofs, ei->len); - return false; - } - } - if (f2fs_sanity_check_inline_data(inode)) { set_sbi_flag(sbi, SBI_NEED_FSCK); f2fs_warn(sbi, "%s: inode (ino=%lx, mode=%u) should not have inline_data, run fsck to fix", @@ -488,6 +472,12 @@ static int do_read_inode(struct inode *inode) return -EFSCORRUPTED; } + if (!sanity_check_extent_cache(inode)) { + f2fs_put_page(node_page, 1); + f2fs_handle_error(sbi, ERROR_CORRUPTED_INODE); + return -EFSCORRUPTED; + } + f2fs_put_page(node_page, 1); stat_inc_inline_xattr(inode); -- cgit v1.2.3 From 273a51e5521213a13e5852e762cc9c03c66b9baa Mon Sep 17 00:00:00 2001 From: Thomas Weißschuh Date: Thu, 9 Feb 2023 03:20:10 +0000 Subject: f2fs: make kobj_type structures constant MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since commit ee6d3dd4ed48 ("driver core: make kobj_type constant.") the driver core allows the usage of const struct kobj_type. Take advantage of this to constify the structure definitions to prevent modification at runtime. Signed-off-by: Thomas Weißschuh Reviewed-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/sysfs.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'fs/f2fs') diff --git a/fs/f2fs/sysfs.c b/fs/f2fs/sysfs.c index 6082e132257a..0b19163c90d4 100644 --- a/fs/f2fs/sysfs.c +++ b/fs/f2fs/sysfs.c @@ -1162,13 +1162,13 @@ static const struct sysfs_ops f2fs_attr_ops = { .store = f2fs_attr_store, }; -static struct kobj_type f2fs_sb_ktype = { +static const struct kobj_type f2fs_sb_ktype = { .default_groups = f2fs_groups, .sysfs_ops = &f2fs_attr_ops, .release = f2fs_sb_release, }; -static struct kobj_type f2fs_ktype = { +static const struct kobj_type f2fs_ktype = { .sysfs_ops = &f2fs_attr_ops, }; @@ -1176,7 +1176,7 @@ static struct kset f2fs_kset = { .kobj = {.ktype = &f2fs_ktype}, }; -static struct kobj_type f2fs_feat_ktype = { +static const struct kobj_type f2fs_feat_ktype = { .default_groups = f2fs_feat_groups, .sysfs_ops = &f2fs_attr_ops, }; @@ -1217,7 +1217,7 @@ static const struct sysfs_ops f2fs_stat_attr_ops = { .store = f2fs_stat_attr_store, }; -static struct kobj_type f2fs_stat_ktype = { +static const struct kobj_type f2fs_stat_ktype = { .default_groups = f2fs_stat_groups, .sysfs_ops = &f2fs_stat_attr_ops, .release = f2fs_stat_kobj_release, @@ -1244,7 +1244,7 @@ static const struct sysfs_ops f2fs_feature_list_attr_ops = { .show = f2fs_sb_feat_attr_show, }; -static struct kobj_type f2fs_feature_list_ktype = { +static const struct kobj_type f2fs_feature_list_ktype = { .default_groups = f2fs_sb_feat_groups, .sysfs_ops = &f2fs_feature_list_attr_ops, .release = f2fs_feature_list_kobj_release, -- cgit v1.2.3 From f2e357893cb7d15994e4ec10838ebb4dccf7eb6e Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Mon, 13 Feb 2023 22:18:24 +0800 Subject: f2fs: export ipu policy in debugfs Export ipu_policy as a string in debugfs for better readability and it can help us better understand some strategies of the file system. Signed-off-by: Yangtao Li Reviewed-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/debug.c | 24 ++++++++++++++++++++++++ fs/f2fs/segment.h | 1 + 2 files changed, 25 insertions(+) (limited to 'fs/f2fs') diff --git a/fs/f2fs/debug.c b/fs/f2fs/debug.c index 32af4f0c5735..ff5995cb9560 100644 --- a/fs/f2fs/debug.c +++ b/fs/f2fs/debug.c @@ -354,6 +354,17 @@ static char *s_flag[] = { [SBI_IS_FREEZING] = " freezefs", }; +static const char *ipu_mode_names[F2FS_IPU_MAX] = { + [F2FS_IPU_FORCE] = "FORCE", + [F2FS_IPU_SSR] = "SSR", + [F2FS_IPU_UTIL] = "UTIL", + [F2FS_IPU_SSR_UTIL] = "SSR_UTIL", + [F2FS_IPU_FSYNC] = "FSYNC", + [F2FS_IPU_ASYNC] = "ASYNC", + [F2FS_IPU_NOCACHE] = "NOCACHE", + [F2FS_IPU_HONOR_OPU_WRITE] = "HONOR_OPU_WRITE", +}; + static int stat_show(struct seq_file *s, void *v) { struct f2fs_stat_info *si; @@ -384,6 +395,19 @@ static int stat_show(struct seq_file *s, void *v) seq_printf(s, "Current Time Sec: %llu / Mounted Time Sec: %llu\n\n", ktime_get_boottime_seconds(), SIT_I(si->sbi)->mounted_time); + + seq_puts(s, "Policy:\n"); + seq_puts(s, " - IPU: ["); + if (IS_F2FS_IPU_DISABLE(si->sbi)) { + seq_puts(s, " DISABLE"); + } else { + unsigned long policy = SM_I(si->sbi)->ipu_policy; + + for_each_set_bit(j, &policy, F2FS_IPU_MAX) + seq_printf(s, " %s", ipu_mode_names[j]); + } + seq_puts(s, " ]\n\n"); + if (test_opt(si->sbi, DISCARD)) seq_printf(s, "Utilization: %u%% (%u valid blocks, %u discard blocks)\n", si->utilization, si->valid_count, si->discard_blks); diff --git a/fs/f2fs/segment.h b/fs/f2fs/segment.h index 8ee5e5db9287..92c8be00d396 100644 --- a/fs/f2fs/segment.h +++ b/fs/f2fs/segment.h @@ -672,6 +672,7 @@ static inline int utilization(struct f2fs_sb_info *sbi) #define F2FS_IPU_DISABLE 0 +/* Modification on enum should be synchronized with ipu_mode_names array */ enum { F2FS_IPU_FORCE, F2FS_IPU_SSR, -- cgit v1.2.3 From dda7d77bcd424ce5da80dd5a7ec92ead00279c02 Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Mon, 13 Feb 2023 22:18:25 +0800 Subject: f2fs: replace si->sbi w/ sbi in stat_show() For each loop add a local f2fs_sb_info pointer insted of looking it up. Signed-off-by: Yangtao Li Reviewed-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/debug.c | 44 +++++++++++++++++++++++--------------------- 1 file changed, 23 insertions(+), 21 deletions(-) (limited to 'fs/f2fs') diff --git a/fs/f2fs/debug.c b/fs/f2fs/debug.c index ff5995cb9560..30a77936e3c5 100644 --- a/fs/f2fs/debug.c +++ b/fs/f2fs/debug.c @@ -373,16 +373,18 @@ static int stat_show(struct seq_file *s, void *v) raw_spin_lock_irqsave(&f2fs_stat_lock, flags); list_for_each_entry(si, &f2fs_stat_list, stat_list) { - update_general_status(si->sbi); + struct f2fs_sb_info *sbi = si->sbi; + + update_general_status(sbi); seq_printf(s, "\n=====[ partition info(%pg). #%d, %s, CP: %s]=====\n", - si->sbi->sb->s_bdev, i++, - f2fs_readonly(si->sbi->sb) ? "RO" : "RW", - is_set_ckpt_flags(si->sbi, CP_DISABLED_FLAG) ? - "Disabled" : (f2fs_cp_error(si->sbi) ? "Error" : "Good")); - if (si->sbi->s_flag) { + sbi->sb->s_bdev, i++, + f2fs_readonly(sbi->sb) ? "RO" : "RW", + is_set_ckpt_flags(sbi, CP_DISABLED_FLAG) ? + "Disabled" : (f2fs_cp_error(sbi) ? "Error" : "Good")); + if (sbi->s_flag) { seq_puts(s, "[SBI:"); - for_each_set_bit(j, &si->sbi->s_flag, 32) + for_each_set_bit(j, &sbi->s_flag, 32) seq_puts(s, s_flag[j]); seq_puts(s, "]\n"); } @@ -394,21 +396,21 @@ static int stat_show(struct seq_file *s, void *v) si->overp_segs, si->rsvd_segs); seq_printf(s, "Current Time Sec: %llu / Mounted Time Sec: %llu\n\n", ktime_get_boottime_seconds(), - SIT_I(si->sbi)->mounted_time); + SIT_I(sbi)->mounted_time); seq_puts(s, "Policy:\n"); seq_puts(s, " - IPU: ["); - if (IS_F2FS_IPU_DISABLE(si->sbi)) { + if (IS_F2FS_IPU_DISABLE(sbi)) { seq_puts(s, " DISABLE"); } else { - unsigned long policy = SM_I(si->sbi)->ipu_policy; + unsigned long policy = SM_I(sbi)->ipu_policy; for_each_set_bit(j, &policy, F2FS_IPU_MAX) seq_printf(s, " %s", ipu_mode_names[j]); } seq_puts(s, " ]\n\n"); - if (test_opt(si->sbi, DISCARD)) + if (test_opt(sbi, DISCARD)) seq_printf(s, "Utilization: %u%% (%u valid blocks, %u discard blocks)\n", si->utilization, si->valid_count, si->discard_blks); else @@ -515,15 +517,15 @@ static int stat_show(struct seq_file *s, void *v) seq_printf(s, " - node segments : %d (%d)\n", si->node_segs, si->bg_node_segs); seq_puts(s, " - Reclaimed segs :\n"); - seq_printf(s, " - Normal : %d\n", si->sbi->gc_reclaimed_segs[GC_NORMAL]); - seq_printf(s, " - Idle CB : %d\n", si->sbi->gc_reclaimed_segs[GC_IDLE_CB]); + seq_printf(s, " - Normal : %d\n", sbi->gc_reclaimed_segs[GC_NORMAL]); + seq_printf(s, " - Idle CB : %d\n", sbi->gc_reclaimed_segs[GC_IDLE_CB]); seq_printf(s, " - Idle Greedy : %d\n", - si->sbi->gc_reclaimed_segs[GC_IDLE_GREEDY]); - seq_printf(s, " - Idle AT : %d\n", si->sbi->gc_reclaimed_segs[GC_IDLE_AT]); + sbi->gc_reclaimed_segs[GC_IDLE_GREEDY]); + seq_printf(s, " - Idle AT : %d\n", sbi->gc_reclaimed_segs[GC_IDLE_AT]); seq_printf(s, " - Urgent High : %d\n", - si->sbi->gc_reclaimed_segs[GC_URGENT_HIGH]); - seq_printf(s, " - Urgent Mid : %d\n", si->sbi->gc_reclaimed_segs[GC_URGENT_MID]); - seq_printf(s, " - Urgent Low : %d\n", si->sbi->gc_reclaimed_segs[GC_URGENT_LOW]); + sbi->gc_reclaimed_segs[GC_URGENT_HIGH]); + seq_printf(s, " - Urgent Mid : %d\n", sbi->gc_reclaimed_segs[GC_URGENT_MID]); + seq_printf(s, " - Urgent Low : %d\n", sbi->gc_reclaimed_segs[GC_URGENT_LOW]); seq_printf(s, "Try to move %d blocks (BG: %d)\n", si->tot_blks, si->bg_data_blks + si->bg_node_blks); seq_printf(s, " - data blocks : %d (%d)\n", si->data_blks, @@ -589,7 +591,7 @@ static int stat_show(struct seq_file *s, void *v) si->ndirty_imeta); seq_printf(s, " - fsync mark: %4lld\n", percpu_counter_sum_positive( - &si->sbi->rf_node_block_count)); + &sbi->rf_node_block_count)); seq_printf(s, " - NATs: %9d/%9d\n - SITs: %9d/%9d\n", si->dirty_nats, si->nats, si->dirty_sits, si->sits); seq_printf(s, " - free_nids: %9d/%9d\n - alloc_nids: %9d\n", @@ -616,12 +618,12 @@ static int stat_show(struct seq_file *s, void *v) si->block_count[LFS], si->segment_count[LFS]); /* segment usage info */ - f2fs_update_sit_info(si->sbi); + f2fs_update_sit_info(sbi); seq_printf(s, "\nBDF: %u, avg. vblocks: %u\n", si->bimodal, si->avg_vblocks); /* memory footprint */ - update_mem_info(si->sbi); + update_mem_info(sbi); seq_printf(s, "\nMemory: %llu KB\n", (si->base_mem + si->cache_mem + si->page_mem) >> 10); seq_printf(s, " - static: %llu KB\n", -- cgit v1.2.3 From 7e986855fe13de2c8290c1102292d8e5f29dd769 Mon Sep 17 00:00:00 2001 From: Jaegeuk Kim Date: Mon, 13 Feb 2023 09:41:33 -0800 Subject: f2fs: fix wrong segment count MAIN_SEGS is for data area, while TOTAL_SEGS includes data and metadata. Reviewed-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/segment.h | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'fs/f2fs') diff --git a/fs/f2fs/segment.h b/fs/f2fs/segment.h index 92c8be00d396..efdb7fc3b797 100644 --- a/fs/f2fs/segment.h +++ b/fs/f2fs/segment.h @@ -719,9 +719,10 @@ static inline unsigned char curseg_alloc_type(struct f2fs_sb_info *sbi, return curseg->alloc_type; } -static inline void check_seg_range(struct f2fs_sb_info *sbi, unsigned int segno) +static inline bool valid_main_segno(struct f2fs_sb_info *sbi, + unsigned int segno) { - f2fs_bug_on(sbi, segno > TOTAL_SEGS(sbi) - 1); + return segno <= (MAIN_SEGS(sbi) - 1); } static inline void verify_fio_blkaddr(struct f2fs_io_info *fio) @@ -776,7 +777,7 @@ static inline int check_block_count(struct f2fs_sb_info *sbi, /* check segment usage, and check boundary of a given segment number */ if (unlikely(GET_SIT_VBLOCKS(raw_sit) > usable_blks_per_seg - || segno > TOTAL_SEGS(sbi) - 1)) { + || !valid_main_segno(sbi, segno))) { f2fs_err(sbi, "Wrong valid blocks %d or segno %u", GET_SIT_VBLOCKS(raw_sit), segno); set_sbi_flag(sbi, SBI_NEED_FSCK); @@ -793,7 +794,7 @@ static inline pgoff_t current_sit_addr(struct f2fs_sb_info *sbi, unsigned int offset = SIT_BLOCK_OFFSET(start); block_t blk_addr = sit_i->sit_base_addr + offset; - check_seg_range(sbi, start); + f2fs_bug_on(sbi, !valid_main_segno(sbi, start)); #ifdef CONFIG_F2FS_CHECK_FS if (f2fs_test_bit(offset, sit_i->sit_bitmap) != -- cgit v1.2.3 From a46bebd502fe1a3bd1d22f64cedd93e7e7702693 Mon Sep 17 00:00:00 2001 From: Daeho Jeong Date: Thu, 9 Feb 2023 10:18:19 -0800 Subject: f2fs: synchronize atomic write aborts To fix a race condition between atomic write aborts, I use the inode lock and make COW inode to be re-usable thoroughout the whole atomic file inode lifetime. Reported-by: syzbot+823000d23b3400619f7c@syzkaller.appspotmail.com Fixes: 3db1de0e582c ("f2fs: change the current atomic write way") Signed-off-by: Daeho Jeong Reviewed-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/file.c | 44 +++++++++++++++++++++++++++++--------------- fs/f2fs/inode.c | 11 +++++++++-- fs/f2fs/segment.c | 3 --- fs/f2fs/super.c | 2 -- 4 files changed, 38 insertions(+), 22 deletions(-) (limited to 'fs/f2fs') diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c index 300eae8b5415..6436c52e7913 100644 --- a/fs/f2fs/file.c +++ b/fs/f2fs/file.c @@ -1863,7 +1863,10 @@ static int f2fs_release_file(struct inode *inode, struct file *filp) atomic_read(&inode->i_writecount) != 1) return 0; + inode_lock(inode); f2fs_abort_atomic_write(inode, true); + inode_unlock(inode); + return 0; } @@ -1878,8 +1881,12 @@ static int f2fs_file_flush(struct file *file, fl_owner_t id) * before dropping file lock, it needs to do in ->flush. */ if (F2FS_I(inode)->atomic_write_task == current && - (current->flags & PF_EXITING)) + (current->flags & PF_EXITING)) { + inode_lock(inode); f2fs_abort_atomic_write(inode, true); + inode_unlock(inode); + } + return 0; } @@ -2085,19 +2092,28 @@ static int f2fs_ioc_start_atomic_write(struct file *filp, bool truncate) goto out; } - /* Create a COW inode for atomic write */ - pinode = f2fs_iget(inode->i_sb, fi->i_pino); - if (IS_ERR(pinode)) { - f2fs_up_write(&fi->i_gc_rwsem[WRITE]); - ret = PTR_ERR(pinode); - goto out; - } + /* Check if the inode already has a COW inode */ + if (fi->cow_inode == NULL) { + /* Create a COW inode for atomic write */ + pinode = f2fs_iget(inode->i_sb, fi->i_pino); + if (IS_ERR(pinode)) { + f2fs_up_write(&fi->i_gc_rwsem[WRITE]); + ret = PTR_ERR(pinode); + goto out; + } - ret = f2fs_get_tmpfile(mnt_userns, pinode, &fi->cow_inode); - iput(pinode); - if (ret) { - f2fs_up_write(&fi->i_gc_rwsem[WRITE]); - goto out; + ret = f2fs_get_tmpfile(mnt_userns, pinode, &fi->cow_inode); + iput(pinode); + if (ret) { + f2fs_up_write(&fi->i_gc_rwsem[WRITE]); + goto out; + } + + set_inode_flag(fi->cow_inode, FI_COW_FILE); + clear_inode_flag(fi->cow_inode, FI_INLINE_DATA); + } else { + /* Reuse the already created COW inode */ + f2fs_do_truncate_blocks(fi->cow_inode, 0, true); } f2fs_write_inode(inode, NULL); @@ -2105,8 +2121,6 @@ static int f2fs_ioc_start_atomic_write(struct file *filp, bool truncate) stat_inc_atomic_inode(inode); set_inode_flag(inode, FI_ATOMIC_FILE); - set_inode_flag(fi->cow_inode, FI_COW_FILE); - clear_inode_flag(fi->cow_inode, FI_INLINE_DATA); isize = i_size_read(inode); fi->original_i_size = isize; diff --git a/fs/f2fs/inode.c b/fs/f2fs/inode.c index 2c250120d5da..7d2e2c0dba65 100644 --- a/fs/f2fs/inode.c +++ b/fs/f2fs/inode.c @@ -767,11 +767,18 @@ int f2fs_write_inode(struct inode *inode, struct writeback_control *wbc) void f2fs_evict_inode(struct inode *inode) { struct f2fs_sb_info *sbi = F2FS_I_SB(inode); - nid_t xnid = F2FS_I(inode)->i_xattr_nid; + struct f2fs_inode_info *fi = F2FS_I(inode); + nid_t xnid = fi->i_xattr_nid; int err = 0; f2fs_abort_atomic_write(inode, true); + if (fi->cow_inode) { + clear_inode_flag(fi->cow_inode, FI_COW_FILE); + iput(fi->cow_inode); + fi->cow_inode = NULL; + } + trace_f2fs_evict_inode(inode); truncate_inode_pages_final(&inode->i_data); @@ -856,7 +863,7 @@ no_delete: stat_dec_inline_inode(inode); stat_dec_compr_inode(inode); stat_sub_compr_blocks(inode, - atomic_read(&F2FS_I(inode)->i_compr_blocks)); + atomic_read(&fi->i_compr_blocks)); if (likely(!f2fs_cp_error(sbi) && !is_sbi_flag_set(sbi, SBI_CP_DISABLED))) diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c index ead3f35f501d..719329c1808c 100644 --- a/fs/f2fs/segment.c +++ b/fs/f2fs/segment.c @@ -192,9 +192,6 @@ void f2fs_abort_atomic_write(struct inode *inode, bool clean) if (!f2fs_is_atomic_file(inode)) return; - clear_inode_flag(fi->cow_inode, FI_COW_FILE); - iput(fi->cow_inode); - fi->cow_inode = NULL; release_atomic_write_cnt(inode); clear_inode_flag(inode, FI_ATOMIC_COMMITTED); clear_inode_flag(inode, FI_ATOMIC_REPLACE); diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c index c11a161ba5be..aa55dc12aff2 100644 --- a/fs/f2fs/super.c +++ b/fs/f2fs/super.c @@ -1427,8 +1427,6 @@ static int f2fs_drop_inode(struct inode *inode) atomic_inc(&inode->i_count); spin_unlock(&inode->i_lock); - f2fs_abort_atomic_write(inode, true); - /* should remain fi->extent_tree for writepage */ f2fs_destroy_extent_node(inode); -- cgit v1.2.3 From c7dbc06688292db34c1bb9c715e29ac4935af994 Mon Sep 17 00:00:00 2001 From: Jaegeuk Kim Date: Tue, 14 Feb 2023 15:53:52 -0800 Subject: f2fs: Revert "f2fs: truncate blocks in batch in __complete_revoke_list()" We should not truncate replaced blocks, and were supposed to truncate the first part as well. This reverts commit 78a99fe6254cad4be310cd84af39f6c46b668c72. Cc: stable@vger.kernel.org Reviewed-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/segment.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'fs/f2fs') diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c index 719329c1808c..227e25836173 100644 --- a/fs/f2fs/segment.c +++ b/fs/f2fs/segment.c @@ -265,19 +265,24 @@ static void __complete_revoke_list(struct inode *inode, struct list_head *head, bool revoke) { struct revoke_entry *cur, *tmp; + pgoff_t start_index = 0; bool truncate = is_inode_flag_set(inode, FI_ATOMIC_REPLACE); list_for_each_entry_safe(cur, tmp, head, list) { - if (revoke) + if (revoke) { __replace_atomic_write_block(inode, cur->index, cur->old_addr, NULL, true); + } else if (truncate) { + f2fs_truncate_hole(inode, start_index, cur->index); + start_index = cur->index + 1; + } list_del(&cur->list); kmem_cache_free(revoke_entry_slab, cur); } if (!revoke && truncate) - f2fs_do_truncate_blocks(inode, 0, false); + f2fs_do_truncate_blocks(inode, start_index * PAGE_SIZE, false); } static int __f2fs_commit_atomic_write(struct inode *inode) -- cgit v1.2.3 From ddf1eca4fc5a4038cb323306f51fbba34ce3f4d2 Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Wed, 15 Feb 2023 14:17:01 +0800 Subject: f2fs: drop unnecessary arg for f2fs_ioc_*() They are not used, let's remove them. Signed-off-by: Yangtao Li Reviewed-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/file.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'fs/f2fs') diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c index 6436c52e7913..ca1720fc1187 100644 --- a/fs/f2fs/file.c +++ b/fs/f2fs/file.c @@ -2539,7 +2539,7 @@ static int f2fs_ioc_gc_range(struct file *filp, unsigned long arg) return __f2fs_ioc_gc_range(filp, &range); } -static int f2fs_ioc_write_checkpoint(struct file *filp, unsigned long arg) +static int f2fs_ioc_write_checkpoint(struct file *filp) { struct inode *inode = file_inode(filp); struct f2fs_sb_info *sbi = F2FS_I_SB(inode); @@ -3253,7 +3253,7 @@ int f2fs_precache_extents(struct inode *inode) return 0; } -static int f2fs_ioc_precache_extents(struct file *filp, unsigned long arg) +static int f2fs_ioc_precache_extents(struct file *filp) { return f2fs_precache_extents(file_inode(filp)); } @@ -4010,7 +4010,7 @@ static int redirty_blocks(struct inode *inode, pgoff_t page_idx, int len) return ret; } -static int f2fs_ioc_decompress_file(struct file *filp, unsigned long arg) +static int f2fs_ioc_decompress_file(struct file *filp) { struct inode *inode = file_inode(filp); struct f2fs_sb_info *sbi = F2FS_I_SB(inode); @@ -4083,7 +4083,7 @@ out: return ret; } -static int f2fs_ioc_compress_file(struct file *filp, unsigned long arg) +static int f2fs_ioc_compress_file(struct file *filp) { struct inode *inode = file_inode(filp); struct f2fs_sb_info *sbi = F2FS_I_SB(inode); @@ -4199,7 +4199,7 @@ static long __f2fs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) case F2FS_IOC_GARBAGE_COLLECT_RANGE: return f2fs_ioc_gc_range(filp, arg); case F2FS_IOC_WRITE_CHECKPOINT: - return f2fs_ioc_write_checkpoint(filp, arg); + return f2fs_ioc_write_checkpoint(filp); case F2FS_IOC_DEFRAGMENT: return f2fs_ioc_defragment(filp, arg); case F2FS_IOC_MOVE_RANGE: @@ -4213,7 +4213,7 @@ static long __f2fs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) case F2FS_IOC_SET_PIN_FILE: return f2fs_ioc_set_pin_file(filp, arg); case F2FS_IOC_PRECACHE_EXTENTS: - return f2fs_ioc_precache_extents(filp, arg); + return f2fs_ioc_precache_extents(filp); case F2FS_IOC_RESIZE_FS: return f2fs_ioc_resize_fs(filp, arg); case FS_IOC_ENABLE_VERITY: @@ -4239,9 +4239,9 @@ static long __f2fs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) case F2FS_IOC_SET_COMPRESS_OPTION: return f2fs_ioc_set_compress_option(filp, arg); case F2FS_IOC_DECOMPRESS_FILE: - return f2fs_ioc_decompress_file(filp, arg); + return f2fs_ioc_decompress_file(filp); case F2FS_IOC_COMPRESS_FILE: - return f2fs_ioc_compress_file(filp, arg); + return f2fs_ioc_compress_file(filp); default: return -ENOTTY; } -- cgit v1.2.3