Commit cb015814 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull f2fs updates from Jaegeuk Kim:
 "This series focuses on minor clean-ups and performance optimizations
  across sysfs, documentation, debugfs, tracepoints, slab allocation,
  and GC. Furthermore, it resolves several corner-case bugs caught by
  xfstests, as well as issues related to 16KB page support and
  f2fs_enable_checkpoint.

  Enhancement:
   - wrap ASCII tables in literal blocks to fix LaTeX build
   - optimize trace_f2fs_write_checkpoint with enums
   - support to show curseg.next_blkoff in debugfs
   - add a sysfs entry to show max open zones
   - add fadvise tracepoint
   - use global inline_xattr_slab instead of per-sb slab cache
   - set default valid_thresh_ratio to 80 for zoned devices
   - maintain one time GC mode is enabled during whole zoned GC cycle

  Bug fix:
   - ensure node page reads complete before f2fs_put_super() finishes
   - do not account invalid blocks in get_left_section_blocks()
   - revert summary entry count from 2048 to 512 in 16kb block support
   - detect recoverable inode during dryrun of find_fsync_dnodes()
   - fix age extent cache insertion skip on counter overflow
   - add sanity checks before unlinking and loading inodes
   - ensure minimum trim granularity accounts for all devices
   - block cache/dio write during f2fs_enable_checkpoint()
   - propagate error from f2fs_enable_checkpoint()
   - invalidate dentry cache on failed whiteout creation
   - avoid updating compression context during writeback
   - avoid updating zero-sized extent in extent cache
   - avoid potential deadlock"

* tag 'f2fs-for-6.19-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/jaegeuk/f2fs: (39 commits)
  f2fs: ignore discard return value
  f2fs: optimize trace_f2fs_write_checkpoint with enums
  f2fs: fix to not account invalid blocks in get_left_section_blocks()
  f2fs: support to show curseg.next_blkoff in debugfs
  docs: f2fs: wrap ASCII tables in literal blocks to fix LaTeX build
  f2fs: expand scalability of f2fs mount option
  f2fs: change default schedule timeout value
  f2fs: introduce f2fs_schedule_timeout()
  f2fs: use memalloc_retry_wait() as much as possible
  f2fs: add a sysfs entry to show max open zones
  f2fs: wrap all unusable_blocks_per_sec code in CONFIG_BLK_DEV_ZONED
  f2fs: simplify list initialization in f2fs_recover_fsync_data()
  f2fs: revert summary entry count from 2048 to 512 in 16kb block support
  f2fs: fix to detect recoverable inode during dryrun of find_fsync_dnodes()
  f2fs: fix return value of f2fs_recover_fsync_data()
  f2fs: add fadvise tracepoint
  f2fs: fix age extent cache insertion skip on counter overflow
  f2fs: Add sanity checks before unlinking and loading inodes
  f2fs: Rename f2fs_unlink exit label
  f2fs: ensure minimum trim granularity accounts for all devices
  ...
parents cfd40392 76ee7fd6
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -643,6 +643,12 @@ Contact: "Jaegeuk Kim" <jaegeuk@kernel.org>
Description:	Shows the number of unusable blocks in a section which was defined by
		the zone capacity reported by underlying zoned device.

What:		/sys/fs/f2fs/<disk>/max_open_zones
Date:		November 2025
Contact:	"Yongpeng Yang" <yangyongpeng@xiaomi.com>
Description:	Shows the max number of zones that F2FS can write concurrently when a zoned
		device is mounted.

What:		/sys/fs/f2fs/<disk>/current_atomic_write
Date:		July 2022
Contact:	"Daeho Jeong" <daehojeong@google.com>
+69 −62
Original line number Diff line number Diff line
@@ -188,6 +188,8 @@ fault_type=%d Support configuring fault injection type, should be
			 enabled with fault_injection option, fault type value
			 is shown below, it supports single or combined type.

			 .. code-block:: none

			     ===========================      ==========
			     Type_Name                        Type_Value
			     ===========================      ==========
@@ -296,7 +298,7 @@ nocheckpoint_merge Disable checkpoint merge feature.
compress_algorithm=%s	 Control compress algorithm, currently f2fs supports "lzo",
			 "lz4", "zstd" and "lzo-rle" algorithm.
compress_algorithm=%s:%d Control compress algorithm and its compress level, now, only
			 "lz4" and "zstd" support compress level config.
			 "lz4" and "zstd" support compress level config::

				 =========      ===========
				 algorithm      level range
