Commit ac524ece authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull f2fs fixes from Jaegeuk Kim:
 "This fixes some critical bugs such as memory leak in compression
  flows, kernel panic when handling errors, and swapon failure due to
  newly added condition check"

* tag 'f2fs-5.13-rc1-fix' of git://git.kernel.org/pub/scm/linux/kernel/git/jaegeuk/f2fs:
  f2fs: return EINVAL for hole cases in swap file
  f2fs: avoid swapon failure by giving a warning first
  f2fs: compress: fix to assign cc.cluster_idx correctly
  f2fs: compress: fix race condition of overwrite vs truncate
  f2fs: compress: fix to free compress page correctly
  f2fs: support iflag change given the mask
  f2fs: avoid null pointer access when handling IPU error
parents b5304a4f f395183f
Loading
Loading
Loading
Loading
+23 −32
Original line number Diff line number Diff line
@@ -117,19 +117,6 @@ static void f2fs_unlock_rpages(struct compress_ctx *cc, int len)
	f2fs_drop_rpages(cc, len, true);
}

static void f2fs_put_rpages_mapping(struct address_space *mapping,
				pgoff_t start, int len)
{
	int i;

	for (i = 0; i < len; i++) {
		struct page *page = find_get_page(mapping, start + i);

		put_page(page);
		put_page(page);
	}
}

static void f2fs_put_rpages_wbc(struct compress_ctx *cc,
		struct writeback_control *wbc, bool redirty, int unlock)
{
@@ -158,12 +145,13 @@ int f2fs_init_compress_ctx(struct compress_ctx *cc)
	return cc->rpages ? 0 : -ENOMEM;
}

void f2fs_destroy_compress_ctx(struct compress_ctx *cc)
void f2fs_destroy_compress_ctx(struct compress_ctx *cc, bool reuse)
{
	page_array_free(cc->inode, cc->rpages, cc->cluster_size);
	cc->rpages = NULL;
	cc->nr_rpages = 0;
	cc->nr_cpages = 0;
	if (!reuse)
		cc->cluster_idx = NULL_CLUSTER;
}

@@ -1036,7 +1024,7 @@ static int prepare_compress_overwrite(struct compress_ctx *cc,
		}

		if (PageUptodate(page))
			unlock_page(page);
			f2fs_put_page(page, 1);
		else
			f2fs_compress_ctx_add_page(cc, page);
	}
@@ -1046,33 +1034,35 @@ static int prepare_compress_overwrite(struct compress_ctx *cc,

		ret = f2fs_read_multi_pages(cc, &bio, cc->cluster_size,
					&last_block_in_bio, false, true);
		f2fs_destroy_compress_ctx(cc);
		f2fs_put_rpages(cc);
		f2fs_destroy_compress_ctx(cc, true);
		if (ret)
			goto release_pages;
			goto out;
		if (bio)
			f2fs_submit_bio(sbi, bio, DATA);

		ret = f2fs_init_compress_ctx(cc);
		if (ret)
			goto release_pages;
			goto out;
	}

	for (i = 0; i < cc->cluster_size; i++) {
		f2fs_bug_on(sbi, cc->rpages[i]);

		page = find_lock_page(mapping, start_idx + i);
		f2fs_bug_on(sbi, !page);
		if (!page) {
			/* page can be truncated */
			goto release_and_retry;
		}

		f2fs_wait_on_page_writeback(page, DATA, true, true);

		f2fs_compress_ctx_add_page(cc, page);
		f2fs_put_page(page, 0);

		if (!PageUptodate(page)) {
release_and_retry:
			f2fs_put_rpages(cc);
			f2fs_unlock_rpages(cc, i + 1);
			f2fs_put_rpages_mapping(mapping, start_idx,
					cc->cluster_size);
			f2fs_destroy_compress_ctx(cc);
			f2fs_destroy_compress_ctx(cc, true);
			goto retry;
		}
	}
@@ -1103,10 +1093,10 @@ static int prepare_compress_overwrite(struct compress_ctx *cc,
	}

