#define __reverse_ffz(x) __reverse_ffs(~(x))
 
 static struct kmem_cache *discard_entry_slab;
+static struct kmem_cache *sit_entry_set_slab;
 
 /*
  * __reverse_ffs is copied from include/asm-generic/bitops/__ffs.h since
        }
 }
 
-static void __mark_sit_entry_dirty(struct f2fs_sb_info *sbi, unsigned int segno)
+static bool __mark_sit_entry_dirty(struct f2fs_sb_info *sbi, unsigned int segno)
 {
        struct sit_info *sit_i = SIT_I(sbi);
-       if (!__test_and_set_bit(segno, sit_i->dirty_sentries_bitmap))
+
+       if (!__test_and_set_bit(segno, sit_i->dirty_sentries_bitmap)) {
                sit_i->dirty_sentries++;
+               return false;
+       }
+
+       return true;
 }
 
 static void __set_sit_entry_type(struct f2fs_sb_info *sbi, int type,
        return dst_page;
 }
 
-static bool flush_sits_in_journal(struct f2fs_sb_info *sbi)
+static struct sit_entry_set *grab_sit_entry_set(void)
+{
+       struct sit_entry_set *ses =
+                       f2fs_kmem_cache_alloc(sit_entry_set_slab, GFP_ATOMIC);
+
+       ses->entry_cnt = 0;
+       INIT_LIST_HEAD(&ses->set_list);
+       return ses;
+}
+
+static void release_sit_entry_set(struct sit_entry_set *ses)
+{
+       list_del(&ses->set_list);
+       kmem_cache_free(sit_entry_set_slab, ses);
+}
+
+static void adjust_sit_entry_set(struct sit_entry_set *ses,
+                                               struct list_head *head)
+{
+       struct sit_entry_set *next = ses;
+
+       if (list_is_last(&ses->set_list, head))
+               return;
+
+       list_for_each_entry_continue(next, head, set_list)
+               if (ses->entry_cnt <= next->entry_cnt)
+                       break;
+
+       list_move_tail(&ses->set_list, &next->set_list);
+}
+
+static void add_sit_entry(unsigned int segno, struct list_head *head)
+{
+       struct sit_entry_set *ses;
+       unsigned int start_segno = START_SEGNO(segno);
+
+       list_for_each_entry(ses, head, set_list) {
+               if (ses->start_segno == start_segno) {
+                       ses->entry_cnt++;
+                       adjust_sit_entry_set(ses, head);
+                       return;
+               }
+       }
+
+       ses = grab_sit_entry_set();
+
+       ses->start_segno = start_segno;
+       ses->entry_cnt++;
+       list_add(&ses->set_list, head);
+}
+
+static void add_sits_in_set(struct f2fs_sb_info *sbi)
+{
+       struct f2fs_sm_info *sm_info = SM_I(sbi);
+       struct list_head *set_list = &sm_info->sit_entry_set;
+       unsigned long *bitmap = SIT_I(sbi)->dirty_sentries_bitmap;
+       unsigned long nsegs = TOTAL_SEGS(sbi);
+       unsigned int segno;
+
+       for_each_set_bit(segno, bitmap, nsegs)
+               add_sit_entry(segno, set_list);
+}
+
+static void remove_sits_in_journal(struct f2fs_sb_info *sbi)
 {
        struct curseg_info *curseg = CURSEG_I(sbi, CURSEG_COLD_DATA);
        struct f2fs_summary_block *sum = curseg->sum_blk;
        int i;
 
-       /*
-        * If the journal area in the current summary is full of sit entries,
-        * all the sit entries will be flushed. Otherwise the sit entries
-        * are not able to replace with newly hot sit entries.
-        */
-       if (sits_in_cursum(sum) >= SIT_JOURNAL_ENTRIES) {
-               for (i = sits_in_cursum(sum) - 1; i >= 0; i--) {
-                       unsigned int segno;
-                       segno = le32_to_cpu(segno_in_journal(sum, i));
-                       __mark_sit_entry_dirty(sbi, segno);
-               }
-               update_sits_in_cursum(sum, -sits_in_cursum(sum));
-               return true;
+       for (i = sits_in_cursum(sum) - 1; i >= 0; i--) {
+               unsigned int segno;
+               bool dirtied;
+
+               segno = le32_to_cpu(segno_in_journal(sum, i));
+               dirtied = __mark_sit_entry_dirty(sbi, segno);
+
+               if (!dirtied)
+                       add_sit_entry(segno, &SM_I(sbi)->sit_entry_set);
        }
-       return false;
+       update_sits_in_cursum(sum, -sits_in_cursum(sum));
 }
 
 /*
        unsigned long *bitmap = sit_i->dirty_sentries_bitmap;
        struct curseg_info *curseg = CURSEG_I(sbi, CURSEG_COLD_DATA);
        struct f2fs_summary_block *sum = curseg->sum_blk;
+       struct sit_entry_set *ses, *tmp;
+       struct list_head *head = &SM_I(sbi)->sit_entry_set;
        unsigned long nsegs = TOTAL_SEGS(sbi);
-       struct page *page = NULL;
-       struct f2fs_sit_block *raw_sit = NULL;
-       unsigned int start = 0, end = 0;
-       unsigned int segno;
-       bool flushed;
+       bool to_journal = true;
 
        mutex_lock(&curseg->curseg_mutex);
        mutex_lock(&sit_i->sentry_lock);
 
        /*
-        * "flushed" indicates whether sit entries in journal are flushed
-        * to the SIT area or not.
+        * add and account sit entries of dirty bitmap in sit entry
+        * set temporarily
         */