@@ -304,6 +306,7 @@ compress_algorithm=%s:%d Control compress algorithm and its compress level, now,
				 lz4            3 - 16
				 zstd           1 - 22
				 =========      ===========

compress_log_size=%u	 Support configuring compress cluster size. The size will
			 be 4KB * (1 << %u). The default and minimum sizes are 16KB.
compress_extension=%s	 Support adding specified extension, so that f2fs can enable
@@ -368,6 +371,8 @@ errors=%s Specify f2fs behavior on critical errors. This supports modes:
			 the partition in read-only mode. By default it uses "continue"
			 mode.

			 .. code-block:: none

			     ====================== =============== =============== ========
			     mode                   continue        remount-ro      panic
			     ====================== =============== =============== ========
@@ -385,6 +390,8 @@ lookup_mode=%s Control the directory lookup behavior for casefolded
			 directories. This option has no effect on directories
			 that do not have the casefold feature enabled.

			 .. code-block:: none

			     ================== ========================================
			     Value              Description
			     ================== ========================================
+5 −5
Original line number Diff line number Diff line
@@ -1318,7 +1318,7 @@ void f2fs_wait_on_all_pages(struct f2fs_sb_info *sbi, int type)
			f2fs_submit_merged_write(sbi, DATA);

		prepare_to_wait(&sbi->cp_wait, &wait, TASK_UNINTERRUPTIBLE);
		io_schedule_timeout(DEFAULT_IO_TIMEOUT);
		io_schedule_timeout(DEFAULT_SCHEDULE_TIMEOUT);
	}
	finish_wait(&sbi->cp_wait, &wait);
}
@@ -1673,7 +1673,7 @@ int f2fs_write_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)
		goto out;
	}

	trace_f2fs_write_checkpoint(sbi->sb, cpc->reason, "start block_ops");
	trace_f2fs_write_checkpoint(sbi->sb, cpc->reason, CP_PHASE_START_BLOCK_OPS);

	err = block_operations(sbi);
	if (err)
@@ -1681,7 +1681,7 @@ int f2fs_write_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)

	stat_cp_time(cpc, CP_TIME_OP_LOCK);

	trace_f2fs_write_checkpoint(sbi->sb, cpc->reason, "finish block_ops");
	trace_f2fs_write_checkpoint(sbi->sb, cpc->reason, CP_PHASE_FINISH_BLOCK_OPS);

	f2fs_flush_merged_writes(sbi);

@@ -1747,7 +1747,7 @@ int f2fs_write_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)

	/* update CP_TIME to trigger checkpoint periodically */
	f2fs_update_time(sbi, CP_TIME);
	trace_f2fs_write_checkpoint(sbi->sb, cpc->reason, "finish checkpoint");
	trace_f2fs_write_checkpoint(sbi->sb, cpc->reason, CP_PHASE_FINISH_CHECKPOINT);
out:
	if (cpc->reason != CP_RESIZE)
		f2fs_up_write(&sbi->cp_global_sem);
@@ -1974,7 +1974,7 @@ void f2fs_flush_ckpt_thread(struct f2fs_sb_info *sbi)

	/* Let's wait for the previous dispatched checkpoint. */
	while (atomic_read(&cprc->queued_ckpt))
		io_schedule_timeout(DEFAULT_IO_TIMEOUT);
		io_schedule_timeout(DEFAULT_SCHEDULE_TIMEOUT);
}

void f2fs_init_ckpt_req_control(struct f2fs_sb_info *sbi)
+7 −10
Original line number Diff line number Diff line
@@ -120,7 +120,7 @@ static void f2fs_unlock_rpages(struct compress_ctx *cc, int len)
}

static void f2fs_put_rpages_wbc(struct compress_ctx *cc,
		struct writeback_control *wbc, bool redirty, int unlock)
		struct writeback_control *wbc, bool redirty, bool unlock)
{
	unsigned int i;

@@ -759,9 +759,6 @@ void f2fs_decompress_cluster(struct decompress_io_ctx *dic, bool in_task)
		ret = -EFSCORRUPTED;

		/* Avoid f2fs_commit_super in irq context */
		if (!in_task)
			f2fs_handle_error_async(sbi, ERROR_FAIL_DECOMPRESSION);
		else
		f2fs_handle_error(sbi, ERROR_FAIL_DECOMPRESSION);
		goto out_release;
	}
