f2fs: split wio_mutex
[linux-block.git] / fs / f2fs / gc.c
index 418fd988164677623cf0ad305d34f7855fb608dd..570480571d72238ddd39ef6189e9df6a64f83c5c 100644 (file)
@@ -32,13 +32,14 @@ static int gc_thread_func(void *data)
 
        wait_ms = gc_th->min_sleep_time;
 
+       set_freezable();
        do {
+               wait_event_interruptible_timeout(*wq,
+                               kthread_should_stop() || freezing(current),
+                               msecs_to_jiffies(wait_ms));
+
                if (try_to_freeze())
                        continue;
-               else
-                       wait_event_interruptible_timeout(*wq,
-                                               kthread_should_stop(),
-                                               msecs_to_jiffies(wait_ms));
                if (kthread_should_stop())
                        break;
 
@@ -84,7 +85,7 @@ static int gc_thread_func(void *data)
                stat_inc_bggc_count(sbi);
 
                /* if return value is not zero, no victim was selected */
-               if (f2fs_gc(sbi, test_opt(sbi, FORCE_FG_GC), true))
+               if (f2fs_gc(sbi, test_opt(sbi, FORCE_FG_GC), true, NULL_SEGNO))
                        wait_ms = gc_th->no_gc_sleep_time;
 
                trace_f2fs_background_gc(sbi->sb, wait_ms,
@@ -172,7 +173,11 @@ static void select_policy(struct f2fs_sb_info *sbi, int gc_type,
        if (gc_type != FG_GC && p->max_search > sbi->max_victim_search)
                p->max_search = sbi->max_victim_search;
 
-       p->offset = sbi->last_victim[p->gc_mode];
+       /* let's select beginning hot/small space first */
+       if (type == CURSEG_HOT_DATA || IS_NODESEG(type))
+               p->offset = 0;
+       else
+               p->offset = SIT_I(sbi)->last_victim[p->gc_mode];
 }
 
 static unsigned int get_max_cost(struct f2fs_sb_info *sbi,
@@ -182,7 +187,7 @@ static unsigned int get_max_cost(struct f2fs_sb_info *sbi,
        if (p->alloc_mode == SSR)
                return sbi->blocks_per_seg;
        if (p->gc_mode == GC_GREEDY)
-               return sbi->blocks_per_seg * p->ofs_unit;
+               return 2 * sbi->blocks_per_seg * p->ofs_unit;
        else if (p->gc_mode == GC_CB)
                return UINT_MAX;
        else /* No other gc_mode */
@@ -207,7 +212,7 @@ static unsigned int check_bg_victims(struct f2fs_sb_info *sbi)
                        continue;
 
                clear_bit(secno, dirty_i->victim_secmap);
-               return secno * sbi->segs_per_sec;
+               return GET_SEG_FROM_SEC(sbi, secno);
        }
        return NULL_SEGNO;
 }
@@ -215,8 +220,8 @@ static unsigned int check_bg_victims(struct f2fs_sb_info *sbi)
 static unsigned int get_cb_cost(struct f2fs_sb_info *sbi, unsigned int segno)
 {
        struct sit_info *sit_i = SIT_I(sbi);
-       unsigned int secno = GET_SECNO(sbi, segno);
-       unsigned int start = secno * sbi->segs_per_sec;
+       unsigned int secno = GET_SEC_FROM_SEG(sbi, segno);
+       unsigned int start = GET_SEG_FROM_SEC(sbi, secno);
        unsigned long long mtime = 0;
        unsigned int vblocks;
        unsigned char age = 0;
@@ -225,7 +230,7 @@ static unsigned int get_cb_cost(struct f2fs_sb_info *sbi, unsigned int segno)
 
        for (i = 0; i < sbi->segs_per_sec; i++)
                mtime += get_seg_entry(sbi, start + i)->mtime;
-       vblocks = get_valid_blocks(sbi, segno, sbi->segs_per_sec);
+       vblocks = get_valid_blocks(sbi, segno, true);
 
        mtime = div_u64(mtime, sbi->segs_per_sec);
        vblocks = div_u64(vblocks, sbi->segs_per_sec);
@@ -248,17 +253,26 @@ static unsigned int get_greedy_cost(struct f2fs_sb_info *sbi,
                                                unsigned int segno)
 {
        unsigned int valid_blocks =
-                       get_valid_blocks(sbi, segno, sbi->segs_per_sec);
+                       get_valid_blocks(sbi, segno, true);
 
        return IS_DATASEG(get_seg_entry(sbi, segno)->type) ?
                                valid_blocks * 2 : valid_blocks;
 }
 
+static unsigned int get_ssr_cost(struct f2fs_sb_info *sbi,
+                                               unsigned int segno)
+{
+       struct seg_entry *se = get_seg_entry(sbi, segno);
+
+       return se->ckpt_valid_blocks > se->valid_blocks ?
+                               se->ckpt_valid_blocks : se->valid_blocks;
+}
+
 static inline unsigned int get_gc_cost(struct f2fs_sb_info *sbi,
                        unsigned int segno, struct victim_sel_policy *p)
 {
        if (p->alloc_mode == SSR)
-               return get_seg_entry(sbi, segno)->ckpt_valid_blocks;
+               return get_ssr_cost(sbi, segno);
 
        /* alloc_mode == LFS */
        if (p->gc_mode == GC_GREEDY)
@@ -291,6 +305,7 @@ static int get_victim_by_default(struct f2fs_sb_info *sbi,
                unsigned int *result, int gc_type, int type, char alloc_mode)
 {
        struct dirty_seglist_info *dirty_i = DIRTY_I(sbi);
+       struct sit_info *sm = SIT_I(sbi);
        struct victim_sel_policy p;
        unsigned int secno, last_victim;
        unsigned int last_segment = MAIN_SEGS(sbi);
@@ -304,10 +319,18 @@ static int get_victim_by_default(struct f2fs_sb_info *sbi,
        p.min_segno = NULL_SEGNO;
        p.min_cost = get_max_cost(sbi, &p);
 
+       if (*result != NULL_SEGNO) {
+               if (IS_DATASEG(get_seg_entry(sbi, *result)->type) &&
+                       get_valid_blocks(sbi, *result, false) &&
+                       !sec_usage_check(sbi, GET_SEC_FROM_SEG(sbi, *result)))
+                       p.min_segno = *result;
+               goto out;
+       }
+
        if (p.max_search == 0)
                goto out;
 
-       last_victim = sbi->last_victim[p.gc_mode];
+       last_victim = sm->last_victim[p.gc_mode];
        if (p.alloc_mode == LFS && gc_type == FG_GC) {
                p.min_segno = check_bg_victims(sbi);
                if (p.min_segno != NULL_SEGNO)
@@ -320,9 +343,10 @@ static int get_victim_by_default(struct f2fs_sb_info *sbi,
 
                segno = find_next_bit(p.dirty_segmap, last_segment, p.offset);
                if (segno >= last_segment) {
-                       if (sbi->last_victim[p.gc_mode]) {
-                               last_segment = sbi->last_victim[p.gc_mode];
-                               sbi->last_victim[p.gc_mode] = 0;
+                       if (sm->last_victim[p.gc_mode]) {
+                               last_segment =
+                                       sm->last_victim[p.gc_mode];
+                               sm->last_victim[p.gc_mode] = 0;
                                p.offset = 0;
                                continue;
                        }
@@ -339,7 +363,7 @@ static int get_victim_by_default(struct f2fs_sb_info *sbi,
                        nsearched++;
                }
 
-               secno = GET_SECNO(sbi, segno);
+               secno = GET_SEC_FROM_SEG(sbi, segno);
 
                if (sec_usage_check(sbi, secno))
                        goto next;
@@ -357,17 +381,18 @@ static int get_victim_by_default(struct f2fs_sb_info *sbi,
                }
 next:
                if (nsearched >= p.max_search) {
-                       if (!sbi->last_victim[p.gc_mode] && segno <= last_victim)
-                               sbi->last_victim[p.gc_mode] = last_victim + 1;
+                       if (!sm->last_victim[p.gc_mode] && segno <= last_victim)
+                               sm->last_victim[p.gc_mode] = last_victim + 1;
                        else
-                               sbi->last_victim[p.gc_mode] = segno + 1;
+                               sm->last_victim[p.gc_mode] = segno + 1;
+                       sm->last_victim[p.gc_mode] %= MAIN_SEGS(sbi);
                        break;
                }
        }
        if (p.min_segno != NULL_SEGNO) {
 got_it:
                if (p.alloc_mode == LFS) {
-                       secno = GET_SECNO(sbi, p.min_segno);
+                       secno = GET_SEC_FROM_SEG(sbi, p.min_segno);
                        if (gc_type == FG_GC)
                                sbi->cur_victim_sec = secno;
                        else
@@ -550,8 +575,10 @@ static bool is_alive(struct f2fs_sb_info *sbi, struct f2fs_summary *sum,
        get_node_info(sbi, nid, dni);
 
        if (sum->version != dni->version) {
-               f2fs_put_page(node_page, 1);
-               return false;
+               f2fs_msg(sbi->sb, KERN_WARNING,
+                               "%s: valid data with mismatched node version.",
+                               __func__);
+               set_sbi_flag(sbi, SBI_NEED_FSCK);
        }
 
        *nofs = ofs_of_node(node_page);
@@ -569,6 +596,7 @@ static void move_encrypted_block(struct inode *inode, block_t bidx,
        struct f2fs_io_info fio = {
                .sbi = F2FS_I_SB(inode),
                .type = DATA,
+               .temp = COLD,
                .op = REQ_OP_READ,
                .op_flags = 0,
                .encrypted_page = NULL,
@@ -653,7 +681,7 @@ static void move_encrypted_block(struct inode *inode, block_t bidx,
        fio.op = REQ_OP_WRITE;
        fio.op_flags = REQ_SYNC;
        fio.new_blkaddr = newaddr;
-       f2fs_submit_page_mbio(&fio);
+       f2fs_submit_page_write(&fio);
 
        f2fs_update_data_blkaddr(&dn, newaddr);
        set_inode_flag(inode, FI_APPEND_WRITE);
@@ -695,10 +723,13 @@ static void move_data_page(struct inode *inode, block_t bidx, int gc_type,
                struct f2fs_io_info fio = {
                        .sbi = F2FS_I_SB(inode),
                        .type = DATA,
+                       .temp = COLD,
                        .op = REQ_OP_WRITE,
                        .op_flags = REQ_SYNC,
+                       .old_blkaddr = NULL_ADDR,
                        .page = page,
                        .encrypted_page = NULL,
+                       .need_lock = LOCK_REQ,
                };
                bool is_dirty = PageDirty(page);
                int err;
@@ -890,7 +921,7 @@ static int do_garbage_collect(struct f2fs_sb_info *sbi,
                                        GET_SUM_BLOCK(sbi, segno));
                f2fs_put_page(sum_page, 0);
 
-               if (get_valid_blocks(sbi, segno, 1) == 0 ||
+               if (get_valid_blocks(sbi, segno, false) == 0 ||
                                !PageUptodate(sum_page) ||
                                unlikely(f2fs_cp_error(sbi)))
                        goto next;
@@ -905,7 +936,6 @@ static int do_garbage_collect(struct f2fs_sb_info *sbi,
                 *   - mutex_lock(sentry_lock)     - change_curseg()
                 *                                  - lock_page(sum_page)
                 */
-
                if (type == SUM_TYPE_NODE)
                        gc_node_segment(sbi, sum->entries, segno, gc_type);
                else
@@ -918,13 +948,13 @@ next:
        }
 
        if (gc_type == FG_GC)
-               f2fs_submit_merged_bio(sbi,
-                               (type == SUM_TYPE_NODE) ? NODE : DATA, WRITE);
+               f2fs_submit_merged_write(sbi,
+                               (type == SUM_TYPE_NODE) ? NODE : DATA);
 
        blk_finish_plug(&plug);
 
        if (gc_type == FG_GC &&
-               get_valid_blocks(sbi, start_segno, sbi->segs_per_sec) == 0)
+               get_valid_blocks(sbi, start_segno, true) == 0)
                sec_freed = 1;
 
        stat_inc_call_count(sbi->stat_info);
@@ -932,13 +962,14 @@ next:
        return sec_freed;
 }
 
-int f2fs_gc(struct f2fs_sb_info *sbi, bool sync, bool background)
+int f2fs_gc(struct f2fs_sb_info *sbi, bool sync,
+                       bool background, unsigned int segno)
 {
-       unsigned int segno;
        int gc_type = sync ? FG_GC : BG_GC;
        int sec_freed = 0;
-       int ret = -EINVAL;
+       int ret;
        struct cp_control cpc;
+       unsigned int init_segno = segno;
        struct gc_inode_list gc_list = {
                .ilist = LIST_HEAD_INIT(gc_list.ilist),
                .iroot = RADIX_TREE_INIT(GFP_NOFS),
@@ -946,8 +977,10 @@ int f2fs_gc(struct f2fs_sb_info *sbi, bool sync, bool background)
 
        cpc.reason = __get_cp_reason(sbi);
 gc_more:
-       if (unlikely(!(sbi->sb->s_flags & MS_ACTIVE)))
+       if (unlikely(!(sbi->sb->s_flags & MS_ACTIVE))) {
+               ret = -EINVAL;
                goto stop;
+       }
        if (unlikely(f2fs_cp_error(sbi))) {
                ret = -EIO;
                goto stop;
@@ -959,13 +992,16 @@ gc_more:
                 * threshold, we can make them free by checkpoint. Then, we
                 * secure free segments which doesn't need fggc any more.
                 */
-               ret = write_checkpoint(sbi, &cpc);
-               if (ret)
-                       goto stop;
+               if (prefree_segments(sbi)) {
+                       ret = write_checkpoint(sbi, &cpc);
+                       if (ret)
+                               goto stop;
+               }
                if (has_not_enough_free_secs(sbi, 0, 0))
                        gc_type = FG_GC;
        }
 
+       ret = -EINVAL;
        /* f2fs_balance_fs doesn't need to do BG_GC in critical path. */
        if (gc_type == BG_GC && !background)
                goto stop;
@@ -981,13 +1017,17 @@ gc_more:
                sbi->cur_victim_sec = NULL_SEGNO;
 
        if (!sync) {
-               if (has_not_enough_free_secs(sbi, sec_freed, 0))
+               if (has_not_enough_free_secs(sbi, sec_freed, 0)) {
+                       segno = NULL_SEGNO;
                        goto gc_more;
+               }
 
                if (gc_type == FG_GC)
                        ret = write_checkpoint(sbi, &cpc);
        }
 stop:
+       SIT_I(sbi)->last_victim[ALLOC_NEXT] = 0;
+       SIT_I(sbi)->last_victim[FLUSH_DEVICE] = init_segno;
        mutex_unlock(&sbi->gc_mutex);
 
        put_gc_inode(&gc_list);
@@ -999,7 +1039,7 @@ stop:
 
 void build_gc_manager(struct f2fs_sb_info *sbi)
 {
-       u64 main_count, resv_count, ovp_count, blocks_per_sec;
+       u64 main_count, resv_count, ovp_count;
 
        DIRTY_I(sbi)->v_ops = &default_v_ops;
 
@@ -1007,8 +1047,12 @@ void build_gc_manager(struct f2fs_sb_info *sbi)
        main_count = SM_I(sbi)->main_segments << sbi->log_blocks_per_seg;
        resv_count = SM_I(sbi)->reserved_segments << sbi->log_blocks_per_seg;
        ovp_count = SM_I(sbi)->ovp_segments << sbi->log_blocks_per_seg;
-       blocks_per_sec = sbi->blocks_per_seg * sbi->segs_per_sec;
 
-       sbi->fggc_threshold = div64_u64((main_count - ovp_count) * blocks_per_sec,
-                                       (main_count - resv_count));
+       sbi->fggc_threshold = div64_u64((main_count - ovp_count) *
+                               BLKS_PER_SEC(sbi), (main_count - resv_count));
+
+       /* give warm/cold data area from slower device */
+       if (sbi->s_ndevs && sbi->segs_per_sec == 1)
+               SIT_I(sbi)->last_victim[ALLOC_NEXT] =
+                               GET_SEGNO(sbi, FDEV(0).end_blk) + 1;
 }