|
@@ -631,7 +631,8 @@ static void locate_dirty_segment(struct f2fs_sb_info *sbi, unsigned int segno)
|
|
|
static struct discard_cmd *__add_discard_cmd(struct f2fs_sb_info *sbi,
|
|
|
struct bio *bio, block_t lstart, block_t len)
|
|
|
{
|
|
|
- struct list_head *wait_list = &(SM_I(sbi)->discard_cmd_list);
|
|
|
+ struct discard_cmd_control *dcc = SM_I(sbi)->dcc_info;
|
|
|
+ struct list_head *cmd_list = &(dcc->discard_cmd_list);
|
|
|
struct discard_cmd *dc;
|
|
|
|
|
|
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,
|
|
|
dc->lstart = lstart;
|
|
|
dc->len = len;
|
|
|
init_completion(&dc->wait);
|
|
|
- list_add_tail(&dc->list, wait_list);
|
|
|
+ list_add_tail(&dc->list, cmd_list);
|
|
|
|
|
|
return dc;
|
|
|
}
|
|
@@ -648,7 +649,8 @@ static struct discard_cmd *__add_discard_cmd(struct f2fs_sb_info *sbi,
|
|
|
/* This should be covered by global mutex, &sit_i->sentry_lock */
|
|
|
void f2fs_wait_discard_bio(struct f2fs_sb_info *sbi, block_t blkaddr)
|
|
|
{
|
|
|
- struct list_head *wait_list = &(SM_I(sbi)->discard_cmd_list);
|
|
|
+ struct discard_cmd_control *dcc = SM_I(sbi)->dcc_info;
|
|
|
+ struct list_head *wait_list = &(dcc->discard_cmd_list);
|
|
|
struct discard_cmd *dc, *tmp;
|
|
|
|
|
|
list_for_each_entry_safe(dc, tmp, wait_list, list) {
|
|
@@ -817,7 +819,7 @@ static void __add_discard_entry(struct f2fs_sb_info *sbi,
|
|
|
struct cp_control *cpc, struct seg_entry *se,
|
|
|
unsigned int start, unsigned int end)
|
|
|
{
|
|
|
- struct list_head *head = &SM_I(sbi)->discard_entry_list;
|
|
|
+ struct list_head *head = &SM_I(sbi)->dcc_info->discard_entry_list;
|
|
|
struct discard_entry *new, *last;
|
|
|
|
|
|
if (!list_empty(head)) {
|
|
@@ -835,7 +837,7 @@ static void __add_discard_entry(struct f2fs_sb_info *sbi,
|
|
|
new->len = end - start;
|
|
|
list_add_tail(&new->list, head);
|
|
|
done:
|
|
|
- SM_I(sbi)->nr_discards += end - start;
|
|
|
+ SM_I(sbi)->dcc_info->nr_discards += end - start;
|
|
|
}
|
|
|
|
|
|
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,
|
|
|
|
|
|
if (!force) {
|
|
|
if (!test_opt(sbi, DISCARD) || !se->valid_blocks ||
|
|
|
- SM_I(sbi)->nr_discards >= SM_I(sbi)->max_discards)
|
|
|
+ SM_I(sbi)->dcc_info->nr_discards >=
|
|
|
+ SM_I(sbi)->dcc_info->max_discards)
|
|
|
return false;
|
|
|
}
|
|
|
|
|
@@ -866,7 +869,8 @@ static bool add_discard_addrs(struct f2fs_sb_info *sbi, struct cp_control *cpc,
|
|
|
dmap[i] = force ? ~ckpt_map[i] & ~discard_map[i] :
|
|
|
(cur_map[i] ^ ckpt_map[i]) & ckpt_map[i];
|
|
|
|
|
|
- while (force || SM_I(sbi)->nr_discards <= SM_I(sbi)->max_discards) {
|
|
|
+ while (force || SM_I(sbi)->dcc_info->nr_discards <=
|
|
|
+ SM_I(sbi)->dcc_info->max_discards) {
|
|
|
start = __find_rev_next_bit(dmap, max_blocks, end + 1);
|
|
|
if (start >= max_blocks)
|
|
|
break;
|
|
@@ -886,7 +890,7 @@ static bool add_discard_addrs(struct f2fs_sb_info *sbi, struct cp_control *cpc,
|
|
|
|
|
|
void release_discard_addrs(struct f2fs_sb_info *sbi)
|
|
|
{
|
|
|
- struct list_head *head = &(SM_I(sbi)->discard_entry_list);
|
|
|
+ struct list_head *head = &(SM_I(sbi)->dcc_info->discard_entry_list);
|
|
|
struct discard_entry *entry, *this;
|
|
|
|
|
|
/* drop caches */
|
|
@@ -912,7 +916,7 @@ static void set_prefree_as_free_segments(struct f2fs_sb_info *sbi)
|
|
|
|
|
|
void clear_prefree_segments(struct f2fs_sb_info *sbi, struct cp_control *cpc)
|
|
|
{
|
|
|
- struct list_head *head = &(SM_I(sbi)->discard_entry_list);
|
|
|
+ struct list_head *head = &(SM_I(sbi)->dcc_info->discard_entry_list);
|
|
|
struct discard_entry *entry, *this;
|
|
|
struct dirty_seglist_info *dirty_i = DIRTY_I(sbi);
|
|
|
struct blk_plug plug;
|
|
@@ -972,13 +976,47 @@ next:
|
|
|
cpc->trimmed += entry->len;
|
|
|
skip:
|
|
|
list_del(&entry->list);
|
|
|
- SM_I(sbi)->nr_discards -= entry->len;
|
|
|
+ SM_I(sbi)->dcc_info->nr_discards -= entry->len;
|
|
|
kmem_cache_free(discard_entry_slab, entry);
|
|
|
}
|
|
|
|
|
|
blk_finish_plug(&plug);
|
|
|
}
|
|
|
|
|
|
+int create_discard_cmd_control(struct f2fs_sb_info *sbi)
|
|
|
+{
|
|
|
+ struct discard_cmd_control *dcc;
|
|
|
+ int err = 0;
|
|
|
+
|
|
|
+ if (SM_I(sbi)->dcc_info) {
|
|
|
+ dcc = SM_I(sbi)->dcc_info;
|
|
|
+ goto init_thread;
|
|
|
+ }
|
|
|
+
|
|
|
+ dcc = kzalloc(sizeof(struct discard_cmd_control), GFP_KERNEL);
|
|
|
+ if (!dcc)
|
|
|
+ return -ENOMEM;
|
|
|
+
|
|
|
+ INIT_LIST_HEAD(&dcc->discard_entry_list);
|
|
|
+ INIT_LIST_HEAD(&dcc->discard_cmd_list);
|
|
|
+ dcc->nr_discards = 0;
|
|
|
+ dcc->max_discards = 0;
|
|
|
+
|
|
|
+ SM_I(sbi)->dcc_info = dcc;
|
|
|
+init_thread:
|
|
|
+ return err;
|
|
|
+}
|
|
|
+
|
|
|
+void destroy_discard_cmd_control(struct f2fs_sb_info *sbi, bool free)
|
|
|
+{
|
|
|
+ struct discard_cmd_control *dcc = SM_I(sbi)->dcc_info;
|
|
|
+
|
|
|
+ if (free) {
|
|
|
+ kfree(dcc);
|
|
|
+ SM_I(sbi)->dcc_info = NULL;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
static bool __mark_sit_entry_dirty(struct f2fs_sb_info *sbi, unsigned int segno)
|
|
|
{
|
|
|
struct sit_info *sit_i = SIT_I(sbi);
|
|
@@ -2708,11 +2746,6 @@ int build_segment_manager(struct f2fs_sb_info *sbi)
|
|
|
sm_info->min_ipu_util = DEF_MIN_IPU_UTIL;
|
|
|
sm_info->min_fsync_blocks = DEF_MIN_FSYNC_BLOCKS;
|
|
|
|
|
|
- INIT_LIST_HEAD(&sm_info->discard_entry_list);
|
|
|
- INIT_LIST_HEAD(&sm_info->discard_cmd_list);
|
|
|
- sm_info->nr_discards = 0;
|
|
|
- sm_info->max_discards = 0;
|
|
|
-
|
|
|
sm_info->trim_sections = DEF_BATCHED_TRIM_SECTIONS;
|
|
|
|
|
|
INIT_LIST_HEAD(&sm_info->sit_entry_set);
|
|
@@ -2723,6 +2756,10 @@ int build_segment_manager(struct f2fs_sb_info *sbi)
|
|
|
return err;
|
|
|
}
|
|
|
|
|
|
+ err = create_discard_cmd_control(sbi);
|
|
|
+ if (err)
|
|
|
+ return err;
|
|
|
+
|
|
|
err = build_sit_info(sbi);
|
|
|
if (err)
|
|
|
return err;
|
|
@@ -2844,6 +2881,7 @@ void destroy_segment_manager(struct f2fs_sb_info *sbi)
|
|
|
if (!sm_info)
|
|
|
return;
|
|
|
destroy_flush_cmd_control(sbi, true);
|
|
|
+ destroy_discard_cmd_control(sbi, true);
|
|
|
destroy_dirty_segmap(sbi);
|
|
|
destroy_curseg(sbi);
|
|
|
destroy_free_segmap(sbi);
|