aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/f2fs/debug.c2
-rw-r--r--fs/f2fs/f2fs.h16
-rw-r--r--fs/f2fs/segment.c68
-rw-r--r--fs/f2fs/super.c5
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
192struct 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 */
193struct fsync_inode_entry { 200struct 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)
631static struct discard_cmd *__add_discard_cmd(struct f2fs_sb_info *sbi, 631static 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 */
649void f2fs_wait_discard_bio(struct f2fs_sb_info *sbi, block_t blkaddr) 650void 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);
837done: 839done:
838 SM_I(sbi)->nr_discards += end - start; 840 SM_I(sbi)->dcc_info->nr_discards += end - start;
839} 841}
840 842
841static bool add_discard_addrs(struct f2fs_sb_info *sbi, struct cp_control *cpc, 843static 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
887void release_discard_addrs(struct f2fs_sb_info *sbi) 891void 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
913void clear_prefree_segments(struct f2fs_sb_info *sbi, struct cp_control *cpc) 917void 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;
973skip: 977skip:
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
986int 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;
1006init_thread:
1007 return err;
1008}
1009
1010void 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
982static bool __mark_sit_entry_dirty(struct f2fs_sb_info *sbi, unsigned int segno) 1020static 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 = {
145enum { 145enum {
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);
283F2FS_RW_ATTR(GC_THREAD, f2fs_gc_kthread, gc_no_gc_sleep_time, no_gc_sleep_time); 286F2FS_RW_ATTR(GC_THREAD, f2fs_gc_kthread, gc_no_gc_sleep_time, no_gc_sleep_time);
284F2FS_RW_ATTR(GC_THREAD, f2fs_gc_kthread, gc_idle, gc_idle); 287F2FS_RW_ATTR(GC_THREAD, f2fs_gc_kthread, gc_idle, gc_idle);
285F2FS_RW_ATTR(SM_INFO, f2fs_sm_info, reclaim_segments, rec_prefree_segments); 288F2FS_RW_ATTR(SM_INFO, f2fs_sm_info, reclaim_segments, rec_prefree_segments);
286F2FS_RW_ATTR(SM_INFO, f2fs_sm_info, max_small_discards, max_discards); 289F2FS_RW_ATTR(DCC_INFO, discard_cmd_control, max_small_discards, max_discards);
287F2FS_RW_ATTR(SM_INFO, f2fs_sm_info, batched_trim_sections, trim_sections); 290F2FS_RW_ATTR(SM_INFO, f2fs_sm_info, batched_trim_sections, trim_sections);
288F2FS_RW_ATTR(SM_INFO, f2fs_sm_info, ipu_policy, ipu_policy); 291F2FS_RW_ATTR(SM_INFO, f2fs_sm_info, ipu_policy, ipu_policy);
289F2FS_RW_ATTR(SM_INFO, f2fs_sm_info, min_ipu_util, min_ipu_util); 292F2FS_RW_ATTR(SM_INFO, f2fs_sm_info, min_ipu_util, min_ipu_util);