diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2019-07-12 20:28:24 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2019-07-12 20:28:24 -0400 |
commit | a641a88e5d6864f20b2608cb01165c756794e645 (patch) | |
tree | 5acf37ca592a87d705169174b51feb47bd253fa9 /fs/f2fs/segment.c | |
parent | 4ce9d181ebe53abbca5f450b8a2984b8c3a38f26 (diff) | |
parent | 2d008835ec2fcf6eef3285e41e62a5eabd1fe76b (diff) |
Merge tag 'f2fs-for-5.3' of git://git.kernel.org/pub/scm/linux/kernel/git/jaegeuk/f2fs
Pull f2fs updates from Jaegeuk Kim:
"In this round, we've introduced native swap file support which can
exploit DIO, enhanced existing checkpoint=disable feature with
additional mount option to tune the triggering condition, and allowed
user to preallocate physical blocks in a pinned file which will be
useful to avoid f2fs fragmentation in append-only workloads. In
addition, we've fixed subtle quota corruption issue.
Enhancements:
- add swap file support which uses DIO
- allocate blocks for pinned file
- allow SSR and mount option to enhance checkpoint=disable
- enhance IPU IOs
- add more sanity checks such as memory boundary access
Bug fixes:
- quota corruption in very corner case of error-injected SPO case
- fix root_reserved on remount and some wrong counts
- add missing fsck flag
Some patches were also introduced to clean up ambiguous i_flags and
debugging messages codes"
* tag 'f2fs-for-5.3' of git://git.kernel.org/pub/scm/linux/kernel/git/jaegeuk/f2fs: (33 commits)
f2fs: improve print log in f2fs_sanity_check_ckpt()
f2fs: avoid out-of-range memory access
f2fs: fix to avoid long latency during umount
f2fs: allow all the users to pin a file
f2fs: support swap file w/ DIO
f2fs: allocate blocks for pinned file
f2fs: fix is_idle() check for discard type
f2fs: add a rw_sem to cover quota flag changes
f2fs: set SBI_NEED_FSCK for xattr corruption case
f2fs: use generic EFSBADCRC/EFSCORRUPTED
f2fs: Use DIV_ROUND_UP() instead of open-coding
f2fs: print kernel message if filesystem is inconsistent
f2fs: introduce f2fs_<level> macros to wrap f2fs_printk()
f2fs: avoid get_valid_blocks() for cleanup
f2fs: ioctl for removing a range from F2FS
f2fs: only set project inherit bit for directory
f2fs: separate f2fs i_flags from fs_flags and ext4 i_flags
f2fs: replace ktype default_attrs with default_groups
f2fs: Add option to limit required GC for checkpoint=disable
f2fs: Fix accounting for unusable blocks
...
Diffstat (limited to 'fs/f2fs/segment.c')
-rw-r--r-- | fs/f2fs/segment.c | 170 |
1 files changed, 134 insertions, 36 deletions
diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c index 8dee063c833f..a661ac32e829 100644 --- a/fs/f2fs/segment.c +++ b/fs/f2fs/segment.c | |||
@@ -546,9 +546,13 @@ void f2fs_balance_fs_bg(struct f2fs_sb_info *sbi) | |||
546 | if (test_opt(sbi, DATA_FLUSH)) { | 546 | if (test_opt(sbi, DATA_FLUSH)) { |
547 | struct blk_plug plug; | 547 | struct blk_plug plug; |
548 | 548 | ||
549 | mutex_lock(&sbi->flush_lock); | ||
550 | |||
549 | blk_start_plug(&plug); | 551 | blk_start_plug(&plug); |
550 | f2fs_sync_dirty_inodes(sbi, FILE_INODE); | 552 | f2fs_sync_dirty_inodes(sbi, FILE_INODE); |
551 | blk_finish_plug(&plug); | 553 | blk_finish_plug(&plug); |
554 | |||
555 | mutex_unlock(&sbi->flush_lock); | ||
552 | } | 556 | } |
553 | f2fs_sync_fs(sbi->sb, true); | 557 | f2fs_sync_fs(sbi->sb, true); |
554 | stat_inc_bg_cp_count(sbi->stat_info); | 558 | stat_inc_bg_cp_count(sbi->stat_info); |
@@ -869,11 +873,14 @@ void f2fs_dirty_to_prefree(struct f2fs_sb_info *sbi) | |||
869 | mutex_unlock(&dirty_i->seglist_lock); | 873 | mutex_unlock(&dirty_i->seglist_lock); |
870 | } | 874 | } |
871 | 875 | ||
872 | int f2fs_disable_cp_again(struct f2fs_sb_info *sbi) | 876 | block_t f2fs_get_unusable_blocks(struct f2fs_sb_info *sbi) |
873 | { | 877 | { |
878 | int ovp_hole_segs = | ||
879 | (overprovision_segments(sbi) - reserved_segments(sbi)); | ||
880 | block_t ovp_holes = ovp_hole_segs << sbi->log_blocks_per_seg; | ||
874 | struct dirty_seglist_info *dirty_i = DIRTY_I(sbi); | 881 | struct dirty_seglist_info *dirty_i = DIRTY_I(sbi); |
875 | block_t ovp = overprovision_segments(sbi) << sbi->log_blocks_per_seg; | ||
876 | block_t holes[2] = {0, 0}; /* DATA and NODE */ | 882 | block_t holes[2] = {0, 0}; /* DATA and NODE */ |
883 | block_t unusable; | ||
877 | struct seg_entry *se; | 884 | struct seg_entry *se; |
878 | unsigned int segno; | 885 | unsigned int segno; |
879 | 886 | ||
@@ -887,10 +894,20 @@ int f2fs_disable_cp_again(struct f2fs_sb_info *sbi) | |||
887 | } | 894 | } |
888 | mutex_unlock(&dirty_i->seglist_lock); | 895 | mutex_unlock(&dirty_i->seglist_lock); |
889 | 896 | ||
890 | if (holes[DATA] > ovp || holes[NODE] > ovp) | 897 | unusable = holes[DATA] > holes[NODE] ? holes[DATA] : holes[NODE]; |
898 | if (unusable > ovp_holes) | ||
899 | return unusable - ovp_holes; | ||
900 | return 0; | ||
901 | } | ||
902 | |||
903 | int f2fs_disable_cp_again(struct f2fs_sb_info *sbi, block_t unusable) | ||
904 | { | ||
905 | int ovp_hole_segs = | ||
906 | (overprovision_segments(sbi) - reserved_segments(sbi)); | ||
907 | if (unusable > F2FS_OPTION(sbi).unusable_cap) | ||
891 | return -EAGAIN; | 908 | return -EAGAIN; |
892 | if (is_sbi_flag_set(sbi, SBI_CP_DISABLED_QUICK) && | 909 | if (is_sbi_flag_set(sbi, SBI_CP_DISABLED_QUICK) && |
893 | dirty_segments(sbi) > overprovision_segments(sbi)) | 910 | dirty_segments(sbi) > ovp_hole_segs) |
894 | return -EAGAIN; | 911 | return -EAGAIN; |
895 | return 0; | 912 | return 0; |
896 | } | 913 | } |
@@ -1480,6 +1497,10 @@ static int __issue_discard_cmd(struct f2fs_sb_info *sbi, | |||
1480 | list_for_each_entry_safe(dc, tmp, pend_list, list) { | 1497 | list_for_each_entry_safe(dc, tmp, pend_list, list) { |
1481 | f2fs_bug_on(sbi, dc->state != D_PREP); | 1498 | f2fs_bug_on(sbi, dc->state != D_PREP); |
1482 | 1499 | ||
1500 | if (dpolicy->timeout != 0 && | ||
1501 | f2fs_time_over(sbi, dpolicy->timeout)) | ||
1502 | break; | ||
1503 | |||
1483 | if (dpolicy->io_aware && i < dpolicy->io_aware_gran && | 1504 | if (dpolicy->io_aware && i < dpolicy->io_aware_gran && |
1484 | !is_idle(sbi, DISCARD_TIME)) { | 1505 | !is_idle(sbi, DISCARD_TIME)) { |
1485 | io_interrupted = true; | 1506 | io_interrupted = true; |
@@ -1740,8 +1761,7 @@ static int __f2fs_issue_discard_zone(struct f2fs_sb_info *sbi, | |||
1740 | devi = f2fs_target_device_index(sbi, blkstart); | 1761 | devi = f2fs_target_device_index(sbi, blkstart); |
1741 | if (blkstart < FDEV(devi).start_blk || | 1762 | if (blkstart < FDEV(devi).start_blk || |
1742 | blkstart > FDEV(devi).end_blk) { | 1763 | blkstart > FDEV(devi).end_blk) { |
1743 | f2fs_msg(sbi->sb, KERN_ERR, "Invalid block %x", | 1764 | f2fs_err(sbi, "Invalid block %x", blkstart); |
1744 | blkstart); | ||
1745 | return -EIO; | 1765 | return -EIO; |
1746 | } | 1766 | } |
1747 | blkstart -= FDEV(devi).start_blk; | 1767 | blkstart -= FDEV(devi).start_blk; |
@@ -1754,10 +1774,9 @@ static int __f2fs_issue_discard_zone(struct f2fs_sb_info *sbi, | |||
1754 | 1774 | ||
1755 | if (sector & (bdev_zone_sectors(bdev) - 1) || | 1775 | if (sector & (bdev_zone_sectors(bdev) - 1) || |
1756 | nr_sects != bdev_zone_sectors(bdev)) { | 1776 | nr_sects != bdev_zone_sectors(bdev)) { |
1757 | f2fs_msg(sbi->sb, KERN_ERR, | 1777 | f2fs_err(sbi, "(%d) %s: Unaligned zone reset attempted (block %x + %x)", |
1758 | "(%d) %s: Unaligned zone reset attempted (block %x + %x)", | 1778 | devi, sbi->s_ndevs ? FDEV(devi).path : "", |
1759 | devi, sbi->s_ndevs ? FDEV(devi).path: "", | 1779 | blkstart, blklen); |
1760 | blkstart, blklen); | ||
1761 | return -EIO; | 1780 | return -EIO; |
1762 | } | 1781 | } |
1763 | trace_f2fs_issue_reset_zone(bdev, blkstart); | 1782 | trace_f2fs_issue_reset_zone(bdev, blkstart); |
@@ -2121,15 +2140,14 @@ static void update_sit_entry(struct f2fs_sb_info *sbi, block_t blkaddr, int del) | |||
2121 | mir_exist = f2fs_test_and_set_bit(offset, | 2140 | mir_exist = f2fs_test_and_set_bit(offset, |
2122 | se->cur_valid_map_mir); | 2141 | se->cur_valid_map_mir); |
2123 | if (unlikely(exist != mir_exist)) { | 2142 | if (unlikely(exist != mir_exist)) { |
2124 | f2fs_msg(sbi->sb, KERN_ERR, "Inconsistent error " | 2143 | f2fs_err(sbi, "Inconsistent error when setting bitmap, blk:%u, old bit:%d", |
2125 | "when setting bitmap, blk:%u, old bit:%d", | 2144 | blkaddr, exist); |
2126 | blkaddr, exist); | ||
2127 | f2fs_bug_on(sbi, 1); | 2145 | f2fs_bug_on(sbi, 1); |
2128 | } | 2146 | } |
2129 | #endif | 2147 | #endif |
2130 | if (unlikely(exist)) { | 2148 | if (unlikely(exist)) { |
2131 | f2fs_msg(sbi->sb, KERN_ERR, | 2149 | f2fs_err(sbi, "Bitmap was wrongly set, blk:%u", |
2132 | "Bitmap was wrongly set, blk:%u", blkaddr); | 2150 | blkaddr); |
2133 | f2fs_bug_on(sbi, 1); | 2151 | f2fs_bug_on(sbi, 1); |
2134 | se->valid_blocks--; | 2152 | se->valid_blocks--; |
2135 | del = 0; | 2153 | del = 0; |
@@ -2150,15 +2168,14 @@ static void update_sit_entry(struct f2fs_sb_info *sbi, block_t blkaddr, int del) | |||
2150 | mir_exist = f2fs_test_and_clear_bit(offset, | 2168 | mir_exist = f2fs_test_and_clear_bit(offset, |
2151 | se->cur_valid_map_mir); | 2169 | se->cur_valid_map_mir); |
2152 | if (unlikely(exist != mir_exist)) { | 2170 | if (unlikely(exist != mir_exist)) { |
2153 | f2fs_msg(sbi->sb, KERN_ERR, "Inconsistent error " | 2171 | f2fs_err(sbi, "Inconsistent error when clearing bitmap, blk:%u, old bit:%d", |
2154 | "when clearing bitmap, blk:%u, old bit:%d", | 2172 | blkaddr, exist); |
2155 | blkaddr, exist); | ||
2156 | f2fs_bug_on(sbi, 1); | 2173 | f2fs_bug_on(sbi, 1); |
2157 | } | 2174 | } |
2158 | #endif | 2175 | #endif |
2159 | if (unlikely(!exist)) { | 2176 | if (unlikely(!exist)) { |
2160 | f2fs_msg(sbi->sb, KERN_ERR, | 2177 | f2fs_err(sbi, "Bitmap was wrongly cleared, blk:%u", |
2161 | "Bitmap was wrongly cleared, blk:%u", blkaddr); | 2178 | blkaddr); |
2162 | f2fs_bug_on(sbi, 1); | 2179 | f2fs_bug_on(sbi, 1); |
2163 | se->valid_blocks++; | 2180 | se->valid_blocks++; |
2164 | del = 0; | 2181 | del = 0; |
@@ -2640,6 +2657,39 @@ static void allocate_segment_by_default(struct f2fs_sb_info *sbi, | |||
2640 | stat_inc_seg_type(sbi, curseg); | 2657 | stat_inc_seg_type(sbi, curseg); |
2641 | } | 2658 | } |
2642 | 2659 | ||
2660 | void allocate_segment_for_resize(struct f2fs_sb_info *sbi, int type, | ||
2661 | unsigned int start, unsigned int end) | ||
2662 | { | ||
2663 | struct curseg_info *curseg = CURSEG_I(sbi, type); | ||
2664 | unsigned int segno; | ||
2665 | |||
2666 | down_read(&SM_I(sbi)->curseg_lock); | ||
2667 | mutex_lock(&curseg->curseg_mutex); | ||
2668 | down_write(&SIT_I(sbi)->sentry_lock); | ||
2669 | |||
2670 | segno = CURSEG_I(sbi, type)->segno; | ||
2671 | if (segno < start || segno > end) | ||
2672 | goto unlock; | ||
2673 | |||
2674 | if (f2fs_need_SSR(sbi) && get_ssr_segment(sbi, type)) | ||
2675 | change_curseg(sbi, type); | ||
2676 | else | ||
2677 | new_curseg(sbi, type, true); | ||
2678 | |||
2679 | stat_inc_seg_type(sbi, curseg); | ||
2680 | |||
2681 | locate_dirty_segment(sbi, segno); | ||
2682 | unlock: | ||
2683 | up_write(&SIT_I(sbi)->sentry_lock); | ||
2684 | |||
2685 | if (segno != curseg->segno) | ||
2686 | f2fs_notice(sbi, "For resize: curseg of type %d: %u ==> %u", | ||
2687 | type, segno, curseg->segno); | ||
2688 | |||
2689 | mutex_unlock(&curseg->curseg_mutex); | ||
2690 | up_read(&SM_I(sbi)->curseg_lock); | ||
2691 | } | ||
2692 | |||
2643 | void f2fs_allocate_new_segments(struct f2fs_sb_info *sbi) | 2693 | void f2fs_allocate_new_segments(struct f2fs_sb_info *sbi) |
2644 | { | 2694 | { |
2645 | struct curseg_info *curseg; | 2695 | struct curseg_info *curseg; |
@@ -2772,9 +2822,8 @@ int f2fs_trim_fs(struct f2fs_sb_info *sbi, struct fstrim_range *range) | |||
2772 | goto out; | 2822 | goto out; |
2773 | 2823 | ||
2774 | if (is_sbi_flag_set(sbi, SBI_NEED_FSCK)) { | 2824 | if (is_sbi_flag_set(sbi, SBI_NEED_FSCK)) { |
2775 | f2fs_msg(sbi->sb, KERN_WARNING, | 2825 | f2fs_warn(sbi, "Found FS corruption, run fsck to fix."); |
2776 | "Found FS corruption, run fsck to fix."); | 2826 | return -EFSCORRUPTED; |
2777 | return -EIO; | ||
2778 | } | 2827 | } |
2779 | 2828 | ||
2780 | /* start/end segment number in main_area */ | 2829 | /* start/end segment number in main_area */ |
@@ -3197,12 +3246,17 @@ int f2fs_inplace_write_data(struct f2fs_io_info *fio) | |||
3197 | 3246 | ||
3198 | if (!IS_DATASEG(get_seg_entry(sbi, segno)->type)) { | 3247 | if (!IS_DATASEG(get_seg_entry(sbi, segno)->type)) { |
3199 | set_sbi_flag(sbi, SBI_NEED_FSCK); | 3248 | set_sbi_flag(sbi, SBI_NEED_FSCK); |
3200 | return -EFAULT; | 3249 | f2fs_warn(sbi, "%s: incorrect segment(%u) type, run fsck to fix.", |
3250 | __func__, segno); | ||
3251 | return -EFSCORRUPTED; | ||
3201 | } | 3252 | } |
3202 | 3253 | ||
3203 | stat_inc_inplace_blocks(fio->sbi); | 3254 | stat_inc_inplace_blocks(fio->sbi); |
3204 | 3255 | ||
3205 | err = f2fs_submit_page_bio(fio); | 3256 | if (fio->bio) |
3257 | err = f2fs_merge_page_bio(fio); | ||
3258 | else | ||
3259 | err = f2fs_submit_page_bio(fio); | ||
3206 | if (!err) { | 3260 | if (!err) { |
3207 | update_device_state(fio); | 3261 | update_device_state(fio); |
3208 | f2fs_update_iostat(fio->sbi, fio->io_type, F2FS_BLKSIZE); | 3262 | f2fs_update_iostat(fio->sbi, fio->io_type, F2FS_BLKSIZE); |
@@ -3393,6 +3447,11 @@ static int read_compacted_summaries(struct f2fs_sb_info *sbi) | |||
3393 | seg_i = CURSEG_I(sbi, i); | 3447 | seg_i = CURSEG_I(sbi, i); |
3394 | segno = le32_to_cpu(ckpt->cur_data_segno[i]); | 3448 | segno = le32_to_cpu(ckpt->cur_data_segno[i]); |
3395 | blk_off = le16_to_cpu(ckpt->cur_data_blkoff[i]); | 3449 | blk_off = le16_to_cpu(ckpt->cur_data_blkoff[i]); |
3450 | if (blk_off > ENTRIES_IN_SUM) { | ||
3451 | f2fs_bug_on(sbi, 1); | ||
3452 | f2fs_put_page(page, 1); | ||
3453 | return -EFAULT; | ||
3454 | } | ||
3396 | seg_i->next_segno = segno; | 3455 | seg_i->next_segno = segno; |
3397 | reset_curseg(sbi, i, 0); | 3456 | reset_curseg(sbi, i, 0); |
3398 | seg_i->alloc_type = ckpt->alloc_type[i]; | 3457 | seg_i->alloc_type = ckpt->alloc_type[i]; |
@@ -3530,8 +3589,11 @@ static int restore_curseg_summaries(struct f2fs_sb_info *sbi) | |||
3530 | 3589 | ||
3531 | /* sanity check for summary blocks */ | 3590 | /* sanity check for summary blocks */ |
3532 | if (nats_in_cursum(nat_j) > NAT_JOURNAL_ENTRIES || | 3591 | if (nats_in_cursum(nat_j) > NAT_JOURNAL_ENTRIES || |
3533 | sits_in_cursum(sit_j) > SIT_JOURNAL_ENTRIES) | 3592 | sits_in_cursum(sit_j) > SIT_JOURNAL_ENTRIES) { |
3593 | f2fs_err(sbi, "invalid journal entries nats %u sits %u\n", | ||
3594 | nats_in_cursum(nat_j), sits_in_cursum(sit_j)); | ||
3534 | return -EINVAL; | 3595 | return -EINVAL; |
3596 | } | ||
3535 | 3597 | ||
3536 | return 0; | 3598 | return 0; |
3537 | } | 3599 | } |
@@ -3762,7 +3824,7 @@ void f2fs_flush_sit_entries(struct f2fs_sb_info *sbi, struct cp_control *cpc) | |||
3762 | struct f2fs_journal *journal = curseg->journal; | 3824 | struct f2fs_journal *journal = curseg->journal; |
3763 | struct sit_entry_set *ses, *tmp; | 3825 | struct sit_entry_set *ses, *tmp; |
3764 | struct list_head *head = &SM_I(sbi)->sit_entry_set; | 3826 | struct list_head *head = &SM_I(sbi)->sit_entry_set; |
3765 | bool to_journal = true; | 3827 | bool to_journal = !is_sbi_flag_set(sbi, SBI_IS_RESIZEFS); |
3766 | struct seg_entry *se; | 3828 | struct seg_entry *se; |
3767 | 3829 | ||
3768 | down_write(&sit_i->sentry_lock); | 3830 | down_write(&sit_i->sentry_lock); |
@@ -3781,7 +3843,8 @@ void f2fs_flush_sit_entries(struct f2fs_sb_info *sbi, struct cp_control *cpc) | |||
3781 | * entries, remove all entries from journal and add and account | 3843 | * entries, remove all entries from journal and add and account |
3782 | * them in sit entry set. | 3844 | * them in sit entry set. |
3783 | */ | 3845 | */ |
3784 | if (!__has_cursum_space(journal, sit_i->dirty_sentries, SIT_JOURNAL)) | 3846 | if (!__has_cursum_space(journal, sit_i->dirty_sentries, SIT_JOURNAL) || |
3847 | !to_journal) | ||
3785 | remove_sits_in_journal(sbi); | 3848 | remove_sits_in_journal(sbi); |
3786 | 3849 | ||
3787 | /* | 3850 | /* |
@@ -4096,11 +4159,10 @@ static int build_sit_entries(struct f2fs_sb_info *sbi) | |||
4096 | 4159 | ||
4097 | start = le32_to_cpu(segno_in_journal(journal, i)); | 4160 | start = le32_to_cpu(segno_in_journal(journal, i)); |
4098 | if (start >= MAIN_SEGS(sbi)) { | 4161 | if (start >= MAIN_SEGS(sbi)) { |
4099 | f2fs_msg(sbi->sb, KERN_ERR, | 4162 | f2fs_err(sbi, "Wrong journal entry on segno %u", |
4100 | "Wrong journal entry on segno %u", | 4163 | start); |
4101 | start); | ||
4102 | set_sbi_flag(sbi, SBI_NEED_FSCK); | 4164 | set_sbi_flag(sbi, SBI_NEED_FSCK); |
4103 | err = -EINVAL; | 4165 | err = -EFSCORRUPTED; |
4104 | break; | 4166 | break; |
4105 | } | 4167 | } |
4106 | 4168 | ||
@@ -4137,11 +4199,10 @@ static int build_sit_entries(struct f2fs_sb_info *sbi) | |||
4137 | up_read(&curseg->journal_rwsem); | 4199 | up_read(&curseg->journal_rwsem); |
4138 | 4200 | ||
4139 | if (!err && total_node_blocks != valid_node_count(sbi)) { | 4201 | if (!err && total_node_blocks != valid_node_count(sbi)) { |
4140 | f2fs_msg(sbi->sb, KERN_ERR, | 4202 | f2fs_err(sbi, "SIT is corrupted node# %u vs %u", |
4141 | "SIT is corrupted node# %u vs %u", | 4203 | total_node_blocks, valid_node_count(sbi)); |
4142 | total_node_blocks, valid_node_count(sbi)); | ||
4143 | set_sbi_flag(sbi, SBI_NEED_FSCK); | 4204 | set_sbi_flag(sbi, SBI_NEED_FSCK); |
4144 | err = -EINVAL; | 4205 | err = -EFSCORRUPTED; |
4145 | } | 4206 | } |
4146 | 4207 | ||
4147 | return err; | 4208 | return err; |
@@ -4232,6 +4293,39 @@ static int build_dirty_segmap(struct f2fs_sb_info *sbi) | |||
4232 | return init_victim_secmap(sbi); | 4293 | return init_victim_secmap(sbi); |
4233 | } | 4294 | } |
4234 | 4295 | ||
4296 | static int sanity_check_curseg(struct f2fs_sb_info *sbi) | ||
4297 | { | ||
4298 | int i; | ||
4299 | |||
4300 | /* | ||
4301 | * In LFS/SSR curseg, .next_blkoff should point to an unused blkaddr; | ||
4302 | * In LFS curseg, all blkaddr after .next_blkoff should be unused. | ||
4303 | */ | ||
4304 | for (i = 0; i < NO_CHECK_TYPE; i++) { | ||
4305 | struct curseg_info *curseg = CURSEG_I(sbi, i); | ||
4306 | struct seg_entry *se = get_seg_entry(sbi, curseg->segno); | ||
4307 | unsigned int blkofs = curseg->next_blkoff; | ||
4308 | |||
4309 | if (f2fs_test_bit(blkofs, se->cur_valid_map)) | ||
4310 | goto out; | ||
4311 | |||
4312 | if (curseg->alloc_type == SSR) | ||
4313 | continue; | ||
4314 | |||
4315 | for (blkofs += 1; blkofs < sbi->blocks_per_seg; blkofs++) { | ||
4316 | if (!f2fs_test_bit(blkofs, se->cur_valid_map)) | ||
4317 | continue; | ||
4318 | out: | ||
4319 | f2fs_err(sbi, | ||
4320 | "Current segment's next free block offset is inconsistent with bitmap, logtype:%u, segno:%u, type:%u, next_blkoff:%u, blkofs:%u", | ||
4321 | i, curseg->segno, curseg->alloc_type, | ||
4322 | curseg->next_blkoff, blkofs); | ||
4323 | return -EFSCORRUPTED; | ||
4324 | } | ||
4325 | } | ||
4326 | return 0; | ||
4327 | } | ||
4328 | |||
4235 | /* | 4329 | /* |
4236 | * Update min, max modified time for cost-benefit GC algorithm | 4330 | * Update min, max modified time for cost-benefit GC algorithm |
4237 | */ | 4331 | */ |
@@ -4327,6 +4421,10 @@ int f2fs_build_segment_manager(struct f2fs_sb_info *sbi) | |||
4327 | if (err) | 4421 | if (err) |
4328 | return err; | 4422 | return err; |
4329 | 4423 | ||
4424 | err = sanity_check_curseg(sbi); | ||
4425 | if (err) | ||
4426 | return err; | ||
4427 | |||
4330 | init_min_max_mtime(sbi); | 4428 | init_min_max_mtime(sbi); |
4331 | return 0; | 4429 | return 0; |
4332 | } | 4430 | } |