NULL_SEGNO should also be returned when the blk_addr value is out-of-bound main area even __is_valid_data_blkaddr return true.
For example, a 64MB partition with total 24 main segments has no any free segments left, then a new wrtie request use get_new_segment may get a out-of-bound segno 24 if CONFIG_F2FS_CHECK_FS is not enabled. GET_SEGNO should also return NULL_SEGNO in this case rather than treating is as valid segment. Besides, if the caller of GET_SEGNO does not ensure blk_addr pass to GET_SEGNO is valid, it should do sanity check about return value of GET_SEGNO, avoid causing some unexpected problems later. Signed-off-by: Zhiguo Niu <zhiguo....@unisoc.com> --- fs/f2fs/file.c | 7 ++++++- fs/f2fs/segment.c | 4 +++- fs/f2fs/segment.h | 3 ++- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c index 23cd6a1..2cd3cd9 100644 --- a/fs/f2fs/file.c +++ b/fs/f2fs/file.c @@ -2985,9 +2985,14 @@ static int f2fs_ioc_flush_device(struct file *filp, unsigned long arg) if (ret) return ret; - if (range.dev_num != 0) + if (range.dev_num != 0) { dev_start_segno = GET_SEGNO(sbi, FDEV(range.dev_num).start_blk); + if (dev_start_segno == NULL_SEGNO) + return -EINVAL; + } dev_end_segno = GET_SEGNO(sbi, FDEV(range.dev_num).end_blk); + if (dev_end_segno == NULL_SEGNO) + return -EINVAL; start_segno = sm->last_victim[FLUSH_DEVICE]; if (start_segno < dev_start_segno || start_segno >= dev_end_segno) diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c index f373ff7..6772ad4 100644 --- a/fs/f2fs/segment.c +++ b/fs/f2fs/segment.c @@ -2496,7 +2496,7 @@ void f2fs_invalidate_blocks(struct f2fs_sb_info *sbi, block_t addr) struct sit_info *sit_i = SIT_I(sbi); f2fs_bug_on(sbi, addr == NULL_ADDR); - if (addr == NEW_ADDR || addr == COMPRESS_ADDR) + if (segno == NULL_SEGNO) return; f2fs_invalidate_internal_cache(sbi, addr); @@ -3708,6 +3708,8 @@ void f2fs_do_replace_block(struct f2fs_sb_info *sbi, struct f2fs_summary *sum, unsigned char old_alloc_type; segno = GET_SEGNO(sbi, new_blkaddr); + if (segno == NULL_SEGNO) + return; se = get_seg_entry(sbi, segno); type = se->type; diff --git a/fs/f2fs/segment.h b/fs/f2fs/segment.h index f2847f1..b0ea315 100644 --- a/fs/f2fs/segment.h +++ b/fs/f2fs/segment.h @@ -96,7 +96,8 @@ static inline void sanity_check_seg_type(struct f2fs_sb_info *sbi, (GET_SEGOFF_FROM_SEG0(sbi, blk_addr) & ((sbi)->blocks_per_seg - 1)) #define GET_SEGNO(sbi, blk_addr) \ - ((!__is_valid_data_blkaddr(blk_addr)) ? \ + ((!__is_valid_data_blkaddr(blk_addr) || \ + !f2fs_is_valid_blkaddr(sbi, blk_addr, DATA_GENERIC)) ? \ NULL_SEGNO : GET_L2R_SEGNO(FREE_I(sbi), \ GET_SEGNO_FROM_SEG0(sbi, blk_addr))) #define BLKS_PER_SEC(sbi) \ -- 1.9.1 _______________________________________________ Linux-f2fs-devel mailing list Linux-f2fs-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel