Commit 79952bdc authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull f2fs updates from Jaegeuk Kim:
 "The main changes include converting major IO paths to use folio, and
  adding various knobs to control GC more flexibly for Zoned devices.

  In addition, there are several patches to address corner cases of
  atomic file operations and better support for file pinning on zoned
  device.

  Enhancement:
   - add knobs to tune foreground/background GCs for Zoned devices
   - convert IO paths to use folio
   - reduce expensive checkpoint trigger frequency
   - allow F2FS_IPU_NOCACHE for pinned file
   - forcibly migrate to secure space for zoned device file pinning
   - get rid of buffer_head use
   - add write priority option based on zone UFS
   - get rid of online repair on corrupted directory

  Bug fixes:
   - fix to don't panic system for no free segment fault injection
   - fix to don't set SB_RDONLY in f2fs_handle_critical_error()
   - avoid unused block when dio write in LFS mode
   - compress: don't redirty sparse cluster during {,de}compress
   - check discard support for conventional zones
   - atomic: prevent atomic file from being dirtied before commit
   - atomic: fix to check atomic_file in f2fs ioctl interfaces
   - atomic: fix to forbid dio in atomic_file
   - atomic: fix to truncate pagecache before on-disk metadata truncation
   - atomic: create COW inode from parent dentry
   - atomic: fix to avoid racing w/ GC
   - atomic: require FMODE_WRITE for atomic write ioctls
   - fix to wait page writeback before setting gcing flag
   - fix to avoid racing in between read and OPU dio write, dio completion
   - fix several potential integer overflows in file offsets and dir_block_index
   - fix to avoid use-after-free in f2fs_stop_gc_thread()

  As usual, there are several code clean-ups and refactorings"

* tag 'f2fs-for-6.12-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/jaegeuk/f2fs: (60 commits)
  f2fs: allow F2FS_IPU_NOCACHE for pinned file
  f2fs: forcibly migrate to secure space for zoned device file pinning
  f2fs: remove unused parameters
  f2fs: fix to don't panic system for no free segment fault injection
  f2fs: fix to don't set SB_RDONLY in f2fs_handle_critical_error()
  f2fs: add valid block ratio not to do excessive GC for one time GC
  f2fs: create gc_no_zoned_gc_percent and gc_boost_zoned_gc_percent
  f2fs: do FG_GC when GC boosting is required for zoned devices
  f2fs: increase BG GC migration window granularity when boosted for zoned devices
  f2fs: add reserved_segments sysfs node
  f2fs: introduce migration_window_granularity
  f2fs: make BG GC more aggressive for zoned devices
  f2fs: avoid unused block when dio write in LFS mode
  f2fs: fix to check atomic_file in f2fs ioctl interfaces
  f2fs: get rid of online repaire on corrupted directory
  f2fs: prevent atomic file from being dirtied before commit
  f2fs: get rid of page->index
  f2fs: convert read_node_page() to use folio
  f2fs: convert __write_node_page() to use folio
  f2fs: convert f2fs_write_data_page() to use folio
  ...
parents fa8380a0 ae87b9c2
Loading
Loading
Loading
Loading
+56 −0
Original line number Diff line number Diff line
@@ -579,6 +579,12 @@ Description: When ATGC is on, it controls age threshold to bypass GCing young
		candidates whose age is not beyond the threshold, by default it was
		initialized as 604800 seconds (equals to 7 days).

What:		/sys/fs/f2fs/<disk>/atgc_enabled
Date:		Feb 2024
Contact:	"Jinbao Liu" <liujinbao1@xiaomi.com>
Description:	It represents whether ATGC is on or off. The value is 1 which
               indicates that ATGC is on, and 0 indicates that it is off.

What:		/sys/fs/f2fs/<disk>/gc_reclaimed_segments
Date:		July 2021
Contact:	"Daeho Jeong" <daehojeong@google.com>
@@ -763,3 +769,53 @@ Date: November 2023
Contact:	"Chao Yu" <chao@kernel.org>
Description:	It controls to enable/disable IO aware feature for background discard.
		By default, the value is 1 which indicates IO aware is on.

What:		/sys/fs/f2fs/<disk>/blkzone_alloc_policy
Date:		July 2024
Contact:	"Yuanhong Liao" <liaoyuanhong@vivo.com>
Description:	The zone UFS we are currently using consists of two parts:
		conventional zones and sequential zones. It can be used to control which part
		to prioritize for writes, with a default value of 0.

		========================  =========================================
		value					  description
		blkzone_alloc_policy = 0  Prioritize writing to sequential zones
		blkzone_alloc_policy = 1  Only allow writing to sequential zones
		blkzone_alloc_policy = 2  Prioritize writing to conventional zones
		========================  =========================================

What:		/sys/fs/f2fs/<disk>/migration_window_granularity
Date:		September 2024
Contact:	"Daeho Jeong" <daehojeong@google.com>
Description:	Controls migration window granularity of garbage collection on large
		section. it can control the scanning window granularity for GC migration
		in a unit of segment, while migration_granularity controls the number
		of segments which can be migrated at the same turn.

What:		/sys/fs/f2fs/<disk>/reserved_segments
Date:		September 2024
Contact:	"Daeho Jeong" <daehojeong@google.com>
Description:	In order to fine tune GC behavior, we can control the number of
		reserved segments.

What:		/sys/fs/f2fs/<disk>/gc_no_zoned_gc_percent
Date:		September 2024
Contact:	"Daeho Jeong" <daehojeong@google.com>
Description:	If the percentage of free sections over total sections is above this
		number, F2FS do not garbage collection for zoned devices through the
		background GC thread. the default number is "60".

What:		/sys/fs/f2fs/<disk>/gc_boost_zoned_gc_percent
Date:		September 2024
Contact:	"Daeho Jeong" <daehojeong@google.com>
Description:	If the percentage of free sections over total sections is under this
		number, F2FS boosts garbage collection for zoned devices through the
		background GC thread. the default number is "25".

What:		/sys/fs/f2fs/<disk>/gc_valid_thresh_ratio
Date:		September 2024
Contact:	"Daeho Jeong" <daehojeong@google.com>
Description:	It controls the valid block ratio threshold not to trigger excessive GC
		for zoned deivces. The initial value of it is 95(%). F2FS will stop the
		background GC thread from intiating GC for sections having valid blocks
		exceeding the ratio.
+9 −8
Original line number Diff line number Diff line
@@ -99,7 +99,7 @@ static struct page *__get_meta_page(struct f2fs_sb_info *sbi, pgoff_t index,
	}

	if (unlikely(!PageUptodate(page))) {
		f2fs_handle_page_eio(sbi, page->index, META);
		f2fs_handle_page_eio(sbi, page_folio(page), META);
		f2fs_put_page(page, 1);
		return ERR_PTR(-EIO);
	}
@@ -345,30 +345,31 @@ static int __f2fs_write_meta_page(struct page *page,
				enum iostat_type io_type)
{
	struct f2fs_sb_info *sbi = F2FS_P_SB(page);
	struct folio *folio = page_folio(page);

	trace_f2fs_writepage(page_folio(page), META);
	trace_f2fs_writepage(folio, META);

	if (unlikely(f2fs_cp_error(sbi))) {
		if (is_sbi_flag_set(sbi, SBI_IS_CLOSE)) {
			ClearPageUptodate(page);
			folio_clear_uptodate(folio);
			dec_page_count(sbi, F2FS_DIRTY_META);
			unlock_page(page);
			folio_unlock(folio);
			return 0;
		}
		goto redirty_out;
	}
	if (unlikely(is_sbi_flag_set(sbi, SBI_POR_DOING)))
		goto redirty_out;
	if (wbc->for_reclaim && page->index < GET_SUM_BLOCK(sbi, 0))
	if (wbc->for_reclaim && folio->index < GET_SUM_BLOCK(sbi, 0))
		goto redirty_out;

	f2fs_do_write_meta_page(sbi, page, io_type);
	f2fs_do_write_meta_page(sbi, folio, io_type);
	dec_page_count(sbi, F2FS_DIRTY_META);

	if (wbc->for_reclaim)
		f2fs_submit_merged_write_cond(sbi, NULL, page, 0, META);

	unlock_page(page);
	folio_unlock(folio);

	if (unlikely(f2fs_cp_error(sbi)))
		f2fs_submit_merged_write(sbi, META);
@@ -1551,7 +1552,7 @@ static int do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)
		blk = start_blk + BLKS_PER_SEG(sbi) - nm_i->nat_bits_blocks;
		for (i = 0; i < nm_i->nat_bits_blocks; i++)
			f2fs_update_meta_page(sbi, nm_i->nat_bits +
					(i << F2FS_BLKSIZE_BITS), blk + i);
					F2FS_BLK_TO_BYTES(i), blk + i);
	}

	/* write out checkpoint buffer at block 0 */
+43 −20
Original line number Diff line number Diff line
@@ -90,11 +90,13 @@ bool f2fs_is_compressed_page(struct page *page)
static void f2fs_set_compressed_page(struct page *page,
		struct inode *inode, pgoff_t index, void *data)
{
	attach_page_private(page, (void *)data);
	struct folio *folio = page_folio(page);

	folio_attach_private(folio, (void *)data);

	/* i_crypto_info and iv index */
	page->index = index;
	page->mapping = inode->i_mapping;
	folio->index = index;
	folio->mapping = inode->i_mapping;
}

static void f2fs_drop_rpages(struct compress_ctx *cc, int len, bool unlock)
@@ -160,17 +162,17 @@ void f2fs_destroy_compress_ctx(struct compress_ctx *cc, bool reuse)
		cc->cluster_idx = NULL_CLUSTER;
}

