f2fs-fix-6.2-rc3

This series fixes the below three bugs introduced in 6.2-rc1.
 
 - 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.
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCgAdFiEE00UqedjCtOrGVvQiQBSofoJIUNIFAmO1xyMACgkQQBSofoJI
 UNLivg//T7APr6AMyG59vmQv1Yzz0g1ZMCnkZ0cdBYBYgam0bwLtAgVFPfFfWc0q
 1E5xqAIlxLjSZ/r9cZcOkTx9wq0De1Htgn5LhflsMrX0xyUYmldQH7uXx+m7nV2y
 kMZ1QyIc7IT7MNP/FdiZnGtnD+amKj0D/pF0rXUYIrr6uwpyDX/lJ2sEJlUQcFuM
 cJ2qAltRNaQumOYcCC1T+jS31fWUQw3DZYbaUi7pS7g7Y8js5xV1fGpPCvfLBcyf
 bBj48ynUSmH5nv4RI2wI0V12/naJNjvzhDCXHO0EM//ruHS86yspnyE2ywpZNKx0
 MQ3aIwG0eKtCFX6Rdg+rVeqIg+eMoXCisIDuY0KY2TMPlwYWEsnMn1UqCp3uN8d0
 yCR5BI7u4JeH11scuATz4lH9ffsIZbNUxQdpQnCOISO4eCYHQwfblYRvUddENLT7
 J9vljgVJvX7aDw2V8ErRGw0OLa5HuWz+7tRkVmYWm/LHOquyt5ZXxDyWrEHrLGiq
 6btAiHUrCa9ugT3jq2ub3CV7bkrUaw0G0LSsYYb5lCK62g6KMQzFpLQ+4MwrWla7
 vIiidlzWmxg/lSpDeRpR1ybuGSPZ9/5iHNTaVHd4kgrWK2Zt3CDKj2fMPnCKPVZ8
 diq1TuVKPbE/K4+zVQACRk2udkzSpwEVkum4awhKdIErlZ0kr04=
 =yV+N
 -----END PGP SIGNATURE-----

Merge tag 'f2fs-fix-6.2-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/jaegeuk/f2fs

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()
This commit is contained in:
Linus Torvalds 2023-01-04 12:02:26 -08:00
commit 2ac44821a8
4 changed files with 25 additions and 26 deletions

View file

@ -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;

View file

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

View file

@ -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;

View file

@ -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 = f2fs_create_flush_cmd_control(sbi);
if (err)
return err;
err = create_discard_cmd_control(sbi);
if (err)