unlock_pages:
	f2fs_put_rpages(cc);
	f2fs_unlock_rpages(cc, i);
release_pages:
	f2fs_put_rpages_mapping(mapping, start_idx, i);
	f2fs_destroy_compress_ctx(cc);
	f2fs_destroy_compress_ctx(cc, true);
out:
	return ret;
}

@@ -1141,7 +1131,7 @@ bool f2fs_compress_write_end(struct inode *inode, void *fsdata,
		set_cluster_dirty(&cc);

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

	return first_index;
}
@@ -1361,7 +1351,7 @@ static int f2fs_write_compressed_pages(struct compress_ctx *cc,
	f2fs_put_rpages(cc);
	page_array_free(cc->inode, cc->cpages, cc->nr_cpages);
	cc->cpages = NULL;
	f2fs_destroy_compress_ctx(cc);
	f2fs_destroy_compress_ctx(cc, false);
	return 0;

out_destroy_crypt:
@@ -1372,7 +1362,8 @@ static int f2fs_write_compressed_pages(struct compress_ctx *cc,
	for (i = 0; i < cc->nr_cpages; i++) {
		if (!cc->cpages[i])
			continue;
		f2fs_put_page(cc->cpages[i], 1);
		f2fs_compress_free_page(cc->cpages[i]);
		cc->cpages[i] = NULL;
	}
out_put_cic:
	kmem_cache_free(cic_entry_slab, cic);
@@ -1522,7 +1513,7 @@ int f2fs_write_multi_pages(struct compress_ctx *cc,
	err = f2fs_write_raw_pages(cc, submitted, wbc, io_type);
	f2fs_put_rpages_wbc(cc, wbc, false, 0);
destroy_out:
	f2fs_destroy_compress_ctx(cc);
	f2fs_destroy_compress_ctx(cc, false);
	return err;
}

+28 −11
Original line number Diff line number Diff line
@@ -2287,7 +2287,7 @@ static int f2fs_mpage_readpages(struct inode *inode,
							max_nr_pages,
							&last_block_in_bio,
							rac != NULL, false);
				f2fs_destroy_compress_ctx(&cc);
				f2fs_destroy_compress_ctx(&cc, false);
				if (ret)
					goto set_error_page;
			}
@@ -2332,7 +2332,7 @@ static int f2fs_mpage_readpages(struct inode *inode,
							max_nr_pages,
							&last_block_in_bio,
							rac != NULL, false);
				f2fs_destroy_compress_ctx(&cc);
				f2fs_destroy_compress_ctx(&cc, false);
			}
		}
#endif
@@ -3033,7 +3033,7 @@ static int f2fs_write_cache_pages(struct address_space *mapping,
		}
	}
	if (f2fs_compressed_file(inode))
		f2fs_destroy_compress_ctx(&cc);
		f2fs_destroy_compress_ctx(&cc, false);
#endif
	if (retry) {
		index = 0;
@@ -3801,6 +3801,7 @@ static int f2fs_is_file_aligned(struct inode *inode)
	block_t pblock;
	unsigned long nr_pblocks;
	unsigned int blocks_per_sec = BLKS_PER_SEC(sbi);
	unsigned int not_aligned = 0;
	int ret = 0;

	cur_lblock = 0;
@@ -3833,13 +3834,20 @@ static int f2fs_is_file_aligned(struct inode *inode)

		if ((pblock - main_blkaddr) & (blocks_per_sec - 1) ||
			nr_pblocks & (blocks_per_sec - 1)) {
			if (f2fs_is_pinned_file(inode)) {
				f2fs_err(sbi, "Swapfile does not align to section");
				ret = -EINVAL;
				goto out;
			}
			not_aligned++;
		}

		cur_lblock += nr_pblocks;
	}
	if (not_aligned)
		f2fs_warn(sbi, "Swapfile (%u) is not align to section: \n"
			"\t1) creat(), 2) ioctl(F2FS_IOC_SET_PIN_FILE), 3) fallocate()",
			not_aligned);
