]> asedeno.scripts.mit.edu Git - linux.git/blobdiff - fs/f2fs/segment.c
Merge tag 'mips_5.4' of git://git.kernel.org/pub/scm/linux/kernel/git/mips/linux
[linux.git] / fs / f2fs / segment.c
index 8dee063c833fa8fb2c6fedc91859c7600226fe8c..8087095814819d21dc2fa056b5a776dc2527699e 100644 (file)
@@ -185,8 +185,6 @@ bool f2fs_need_SSR(struct f2fs_sb_info *sbi)
 
 void f2fs_register_inmem_page(struct inode *inode, struct page *page)
 {
-       struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
-       struct f2fs_inode_info *fi = F2FS_I(inode);
        struct inmem_pages *new;
 
        f2fs_trace_pid(page);
@@ -200,15 +198,11 @@ void f2fs_register_inmem_page(struct inode *inode, struct page *page)
        INIT_LIST_HEAD(&new->list);
 
        /* increase reference count with clean state */
-       mutex_lock(&fi->inmem_lock);
        get_page(page);
-       list_add_tail(&new->list, &fi->inmem_pages);
-       spin_lock(&sbi->inode_lock[ATOMIC_FILE]);
-       if (list_empty(&fi->inmem_ilist))
-               list_add_tail(&fi->inmem_ilist, &sbi->inode_list[ATOMIC_FILE]);
-       spin_unlock(&sbi->inode_lock[ATOMIC_FILE]);
+       mutex_lock(&F2FS_I(inode)->inmem_lock);
+       list_add_tail(&new->list, &F2FS_I(inode)->inmem_pages);
        inc_page_count(F2FS_I_SB(inode), F2FS_INMEM_PAGES);
-       mutex_unlock(&fi->inmem_lock);
+       mutex_unlock(&F2FS_I(inode)->inmem_lock);
 
        trace_f2fs_register_inmem_page(page, INMEM);
 }
@@ -330,19 +324,17 @@ void f2fs_drop_inmem_pages(struct inode *inode)
                mutex_lock(&fi->inmem_lock);
                __revoke_inmem_pages(inode, &fi->inmem_pages,
                                                true, false, true);
-
-               if (list_empty(&fi->inmem_pages)) {
-                       spin_lock(&sbi->inode_lock[ATOMIC_FILE]);
-                       if (!list_empty(&fi->inmem_ilist))
-                               list_del_init(&fi->inmem_ilist);
-                       spin_unlock(&sbi->inode_lock[ATOMIC_FILE]);
-               }
                mutex_unlock(&fi->inmem_lock);
        }
 
        clear_inode_flag(inode, FI_ATOMIC_FILE);
        fi->i_gc_failures[GC_FAILURE_ATOMIC] = 0;
        stat_dec_atomic_write(inode);
+
+       spin_lock(&sbi->inode_lock[ATOMIC_FILE]);
+       if (!list_empty(&fi->inmem_ilist))
+               list_del_init(&fi->inmem_ilist);
+       spin_unlock(&sbi->inode_lock[ATOMIC_FILE]);
 }
 
 void f2fs_drop_inmem_page(struct inode *inode, struct page *page)
@@ -471,11 +463,6 @@ int f2fs_commit_inmem_pages(struct inode *inode)
 
        mutex_lock(&fi->inmem_lock);
        err = __f2fs_commit_inmem_pages(inode);
-
-       spin_lock(&sbi->inode_lock[ATOMIC_FILE]);
-       if (!list_empty(&fi->inmem_ilist))
-               list_del_init(&fi->inmem_ilist);
-       spin_unlock(&sbi->inode_lock[ATOMIC_FILE]);
        mutex_unlock(&fi->inmem_lock);
 
        clear_inode_flag(inode, FI_ATOMIC_COMMIT);
@@ -501,7 +488,7 @@ void f2fs_balance_fs(struct f2fs_sb_info *sbi, bool need)
        if (need && excess_cached_nats(sbi))
                f2fs_balance_fs_bg(sbi);
 
