aboutsummaryrefslogtreecommitdiffstats
path: root/fs/f2fs
diff options
context:
space:
mode:
authorJaegeuk Kim <jaegeuk.kim@samsung.com>2013-01-03 03:55:52 -0500
committerJaegeuk Kim <jaegeuk.kim@samsung.com>2013-01-09 17:42:59 -0500
commit408e9375610cca6d54e9c654cbe05a647687e12e (patch)
tree8bee0c5d2c8579721e81ba3d5689837a3d12be46 /fs/f2fs
parentc335a86930b4841c11df12e1fdfd8345e0ebce84 (diff)
f2fs: revisit the f2fs_gc flow
I'd like to revisit the f2fs_gc flow and rewrite as follows. 1. In practical, the nGC parameter of f2fs_gc is meaningless. So, let's remove it. 2. Background GC marks victim blocks as dirty one at a time. 3. Foreground GC should do cleaning job until acquiring enough free sections. Afterwards, it needs to do checkpoint. Signed-off-by: Jaegeuk Kim <jaegeuk.kim@samsung.com>
Diffstat (limited to 'fs/f2fs')
-rw-r--r--fs/f2fs/f2fs.h2
-rw-r--r--fs/f2fs/gc.c60
-rw-r--r--fs/f2fs/segment.c2
3 files changed, 23 insertions, 41 deletions
diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
index 280713289d8c..285e43d602f3 100644
--- a/fs/f2fs/f2fs.h
+++ b/fs/f2fs/f2fs.h
@@ -986,7 +986,7 @@ int do_write_data_page(struct page *);
986int start_gc_thread(struct f2fs_sb_info *); 986int start_gc_thread(struct f2fs_sb_info *);
987void stop_gc_thread(struct f2fs_sb_info *); 987void stop_gc_thread(struct f2fs_sb_info *);
988block_t start_bidx_of_node(unsigned int); 988block_t start_bidx_of_node(unsigned int);
989int f2fs_gc(struct f2fs_sb_info *, int); 989int f2fs_gc(struct f2fs_sb_info *);
990void build_gc_manager(struct f2fs_sb_info *); 990void build_gc_manager(struct f2fs_sb_info *);
991int create_gc_caches(void); 991int create_gc_caches(void);
992void destroy_gc_caches(void); 992void destroy_gc_caches(void);
diff --git a/fs/f2fs/gc.c b/fs/f2fs/gc.c
index b0ec721e984a..b4dd90cf1f18 100644
--- a/fs/f2fs/gc.c
+++ b/fs/f2fs/gc.c
@@ -78,7 +78,7 @@ static int gc_thread_func(void *data)
78 78
79 sbi->bg_gc++; 79 sbi->bg_gc++;
80 80
81 if (f2fs_gc(sbi, 1) == GC_NONE) 81 if (f2fs_gc(sbi) == GC_NONE)
82 wait_ms = GC_THREAD_NOGC_SLEEP_TIME; 82 wait_ms = GC_THREAD_NOGC_SLEEP_TIME;
83 else if (wait_ms == GC_THREAD_NOGC_SLEEP_TIME) 83 else if (wait_ms == GC_THREAD_NOGC_SLEEP_TIME)
84 wait_ms = GC_THREAD_MAX_SLEEP_TIME; 84 wait_ms = GC_THREAD_MAX_SLEEP_TIME;
@@ -651,62 +651,44 @@ static int do_garbage_collect(struct f2fs_sb_info *sbi, unsigned int segno,
651 return ret; 651 return ret;
652} 652}
653 653
654int f2fs_gc(struct f2fs_sb_info *sbi, int nGC) 654int f2fs_gc(struct f2fs_sb_info *sbi)
655{ 655{
656 unsigned int segno;
657 int old_free_secs, cur_free_secs;
658 int gc_status, nfree;
659 struct list_head ilist; 656 struct list_head ilist;
657 unsigned int segno, i;
660 int gc_type = BG_GC; 658 int gc_type = BG_GC;
659 int gc_status = GC_NONE;
661 660
662 INIT_LIST_HEAD(&ilist); 661 INIT_LIST_HEAD(&ilist);
663gc_more: 662gc_more:
664 nfree = 0; 663 if (!(sbi->sb->s_flags & MS_ACTIVE))
665 gc_status = GC_NONE; 664 goto stop;
666 665
667 if (has_not_enough_free_secs(sbi)) 666 if (has_not_enough_free_secs(sbi))
668 old_free_secs = reserved_sections(sbi); 667 gc_type = FG_GC;
669 else
670 old_free_secs = free_sections(sbi);
671
672 while (sbi->sb->s_flags & MS_ACTIVE) {
673 int i;
674 if (has_not_enough_free_secs(sbi))
675 gc_type = FG_GC;
676 668
677 cur_free_secs = free_sections(sbi) + nfree; 669 if (!__get_victim(sbi, &segno, gc_type, NO_CHECK_TYPE))
670 goto stop;
678 671
679 /* We got free space successfully. */ 672 for (i = 0; i < sbi->segs_per_sec; i++) {
680 if (nGC < cur_free_secs - old_free_secs) 673 /*
681 break; 674 * do_garbage_collect will give us three gc_status:
682 675 * GC_ERROR, GC_DONE, and GC_BLOCKED.
683 if (!__get_victim(sbi, &segno, gc_type, NO_CHECK_TYPE)) 676 * If GC is finished uncleanly, we have to return
677 * the victim to dirty segment list.
678 */
679 gc_status = do_garbage_collect(sbi, segno + i, &ilist, gc_type);
680 if (gc_status != GC_DONE)
684 break; 681 break;
685
686 for (i = 0; i < sbi->segs_per_sec; i++) {
687 /*
688 * do_garbage_collect will give us three gc_status:
689 * GC_ERROR, GC_DONE, and GC_BLOCKED.
690 * If GC is finished uncleanly, we have to return
691 * the victim to dirty segment list.
692 */
693 gc_status = do_garbage_collect(sbi, segno + i,
694 &ilist, gc_type);
695 if (gc_status != GC_DONE)
696 goto stop;
697 nfree++;
698 }
699 } 682 }
700stop: 683 if (has_not_enough_free_secs(sbi)) {
701 if (has_not_enough_free_secs(sbi) || gc_status == GC_BLOCKED) {
702 write_checkpoint(sbi, (gc_status == GC_BLOCKED), false); 684 write_checkpoint(sbi, (gc_status == GC_BLOCKED), false);
703 if (nfree) 685 if (has_not_enough_free_secs(sbi))
704 goto gc_more; 686 goto gc_more;
705 } 687 }
688stop:
706 mutex_unlock(&sbi->gc_mutex); 689 mutex_unlock(&sbi->gc_mutex);
707 690
708 put_gc_inode(&ilist); 691 put_gc_inode(&ilist);
709 BUG_ON(!list_empty(&ilist));
710 return gc_status; 692 return gc_status;
711} 693}
712 694
diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c
index de6240922b0a..4b0099066582 100644
--- a/fs/f2fs/segment.c
+++ b/fs/f2fs/segment.c
@@ -31,7 +31,7 @@ void f2fs_balance_fs(struct f2fs_sb_info *sbi)
31 */ 31 */
32 if (has_not_enough_free_secs(sbi)) { 32 if (has_not_enough_free_secs(sbi)) {
33 mutex_lock(&sbi->gc_mutex); 33 mutex_lock(&sbi->gc_mutex);
34 f2fs_gc(sbi, 1); 34 f2fs_gc(sbi);
35 } 35 }
36} 36}
37 37