void f2fs_compress_ctx_add_page(struct compress_ctx *cc, struct page *page)
void f2fs_compress_ctx_add_page(struct compress_ctx *cc, struct folio *folio)
{
	unsigned int cluster_ofs;

	if (!f2fs_cluster_can_merge_page(cc, page->index))
	if (!f2fs_cluster_can_merge_page(cc, folio->index))
		f2fs_bug_on(F2FS_I_SB(cc->inode), 1);

	cluster_ofs = offset_in_cluster(cc, page->index);
	cc->rpages[cluster_ofs] = page;
	cluster_ofs = offset_in_cluster(cc, folio->index);
	cc->rpages[cluster_ofs] = folio_page(folio, 0);
	cc->nr_rpages++;
	cc->cluster_idx = cluster_idx(cc, page->index);
	cc->cluster_idx = cluster_idx(cc, folio->index);
}

#ifdef CONFIG_F2FS_FS_LZO
@@ -879,7 +881,7 @@ static bool cluster_has_invalid_data(struct compress_ctx *cc)
		f2fs_bug_on(F2FS_I_SB(cc->inode), !page);

		/* beyond EOF */
		if (page->index >= nr_pages)
		if (page_folio(page)->index >= nr_pages)
			return true;
	}
	return false;
@@ -945,7 +947,7 @@ static int __f2fs_get_cluster_blocks(struct inode *inode,
	unsigned int cluster_size = F2FS_I(inode)->i_cluster_size;
	int count, i;

	for (i = 1, count = 1; i < cluster_size; i++) {
	for (i = 0, count = 0; i < cluster_size; i++) {
		block_t blkaddr = data_blkaddr(dn->inode, dn->node_page,
							dn->ofs_in_node + i);

@@ -956,8 +958,8 @@ static int __f2fs_get_cluster_blocks(struct inode *inode,
	return count;
}

static int __f2fs_cluster_blocks(struct inode *inode,
				unsigned int cluster_idx, bool compr_blks)
static int __f2fs_cluster_blocks(struct inode *inode, unsigned int cluster_idx,
				enum cluster_check_type type)
{
	struct dnode_of_data dn;
	unsigned int start_idx = cluster_idx <<
@@ -978,10 +980,12 @@ static int __f2fs_cluster_blocks(struct inode *inode,
	}

	if (dn.data_blkaddr == COMPRESS_ADDR) {
		if (compr_blks)
			ret = __f2fs_get_cluster_blocks(inode, &dn);
		else
		if (type == CLUSTER_COMPR_BLKS)
			ret = 1 + __f2fs_get_cluster_blocks(inode, &dn);
		else if (type == CLUSTER_IS_COMPR)
			ret = 1;
	} else if (type == CLUSTER_RAW_BLKS) {
		ret = __f2fs_get_cluster_blocks(inode, &dn);
	}
fail:
	f2fs_put_dnode(&dn);
@@ -991,7 +995,16 @@ static int __f2fs_cluster_blocks(struct inode *inode,
/* return # of compressed blocks in compressed cluster */
static int f2fs_compressed_blocks(struct compress_ctx *cc)
{
	return __f2fs_cluster_blocks(cc->inode, cc->cluster_idx, true);
	return __f2fs_cluster_blocks(cc->inode, cc->cluster_idx,
		CLUSTER_COMPR_BLKS);
}

/* return # of raw blocks in non-compressed cluster */
static int f2fs_decompressed_blocks(struct inode *inode,
				unsigned int cluster_idx)
{
	return __f2fs_cluster_blocks(inode, cluster_idx,
		CLUSTER_RAW_BLKS);
}

/* return whether cluster is compressed one or not */
@@ -999,7 +1012,16 @@ int f2fs_is_compressed_cluster(struct inode *inode, pgoff_t index)
{
	return __f2fs_cluster_blocks(inode,
		index >> F2FS_I(inode)->i_log_cluster_size,
		false);
		CLUSTER_IS_COMPR);
}

/* return whether cluster contains non raw blocks or not */
bool f2fs_is_sparse_cluster(struct inode *inode, pgoff_t index)
{
	unsigned int cluster_idx = index >> F2FS_I(inode)->i_log_cluster_size;

	return f2fs_decompressed_blocks(inode, cluster_idx) !=
		F2FS_I(inode)->i_cluster_size;
}

static bool cluster_may_compress(struct compress_ctx *cc)
@@ -1093,7 +1115,7 @@ static int prepare_compress_overwrite(struct compress_ctx *cc,
		if (PageUptodate(page))
			f2fs_put_page(page, 1);
		else
			f2fs_compress_ctx_add_page(cc, page);
			f2fs_compress_ctx_add_page(cc, page_folio(page));
	}

	if (!f2fs_cluster_is_empty(cc)) {
@@ -1123,7 +1145,7 @@ static int prepare_compress_overwrite(struct compress_ctx *cc,
		}

		f2fs_wait_on_page_writeback(page, DATA, true, true);
		f2fs_compress_ctx_add_page(cc, page);
		f2fs_compress_ctx_add_page(cc, page_folio(page));

		if (!PageUptodate(page)) {
release_and_retry:
@@ -1523,7 +1545,8 @@ static int f2fs_write_raw_pages(struct compress_ctx *cc,
		if (!clear_page_dirty_for_io(cc->rpages[i]))
			goto continue_unlock;

		ret = f2fs_write_single_data_page(cc->rpages[i], &submitted,
		ret = f2fs_write_single_data_page(page_folio(cc->rpages[i]),
						&submitted,
						NULL, NULL, wbc, io_type,
						compr_blocks, false);
		if (ret) {
+92 −72
Original line number Diff line number Diff line
@@ -7,7 +7,6 @@
 */
#include <linux/fs.h>
#include <linux/f2fs_fs.h>
#include <linux/buffer_head.h>
#include <linux/sched/mm.h>
#include <linux/mpage.h>
#include <linux/writeback.h>
@@ -355,7 +354,7 @@ static void f2fs_write_end_io(struct bio *bio)
		}

		f2fs_bug_on(sbi, page->mapping == NODE_MAPPING(sbi) &&
					page->index != nid_of_node(page));
				page_folio(page)->index != nid_of_node(page));

		dec_page_count(sbi, type);
		if (f2fs_in_warm_node_list(sbi, page))
@@ -704,7 +703,7 @@ int f2fs_submit_page_bio(struct f2fs_io_info *fio)
	bio = __bio_alloc(fio, 1);

	f2fs_set_bio_crypt_ctx(bio, fio->page->mapping->host,
			       fio->page->index, fio, GFP_NOIO);
			page_folio(fio->page)->index, fio, GFP_NOIO);

	if (bio_add_page(bio, page, PAGE_SIZE, 0) < PAGE_SIZE) {
		bio_put(bio);
@@ -803,7 +802,7 @@ static int add_ipu_page(struct f2fs_io_info *fio, struct bio **bio,
							    fio->new_blkaddr));
			if (f2fs_crypt_mergeable_bio(*bio,
					fio->page->mapping->host,
					fio->page->index, fio) &&
					page_folio(fio->page)->index, fio) &&
			    bio_add_page(*bio, page, PAGE_SIZE, 0) ==
					PAGE_SIZE) {
				ret = 0;
@@ -903,7 +902,7 @@ int f2fs_merge_page_bio(struct f2fs_io_info *fio)
	if (!bio) {
		bio = __bio_alloc(fio, BIO_MAX_VECS);
		f2fs_set_bio_crypt_ctx(bio, fio->page->mapping->host,
				       fio->page->index, fio, GFP_NOIO);
				page_folio(fio->page)->index, fio, GFP_NOIO);

		add_bio_entry(fio->sbi, bio, page, fio->temp);
	} else {
@@ -996,13 +995,13 @@ void f2fs_submit_page_write(struct f2fs_io_info *fio)
	    (!io_is_mergeable(sbi, io->bio, io, fio, io->last_block_in_bio,
			      fio->new_blkaddr) ||
	     !f2fs_crypt_mergeable_bio(io->bio, fio->page->mapping->host,
				       bio_page->index, fio)))
				page_folio(bio_page)->index, fio)))
		__submit_merged_bio(io);
alloc_new:
	if (io->bio == NULL) {
		io->bio = __bio_alloc(fio, BIO_MAX_VECS);
		f2fs_set_bio_crypt_ctx(io->bio, fio->page->mapping->host,
				       bio_page->index, fio, GFP_NOIO);
				page_folio(bio_page)->index, fio, GFP_NOIO);
		io->fio = *fio;
	}

@@ -1087,7 +1086,7 @@ static struct bio *f2fs_grab_read_bio(struct inode *inode, block_t blkaddr,
}

/* This can handle encryption stuffs */
static int f2fs_submit_page_read(struct inode *inode, struct page *page,
static int f2fs_submit_page_read(struct inode *inode, struct folio *folio,
				 block_t blkaddr, blk_opf_t op_flags,
				 bool for_write)
{
@@ -1095,14 +1094,14 @@ static int f2fs_submit_page_read(struct inode *inode, struct page *page,
	struct bio *bio;

	bio = f2fs_grab_read_bio(inode, blkaddr, 1, op_flags,
					page->index, for_write);
					folio->index, for_write);
	if (IS_ERR(bio))
		return PTR_ERR(bio);

	/* wait for GCed page writeback via META_MAPPING */
	f2fs_wait_on_block_writeback(inode, blkaddr);

	if (bio_add_page(bio, page, PAGE_SIZE, 0) < PAGE_SIZE) {
	if (!bio_add_folio(bio, folio, PAGE_SIZE, 0)) {
		iostat_update_and_unbind_ctx(bio);
		if (bio->bi_private)
			mempool_free(bio->bi_private, bio_post_read_ctx_pool);
@@ -1270,7 +1269,7 @@ struct page *f2fs_get_read_data_page(struct inode *inode, pgoff_t index,
		return page;
	}

	err = f2fs_submit_page_read(inode, page, dn.data_blkaddr,
	err = f2fs_submit_page_read(inode, page_folio(page), dn.data_blkaddr,
						op_flags, for_write);
	if (err)
		goto put_err;
@@ -1713,6 +1712,14 @@ int f2fs_map_blocks(struct inode *inode, struct f2fs_map_blocks *map, int flag)
		dn.ofs_in_node = end_offset;
	}

	if (flag == F2FS_GET_BLOCK_DIO && f2fs_lfs_mode(sbi) &&
	    map->m_may_create) {
		/* the next block to be allocated may not be contiguous. */
		if (GET_SEGOFF_FROM_SEG0(sbi, blkaddr) % BLKS_PER_SEC(sbi) ==
		    CAP_BLKS_PER_SEC(sbi) - 1)
			goto sync_out;
	}

	if (pgofs >= end)
		goto sync_out;
	else if (dn.ofs_in_node < end_offset)
@@ -1939,7 +1946,7 @@ int f2fs_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,

	inode_lock_shared(inode);

	maxbytes = max_file_blocks(inode) << F2FS_BLKSIZE_BITS;
	maxbytes = F2FS_BLK_TO_BYTES(max_file_blocks(inode));
	if (start > maxbytes) {
		ret = -EFBIG;
		goto out;
@@ -2064,7 +2071,7 @@ int f2fs_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
static inline loff_t f2fs_readpage_limit(struct inode *inode)
{
	if (IS_ENABLED(CONFIG_FS_VERITY) && IS_VERITY(inode))
		return inode->i_sb->s_maxbytes;
		return F2FS_BLK_TO_BYTES(max_file_blocks(inode));

	return i_size_read(inode);
}
@@ -2208,19 +2215,22 @@ int f2fs_read_multi_pages(struct compress_ctx *cc, struct bio **bio_ret,
	/* get rid of pages beyond EOF */
	for (i = 0; i < cc->cluster_size; i++) {
		struct page *page = cc->rpages[i];
		struct folio *folio;

		if (!page)
			continue;
		if ((sector_t)page->index >= last_block_in_file) {
			zero_user_segment(page, 0, PAGE_SIZE);
			if (!PageUptodate(page))
				SetPageUptodate(page);
		} else if (!PageUptodate(page)) {

		folio = page_folio(page);
		if ((sector_t)folio->index >= last_block_in_file) {
			folio_zero_segment(folio, 0, folio_size(folio));
			if (!folio_test_uptodate(folio))
				folio_mark_uptodate(folio);
		} else if (!folio_test_uptodate(folio)) {
			continue;
		}
		unlock_page(page);
		folio_unlock(folio);
		if (for_write)
			put_page(page);
			folio_put(folio);
		cc->rpages[i] = NULL;
		cc->nr_rpages--;
	}
@@ -2280,7 +2290,7 @@ int f2fs_read_multi_pages(struct compress_ctx *cc, struct bio **bio_ret,
	}

	for (i = 0; i < cc->nr_cpages; i++) {
		struct page *page = dic->cpages[i];
		struct folio *folio = page_folio(dic->cpages[i]);
		block_t blkaddr;
		struct bio_post_read_ctx *ctx;

@@ -2290,7 +2300,8 @@ int f2fs_read_multi_pages(struct compress_ctx *cc, struct bio **bio_ret,

		f2fs_wait_on_block_writeback(inode, blkaddr);

		if (f2fs_load_compressed_page(sbi, page, blkaddr)) {
		if (f2fs_load_compressed_page(sbi, folio_page(folio, 0),
								blkaddr)) {
			if (atomic_dec_and_test(&dic->remaining_pages)) {
				f2fs_decompress_cluster(dic, true);
				break;
@@ -2300,7 +2311,7 @@ int f2fs_read_multi_pages(struct compress_ctx *cc, struct bio **bio_ret,

		if (bio && (!page_is_mergeable(sbi, bio,
					*last_block_in_bio, blkaddr) ||
		    !f2fs_crypt_mergeable_bio(bio, inode, page->index, NULL))) {
		    !f2fs_crypt_mergeable_bio(bio, inode, folio->index, NULL))) {
submit_and_realloc:
			f2fs_submit_read_bio(sbi, bio, DATA);
			bio = NULL;
@@ -2309,7 +2320,7 @@ int f2fs_read_multi_pages(struct compress_ctx *cc, struct bio **bio_ret,
		if (!bio) {
			bio = f2fs_grab_read_bio(inode, blkaddr, nr_pages,
					f2fs_ra_op_flags(rac),
					page->index, for_write);
					folio->index, for_write);
			if (IS_ERR(bio)) {
				ret = PTR_ERR(bio);
				f2fs_decompress_end_io(dic, ret, true);
@@ -2319,7 +2330,7 @@ int f2fs_read_multi_pages(struct compress_ctx *cc, struct bio **bio_ret,
			}
		}

		if (bio_add_page(bio, page, blocksize, 0) < blocksize)
		if (!bio_add_folio(bio, folio, blocksize, 0))
			goto submit_and_realloc;

		ctx = get_post_read_ctx(bio);
@@ -2430,7 +2441,7 @@ static int f2fs_mpage_readpages(struct inode *inode,
		if (ret)
			goto set_error_page;

		f2fs_compress_ctx_add_page(&cc, &folio->page);
		f2fs_compress_ctx_add_page(&cc, folio);

		goto next_page;
read_single_page:
@@ -2645,21 +2656,24 @@ static inline bool need_inplace_update(struct f2fs_io_info *fio)

int f2fs_do_write_data_page(struct f2fs_io_info *fio)
{
	struct page *page = fio->page;
	struct inode *inode = page->mapping->host;
	struct folio *folio = page_folio(fio->page);
	struct inode *inode = folio->mapping->host;
	struct dnode_of_data dn;
	struct node_info ni;
	bool ipu_force = false;
	bool atomic_commit;
	int err = 0;

	/* Use COW inode to make dnode_of_data for atomic write */
	if (f2fs_is_atomic_file(inode))
	atomic_commit = f2fs_is_atomic_file(inode) &&
				page_private_atomic(folio_page(folio, 0));
	if (atomic_commit)
		set_new_dnode(&dn, F2FS_I(inode)->cow_inode, NULL, NULL, 0);
	else
		set_new_dnode(&dn, inode, NULL, NULL, 0);

	if (need_inplace_update(fio) &&
	    f2fs_lookup_read_extent_cache_block(inode, page->index,
	    f2fs_lookup_read_extent_cache_block(inode, folio->index,
						&fio->old_blkaddr)) {
		if (!f2fs_is_valid_blkaddr(fio->sbi, fio->old_blkaddr,
						DATA_GENERIC_ENHANCE))
@@ -2674,7 +2688,7 @@ int f2fs_do_write_data_page(struct f2fs_io_info *fio)
	if (fio->need_lock == LOCK_REQ && !f2fs_trylock_op(fio->sbi))
		return -EAGAIN;

	err = f2fs_get_dnode_of_data(&dn, page->index, LOOKUP_NODE);
	err = f2fs_get_dnode_of_data(&dn, folio->index, LOOKUP_NODE);
	if (err)
		goto out;

@@ -2682,8 +2696,8 @@ int f2fs_do_write_data_page(struct f2fs_io_info *fio)

	/* This page is already truncated */
	if (fio->old_blkaddr == NULL_ADDR) {
		ClearPageUptodate(page);
		clear_page_private_gcing(page);
		folio_clear_uptodate(folio);
		clear_page_private_gcing(folio_page(folio, 0));
		goto out_writepage;
	}
got_it:
@@ -2709,7 +2723,7 @@ int f2fs_do_write_data_page(struct f2fs_io_info *fio)
		if (err)
			goto out_writepage;

		set_page_writeback(page);
		folio_start_writeback(folio);
		f2fs_put_dnode(&dn);
		if (fio->need_lock == LOCK_REQ)
			f2fs_unlock_op(fio->sbi);
@@ -2717,11 +2731,11 @@ int f2fs_do_write_data_page(struct f2fs_io_info *fio)
		if (err) {
			if (fscrypt_inode_uses_fs_layer_crypto(inode))
				fscrypt_finalize_bounce_page(&fio->encrypted_page);
			end_page_writeback(page);
			folio_end_writeback(folio);
		} else {
			set_inode_flag(inode, FI_UPDATE_WRITE);
		}
		trace_f2fs_do_write_data_page(page_folio(page), IPU);
		trace_f2fs_do_write_data_page(folio, IPU);
		return err;
	}

@@ -2743,15 +2757,17 @@ int f2fs_do_write_data_page(struct f2fs_io_info *fio)
	if (err)
		goto out_writepage;

	set_page_writeback(page);
	folio_start_writeback(folio);

	if (fio->compr_blocks && fio->old_blkaddr == COMPRESS_ADDR)
		f2fs_i_compr_blocks_update(inode, fio->compr_blocks - 1, false);

	/* LFS mode write path */
	f2fs_outplace_write_data(&dn, fio);
	trace_f2fs_do_write_data_page(page_folio(page), OPU);
	trace_f2fs_do_write_data_page(folio, OPU);
	set_inode_flag(inode, FI_APPEND_WRITE);
	if (atomic_commit)
		clear_page_private_atomic(folio_page(folio, 0));
out_writepage:
	f2fs_put_dnode(&dn);
out:
@@ -2760,7 +2776,7 @@ int f2fs_do_write_data_page(struct f2fs_io_info *fio)
	return err;
}

int f2fs_write_single_data_page(struct page *page, int *submitted,
int f2fs_write_single_data_page(struct folio *folio, int *submitted,
				struct bio **bio,
				sector_t *last_block,
				struct writeback_control *wbc,
@@ -2768,12 +2784,13 @@ int f2fs_write_single_data_page(struct page *page, int *submitted,
				int compr_blocks,
				bool allow_balance)
{
	struct inode *inode = page->mapping->host;
	struct inode *inode = folio->mapping->host;
	struct page *page = folio_page(folio, 0);
	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
	loff_t i_size = i_size_read(inode);
	const pgoff_t end_index = ((unsigned long long)i_size)
							>> PAGE_SHIFT;
	loff_t psize = (loff_t)(page->index + 1) << PAGE_SHIFT;
	loff_t psize = (loff_t)(folio->index + 1) << PAGE_SHIFT;
	unsigned offset = 0;
	bool need_balance_fs = false;
	bool quota_inode = IS_NOQUOTA(inode);
@@ -2797,11 +2814,11 @@ int f2fs_write_single_data_page(struct page *page, int *submitted,
		.last_block = last_block,
	};

	trace_f2fs_writepage(page_folio(page), DATA);
	trace_f2fs_writepage(folio, DATA);

	/* we should bypass data pages to proceed the kworker jobs */
	if (unlikely(f2fs_cp_error(sbi))) {
		mapping_set_error(page->mapping, -EIO);
		mapping_set_error(folio->mapping, -EIO);
		/*
		 * don't drop any dirty dentry pages for keeping lastest
		 * directory structure.
@@ -2819,7 +2836,7 @@ int f2fs_write_single_data_page(struct page *page, int *submitted,
	if (unlikely(is_sbi_flag_set(sbi, SBI_POR_DOING)))
		goto redirty_out;

	if (page->index < end_index ||
	if (folio->index < end_index ||
			f2fs_verity_in_progress(inode) ||
			compr_blocks)
		goto write;
@@ -2829,10 +2846,10 @@ int f2fs_write_single_data_page(struct page *page, int *submitted,
	 * this page does not have to be written to disk.
	 */
	offset = i_size & (PAGE_SIZE - 1);
	if ((page->index >= end_index + 1) || !offset)
	if ((folio->index >= end_index + 1) || !offset)
		goto out;

	zero_user_segment(page, offset, PAGE_SIZE);
	folio_zero_segment(folio, offset, folio_size(folio));
write:
	/* Dentry/quota blocks are controlled by checkpoint */
	if (S_ISDIR(inode->i_mode) || quota_inode) {
@@ -2862,7 +2879,7 @@ int f2fs_write_single_data_page(struct page *page, int *submitted,

	err = -EAGAIN;
	if (f2fs_has_inline_data(inode)) {
		err = f2fs_write_inline_data(inode, page);
		err = f2fs_write_inline_data(inode, folio);
		if (!err)
			goto out;
	}
@@ -2892,7 +2909,7 @@ int f2fs_write_single_data_page(struct page *page, int *submitted,
out:
	inode_dec_dirty_pages(inode);
	if (err) {
		ClearPageUptodate(page);
		folio_clear_uptodate(folio);
		clear_page_private_gcing(page);
	}

@@ -2902,7 +2919,7 @@ int f2fs_write_single_data_page(struct page *page, int *submitted,
		f2fs_remove_dirty_inode(inode);
		submitted = NULL;
	}
	unlock_page(page);
	folio_unlock(folio);
	if (!S_ISDIR(inode->i_mode) && !IS_NOQUOTA(inode) &&
			!F2FS_I(inode)->wb_task && allow_balance)
		f2fs_balance_fs(sbi, need_balance_fs);
@@ -2920,7 +2937,7 @@ int f2fs_write_single_data_page(struct page *page, int *submitted,
	return 0;

redirty_out:
	redirty_page_for_writepage(wbc, page);
	folio_redirty_for_writepage(wbc, folio);
	/*
	 * pageout() in MM translates EAGAIN, so calls handle_write_error()
	 * -> mapping_set_error() -> set_bit(AS_EIO, ...).
@@ -2929,29 +2946,30 @@ int f2fs_write_single_data_page(struct page *page, int *submitted,
	 */
	if (!err || wbc->for_reclaim)
		return AOP_WRITEPAGE_ACTIVATE;
	unlock_page(page);
	folio_unlock(folio);
	return err;
}

static int f2fs_write_data_page(struct page *page,
					struct writeback_control *wbc)
{
	struct folio *folio = page_folio(page);
#ifdef CONFIG_F2FS_FS_COMPRESSION
	struct inode *inode = page->mapping->host;
	struct inode *inode = folio->mapping->host;

	if (unlikely(f2fs_cp_error(F2FS_I_SB(inode))))
		goto out;

	if (f2fs_compressed_file(inode)) {
		if (f2fs_is_compressed_cluster(inode, page->index)) {
			redirty_page_for_writepage(wbc, page);
		if (f2fs_is_compressed_cluster(inode, folio->index)) {
			folio_redirty_for_writepage(wbc, folio);
			return AOP_WRITEPAGE_ACTIVATE;
		}
	}
out:
#endif

	return f2fs_write_single_data_page(page, NULL, NULL, NULL,
	return f2fs_write_single_data_page(folio, NULL, NULL, NULL,
						wbc, FS_DATA_IO, 0, true);
}

@@ -3157,11 +3175,11 @@ static int f2fs_write_cache_pages(struct address_space *mapping,
#ifdef CONFIG_F2FS_FS_COMPRESSION
			if (f2fs_compressed_file(inode)) {
				folio_get(folio);
				f2fs_compress_ctx_add_page(&cc, &folio->page);
				f2fs_compress_ctx_add_page(&cc, folio);
				continue;
			}
#endif
			ret = f2fs_write_single_data_page(&folio->page,
			ret = f2fs_write_single_data_page(folio,
					&submitted, &bio, &last_block,
					wbc, io_type, 0, true);
			if (ret == AOP_WRITEPAGE_ACTIVATE)
@@ -3369,11 +3387,11 @@ void f2fs_write_failed(struct inode *inode, loff_t to)
}

static int prepare_write_begin(struct f2fs_sb_info *sbi,
			struct page *page, loff_t pos, unsigned len,
			struct folio *folio, loff_t pos, unsigned int len,
			block_t *blk_addr, bool *node_changed)
{
	struct inode *inode = page->mapping->host;
	pgoff_t index = page->index;
	struct inode *inode = folio->mapping->host;
	pgoff_t index = folio->index;
	struct dnode_of_data dn;
	struct page *ipage;
	bool locked = false;
@@ -3410,13 +3428,13 @@ static int prepare_write_begin(struct f2fs_sb_info *sbi,

	if (f2fs_has_inline_data(inode)) {
		if (pos + len <= MAX_INLINE_DATA(inode)) {
			f2fs_do_read_inline_data(page_folio(page), ipage);
			f2fs_do_read_inline_data(folio, ipage);
			set_inode_flag(inode, FI_DATA_EXIST);
			if (inode->i_nlink)
				set_page_private_inline(ipage);
			goto out;
		}
		err = f2fs_convert_inline_page(&dn, page);
		err = f2fs_convert_inline_page(&dn, folio_page(folio, 0));
		if (err || dn.data_blkaddr != NULL_ADDR)
			goto out;
	}
@@ -3509,12 +3527,12 @@ static int __reserve_data_block(struct inode *inode, pgoff_t index,
}

static int prepare_atomic_write_begin(struct f2fs_sb_info *sbi,
			struct page *page, loff_t pos, unsigned int len,
			struct folio *folio, loff_t pos, unsigned int len,
			block_t *blk_addr, bool *node_changed, bool *use_cow)
{
	struct inode *inode = page->mapping->host;
	struct inode *inode = folio->mapping->host;
	struct inode *cow_inode = F2FS_I(inode)->cow_inode;
	pgoff_t index = page->index;
	pgoff_t index = folio->index;
	int err = 0;
	block_t ori_blk_addr = NULL_ADDR;

@@ -3620,10 +3638,10 @@ static int f2fs_write_begin(struct file *file, struct address_space *mapping,
	*foliop = folio;

	if (f2fs_is_atomic_file(inode))
		err = prepare_atomic_write_begin(sbi, &folio->page, pos, len,
		err = prepare_atomic_write_begin(sbi, folio, pos, len,
					&blkaddr, &need_balance, &use_cow);
	else
		err = prepare_write_begin(sbi, &folio->page, pos, len,
		err = prepare_write_begin(sbi, folio, pos, len,
					&blkaddr, &need_balance);
	if (err)
		goto put_folio;
@@ -3648,7 +3666,7 @@ static int f2fs_write_begin(struct file *file, struct address_space *mapping,

	if (!(pos & (PAGE_SIZE - 1)) && (pos + len) >= i_size_read(inode) &&
	    !f2fs_verity_in_progress(inode)) {
		folio_zero_segment(folio, len, PAGE_SIZE);
		folio_zero_segment(folio, len, folio_size(folio));
		return 0;
	}

@@ -3662,8 +3680,8 @@ static int f2fs_write_begin(struct file *file, struct address_space *mapping,
			goto put_folio;
		}
		err = f2fs_submit_page_read(use_cow ?
				F2FS_I(inode)->cow_inode : inode, &folio->page,
				blkaddr, 0, true);
				F2FS_I(inode)->cow_inode : inode,
				folio, blkaddr, 0, true);
		if (err)
			goto put_folio;

@@ -3727,6 +3745,9 @@ static int f2fs_write_end(struct file *file,

	folio_mark_dirty(folio);

	if (f2fs_is_atomic_file(inode))
		set_page_private_atomic(folio_page(folio, 0));

	if (pos + copied > i_size_read(inode) &&
	    !f2fs_verity_in_progress(inode)) {
		f2fs_i_size_write(inode, pos + copied);
@@ -4117,9 +4138,8 @@ const struct address_space_operations f2fs_dblock_aops = {
	.swap_deactivate = f2fs_swap_deactivate,
};

void f2fs_clear_page_cache_dirty_tag(struct page *page)
void f2fs_clear_page_cache_dirty_tag(struct folio *folio)
{
	struct folio *folio = page_folio(page);
	struct address_space *mapping = folio->mapping;
	unsigned long flags;

+1 −1
Original line number Diff line number Diff line
@@ -275,7 +275,7 @@ static void update_mem_info(struct f2fs_sb_info *sbi)
	/* build nm */
	si->base_mem += sizeof(struct f2fs_nm_info);
	si->base_mem += __bitmap_size(sbi, NAT_BITMAP);
	si->base_mem += (NM_I(sbi)->nat_bits_blocks << F2FS_BLKSIZE_BITS);
	si->base_mem += F2FS_BLK_TO_BYTES(NM_I(sbi)->nat_bits_blocks);
	si->base_mem += NM_I(sbi)->nat_blocks *
				f2fs_bitmap_size(NAT_ENTRY_PER_BLOCK);
	si->base_mem += NM_I(sbi)->nat_blocks / 8;
Loading