Commit d46dd0d8 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull f2fs updates from Jaegeuk Kim:
 "In this round, the changes primarily focus on resolving race
  conditions, memory safety issues (UAF), and improving the robustness
  of garbage collection (GC), and folio management.

  Enhancements:
   - add page-order information for large folio reads in iostat
   - add defrag_blocks sysfs node

  Bug fixes:
   - fix uninitialized kobject put in f2fs_init_sysfs()
   - disallow setting an extension to both cold and hot
   - fix node_cnt race between extent node destroy and writeback
   - preserve previous reserve_{blocks,node} value when remount
   - freeze GC and discard threads quickly
   - fix false alarm of lockdep on cp_global_sem lock
   - fix data loss caused by incorrect use of nat_entry flag
   - skip empty sections in f2fs_get_victim
   - fix inline data not being written to disk in writeback path
   - fix fsck inconsistency caused by FGGC of node block
   - fix fsck inconsistency caused by incorrect nat_entry flag usage
   - call f2fs_handle_critical_error() to set cp_error flag
   - fix fiemap boundary handling when read extent cache is incomplete
   - fix use-after-free of sbi in f2fs_compress_write_end_io()
   - fix UAF caused by decrementing sbi->nr_pages[] in f2fs_write_end_io()
   - fix incorrect file address mapping when inline inode is unwritten
   - fix incomplete search range in f2fs_get_victim when f2fs_need_rand_seg is enabled
   - avoid memory leak in f2fs_rename()"

* tag 'f2fs-for-7.1-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/jaegeuk/f2fs: (35 commits)
  f2fs: add page-order information for large folio reads in iostat
  f2fs: do not support mmap write for large folio
  f2fs: fix uninitialized kobject put in f2fs_init_sysfs()
  f2fs: protect extension_list reading with sb_lock in f2fs_sbi_show()
  f2fs: disallow setting an extension to both cold and hot
  f2fs: fix node_cnt race between extent node destroy and writeback
  f2fs: allow empty mount string for Opt_usr|grp|projjquota
  f2fs: fix to preserve previous reserve_{blocks,node} value when remount
  f2fs: invalidate block device page cache on umount
  f2fs: fix to freeze GC and discard threads quickly
  f2fs: fix to avoid uninit-value access in f2fs_sanity_check_node_footer
  f2fs: fix false alarm of lockdep on cp_global_sem lock
  f2fs: fix data loss caused by incorrect use of nat_entry flag
  f2fs: fix to skip empty sections in f2fs_get_victim
  f2fs: fix inline data not being written to disk in writeback path
  f2fs: fix fsck inconsistency caused by FGGC of node block
  f2fs: fix fsck inconsistency caused by incorrect nat_entry flag usage
  f2fs: fix to do sanity check on dcc->discard_cmd_cnt conditionally
  f2fs: refactor node footer flag setting related code
  f2fs: refactor f2fs_move_node_folio function
  ...
parents bb0bc49a cb8ff3ea
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -407,6 +407,12 @@ Contact: "Hridya Valsaraju" <hridya@google.com>
Description:	Average number of valid blocks.
		Available when CONFIG_F2FS_STAT_FS=y.

What:		/sys/fs/f2fs/<disk>/defrag_blocks
Date:		February 2026
Contact:	"Jinbao Liu" <liujinbao1@xiaomi.com>
Description:	Number of blocks moved by defragment.
		Available when CONFIG_F2FS_STAT_FS=y.

What:		/sys/fs/f2fs/<disk>/mounted_time_sec
Date:		February 2020
Contact:	"Jaegeuk Kim" <jaegeuk@kernel.org>
+0 −9
Original line number Diff line number Diff line
@@ -232,15 +232,6 @@ static inline void f2fs_unlock_all(struct f2fs_sb_info *sbi)
static struct kmem_cache *ino_entry_slab;
struct kmem_cache *f2fs_inode_entry_slab;

