Commit 2ac44821 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull f2fs fixes from Jaegeuk Kim:

 - fix a null pointer dereference in f2fs_issue_flush, which occurs by
   the combination of mount/remount options.

 - fix a bug in per-block age-based extent_cache newly introduced in
   6.2-rc1, which reported a wrong age information in extent_cache.

 - fix a kernel panic if extent_tree was not created, which was caught
   by a wrong BUG_ON

* tag 'f2fs-fix-6.2-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/jaegeuk/f2fs:
  f2fs: let's avoid panic if extent_tree is not created
  f2fs: should use a temp extent_info for lookup
  f2fs: don't mix to use union values in extent_info
  f2fs: initialize extent_cache parameter
  f2fs: fix to avoid NULL pointer dereference in f2fs_issue_flush()
parents b61778fa df9d44b6
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -2183,7 +2183,7 @@ int f2fs_read_multi_pages(struct compress_ctx *cc, struct bio **bio_ret,
	sector_t last_block_in_file;
	const unsigned blocksize = blks_to_bytes(inode, 1);
	struct decompress_io_ctx *dic = NULL;
	struct extent_info ei = {0, };
	struct extent_info ei = {};
	bool from_dnode = true;
	int i;
	int ret = 0;
+18 −16
Original line number Diff line number Diff line
@@ -546,7 +546,8 @@ static bool __lookup_extent_tree(struct inode *inode, pgoff_t pgofs,
	struct extent_node *en;
	bool ret = false;

	f2fs_bug_on(sbi, !et);
	if (!et)
		return false;

	trace_f2fs_lookup_extent_tree_start(inode, pgofs, type);

@@ -881,12 +882,14 @@ static unsigned long long __calculate_block_age(unsigned long long new,
}

/* This returns a new age and allocated blocks in ei */
static int __get_new_block_age(struct inode *inode, struct extent_info *ei)
static int __get_new_block_age(struct inode *inode, struct extent_info *ei,
						block_t blkaddr)
{
	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
	loff_t f_size = i_size_read(inode);
	unsigned long long cur_blocks =
				atomic64_read(&sbi->allocated_data_blocks);
	struct extent_info tei = *ei;	/* only fofs and len are valid */

	/*
	 * When I/O is not aligned to a PAGE_SIZE, update will happen to the last
@@ -894,20 +897,20 @@ static int __get_new_block_age(struct inode *inode, struct extent_info *ei)
	 * block here.
	 */
	if ((f_size >> PAGE_SHIFT) == ei->fofs && f_size & (PAGE_SIZE - 1) &&
			ei->blk == NEW_ADDR)
			blkaddr == NEW_ADDR)
		return -EINVAL;

	if (__lookup_extent_tree(inode, ei->fofs, ei, EX_BLOCK_AGE)) {
	if (__lookup_extent_tree(inode, ei->fofs, &tei, EX_BLOCK_AGE)) {
		unsigned long long cur_age;

		if (cur_blocks >= ei->last_blocks)
			cur_age = cur_blocks - ei->last_blocks;
		if (cur_blocks >= tei.last_blocks)
			cur_age = cur_blocks - tei.last_blocks;
		else
			/* allocated_data_blocks overflow */
			cur_age = ULLONG_MAX - ei->last_blocks + cur_blocks;
			cur_age = ULLONG_MAX - tei.last_blocks + cur_blocks;

		if (ei->age)
			ei->age = __calculate_block_age(cur_age, ei->age);
		if (tei.age)
			ei->age = __calculate_block_age(cur_age, tei.age);
		else
			ei->age = cur_age;
		ei->last_blocks = cur_blocks;
@@ -915,14 +918,14 @@ static int __get_new_block_age(struct inode *inode, struct extent_info *ei)
		return 0;
	}

	f2fs_bug_on(sbi, ei->blk == NULL_ADDR);
	f2fs_bug_on(sbi, blkaddr == NULL_ADDR);

	/* the data block was allocated for the first time */
	if (ei->blk == NEW_ADDR)
	if (blkaddr == NEW_ADDR)
		goto out;

	if (__is_valid_data_blkaddr(ei->blk) &&
			!f2fs_is_valid_blkaddr(sbi, ei->blk, DATA_GENERIC_ENHANCE)) {
	if (__is_valid_data_blkaddr(blkaddr) &&
	    !f2fs_is_valid_blkaddr(sbi, blkaddr, DATA_GENERIC_ENHANCE)) {
		f2fs_bug_on(sbi, 1);
		return -EINVAL;
	}
@@ -938,7 +941,7 @@ static int __get_new_block_age(struct inode *inode, struct extent_info *ei)

static void __update_extent_cache(struct dnode_of_data *dn, enum extent_type type)
{
	struct extent_info ei;
	struct extent_info ei = {};

	if (!__may_extent_tree(dn->inode, type))
		return;
@@ -953,8 +956,7 @@ static void __update_extent_cache(struct dnode_of_data *dn, enum extent_type typ
		else
			ei.blk = dn->data_blkaddr;
	} else if (type == EX_BLOCK_AGE) {
		ei.blk = dn->data_blkaddr;
		if (__get_new_block_age(dn->inode, &ei))
		if (__get_new_block_age(dn->inode, &ei, dn->data_blkaddr))
			return;
	}
	__update_extent_tree_range(dn->inode, &ei, type);
+1 −1
Original line number Diff line number Diff line
@@ -2559,7 +2559,7 @@ static int f2fs_defragment_range(struct f2fs_sb_info *sbi,
	struct f2fs_map_blocks map = { .m_next_extent = NULL,
					.m_seg_type = NO_CHECK_TYPE,
					.m_may_create = false };
	struct extent_info ei = {0, };
	struct extent_info ei = {};
	pgoff_t pg_start, pg_end, next_pgofs;
	unsigned int blk_per_seg = sbi->blocks_per_seg;
	unsigned int total = 0, sec_num;
+5 −8
Original line number Diff line number Diff line
@@ -663,8 +663,7 @@ int f2fs_create_flush_cmd_control(struct f2fs_sb_info *sbi)
	if (IS_ERR(fcc->f2fs_issue_flush)) {
		int err = PTR_ERR(fcc->f2fs_issue_flush);

		kfree(fcc);
		SM_I(sbi)->fcc_info = NULL;
		fcc->f2fs_issue_flush = NULL;
		return err;
	}

@@ -3161,7 +3160,7 @@ static int __get_segment_type_4(struct f2fs_io_info *fio)
static int __get_age_segment_type(struct inode *inode, pgoff_t pgofs)
{
	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
	struct extent_info ei;
	struct extent_info ei = {};

	if (f2fs_lookup_age_extent_cache(inode, pgofs, &ei)) {
		if (!ei.age)
@@ -5138,11 +5137,9 @@ int f2fs_build_segment_manager(struct f2fs_sb_info *sbi)

	init_f2fs_rwsem(&sm_info->curseg_lock);

	if (!f2fs_readonly(sbi->sb)) {
	err = f2fs_create_flush_cmd_control(sbi);
	if (err)
		return err;
	}

	err = create_discard_cmd_control(sbi);
	if (err)