Commit c5d9ab85 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull f2fs update from Jaegeuk Kim:
 "In this round, there are a number of updates on mainly two areas:
  Zoned block device support and Per-file compression. For example,
  we've found several issues to support Zoned block device especially
  having large sections regarding to GC and file pinning used for
  Android devices. In compression side, we've fixed many corner race
  conditions that had broken the design assumption.

  Enhancements:
   - Support file pinning for Zoned block device having large section
   - Enhance the data recovery after sudden power cut on Zoned block
     device
   - Add more error injection cases to easily detect the kernel panics
   - add a proc entry show the entire disk layout
   - Improve various error paths paniced by BUG_ON in block allocation
     and GC
   - support SEEK_DATA and SEEK_HOLE for compression files

  Bug fixes:
   - avoid use-after-free issue in f2fs_filemap_fault
   - fix some race conditions to break the atomic write design
     assumption
   - fix to truncate meta inode pages forcely
   - resolve various per-file compression issues wrt the space
     management and compression policies
   - fix some swap-related bugs

  In addition, we removed deprecated codes such as io_bits and
  heap_allocation, and also fixed minor error handling routines with
  neat debugging messages"

* tag 'f2fs-for-6.9-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/jaegeuk/f2fs: (60 commits)
  f2fs: fix to avoid use-after-free issue in f2fs_filemap_fault
  f2fs: truncate page cache before clearing flags when aborting atomic write
  f2fs: mark inode dirty for FI_ATOMIC_COMMITTED flag
  f2fs: prevent atomic write on pinned file
  f2fs: fix to handle error paths of {new,change}_curseg()
  f2fs: unify the error handling of f2fs_is_valid_blkaddr
  f2fs: zone: fix to remove pow2 check condition for zoned block device
  f2fs: fix to truncate meta inode pages forcely
  f2fs: compress: fix reserve_cblocks counting error when out of space
  f2fs: compress: relocate some judgments in f2fs_reserve_compress_blocks
  f2fs: add a proc entry show disk layout
  f2fs: introduce SEGS_TO_BLKS/BLKS_TO_SEGS for cleanup
  f2fs: fix to check return value of f2fs_gc_range
  f2fs: fix to check return value __allocate_new_segment
  f2fs: fix to do sanity check in update_sit_entry
  f2fs: fix to reset fields for unloaded curseg
  f2fs: clean up new_curseg()
  f2fs: relocate f2fs_precache_extents() in f2fs_swap_activate()
  f2fs: fix blkofs_end correctly in f2fs_migrate_blocks()
  f2fs: ro: don't start discard thread for readonly image
  ...
parents 0d7ca657 eb70d5a6
Loading
Loading
Loading
Loading
+27 −25
Original line number Diff line number Diff line
@@ -205,7 +205,7 @@ Description: Controls the idle timing of system, if there is no FS operation
What:		/sys/fs/f2fs/<disk>/discard_idle_interval
Date:		September 2018
Contact:	"Chao Yu" <yuchao0@huawei.com>
Contact:	"Sahitya Tummala" <stummala@codeaurora.org>
Contact:	"Sahitya Tummala" <quic_stummala@quicinc.com>
Description:	Controls the idle timing of discard thread given
		this time interval.
		Default is 5 secs.
@@ -213,7 +213,7 @@ Description: Controls the idle timing of discard thread given
What:		/sys/fs/f2fs/<disk>/gc_idle_interval
Date:		September 2018
Contact:	"Chao Yu" <yuchao0@huawei.com>
Contact:	"Sahitya Tummala" <stummala@codeaurora.org>
Contact:	"Sahitya Tummala" <quic_stummala@quicinc.com>
Description:    Controls the idle timing for gc path. Set to 5 seconds by default.

What:		/sys/fs/f2fs/<disk>/iostat_enable
@@ -701,9 +701,9 @@ Description: Support configuring fault injection type, should be
		enabled with fault_injection option, fault type value
		is shown below, it supports single or combined type.

		===================      ===========
		===========================      ===========
		Type_Name                        Type_Value
		===================      ===========
		===========================      ===========
		FAULT_KMALLOC                    0x000000001
		FAULT_KVMALLOC                   0x000000002
		FAULT_PAGE_ALLOC                 0x000000004
@@ -722,8 +722,10 @@ Description: Support configuring fault injection type, should be
		FAULT_SLAB_ALLOC                 0x000008000
		FAULT_DQUOT_INIT                 0x000010000
		FAULT_LOCK_OP                    0x000020000
		FAULT_BLKADDR            0x000040000
		===================      ===========
		FAULT_BLKADDR_VALIDITY           0x000040000
		FAULT_BLKADDR_CONSISTENCE        0x000080000
		FAULT_NO_SEGMENT                 0x000100000
		===========================      ===========