void f2fs_stop_checkpoint(struct f2fs_sb_info *sbi, bool end_io,
						unsigned char reason)
{
	f2fs_build_fault_attr(sbi, 0, 0, FAULT_ALL);
	if (!end_io)
		f2fs_flush_merged_writes(sbi);
	f2fs_handle_critical_error(sbi, reason);
}

/*
 * We guarantee no failure on the returned page.
 */
+11 −3
Original line number Diff line number Diff line
@@ -1491,10 +1491,10 @@ void f2fs_compress_write_end_io(struct bio *bio, struct folio *folio)

	f2fs_compress_free_page(page);

	if (atomic_dec_return(&cic->pending_pages)) {
		dec_page_count(sbi, type);

	if (atomic_dec_return(&cic->pending_pages))
		return;
	}

	for (i = 0; i < cic->nr_rpages; i++) {
		WARN_ON(!cic->rpages[i]);
@@ -1504,6 +1504,14 @@ void f2fs_compress_write_end_io(struct bio *bio, struct folio *folio)

	page_array_free(sbi, cic->rpages, cic->nr_rpages);
	kmem_cache_free(cic_entry_slab, cic);

	/*
	 * Make sure dec_page_count() is the last access to sbi.
	 * Once it drops the F2FS_WB_CP_DATA counter to zero, the
	 * unmount thread can proceed to destroy sbi and
	 * sbi->page_array_slab.
	 */
	dec_page_count(sbi, type);
}

static int f2fs_write_raw_pages(struct compress_ctx *cc,
+34 −19
Original line number Diff line number Diff line
@@ -173,7 +173,8 @@ static void f2fs_finish_read_bio(struct bio *bio, bool in_task)
		while (nr_pages--)
			dec_page_count(F2FS_F_SB(folio), __read_io_type(folio));

		if (F2FS_F_SB(folio)->node_inode && is_node_folio(folio) &&
		if (bio->bi_status == BLK_STS_OK &&
			F2FS_F_SB(folio)->node_inode && is_node_folio(folio) &&
			f2fs_sanity_check_node_footer(F2FS_F_SB(folio),
				folio, folio->index, NODE_TYPE_REGULAR, true))
			bio->bi_status = BLK_STS_IOERR;
@@ -386,6 +387,8 @@ static void f2fs_write_end_io(struct bio *bio)
				folio->index, NODE_TYPE_REGULAR, true);
			f2fs_bug_on(sbi, folio->index != nid_of_node(folio));
		}
		if (f2fs_in_warm_node_list(folio))
			f2fs_del_fsync_node_entry(sbi, folio);

		dec_page_count(sbi, type);

@@ -397,8 +400,6 @@ static void f2fs_write_end_io(struct bio *bio)
				wq_has_sleeper(&sbi->cp_wait))
			wake_up(&sbi->cp_wait);

		if (f2fs_in_warm_node_list(sbi, folio))
			f2fs_del_fsync_node_entry(sbi, folio);
		folio_clear_f2fs_gcing(folio);
		folio_end_writeback(folio);
	}