-       if (f2fs_is_checkpoint_ready(sbi))
+       if (!f2fs_is_checkpoint_ready(sbi))
                return;
 
        /*
@@ -546,9 +533,13 @@ void f2fs_balance_fs_bg(struct f2fs_sb_info *sbi)
                if (test_opt(sbi, DATA_FLUSH)) {
                        struct blk_plug plug;
 
+                       mutex_lock(&sbi->flush_lock);
+
                        blk_start_plug(&plug);
                        f2fs_sync_dirty_inodes(sbi, FILE_INODE);
                        blk_finish_plug(&plug);
+
+                       mutex_unlock(&sbi->flush_lock);
                }
                f2fs_sync_fs(sbi->sb, true);
                stat_inc_bg_cp_count(sbi->stat_info);
@@ -813,9 +804,13 @@ static void __remove_dirty_segment(struct f2fs_sb_info *sbi, unsigned int segno,
                if (test_and_clear_bit(segno, dirty_i->dirty_segmap[t]))
                        dirty_i->nr_dirty[t]--;
 
-               if (get_valid_blocks(sbi, segno, true) == 0)
+               if (get_valid_blocks(sbi, segno, true) == 0) {
                        clear_bit(GET_SEC_FROM_SEG(sbi, segno),
                                                dirty_i->victim_secmap);
+#ifdef CONFIG_F2FS_CHECK_FS
+                       clear_bit(segno, SIT_I(sbi)->invalid_segmap);
+#endif
+               }
        }
 }
 
@@ -869,11 +864,14 @@ void f2fs_dirty_to_prefree(struct f2fs_sb_info *sbi)
        mutex_unlock(&dirty_i->seglist_lock);
 }
 
-int f2fs_disable_cp_again(struct f2fs_sb_info *sbi)
+block_t f2fs_get_unusable_blocks(struct f2fs_sb_info *sbi)
 {
+       int ovp_hole_segs =
+               (overprovision_segments(sbi) - reserved_segments(sbi));
+       block_t ovp_holes = ovp_hole_segs << sbi->log_blocks_per_seg;
        struct dirty_seglist_info *dirty_i = DIRTY_I(sbi);
-       block_t ovp = overprovision_segments(sbi) << sbi->log_blocks_per_seg;
        block_t holes[2] = {0, 0};      /* DATA and NODE */
+       block_t unusable;
        struct seg_entry *se;
        unsigned int segno;
 
@@ -887,10 +885,20 @@ int f2fs_disable_cp_again(struct f2fs_sb_info *sbi)
        }
        mutex_unlock(&dirty_i->seglist_lock);
 
-       if (holes[DATA] > ovp || holes[NODE] > ovp)
+       unusable = holes[DATA] > holes[NODE] ? holes[DATA] : holes[NODE];
+       if (unusable > ovp_holes)
+               return unusable - ovp_holes;
+       return 0;
+}
+
+int f2fs_disable_cp_again(struct f2fs_sb_info *sbi, block_t unusable)
+{
+       int ovp_hole_segs =
+               (overprovision_segments(sbi) - reserved_segments(sbi));
+       if (unusable > F2FS_OPTION(sbi).unusable_cap)
                return -EAGAIN;
        if (is_sbi_flag_set(sbi, SBI_CP_DISABLED_QUICK) &&
-               dirty_segments(sbi) > overprovision_segments(sbi))
+               dirty_segments(sbi) > ovp_hole_segs)
                return -EAGAIN;
        return 0;
 }
