diff options
author | Jaegeuk Kim <jaegeuk.kim@samsung.com> | 2013-01-03 03:55:52 -0500 |
---|---|---|
committer | Jaegeuk Kim <jaegeuk.kim@samsung.com> | 2013-01-09 17:42:59 -0500 |
commit | 408e9375610cca6d54e9c654cbe05a647687e12e (patch) | |
tree | 8bee0c5d2c8579721e81ba3d5689837a3d12be46 /fs/f2fs | |
parent | c335a86930b4841c11df12e1fdfd8345e0ebce84 (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.h | 2 | ||||
-rw-r--r-- | fs/f2fs/gc.c | 60 | ||||
-rw-r--r-- | fs/f2fs/segment.c | 2 |
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 *); | |||
986 | int start_gc_thread(struct f2fs_sb_info *); | 986 | int start_gc_thread(struct f2fs_sb_info *); |
987 | void stop_gc_thread(struct f2fs_sb_info *); | 987 | void stop_gc_thread(struct f2fs_sb_info *); |
988 | block_t start_bidx_of_node(unsigned int); | 988 | block_t start_bidx_of_node(unsigned int); |
989 | int f2fs_gc(struct f2fs_sb_info *, int); | 989 | int f2fs_gc(struct f2fs_sb_info *); |
990 | void build_gc_manager(struct f2fs_sb_info *); | 990 | void build_gc_manager(struct f2fs_sb_info *); |
991 | int create_gc_caches(void); | 991 | int create_gc_caches(void); |
992 | void destroy_gc_caches(void); | 992 | void 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 | ||
654 | int f2fs_gc(struct f2fs_sb_info *sbi, int nGC) | 654 | int 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); |
663 | gc_more: | 662 | gc_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 | } |
700 | stop: | 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 | } |
688 | stop: | ||
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 | ||