@@ -1060,7 +1057,7 @@ static void cancel_cluster_writeback(struct compress_ctx *cc,
		f2fs_submit_merged_write(F2FS_I_SB(cc->inode), DATA);
		while (atomic_read(&cic->pending_pages) !=
					(cc->valid_nr_cpages - submitted + 1))
			f2fs_io_schedule_timeout(DEFAULT_IO_TIMEOUT);
			f2fs_io_schedule_timeout(DEFAULT_SCHEDULE_TIMEOUT);
	}

	/* Cancel writeback and stay locked. */
@@ -1205,7 +1202,7 @@ bool f2fs_compress_write_end(struct inode *inode, void *fsdata,
	if (copied)
		set_cluster_dirty(&cc);

	f2fs_put_rpages_wbc(&cc, NULL, false, 1);
	f2fs_put_rpages_wbc(&cc, NULL, false, true);
	f2fs_destroy_compress_ctx(&cc, false);

	return first_index;
@@ -1577,7 +1574,7 @@ static int f2fs_write_raw_pages(struct compress_ctx *cc,
				 */
				if (IS_NOQUOTA(cc->inode))
					goto out;
				f2fs_io_schedule_timeout(DEFAULT_IO_TIMEOUT);
				f2fs_schedule_timeout(DEFAULT_SCHEDULE_TIMEOUT);
				goto retry_write;
			}
			goto out;
@@ -1608,7 +1605,7 @@ int f2fs_write_multi_pages(struct compress_ctx *cc,
			add_compr_block_stat(cc->inode, cc->cluster_size);
			goto write;
		} else if (err) {
			f2fs_put_rpages_wbc(cc, wbc, true, 1);
			f2fs_put_rpages_wbc(cc, wbc, true, true);
			goto destroy_out;
		}

@@ -1622,7 +1619,7 @@ int f2fs_write_multi_pages(struct compress_ctx *cc,
	f2fs_bug_on(F2FS_I_SB(cc->inode), *submitted);

	err = f2fs_write_raw_pages(cc, submitted, wbc, io_type);
	f2fs_put_rpages_wbc(cc, wbc, false, 0);
	f2fs_put_rpages_wbc(cc, wbc, false, false);
destroy_out:
	f2fs_destroy_compress_ctx(cc, false);
	return err;
+33 −17
Original line number Diff line number Diff line
@@ -752,7 +752,7 @@ static bool io_is_mergeable(struct f2fs_sb_info *sbi, struct bio *bio,
}

static void add_bio_entry(struct f2fs_sb_info *sbi, struct bio *bio,
				struct page *page, enum temp_type temp)
				struct folio *folio, enum temp_type temp)
{
	struct f2fs_bio_info *io = sbi->write_io[DATA] + temp;
	struct bio_entry *be;
@@ -761,8 +761,7 @@ static void add_bio_entry(struct f2fs_sb_info *sbi, struct bio *bio,
	be->bio = bio;
	bio_get(bio);

	if (bio_add_page(bio, page, PAGE_SIZE, 0) != PAGE_SIZE)
		f2fs_bug_on(sbi, 1);
	bio_add_folio_nofail(bio, folio, folio_size(folio), 0);

	f2fs_down_write(&io->bio_list_lock);
	list_add_tail(&be->list, &io->bio_list);
@@ -776,7 +775,7 @@ static void del_bio_entry(struct bio_entry *be)
}

static int add_ipu_page(struct f2fs_io_info *fio, struct bio **bio,
							struct page *page)
							struct folio *folio)
{
	struct folio *fio_folio = fio->folio;
	struct f2fs_sb_info *sbi = fio->sbi;
@@ -802,8 +801,7 @@ static int add_ipu_page(struct f2fs_io_info *fio, struct bio **bio,
			if (f2fs_crypt_mergeable_bio(*bio,
					fio_folio->mapping->host,
					fio_folio->index, fio) &&
			    bio_add_page(*bio, page, PAGE_SIZE, 0) ==
					PAGE_SIZE) {
			    bio_add_folio(*bio, folio, folio_size(folio), 0)) {
				ret = 0;
				break;
			}
@@ -904,9 +902,9 @@ int f2fs_merge_page_bio(struct f2fs_io_info *fio)
		f2fs_set_bio_crypt_ctx(bio, folio->mapping->host,
				folio->index, fio, GFP_NOIO);

		add_bio_entry(fio->sbi, bio, &data_folio->page, fio->temp);
		add_bio_entry(fio->sbi, bio, data_folio, fio->temp);
	} else {
		if (add_ipu_page(fio, &bio, &data_folio->page))
		if (add_ipu_page(fio, &bio, data_folio))
			goto alloc_new;
	}

@@ -1275,7 +1273,7 @@ struct folio *f2fs_find_data_folio(struct inode *inode, pgoff_t index,
	struct address_space *mapping = inode->i_mapping;
	struct folio *folio;

	folio = __filemap_get_folio(mapping, index, FGP_ACCESSED, 0);
	folio = f2fs_filemap_get_folio(mapping, index, FGP_ACCESSED, 0);
	if (IS_ERR(folio))
		goto read;
	if (folio_test_uptodate(folio))
@@ -1420,6 +1418,7 @@ static int __allocate_data_block(struct dnode_of_data *dn, int seg_type)

static void f2fs_map_lock(struct f2fs_sb_info *sbi, int flag)
{
	f2fs_down_read(&sbi->cp_enable_rwsem);
	if (flag == F2FS_GET_BLOCK_PRE_AIO)
		f2fs_down_read(&sbi->node_change);
	else
@@ -1432,6 +1431,7 @@ static void f2fs_map_unlock(struct f2fs_sb_info *sbi, int flag)
		f2fs_up_read(&sbi->node_change);
	else
		f2fs_unlock_op(sbi);
	f2fs_up_read(&sbi->cp_enable_rwsem);
}

int f2fs_get_block_locked(struct dnode_of_data *dn, pgoff_t index)
@@ -3138,8 +3138,8 @@ static int f2fs_write_cache_pages(struct address_space *mapping,
				} else if (ret == -EAGAIN) {
					ret = 0;
					if (wbc->sync_mode == WB_SYNC_ALL) {
						f2fs_io_schedule_timeout(
							DEFAULT_IO_TIMEOUT);
						f2fs_schedule_timeout(
							DEFAULT_SCHEDULE_TIMEOUT);
						goto retry_write;
					}
					goto next;
@@ -3221,6 +3221,19 @@ static inline bool __should_serialize_io(struct inode *inode,
	return false;
}

static inline void account_writeback(struct inode *inode, bool inc)
{
	if (!f2fs_sb_has_compression(F2FS_I_SB(inode)))
		return;

	f2fs_down_read(&F2FS_I(inode)->i_sem);
	if (inc)
		atomic_inc(&F2FS_I(inode)->writeback);
	else
		atomic_dec(&F2FS_I(inode)->writeback);
	f2fs_up_read(&F2FS_I(inode)->i_sem);
}

static int __f2fs_write_data_pages(struct address_space *mapping,
						struct writeback_control *wbc,
						enum iostat_type io_type)
@@ -3266,10 +3279,14 @@ static int __f2fs_write_data_pages(struct address_space *mapping,
		locked = true;
	}

	account_writeback(inode, true);

	blk_start_plug(&plug);
	ret = f2fs_write_cache_pages(mapping, wbc, io_type);
	blk_finish_plug(&plug);

	account_writeback(inode, false);

	if (locked)
		mutex_unlock(&sbi->writepages);

@@ -3566,8 +3583,9 @@ static int f2fs_write_begin(const struct kiocb *iocb,
	 * Do not use FGP_STABLE to avoid deadlock.
	 * Will wait that below with our IO control.
	 */
	folio = __filemap_get_folio(mapping, index,
				FGP_LOCK | FGP_WRITE | FGP_CREAT, GFP_NOFS);
	folio = f2fs_filemap_get_folio(mapping, index,
				FGP_LOCK | FGP_WRITE | FGP_CREAT | FGP_NOFS,
				mapping_gfp_mask(mapping));
	if (IS_ERR(folio)) {
		err = PTR_ERR(folio);
		goto fail;
@@ -3637,8 +3655,7 @@ static int f2fs_write_begin(const struct kiocb *iocb,
	return 0;

put_folio:
	folio_unlock(folio);
	folio_put(folio);
	f2fs_folio_put(folio, true);
fail:
	f2fs_write_failed(inode, pos + len);
	return err;
@@ -3694,8 +3711,7 @@ static int f2fs_write_end(const struct kiocb *iocb,
					pos + copied);
	}
unlock_out:
	folio_unlock(folio);
	folio_put(folio);
	f2fs_folio_put(folio, true);
	f2fs_update_time(F2FS_I_SB(inode), REQ_TIME);
	return copied;
}
Loading