@@ -1480,6 +1488,10 @@ static int __issue_discard_cmd(struct f2fs_sb_info *sbi,
                list_for_each_entry_safe(dc, tmp, pend_list, list) {
                        f2fs_bug_on(sbi, dc->state != D_PREP);
 
+                       if (dpolicy->timeout != 0 &&
+                               f2fs_time_over(sbi, dpolicy->timeout))
+                               break;
+
                        if (dpolicy->io_aware && i < dpolicy->io_aware_gran &&
                                                !is_idle(sbi, DISCARD_TIME)) {
                                io_interrupted = true;
@@ -1740,8 +1752,7 @@ static int __f2fs_issue_discard_zone(struct f2fs_sb_info *sbi,
                devi = f2fs_target_device_index(sbi, blkstart);
                if (blkstart < FDEV(devi).start_blk ||
                    blkstart > FDEV(devi).end_blk) {
-                       f2fs_msg(sbi->sb, KERN_ERR, "Invalid block %x",
-                                blkstart);
+                       f2fs_err(sbi, "Invalid block %x", blkstart);
                        return -EIO;
                }
                blkstart -= FDEV(devi).start_blk;
@@ -1754,10 +1765,9 @@ static int __f2fs_issue_discard_zone(struct f2fs_sb_info *sbi,
 
                if (sector & (bdev_zone_sectors(bdev) - 1) ||
                                nr_sects != bdev_zone_sectors(bdev)) {
-                       f2fs_msg(sbi->sb, KERN_ERR,
-                               "(%d) %s: Unaligned zone reset attempted (block %x + %x)",
-                               devi, sbi->s_ndevs ? FDEV(devi).path: "",
-                               blkstart, blklen);
+                       f2fs_err(sbi, "(%d) %s: Unaligned zone reset attempted (block %x + %x)",
+                                devi, sbi->s_ndevs ? FDEV(devi).path : "",
+                                blkstart, blklen);
                        return -EIO;
                }
                trace_f2fs_issue_reset_zone(bdev, blkstart);
@@ -2065,6 +2075,13 @@ static void destroy_discard_cmd_control(struct f2fs_sb_info *sbi)
 
        f2fs_stop_discard_thread(sbi);
 
+       /*
+        * Recovery can cache discard commands, so in error path of
+        * fill_super(), it needs to give a chance to handle them.
+        */
+       if (unlikely(atomic_read(&dcc->discard_cmd_cnt)))
+               f2fs_issue_discard_timeout(sbi);
+
        kvfree(dcc);
        SM_I(sbi)->dcc_info = NULL;
 }
@@ -2121,15 +2138,14 @@ static void update_sit_entry(struct f2fs_sb_info *sbi, block_t blkaddr, int del)
                mir_exist = f2fs_test_and_set_bit(offset,
                                                se->cur_valid_map_mir);
                if (unlikely(exist != mir_exist)) {
-                       f2fs_msg(sbi->sb, KERN_ERR, "Inconsistent error "
-                               "when setting bitmap, blk:%u, old bit:%d",
-                               blkaddr, exist);
+                       f2fs_err(sbi, "Inconsistent error when setting bitmap, blk:%u, old bit:%d",
+                                blkaddr, exist);
                        f2fs_bug_on(sbi, 1);
                }
 #endif
                if (unlikely(exist)) {
-                       f2fs_msg(sbi->sb, KERN_ERR,
-                               "Bitmap was wrongly set, blk:%u", blkaddr);
+                       f2fs_err(sbi, "Bitmap was wrongly set, blk:%u",
+                                blkaddr);
                        f2fs_bug_on(sbi, 1);
                        se->valid_blocks--;
                        del = 0;
@@ -2138,9 +2154,11 @@ static void update_sit_entry(struct f2fs_sb_info *sbi, block_t blkaddr, int del)
                if (!f2fs_test_and_set_bit(offset, se->discard_map))
                        sbi->discard_blks--;
 
-               /* don't overwrite by SSR to keep node chain */
-               if (IS_NODESEG(se->type) &&
-                               !is_sbi_flag_set(sbi, SBI_CP_DISABLED)) {
+               /*
+                * SSR should never reuse block which is checkpointed
+                * or newly invalidated.
+                */
+               if (!is_sbi_flag_set(sbi, SBI_CP_DISABLED)) {
                        if (!f2fs_test_and_set_bit(offset, se->ckpt_valid_map))
                                se->ckpt_valid_blocks++;
                }
@@ -2150,15 +2168,14 @@ static void update_sit_entry(struct f2fs_sb_info *sbi, block_t blkaddr, int del)
                mir_exist = f2fs_test_and_clear_bit(offset,
                                                se->cur_valid_map_mir);
                if (unlikely(exist != mir_exist)) {
-                       f2fs_msg(sbi->sb, KERN_ERR, "Inconsistent error "
-                               "when clearing bitmap, blk:%u, old bit:%d",
-                               blkaddr, exist);
+                       f2fs_err(sbi, "Inconsistent error when clearing bitmap, blk:%u, old bit:%d",
+                                blkaddr, exist);
                        f2fs_bug_on(sbi, 1);
                }
 #endif
                if (unlikely(!exist)) {
-                       f2fs_msg(sbi->sb, KERN_ERR,
-                               "Bitmap was wrongly cleared, blk:%u", blkaddr);
+                       f2fs_err(sbi, "Bitmap was wrongly cleared, blk:%u",
+                                blkaddr);
                        f2fs_bug_on(sbi, 1);
                        se->valid_blocks++;
                        del = 0;
@@ -2640,6 +2657,39 @@ static void allocate_segment_by_default(struct f2fs_sb_info *sbi,
        stat_inc_seg_type(sbi, curseg);
 }
 
+void allocate_segment_for_resize(struct f2fs_sb_info *sbi, int type,
+                                       unsigned int start, unsigned int end)
+{
+       struct curseg_info *curseg = CURSEG_I(sbi, type);
+       unsigned int segno;
+
+       down_read(&SM_I(sbi)->curseg_lock);
+       mutex_lock(&curseg->curseg_mutex);
+       down_write(&SIT_I(sbi)->sentry_lock);
+
+       segno = CURSEG_I(sbi, type)->segno;
+       if (segno < start || segno > end)
+               goto unlock;
+
+       if (f2fs_need_SSR(sbi) && get_ssr_segment(sbi, type))
+               change_curseg(sbi, type);
+       else
+               new_curseg(sbi, type, true);
+
+       stat_inc_seg_type(sbi, curseg);
+
+       locate_dirty_segment(sbi, segno);
+unlock:
+       up_write(&SIT_I(sbi)->sentry_lock);
+
+       if (segno != curseg->segno)
+               f2fs_notice(sbi, "For resize: curseg of type %d: %u ==> %u",
+                           type, segno, curseg->segno);
+
+       mutex_unlock(&curseg->curseg_mutex);
+       up_read(&SM_I(sbi)->curseg_lock);
+}
+
 void f2fs_allocate_new_segments(struct f2fs_sb_info *sbi)
 {
        struct curseg_info *curseg;
@@ -2772,9 +2822,8 @@ int f2fs_trim_fs(struct f2fs_sb_info *sbi, struct fstrim_range *range)
                goto out;
 
        if (is_sbi_flag_set(sbi, SBI_NEED_FSCK)) {
-               f2fs_msg(sbi->sb, KERN_WARNING,
-                       "Found FS corruption, run fsck to fix.");
-               return -EIO;
+               f2fs_warn(sbi, "Found FS corruption, run fsck to fix.");
+               return -EFSCORRUPTED;
        }
 
        /* start/end segment number in main_area */
@@ -3067,12 +3116,14 @@ void f2fs_allocate_data_block(struct f2fs_sb_info *sbi, struct page *page,
                f2fs_inode_chksum_set(sbi, page);
        }
 
+       if (F2FS_IO_ALIGNED(sbi))
+               fio->retry = false;
+
        if (add_list) {
                struct f2fs_bio_info *io;
 
                INIT_LIST_HEAD(&fio->list);
                fio->in_list = true;
-               fio->retry = false;
                io = sbi->write_io[fio->type] + fio->temp;
                spin_lock(&io->io_lock);
                list_add_tail(&fio->list, &io->io_list);
@@ -3197,12 +3248,17 @@ int f2fs_inplace_write_data(struct f2fs_io_info *fio)
 
        if (!IS_DATASEG(get_seg_entry(sbi, segno)->type)) {
                set_sbi_flag(sbi, SBI_NEED_FSCK);
-               return -EFAULT;
+               f2fs_warn(sbi, "%s: incorrect segment(%u) type, run fsck to fix.",
+                         __func__, segno);
+               return -EFSCORRUPTED;
        }
 
        stat_inc_inplace_blocks(fio->sbi);
 
-       err = f2fs_submit_page_bio(fio);
+       if (fio->bio)
+               err = f2fs_merge_page_bio(fio);
+       else
+               err = f2fs_submit_page_bio(fio);
        if (!err) {
                update_device_state(fio);
                f2fs_update_iostat(fio->sbi, fio->io_type, F2FS_BLKSIZE);
@@ -3530,8 +3586,11 @@ static int restore_curseg_summaries(struct f2fs_sb_info *sbi)
 
        /* sanity check for summary blocks */
        if (nats_in_cursum(nat_j) > NAT_JOURNAL_ENTRIES ||
-                       sits_in_cursum(sit_j) > SIT_JOURNAL_ENTRIES)
+                       sits_in_cursum(sit_j) > SIT_JOURNAL_ENTRIES) {
+               f2fs_err(sbi, "invalid journal entries nats %u sits %u\n",
+                        nats_in_cursum(nat_j), sits_in_cursum(sit_j));
                return -EINVAL;
+       }
 
        return 0;
 }
@@ -3762,7 +3821,7 @@ void f2fs_flush_sit_entries(struct f2fs_sb_info *sbi, struct cp_control *cpc)
        struct f2fs_journal *journal = curseg->journal;
        struct sit_entry_set *ses, *tmp;
        struct list_head *head = &SM_I(sbi)->sit_entry_set;
-       bool to_journal = true;
+       bool to_journal = !is_sbi_flag_set(sbi, SBI_IS_RESIZEFS);
        struct seg_entry *se;
 
        down_write(&sit_i->sentry_lock);
@@ -3781,7 +3840,8 @@ void f2fs_flush_sit_entries(struct f2fs_sb_info *sbi, struct cp_control *cpc)
         * entries, remove all entries from journal and add and account
         * them in sit entry set.
         */
-       if (!__has_cursum_space(journal, sit_i->dirty_sentries, SIT_JOURNAL))
+       if (!__has_cursum_space(journal, sit_i->dirty_sentries, SIT_JOURNAL) ||
+                                                               !to_journal)
                remove_sits_in_journal(sbi);
 
        /*
@@ -3878,8 +3938,8 @@ static int build_sit_info(struct f2fs_sb_info *sbi)
        struct f2fs_super_block *raw_super = F2FS_RAW_SUPER(sbi);
        struct sit_info *sit_i;
        unsigned int sit_segs, start;
-       char *src_bitmap;
-       unsigned int bitmap_size;
+       char *src_bitmap, *bitmap;
+       unsigned int bitmap_size, main_bitmap_size, sit_bitmap_size;
 
        /* allocate memory for SIT information */
        sit_i = f2fs_kzalloc(sbi, sizeof(struct sit_info), GFP_KERNEL);
@@ -3895,33 +3955,37 @@ static int build_sit_info(struct f2fs_sb_info *sbi)
        if (!sit_i->sentries)
                return -ENOMEM;
 
-       bitmap_size = f2fs_bitmap_size(MAIN_SEGS(sbi));
-       sit_i->dirty_sentries_bitmap = f2fs_kvzalloc(sbi, bitmap_size,
+       main_bitmap_size = f2fs_bitmap_size(MAIN_SEGS(sbi));
+       sit_i->dirty_sentries_bitmap = f2fs_kvzalloc(sbi, main_bitmap_size,
                                                                GFP_KERNEL);
        if (!sit_i->dirty_sentries_bitmap)
                return -ENOMEM;
 
+#ifdef CONFIG_F2FS_CHECK_FS
+       bitmap_size = MAIN_SEGS(sbi) * SIT_VBLOCK_MAP_SIZE * 4;
+#else
+       bitmap_size = MAIN_SEGS(sbi) * SIT_VBLOCK_MAP_SIZE * 3;
+#endif
+       sit_i->bitmap = f2fs_kvzalloc(sbi, bitmap_size, GFP_KERNEL);
+       if (!sit_i->bitmap)
+               return -ENOMEM;
+
+       bitmap = sit_i->bitmap;
+
        for (start = 0; start < MAIN_SEGS(sbi); start++) {
-               sit_i->sentries[start].cur_valid_map
-                       = f2fs_kzalloc(sbi, SIT_VBLOCK_MAP_SIZE, GFP_KERNEL);
-               sit_i->sentries[start].ckpt_valid_map
-                       = f2fs_kzalloc(sbi, SIT_VBLOCK_MAP_SIZE, GFP_KERNEL);
-               if (!sit_i->sentries[start].cur_valid_map ||
-                               !sit_i->sentries[start].ckpt_valid_map)
-                       return -ENOMEM;
+               sit_i->sentries[start].cur_valid_map = bitmap;
+               bitmap += SIT_VBLOCK_MAP_SIZE;
+
+               sit_i->sentries[start].ckpt_valid_map = bitmap;
+               bitmap += SIT_VBLOCK_MAP_SIZE;
 
 #ifdef CONFIG_F2FS_CHECK_FS
-               sit_i->sentries[start].cur_valid_map_mir
-                       = f2fs_kzalloc(sbi, SIT_VBLOCK_MAP_SIZE, GFP_KERNEL);
-               if (!sit_i->sentries[start].cur_valid_map_mir)
-                       return -ENOMEM;
+               sit_i->sentries[start].cur_valid_map_mir = bitmap;
+               bitmap += SIT_VBLOCK_MAP_SIZE;
 #endif
 
-               sit_i->sentries[start].discard_map
-                       = f2fs_kzalloc(sbi, SIT_VBLOCK_MAP_SIZE,
-                                                       GFP_KERNEL);
-               if (!sit_i->sentries[start].discard_map)
-                       return -ENOMEM;
+               sit_i->sentries[start].discard_map = bitmap;
+               bitmap += SIT_VBLOCK_MAP_SIZE;
        }
 
        sit_i->tmp_map = f2fs_kzalloc(sbi, SIT_VBLOCK_MAP_SIZE, GFP_KERNEL);
@@ -3941,17 +4005,23 @@ static int build_sit_info(struct f2fs_sb_info *sbi)
        sit_segs = le32_to_cpu(raw_super->segment_count_sit) >> 1;
 
        /* setup SIT bitmap from ckeckpoint pack */
-       bitmap_size = __bitmap_size(sbi, SIT_BITMAP);
+       sit_bitmap_size = __bitmap_size(sbi, SIT_BITMAP);
        src_bitmap = __bitmap_ptr(sbi, SIT_BITMAP);
 
-       sit_i->sit_bitmap = kmemdup(src_bitmap, bitmap_size, GFP_KERNEL);
+       sit_i->sit_bitmap = kmemdup(src_bitmap, sit_bitmap_size, GFP_KERNEL);
        if (!sit_i->sit_bitmap)
                return -ENOMEM;
 
 #ifdef CONFIG_F2FS_CHECK_FS
-       sit_i->sit_bitmap_mir = kmemdup(src_bitmap, bitmap_size, GFP_KERNEL);
+       sit_i->sit_bitmap_mir = kmemdup(src_bitmap,
+                                       sit_bitmap_size, GFP_KERNEL);
        if (!sit_i->sit_bitmap_mir)
                return -ENOMEM;
+
+       sit_i->invalid_segmap = f2fs_kvzalloc(sbi,
+                                       main_bitmap_size, GFP_KERNEL);
+       if (!sit_i->invalid_segmap)
+               return -ENOMEM;
 #endif
 
        /* init SIT information */
@@ -3960,7 +4030,7 @@ static int build_sit_info(struct f2fs_sb_info *sbi)
        sit_i->sit_base_addr = le32_to_cpu(raw_super->sit_blkaddr);
        sit_i->sit_blocks = sit_segs << sbi->log_blocks_per_seg;
        sit_i->written_valid_blocks = 0;
-       sit_i->bitmap_size = bitmap_size;
+       sit_i->bitmap_size = sit_bitmap_size;
        sit_i->dirty_sentries = 0;
        sit_i->sents_per_block = SIT_ENTRY_PER_BLOCK;
        sit_i->elapsed_time = le64_to_cpu(sbi->ckpt->elapsed_time);
@@ -4096,11 +4166,9 @@ static int build_sit_entries(struct f2fs_sb_info *sbi)
 
                start = le32_to_cpu(segno_in_journal(journal, i));
                if (start >= MAIN_SEGS(sbi)) {
-                       f2fs_msg(sbi->sb, KERN_ERR,
-                                       "Wrong journal entry on segno %u",
-                                       start);
-                       set_sbi_flag(sbi, SBI_NEED_FSCK);
-                       err = -EINVAL;
+                       f2fs_err(sbi, "Wrong journal entry on segno %u",
+                                start);
+                       err = -EFSCORRUPTED;
                        break;
                }
 
@@ -4137,11 +4205,9 @@ static int build_sit_entries(struct f2fs_sb_info *sbi)
        up_read(&curseg->journal_rwsem);
 
        if (!err && total_node_blocks != valid_node_count(sbi)) {
-               f2fs_msg(sbi->sb, KERN_ERR,
-                       "SIT is corrupted node# %u vs %u",
-                       total_node_blocks, valid_node_count(sbi));
-               set_sbi_flag(sbi, SBI_NEED_FSCK);
-               err = -EINVAL;
+               f2fs_err(sbi, "SIT is corrupted node# %u vs %u",
+                        total_node_blocks, valid_node_count(sbi));
+               err = -EFSCORRUPTED;
        }
 
        return err;
@@ -4232,6 +4298,39 @@ static int build_dirty_segmap(struct f2fs_sb_info *sbi)
        return init_victim_secmap(sbi);
 }
 
+static int sanity_check_curseg(struct f2fs_sb_info *sbi)
+{
+       int i;
+
+       /*
+        * In LFS/SSR curseg, .next_blkoff should point to an unused blkaddr;
+        * In LFS curseg, all blkaddr after .next_blkoff should be unused.
+        */
+       for (i = 0; i < NO_CHECK_TYPE; i++) {
+               struct curseg_info *curseg = CURSEG_I(sbi, i);
+               struct seg_entry *se = get_seg_entry(sbi, curseg->segno);
+               unsigned int blkofs = curseg->next_blkoff;
+
+               if (f2fs_test_bit(blkofs, se->cur_valid_map))
+                       goto out;
+
+               if (curseg->alloc_type == SSR)
+                       continue;
+
+               for (blkofs += 1; blkofs < sbi->blocks_per_seg; blkofs++) {
+                       if (!f2fs_test_bit(blkofs, se->cur_valid_map))
+                               continue;
+out:
+                       f2fs_err(sbi,
+                                "Current segment's next free block offset is inconsistent with bitmap, logtype:%u, segno:%u, type:%u, next_blkoff:%u, blkofs:%u",
+                                i, curseg->segno, curseg->alloc_type,
+                                curseg->next_blkoff, blkofs);
+                       return -EFSCORRUPTED;
+               }
+       }
+       return 0;
+}
+
 /*
  * Update min, max modified time for cost-benefit GC algorithm
  */
@@ -4327,6 +4426,10 @@ int f2fs_build_segment_manager(struct f2fs_sb_info *sbi)
        if (err)
                return err;
 
+       err = sanity_check_curseg(sbi);
+       if (err)
+               return err;
+
        init_min_max_mtime(sbi);
        return 0;
 }
@@ -4394,21 +4497,12 @@ static void destroy_free_segmap(struct f2fs_sb_info *sbi)
 static void destroy_sit_info(struct f2fs_sb_info *sbi)
 {
        struct sit_info *sit_i = SIT_I(sbi);
-       unsigned int start;
 
        if (!sit_i)
                return;
 
-       if (sit_i->sentries) {
-               for (start = 0; start < MAIN_SEGS(sbi); start++) {
-                       kvfree(sit_i->sentries[start].cur_valid_map);
-#ifdef CONFIG_F2FS_CHECK_FS
-                       kvfree(sit_i->sentries[start].cur_valid_map_mir);
-#endif
-                       kvfree(sit_i->sentries[start].ckpt_valid_map);
-                       kvfree(sit_i->sentries[start].discard_map);
-               }
-       }
+       if (sit_i->sentries)
+               kvfree(sit_i->bitmap);
        kvfree(sit_i->tmp_map);
 
        kvfree(sit_i->sentries);
@@ -4419,6 +4513,7 @@ static void destroy_sit_info(struct f2fs_sb_info *sbi)
        kvfree(sit_i->sit_bitmap);
 #ifdef CONFIG_F2FS_CHECK_FS
        kvfree(sit_i->sit_bitmap_mir);
+       kvfree(sit_i->invalid_segmap);
 #endif
        kvfree(sit_i);
 }