out:
	return ret;
}
@@ -3858,6 +3866,7 @@ static int check_swap_activate_fast(struct swap_info_struct *sis,
	int nr_extents = 0;
	unsigned long nr_pblocks;
	unsigned int blocks_per_sec = BLKS_PER_SEC(sbi);
	unsigned int not_aligned = 0;
	int ret = 0;

	/*
@@ -3887,7 +3896,7 @@ static int check_swap_activate_fast(struct swap_info_struct *sis,
		/* hole */
		if (!(map.m_flags & F2FS_MAP_FLAGS)) {
			f2fs_err(sbi, "Swapfile has holes\n");
			ret = -ENOENT;
			ret = -EINVAL;
			goto out;
		}

@@ -3896,10 +3905,13 @@ static int check_swap_activate_fast(struct swap_info_struct *sis,

		if ((pblock - SM_I(sbi)->main_blkaddr) & (blocks_per_sec - 1) ||
				nr_pblocks & (blocks_per_sec - 1)) {
			if (f2fs_is_pinned_file(inode)) {
				f2fs_err(sbi, "Swapfile does not align to section");
				ret = -EINVAL;
				goto out;
			}
			not_aligned++;
		}

		if (cur_lblock + nr_pblocks >= sis->max)
			nr_pblocks = sis->max - cur_lblock;
@@ -3927,6 +3939,11 @@ static int check_swap_activate_fast(struct swap_info_struct *sis,
	sis->max = cur_lblock;
	sis->pages = cur_lblock - 1;
	sis->highest_bit = cur_lblock - 1;

	if (not_aligned)
		f2fs_warn(sbi, "Swapfile (%u) is not align to section: \n"
			"\t1) creat(), 2) ioctl(F2FS_IOC_SET_PIN_FILE), 3) fallocate()",
			not_aligned);
out:
	return ret;
}
@@ -4035,7 +4052,7 @@ static int check_swap_activate(struct swap_info_struct *sis,
	return ret;
bad_bmap:
	f2fs_err(sbi, "Swapfile has holes\n");
	return -ENOENT;
	return -EINVAL;
}

static int f2fs_swap_activate(struct swap_info_struct *sis, struct file *file,
+1 −1
Original line number Diff line number Diff line
@@ -3956,7 +3956,7 @@ struct decompress_io_ctx *f2fs_alloc_dic(struct compress_ctx *cc);
void f2fs_decompress_end_io(struct decompress_io_ctx *dic, bool failed);
void f2fs_put_page_dic(struct page *page);
int f2fs_init_compress_ctx(struct compress_ctx *cc);
void f2fs_destroy_compress_ctx(struct compress_ctx *cc);
void f2fs_destroy_compress_ctx(struct compress_ctx *cc, bool reuse);
void f2fs_init_compress_info(struct f2fs_sb_info *sbi);
int f2fs_init_page_array_cache(struct f2fs_sb_info *sbi);
void f2fs_destroy_page_array_cache(struct f2fs_sb_info *sbi);
+2 −1
Original line number Diff line number Diff line
@@ -1817,7 +1817,8 @@ static int f2fs_setflags_common(struct inode *inode, u32 iflags, u32 mask)
	struct f2fs_inode_info *fi = F2FS_I(inode);
	u32 masked_flags = fi->i_flags & mask;

	f2fs_bug_on(F2FS_I_SB(inode), (iflags & ~mask));
	/* mask can be shrunk by flags_valid selector */
	iflags &= mask;

	/* Is it quota file? Do not allow user to mess with it */
	if (IS_NOQUOTA(inode))
+2 −2
Original line number Diff line number Diff line
@@ -3574,12 +3574,12 @@ int f2fs_inplace_write_data(struct f2fs_io_info *fio)

	return err;
drop_bio:
	if (fio->bio) {
	if (fio->bio && *(fio->bio)) {
		struct bio *bio = *(fio->bio);

		bio->bi_status = BLK_STS_IOERR;
		bio_endio(bio);
		fio->bio = NULL;
		*(fio->bio) = NULL;
	}
	return err;
}