What:		/sys/fs/f2fs/<disk>/discard_io_aware_gran
Date:		January 2023
+26 −28
Original line number Diff line number Diff line
@@ -126,9 +126,7 @@ norecovery Disable the roll-forward recovery routine, mounted read-
discard/nodiscard	 Enable/disable real-time discard in f2fs, if discard is
			 enabled, f2fs will issue discard/TRIM commands when a
			 segment is cleaned.
no_heap			 Disable heap-style segment allocation which finds free
			 segments for data from the beginning of main area, while
			 for node from the end of main area.
heap/no_heap		 Deprecated.
nouser_xattr		 Disable Extended User Attributes. Note: xattr is enabled
			 by default if CONFIG_F2FS_FS_XATTR is selected.
noacl			 Disable POSIX Access Control List. Note: acl is enabled
@@ -184,9 +182,9 @@ 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.

			 ===================	  ===========
			 ===========================      ===========
			 Type_Name                        Type_Value
			 ===================	  ===========
			 ===========================      ===========
			 FAULT_KMALLOC                    0x000000001
			 FAULT_KVMALLOC                   0x000000002
			 FAULT_PAGE_ALLOC                 0x000000004
@@ -205,8 +203,10 @@ fault_type=%d Support configuring fault injection type, should be
			 FAULT_SLAB_ALLOC                 0x000008000
			 FAULT_DQUOT_INIT                 0x000010000
			 FAULT_LOCK_OP                    0x000020000
			 FAULT_BLKADDR		  0x000040000
			 ===================	  ===========
			 FAULT_BLKADDR_VALIDITY           0x000040000
			 FAULT_BLKADDR_CONSISTENCE        0x000080000
			 FAULT_NO_SEGMENT                 0x000100000
			 ===========================      ===========
mode=%s			 Control block allocation mode which supports "adaptive"
			 and "lfs". In "lfs" mode, there should be no random
			 writes towards main area.
@@ -228,8 +228,6 @@ mode=%s Control block allocation mode which supports "adaptive"
			 option for more randomness.
			 Please, use these options for your experiments and we strongly
			 recommend to re-format the filesystem after using these options.
io_bits=%u		 Set the bit size of write IO requests. It should be set
			 with "mode=lfs".
usrquota		 Enable plain user disk quota accounting.
grpquota		 Enable plain group disk quota accounting.
prjquota		 Enable plain project quota accounting.
+45 −29
Original line number Diff line number Diff line
@@ -154,49 +154,47 @@ static bool __is_bitmap_valid(struct f2fs_sb_info *sbi, block_t blkaddr,
	if (unlikely(f2fs_cp_error(sbi)))
		return exist;

	if (exist && type == DATA_GENERIC_ENHANCE_UPDATE) {
		f2fs_err(sbi, "Inconsistent error blkaddr:%u, sit bitmap:%d",
			 blkaddr, exist);
		set_sbi_flag(sbi, SBI_NEED_FSCK);
	if ((exist && type == DATA_GENERIC_ENHANCE_UPDATE) ||
		(!exist && type == DATA_GENERIC_ENHANCE))
		goto out_err;
	if (!exist && type != DATA_GENERIC_ENHANCE_UPDATE)
		goto out_handle;
	return exist;
	}

	if (!exist && type == DATA_GENERIC_ENHANCE) {
out_err:
	f2fs_err(sbi, "Inconsistent error blkaddr:%u, sit bitmap:%d",
		 blkaddr, exist);
	set_sbi_flag(sbi, SBI_NEED_FSCK);
	dump_stack();
	}
out_handle:
	f2fs_handle_error(sbi, ERROR_INVALID_BLKADDR);
	return exist;
}

