diff options
Diffstat (limited to 'fs/f2fs/segment.c')
-rw-r--r-- | fs/f2fs/segment.c | 68 |
1 files changed, 53 insertions, 15 deletions
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); |