Commit 2ac44821 authored by Linus Torvalds's avatar Linus Torvalds

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()
parents b61778fa df9d44b6
...@@ -2183,7 +2183,7 @@ int f2fs_read_multi_pages(struct compress_ctx *cc, struct bio **bio_ret, ...@@ -2183,7 +2183,7 @@ int f2fs_read_multi_pages(struct compress_ctx *cc, struct bio **bio_ret,
sector_t last_block_in_file; sector_t last_block_in_file;
const unsigned blocksize = blks_to_bytes(inode, 1); const unsigned blocksize = blks_to_bytes(inode, 1);
struct decompress_io_ctx *dic = NULL; struct decompress_io_ctx *dic = NULL;
struct extent_info ei = {0, }; struct extent_info ei = {};
bool from_dnode = true; bool from_dnode = true;
int i; int i;
int ret = 0; int ret = 0;
......
...@@ -546,7 +546,8 @@ static bool __lookup_extent_tree(struct inode *inode, pgoff_t pgofs, ...@@ -546,7 +546,8 @@ static bool __lookup_extent_tree(struct inode *inode, pgoff_t pgofs,
struct extent_node *en; struct extent_node *en;
bool ret = false; bool ret = false;
f2fs_bug_on(sbi, !et); if (!et)
return false;
trace_f2fs_lookup_extent_tree_start(inode, pgofs, type); trace_f2fs_lookup_extent_tree_start(inode, pgofs, type);
...@@ -881,12 +882,14 @@ static unsigned long long __calculate_block_age(unsigned long long new, ...@@ -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 */ /* 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); struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
loff_t f_size = i_size_read(inode); loff_t f_size = i_size_read(inode);
unsigned long long cur_blocks = unsigned long long cur_blocks =
atomic64_read(&sbi->allocated_data_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 * 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) ...@@ -894,20 +897,20 @@ static int __get_new_block_age(struct inode *inode, struct extent_info *ei)
* block here. * block here.
*/ */
if ((f_size >> PAGE_SHIFT) == ei->fofs && f_size & (PAGE_SIZE - 1) && if ((f_size >> PAGE_SHIFT) == ei->fofs && f_size & (PAGE_SIZE - 1) &&
ei->blk == NEW_ADDR) blkaddr == NEW_ADDR)
return -EINVAL; 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; unsigned long long cur_age;
if (cur_blocks >= ei->last_blocks) if (cur_blocks >= tei.last_blocks)
cur_age = cur_blocks - ei->last_blocks; cur_age = cur_blocks - tei.last_blocks;
else else
/* allocated_data_blocks overflow */ /* 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) if (tei.age)
ei->age = __calculate_block_age(cur_age, ei->age); ei->age = __calculate_block_age(cur_age, tei.age);
else else
ei->age = cur_age; ei->age = cur_age;
ei->last_blocks = cur_blocks; ei->last_blocks = cur_blocks;
...@@ -915,14 +918,14 @@ static int __get_new_block_age(struct inode *inode, struct extent_info *ei) ...@@ -915,14 +918,14 @@ static int __get_new_block_age(struct inode *inode, struct extent_info *ei)
return 0; 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 */ /* the data block was allocated for the first time */
if (ei->blk == NEW_ADDR) if (blkaddr == NEW_ADDR)
goto out; goto out;
if (__is_valid_data_blkaddr(ei->blk) && if (__is_valid_data_blkaddr(blkaddr) &&
!f2fs_is_valid_blkaddr(sbi, ei->blk, DATA_GENERIC_ENHANCE)) { !f2fs_is_valid_blkaddr(sbi, blkaddr, DATA_GENERIC_ENHANCE)) {
f2fs_bug_on(sbi, 1); f2fs_bug_on(sbi, 1);
return -EINVAL; return -EINVAL;
} }
...@@ -938,7 +941,7 @@ static int __get_new_block_age(struct inode *inode, struct extent_info *ei) ...@@ -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) 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)) if (!__may_extent_tree(dn->inode, type))
return; return;
...@@ -953,8 +956,7 @@ static void __update_extent_cache(struct dnode_of_data *dn, enum extent_type typ ...@@ -953,8 +956,7 @@ static void __update_extent_cache(struct dnode_of_data *dn, enum extent_type typ
else else
ei.blk = dn->data_blkaddr; ei.blk = dn->data_blkaddr;
} else if (type == EX_BLOCK_AGE) { } else if (type == EX_BLOCK_AGE) {
ei.blk = dn->data_blkaddr; if (__get_new_block_age(dn->inode, &ei, dn->data_blkaddr))
if (__get_new_block_age(dn->inode, &ei))
return; return;
} }
__update_extent_tree_range(dn->inode, &ei, type); __update_extent_tree_range(dn->inode, &ei, type);
......
...@@ -2559,7 +2559,7 @@ static int f2fs_defragment_range(struct f2fs_sb_info *sbi, ...@@ -2559,7 +2559,7 @@ static int f2fs_defragment_range(struct f2fs_sb_info *sbi,
struct f2fs_map_blocks map = { .m_next_extent = NULL, struct f2fs_map_blocks map = { .m_next_extent = NULL,
.m_seg_type = NO_CHECK_TYPE, .m_seg_type = NO_CHECK_TYPE,
.m_may_create = false }; .m_may_create = false };
struct extent_info ei = {0, }; struct extent_info ei = {};
pgoff_t pg_start, pg_end, next_pgofs; pgoff_t pg_start, pg_end, next_pgofs;
unsigned int blk_per_seg = sbi->blocks_per_seg; unsigned int blk_per_seg = sbi->blocks_per_seg;
unsigned int total = 0, sec_num; unsigned int total = 0, sec_num;
......
...@@ -663,8 +663,7 @@ int f2fs_create_flush_cmd_control(struct f2fs_sb_info *sbi) ...@@ -663,8 +663,7 @@ int f2fs_create_flush_cmd_control(struct f2fs_sb_info *sbi)
if (IS_ERR(fcc->f2fs_issue_flush)) { if (IS_ERR(fcc->f2fs_issue_flush)) {
int err = PTR_ERR(fcc->f2fs_issue_flush); int err = PTR_ERR(fcc->f2fs_issue_flush);
kfree(fcc); fcc->f2fs_issue_flush = NULL;
SM_I(sbi)->fcc_info = NULL;
return err; return err;
} }
...@@ -3161,7 +3160,7 @@ static int __get_segment_type_4(struct f2fs_io_info *fio) ...@@ -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) static int __get_age_segment_type(struct inode *inode, pgoff_t pgofs)
{ {
struct f2fs_sb_info *sbi = F2FS_I_SB(inode); 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 (f2fs_lookup_age_extent_cache(inode, pgofs, &ei)) {
if (!ei.age) if (!ei.age)
...@@ -5138,11 +5137,9 @@ int f2fs_build_segment_manager(struct f2fs_sb_info *sbi) ...@@ -5138,11 +5137,9 @@ int f2fs_build_segment_manager(struct f2fs_sb_info *sbi)
init_f2fs_rwsem(&sm_info->curseg_lock); init_f2fs_rwsem(&sm_info->curseg_lock);
if (!f2fs_readonly(sbi->sb)) { err = f2fs_create_flush_cmd_control(sbi);
err = f2fs_create_flush_cmd_control(sbi); if (err)
if (err) return err;
return err;
}
err = create_discard_cmd_control(sbi); err = create_discard_cmd_control(sbi);
if (err) if (err)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment