Merge branch 'for-linus' of git://git.kernel.dk/linux-block
[linux-2.6-microblaze.git] / fs / f2fs / gc.c
index 418fd98..0265221 100644 (file)
@@ -84,7 +84,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 +172,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 +186,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 +211,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 +219,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 +229,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,7 +252,7 @@ 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;
@@ -291,6 +295,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 +309,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 +333,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 +353,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 +371,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 +565,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);
@@ -697,8 +714,10 @@ static void move_data_page(struct inode *inode, block_t bidx, int gc_type,
                        .type = DATA,
                        .op = REQ_OP_WRITE,
                        .op_flags = REQ_SYNC,
+                       .old_blkaddr = NULL_ADDR,
                        .page = page,
                        .encrypted_page = NULL,
+                       .need_lock = true,
                };
                bool is_dirty = PageDirty(page);
                int err;
@@ -890,7 +909,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 +924,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
@@ -924,7 +942,7 @@ next:
        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 +950,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;
        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),
@@ -959,9 +978,11 @@ 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;
        }
@@ -981,13 +1002,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 +1024,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 +1032,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;
 }