bool f2fs_is_valid_blkaddr(struct f2fs_sb_info *sbi,
static bool __f2fs_is_valid_blkaddr(struct f2fs_sb_info *sbi,
					block_t blkaddr, int type)
{
	if (time_to_inject(sbi, FAULT_BLKADDR))
		return false;

	switch (type) {
	case META_NAT:
		break;
	case META_SIT:
		if (unlikely(blkaddr >= SIT_BLK_CNT(sbi)))
			return false;
			goto err;
		break;
	case META_SSA:
		if (unlikely(blkaddr >= MAIN_BLKADDR(sbi) ||
			blkaddr < SM_I(sbi)->ssa_blkaddr))
			return false;
			goto err;
		break;
	case META_CP:
		if (unlikely(blkaddr >= SIT_I(sbi)->sit_base_addr ||
			blkaddr < __start_cp_addr(sbi)))
			return false;
			goto err;
		break;
	case META_POR:
		if (unlikely(blkaddr >= MAX_BLKADDR(sbi) ||
			blkaddr < MAIN_BLKADDR(sbi)))
			return false;
			goto err;
		break;
	case DATA_GENERIC:
	case DATA_GENERIC_ENHANCE:
@@ -213,7 +211,7 @@ bool f2fs_is_valid_blkaddr(struct f2fs_sb_info *sbi,
				  blkaddr);
			set_sbi_flag(sbi, SBI_NEED_FSCK);
			dump_stack();
			return false;
			goto err;
		} else {
			return __is_bitmap_valid(sbi, blkaddr, type);
		}
@@ -221,13 +219,30 @@ bool f2fs_is_valid_blkaddr(struct f2fs_sb_info *sbi,
	case META_GENERIC:
		if (unlikely(blkaddr < SEG0_BLKADDR(sbi) ||
			blkaddr >= MAIN_BLKADDR(sbi)))
			return false;
			goto err;
		break;
	default:
		BUG();
	}

	return true;
err:
	f2fs_handle_error(sbi, ERROR_INVALID_BLKADDR);
	return false;
}

bool f2fs_is_valid_blkaddr(struct f2fs_sb_info *sbi,
					block_t blkaddr, int type)
{
	if (time_to_inject(sbi, FAULT_BLKADDR_VALIDITY))
		return false;
	return __f2fs_is_valid_blkaddr(sbi, blkaddr, type);
}

bool f2fs_is_valid_blkaddr_raw(struct f2fs_sb_info *sbi,
					block_t blkaddr, int type)
{
	return __f2fs_is_valid_blkaddr(sbi, blkaddr, type);
}

/*
@@ -889,7 +904,7 @@ static struct page *validate_checkpoint(struct f2fs_sb_info *sbi,

	cp_blocks = le32_to_cpu(cp_block->cp_pack_total_block_count);

	if (cp_blocks > sbi->blocks_per_seg || cp_blocks <= F2FS_CP_PACKS) {
	if (cp_blocks > BLKS_PER_SEG(sbi) || cp_blocks <= F2FS_CP_PACKS) {
		f2fs_warn(sbi, "invalid cp_pack_total_block_count:%u",
			  le32_to_cpu(cp_block->cp_pack_total_block_count));
		goto invalid_cp;
@@ -1324,7 +1339,7 @@ static void update_ckpt_flags(struct f2fs_sb_info *sbi, struct cp_control *cpc)

	if (cpc->reason & CP_UMOUNT) {
		if (le32_to_cpu(ckpt->cp_pack_total_block_count) +
			NM_I(sbi)->nat_bits_blocks > sbi->blocks_per_seg) {
			NM_I(sbi)->nat_bits_blocks > BLKS_PER_SEG(sbi)) {
			clear_ckpt_flags(sbi, CP_NAT_BITS_FLAG);
			f2fs_notice(sbi, "Disable nat_bits due to no space");
		} else if (!is_set_ckpt_flags(sbi, CP_NAT_BITS_FLAG) &&
@@ -1527,7 +1542,7 @@ static int do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)
		cp_ver |= ((__u64)crc32 << 32);
		*(__le64 *)nm_i->nat_bits = cpu_to_le64(cp_ver);

		blk = start_blk + sbi->blocks_per_seg - nm_i->nat_bits_blocks;
		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);
@@ -1587,8 +1602,9 @@ static int do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)
	 */
	if (f2fs_sb_has_encrypt(sbi) || f2fs_sb_has_verity(sbi) ||
		f2fs_sb_has_compression(sbi))
		invalidate_mapping_pages(META_MAPPING(sbi),
				MAIN_BLKADDR(sbi), MAX_BLKADDR(sbi) - 1);
		f2fs_bug_on(sbi,
			invalidate_inode_pages2_range(META_MAPPING(sbi),
				MAIN_BLKADDR(sbi), MAX_BLKADDR(sbi) - 1));

	f2fs_release_ino_entry(sbi, false);

@@ -1730,7 +1746,7 @@ void f2fs_init_ino_entry_info(struct f2fs_sb_info *sbi)
		im->ino_num = 0;
	}

	sbi->max_orphans = (sbi->blocks_per_seg - F2FS_CP_PACKS -
	sbi->max_orphans = (BLKS_PER_SEG(sbi) - F2FS_CP_PACKS -
			NR_CURSEG_PERSIST_TYPE - __cp_payload(sbi)) *
			F2FS_ORPHANS_PER_BLOCK;
}
+32 −23
Original line number Diff line number Diff line
@@ -512,8 +512,8 @@ static int lzorle_compress_pages(struct compress_ctx *cc)
	ret = lzorle1x_1_compress(cc->rbuf, cc->rlen, cc->cbuf->cdata,
					&cc->clen, cc->private);
	if (ret != LZO_E_OK) {
		printk_ratelimited("%sF2FS-fs (%s): lzo-rle compress failed, ret:%d\n",
				KERN_ERR, F2FS_I_SB(cc->inode)->sb->s_id, ret);
		f2fs_err_ratelimited(F2FS_I_SB(cc->inode),
				"lzo-rle compress failed, ret:%d", ret);
		return -EIO;
	}
	return 0;