@@ -1578,7 +1579,8 @@ static bool f2fs_map_blocks_cached(struct inode *inode,
		f2fs_wait_on_block_writeback_range(inode,
					map->m_pblk, map->m_len);

	if (f2fs_allow_multi_device_dio(sbi, flag)) {
	map->m_multidev_dio = f2fs_allow_multi_device_dio(sbi, flag);
	if (map->m_multidev_dio) {
		int bidx = f2fs_target_device_index(sbi, map->m_pblk);
		struct f2fs_dev_info *dev = &sbi->devs[bidx];

@@ -1638,8 +1640,26 @@ int f2fs_map_blocks(struct inode *inode, struct f2fs_map_blocks *map, int flag)
	lfs_dio_write = (flag == F2FS_GET_BLOCK_DIO && f2fs_lfs_mode(sbi) &&
				map->m_may_create);

	if (!map->m_may_create && f2fs_map_blocks_cached(inode, map, flag))
	if (!map->m_may_create && f2fs_map_blocks_cached(inode, map, flag)) {
		struct extent_info ei;

		/*
		 * 1. If map->m_multidev_dio is true, map->m_pblk cannot be
		 * waitted by f2fs_wait_on_block_writeback_range() and are not
		 * mergeable.
		 * 2. If pgofs hits the read extent cache, it means the mapping
		 * is already cached in the extent cache, but it is not
		 * mergeable, and there is no need to query the mapping again
		 * via f2fs_get_dnode_of_data().
		 */
		pgofs =	(pgoff_t)map->m_lblk + map->m_len;
		if (map->m_len == maxblocks ||
			map->m_multidev_dio ||
			f2fs_lookup_read_extent_cache(inode, pgofs, &ei))
			goto out;
		ofs = map->m_len;
		goto map_more;
	}

	map->m_bdev = inode->i_sb->s_bdev;
	map->m_multidev_dio =
@@ -1650,7 +1670,8 @@ int f2fs_map_blocks(struct inode *inode, struct f2fs_map_blocks *map, int flag)

	/* it only supports block size == page size */
	pgofs =	(pgoff_t)map->m_lblk;
	end = pgofs + maxblocks;
map_more:
	end = (pgoff_t)map->m_lblk + maxblocks;

	if (flag == F2FS_GET_BLOCK_PRECACHE)
		mode = LOOKUP_NODE_RA;
@@ -2490,6 +2511,8 @@ static int f2fs_read_data_large_folio(struct inode *inode,
	if (!folio)
		goto out;

	f2fs_update_read_folio_count(F2FS_I_SB(inode), folio);

	folio_in_bio = false;
	index = folio->index;
	offset = 0;
@@ -2664,6 +2687,8 @@ static int f2fs_mpage_readpages(struct inode *inode, struct fsverity_info *vi,
			prefetchw(&folio->flags);
		}

		f2fs_update_read_folio_count(F2FS_I_SB(inode), folio);

#ifdef CONFIG_F2FS_FS_COMPRESSION
		index = folio->index;

@@ -2790,7 +2815,6 @@ int f2fs_encrypt_one_page(struct f2fs_io_info *fio)
	struct inode *inode = fio_inode(fio);
	struct folio *mfolio;
	struct page *page;
	gfp_t gfp_flags = GFP_NOFS;

	if (!f2fs_encrypted_file(inode))
		return 0;
@@ -2800,19 +2824,10 @@ int f2fs_encrypt_one_page(struct f2fs_io_info *fio)
	if (fscrypt_inode_uses_inline_crypto(inode))
		return 0;

retry_encrypt:
	fio->encrypted_page = fscrypt_encrypt_pagecache_blocks(page_folio(page),
					PAGE_SIZE, 0, gfp_flags);
	if (IS_ERR(fio->encrypted_page)) {
		/* flush pending IOs and wait for a while in the ENOMEM case */
		if (PTR_ERR(fio->encrypted_page) == -ENOMEM) {
			f2fs_flush_merged_writes(fio->sbi);
			memalloc_retry_wait(GFP_NOFS);
			gfp_flags |= __GFP_NOFAIL;
			goto retry_encrypt;
		}
					PAGE_SIZE, 0, GFP_NOFS);
	if (IS_ERR(fio->encrypted_page))
		return PTR_ERR(fio->encrypted_page);
	}

	mfolio = filemap_lock_folio(META_MAPPING(fio->sbi), fio->old_blkaddr);
	if (!IS_ERR(mfolio)) {
+1 −0
Original line number Diff line number Diff line
@@ -659,6 +659,7 @@ static int stat_show(struct seq_file *s, void *v)
				si->bg_node_blks);
		seq_printf(s, "BG skip : IO: %u, Other: %u\n",
				si->io_skip_bggc, si->other_skip_bggc);
		seq_printf(s, "defrag blocks : %u\n", si->defrag_blks);
		seq_puts(s, "\nExtent Cache (Read):\n");
		seq_printf(s, "  - Hit Count: L1-1:%llu L1-2:%llu L2:%llu\n",
				si->hit_largest, si->hit_cached[EX_READ],
Loading