-       flushed = flush_sits_in_journal(sbi);
-
-       for_each_set_bit(segno, bitmap, nsegs) {
-               struct seg_entry *se = get_seg_entry(sbi, segno);
-               int sit_offset, offset;
+       add_sits_in_set(sbi);
 
-               sit_offset = SIT_ENTRY_OFFSET(sit_i, segno);
-
-               /* add discard candidates */
-               if (SM_I(sbi)->nr_discards < SM_I(sbi)->max_discards)
-                       add_discard_addrs(sbi, segno, se);
+       /*
+        * if there are no enough space in journal to store dirty sit
+        * entries, remove all entries from journal and add and account
+        * them in sit entry set.
+        */
+       if (!__has_cursum_space(sum, sit_i->dirty_sentries, SIT_JOURNAL))
+               remove_sits_in_journal(sbi);
 
-               if (flushed)
-                       goto to_sit_page;
+       if (!sit_i->dirty_sentries)
+               goto out;
 
-               offset = lookup_journal_in_cursum(sum, SIT_JOURNAL, segno, 1);
-               if (offset >= 0) {
-                       segno_in_journal(sum, offset) = cpu_to_le32(segno);
-                       seg_info_to_raw_sit(se, &sit_in_journal(sum, offset));
-                       goto flush_done;
+       /*
+        * there are two steps to flush sit entries:
+        * #1, flush sit entries to journal in current cold data summary block.
+        * #2, flush sit entries to sit page.
+        */
+       list_for_each_entry_safe(ses, tmp, head, set_list) {
+               struct page *page;
+               struct f2fs_sit_block *raw_sit = NULL;
+               unsigned int start_segno = ses->start_segno;
+               unsigned int end = min(start_segno + SIT_ENTRY_PER_BLOCK,
+                                                               nsegs);
+               unsigned int segno = start_segno;
+
+               if (to_journal &&
+                       !__has_cursum_space(sum, ses->entry_cnt, SIT_JOURNAL))
+                       to_journal = false;
+
+               if (!to_journal) {
+                       page = get_next_sit_page(sbi, start_segno);
+                       raw_sit = page_address(page);
                }
-to_sit_page:
-               if (!page || (start > segno) || (segno > end)) {
-                       if (page) {
-                               f2fs_put_page(page, 1);
-                               page = NULL;
-                       }
 
-                       start = START_SEGNO(segno);
-                       end = start + SIT_ENTRY_PER_BLOCK - 1;
+               /* flush dirty sit entries in region of current sit set */
+               for_each_set_bit_from(segno, bitmap, end) {
+                       int offset, sit_offset;
+                       struct seg_entry *se = get_seg_entry(sbi, segno);
+
+                       /* add discard candidates */
+                       if (SM_I(sbi)->nr_discards < SM_I(sbi)->max_discards)
+                               add_discard_addrs(sbi, segno, se);
+
+                       if (to_journal) {
+                               offset = lookup_journal_in_cursum(sum,
+                                                       SIT_JOURNAL, segno, 1);
+                               f2fs_bug_on(sbi, offset < 0);
+                               segno_in_journal(sum, offset) =
+                                                       cpu_to_le32(segno);
+                               seg_info_to_raw_sit(se,
+                                               &sit_in_journal(sum, offset));
+                       } else {
+                               sit_offset = SIT_ENTRY_OFFSET(sit_i, segno);
+                               seg_info_to_raw_sit(se,
+                                               &raw_sit->entries[sit_offset]);
+                       }
 
-                       /* read sit block that will be updated */
-                       page = get_next_sit_page(sbi, start);
-                       raw_sit = page_address(page);
+                       __clear_bit(segno, bitmap);
+                       sit_i->dirty_sentries--;
+                       ses->entry_cnt--;
                }
 
-               /* udpate entry in SIT block */
-               seg_info_to_raw_sit(se, &raw_sit->entries[sit_offset]);
-flush_done:
-               __clear_bit(segno, bitmap);
-               sit_i->dirty_sentries--;
+               if (!to_journal)
+                       f2fs_put_page(page, 1);
+
+               f2fs_bug_on(sbi, ses->entry_cnt);
+               release_sit_entry_set(ses);
        }
+
+       f2fs_bug_on(sbi, !list_empty(head));
+       f2fs_bug_on(sbi, sit_i->dirty_sentries);
+
+out:
        mutex_unlock(&sit_i->sentry_lock);
        mutex_unlock(&curseg->curseg_mutex);
 
-       /* writeout last modified SIT block */
-       f2fs_put_page(page, 1);
-
        set_prefree_as_free_segments(sbi);
 }
 
        sm_info->nr_discards = 0;
        sm_info->max_discards = 0;
 
+       INIT_LIST_HEAD(&sm_info->sit_entry_set);
+
        if (test_opt(sbi, FLUSH_MERGE) && !f2fs_readonly(sbi->sb)) {
                err = create_flush_cmd_control(sbi);
                if (err)
        discard_entry_slab = f2fs_kmem_cache_create("discard_entry",
                        sizeof(struct discard_entry));
        if (!discard_entry_slab)
-               return -ENOMEM;
+               goto fail;
+
+       sit_entry_set_slab = f2fs_kmem_cache_create("sit_entry_set",
+                       sizeof(struct nat_entry_set));
+       if (!sit_entry_set_slab)
+               goto destory_discard_entry;
        return 0;
+
+destory_discard_entry:
+       kmem_cache_destroy(discard_entry_slab);
+fail:
+       return -ENOMEM;
 }
 
 void destroy_segment_manager_caches(void)
 {
+       kmem_cache_destroy(sit_entry_set_slab);
        kmem_cache_destroy(discard_entry_slab);
 }