@@ -780,9 +780,9 @@ void f2fs_decompress_cluster(struct decompress_io_ctx *dic, bool in_task)
		if (provided != calculated) {
			if (!is_inode_flag_set(dic->inode, FI_COMPRESS_CORRUPT)) {
				set_inode_flag(dic->inode, FI_COMPRESS_CORRUPT);
				printk_ratelimited(
					"%sF2FS-fs (%s): checksum invalid, nid = %lu, %x vs %x",
					KERN_INFO, sbi->sb->s_id, dic->inode->i_ino,
				f2fs_info_ratelimited(sbi,
					"checksum invalid, nid = %lu, %x vs %x",
					dic->inode->i_ino,
					provided, calculated);
			}
			set_sbi_flag(sbi, SBI_NEED_FSCK);
@@ -1418,6 +1418,8 @@ void f2fs_compress_write_end_io(struct bio *bio, struct page *page)
	struct f2fs_sb_info *sbi = bio->bi_private;
	struct compress_io_ctx *cic =
			(struct compress_io_ctx *)page_private(page);
	enum count_type type = WB_DATA_TYPE(page,
				f2fs_is_compressed_page(page));
	int i;

	if (unlikely(bio->bi_status))
@@ -1425,7 +1427,7 @@ void f2fs_compress_write_end_io(struct bio *bio, struct page *page)

	f2fs_compress_free_page(page);

	dec_page_count(sbi, F2FS_WB_DATA);
	dec_page_count(sbi, type);

	if (atomic_dec_return(&cic->pending_pages))
		return;
@@ -1441,12 +1443,14 @@ void f2fs_compress_write_end_io(struct bio *bio, struct page *page)
}

static int f2fs_write_raw_pages(struct compress_ctx *cc,
					int *submitted,
					int *submitted_p,
					struct writeback_control *wbc,
					enum iostat_type io_type)
{
	struct address_space *mapping = cc->inode->i_mapping;
	int _submitted, compr_blocks, ret, i;
	struct f2fs_sb_info *sbi = F2FS_M_SB(mapping);
	int submitted, compr_blocks, i;
	int ret = 0;

	compr_blocks = f2fs_compressed_blocks(cc);

@@ -1461,6 +1465,10 @@ static int f2fs_write_raw_pages(struct compress_ctx *cc,
	if (compr_blocks < 0)
		return compr_blocks;

	/* overwrite compressed cluster w/ normal cluster */
	if (compr_blocks > 0)
		f2fs_lock_op(sbi);

	for (i = 0; i < cc->cluster_size; i++) {
		if (!cc->rpages[i])
			continue;
@@ -1485,7 +1493,7 @@ 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(cc->rpages[i], &submitted,
						NULL, NULL, wbc, io_type,
						compr_blocks, false);
		if (ret) {
@@ -1493,26 +1501,29 @@ static int f2fs_write_raw_pages(struct compress_ctx *cc,
				unlock_page(cc->rpages[i]);
				ret = 0;
			} else if (ret == -EAGAIN) {
				ret = 0;
				/*
				 * for quota file, just redirty left pages to
				 * avoid deadlock caused by cluster update race
				 * from foreground operation.
				 */
				if (IS_NOQUOTA(cc->inode))
					return 0;
				ret = 0;
					goto out;
				f2fs_io_schedule_timeout(DEFAULT_IO_TIMEOUT);
				goto retry_write;
			}
			return ret;
			goto out;
		}

		*submitted += _submitted;
		*submitted_p += submitted;
	}

	f2fs_balance_fs(F2FS_M_SB(mapping), true);
out:
	if (compr_blocks > 0)
		f2fs_unlock_op(sbi);

	return 0;
	f2fs_balance_fs(sbi, true);
	return ret;
}

int f2fs_write_multi_pages(struct compress_ctx *cc,
@@ -1806,16 +1817,18 @@ void f2fs_put_page_dic(struct page *page, bool in_task)
 * check whether cluster blocks are contiguous, and add extent cache entry
 * only if cluster blocks are logically and physically contiguous.
 */
unsigned int f2fs_cluster_blocks_are_contiguous(struct dnode_of_data *dn)
unsigned int f2fs_cluster_blocks_are_contiguous(struct dnode_of_data *dn,
						unsigned int ofs_in_node)
{
	bool compressed = f2fs_data_blkaddr(dn) == COMPRESS_ADDR;
	bool compressed = data_blkaddr(dn->inode, dn->node_page,
					ofs_in_node) == COMPRESS_ADDR;
	int i = compressed ? 1 : 0;
	block_t first_blkaddr = data_blkaddr(dn->inode, dn->node_page,
						dn->ofs_in_node + i);
							ofs_in_node + i);

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

		if (!__is_valid_data_blkaddr(blkaddr))
			break;
@@ -1878,12 +1891,8 @@ void f2fs_cache_compressed_page(struct f2fs_sb_info *sbi, struct page *page,

	set_page_private_data(cpage, ino);

	if (!f2fs_is_valid_blkaddr(sbi, blkaddr, DATA_GENERIC_ENHANCE_READ))
		goto out;

	memcpy(page_address(cpage), page_address(page), PAGE_SIZE);
	SetPageUptodate(cpage);
out:
	f2fs_put_page(cpage, 1);
}

+66 −125
Original line number Diff line number Diff line
@@ -48,7 +48,7 @@ void f2fs_destroy_bioset(void)
	bioset_exit(&f2fs_bioset);
}

static bool __is_cp_guaranteed(struct page *page)
bool f2fs_is_cp_guaranteed(struct page *page)
{
	struct address_space *mapping = page->mapping;
	struct inode *inode;
@@ -65,8 +65,6 @@ static bool __is_cp_guaranteed(struct page *page)
			S_ISDIR(inode->i_mode))
		return true;

	if (f2fs_is_compressed_page(page))
		return false;
	if ((S_ISREG(inode->i_mode) && IS_NOQUOTA(inode)) ||
			page_private_gcing(page))
		return true;
@@ -338,18 +336,7 @@ static void f2fs_write_end_io(struct bio *bio)

	bio_for_each_segment_all(bvec, bio, iter_all) {
		struct page *page = bvec->bv_page;
		enum count_type type = WB_DATA_TYPE(page);

		if (page_private_dummy(page)) {
			clear_page_private_dummy(page);
			unlock_page(page);
			mempool_free(page, sbi->write_io_dummy);

			if (unlikely(bio->bi_status))
				f2fs_stop_checkpoint(sbi, true,
						STOP_CP_REASON_WRITE_FAIL);
			continue;
		}
		enum count_type type = WB_DATA_TYPE(page, false);

		fscrypt_finalize_bounce_page(&page);

@@ -524,51 +511,14 @@ void f2fs_submit_read_bio(struct f2fs_sb_info *sbi, struct bio *bio,
	submit_bio(bio);
}

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 (start == 0)
		return;

	/* 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);

		lock_page(page);

		zero_user_segment(page, 0, PAGE_SIZE);
		set_page_private_dummy(page);

		if (bio_add_page(bio, page, PAGE_SIZE, 0) < PAGE_SIZE)
			f2fs_bug_on(sbi, 1);
	}
}

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)
	if (f2fs_lfs_mode(sbi) && current->plug && PAGE_TYPE_ON_MAIN(type))
		blk_finish_plug(current->plug);

		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);
		}
	}

	trace_f2fs_submit_write_bio(sbi->sb, type, bio);
	iostat_update_submit_ctx(bio, type);
	submit_bio(bio);
@@ -740,10 +690,8 @@ int f2fs_submit_page_bio(struct f2fs_io_info *fio)

	if (!f2fs_is_valid_blkaddr(fio->sbi, fio->new_blkaddr,
			fio->is_por ? META_POR : (__is_meta_io(fio) ?
			META_GENERIC : DATA_GENERIC_ENHANCE))) {
		f2fs_handle_error(fio->sbi, ERROR_INVALID_BLKADDR);
			META_GENERIC : DATA_GENERIC_ENHANCE)))
		return -EFSCORRUPTED;
	}

	trace_f2fs_submit_page_bio(page, fio);

@@ -762,7 +710,7 @@ int f2fs_submit_page_bio(struct f2fs_io_info *fio)
		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));
			__read_io_type(page) : WB_DATA_TYPE(fio->page, false));

	if (is_read_io(bio_op(bio)))
		f2fs_submit_read_bio(fio->sbi, bio, fio->type);
@@ -796,16 +744,6 @@ static bool io_is_mergeable(struct f2fs_sb_info *sbi, struct bio *bio,
					block_t last_blkaddr,
					block_t cur_blkaddr)
{
	if (F2FS_IO_ALIGNED(sbi) && (fio->type == DATA || fio->type == NODE)) {
		unsigned int filled_blocks =
				F2FS_BYTES_TO_BLK(bio->bi_iter.bi_size);
		unsigned int io_size = F2FS_IO_SIZE(sbi);
		unsigned int left_vecs = bio->bi_max_vecs - bio->bi_vcnt;

		/* IOs in bio is aligned and left space of vectors is not enough */
		if (!(filled_blocks % io_size) && left_vecs < io_size)
			return false;
	}
	if (!page_is_mergeable(sbi, bio, last_blkaddr, cur_blkaddr))
		return false;
	return io_type_is_mergeable(io, fio);
@@ -948,10 +886,8 @@ int f2fs_merge_page_bio(struct f2fs_io_info *fio)
			fio->encrypted_page : fio->page;

	if (!f2fs_is_valid_blkaddr(fio->sbi, fio->new_blkaddr,
			__is_meta_io(fio) ? META_GENERIC : DATA_GENERIC)) {
		f2fs_handle_error(fio->sbi, ERROR_INVALID_BLKADDR);
			__is_meta_io(fio) ? META_GENERIC : DATA_GENERIC))
		return -EFSCORRUPTED;
	}

	trace_f2fs_submit_page_bio(page, fio);

