diff options
author | Jaegeuk Kim <jaegeuk@kernel.org> | 2017-01-11 17:40:24 -0500 |
---|---|---|
committer | Jaegeuk Kim <jaegeuk@kernel.org> | 2017-02-22 21:48:53 -0500 |
commit | 0b54fb8458199dbed409abb06933c27439ea0911 (patch) | |
tree | 32da2196ef3fe6b1485a89ac7ae15833b293748d | |
parent | d4adb30f25f5f2aa9b205891e395251d2a9098be (diff) |
f2fs: factor out discard command info into discard_cmd_control
This patch adds discard_cmd_control with the existing discarding controls.
Reviewed-by: Chao Yu <yuchao0@huawei.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
-rw-r--r-- | fs/f2fs/debug.c | 2 | ||||
-rw-r--r-- | fs/f2fs/f2fs.h | 16 | ||||
-rw-r--r-- | fs/f2fs/segment.c | 68 | ||||
-rw-r--r-- | fs/f2fs/super.c | 5 |
4 files changed, 69 insertions, 22 deletions
diff --git a/fs/f2fs/debug.c b/fs/f2fs/debug.c index cd338ca24941..f9f6b0aeba02 100644 --- a/fs/f2fs/debug.c +++ b/fs/f2fs/debug.c | |||
@@ -196,6 +196,8 @@ get_cache: | |||
196 | /* build merge flush thread */ | 196 | /* build merge flush thread */ |
197 | if (SM_I(sbi)->fcc_info) | 197 | if (SM_I(sbi)->fcc_info) |
198 | si->cache_mem += sizeof(struct flush_cmd_control); | 198 | si->cache_mem += sizeof(struct flush_cmd_control); |
199 | if (SM_I(sbi)->dcc_info) | ||
200 | si->cache_mem += sizeof(struct discard_cmd_control); | ||
199 | 201 | ||
200 | /* free nids */ | 202 | /* free nids */ |
201 | si->cache_mem += (NM_I(sbi)->nid_cnt[FREE_NID_LIST] + | 203 | si->cache_mem += (NM_I(sbi)->nid_cnt[FREE_NID_LIST] + |
diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index 548e75d18ec1..90eb2b3645a3 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h | |||
@@ -189,6 +189,13 @@ struct discard_cmd { | |||
189 | struct bio *bio; /* bio */ | 189 | struct bio *bio; /* bio */ |
190 | }; | 190 | }; |
191 | 191 | ||
192 | struct discard_cmd_control { | ||
193 | struct list_head discard_entry_list; /* 4KB discard entry list */ | ||
194 | int nr_discards; /* # of discards in the list */ | ||
195 | struct list_head discard_cmd_list; /* discard cmd list */ | ||
196 | int max_discards; /* max. discards to be issued */ | ||
197 | }; | ||
198 | |||
192 | /* for the list of fsync inodes, used only during recovery */ | 199 | /* for the list of fsync inodes, used only during recovery */ |
193 | struct fsync_inode_entry { | 200 | struct fsync_inode_entry { |
194 | struct list_head list; /* list head */ | 201 | struct list_head list; /* list head */ |
@@ -632,12 +639,6 @@ struct f2fs_sm_info { | |||
632 | /* a threshold to reclaim prefree segments */ | 639 | /* a threshold to reclaim prefree segments */ |
633 | unsigned int rec_prefree_segments; | 640 | unsigned int rec_prefree_segments; |
634 | 641 | ||
635 | /* for small discard management */ | ||
636 | struct list_head discard_entry_list; /* 4KB discard entry list */ | ||
637 | struct list_head discard_cmd_list; /* discard cmd list */ | ||
638 | int nr_discards; /* # of discards in the list */ | ||
639 | int max_discards; /* max. discards to be issued */ | ||
640 | |||
641 | /* for batched trimming */ | 642 | /* for batched trimming */ |
642 | unsigned int trim_sections; /* # of sections to trim */ | 643 | unsigned int trim_sections; /* # of sections to trim */ |
643 | 644 | ||
@@ -649,6 +650,9 @@ struct f2fs_sm_info { | |||
649 | 650 | ||
650 | /* for flush command control */ | 651 | /* for flush command control */ |
651 | struct flush_cmd_control *fcc_info; | 652 | struct flush_cmd_control *fcc_info; |
653 | |||
654 | /* for discard command control */ | ||
655 | struct discard_cmd_control *dcc_info; | ||
652 | }; | 656 | }; |
653 | 657 | ||
654 | /* | 658 | /* |
diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c index fa30c117b4cc..a009f8a70c3d 100644 --- a/fs/f2fs/segment.c +++ b/fs/f2fs/segment.c | |||
@@ -631,7 +631,8 @@ static void locate_dirty_segment(struct f2fs_sb_info *sbi, unsigned int segno) | |||
631 | static struct discard_cmd *__add_discard_cmd(struct f2fs_sb_info *sbi, | 631 | static struct discard_cmd *__add_discard_cmd(struct f2fs_sb_info *sbi, |
632 | struct bio *bio, block_t lstart, block_t len) | 632 | struct bio *bio, block_t lstart, block_t len) |
633 | { | 633 | { |
634 | struct list_head *wait_list = &(SM_I(sbi)->discard_cmd_list); | 634 | struct discard_cmd_control *dcc = SM_I(sbi)->dcc_info; |
635 | struct list_head *cmd_list = &(dcc->discard_cmd_list); | ||
635 | struct discard_cmd *dc; | 636 | struct discard_cmd *dc; |
636 | 637 | ||
637 | dc = f2fs_kmem_cache_alloc(discard_cmd_slab, GFP_NOFS); | 638 | dc = f2fs_kmem_cache_alloc(discard_cmd_slab, GFP_NOFS); |
@@ -640,7 +641,7 @@ static struct discard_cmd *__add_discard_cmd(struct f2fs_sb_info *sbi, | |||
640 | dc->lstart = lstart; | 641 | dc->lstart = lstart; |
641 | dc->len = len; | 642 | dc->len = len; |
642 | init_completion(&dc->wait); | 643 | init_completion(&dc->wait); |
643 | list_add_tail(&dc->list, wait_list); | 644 | list_add_tail(&dc->list, cmd_list); |
644 | 645 | ||
645 | return dc; | 646 | return dc; |
646 | } | 647 | } |
@@ -648,7 +649,8 @@ static struct discard_cmd *__add_discard_cmd(struct f2fs_sb_info *sbi, | |||
648 | /* This should be covered by global mutex, &sit_i->sentry_lock */ | 649 | /* This should be covered by global mutex, &sit_i->sentry_lock */ |
649 | void f2fs_wait_discard_bio(struct f2fs_sb_info *sbi, block_t blkaddr) | 650 | void f2fs_wait_discard_bio(struct f2fs_sb_info *sbi, block_t blkaddr) |
650 | { | 651 | { |
651 | struct list_head *wait_list = &(SM_I(sbi)->discard_cmd_list); | 652 | struct discard_cmd_control *dcc = SM_I(sbi)->dcc_info; |
653 | struct list_head *wait_list = &(dcc->discard_cmd_list); | ||
652 | struct discard_cmd *dc, *tmp; | 654 | struct discard_cmd *dc, *tmp; |
653 | 655 | ||
654 | list_for_each_entry_safe(dc, tmp, wait_list, list) { | 656 | list_for_each_entry_safe(dc, tmp, wait_list, list) { |
@@ -817,7 +819,7 @@ static void __add_discard_entry(struct f2fs_sb_info *sbi, | |||
817 | struct cp_control *cpc, struct seg_entry *se, | 819 | struct cp_control *cpc, struct seg_entry *se, |
818 | unsigned int start, unsigned int end) | 820 | unsigned int start, unsigned int end) |
819 | { | 821 | { |
820 | struct list_head *head = &SM_I(sbi)->discard_entry_list; | 822 | struct list_head *head = &SM_I(sbi)->dcc_info->discard_entry_list; |
821 | struct discard_entry *new, *last; | 823 | struct discard_entry *new, *last; |
822 | 824 | ||
823 | if (!list_empty(head)) { | 825 | if (!list_empty(head)) { |
@@ -835,7 +837,7 @@ static void __add_discard_entry(struct f2fs_sb_info *sbi, | |||
835 | new->len = end - start; | 837 | new->len = end - start; |
836 | list_add_tail(&new->list, head); | 838 | list_add_tail(&new->list, head); |
837 | done: | 839 | done: |
838 | SM_I(sbi)->nr_discards += end - start; | 840 | SM_I(sbi)->dcc_info->nr_discards += end - start; |
839 | } | 841 | } |
840 | 842 | ||
841 | static bool add_discard_addrs(struct f2fs_sb_info *sbi, struct cp_control *cpc, | 843 | static bool add_discard_addrs(struct f2fs_sb_info *sbi, struct cp_control *cpc, |
@@ -857,7 +859,8 @@ static bool add_discard_addrs(struct f2fs_sb_info *sbi, struct cp_control *cpc, | |||
857 | 859 | ||
858 | if (!force) { | 860 | if (!force) { |
859 | if (!test_opt(sbi, DISCARD) || !se->valid_blocks || | 861 | if (!test_opt(sbi, DISCARD) || !se->valid_blocks || |
860 | SM_I(sbi)->nr_discards >= SM_I(sbi)->max_discards) | 862 | SM_I(sbi)->dcc_info->nr_discards >= |
863 | SM_I(sbi)->dcc_info->max_discards) | ||
861 | return false; | 864 | return false; |
862 | } | 865 | } |
863 | 866 | ||
@@ -866,7 +869,8 @@ static bool add_discard_addrs(struct f2fs_sb_info *sbi, struct cp_control *cpc, | |||
866 | dmap[i] = force ? ~ckpt_map[i] & ~discard_map[i] : | 869 | dmap[i] = force ? ~ckpt_map[i] & ~discard_map[i] : |
867 | (cur_map[i] ^ ckpt_map[i]) & ckpt_map[i]; | 870 | (cur_map[i] ^ ckpt_map[i]) & ckpt_map[i]; |
868 | 871 | ||
869 | while (force || SM_I(sbi)->nr_discards <= SM_I(sbi)->max_discards) { | 872 | while (force || SM_I(sbi)->dcc_info->nr_discards <= |
873 | SM_I(sbi)->dcc_info->max_discards) { | ||
870 | start = __find_rev_next_bit(dmap, max_blocks, end + 1); | 874 | start = __find_rev_next_bit(dmap, max_blocks, end + 1); |
871 | if (start >= max_blocks) | 875 | if (start >= max_blocks) |
872 | break; | 876 | break; |
@@ -886,7 +890,7 @@ static bool add_discard_addrs(struct f2fs_sb_info *sbi, struct cp_control *cpc, | |||
886 | 890 | ||
887 | void release_discard_addrs(struct f2fs_sb_info *sbi) | 891 | void release_discard_addrs(struct f2fs_sb_info *sbi) |
888 | { | 892 | { |
889 | struct list_head *head = &(SM_I(sbi)->discard_entry_list); | 893 | struct list_head *head = &(SM_I(sbi)->dcc_info->discard_entry_list); |
890 | struct discard_entry *entry, *this; | 894 | struct discard_entry *entry, *this; |
891 | 895 | ||
892 | /* drop caches */ | 896 | /* drop caches */ |
@@ -912,7 +916,7 @@ static void set_prefree_as_free_segments(struct f2fs_sb_info *sbi) | |||
912 | 916 | ||
913 | void clear_prefree_segments(struct f2fs_sb_info *sbi, struct cp_control *cpc) | 917 | void clear_prefree_segments(struct f2fs_sb_info *sbi, struct cp_control *cpc) |
914 | { | 918 | { |
915 | struct list_head *head = &(SM_I(sbi)->discard_entry_list); | 919 | struct list_head *head = &(SM_I(sbi)->dcc_info->discard_entry_list); |
916 | struct discard_entry *entry, *this; | 920 | struct discard_entry *entry, *this; |
917 | struct dirty_seglist_info *dirty_i = DIRTY_I(sbi); | 921 | struct dirty_seglist_info *dirty_i = DIRTY_I(sbi); |
918 | struct blk_plug plug; | 922 | struct blk_plug plug; |
@@ -972,13 +976,47 @@ next: | |||
972 | cpc->trimmed += entry->len; | 976 | cpc->trimmed += entry->len; |
973 | skip: | 977 | skip: |
974 | list_del(&entry->list); | 978 | list_del(&entry->list); |
975 | SM_I(sbi)->nr_discards -= entry->len; | 979 | SM_I(sbi)->dcc_info->nr_discards -= entry->len; |
976 | kmem_cache_free(discard_entry_slab, entry); | 980 | kmem_cache_free(discard_entry_slab, entry); |
977 | } | 981 | } |
978 | 982 | ||
979 | blk_finish_plug(&plug); | 983 | blk_finish_plug(&plug); |
980 | } | 984 | } |
981 | 985 | ||
986 | int create_discard_cmd_control(struct f2fs_sb_info *sbi) | ||
987 | { | ||
988 | struct discard_cmd_control *dcc; | ||
989 | int err = 0; | ||
990 | |||
991 | if (SM_I(sbi)->dcc_info) { | ||
992 | dcc = SM_I(sbi)->dcc_info; | ||
993 | goto init_thread; | ||
994 | } | ||
995 | |||
996 | dcc = kzalloc(sizeof(struct discard_cmd_control), GFP_KERNEL); | ||
997 | if (!dcc) | ||
998 | return -ENOMEM; | ||
999 | |||
1000 | INIT_LIST_HEAD(&dcc->discard_entry_list); | ||
1001 | INIT_LIST_HEAD(&dcc->discard_cmd_list); | ||
1002 | dcc->nr_discards = 0; | ||
1003 | dcc->max_discards = 0; | ||
1004 | |||
1005 | SM_I(sbi)->dcc_info = dcc; | ||
1006 | init_thread: | ||
1007 | return err; | ||
1008 | } | ||
1009 | |||
1010 | void destroy_discard_cmd_control(struct f2fs_sb_info *sbi, bool free) | ||
1011 | { | ||
1012 | struct discard_cmd_control *dcc = SM_I(sbi)->dcc_info; | ||
1013 | |||
1014 | if (free) { | ||
1015 | kfree(dcc); | ||
1016 | SM_I(sbi)->dcc_info = NULL; | ||
1017 | } | ||
1018 | } | ||
1019 | |||
982 | static bool __mark_sit_entry_dirty(struct f2fs_sb_info *sbi, unsigned int segno) | 1020 | static bool __mark_sit_entry_dirty(struct f2fs_sb_info *sbi, unsigned int segno) |
983 | { | 1021 | { |
984 | struct sit_info *sit_i = SIT_I(sbi); | 1022 | struct sit_info *sit_i = SIT_I(sbi); |
@@ -2708,11 +2746,6 @@ int build_segment_manager(struct f2fs_sb_info *sbi) | |||
2708 | sm_info->min_ipu_util = DEF_MIN_IPU_UTIL; | 2746 | sm_info->min_ipu_util = DEF_MIN_IPU_UTIL; |
2709 | sm_info->min_fsync_blocks = DEF_MIN_FSYNC_BLOCKS; | 2747 | sm_info->min_fsync_blocks = DEF_MIN_FSYNC_BLOCKS; |
2710 | 2748 | ||
2711 | INIT_LIST_HEAD(&sm_info->discard_entry_list); | ||
2712 | INIT_LIST_HEAD(&sm_info->discard_cmd_list); | ||
2713 | sm_info->nr_discards = 0; | ||
2714 | sm_info->max_discards = 0; | ||
2715 | |||
2716 | sm_info->trim_sections = DEF_BATCHED_TRIM_SECTIONS; | 2749 | sm_info->trim_sections = DEF_BATCHED_TRIM_SECTIONS; |
2717 | 2750 | ||
2718 | INIT_LIST_HEAD(&sm_info->sit_entry_set); | 2751 | INIT_LIST_HEAD(&sm_info->sit_entry_set); |
@@ -2723,6 +2756,10 @@ int build_segment_manager(struct f2fs_sb_info *sbi) | |||
2723 | return err; | 2756 | return err; |
2724 | } | 2757 | } |
2725 | 2758 | ||
2759 | err = create_discard_cmd_control(sbi); | ||
2760 | if (err) | ||
2761 | return err; | ||
2762 | |||
2726 | err = build_sit_info(sbi); | 2763 | err = build_sit_info(sbi); |
2727 | if (err) | 2764 | if (err) |
2728 | return err; | 2765 | return err; |
@@ -2844,6 +2881,7 @@ void destroy_segment_manager(struct f2fs_sb_info *sbi) | |||
2844 | if (!sm_info) | 2881 | if (!sm_info) |
2845 | return; | 2882 | return; |
2846 | destroy_flush_cmd_control(sbi, true); | 2883 | destroy_flush_cmd_control(sbi, true); |
2884 | destroy_discard_cmd_control(sbi, true); | ||
2847 | destroy_dirty_segmap(sbi); | 2885 | destroy_dirty_segmap(sbi); |
2848 | destroy_curseg(sbi); | 2886 | destroy_curseg(sbi); |
2849 | destroy_free_segmap(sbi); | 2887 | destroy_free_segmap(sbi); |
diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c index e68cec492f06..921228189acd 100644 --- a/fs/f2fs/super.c +++ b/fs/f2fs/super.c | |||
@@ -145,6 +145,7 @@ static match_table_t f2fs_tokens = { | |||
145 | enum { | 145 | enum { |
146 | GC_THREAD, /* struct f2fs_gc_thread */ | 146 | GC_THREAD, /* struct f2fs_gc_thread */ |
147 | SM_INFO, /* struct f2fs_sm_info */ | 147 | SM_INFO, /* struct f2fs_sm_info */ |
148 | DCC_INFO, /* struct discard_cmd_control */ | ||
148 | NM_INFO, /* struct f2fs_nm_info */ | 149 | NM_INFO, /* struct f2fs_nm_info */ |
149 | F2FS_SBI, /* struct f2fs_sb_info */ | 150 | F2FS_SBI, /* struct f2fs_sb_info */ |
150 | #ifdef CONFIG_F2FS_FAULT_INJECTION | 151 | #ifdef CONFIG_F2FS_FAULT_INJECTION |
@@ -168,6 +169,8 @@ static unsigned char *__struct_ptr(struct f2fs_sb_info *sbi, int struct_type) | |||
168 | return (unsigned char *)sbi->gc_thread; | 169 | return (unsigned char *)sbi->gc_thread; |
169 | else if (struct_type == SM_INFO) | 170 | else if (struct_type == SM_INFO) |
170 | return (unsigned char *)SM_I(sbi); | 171 | return (unsigned char *)SM_I(sbi); |
172 | else if (struct_type == DCC_INFO) | ||
173 | return (unsigned char *)SM_I(sbi)->dcc_info; | ||
171 | else if (struct_type == NM_INFO) | 174 | else if (struct_type == NM_INFO) |
172 | return (unsigned char *)NM_I(sbi); | 175 | return (unsigned char *)NM_I(sbi); |
173 | else if (struct_type == F2FS_SBI) | 176 | else if (struct_type == F2FS_SBI) |
@@ -283,7 +286,7 @@ F2FS_RW_ATTR(GC_THREAD, f2fs_gc_kthread, gc_max_sleep_time, max_sleep_time); | |||
283 | F2FS_RW_ATTR(GC_THREAD, f2fs_gc_kthread, gc_no_gc_sleep_time, no_gc_sleep_time); | 286 | F2FS_RW_ATTR(GC_THREAD, f2fs_gc_kthread, gc_no_gc_sleep_time, no_gc_sleep_time); |
284 | F2FS_RW_ATTR(GC_THREAD, f2fs_gc_kthread, gc_idle, gc_idle); | 287 | F2FS_RW_ATTR(GC_THREAD, f2fs_gc_kthread, gc_idle, gc_idle); |
285 | F2FS_RW_ATTR(SM_INFO, f2fs_sm_info, reclaim_segments, rec_prefree_segments); | 288 | F2FS_RW_ATTR(SM_INFO, f2fs_sm_info, reclaim_segments, rec_prefree_segments); |
286 | F2FS_RW_ATTR(SM_INFO, f2fs_sm_info, max_small_discards, max_discards); | 289 | F2FS_RW_ATTR(DCC_INFO, discard_cmd_control, max_small_discards, max_discards); |
287 | F2FS_RW_ATTR(SM_INFO, f2fs_sm_info, batched_trim_sections, trim_sections); | 290 | F2FS_RW_ATTR(SM_INFO, f2fs_sm_info, batched_trim_sections, trim_sections); |
288 | F2FS_RW_ATTR(SM_INFO, f2fs_sm_info, ipu_policy, ipu_policy); | 291 | F2FS_RW_ATTR(SM_INFO, f2fs_sm_info, ipu_policy, ipu_policy); |
289 | F2FS_RW_ATTR(SM_INFO, f2fs_sm_info, min_ipu_util, min_ipu_util); | 292 | F2FS_RW_ATTR(SM_INFO, f2fs_sm_info, min_ipu_util, min_ipu_util); |