@@ -973,7 +909,7 @@ int f2fs_merge_page_bio(struct f2fs_io_info *fio)
	if (fio->io_wbc)
		wbc_account_cgroup_owner(fio->io_wbc, fio->page, PAGE_SIZE);

	inc_page_count(fio->sbi, WB_DATA_TYPE(page));
	inc_page_count(fio->sbi, WB_DATA_TYPE(page, false));

	*fio->last_block = fio->new_blkaddr;
	*fio->bio = bio;
@@ -1007,11 +943,12 @@ void f2fs_submit_page_write(struct f2fs_io_info *fio)
	enum page_type btype = PAGE_TYPE_OF_BIO(fio->type);
	struct f2fs_bio_info *io = sbi->write_io[btype] + fio->temp;
	struct page *bio_page;
	enum count_type type;

	f2fs_bug_on(sbi, is_read_io(fio->op));

	f2fs_down_write(&io->io_rwsem);

next:
#ifdef CONFIG_BLK_DEV_ZONED
	if (f2fs_sb_has_blkzoned(sbi) && btype < META && io->zone_pending_bio) {
		wait_for_completion_io(&io->zone_wait);
@@ -1021,7 +958,6 @@ void f2fs_submit_page_write(struct f2fs_io_info *fio)
	}
#endif

next:
	if (fio->in_list) {
		spin_lock(&io->io_lock);
		if (list_empty(&io->io_list)) {
@@ -1046,7 +982,8 @@ void f2fs_submit_page_write(struct f2fs_io_info *fio)
	/* set submitted = true as a return value */
	fio->submitted = 1;

	inc_page_count(sbi, WB_DATA_TYPE(bio_page));
	type = WB_DATA_TYPE(bio_page, fio->compressed_page);
	inc_page_count(sbi, type);

	if (io->bio &&
	    (!io_is_mergeable(sbi, io->bio, io, fio, io->last_block_in_bio,
@@ -1056,13 +993,6 @@ void f2fs_submit_page_write(struct f2fs_io_info *fio)
		__submit_merged_bio(io);
alloc_new:
	if (io->bio == NULL) {
		if (F2FS_IO_ALIGNED(sbi) &&
				(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 = 1;
			goto skip;
		}
		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);
@@ -1080,10 +1010,6 @@ void f2fs_submit_page_write(struct f2fs_io_info *fio)
	io->last_block_in_bio = fio->new_blkaddr;

	trace_f2fs_submit_page_write(fio->page, fio);
skip:
	if (fio->in_list)
		goto next;
out:
#ifdef CONFIG_BLK_DEV_ZONED
	if (f2fs_sb_has_blkzoned(sbi) && btype < META &&
			is_end_zone_blkaddr(sbi, fio->new_blkaddr)) {
@@ -1096,6 +1022,9 @@ void f2fs_submit_page_write(struct f2fs_io_info *fio)
		__submit_merged_bio(io);
	}
#endif
	if (fio->in_list)
		goto next;
out:
	if (is_sbi_flag_set(sbi, SBI_IS_SHUTDOWN) ||
				!f2fs_is_checkpoint_ready(sbi))
		__submit_merged_bio(io);
@@ -1218,7 +1147,8 @@ int f2fs_reserve_new_blocks(struct dnode_of_data *dn, blkcnt_t count)

	if (unlikely(is_inode_flag_set(dn->inode, FI_NO_ALLOC)))
		return -EPERM;
	if (unlikely((err = inc_valid_block_count(sbi, dn->inode, &count))))
	err = inc_valid_block_count(sbi, dn->inode, &count, true);
	if (unlikely(err))
		return err;

	trace_f2fs_reserve_new_blocks(dn->inode, dn->nid,
@@ -1285,8 +1215,6 @@ struct page *f2fs_get_read_data_page(struct inode *inode, pgoff_t index,
		if (!f2fs_is_valid_blkaddr(F2FS_I_SB(inode), dn.data_blkaddr,
						DATA_GENERIC_ENHANCE_READ)) {
			err = -EFSCORRUPTED;
			f2fs_handle_error(F2FS_I_SB(inode),
						ERROR_INVALID_BLKADDR);
			goto put_err;
		}
		goto got_it;
@@ -1312,8 +1240,6 @@ struct page *f2fs_get_read_data_page(struct inode *inode, pgoff_t index,
						dn.data_blkaddr,
						DATA_GENERIC_ENHANCE)) {
		err = -EFSCORRUPTED;
		f2fs_handle_error(F2FS_I_SB(inode),
					ERROR_INVALID_BLKADDR);
		goto put_err;
	}
got_it:
@@ -1475,15 +1401,18 @@ static int __allocate_data_block(struct dnode_of_data *dn, int seg_type)

	dn->data_blkaddr = f2fs_data_blkaddr(dn);
	if (dn->data_blkaddr == NULL_ADDR) {
		err = inc_valid_block_count(sbi, dn->inode, &count);
		err = inc_valid_block_count(sbi, dn->inode, &count, true);
		if (unlikely(err))
			return err;
	}

	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,
				&sum, seg_type, NULL);
	err = f2fs_allocate_data_block(sbi, NULL, old_blkaddr,
				&dn->data_blkaddr, &sum, seg_type, NULL);
	if (err)
		return err;

	if (GET_SEGNO(sbi, old_blkaddr) != NULL_SEGNO)
		f2fs_invalidate_internal_cache(sbi, old_blkaddr);

@@ -1641,7 +1570,6 @@ int f2fs_map_blocks(struct inode *inode, struct f2fs_map_blocks *map, int flag)
	if (!is_hole &&
	    !f2fs_is_valid_blkaddr(sbi, blkaddr, DATA_GENERIC_ENHANCE)) {
		err = -EFSCORRUPTED;
		f2fs_handle_error(sbi, ERROR_INVALID_BLKADDR);
		goto sync_out;
	}

@@ -2165,8 +2093,6 @@ static int f2fs_read_single_page(struct inode *inode, struct page *page,
		if (!f2fs_is_valid_blkaddr(F2FS_I_SB(inode), block_nr,
						DATA_GENERIC_ENHANCE_READ)) {
			ret = -EFSCORRUPTED;
			f2fs_handle_error(F2FS_I_SB(inode),
						ERROR_INVALID_BLKADDR);
			goto out;
		}
	} else {
@@ -2668,8 +2594,6 @@ bool f2fs_should_update_outplace(struct inode *inode, struct f2fs_io_info *fio)
	if (fio) {
		if (page_private_gcing(fio->page))
			return true;
		if (page_private_dummy(fio->page))
			return true;
		if (unlikely(is_sbi_flag_set(sbi, SBI_CP_DISABLED) &&
			f2fs_is_checkpointed_data(sbi, fio->old_blkaddr)))
			return true;
@@ -2706,11 +2630,8 @@ int f2fs_do_write_data_page(struct f2fs_io_info *fio)
	    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,
						ERROR_INVALID_BLKADDR);
						DATA_GENERIC_ENHANCE))
			return -EFSCORRUPTED;
		}

		ipu_force = true;
		fio->need_lock = LOCK_DONE;
@@ -2738,7 +2659,6 @@ int f2fs_do_write_data_page(struct f2fs_io_info *fio)
		!f2fs_is_valid_blkaddr(fio->sbi, fio->old_blkaddr,
						DATA_GENERIC_ENHANCE)) {
		err = -EFSCORRUPTED;
		f2fs_handle_error(fio->sbi, ERROR_INVALID_BLKADDR);
		goto out_writepage;
	}

@@ -2838,7 +2758,7 @@ int f2fs_write_single_data_page(struct page *page, int *submitted,
		.encrypted_page = NULL,
		.submitted = 0,
		.compr_blocks = compr_blocks,
		.need_lock = LOCK_RETRY,
		.need_lock = compr_blocks ? LOCK_DONE : LOCK_RETRY,
		.post_read = f2fs_post_read_required(inode) ? 1 : 0,
		.io_type = io_type,
		.io_wbc = wbc,
@@ -2919,6 +2839,7 @@ int f2fs_write_single_data_page(struct page *page, int *submitted,
	if (err == -EAGAIN) {
		err = f2fs_do_write_data_page(&fio);
		if (err == -EAGAIN) {
			f2fs_bug_on(sbi, compr_blocks);
			fio.need_lock = LOCK_REQ;
			err = f2fs_do_write_data_page(&fio);
		}
@@ -3704,7 +3625,6 @@ static int f2fs_write_begin(struct file *file, struct address_space *mapping,
		if (!f2fs_is_valid_blkaddr(sbi, blkaddr,
				DATA_GENERIC_ENHANCE_READ)) {
			err = -EFSCORRUPTED;
			f2fs_handle_error(sbi, ERROR_INVALID_BLKADDR);
			goto fail;
		}
		err = f2fs_submit_page_read(use_cow ?
@@ -3905,26 +3825,36 @@ static int f2fs_migrate_blocks(struct inode *inode, block_t start_blk,
	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
	unsigned int blkofs;
	unsigned int blk_per_sec = BLKS_PER_SEC(sbi);
	unsigned int end_blk = start_blk + blkcnt - 1;
	unsigned int secidx = start_blk / blk_per_sec;
	unsigned int end_sec = secidx + blkcnt / blk_per_sec;
	unsigned int end_sec;
	int ret = 0;

	if (!blkcnt)
		return 0;
	end_sec = end_blk / blk_per_sec;

	f2fs_down_write(&F2FS_I(inode)->i_gc_rwsem[WRITE]);
	filemap_invalidate_lock(inode->i_mapping);

	set_inode_flag(inode, FI_ALIGNED_WRITE);
	set_inode_flag(inode, FI_OPU_WRITE);

	for (; secidx < end_sec; secidx++) {
	for (; secidx <= end_sec; secidx++) {
		unsigned int blkofs_end = secidx == end_sec ?
				end_blk % blk_per_sec : blk_per_sec - 1;

		f2fs_down_write(&sbi->pin_sem);

		f2fs_lock_op(sbi);
		f2fs_allocate_new_section(sbi, CURSEG_COLD_DATA_PINNED, false);
		f2fs_unlock_op(sbi);
		ret = f2fs_allocate_pinning_section(sbi);
		if (ret) {
			f2fs_up_write(&sbi->pin_sem);
			break;
		}

		set_inode_flag(inode, FI_SKIP_WRITES);

		for (blkofs = 0; blkofs < blk_per_sec; blkofs++) {
		for (blkofs = 0; blkofs <= blkofs_end; blkofs++) {
			struct page *page;
			unsigned int blkidx = secidx * blk_per_sec + blkofs;

@@ -4013,27 +3943,34 @@ static int check_swap_activate(struct swap_info_struct *sis,
		nr_pblocks = map.m_len;

		if ((pblock - SM_I(sbi)->main_blkaddr) & sec_blks_mask ||
				nr_pblocks & sec_blks_mask) {
				nr_pblocks & sec_blks_mask ||
				!f2fs_valid_pinned_area(sbi, pblock)) {
			bool last_extent = false;

			not_aligned++;

			nr_pblocks = roundup(nr_pblocks, blks_per_sec);
			if (cur_lblock + nr_pblocks > sis->max)
				nr_pblocks -= blks_per_sec;

			if (!nr_pblocks) {
			/* this extent is last one */
				nr_pblocks = map.m_len;
				f2fs_warn(sbi, "Swapfile: last extent is not aligned to section");
				goto next;
			if (!nr_pblocks) {
				nr_pblocks = last_lblock - cur_lblock;
				last_extent = true;
			}

			ret = f2fs_migrate_blocks(inode, cur_lblock,
							nr_pblocks);
			if (ret)
			if (ret) {
				if (ret == -ENOENT)
					ret = -EINVAL;
				goto out;
			}

			if (!last_extent)
				goto retry;
		}
next:

		if (cur_lblock + nr_pblocks >= sis->max)
			nr_pblocks = sis->max - cur_lblock;

@@ -4071,17 +4008,17 @@ static int f2fs_swap_activate(struct swap_info_struct *sis, struct file *file,
				sector_t *span)
{
	struct inode *inode = file_inode(file);
	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
	int ret;

	if (!S_ISREG(inode->i_mode))
		return -EINVAL;

	if (f2fs_readonly(F2FS_I_SB(inode)->sb))
	if (f2fs_readonly(sbi->sb))
		return -EROFS;

	if (f2fs_lfs_mode(F2FS_I_SB(inode))) {
		f2fs_err(F2FS_I_SB(inode),
			"Swapfile not supported in LFS mode");
	if (f2fs_lfs_mode(sbi) && !f2fs_sb_has_blkzoned(sbi)) {
		f2fs_err(sbi, "Swapfile not supported in LFS mode");
		return -EINVAL;
	}

@@ -4092,6 +4029,10 @@ static int f2fs_swap_activate(struct swap_info_struct *sis, struct file *file,
	if (!f2fs_disable_compressed_file(inode))
		return -EINVAL;

	ret = filemap_fdatawrite(inode->i_mapping);
	if (ret < 0)
		return ret;

	f2fs_precache_extents(inode);

	ret = check_swap_activate(sis, file, span);
@@ -4100,7 +4041,7 @@ static int f2fs_swap_activate(struct swap_info_struct *sis, struct file *file,

	stat_inc_swapfile_inode(inode);
	set_inode_flag(inode, FI_PIN_FILE);
	f2fs_update_time(F2FS_I_SB(inode), REQ_TIME);
	f2fs_update_time(sbi, REQ_TIME);
	return ret;
}

Loading